Files
Miha Kralj 060649192f docs: remove C# Implementation Considerations sections, clean up temp scripts, reorganize test files
- Remove 'C# Implementation Considerations' sections from 34 indicator .md files
- Delete 29 temp PowerShell scripts (_fix_mojibake.ps1, _hex_scan.ps1, etc.)
- Move test files into tests/ subdirectories for consistent project structure
- Add trader-focused bullet points to indicator documentation
2026-03-12 12:34:16 -07:00

174 lines
4.7 KiB
C#

namespace QuanTAlib.Tests;
public class AhrensValidationTests
{
private static TSeries MakeSeries(int count = 500)
{
var gbm = new GBM(startPrice: 100, seed: 42);
var series = new TSeries();
for (int i = 0; i < count; i++)
{
series.Add(gbm.Next());
}
return series;
}
[Fact]
public void Batch_And_Streaming_Match()
{
TSeries src = MakeSeries(1000);
int period = 9;
TSeries batchResult = Ahrens.Batch(src, period);
var streaming = new Ahrens(period);
for (int i = 0; i < src.Count; i++)
{
streaming.Update(new TValue(DateTime.UtcNow, src.Values[i]));
}
for (int i = period; i < src.Count; i++)
{
Assert.Equal(batchResult.Values[i], streaming.Last.Value is double _ ? batchResult.Values[i] : double.NaN, 10);
}
// More direct: streaming last == batch last
Assert.Equal(batchResult.Values[src.Count - 1], streaming.Last.Value, 10);
}
[Fact]
public void Span_And_Streaming_Match()
{
TSeries src = MakeSeries(1000);
int period = 9;
double[] spanOut = new double[src.Count];
Ahrens.Batch(src.Values, spanOut, period);
var streaming = new Ahrens(period);
double[] streamVals = new double[src.Count];
for (int i = 0; i < src.Count; i++)
{
streamVals[i] = streaming.Update(new TValue(DateTime.UtcNow, src.Values[i])).Value;
}
for (int i = period; i < src.Count; i++)
{
Assert.Equal(spanOut[i], streamVals[i], 10);
}
}
[Theory]
[InlineData(1)]
[InlineData(3)]
[InlineData(9)]
[InlineData(20)]
[InlineData(50)]
public void DifferentPeriods_AllFinite(int period)
{
TSeries src = MakeSeries(200);
TSeries result = Ahrens.Batch(src, period);
for (int i = period; i < result.Count; i++)
{
Assert.True(double.IsFinite(result.Values[i]), $"Non-finite at index {i} for period {period}");
}
}
[Fact]
public void Constant_ConvergesToConstant()
{
int period = 9;
double constant = 100.0;
var ind = new Ahrens(period);
for (int i = 0; i < 500; i++)
{
ind.Update(new TValue(DateTime.UtcNow, constant));
}
Assert.Equal(constant, ind.Last.Value, 8);
}
[Fact]
public void Calculate_ReturnsHotIndicator()
{
TSeries src = MakeSeries(200);
(TSeries results, Ahrens indicator) = Ahrens.Calculate(src, 9);
Assert.True(indicator.IsHot);
Assert.Equal(src.Count, results.Count);
}
[Fact]
public void BarCorrection_Consistency()
{
TSeries src = MakeSeries(100);
int period = 9;
// Run full series
var ind1 = new Ahrens(period);
for (int i = 0; i < src.Count; i++)
{
ind1.Update(new TValue(DateTime.UtcNow, src.Values[i]));
}
double fullResult = ind1.Last.Value;
// Run with bar corrections at every bar
var ind2 = new Ahrens(period);
for (int i = 0; i < src.Count; i++)
{
// First update with wrong value
ind2.Update(new TValue(DateTime.UtcNow, src.Values[i] + 10.0));
// Correct it
ind2.Update(new TValue(DateTime.UtcNow, src.Values[i]), isNew: false);
// Then advance
if (i < src.Count - 1)
{
// The next isNew=true will snapshot the corrected state
}
}
Assert.Equal(fullResult, ind2.Last.Value, 10);
}
[Fact]
public void SubsetStability()
{
TSeries src = MakeSeries(500);
int period = 9;
// Run full 500 bars
var full = new Ahrens(period);
for (int i = 0; i < 500; i++)
{
full.Update(new TValue(DateTime.UtcNow, src.Values[i]));
}
// Run only first 300 bars
var partial = new Ahrens(period);
for (int i = 0; i < 300; i++)
{
partial.Update(new TValue(DateTime.UtcNow, src.Values[i]));
}
// Continue the partial from 300 to 500
for (int i = 300; i < 500; i++)
{
partial.Update(new TValue(DateTime.UtcNow, src.Values[i]));
}
Assert.Equal(full.Last.Value, partial.Last.Value, 10);
}
[Fact]
public void LargeDataset_NoOverflow()
{
TSeries src = MakeSeries(5000);
int period = 50;
TSeries result = Ahrens.Batch(src, period);
Assert.Equal(5000, result.Count);
Assert.True(double.IsFinite(result.Values[result.Count - 1]));
}
}