/// <summary> /// Gets a copy of this data from a date, to a date. /// </summary> /// <param name="start">Date to start from</param> /// <param name="end">Date to end at</param> /// <returns>New object with the data from the requested dates</returns> public TickerData SubSet(DateTime start, DateTime end) { TickerData copyData = new TickerData(TickerAndExchange); int copyStartIndex = -1; int copyEndIndex = -1; for (int i = 0; i < Dates.Count; i++) { if (copyStartIndex == -1 && Dates[i] >= start) { copyStartIndex = i; } if (copyEndIndex == -1 && Dates[i] >= end) { copyEndIndex = i; } if (copyStartIndex > -1 && copyEndIndex > -1) { break; } } if (copyStartIndex != -1) { if (copyEndIndex == -1 && end > Dates.Last()) { copyEndIndex = Dates.Count - 1; } int amountToCopy = (copyEndIndex - copyStartIndex) + 1; copyData.Dates.AddRange(Dates.GetRange(copyStartIndex, amountToCopy)); copyData.Open.AddRange(Open.GetRange(copyStartIndex, amountToCopy)); copyData.Close.AddRange(Close.GetRange(copyStartIndex, amountToCopy)); copyData.High.AddRange(High.GetRange(copyStartIndex, amountToCopy)); copyData.Low.AddRange(Low.GetRange(copyStartIndex, amountToCopy)); copyData.Volume.AddRange(Volume.GetRange(copyStartIndex, amountToCopy)); // Extras copyData.Typical.AddRange(Typical.GetRange(copyStartIndex, amountToCopy)); copyData.Median.AddRange(Median.GetRange(copyStartIndex, amountToCopy)); copyData.HigherTimeframeTrend.AddRange(HigherTimeframeTrend.GetRange(copyStartIndex, amountToCopy)); for (int i = 0; i < HigherTimeframeValueStrings.Length; i++) { string key = HigherTimeframeValueStrings[i]; copyData.HigherTimeframeValues[key].AddRange(HigherTimeframeValues[key].GetRange(copyStartIndex, amountToCopy)); } copyData.Start = copyData.Dates[0]; copyData.End = copyData.Dates[copyData.Dates.Count - 1]; copyData.NumBars = copyData.Dates.Count; copyData.SaveDates(); } return(copyData); }
/// <summary> /// Creates an object of ticker data from the stream passed in. /// </summary> /// <param name="data">String of ticker data</param> /// <param name="ticker">Ticker name for this data string</param> /// <param name="isFromDisk">True if this string is loaded from our disk, saves a lot of calculation time</param> /// <param name="start">Start date of the data</param> /// <param name="end">End date of the data</param> /// <returns>Returns an object created from the ticker data string</returns> private TickerData CreateTickerDataFromString(string data, TickerExchangePair ticker, bool isFromDisk, DateTime start, DateTime end) { if (string.IsNullOrEmpty(data)) { throw new Exception("No ticker data to parse."); } using (StringReader reader = new StringReader(data)) { string line = string.Empty; // Strip off the headers if the are present if (reader.Peek() == 68) // "D" { reader.ReadLine(); } TickerData tickerData = new TickerData(ticker); // Value for an invalid date. DateTime invalidDate = new DateTime(1970, 1, 1); // Read each line of the string and convert it into numerical data and dates. do { line = reader.ReadLine(); if (line != null) { string[] splitData = line.Split(new char[] { ',' }); DateTime lineDate = DateTime.MaxValue; long lineDateDigit = 0; if (long.TryParse(splitData[0], out lineDateDigit)) { lineDate = UtilityMethods.ConvertFromUnixTimestamp(splitData[0]); } else { lineDate = DateTime.Parse(splitData[0]); } // Because of the way google returns data, we don't always get our exact dates. // What we get is an interval of dates containing the ones we asked for, so // we'll filter that data down to just the dates we want. if (start != invalidDate && lineDate < start) { continue; } if (end != invalidDate && lineDate > end) { break; } // Sometimes google has random 0's or 0.01 values for things so we'll just skip those bars. if (!IsDataFieldValid(splitData, 1) || !IsDataFieldValid(splitData, 2) || !IsDataFieldValid(splitData, 3) || !IsDataFieldValid(splitData, 4) || !IsDataFieldValid(splitData, 5)) { continue; } // Add the data to our object. double open = Convert.ToDouble(splitData[1]); double high = Convert.ToDouble(splitData[2]); double low = Convert.ToDouble(splitData[3]); double close = Convert.ToDouble(splitData[4]); long volume = Convert.ToInt64(splitData[5]); tickerData.Dates.Add(lineDate); tickerData.Open.Add(open); tickerData.High.Add(high); tickerData.Low.Add(low); tickerData.Close.Add(close); tickerData.Volume.Add(volume); tickerData.NumBars = tickerData.Dates.Count; // If this data is from the disk we don't need to calculate the extra fields since // we've already saved them in the file. if (isFromDisk) { tickerData.Typical.Add(Convert.ToDouble(splitData[(int)DataFields.Typical])); tickerData.Median.Add(Convert.ToDouble(splitData[(int)DataFields.Median])); tickerData.HigherTimeframeTrend.Add(Convert.ToDouble(splitData[(int)DataFields.HigherState])); for (int i = 0; i < TickerData.HigherTimeframeValueStrings.Length; i++) { string key = TickerData.HigherTimeframeValueStrings[i]; List <double> higherValues = tickerData.HigherTimeframeValues[key]; higherValues.Add(Convert.ToDouble(splitData[(int)DataFields.HigherValuesStart + i])); } } else { // Extra non-downloaded data. high = tickerData.High[tickerData.NumBars - 1]; low = tickerData.Low[tickerData.NumBars - 1]; close = tickerData.Close[tickerData.NumBars - 1]; tickerData.Typical.Add((high + low + close) / 3); tickerData.Median.Add((high + low) / 2); // Calculate the higher momentum state for this bar. This is a pretty // time consuming function since it has to loop back through all the // bars before (and including) this one. double lastValue = tickerData.HigherTimeframeTrend.Count > 0 ? tickerData.HigherTimeframeTrend[tickerData.HigherTimeframeTrend.Count - 1] : Order.OrderType.Long; tickerData.HigherTimeframeTrend.Add(GetHigherTimerframeExtras(tickerData, lastValue)); } } } while (line != null); tickerData.Start = tickerData.Dates[0]; tickerData.End = tickerData.Dates[tickerData.Dates.Count - 1]; tickerData.SaveDates(); return(tickerData); } }