Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Stock Quotes and Charts from Google Finance using C#

0.00/5 (No votes)
9 Jul 2013 1  
Fetching Stock Quotes using Google Finance APIs in .NET Framework 4

Introduction

This simple Windows Forms Application shows how to use the Google Finance APIs to fetch the stock quotes and charts and update them at a fixed interval using the System.Windows.Forms.Timer class.

Using the code

In order to fetch XML data from Google Finance, there is no sign up or Log in required. The following URL is used to fetch data from Google: https://www.google.com/ig/api?stock=GOOG (here, GOOG stands for Google's stock and this symbol can be replaced by another stock symbol to fetch different stock) 

Here is a simple screenshot of the XML that is returned by Google APIs for Google's stock (GOOG).

Now, we can combine two or more stocks into one URL and fetch a big XML file that can be parsed locally and hence reduce the number of requests made to Google Finance.

For example, to fetch Google (GOOG) and Apple's (AAPL) stock in one XML file, the following URL can be used:

https://www.google.com/ig/api?stock=GOOG&stock=AAPL   

Back to Coding, here is the Class diagram for the Solution: 

The following method in Stock_quotes class is used to fetch the XML data: 

/// <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);
}

To validate a quote entered by the user, we look at the "last" element (trading value) in the XML file and if it is = 0.00 or doesn't exist, then the stock quote entered by the user is in-valid. Here is the method in Stock_quotes class that validates 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 class: This is a static class that handles all the parsing of XML data. 

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 class: This class handles the internal data-structures that holds the individual stock and market data.

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: Simple Stock object class that is used to transfer the information between XDocument and 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;
        }
    }
}

Points of Interest 

I was able to reduce the number of requests that are being made to the Google APIs by combining the more stock quotes into a single URL and then parse the document locally. As, you can imagine, with more stock quotes entered and to fetch the data every 5 seconds, the number of queries can increase dramatically. 

To-do

  • Analyze the data coming from the stock market and perform some prediction of stock prices. 

History

  • V1.0: July 9th, 2013.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here