///Cloner Constructor: public ChartPoint(ChartPoint point) { this.x = point.x; this.y = point.y; }
/// <summary> /// Add a new point to this series: /// </summary> /// <param name="time">Time of the chart point</param> /// <param name="value">Value of the chart point</param> /// <param name="liveMode">This is a live mode point</param> public void AddPoint(DateTime time, decimal value, bool liveMode = false) { if (Values.Count >= 4000 && !liveMode) { // perform rate limiting in backtest mode return; } var chartPoint = new ChartPoint(time, value); if (Values.Count > 0 && Values[Values.Count - 1].x == chartPoint.x) { // duplicate points at the same time, overwrite the value Values[Values.Count - 1] = chartPoint; } else { Values.Add(chartPoint); } }
///Cloner Constructor: public ChartPoint(ChartPoint point) { x = point.x; y = point.y.SmartRounding(); }
///Cloner Constructor: public ChartPoint(ChartPoint point) { x = point.x; y = point.y; }
/// <summary> /// Linear interpolation used for sampling /// </summary> private static decimal Interpolate(ChartPoint previous, ChartPoint current, long target) { var deltaTicks = current.x - previous.x; // if they're at the same time return the current value if (deltaTicks == 0) { return current.y; } double percentage = (target - previous.x) / (double)deltaTicks; // y=mx+b return (current.y - previous.y) * (decimal)percentage + previous.y; }
///Cloner Constructor: public ChartPoint(ChartPoint point) { x = point.x; y = Round(point.y); }
/// <summary> /// Linear interpolation used for sampling /// </summary> private static decimal Interpolate(ChartPoint previous, ChartPoint current, long target) { var deltaTicks = current.x - previous.x; double percentage = (target - previous.x) / (double)deltaTicks; // y=mx+b return (current.y - previous.y) * (decimal)percentage + previous.y; }
/// <summary> /// Samples the given series /// </summary> /// <param name="series">The series to be sampled</param> /// <param name="start">The date to start sampling, if before start of data then start of data will be used</param> /// <param name="stop">The date to stop sampling, if after stop of data, then stop of data will be used</param> /// <returns>The sampled series</returns> public Series Sample(Series series, DateTime start, DateTime stop) { var sampled = new Series(series.Name, series.SeriesType); // chart point times are always in universal, so force it here as well double nextSample = Time.DateTimeToUnixTimeStamp(start.ToUniversalTime()); double unixStopDate = Time.DateTimeToUnixTimeStamp(stop.ToUniversalTime()); // we can't sample a single point and it doesn't make sense to sample scatter plots // in this case just copy the raw data if (series.Values.Count < 2 || series.SeriesType == SeriesType.Scatter) { // we can minimally verify we're within the start/stop interval foreach (var point in series.Values) { if (point.x >= nextSample && point.x <= unixStopDate) { sampled.Values.Add(point); } } return(sampled); } var enumerator = series.Values.GetEnumerator(); // initialize current/previous enumerator.MoveNext(); ChartPoint previous = enumerator.Current; enumerator.MoveNext(); ChartPoint current = enumerator.Current; // make sure we don't start sampling before the data begins if (nextSample < previous.x) { nextSample = previous.x; } // make sure to advance into the requestd time frame before sampling while (current.x < nextSample && enumerator.MoveNext()) { previous = current; current = enumerator.Current; } do { // advance our current/previous if (nextSample > current.x) { if (enumerator.MoveNext()) { previous = current; current = enumerator.Current; } else { break; } } // iterate until we pass where we want our next point while (nextSample <= current.x && nextSample <= unixStopDate) { var value = Interpolate(previous, current, (long)nextSample); sampled.Values.Add(new ChartPoint { x = (long)nextSample, y = value }); nextSample += _seconds; } // if we've passed our stop then we're finished sampling if (nextSample > unixStopDate) { break; } }while (true); return(sampled); }
/// <summary> /// Samples the given series /// </summary> /// <param name="series">The series to be sampled</param> /// <param name="start">The date to start sampling, if before start of data then start of data will be used</param> /// <param name="stop">The date to stop sampling, if after stop of data, then stop of data will be used</param> /// <returns>The sampled series</returns> public Series Sample(Series series, DateTime start, DateTime stop) { var sampled = new Series(series.Name, series.SeriesType); if (series.Values.Count < 2) { // return new instance, but keep the same data sampled.Values.AddRange(series.Values); return(sampled); } double nextSample = Time.DateTimeToUnixTimeStamp(start); double unixStopDate = Time.DateTimeToUnixTimeStamp(stop); var enumerator = series.Values.GetEnumerator(); // initialize current/previous enumerator.MoveNext(); ChartPoint previous = enumerator.Current; enumerator.MoveNext(); ChartPoint current = enumerator.Current; // make sure we don't start sampling before the data begins if (nextSample < previous.x) { nextSample = previous.x; } // make sure to advance into the requestd time frame before sampling while (current.x < nextSample && enumerator.MoveNext()) { previous = current; current = enumerator.Current; } do { // advance our current/previous if (nextSample > current.x) { if (enumerator.MoveNext()) { previous = current; current = enumerator.Current; } else { break; } } // iterate until we pass where we want our next point while (nextSample <= current.x && nextSample <= unixStopDate) { var value = Interpolate(previous, current, (long)nextSample); sampled.Values.Add(new ChartPoint { x = (long)nextSample, y = value }); nextSample += _seconds; } // if we've passed our stop then we're finished sampling if (nextSample > unixStopDate) { break; } }while (true); return(sampled); }