#region Using using System; using System.Text; using System.Net; using System.IO; using System.Timers; using System.Globalization; #endregion namespace MTRACKER { public class StockEngine { #region Constructors /// /// Create an instance of StockEngine. /// /// The symbol of the quote to retrieve. public StockEngine(string symbol) { Init(symbol, false, 60000); } /// /// Create an instance of StockEngine. /// /// The symbol of the quote to retrieve. /// Specify whether or not to automatically update the quote. public StockEngine(string symbol, bool autoUpdate) { Init(symbol, autoUpdate, 60000); } /// /// Create an instance of StockEngine. /// /// The symbol of the quote to retrieve. /// Specify whether or not to automatically update the quote. /// Specify at what interval to update. In milliseconds. public StockEngine(string symbol, bool autoUpdate, int updateInterval) { Init(symbol, autoUpdate, updateInterval); } /// /// Initializes the object with data from the constructors. /// private void Init(string symbol, bool autoUpdate, int updateInterval) { UpdateInterval = updateInterval; Symbol = symbol; InitializeTimer(); AutoUpdate = autoUpdate; } #endregion #region Properties private string _Symbol; /// /// Gets or sets the symbol of the stock to retrieve. /// public string Symbol { get { return _Symbol; } set { if (String.IsNullOrEmpty(value)) throw new ArgumentException("The stock symbol is not a valid character string."); _Symbol = value; } } private bool _AutoUpdate; /// /// Gets or sets whether or not to automatically update the quote. /// public bool AutoUpdate { get { return _AutoUpdate; } set { _Timer.Enabled = value; _AutoUpdate = value; } } private int _UpdateInterval; /// /// Gets or sets at what interval to update. In milliseconds. /// public int UpdateInterval { get { return _UpdateInterval; } set { //if (value < 60000) // throw new ArgumentException("The update interval must be at least than 60.000"); _UpdateInterval = value; _Timer.Interval = value; } } private double _Value; /// /// Gets the stock quote that corresponds to the symbol specified. /// public double Value { get { return _Value; } } private DateTime _LastUpdated; /// /// Gets the time of the last retrieval. /// public DateTime LastUpdated { get { return _LastUpdated; } } #endregion #region Methods /// /// Retrieves the stock quote from the Internet. /// /// Specify the symbol of the stock to retrieve. /// The value of the stock quote. public static StockEngine Execute(string symbol) { StockEngine engine = new StockEngine(symbol, false); HttpWebRequest request = engine.CreateRequest(); engine.ProcessResponse(request); return engine; } /// /// Creates a web request to Yahoo finacial service. /// private HttpWebRequest CreateRequest() { string serverURL = "http://download.finance.yahoo.com/d/quotes.csv?s=" + Symbol + "&f=sl1d1t1c1ohgv&e=.csv"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serverURL); return request; } /// /// Retrieves the response from the web request. /// /// The request from which to get the response from. private void ProcessResponse(HttpWebRequest request) { try { using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII)) { string html = reader.ReadToEnd(); ParseQuote(html); } } } catch (WebException) { OnError(); } } /// /// Parses the retrieved HTML document in order /// to substract the right stock quote. /// /// The HTML to parse. private void ParseQuote(string html) { if (html.Contains("N/A")) throw new ArgumentException("The symbol '" + Symbol + "' does not exist (or) Data is not available."); else { string[] args = html.Split(','); CultureInfo format = new CultureInfo("en-US"); DateTime date = DateTime.Parse(args[2].Replace("\"", string.Empty), format); DateTime time = DateTime.Parse(args[3].Replace("\"", string.Empty), format); _Value = double.Parse(args[1], format); _LastUpdated = date.Add(new TimeSpan(time.Hour, time.Minute, time.Second)); OnUpdated(); } } #endregion #region Auto update /// /// The timer that controls the automatic updates. /// private readonly Timer _Timer = new Timer(); /// /// Prepares the timer for automatic updates. /// private void InitializeTimer() { _Timer.Elapsed += delegate { BeginGetQuote(); }; _Timer.Interval = _UpdateInterval; } /// /// Starts the asynchonous data retrieval. /// private void BeginGetQuote() { _Timer.Stop(); HttpWebRequest request = CreateRequest(); request.BeginGetResponse(EndGetQuote, request); } /// /// Ends the asynchonous data retrieval. /// private void EndGetQuote(IAsyncResult stateInfo) { HttpWebRequest request = stateInfo.AsyncState as HttpWebRequest; ProcessResponse(request); _Timer.Start(); } #endregion #region Events /// /// Occurs when the quote has been updated. /// public event EventHandler Updated; protected virtual void OnUpdated() { if (Updated != null) { Updated(this, new EventArgs()); } } /// /// Occurs when the the stock quote retrievel fails. /// public event EventHandler Error; protected virtual void OnError() { if (Error != null) { Error(this, new EventArgs()); } } #endregion } }