使用 C# 获取谷歌财经的股票报价和图表






4.83/5 (13投票s)
在 .NET Framework 4 中使用 Google Finance API 获取股票报价
引言
这个简单的 Windows Forms 应用程序展示了如何使用 Google Finance API 获取股票报价和图表,并使用 System.Windows.Forms.Timer
类以固定间隔更新它们。
使用代码
为了从 Google Finance 获取 XML 数据,无需注册或登录。以下 URL 用于从 Google 获取数据:https://www.google.com/ig/api?stock=GOOG (这里,GOOG 代表 Google 的股票,这个代码可以替换为其他股票代码来获取不同的股票)
以下是 Google API 返回的 Google 股票 (GOOG) 的 XML 数据的简单截图。
现在,我们可以将两个或多个股票组合到一个 URL 中,并获取一个大型 XML 文件,该文件可以在本地解析,从而减少对 Google Finance 的请求次数。
例如,要在一个 XML 文件中获取 Google (GOOG) 和 Apple (AAPL) 的股票,可以使用以下 URL
https://www.google.com/ig/api?stock=GOOG&stock=AAPL
回到代码,以下是解决方案的类图:
Stock_quotes
类中的以下方法用于获取 XML 数据:
/// <summary>
/// Fetches the XML data in to the XDocument from the google finance apis
/// </summary>
/// <param name="symbol"></param>
/// <returns></returns>
public static XDocument FetchQuote(string symbol)
{
symbol = symbol.Trim();
symbol = symbol.Replace(" ", "&stock=");
symbol = symbol.Replace(",", "&stock=");
string url = "https://www.google.com/ig/api?stock=" + (symbol);
return XDocument.Load(url);
}
为了验证用户输入的股票代码,我们查看 XML 文件中的 "last" 元素(交易价值),如果它等于 0.00 或不存在,则用户输入的股票代码无效。以下是 Stock_quotes
类中验证股票代码的方法
/// <summary>
/// Takes a XDocument, parses it and returns a list of stock objects that corresponds to valid
/// stock symbols
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
public static List<Stock> getValidStocks(XDocument doc)
{
List<Stock> stocks = new List<Stock>();
foreach (var root in doc.Root.Elements("finance"))
{
try
{
if (root.Element("last") != null && root.Element("last").Attribute(
"data").Value != null && root.Element("last").Attribute(
"data").Value.Equals("0.00") == false)
{
stocks.Add(Stock_quotes.createNewStock(root));
}
else
{
System.Windows.Forms.MessageBox.Show(root.Element("symbol").Attribute(
"data").Value + " is not a valid stock symbol");
}
}
catch (Exception er)
{
//Error message
}
}
return stocks;
}
Stock_quotes.cs
类:这是一个静态类,处理所有 XML 数据的解析。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Xml.Linq;
using System.Xml;
namespace Quotes
{
static class Stock_quotes
{
/// <summary>
/// Fetches the XML data in to the XDocument from the google finance apis
/// </summary>
/// <param name="symbol"></param>
/// <returns></returns>
public static XDocument FetchQuote(string symbol)
{
symbol = symbol.Trim();
symbol = symbol.Replace(" ", "&stock=");
symbol = symbol.Replace(",", "&stock=");
string url = "https://www.google.com/ig/api?stock=" + (symbol);
return XDocument.Load(url);
}
/// <summary>
/// Takes a XDocument, parses it and returns a list of stock objects that corresponds to valid
/// stock symbols
/// </summary>
/// <param name="doc"></param>
/// <returns></returns>
public static List<Stock> getValidStocks(XDocument doc)
{
List<Stock> stocks = new List<Stock>();
foreach (var root in doc.Root.Elements("finance"))
{
try
{
if (root.Element("last") != null && root.Element(
"last").Attribute("data").Value != null && root.Element(
"last").Attribute("data").Value.Equals("0.00") == false)
{
stocks.Add(Stock_quotes.createNewStock(root));
}
else
{
System.Windows.Forms.MessageBox.Show(root.Element("symbol").Attribute(
"data").Value + " is not a valid stock symbol");
}
}
catch (Exception er)
{
//Error message
}
}
return stocks;
}
/// <summary>
/// Retrieves a particular stock from the XDocument.
/// </summary>
/// <param name="doc"></param>
/// <param name="symbol"></param>
/// <param name="lookUpField"></param>
/// <returns></returns>
public static Stock getThisStock(XDocument doc, string symbol, string lookUpField)
{
Stock stock = null;
foreach (var root in doc.Root.Elements("finance"))
{
if (root.Element(lookUpField).Attribute("data").Value.Equals(symbol))
{
return Stock_quotes.createNewStock(root);
}
}
return stock;
}
/// <summary>
/// Creates a new Stock from XElement.
/// </summary>
/// <param name="root"></param>
/// <returns></returns>
public static Stock createNewStock(XElement root)
{
Stock stock = new Stock();
stock.Symbol = root.Element("symbol").Attribute("data").Value;
DateTime eastern = Stock_quotes.UTCtoEastern(root.Element("current_date_utc").Attribute(
"data").Value, root.Element("current_time_utc").Attribute("data").Value);
stock.Date = eastern.ToShortDateString();
stock.Time = eastern.ToLongTimeString();
stock.Trade = root.Element("last").Attribute("data").Value;
stock.Chg = root.Element("change").Attribute("data").Value;
stock.Perc_chg = root.Element("perc_change").Attribute("data").Value;
stock.Volume = root.Element("volume").Attribute("data").Value;
stock.High = root.Element("high").Attribute("data").Value;
stock.Low = root.Element("low").Attribute("data").Value;
stock.Chart_url = "https://www.google.com" +
root.Element("chart_url").Attribute("data").Value;
stock.Market_cap = root.Element("market_cap").Attribute("data").Value;
stock.Exchange = root.Element("exchange").Attribute("data").Value;
stock.Currency = root.Element("currency").Attribute("data").Value;
stock.Company = root.Element("company").Attribute("data").Value;
stock.Y_close = root.Element("y_close").Attribute("data").Value;
return stock;
}
/// <summary>
/// Converts date and time from UTC to Eastern standard
/// </summary>
/// <param name="date"></param>
/// <param name="time"></param>
/// <returns></returns>
public static DateTime UTCtoEastern(string date, string time)
{
int year = Convert.ToInt32(date.Substring(0, 4));
int month = Convert.ToInt32(date.Substring(4, 2));
int day = Convert.ToInt32(date.Substring(6, 2));
int hours = Convert.ToInt32(time.Substring(0, 2));
int mins = Convert.ToInt32(time.Substring(2, 2));
int sec = Convert.ToInt32(time.Substring(4, 2));
DateTime utcTime = new DateTime(year, month, day, hours, mins, sec, DateTimeKind.Utc);
TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, easternZone);
}
}
}
Database.cs 类:该类处理内部数据结构,用于存储单个股票和市场数据。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Windows.Forms;
using System.Xml.Linq;
namespace Quotes
{
/// <summary>
/// Database class that holds two data-tables: data_table (used to hold individualt stocks data)
/// and market_data_table (used to hold the individual market data)
/// </summary>
class Database
{
private DataTable data_table;
private DataTable market_data_table;
public DataTable Data_table
{
get { return data_table; }
set { data_table = value; }
}
public DataTable Market_data_table
{
get { return market_data_table; }
set { market_data_table = value; }
}
/// <summary>
/// Timer that ticks every 5 seconds to pull the XML file
/// </summary>
private Timer updateTimer;
/// <summary>
/// Parametrized constructor
/// </summary>
/// <param name="tableName">name of the table
/// that holds individual stock data</param>
/// <param name="colNames">Column names in both tables</param>
public Database(string tableName, string[] colNames)
{
data_table = new DataTable(tableName);
market_data_table = new DataTable("Market Table");
foreach (string s in colNames)
{
data_table.Columns.Add(s);
}
foreach (string s in colNames)
{
market_data_table.Columns.Add(s);
}
updateTimer = new Timer();
updateTimer.Interval = 5000;
//Change the value here to increase/decrease the update time
updateTimer.Tick += new EventHandler(updateTimer_Tick);
updateTimer.Enabled = true;
}
void updateTimer_Tick(object sender, EventArgs e)
{
//Fetching all the stocks at once in XDocument file
XDocument doc = Stock_quotes.FetchQuote(
this.getAllSymbolsFromTable(data_table) + Main_view.market_symbol_string);
//This will update the data_table
this.addValuesToTheTable(data_table, doc);
//This will update the market_table
this.addValuesToTheTable(market_data_table, doc);
}
/// <summary>
/// Adds a stock symbol to the table or throws an ArgumentException
/// </summary>
/// <param name="symbol">symbol(s) to the added. Multiple entries
// are allowed that are separated by " " or ","</param>
/// <param name="table"></param>
public void addStockSymbolToTheTable(string symbol, DataTable table)
{
if (symbol != null && symbol.Length > 0)
{
XDocument xDoc = Stock_quotes.FetchQuote(symbol);
List<Stock> list = Stock_quotes.getValidStocks(xDoc);
foreach (Stock stock in list)
{
table.Rows.Add(stock.Symbol, stock.Company ,stock.Date, stock.Time,
stock.Y_close, stock.Trade, stock.Chg, stock.Perc_chg, stock.Volume,
stock.High, stock.Low, stock.Chart_url, stock.Market_cap,
stock.Exchange, stock.Currency);
}
}
else
{
throw new ArgumentException("Added symbol is not accepted as a valid input");
}
}
/// <summary>
/// Gets all the symbols (in the symbol column) from the table
/// </summary>
/// <param name="table"></param>
/// <returns></returns>
public string getAllSymbolsFromTable(DataTable table)
{
StringBuilder result = new StringBuilder();
foreach (DataRow row in table.Rows)
{
result.Append(row["Symbol"] + " ");
}
return result.ToString();
}
/// <summary>
/// Updates the table data
/// </summary>
/// <param name="table"></param>
/// <param name="doc"></param>
public void addValuesToTheTable(DataTable table, XDocument doc)
{
foreach (DataRow row in table.Rows)
{
Stock stock = Stock_quotes.getThisStock(doc, (string)row["Symbol"], "symbol");
row["Symbol"] = stock.Symbol;
row["Company"] = stock.Company;
row["Date"] = stock.Date;
row["Time"] = stock.Time;
row["Closed Yesterday"] = stock.Y_close;
row["Trade"] = stock.Trade;
row["Chg"] = stock.Chg;
row["%Chg"] = stock.Perc_chg;
row["Volume"] = stock.Volume;
row["High"] = stock.High;
row["Low"] = stock.Low;
row["Chart"] = stock.Chart_url;
row["Market Cap"] = stock.Market_cap;
row["Exchange"] = stock.Exchange;
row["Currency"] = stock.Currency;
}
}
/// <summary>
/// Retrives Chart URL from the table based on the stock symbol
/// </summary>
/// <param name="symbol"></param>
/// <param name="table"></param>
/// <returns></returns>
public string getChartURL(string symbol, DataTable table)
{
string result = string.Empty;
if (table.Rows.Count > 0)
{
foreach (DataRow row in table.Rows)
{
if (((string)row["Symbol"]).Equals(symbol))
{
result = (string)row["Chart"];
break;
}
}
return result;
}
else
{
return result;
}
}
/// <summary>
/// Saves the symbols that user has entered into the settings file
/// </summary>
public void saveSymbols()
{
Properties.Settings.Default.symbols = new System.Collections.Specialized.StringCollection();
foreach (DataRow row in data_table.Rows)
{
Properties.Settings.Default.symbols.Add((string)row["Symbol"]);
}
Properties.Settings.Default.Save();
}
/// <summary>
/// Loads symbols that user had entered previously from the settings file
/// </summary>
public void loadSavedSymbols()
{
var list = Properties.Settings.Default.symbols;
if (list !=null && list.Count != 0)
{
StringBuilder symbols = new StringBuilder();
foreach (string s in list)
{
symbols.Append(s + " ");
}
try
{
this.addStockSymbolToTheTable(symbols.ToString(), data_table);
}
catch (ArgumentException ar)
{
MessageBox.Show(ar.Message);
}
}
}
}
}
Stock.cs:一个简单的 Stock
对象类,用于在 XDocument
和 DataTables 之间传递信息。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Quotes
{
/// <summary>
/// Simple Stock object class used to transfer data from XML file to the Data-table
/// </summary>
class Stock
{
private string symbol;
public string Symbol
{
get { return symbol; }
set { symbol = value; }
}
private string date;
public string Date
{
get { return date; }
set { date = value; }
}
private string time;
public string Time
{
get { return time; }
set { time = value; }
}
private string trade;
public string Trade
{
get { return trade; }
set { trade = value; }
}
private string chg;
public string Chg
{
get { return chg; }
set { chg = value; }
}
private string perc_chg;
public string Perc_chg
{
get { return perc_chg; }
set { perc_chg = value; }
}
private string volume;
public string Volume
{
get { return volume; }
set { volume = value; }
}
private string high;
public string High
{
get { return high; }
set { high = value; }
}
private string low;
public string Low
{
get { return low; }
set { low = value; }
}
private string chart_url;
public string Chart_url
{
get { return chart_url; }
set { chart_url = value; }
}
private string market_cap;
public string Market_cap
{
get { return market_cap; }
set { market_cap = value; }
}
private string exchange;
public string Exchange
{
get { return exchange; }
set { exchange = value; }
}
private string currency;
public string Currency
{
get { return currency; }
set { currency = value; }
}
private string company;
public string Company
{
get { return company; }
set { company = value; }
}
private string y_close;
public string Y_close
{
get { return y_close; }
set { y_close = value; }
}
public Stock()
{
symbol = string.Empty;
date = string.Empty;
time = string.Empty;
trade = string.Empty;
chg = string.Empty;
perc_chg = string.Empty;
volume = string.Empty;
high = string.Empty;
low = string.Empty;
chart_url = string.Empty;
market_cap = string.Empty;
exchange = string.Empty;
currency = string.Empty;
company = string.Empty;
y_close = string.Empty;
}
}
}
兴趣点
我能够通过将更多的股票代码组合到一个 URL 中,然后在本地解析文档来减少对 Google API 的请求次数。正如您所想,随着输入的股票代码数量增加以及每 5 秒获取一次数据,查询次数可能会急剧增加。
待办事项
- 分析来自股票市场的数据并对股票价格进行一些预测。
历史
- V1.0:2013 年 7 月 9 日。