mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-22 12:38:06 +00:00
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
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
namespace QuanTAlib.Tests;
|
||||
|
||||
public class DecoValidationTests
|
||||
{
|
||||
private const double Tolerance = 1e-10;
|
||||
|
||||
[Fact]
|
||||
public void StreamingMatchesBatch_DefaultParams()
|
||||
{
|
||||
var gbm = new GBM(startPrice: 100.0, mu: 0.05, sigma: 0.2, seed: 42);
|
||||
var bars = gbm.Fetch(500, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
TSeries source = bars.Close;
|
||||
|
||||
// Streaming
|
||||
var deco = new Deco(30, 60);
|
||||
var streaming = new double[source.Count];
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
streaming[i] = deco.Update(source[i]).Value;
|
||||
}
|
||||
|
||||
// Batch span
|
||||
var batch = new double[source.Count];
|
||||
Deco.Batch(source.Values, batch, 30, 60);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
Assert.Equal(batch[i], streaming[i], Tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StreamingMatchesBatch_ShortPeriods()
|
||||
{
|
||||
var gbm = new GBM(startPrice: 50.0, mu: 0.01, sigma: 0.3, seed: 7);
|
||||
var bars = gbm.Fetch(200, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
TSeries source = bars.Close;
|
||||
|
||||
var deco = new Deco(5, 15);
|
||||
var streaming = new double[source.Count];
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
streaming[i] = deco.Update(source[i]).Value;
|
||||
}
|
||||
|
||||
var batch = new double[source.Count];
|
||||
Deco.Batch(source.Values, batch, 5, 15);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
Assert.Equal(batch[i], streaming[i], Tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstantPrice_OscillatesAtZero()
|
||||
{
|
||||
var source = new TSeries();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
source.Add(new TValue(DateTime.UtcNow.AddSeconds(i), 50.0));
|
||||
}
|
||||
|
||||
var deco = new Deco(10, 20);
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
var result = deco.Update(source[i]);
|
||||
if (i >= 2)
|
||||
{
|
||||
Assert.Equal(0.0, result.Value, Tolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deterministic_SameInputSameOutput()
|
||||
{
|
||||
var gbm = new GBM(startPrice: 100.0, mu: 0.05, sigma: 0.2, seed: 123);
|
||||
var bars = gbm.Fetch(300, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
TSeries source = bars.Close;
|
||||
|
||||
var deco1 = new Deco(10, 30);
|
||||
var deco2 = new Deco(10, 30);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
var r1 = deco1.Update(source[i]);
|
||||
var r2 = deco2.Update(source[i]);
|
||||
Assert.Equal(r1.Value, r2.Value, Tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DirectionalCorrectness_UpTrend()
|
||||
{
|
||||
// Exponential growth produces non-zero HP output (linear ramp has zero second-difference)
|
||||
var deco = new Deco(5, 10);
|
||||
double lastVal = 0;
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
var result = deco.Update(new TValue(DateTime.UtcNow.AddSeconds(i), 100.0 * Math.Exp(0.02 * i)));
|
||||
lastVal = result.Value;
|
||||
}
|
||||
// Exponential uptrend produces non-zero DECO
|
||||
Assert.NotEqual(0.0, lastVal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SymmetryCheck_OppositeInputs()
|
||||
{
|
||||
// Sinusoidal inputs with opposite phase should produce opposite-sign DECO values
|
||||
var decoUp = new Deco(5, 10);
|
||||
var decoDown = new Deco(5, 10);
|
||||
|
||||
double lastUp = 0, lastDown = 0;
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
double phase = 2.0 * Math.PI * i / 20.0; // period=20 bars
|
||||
var rUp = decoUp.Update(new TValue(DateTime.UtcNow.AddSeconds(i), 100.0 + 10.0 * Math.Sin(phase)));
|
||||
var rDown = decoDown.Update(new TValue(DateTime.UtcNow.AddSeconds(i), 100.0 - 10.0 * Math.Sin(phase)));
|
||||
lastUp = rUp.Value;
|
||||
lastDown = rDown.Value;
|
||||
}
|
||||
// Opposite-phase sinusoidal inputs should produce opposite-sign DECO values
|
||||
Assert.True(lastUp * lastDown < 0,
|
||||
$"Expected opposite signs: up={lastUp}, down={lastDown}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HpFilter_Components_SumCorrectly()
|
||||
{
|
||||
// Verify that the HP_long and HP_short filters produce sensible output:
|
||||
// For constant input, both HP outputs should be zero, hence DECO = 0
|
||||
var source = new double[50];
|
||||
Array.Fill(source, 42.0);
|
||||
var output = new double[50];
|
||||
Deco.Batch(source, output, 10, 20);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
Assert.Equal(0.0, output[i], Tolerance);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LargeDataset_NoOverflow()
|
||||
{
|
||||
var gbm = new GBM(startPrice: 1000.0, mu: 0.1, sigma: 0.5, seed: 55);
|
||||
var bars = gbm.Fetch(5000, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
TSeries source = bars.Close;
|
||||
|
||||
var output = new double[source.Count];
|
||||
var ex = Record.Exception(() => Deco.Batch(source.Values, output, 30, 60));
|
||||
Assert.Null(ex);
|
||||
|
||||
for (int i = 0; i < source.Count; i++)
|
||||
{
|
||||
Assert.True(double.IsFinite(output[i]), $"Non-finite at index {i}");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CalculateMethod_ReturnsConsistentResults()
|
||||
{
|
||||
var gbm = new GBM(startPrice: 100.0, mu: 0.05, sigma: 0.2, seed: 42);
|
||||
var bars = gbm.Fetch(200, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
TSeries source = bars.Close;
|
||||
|
||||
var (results, indicator) = Deco.Calculate(source, 15, 30);
|
||||
Assert.Equal(source.Count, results.Count);
|
||||
Assert.True(indicator.IsHot);
|
||||
Assert.True(double.IsFinite(results.Values[^1]));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user