Stock quote and chart from Yahoo! in C#
This article introduces you to how to access stock quotes from the Yahoo! Finance service.
Introduction
The U.S. stock market went down today and I lost a lot of money, but hopefully everyone here has made money from the stock market. Anyway, in this article, I will introduce you to how to access stock quotes with a 20 minute delay from the Yahoo! Finance service. You can download the source code and modify it according to your needs. Click here to see the live demo: http://www.igotmessage.com/Finance.aspx.
Background
It is easy to download stock data from Yahoo!. For example, copy and paste this URL into your browser address: http://download.finance.yahoo.com/d/quotes.csv?s=YHOO+GOOG+MSFT&f=sl1d1t1c1hgvbap2.
Depending on your Internet browser setting, you may be asked to save the results into a filename called "quotes.csv" or the following will appear in your browser:
"YHOO",14.8188,"6/22/2009","1:20pm",-0.9812,15.61,14.80,13944065,14.81,14.82,"-6.21%"
"GOOG",402.25,"6/22/2009","1:20pm",-17.84,417.49,402.11,2399141,402.14,402.27,"-4.25%"
"MSFT",23.359,"6/22/2009","1:20pm",-0.711,23.95,23.32,36595084,23.35,23.36,"-2.95%"
The URL starts with a base URL and then adds parameters and values after a question mark (?).
- http://quote.yahoo.com/d/quotes.csv? - The default URL to get the information
- 's=' - Appends a bunch of stock symbols separated by "+" after this
- & - to join the string
- 'f=' - Appends a bunch of special tags after this with no spaces in between
The following are special tags provided by Yahoo! Finance:
a | Ask | a2 | Average Daily Volume | a5 | Ask Size |
b | Bid | b2 | Ask (Real-time) | b3 | Bid (Real-time) |
b4 | Book Value | b6 | Bid Size | c | Change & Percent Change |
c1 | Change | c3 | Commission | c6 | Change (Real-time) |
c8 | After Hours Change (Real-time) | d | Dividend/Share | d1 | Last Trade Date |
d2 | Trade Date | e | Earnings/Share | e1 | Error Indication (returned for symbol changed / invalid) |
e7 | EPS Estimate Current Year | e8 | EPS Estimate Next Year | e9 | EPS Estimate Next Quarter |
f6 | Float Shares | g | Day’s Low | h | Day’s High |
j | 52-week Low | k | 52-week High | g1 | Holdings Gain Percent |
g3 | Annualized Gain | g4 | Holdings Gain | g5 | Holdings Gain Percent (Real-time) |
g6 | Holdings Gain (Real-time) | i | More Info | i5 | Order Book (Real-time) |
j1 | Market Capitalization | j3 | Market Cap (Real-time) | j4 | EBITDA |
j5 | Change From 52-week Low | j6 | Percent Change From 52-week Low | k1 | Last Trade (Real-time) With Time |
k2 | Change Percent (Real-time) | k3 | Last Trade Size | k4 | Change From 52-week High |
k5 | Percebt Change From 52-week High | l | Last Trade (With Time) | l1 | Last Trade (Price Only) |
l2 | High Limit | l3 | Low Limit | m | Day’s Range |
m2 | Day’s Range (Real-time) | m3 | 50-day Moving Average | m4 | 200-day Moving Average |
m5 | Change From 200-day Moving Average | m6 | Percent Change From 200-day Moving Average | m7 | Change From 50-day Moving Average |
m8 | Percent Change From 50-day Moving Average | n | Name | n4 | Notes |
o | Open | p | Previous Close | p1 | Price Paid |
p2 | Change in Percent | p5 | Price/Sales | p6 | Price/Book |
q | Ex-Dividend Date | r | P/E Ratio | r1 | Dividend Pay Date |
r2 | P/E Ratio (Real-time) | r5 | PEG Ratio | r6 | Price/EPS Estimate Current Year |
r7 | Price/EPS Estimate Next Year | s | Symbol | s1 | Shares Owned |
s7 | Short Ratio | t1 | Last Trade Time | t6 | Trade Links |
t7 | Ticker Trend | t8 | 1 yr Target Price | v | Volume/td> |
v1 | Holdings Value | v7 | Holdings Value (Real-time)/td> | w | 52-week Range |
w1 | Day’s Value Change | w4 | Day’s Value Change (Real-time) | x | Stock Exchange |
y | Dividend Yield |
Let's say that you want to have the following quotes: YHOO, GOOG, GE, MSFT. You want to get the Name, Last Price, Last Traded Volume, 52-Week High. From the table above, you can find out that the special tags needed are as follows:
- Name - n
- Last Price- l1
- Last Traded Volume - v
- 52-Week High - k
- 52-Week Low - j
All you need to do is to construct the URL with the given special tags above. The URL will look like this: http://quote.yahoo.com/d/quotes.csv?s=YHOO+GOOG+GE+MSFT&f=nl1vkj.
Chart
It's also easy to get stock charts from Yahoo! Finance. All you need to do is make a request for the image with the identical URL that is in the Yahoo! Finance page. For example, this is the last three months of Microsoft stock: http://chart.finance.yahoo.com/c/3m/d/msft.
The URL also starts with a base URL and then adds a stock symbol after that.
Small chart:
- 1 day: http://ichart.yahoo.com/t?s=MSFT
- 5 days: http://ichart.yahoo.com/v?s=MSFT
- 1 year: http://ichart.finance.yahoo.com/c/bb/m/msft
Big chart:
- 1 day: http://ichart.finance.yahoo.com/b?s=MSFT
- 5 days: http://ichart.finance.yahoo.com/w?s=MSFT
- 3 months: http://chart.finance.yahoo.com/c/3m/msft
- 6 months: http://chart.finance.yahoo.com/c/6m/msft
- 1 year: http://chart.finance.yahoo.com/c/1y/msft
- 2 years: http://chart.finance.yahoo.com/c/2y/msft
- 5 years: http://chart.finance.yahoo.com/c/5y/msft
- Max: http://chart.finance.yahoo.com/c/my/msft
Implementation
First, create a new ASP.NET Web Application by using Microsoft Visual C# .NET.
- Open Visual Studio .NET.
- On the File menu, point to New, and then click Project.
- In the New Project dialog box, under Project Types, click Visual C# Projects. Under Templates, click ASP.NET Web Application.
- In the Name text box, type sample.
- Click OK.
Now, open the Default.aspx page and add the following code:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="sample._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Stock quote and chart from Yahoo in C#</title>
<script type="text/javascript" language="JavaScript">
/// <summary>
/// This function will be called when user clicks the Get Quotes button.
/// </summary>
/// <returns>Always return false.</returns>
function SendRequest()
{
var txtSymbol = document.getElementById("txtSymbol");
// Refresh the page.
window.location = "default.aspx?s=" + txtSymbol.value;
return false;
}
/// <summary>
/// The functyion will be called when a keyboard key is pressed in the textbox.
/// </summary>
/// <param name="e">Onkeypress event.</param>
/// <returns>Return true if user presses Enter key; otherwise false.</returns>
function CheckEnter(e)
{
if ((e.keyCode && e.keyCode == 13) || (e.which && e.which == 13))
// Enter is pressed in the textbox.
return SendRequest();
return true;
}
/// <summary>
/// The function will be called when user
// changes the chart type to another type.
/// </summary>
/// <param name="type">Chart type.</param>
/// <param name="num">Stock number.</param>
/// <param name="symbol">Stock symobl.</param>
function changeChart(type, num, symbol)
{
// All the DIVs are inside the main DIV
// and defined in the code-behind class.
var div1d=document.getElementById("div1d_"+num);
var div5d = document.getElementById("div5d_" + num);
var div3m = document.getElementById("div3m_" + num);
var div6m = document.getElementById("div6m_" + num);
var div1y = document.getElementById("div1y_" + num);
var div2y = document.getElementById("div2y_" + num);
var div5y = document.getElementById("div5y_" + num);
var divMax = document.getElementById("divMax_" + num);
var divChart = document.getElementById("imgChart_" + num);
// Set innerHTML property.
div1d.innerHTML = "1d";
div5d.innerHTML="5d";
div3m.innerHTML="3m";
div6m.innerHTML="6m";
div1y.innerHTML="1y";
div2y.innerHTML="2y";
div5y.innerHTML="5y";
divMax.innerHTML="Max";
// Use a random number to defeat cache.
var rand_no = Math.random();
rand_no = rand_no * 100000000;
// Display the stock chart.
switch(type)
{
case 1: // 5 days
div5d.innerHTML="<b>5d</b>";
divChart.src = "http://ichart.finance.yahoo.com/w?s=" +
symbol + "&" + rand_no;
break;
case 2: // 3 months
div3m.innerHTML="<b>3m</b>";
divChart.src = "http://chart.finance.yahoo.com/c/3m/" +
symbol + "?" + rand_no;
break;
case 3: // 6 months
div6m.innerHTML = "<b>6m</b>";
divChart.src = "http://chart.finance.yahoo.com/c/6m/" +
symbol + "?" + rand_no;
break;
case 4: // 1 year
div1y.innerHTML = "<b>1y</b>";
divChart.src = "http://chart.finance.yahoo.com/c/1y/" +
symbol + "?" + rand_no;
break;
case 5: // 2 years
div2y.innerHTML = "<b>2y</b>";
divChart.src = "http://chart.finance.yahoo.com/c/2y/" +
symbol + "?" + rand_no;
break;
case 6: // 5 years
div5y.innerHTML = "<b>5y</b>";
divChart.src = "http://chart.finance.yahoo.com/c/5y/" +
symbol + "?" + rand_no;
break;
case 7: // Max
divMax.innerHTML = "<b>msx</b>";
divChart.src = "http://chart.finance.yahoo.com/c/my/" +
symbol + "?" + rand_no;
break;
case 0: // 1 day
default:
div1d.innerHTML = "<b>1d</b>";
divChart.src = "http://ichart.finance.yahoo.com/b?s=" +
symbol + "&" + rand_no;
break;
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<table width="100%" border="0"
cellspacing="0" cellpadding="0">
<tr valign="top">
<td style="font-family: Arial, Helvetica, sans-serif;
font-size: 14px; color: #000; text-decoration: none;">
<input type="text" value="" id="txtSymbol"
runat="server" onkeypress="return CheckEnter(event);" />
<input type="button" value="Get Quotes"
onclick="return SendRequest();" />
<br />
<span style="font-family: Arial, Helvetica, sans-serif;
font-size: 11px; color: #666;">
e.g. "YHOO or YHOO GOOG"
</span>
<%if (m_symbol != "") {%>
<div id="divService" runat="server">
<!-- Main DIV: this DIV contains text and DIVs
that displays stock quotes and chart. -->
</div>
<%}%>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Next, open the code-behind page (Default.aspx.cs) and write this code:
using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Net;
using System.Text;
namespace sample
{
public partial class _Default : System.Web.UI.Page
{
// Stock symbols seperated by space or comma.
protected string m_symbol = "";
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// The page is being loaded and accessed for the first time.
// Retrieve user input from the form.
if (Request.QueryString["s"] == null)
// Set the default stock symbol to YHOO.
m_symbol = "YHOO";
else
// Get the user's input.
m_symbol = Request.QueryString["s"].ToString().ToUpper();
// Update the textbox value.
txtSymbol.Value = m_symbol;
// This DIV that contains text and DIVs
// that displays stock quotes and chart from Yahoo.
// Set the innerHTML property to replaces the existing content of the DIV.
divService.InnerHtml = "<br />";
if (m_symbol.Trim() != "")
{
try
{
// Return the stock quote data in XML format.
String arg = GetQuote(m_symbol.Trim());
if (arg == null)
return;
// Read XML.
// Declare an XmlDocument object to represents an XML document.
XmlDocument xd = new XmlDocument();
// Loads the XML data from a stream.
xd.LoadXml(arg);
// Read XSLT
// Declare an XslCompiledTransform object
// to transform XML data using an XSLT style sheet.
XslCompiledTransform xslt = new XslCompiledTransform();
// Use the Load method to load the Xsl transform object.
xslt.Load(Server.MapPath("stock.xsl"));
// Transform the XML document into HTML.
StringWriter fs = new StringWriter();
xslt.Transform(xd.CreateNavigator(), null, fs);
string result = fs.ToString();
// Replace the characters "<" and ">"
// back to "<" and ">".
divService.InnerHtml = "<br />" +
result.Replace("<", "<").Replace(
">", "<") + "<br />";
// Display stock charts.
String[] symbols = m_symbol.Replace(",", " ").Split(' ');
// Loop through each stock
for (int i = 0; i < symbols.Length; ++i)
{
if (symbols[i].Trim() == "")
continue;
int index =
divService.InnerHtml.ToLower().IndexOf(
symbols[i].Trim().ToLower() +
" is invalid.");
// If index = -1, the stock symbol is valid.
if (index == -1)
{
// Use a random number to defeat cache.
Random random = new Random();
divService.InnerHtml += "<img id='imgChart_" +
i.ToString() +
"' src='http://ichart.finance.yahoo.com/b?s=" +
symbols[i].Trim().ToUpper() + "& " +
random.Next() + "' border=0><br />";
// 1 days
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(0," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div1d_" + i.ToString() +
"'><b>1d</b></span></a> ";
// 5 days
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(1," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div5d_" + i.ToString() +
"'>5d</span></a> ";
// 3 months
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(2," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div3m_" + i.ToString() +
"'>3m</span></a>& ";
// 6 months
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(3," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div6m_" + i.ToString() +
"'>6m</span></a> ";
// 1 yeas
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(4," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div1y_" + i.ToString() +
"'>1y</span></a> ";
// 2 years
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(5," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div2y_" + i.ToString() +
"'>2y</span></a> ";
// 5 years
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(6," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='div5y_" + i.ToString() +
"'>5y</span></a> ";
// Max
divService.InnerHtml +=
"<a style='font-family: Arial, Helvetica, sans-serif; " +
"font-size: 14px; color: Blue;' " +
"href='javascript:changeChart(7," +
i.ToString() + ", \"" + symbols[i].ToLower() +
"\");'><span id='divMax_" + i.ToString() +
"'>Max</span></a>" +
"<br><br /><br /> ";
}
}
}
catch
{
// Handle exceptions
}
}
}
}
/// <summary>
/// This function handles and parses multiple stock symbols as input parameters
/// and builds a valid XML return document.
/// </summary>
/// <param name="symbol">A bunch of stock symbols
/// seperated by space or comma</param>
/// <returns>Return stock quote data in XML format</returns>
public string GetQuote(string symbol)
{
// Set the return string to null.
string result = null;
try
{
// Use Yahoo finance service to download stock data from Yahoo
string yahooURL = @"http://download.finance.yahoo.com/d/quotes.csv?s=" +
symbol + "&f=sl1d1t1c1hgvbap2";
string[] symbols = symbol.Replace(",", " ").Split(' ');
// Initialize a new WebRequest.
HttpWebRequest webreq = (HttpWebRequest)WebRequest.Create(yahooURL);
// Get the response from the Internet resource.
HttpWebResponse webresp = (HttpWebResponse)webreq.GetResponse();
// Read the body of the response from the server.
StreamReader strm =
new StreamReader(webresp.GetResponseStream(), Encoding.ASCII);
// Construct a XML in string format.
string tmp = " ";
string content = "";
for (int i = 0; i < symbols.Length; i++)
{
// Loop through each line from the stream,
// building the return XML Document string
if (symbols[i].Trim() == "")
continue;
content = strm.ReadLine().Replace("\"", "");
string[] contents = content.ToString().Split(',');
// If contents[2] = "N/A". the stock symbol is invalid.
if (contents[2] == "N/A")
{
// Construct XML via strings.
tmp += "<Stock>";
// "<" and ">" are illegal
// in XML elements. Replace the characters "<"
// and ">" to ">" and "<".
tmp += "<Symbol><span style='color:red'>" +
symbols[i].ToUpper() +
" is invalid.</span></Symbol>";
tmp += "<Last></Last>";
tmp += "<Date></Date>";
tmp += "<Time></Time>";
tmp += "<Change></Change>";
tmp += "<High></High>";
tmp += "<Low></Low>";
tmp += "<Volume></Volume>";
tmp += "<Bid></Bid>";
tmp += "<Ask></Ask>";
tmp += "<Ask></Ask>";
tmp += "</Stock>";
}
else
{
//construct XML via strings.
tmp += "<Stock>";
tmp += "<Symbol>" + contents[0] + "</Symbol>";
try
{
tmp += "<Last>" +
String.Format("{0:c}", Convert.ToDouble(contents[1])) +
"</Last>";
}
catch
{
tmp += "<Last>" + contents[1] + "</Last>";
}
tmp += "<Date>" + contents[2] + "</Date>";
tmp += "<Time>" + contents[3] + "</Time>";
// "<" and ">" are illegal in XML elements.
// Replace the characters "<" and ">"
// to ">" and "<".
if (contents[4].Trim().Substring(0, 1) == "-")
tmp += "<Change><span style='color:red'>" +
contents[4] + "(" + contents[10] + ")" +
"<span></Change>";
else if (contents[4].Trim().Substring(0, 1) == "+")
tmp += "<Change><span style='color:green'>" +
contents[4] + "(" + contents[10] + ")" +
"<span></Change>";
else
tmp += "<Change>" + contents[4] + "(" +
contents[10] + ")" + "</Change>";
tmp += "<High>" + contents[5] + "</High>";
tmp += "<Low>" + contents[6] + "</Low>";
try
{
tmp += "<Volume>" + String.Format("{0:0,0}",
Convert.ToInt64(contents[7])) + "</Volume>";
}
catch
{
tmp += "<Volume>" + contents[7] + "</Volume>";
}
tmp += "<Bid>" + contents[8] + "</Bid>";
tmp += "<Ask>" + contents[9] + "</Ask>";
tmp += "</Stock>";
}
// Set the return string
result += tmp;
tmp = "";
}
// Set the return string
result += "</StockQuotes>";
// Close the StreamReader object.
strm.Close();
}
catch
{
// Handle exceptions.
}
// Return the stock quote data in XML format.
return result;
}
}
}
Next, add a new XSLT file named stock.xsl to the project. With this XSLT, we can transform the stock quotes XML document into HTML.
- In Solution Explorer, select the project.
- On the Project menu, click Add New Item. The Add New Item dialog box appears.
- Click Data.
- In the right pane, click the XSLT file.
- Rename the item to styles.css.
- Click Open.
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<TABLE width="770" STYLE="border:1px solid black">
<TR STYLE="font-size:14px; font-family:Arial,
Helvetica, sans-serif; font-weight:bold">
<TD>Symbol</TD>
<TD>Date</TD>
<TD>Time</TD>
<TD>Trade</TD>
<TD>% Chg</TD>
<TD>Bid</TD>
<TD>Ask</TD>
<TD>Volume</TD>
<TD>High</TD>
<TD>Low</TD>
</TR>
<xsl:for-each select="StockQuotes/Stock">
<TR STYLE="font-family:Arial, Helvetica, sans-serif;
font-size:14px; padding:0px 2px">
<TD>
<xsl:value-of select="Symbol" />
</TD>
<TD>
<xsl:value-of select="Date" />
</TD>
<TD>
<xsl:value-of select="Time" />
</TD>
<TD>
<xsl:value-of select="Last" />
</TD>
<TD>
<xsl:value-of select="Change" />
</TD>
<TD>
<xsl:value-of select="Bid" />
</TD>
<TD>
<xsl:value-of select="Ask" />
</TD>
<TD>
<xsl:value-of select="Volume" />
</TD>
<TD>
<xsl:value-of select="High" />
</TD>
<TD>
<xsl:value-of select="Low" />
</TD>
</TR>
</xsl:for-each>
</TABLE>
</html>
</xsl:template>
</xsl:stylesheet>
Finally, press Control+F5 to run the project.
Conclusion
This article walked you through a step-by-step guide of how to get stock quote data from Yahoo! and display it using C# .NET. I am sure there are a lot of things that can be improved. For example, you can use AJAX technology to update stock quotes automatically without refreshing the whole page. I hope this article gives you some ideas of where to start. For more information, please go to: http://www.igotmessage.com/StockQuote.aspx.