Click here to Skip to main content
Click here to Skip to main content

Stock Quotes and Charts from Google Finance using C#

, 9 Jul 2013
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Amanpreet Mukker
Software Developer
United States United States
No Biography provided
Follow on   Twitter

Comments and Discussions

 
QuestionNot working Pinmemberjenit.vaghasiya9-Jul-14 2:00 
QuestionGoogle Finance API no longer supported. This project is obsolete. PinmemberAndrew Durber8-Jul-14 2:16 
QuestionGood Article but returning error now PinmemberRajibdotnet057-Apr-14 6:08 
AnswerRe: Good Article but returning error now PinmemberAndrew Durber8-Jul-14 2:12 
GeneralMy vote of 2 PinprofessionalMember 103935164-Apr-14 21:04 
QuestionError Occured please simply for me urgent PinmemberMember 989847331-Dec-13 19:15 
QuestionGot Error Plz Help Me Fast Pinmemberavinashkalola25-Dec-13 21:21 
AnswerRe: Got Error Plz Help Me Fast PinmemberAmanpreet Mukker27-Dec-13 3:55 
QuestionError Pinmemberdanny3335-Dec-13 2:59 
AnswerRe: Error Pinmemberavinashkalola25-Dec-13 21:22 
GeneralRe: Error Pinmemberdanny33329-Dec-13 23:31 
GeneralRe: Error Pinmemberdanny33331-Dec-13 3:54 
QuestionRe: Error PinmemberLisa Sosa26-Dec-13 23:44 
AnswerRe: Error Pinmemberdanny33331-Dec-13 3:54 
QuestionWell-done! PinmemberTim Claason4-Dec-13 9:33 
QuestionCan your code/tool be extended to download real time quotes from google finance and feed it to Amibroker PinmemberRaj23230-Nov-13 21:10 
AnswerRe: Can your code/tool be extended to download real time quotes from google finance and feed it to Amibroker PinmemberAmanpreet Mukker5-Dec-13 6:13 
QuestionNeed to close - error Pinmemberwizajit@gmail.com11-Nov-13 3:43 
AnswerRe: Need to close - error PinmemberAmanpreet Mukker13-Nov-13 3:15 
GeneralRe: Need to close - error Pinmemberwizajit@gmail.com14-Nov-13 6:35 
GeneralRe: Need to close - error PinmemberAmanpreet Mukker15-Nov-13 8:34 
GeneralRe: Need to close - error Pinmemberwizajit@gmail.com17-Nov-13 23:16 
GeneralExcellent article PinmemberRavi Vooda16-Sep-13 6:43 
GeneralRe: Excellent article PinmemberAmanpreet Mukker17-Sep-13 4:55 
QuestionIndian Stock Market Data Pinmemberdanny33323-Aug-13 4:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 9 Jul 2013
Article Copyright 2013 by Amanpreet Mukker
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid