1022 lines
49 KiB
C#
1022 lines
49 KiB
C#
/*
|
|
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
|
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using NUnit.Framework;
|
|
|
|
namespace QuantConnect.Tests.Common
|
|
{
|
|
[TestFixture]
|
|
public class SeriesSamplerTests
|
|
{
|
|
private readonly DateTime _reference = new(2023, 2, 2);
|
|
|
|
[TestCase(0, true)]
|
|
[TestCase(1, true)]
|
|
[TestCase(2, true)]
|
|
[TestCase(3, true)]
|
|
[TestCase(0, false)]
|
|
[TestCase(1, false)]
|
|
[TestCase(2, false)]
|
|
[TestCase(3, false)]
|
|
public void ReturnsIdentityFutureOrPastCandlestick(int dataPoints, bool futureOrPast)
|
|
{
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
for (var i = 0; i < dataPoints; i++)
|
|
{
|
|
series.AddPoint(new Candlestick(_reference.AddDays(futureOrPast ? (i + 1000) : i), 1, 1, 1, 1));
|
|
}
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
var sampled = sampler.Sample(series, _reference.AddDays(10), _reference.AddDays(11));
|
|
|
|
// empty
|
|
Assert.AreEqual(0, sampled.Values.Count);
|
|
}
|
|
|
|
[TestCase(0, true)]
|
|
[TestCase(1, true)]
|
|
[TestCase(2, true)]
|
|
[TestCase(3, true)]
|
|
[TestCase(0, false)]
|
|
[TestCase(1, false)]
|
|
[TestCase(2, false)]
|
|
[TestCase(3, false)]
|
|
public void ReturnsIdentityFutureOrPastPoints(int dataPoints, bool futureOrPast)
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
for (var i = 0; i < dataPoints; i++)
|
|
{
|
|
series.AddPoint(new ChartPoint(_reference.AddDays(futureOrPast ? (i + 1000) : i), 1));
|
|
}
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
var sampled = sampler.Sample(series, _reference.AddDays(10), _reference.AddDays(11));
|
|
|
|
// empty
|
|
Assert.AreEqual(0, sampled.Values.Count);
|
|
}
|
|
|
|
[TestCase(false)]
|
|
[TestCase(true)]
|
|
public void ReturnsIdentityOnSinglePoint(bool isNullValue)
|
|
{
|
|
var series = new Series {Name = "name"};
|
|
series.AddPoint(new ChartPoint(_reference, isNullValue ? null: 1));
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddSeconds(-1), _reference.AddSeconds(1));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(1, sampled.Values.Count);
|
|
Assert.AreEqual(seriesValues[0].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[0].y, sampledValues[0].y);
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamplesNullFirstValue(bool subSample)
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
series.AddPoint(new ChartPoint(_reference, null));
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(_reference.AddDays(2), 3m);
|
|
series.AddPoint(_reference.AddDays(3), 4m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1.5)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(3));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[0].y);
|
|
|
|
Assert.AreEqual((seriesValues[1].x + seriesValues[2].x) / 2, sampledValues[1].x);
|
|
Assert.AreEqual((seriesValues[1].y + seriesValues[2].y) / 2, sampledValues[1].y);
|
|
|
|
Assert.AreEqual(seriesValues[3].x, sampledValues[2].x);
|
|
Assert.AreEqual(seriesValues[3].y, sampledValues[2].y);
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamples(bool subSample)
|
|
{
|
|
var series = new Series {Name = "name"};
|
|
series.AddPoint(_reference, 1m);
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(_reference.AddDays(2), 3m);
|
|
series.AddPoint(_reference.AddDays(3), 4m);
|
|
series.AddPoint(new ChartPoint(_reference.AddDays(4), null));
|
|
series.AddPoint(_reference.AddDays(5), 5m);
|
|
series.AddPoint(_reference.AddDays(6), 6m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1.5)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(6));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(5, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[0].y, sampledValues[0].y);
|
|
|
|
Assert.AreEqual((seriesValues[1].x + seriesValues[2].x)/2, sampledValues[1].x);
|
|
Assert.AreEqual((seriesValues[1].y + seriesValues[2].y)/2, sampledValues[1].y);
|
|
|
|
Assert.AreEqual(seriesValues[3].x, sampledValues[2].x);
|
|
Assert.AreEqual(seriesValues[3].y, sampledValues[2].y);
|
|
|
|
Assert.AreEqual((seriesValues[4].x + seriesValues[5].x) / 2, sampledValues[3].x);
|
|
Assert.AreEqual(seriesValues[5].y, sampledValues[3].y);
|
|
|
|
Assert.AreEqual(seriesValues[6].x, sampledValues[4].x);
|
|
Assert.AreEqual(seriesValues[6].y, sampledValues[4].y);
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamplesWithTimeJump(bool subSample)
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
series.AddPoint(_reference, 1m);
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(_reference.AddDays(2), 3m);
|
|
series.AddPoint(_reference.AddDays(3), 4m);
|
|
series.AddPoint(new ChartPoint(_reference.AddDays(4), null));
|
|
// time jump
|
|
series.AddPoint(_reference.AddDays(20), 5m);
|
|
series.AddPoint(_reference.AddDays(21), 6m);
|
|
|
|
var span = TimeSpan.FromDays(1.5);
|
|
var sampler = new SeriesSampler(span) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(24));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(subSample ? 15 : 5, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[0].y, sampledValues[0].y);
|
|
|
|
Assert.AreEqual((seriesValues[1].x + seriesValues[2].x) / 2, sampledValues[1].x);
|
|
Assert.AreEqual((seriesValues[1].y + seriesValues[2].y) / 2, sampledValues[1].y);
|
|
|
|
Assert.AreEqual(seriesValues[3].x, sampledValues[2].x);
|
|
Assert.AreEqual(seriesValues[3].y, sampledValues[2].y);
|
|
|
|
var expectedTime = seriesValues[3].x;
|
|
for (var i = 3; i < 13; i++)
|
|
{
|
|
expectedTime += (long)span.TotalSeconds;
|
|
|
|
if (subSample)
|
|
{
|
|
Assert.AreEqual(expectedTime, sampledValues[i].x);
|
|
// all nulls
|
|
Assert.AreEqual(null, sampledValues[i].y);
|
|
}
|
|
}
|
|
|
|
var expectedIndex = subSample ? 13 : 3;
|
|
|
|
Assert.AreEqual(expectedTime + (long)span.TotalSeconds, sampledValues[expectedIndex].x);
|
|
Assert.AreEqual(seriesValues[5].y, sampledValues[expectedIndex].y);
|
|
|
|
expectedIndex++;
|
|
Assert.AreEqual(seriesValues[6].x, sampledValues[expectedIndex].x);
|
|
Assert.AreEqual(seriesValues[6].y, sampledValues[expectedIndex].y);
|
|
}
|
|
|
|
[Test]
|
|
public void SubSamples()
|
|
{
|
|
var series = new Series {Name = "name"};
|
|
series.AddPoint(_reference, 1m);
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(new ChartPoint(_reference.AddDays(2), null));
|
|
series.AddPoint(_reference.AddDays(3), 4m);
|
|
series.AddPoint(_reference.AddDays(4), 5m);
|
|
series.AddPoint(_reference.AddDays(5), 6m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(0.5));
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddDays(1), _reference.AddDays(3));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(5, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[1].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[0].y);
|
|
|
|
Assert.AreEqual((seriesValues[1].x + seriesValues[2].x) / 2, sampledValues[1].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[1].y);
|
|
Assert.AreEqual(seriesValues[2].x, sampledValues[2].x);
|
|
Assert.AreEqual(null, sampledValues[2].y);
|
|
|
|
Assert.AreEqual((seriesValues[3].x + seriesValues[2].x) / 2, sampledValues[3].x);
|
|
Assert.AreEqual(seriesValues[3].y, sampledValues[3].y);
|
|
Assert.AreEqual(seriesValues[3].x, sampledValues[4].x);
|
|
Assert.AreEqual(seriesValues[3].y, sampledValues[4].y);
|
|
}
|
|
|
|
[Test]
|
|
public void SubSamplesDisabled()
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
series.AddPoint(_reference, 1m);
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(new ChartPoint(_reference.AddDays(2), null));
|
|
// even if the data doesn't fit exactly the expected bar span we expect it to pass through
|
|
series.AddPoint(_reference.AddDays(2.8), 4m);
|
|
series.AddPoint(_reference.AddDays(4), 5m);
|
|
series.AddPoint(_reference.AddDays(5), 6m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(0.5)) { SubSample = false };
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddDays(1), _reference.AddDays(3));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[1].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[0].y);
|
|
|
|
Assert.AreEqual(seriesValues[2].x, sampledValues[1].x);
|
|
Assert.AreEqual(seriesValues[2].y, sampledValues[1].y);
|
|
|
|
Assert.AreEqual(seriesValues[3].x, sampledValues[2].x);
|
|
Assert.AreEqual(seriesValues[3].y, sampledValues[2].y);
|
|
}
|
|
|
|
[Test]
|
|
public void SubSamplesWithTimeJump()
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
series.AddPoint(_reference, 1m);
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(new ChartPoint(_reference.AddDays(2), null));
|
|
series.AddPoint(_reference.AddDays(10), 4m);
|
|
series.AddPoint(_reference.AddDays(11), 5m);
|
|
series.AddPoint(_reference.AddDays(12), 6m);
|
|
|
|
var span = TimeSpan.FromDays(0.5);
|
|
var sampler = new SeriesSampler(span);
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddDays(1), _reference.AddDays(12));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(23, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[1].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[0].y);
|
|
|
|
var expectedTime = seriesValues[1].x;
|
|
expectedTime += (long)span.TotalSeconds;
|
|
|
|
Assert.AreEqual(expectedTime, sampledValues[1].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[1].y);
|
|
|
|
for (var i = 2; i < 17; i++)
|
|
{
|
|
expectedTime += (long)span.TotalSeconds;
|
|
|
|
Assert.AreEqual(expectedTime, sampledValues[i].x);
|
|
Assert.AreEqual(null, sampledValues[i].y);
|
|
}
|
|
|
|
Assert.AreEqual(seriesValues[4].x, sampledValues[20].x);
|
|
Assert.AreEqual(seriesValues[4].y, sampledValues[20].y);
|
|
|
|
Assert.AreEqual(seriesValues[4].x + (long)span.TotalSeconds, sampledValues[21].x);
|
|
Assert.AreEqual((seriesValues[4].y + seriesValues[5].y) / 2, sampledValues[21].y);
|
|
|
|
Assert.AreEqual(seriesValues[5].x, sampledValues[22].x);
|
|
Assert.AreEqual(seriesValues[5].y, sampledValues[22].y);
|
|
}
|
|
|
|
[Test]
|
|
public void DoesNotSampleBeforeStart()
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
series.AddPoint(_reference, 1m);
|
|
series.AddPoint(_reference.AddDays(1), 2m);
|
|
series.AddPoint(_reference.AddDays(2), 3m);
|
|
series.AddPoint(_reference.AddDays(3), 4m);
|
|
series.AddPoint(_reference.AddDays(4), 5m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddDays(-1), _reference.AddDays(2));
|
|
|
|
var seriesValues = series.Values.Cast<ChartPoint>().ToList();
|
|
var sampledValues = sampled.Values.Cast<ChartPoint>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].x, sampledValues[0].x);
|
|
Assert.AreEqual(seriesValues[0].y, sampledValues[0].y);
|
|
|
|
Assert.AreEqual(seriesValues[1].x, sampledValues[1].x);
|
|
Assert.AreEqual(seriesValues[1].y, sampledValues[1].y);
|
|
|
|
Assert.AreEqual(seriesValues[2].x, sampledValues[2].x);
|
|
Assert.AreEqual(seriesValues[2].y, sampledValues[2].y);
|
|
}
|
|
|
|
[Test]
|
|
public void HandlesDuplicateTimes()
|
|
{
|
|
var series = new Series();
|
|
series.Values.Add(new ChartPoint(_reference, 1m));
|
|
series.Values.Add(new ChartPoint(_reference, 2m));
|
|
series.Values.Add(new ChartPoint(_reference.AddDays(1), 3m));
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(1));
|
|
|
|
// sampler will only produce one value at the time
|
|
// it was also respect the latest value
|
|
|
|
Assert.AreEqual(2, sampled.Values.Count);
|
|
foreach (var pair in series.Values.Skip(1).Cast<ChartPoint>().Zip(sampled.Values.Cast<ChartPoint>(), Tuple.Create))
|
|
{
|
|
Assert.AreEqual(pair.Item1.x, pair.Item2.x);
|
|
Assert.AreEqual(pair.Item1.y, pair.Item2.y);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DoesNotSampleScatterPlots()
|
|
{
|
|
var scatter = new Series("scatter", SeriesType.Scatter, 0, "$");
|
|
scatter.AddPoint(_reference, 1m);
|
|
scatter.AddPoint(_reference, 3m);
|
|
scatter.AddPoint(_reference.AddSeconds(1), 1.5m);
|
|
scatter.AddPoint(_reference.AddSeconds(0.5), 1.5m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromMilliseconds(1));
|
|
var sampled = sampler.Sample(scatter, _reference, _reference.AddDays(1));
|
|
foreach (var pair in scatter.Values.Cast<ChartPoint>().Zip(sampled.Values.Cast<ChartPoint>(), Tuple.Create))
|
|
{
|
|
Assert.AreEqual(pair.Item1.x, pair.Item2.x);
|
|
Assert.AreEqual(pair.Item1.y, pair.Item2.y);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void SubSampleTreemapPlots()
|
|
{
|
|
var treeMap = new Series("Treemap", SeriesType.Treemap, 0, "$");
|
|
treeMap.AddPoint(_reference, 1m);
|
|
treeMap.AddPoint(_reference.AddSeconds(0.5), 1.5m);
|
|
treeMap.AddPoint(_reference.AddMinutes(1), 2m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromMilliseconds(1));
|
|
var sampled = sampler.Sample(treeMap, _reference, _reference.AddDays(1));
|
|
|
|
Assert.AreEqual(1000 * 60 + 1, sampled.Values.Count);
|
|
foreach (var newValues in sampled.Values.Cast<ChartPoint>())
|
|
{
|
|
var expected = (ChartPoint)treeMap.Values[0];
|
|
if (newValues.Time >= treeMap.Values[1].Time)
|
|
{
|
|
expected = (ChartPoint)treeMap.Values[1];
|
|
}
|
|
if (newValues.Time >= treeMap.Values[2].Time)
|
|
{
|
|
expected = (ChartPoint)treeMap.Values[2];
|
|
}
|
|
Assert.AreEqual(expected.y, newValues.y);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void DownSampleTreemapPlots()
|
|
{
|
|
var treeMap = new Series("Treemap", SeriesType.Treemap, 0, "$");
|
|
treeMap.AddPoint(_reference, 1m);
|
|
treeMap.AddPoint(_reference, 3m);
|
|
treeMap.AddPoint(_reference.AddSeconds(0.5), 1.5m);
|
|
treeMap.AddPoint(_reference.AddSeconds(1), 1.5m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
var sampled = sampler.Sample(treeMap, _reference, _reference.AddDays(1));
|
|
|
|
// the last value
|
|
Assert.AreEqual(1, sampled.Values.Count);
|
|
Assert.AreEqual(_reference, sampled.Values[0].Time);
|
|
Assert.AreEqual(((ChartPoint)treeMap.Values.Last()).Y, ((ChartPoint)sampled.Values[0]).Y);
|
|
}
|
|
|
|
[Test]
|
|
public void EmitsEmptySeriesWithSinglePointOutsideOfStartStop()
|
|
{
|
|
var series = new Series { Name = "name" };
|
|
series.AddPoint(_reference.AddSeconds(-1), 1m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference);
|
|
Assert.AreEqual(0, sampled.Values.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void ReturnsIdentityOnSinglePointCandlestickSeries()
|
|
{
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddSeconds(-1), _reference.AddSeconds(1));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(1, sampledValues.Count);
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
Assert.AreEqual(seriesValues[0].Open, sampledValues[0].Open);
|
|
Assert.AreEqual(seriesValues[0].High, sampledValues[0].High);
|
|
Assert.AreEqual(seriesValues[0].Low, sampledValues[0].Low);
|
|
Assert.AreEqual(seriesValues[0].Close, sampledValues[0].Close);
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DoesNotSampleCandlestickSeriesBeforeStart(bool subSample)
|
|
{
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(_reference.AddDays(3), 2m, 2m, 1m, 1m);
|
|
series.AddPoint(_reference.AddDays(4), 2m, 3m, 2m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddDays(-1), _reference.AddDays(2));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
for (var i = 0; i < sampledValues.Count; i++)
|
|
{
|
|
Assert.AreEqual(seriesValues[i].Time, sampledValues[i].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[i], sampledValues[i]);
|
|
}
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamplesCandlestickSeriesWithStopSameAsLastPoint(bool subSample)
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 1.5 day intervals
|
|
// Original series: |---------|---------|---------|
|
|
// Sampled series: |--------------|--------------|
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(_reference.AddDays(3), 2m, 2m, 1m, 1m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1.5)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(3));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(1.5), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(Math.Max(seriesValues[1].High.Value, seriesValues[2].High.Value), sampledValues[1].High);
|
|
Assert.AreEqual(Math.Min(seriesValues[1].Low.Value, seriesValues[2].Low.Value), sampledValues[1].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[1], seriesValues[2], TimeSpan.FromDays(1), sampledValues[1].LongTime), sampledValues[1].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(2 * 1.5), sampledValues[2].Time);
|
|
Assert.AreEqual(seriesValues[3].Open, sampledValues[2].Open);
|
|
Assert.AreEqual(seriesValues[3].High, sampledValues[2].High);
|
|
Assert.AreEqual(seriesValues[3].Low, sampledValues[2].Low);
|
|
Assert.AreEqual(seriesValues[3].Close, sampledValues[2].Close);
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamplesCandlestickSeriesWithStopAfterLastPoint(bool subSample)
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 1.5 day intervals
|
|
// Original series: |---------|---------|---------|---------|
|
|
// Sampled series: |--------------|--------------|--------------
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(_reference.AddDays(3), 2m, 2m, 1m, 1m);
|
|
series.AddPoint(_reference.AddDays(4), 2m, 3m, 2m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1.5)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(4));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(1.5), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(Math.Max(seriesValues[1].High.Value, seriesValues[2].High.Value), sampledValues[1].High);
|
|
Assert.AreEqual(Math.Min(seriesValues[1].Low.Value, seriesValues[2].Low.Value), sampledValues[1].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[1], seriesValues[2], TimeSpan.FromDays(1), sampledValues[1].LongTime), sampledValues[1].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(2 * 1.5), sampledValues[2].Time);
|
|
Assert.AreEqual(seriesValues[3].Open, sampledValues[2].Open);
|
|
Assert.AreEqual(seriesValues[3].High, sampledValues[2].High);
|
|
Assert.AreEqual(seriesValues[3].Low, sampledValues[2].Low);
|
|
Assert.AreEqual(seriesValues[3].Close, sampledValues[2].Close);
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamplesCandlestickSeriesWithResamplePeriodSpanningMultipleCandlesticks(bool subSample)
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 2.5 day intervals
|
|
// Original series: |---------|---------|---------|---------|---------|---------|---------|
|
|
// Sampled series: |------------------------|------------------------|-----------------------
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(_reference.AddDays(3), 2m, 2m, 1m, 1m);
|
|
series.AddPoint(_reference.AddDays(4), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(5), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(6), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(7), 2m, 3m, 2m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(2.5)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(5));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(2.5), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(new[] { seriesValues[1].High, seriesValues[2].High, seriesValues[3].High }.Max(), sampledValues[1].High);
|
|
Assert.AreEqual(new[] { seriesValues[1].Low, seriesValues[2].Low, seriesValues[3].Low }.Min(), sampledValues[1].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[1], seriesValues[3], TimeSpan.FromDays(1), sampledValues[1].LongTime), (double)sampledValues[1].Close, delta: 1e-3);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(2 * 2.5), sampledValues[2].Time);
|
|
Assert.AreEqual(seriesValues[4].Open, sampledValues[2].Open);
|
|
Assert.AreEqual(Math.Max(seriesValues[4].High.Value, seriesValues[5].High.Value), sampledValues[2].High);
|
|
Assert.AreEqual(Math.Min(seriesValues[4].Low.Value, seriesValues[5].Low.Value), sampledValues[2].Low);
|
|
Assert.AreEqual(seriesValues[5].Close, sampledValues[2].Close);
|
|
}
|
|
|
|
private static decimal InterpolateClose(Candlestick prev, Candlestick next, TimeSpan candleSpan, long time)
|
|
{
|
|
var prevOpenUnitTime = Time.DateTimeToUnixTimeStamp(prev.Time - candleSpan).SafeDecimalCast();
|
|
return (next.Close.Value - prev.Open.Value) * (time - prevOpenUnitTime) / (next.LongTime - prevOpenUnitTime) + prev.Open.Value;
|
|
}
|
|
|
|
[TestCase(true)]
|
|
[TestCase(false)]
|
|
public void DownSamplesCandlestickSeriesWithStopBeforeLastPoint(bool subSample)
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 1.25 day intervals
|
|
// Original series: |-----------|-----------|-----------|-----------|
|
|
// Sampled series: |--------------|--------------|--------------|
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(_reference.AddDays(3), 2m, 2m, 1m, 1m);
|
|
series.AddPoint(_reference.AddDays(4), 2m, 3m, 2m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1.25)) { SubSample = subSample };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(4));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(4, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(1.25), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(Math.Max(seriesValues[1].High.Value, seriesValues[2].High.Value), sampledValues[1].High);
|
|
Assert.AreEqual(Math.Min(seriesValues[1].Low.Value, seriesValues[2].Low.Value), sampledValues[1].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[1], seriesValues[2], TimeSpan.FromDays(1), sampledValues[1].LongTime), sampledValues[1].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(2 * 1.25), sampledValues[2].Time);
|
|
Assert.AreEqual(seriesValues[3].Open, sampledValues[2].Open);
|
|
Assert.AreEqual(seriesValues[3].High, sampledValues[2].High);
|
|
Assert.AreEqual(1.5m, sampledValues[2].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[3], seriesValues[3], TimeSpan.FromDays(1), sampledValues[2].LongTime), sampledValues[2].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(3 * 1.25), sampledValues[3].Time);
|
|
Assert.AreEqual(seriesValues[4].Open, sampledValues[3].Open);
|
|
Assert.AreEqual(2.75m, sampledValues[3].High);
|
|
Assert.AreEqual(seriesValues[4].Low, sampledValues[3].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[4], seriesValues[4], TimeSpan.FromDays(1), sampledValues[3].LongTime), sampledValues[3].Close);
|
|
}
|
|
|
|
[Test]
|
|
public void SubSamplesCandlestickSeries()
|
|
{
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(_reference.AddDays(3), 2m, 2m, 1m, 1m);
|
|
series.AddPoint(_reference.AddDays(4), 2m, 3m, 2m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(1));
|
|
|
|
var sampled = sampler.Sample(series, _reference.AddDays(1), _reference.AddDays(2));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(2, sampled.Values.Count);
|
|
|
|
for (var i = 0; i < sampledValues.Count; i++)
|
|
{
|
|
Assert.AreEqual(seriesValues[i + 1].Time, sampledValues[i].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[i + 1], sampledValues[i]);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void SamplesCandlestickSeriesWithHigherSamplingResolution()
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 0.25 day intervals
|
|
// Original series: |-------------------|-------------------|
|
|
// Sampled series: |----|----|----|----|----|----|----|----|
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(0.25));
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(2));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(9, sampled.Values.Count);
|
|
|
|
// First half:
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(0.25), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(2.25, sampledValues[1].High);
|
|
Assert.AreEqual(seriesValues[1].Low, sampledValues[1].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[1].LongTime), sampledValues[1].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(2 * 0.25), sampledValues[2].Time);
|
|
Assert.AreEqual(sampledValues[1].Close, sampledValues[2].Open);
|
|
Assert.AreEqual(2.5, sampledValues[2].High);
|
|
Assert.AreEqual(2.25, sampledValues[2].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[2].LongTime), sampledValues[2].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(3 * 0.25), sampledValues[3].Time);
|
|
Assert.AreEqual(sampledValues[2].Close, sampledValues[3].Open);
|
|
Assert.AreEqual(2.75, sampledValues[3].High);
|
|
Assert.AreEqual(2.5, sampledValues[3].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[3].LongTime), sampledValues[3].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(4 * 0.25), sampledValues[4].Time);
|
|
Assert.AreEqual(sampledValues[3].Close, sampledValues[4].Open);
|
|
Assert.AreEqual(seriesValues[1].High, sampledValues[4].High);
|
|
Assert.AreEqual(2.75, sampledValues[4].Low);
|
|
Assert.AreEqual(seriesValues[1].Close, sampledValues[4].Close);
|
|
|
|
// Second half:
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(5 * 0.25), sampledValues[5].Time);
|
|
Assert.AreEqual(seriesValues[2].Open, sampledValues[5].Open);
|
|
Assert.AreEqual(seriesValues[2].High, sampledValues[5].High);
|
|
Assert.AreEqual(3.75, sampledValues[5].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[5].LongTime), sampledValues[5].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(6 * 0.25), sampledValues[6].Time);
|
|
Assert.AreEqual(sampledValues[5].Close, sampledValues[6].Open);
|
|
Assert.AreEqual(3.75m, sampledValues[6].High);
|
|
Assert.AreEqual(3.5m, sampledValues[6].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[6].LongTime), sampledValues[6].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(7 * 0.25), sampledValues[7].Time);
|
|
Assert.AreEqual(sampledValues[6].Close, sampledValues[7].Open);
|
|
Assert.AreEqual(3.5m, sampledValues[7].High);
|
|
Assert.AreEqual(3.25m, sampledValues[7].Low);
|
|
Assert.AreEqual(InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[7].LongTime), sampledValues[7].Close);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddDays(8 * 0.25), sampledValues[8].Time);
|
|
Assert.AreEqual(sampledValues[7].Close, sampledValues[8].Open);
|
|
Assert.AreEqual(3.25m, sampledValues[8].High);
|
|
Assert.AreEqual(seriesValues[2].Low, sampledValues[8].Low);
|
|
Assert.AreEqual(seriesValues[2].Close, sampledValues[8].Close);
|
|
}
|
|
|
|
[Test]
|
|
public void SamplesCandlestickSeriesWithHigherSamplingResolutionDisabled()
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 0.25 day intervals
|
|
// Original series: |-------------------|-------------------|
|
|
// Sampled series: |-------------------|-------------------|
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
// even if the data doesn't fit exactly the expected bar span we expect it to pass through
|
|
series.AddPoint(_reference.AddDays(1.6), 4m, 4m, 3m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromDays(0.25)) { SubSample = false };
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(2));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(3, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[1].Time, sampledValues[1].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[1], sampledValues[1]);
|
|
|
|
Assert.AreEqual(seriesValues[2].Time, sampledValues[2].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[2], sampledValues[2]);
|
|
}
|
|
|
|
[Test]
|
|
public void SamplesCandlestickSeriesWithLowerSamplingResolutionNullValues()
|
|
{
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(new Candlestick(_reference.AddDays(3), null, null, null, null));
|
|
// Time jump
|
|
series.AddPoint(_reference.AddDays(11), 5m, 5m, 5m, 5m);
|
|
|
|
var barSpan = TimeSpan.FromDays(1.5);
|
|
var sampler = new SeriesSampler(barSpan);
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(12));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(8, sampled.Values.Count);
|
|
|
|
var expectedTime = series.Values[3].Time;
|
|
for (var i = 2; i < 7; i++)
|
|
{
|
|
Assert.AreEqual(expectedTime, sampledValues[i].Time);
|
|
Assert.AreEqual(null, sampledValues[i].Open);
|
|
Assert.AreEqual(null, sampledValues[i].High);
|
|
Assert.AreEqual(null, sampledValues[i].Low);
|
|
Assert.AreEqual(null, sampledValues[i].Close);
|
|
expectedTime += barSpan;
|
|
}
|
|
|
|
Assert.AreEqual(expectedTime, sampledValues[7].Time);
|
|
Assert.AreEqual(seriesValues[4].Open, sampledValues[7].Open);
|
|
Assert.AreEqual(seriesValues[4].High, sampledValues[7].High);
|
|
Assert.AreEqual(seriesValues[4].Low, sampledValues[7].Low);
|
|
Assert.AreEqual(seriesValues[4].Close, sampledValues[7].Close);
|
|
}
|
|
|
|
[Test]
|
|
public void SamplesCandlestickSeriesWithHigherSamplingResolutionNullValues()
|
|
{
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
series.AddPoint(new Candlestick(_reference.AddDays(3), null, null, null, null));
|
|
// Time jump
|
|
series.AddPoint(_reference.AddDays(10), 5m, 5m, 5m, 5m);
|
|
|
|
var barSpan = TimeSpan.FromDays(0.5);
|
|
var sampler = new SeriesSampler(barSpan);
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(10));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(21, sampled.Values.Count);
|
|
|
|
var expectedTime = series.Values[2].Time;
|
|
for (var i = 5; i < 19; i++)
|
|
{
|
|
expectedTime += barSpan;
|
|
Assert.AreEqual(expectedTime, sampledValues[i].Time);
|
|
Assert.AreEqual(null, sampledValues[i].Open);
|
|
Assert.AreEqual(null, sampledValues[i].High);
|
|
Assert.AreEqual(null, sampledValues[i].Low);
|
|
Assert.AreEqual(null, sampledValues[i].Close);
|
|
}
|
|
|
|
expectedTime += barSpan;
|
|
Assert.AreEqual(expectedTime, sampledValues[19].Time);
|
|
Assert.AreEqual(seriesValues[4].Open, sampledValues[19].Open);
|
|
Assert.AreEqual(seriesValues[4].High, sampledValues[19].High);
|
|
Assert.AreEqual(seriesValues[4].Low, sampledValues[19].Low);
|
|
Assert.AreEqual(seriesValues[4].Close, sampledValues[19].Close);
|
|
|
|
expectedTime += barSpan;
|
|
Assert.AreEqual(expectedTime, sampledValues[20].Time);
|
|
Assert.AreEqual(seriesValues[4].Open, sampledValues[20].Open);
|
|
Assert.AreEqual(seriesValues[4].High, sampledValues[20].High);
|
|
Assert.AreEqual(seriesValues[4].Low, sampledValues[20].Low);
|
|
Assert.AreEqual(seriesValues[4].Close, sampledValues[20].Close);
|
|
}
|
|
|
|
[Test]
|
|
public void SamplesCandlestickSeriesWithHigherUnevenSamplingResolutionAndStopAfterLastPoint()
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 10 hours intervals
|
|
// Original series: |-------------------|-------------------|
|
|
// Sampled series: |--------|--------|--------|--------|--------
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromHours(10));
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddDays(2));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(5, sampled.Values.Count);
|
|
|
|
// First half:
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(1 * 10), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(2.416667m, sampledValues[1].High);
|
|
Assert.AreEqual(seriesValues[1].Low, sampledValues[1].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[1].LongTime), (double)sampledValues[1].Close, delta: 1e-3);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(2 * 10), sampledValues[2].Time);
|
|
Assert.AreEqual(sampledValues[1].Close, sampledValues[2].Open);
|
|
Assert.AreEqual(2.833333m, sampledValues[2].High);
|
|
Assert.AreEqual(2.416667m, sampledValues[2].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[2].LongTime), (double)sampledValues[2].Close, delta: 1e-3);
|
|
|
|
// Second half:
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(3 * 10), sampledValues[3].Time);
|
|
Assert.AreEqual(seriesValues[2].Open, sampledValues[3].Open);
|
|
Assert.AreEqual(seriesValues[2].High, sampledValues[3].High);
|
|
Assert.AreEqual(3.75m, sampledValues[3].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[3].LongTime), (double)sampledValues[3].Close, delta: 1e-3);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(4 * 10), sampledValues[4].Time);
|
|
Assert.AreEqual(sampledValues[3].Close, sampledValues[4].Open);
|
|
Assert.AreEqual(3.75m, sampledValues[4].High);
|
|
Assert.AreEqual(3.333333m, sampledValues[4].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[4].LongTime), (double)sampledValues[4].Close, delta: 1e-3);
|
|
}
|
|
|
|
[Test]
|
|
public void SamplesCandlestickSeriesWithHigherUnevenSamplingResolutionAndStopBeforeLastPoint()
|
|
{
|
|
// Original series is sampled at 1 day intervals
|
|
// Sampled series is sampled at 10 hours intervals
|
|
// Original series: |-------------------|-------------------|
|
|
// Sampled series: |--------|--------|--------|--------|
|
|
|
|
var series = new CandlestickSeries { Name = "name" };
|
|
series.AddPoint(_reference, 1m, 2m, 1m, 2m);
|
|
series.AddPoint(_reference.AddDays(1), 2m, 3m, 2m, 3m);
|
|
series.AddPoint(_reference.AddDays(2), 4m, 4m, 3m, 3m);
|
|
|
|
var sampler = new SeriesSampler(TimeSpan.FromHours(10));
|
|
|
|
var sampled = sampler.Sample(series, _reference, _reference.AddHours(40));
|
|
|
|
var seriesValues = series.Values.Cast<Candlestick>().ToList();
|
|
var sampledValues = sampled.Values.Cast<Candlestick>().ToList();
|
|
|
|
Assert.AreEqual(5, sampled.Values.Count);
|
|
|
|
Assert.AreEqual(5, sampled.Values.Count);
|
|
|
|
// First half:
|
|
|
|
Assert.AreEqual(seriesValues[0].Time, sampledValues[0].Time);
|
|
AssertCandlesticksValuesAreEqual(seriesValues[0], sampledValues[0]);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(1 * 10), sampledValues[1].Time);
|
|
Assert.AreEqual(seriesValues[1].Open, sampledValues[1].Open);
|
|
Assert.AreEqual(2.416667m, sampledValues[1].High);
|
|
Assert.AreEqual(seriesValues[1].Low, sampledValues[1].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[1].LongTime), (double)sampledValues[1].Close, delta: 1e-3);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(2 * 10), sampledValues[2].Time);
|
|
Assert.AreEqual(sampledValues[1].Close, sampledValues[2].Open);
|
|
Assert.AreEqual(2.833333m, sampledValues[2].High);
|
|
Assert.AreEqual(2.416667m, sampledValues[2].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[1], seriesValues[1], TimeSpan.FromDays(1), sampledValues[2].LongTime), (double)sampledValues[2].Close, delta: 1e-3);
|
|
|
|
// Second half:
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(3 * 10), sampledValues[3].Time);
|
|
Assert.AreEqual(seriesValues[2].Open, sampledValues[3].Open);
|
|
Assert.AreEqual(seriesValues[2].High, sampledValues[3].High);
|
|
Assert.AreEqual(3.75m, sampledValues[3].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[3].LongTime), (double)sampledValues[3].Close, delta: 1e-3);
|
|
|
|
Assert.AreEqual(seriesValues[0].Time.AddHours(4 * 10), sampledValues[4].Time);
|
|
Assert.AreEqual(sampledValues[3].Close, sampledValues[4].Open);
|
|
Assert.AreEqual(3.75m, sampledValues[4].High);
|
|
Assert.AreEqual(3.333333m, sampledValues[4].Low);
|
|
Assert.AreEqual((double)InterpolateClose(seriesValues[2], seriesValues[2], TimeSpan.FromDays(1), sampledValues[4].LongTime), (double)sampledValues[4].Close, delta: 1e-3);
|
|
}
|
|
|
|
private static void AssertCandlesticksValuesAreEqual(Candlestick first, Candlestick second)
|
|
{
|
|
Assert.AreEqual(first.Open, second.Open);
|
|
Assert.AreEqual(first.High, second.High);
|
|
Assert.AreEqual(first.Low, second.Low);
|
|
Assert.AreEqual(first.Close, second.Close);
|
|
}
|
|
}
|
|
}
|