/// <summary>
        /// Retrieves stock history data from Google for the specified stock.
        /// </summary>
        /// <param name="stock">The stock for which data will be retrieved.</param>
        /// <param name="startDate">The start date of the data set.</param>
        /// <param name="endDate">The end date of the data set.</param>
        /// <returns>
        /// The stock history read from Google.
        /// </returns>
        public List<StockDaily> GetDataFromGoogle(Stock stock, DateTime startDate, DateTime endDate)
        {
            var history = new List<StockDaily>();

            // Read all of the lines from the CSV file.
            var csvLines = GetCsvData(stock, startDate, endDate).Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            // Iterate through each line to populate the price history...
            // ...skip the first line which contains the column headers.
            for (var index = 1; index < csvLines.Length; index++)
            {
                var fields = csvLines[index].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                // Construct the interval data from the fields of the CSV line.
                var priceData = new StockDaily
                    {
                        Exchange = stock.Exchange,
                        Ticker = stock.Ticker,
                        Date = DateTime.Parse(fields[GoogleCsvDateColumnIndex]),
                        OpenPrice = Convert.ToSingle(fields[GoogleCsvOpenPriceColumnIndex]),
                        HighPrice = Convert.ToSingle(fields[GoogleCsvHighPriceColumnIndex]),
                        LowPrice = Convert.ToSingle(fields[GoogleCsvLowPriceColumnIndex]),
                        ClosePrice = Convert.ToSingle(fields[GoogleCsvClosePriceColumnIndex]),
                        Volume =
                            Convert.ToInt64(fields[GoogleCsvVolumeColumnIndex]) <= int.MaxValue
                                ? Convert.ToInt32(fields[GoogleCsvVolumeColumnIndex])
                                : int.MaxValue
                    };

                // Google sometimes provides data for non-trading days.  Weed these out based on volume.
                if (priceData.Volume > 0)
                {
                    // Google also sometimes has missing data points...we'll filter those out too.
                    const float Epsilon = 0.000001f;
                    if (Math.Abs(priceData.OpenPrice - 0.0f) < Epsilon
                        || Math.Abs(priceData.ClosePrice - 0.0f) < Epsilon
                        || Math.Abs(priceData.HighPrice - 0.0f) < Epsilon
                        || Math.Abs(priceData.LowPrice - 0.0f) < Epsilon)
                    {
                        Console.WriteLine("WARNING:  Filtering out data from " + priceData.Date + " due to missing price values!");
                        Console.WriteLine();
                    }
                    else
                    {
                        history.Add(priceData);
                    }
                }
            }

            // Sort the history into chronological order (Google CSV's are in reverse-chronological order).
            history.Sort(CompareDailyStockIntervals);

            return history;
        }
        /// <summary>
        /// Gets CSV data from Google containing 5 years of historical data for the specified stock..
        /// </summary>
        /// <param name="stock">The stock for which data will be retrieved.</param>
        /// <param name="startDate">The start date of the data set.</param>
        /// <param name="endDate">The end date of the data set.</param>
        /// <returns>
        /// The contents of the retrieved CSV file.
        /// </returns>
        private static string GetCsvData(Stock stock, DateTime startDate, DateTime endDate)
        {
            // Construct a Google URL with the correct parameters.
            var url = "http://www.google.com/finance/historical?q=" + stock.Exchange + "%3A" + stock.Ticker + "&startdate= " + startDate.ToShortDateString() + "&enddate=" + endDate.ToShortDateString() + "&output=csv";

            StreamReader reader = null;

            try
            {
                // Retrieve and return the raw CSV data served by Google.
                var webClient = new WebClient();
                var stream = webClient.OpenRead(url);
                Debug.Assert(stream != null, "stream != null");
                reader = new StreamReader(stream);

                return reader.ReadToEnd();
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
            }
        }
 /// <summary>
 /// Deprecated Method for adding a new object to the Stocks EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
 /// </summary>
 public void AddToStocks(Stock stock)
 {
     base.AddObject("Stocks", stock);
 }
 /// <summary>
 /// Create a new Stock object.
 /// </summary>
 /// <param name="exchange">Initial value of the Exchange property.</param>
 /// <param name="ticker">Initial value of the Ticker property.</param>
 /// <param name="companyName">Initial value of the CompanyName property.</param>
 public static Stock CreateStock(global::System.String exchange, global::System.String ticker, global::System.String companyName)
 {
     Stock stock = new Stock();
     stock.Exchange = exchange;
     stock.Ticker = ticker;
     stock.CompanyName = companyName;
     return stock;
 }
        /// <summary>
        /// Reads a list of stocks for the specified stock exchange from the specified file name.
        /// </summary>
        /// <param name="exchangeId">The ID of the stock exchange.</param>
        /// <param name="companyListFile">The file containing the list of stocks for the exchange.</param>
        /// <returns>
        /// A list of stocks for the specified stock exchange.
        /// </returns>
        private List<Stock> ReadStockListForExchange(string exchangeId, string companyListFile)
        {
            var stocks = new List<Stock>();
            var csvLines = File.ReadAllLines(companyListFile);
            var tickerRegEx = new Regex(@"^[A-Z]*$");
            const int MaxNameLength = 50;

            // Loop through each line of the CSV file and create a new Stock object.
            // Start with index 1 to skip the header line.
            for (var index = 1; index < csvLines.Length; index++)
            {
                var fields = csvLines[index].Replace("\"", string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                // Validate the ticker symbol
                var ticker = fields[0].ToUpper(CultureInfo.InvariantCulture);
                if (!tickerRegEx.IsMatch(ticker))
                {
                    // This isn't a standard ticker with only capital letters.
                    continue;
                }

                // Length-limit the company name.
                var name = fields[1];
                if (name.Length > MaxNameLength)
                {
                    name = name.Substring(0, MaxNameLength);
                }

                // Create and add the stock.
                var stock = new Stock { Exchange = exchangeId, Ticker = ticker, CompanyName = name };
                stocks.Add(stock);
            }

            return stocks;
        }