@@ -61,7 +61,7 @@ public virtual BaseSeries Sample(BaseSeries series, DateTime start, DateTime sto
6161 if ( dataDiff >= Step )
6262 {
6363 // we don't want to subsample this case, directly return what we are given as long as is within the range
64- return GetIdentitySeries ( series . Clone ( empty : true ) , series , start , stop , truncateValues : false ) ;
64+ return GetIdentitySeries ( series . Clone ( empty : true ) , series , start , stop , truncateValues : false , roundTime : series . SeriesType == SeriesType . StackedArea ) ;
6565 }
6666 }
6767
@@ -125,13 +125,13 @@ private Series SampleSeries(Series series, DateTime start, DateTime stop, bool t
125125 {
126126 var sampled = ( Series ) series . Clone ( empty : true ) ;
127127
128- var nextSampleTime = start ;
128+ var nextSampleTime = start . RoundUp ( Step ) ;
129129
130130 // we can't sample a single point and it doesn't make sense to sample scatter plots
131131 // in this case just copy the raw data
132132 if ( series . Values . Count < 2 || series . SeriesType == SeriesType . Scatter )
133133 {
134- return GetIdentitySeries ( sampled , series , start , stop , truncateValues ) ;
134+ return GetIdentitySeries ( sampled , series , start , stop , truncateValues , series . SeriesType == SeriesType . StackedArea ) ;
135135 }
136136
137137 var enumerator = series . Values . Cast < ChartPoint > ( ) . GetEnumerator ( ) ;
@@ -143,9 +143,9 @@ private Series SampleSeries(Series series, DateTime start, DateTime stop, bool t
143143 var current = enumerator . Current ;
144144
145145 // make sure we don't start sampling before the data begins
146- if ( nextSampleTime < previous . Time )
146+ while ( nextSampleTime < previous . Time )
147147 {
148- nextSampleTime = previous . Time ;
148+ nextSampleTime += Step ;
149149 }
150150
151151 // make sure to advance into the requested time frame before sampling
@@ -168,7 +168,7 @@ private Series SampleSeries(Series series, DateTime start, DateTime stop, bool t
168168 }
169169 else
170170 {
171- sampledPoint = TruncateValue ( Interpolate ( previous , current , nextSampleTime , ( decimal ) Step . TotalSeconds ) , truncateValues , clone : false ) ;
171+ sampledPoint = TruncateValue ( Interpolate ( previous , current , nextSampleTime , ( decimal ) Step . TotalSeconds ) , truncateValues , clone : false , roundTime : false ) ;
172172 }
173173
174174 nextSampleTime += Step ;
@@ -224,7 +224,7 @@ private CandlestickSeries SampleCandlestickSeries(CandlestickSeries series, Date
224224 // we can't sample a single point, so just copy the raw data
225225 if ( seriesSize < 2 )
226226 {
227- return GetIdentitySeries ( sampledSeries , series , start , stop , truncateValues ) ;
227+ return GetIdentitySeries ( sampledSeries , series , start , stop , truncateValues , roundTime : false ) ;
228228 }
229229
230230 // Make sure we don't start sampling before the data begins.
@@ -240,7 +240,7 @@ private CandlestickSeries SampleCandlestickSeries(CandlestickSeries series, Date
240240 if ( startIndex < 0 )
241241 {
242242 // there's not value before the start, just return identity
243- return GetIdentitySeries ( sampledSeries , series , start , stop , truncateValues ) ;
243+ return GetIdentitySeries ( sampledSeries , series , start , stop , truncateValues , roundTime : false ) ;
244244 }
245245 if ( candlesticks [ startIndex ] . Time == nextSampleTime && nextSampleTime <= stop )
246246 {
@@ -333,7 +333,7 @@ private CandlestickSeries SampleCandlestickSeries(CandlestickSeries series, Date
333333 /// Aggregates the candlesticks in the given range into a single candlestick,
334334 /// keeping the first open and last close and calculating highest high and lowest low
335335 /// </summary>
336- private static Candlestick AggregateCandlesticks ( List < ISeriesPoint > candlesticks , int start , int end , DateTime time , bool truncateValues )
336+ private Candlestick AggregateCandlesticks ( List < ISeriesPoint > candlesticks , int start , int end , DateTime time , bool truncateValues )
337337 {
338338 var aggregatedCandlestick = new Candlestick
339339 {
@@ -349,7 +349,7 @@ private static Candlestick AggregateCandlesticks(List<ISeriesPoint> candlesticks
349349 aggregatedCandlestick . Update ( current . Close ) ;
350350 }
351351
352- return ( Candlestick ) TruncateValue ( aggregatedCandlestick , truncateValues , clone : false ) ;
352+ return ( Candlestick ) TruncateValue ( aggregatedCandlestick , truncateValues , clone : false , roundTime : false ) ;
353353 }
354354
355355 /// <summary>
@@ -424,15 +424,18 @@ private static Candlestick Interpolate(Candlestick template, Candlestick first,
424424 /// Truncates the value/values of the point after cloning it to avoid mutating the original point
425425 /// </summary>
426426 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
427- private static ISeriesPoint TruncateValue ( ISeriesPoint point , bool truncate , bool clone = false )
427+ private ISeriesPoint TruncateValue ( ISeriesPoint point , bool truncate , bool clone = false , bool roundTime = false )
428428 {
429+ var truncatedPoint = clone ? point . Clone ( ) : point ;
430+ if ( roundTime )
431+ {
432+ truncatedPoint . Time = truncatedPoint . Time . RoundUp ( Step ) ;
433+ }
429434 if ( ! truncate )
430435 {
431- return point ;
436+ return truncatedPoint ;
432437 }
433438
434- var truncatedPoint = clone ? point . Clone ( ) : point ;
435-
436439 if ( truncatedPoint is ChartPoint chartPoint )
437440 {
438441 chartPoint . y = SafeTruncate ( chartPoint . y ) ;
@@ -451,15 +454,15 @@ private static ISeriesPoint TruncateValue(ISeriesPoint point, bool truncate, boo
451454 /// <summary>
452455 /// Gets the identity series, this is the series with no sampling applied.
453456 /// </summary>
454- protected static T GetIdentitySeries < T > ( T sampled , T series , DateTime start , DateTime stop , bool truncateValues )
457+ protected T GetIdentitySeries < T > ( T sampled , T series , DateTime start , DateTime stop , bool truncateValues , bool roundTime )
455458 where T : BaseSeries
456459 {
457460 // we can minimally verify we're within the start/stop interval
458461 foreach ( var point in series . Values )
459462 {
460463 if ( point . Time >= start && point . Time <= stop )
461464 {
462- sampled . Values . Add ( TruncateValue ( point , truncateValues , clone : true ) ) ;
465+ sampled . Values . Add ( TruncateValue ( point , truncateValues , clone : true , roundTime ) ) ;
463466 }
464467 }
465468 return sampled ;
0 commit comments