Skip to content

Commit

Permalink
Rounding when sampling charts
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin-Molinero committed Jan 25, 2024
1 parent 738231b commit 4c95322
Showing 1 changed file with 19 additions and 16 deletions.
35 changes: 19 additions & 16 deletions Common/SeriesSampler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public virtual BaseSeries Sample(BaseSeries series, DateTime start, DateTime sto
if (dataDiff >= Step)
{
// we don't want to subsample this case, directly return what we are given as long as is within the range
return GetIdentitySeries(series.Clone(empty: true), series, start, stop, truncateValues: false);
return GetIdentitySeries(series.Clone(empty: true), series, start, stop, truncateValues: false, roundTime: series.SeriesType == SeriesType.StackedArea);
}
}

Expand Down Expand Up @@ -125,13 +125,13 @@ private Series SampleSeries(Series series, DateTime start, DateTime stop, bool t
{
var sampled = (Series)series.Clone(empty: true);

var nextSampleTime = start;
var nextSampleTime = start.RoundUp(Step);

// 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)
{
return GetIdentitySeries(sampled, series, start, stop, truncateValues);
return GetIdentitySeries(sampled, series, start, stop, truncateValues, series.SeriesType == SeriesType.StackedArea);
}

var enumerator = series.Values.Cast<ChartPoint>().GetEnumerator();
Expand All @@ -143,9 +143,9 @@ private Series SampleSeries(Series series, DateTime start, DateTime stop, bool t
var current = enumerator.Current;

// make sure we don't start sampling before the data begins
if (nextSampleTime < previous.Time)
while (nextSampleTime < previous.Time)
{
nextSampleTime = previous.Time;
nextSampleTime += Step;
}

// make sure to advance into the requested time frame before sampling
Expand All @@ -168,7 +168,7 @@ private Series SampleSeries(Series series, DateTime start, DateTime stop, bool t
}
else
{
sampledPoint = TruncateValue(Interpolate(previous, current, nextSampleTime, (decimal)Step.TotalSeconds), truncateValues, clone: false);
sampledPoint = TruncateValue(Interpolate(previous, current, nextSampleTime, (decimal)Step.TotalSeconds), truncateValues, clone: false, roundTime: false);
}

nextSampleTime += Step;
Expand Down Expand Up @@ -224,7 +224,7 @@ private CandlestickSeries SampleCandlestickSeries(CandlestickSeries series, Date
// we can't sample a single point, so just copy the raw data
if (seriesSize < 2)
{
return GetIdentitySeries(sampledSeries, series, start, stop, truncateValues);
return GetIdentitySeries(sampledSeries, series, start, stop, truncateValues, roundTime: false);
}

// Make sure we don't start sampling before the data begins.
Expand All @@ -240,7 +240,7 @@ private CandlestickSeries SampleCandlestickSeries(CandlestickSeries series, Date
if (startIndex < 0)
{
// there's not value before the start, just return identity
return GetIdentitySeries(sampledSeries, series, start, stop, truncateValues);
return GetIdentitySeries(sampledSeries, series, start, stop, truncateValues, roundTime: false);
}
if (candlesticks[startIndex].Time == nextSampleTime && nextSampleTime <= stop)
{
Expand Down Expand Up @@ -333,7 +333,7 @@ private CandlestickSeries SampleCandlestickSeries(CandlestickSeries series, Date
/// Aggregates the candlesticks in the given range into a single candlestick,
/// keeping the first open and last close and calculating highest high and lowest low
/// </summary>
private static Candlestick AggregateCandlesticks(List<ISeriesPoint> candlesticks, int start, int end, DateTime time, bool truncateValues)
private Candlestick AggregateCandlesticks(List<ISeriesPoint> candlesticks, int start, int end, DateTime time, bool truncateValues)
{
var aggregatedCandlestick = new Candlestick
{
Expand All @@ -349,7 +349,7 @@ private static Candlestick AggregateCandlesticks(List<ISeriesPoint> candlesticks
aggregatedCandlestick.Update(current.Close);
}

return (Candlestick)TruncateValue(aggregatedCandlestick, truncateValues, clone: false);
return (Candlestick)TruncateValue(aggregatedCandlestick, truncateValues, clone: false, roundTime: false);
}

/// <summary>
Expand Down Expand Up @@ -424,15 +424,18 @@ private static Candlestick Interpolate(Candlestick template, Candlestick first,
/// Truncates the value/values of the point after cloning it to avoid mutating the original point
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ISeriesPoint TruncateValue(ISeriesPoint point, bool truncate, bool clone = false)
private ISeriesPoint TruncateValue(ISeriesPoint point, bool truncate, bool clone = false, bool roundTime = false)
{
var truncatedPoint = clone ? point.Clone() : point;
if (roundTime)
{
truncatedPoint.Time = truncatedPoint.Time.RoundUp(Step);
}
if (!truncate)
{
return point;
return truncatedPoint;
}

var truncatedPoint = clone ? point.Clone() : point;

if (truncatedPoint is ChartPoint chartPoint)
{
chartPoint.y = SafeTruncate(chartPoint.y);
Expand All @@ -451,15 +454,15 @@ private static ISeriesPoint TruncateValue(ISeriesPoint point, bool truncate, boo
/// <summary>
/// Gets the identity series, this is the series with no sampling applied.
/// </summary>
protected static T GetIdentitySeries<T>(T sampled, T series, DateTime start, DateTime stop, bool truncateValues)
protected T GetIdentitySeries<T>(T sampled, T series, DateTime start, DateTime stop, bool truncateValues, bool roundTime)
where T : BaseSeries
{
// we can minimally verify we're within the start/stop interval
foreach (var point in series.Values)
{
if (point.Time >= start && point.Time <= stop)
{
sampled.Values.Add(TruncateValue(point, truncateValues, clone: true));
sampled.Values.Add(TruncateValue(point, truncateValues, clone: true, roundTime));
}
}
return sampled;
Expand Down

0 comments on commit 4c95322

Please sign in to comment.