mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-31 10:57:43 +00:00
060649192f
- 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
133 lines
4.4 KiB
C#
133 lines
4.4 KiB
C#
using System;
|
|
using Xunit;
|
|
|
|
namespace QuanTAlib;
|
|
|
|
public class StcTests
|
|
{
|
|
private const int CycleLength = 12;
|
|
private const int FastLength = 26;
|
|
private const int SlowLength = 50;
|
|
|
|
private static Stc CreateDefaultStc() => new(kPeriod: CycleLength, dPeriod: CycleLength, fastLength: FastLength, slowLength: SlowLength, smoothing: StcSmoothing.Sigmoid);
|
|
|
|
[Fact]
|
|
public void Constructor_ValidatesInput()
|
|
{
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => new Stc(kPeriod: 1));
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => new Stc(dPeriod: 0));
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => new Stc(fastLength: 1));
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => new Stc(slowLength: 1));
|
|
}
|
|
|
|
[Fact]
|
|
public void Calc_ReturnsValue()
|
|
{
|
|
var stc = CreateDefaultStc();
|
|
var result = stc.Update(new TValue(DateTime.UtcNow, 100));
|
|
// Expect NaN during warmup
|
|
Assert.True(double.IsNaN(result.Value) || double.IsFinite(result.Value));
|
|
}
|
|
|
|
[Fact]
|
|
public void Properties_Accessible()
|
|
{
|
|
var stc = CreateDefaultStc();
|
|
Assert.Equal(0, stc.Last.Value); // Initial value before updates
|
|
Assert.False(stc.IsHot);
|
|
Assert.Contains("Stc", stc.Name, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void IsHot_BecomesTrueWhenBufferFull()
|
|
{
|
|
var stc = CreateDefaultStc();
|
|
int warmup = stc.WarmupPeriod;
|
|
|
|
for (int i = 0; i < warmup - 1; i++)
|
|
{
|
|
stc.Update(new TValue(DateTime.UtcNow, 100));
|
|
Assert.False(stc.IsHot);
|
|
}
|
|
|
|
stc.Update(new TValue(DateTime.UtcNow, 100));
|
|
Assert.True(stc.IsHot);
|
|
}
|
|
|
|
[Fact]
|
|
public void BatchCalc_MatchesIterativeCalc()
|
|
{
|
|
var iterativeStc = CreateDefaultStc();
|
|
var batchStc = CreateDefaultStc();
|
|
var series = new TSeries();
|
|
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 123);
|
|
|
|
for (int i = 0; i < 200; i++)
|
|
{
|
|
var bar = gbm.Next();
|
|
series.Add(bar.Time, bar.Close);
|
|
iterativeStc.Update(new TValue(bar.Time, bar.Close));
|
|
}
|
|
|
|
var batchResult = batchStc.Update(series);
|
|
|
|
Assert.Equal(iterativeStc.Last.Value, batchResult.Last.Value, 1e-9);
|
|
}
|
|
|
|
[Fact]
|
|
public void SpanBatch_MatchesTSeriesBatch()
|
|
{
|
|
// Use default parameters for static calculation
|
|
var series = new TSeries();
|
|
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 123);
|
|
double[] input = new double[200];
|
|
double[] output = new double[200];
|
|
|
|
for (int i = 0; i < 200; i++)
|
|
{
|
|
var bar = gbm.Next();
|
|
series.Add(bar.Time, bar.Close);
|
|
input[i] = bar.Close;
|
|
}
|
|
|
|
var batchStc = CreateDefaultStc();
|
|
var tseriesResult = batchStc.Update(series);
|
|
|
|
Stc.Batch(input.AsSpan(), output.AsSpan(), kPeriod: CycleLength, dPeriod: CycleLength, fastLength: FastLength, slowLength: SlowLength, smoothing: StcSmoothing.Sigmoid);
|
|
|
|
// Compare last value
|
|
Assert.Equal(tseriesResult.Last.Value, output[^1], 1e-9);
|
|
}
|
|
|
|
[Fact]
|
|
public void NaN_Input_HandledSafely()
|
|
{
|
|
var stc = CreateDefaultStc();
|
|
stc.Update(new TValue(DateTime.UtcNow, 100));
|
|
var result = stc.Update(new TValue(DateTime.UtcNow, double.NaN));
|
|
// Should be NaN during warmup
|
|
Assert.True(double.IsNaN(result.Value) || double.IsFinite(result.Value));
|
|
}
|
|
|
|
[Fact]
|
|
public void SmoothingOptions_ProduceDifferentResults()
|
|
{
|
|
var stcSigmoid = new Stc(kPeriod: 10, dPeriod: 10, fastLength: 20, slowLength: 40, smoothing: StcSmoothing.Sigmoid);
|
|
var stcEma = new Stc(kPeriod: 10, dPeriod: 10, fastLength: 20, slowLength: 40, smoothing: StcSmoothing.Ema);
|
|
var stcDigital = new Stc(kPeriod: 10, dPeriod: 10, fastLength: 20, slowLength: 40, smoothing: StcSmoothing.Digital);
|
|
|
|
var gbm = new GBM(startPrice: 100, mu: 0.05, sigma: 0.2, seed: 123);
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
double val = gbm.Next().Close;
|
|
stcSigmoid.Update(new TValue(DateTime.UtcNow, val));
|
|
stcEma.Update(new TValue(DateTime.UtcNow, val));
|
|
stcDigital.Update(new TValue(DateTime.UtcNow, val));
|
|
}
|
|
|
|
Assert.NotEqual(stcSigmoid.Last.Value, stcEma.Last.Value);
|
|
Assert.NotEqual(stcSigmoid.Last.Value, stcDigital.Last.Value);
|
|
}
|
|
}
|