65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (13投票s)

2013 年 7 月 9 日

CPOL

2分钟阅读

viewsIcon

157692

downloadIcon

8094

在 .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 日。
© . All rights reserved.