mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-31 19:07:42 +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
118 lines
4.0 KiB
C#
118 lines
4.0 KiB
C#
using OoplesFinance.StockIndicators;
|
|
using OoplesFinance.StockIndicators.Models;
|
|
using System;
|
|
using System.Linq;
|
|
using Skender.Stock.Indicators;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace QuanTAlib.Tests;
|
|
|
|
public sealed class StcValidationTests : IDisposable
|
|
{
|
|
private readonly ValidationTestData _testData;
|
|
private readonly ITestOutputHelper _output;
|
|
|
|
public StcValidationTests(ITestOutputHelper output)
|
|
{
|
|
_output = output;
|
|
_testData = new ValidationTestData();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_testData.Dispose();
|
|
}
|
|
|
|
[Fact]
|
|
public void Validate_Skender_Stc_Deviation()
|
|
{
|
|
// Skender's STC implementation uses a "Single Smoothed" approach (Stoch of MACD).
|
|
// QuanTAlib implements the standard "Double Smoothed" approach (Stoch of Stoch of MACD),
|
|
// as originally defined by Schaff.
|
|
//
|
|
// Example mismatch at index 333:
|
|
// QuanTAlib (Double Smoothed) = 50.0
|
|
// Skender (Single Smoothed) = 97.05
|
|
//
|
|
// This test documents this known deviation rather than failing on it.
|
|
|
|
const int cycle = 10;
|
|
int fast = 23;
|
|
int slow = 50;
|
|
|
|
var sResult = _testData.SkenderQuotes.GetStc(cycle, fast, slow).ToList();
|
|
var qStc = new Stc(kPeriod: cycle, dPeriod: 3, fastLength: fast, slowLength: slow, smoothing: StcSmoothing.Ema);
|
|
var qResult = qStc.Update(_testData.Data);
|
|
|
|
// Skender recommends S+C+250 warmup. 50+10+250 = 310.
|
|
int skip = 310;
|
|
double sumSq = 0;
|
|
int count = 0;
|
|
|
|
for (int i = skip; i < qResult.Count; i++)
|
|
{
|
|
double sVal = sResult[i].Stc ?? double.NaN;
|
|
double qVal = qResult[i].Value;
|
|
|
|
if (!double.IsNaN(sVal) && !double.IsNaN(qVal))
|
|
{
|
|
sumSq += (sVal - qVal) * (sVal - qVal);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
double rmse = Math.Sqrt(sumSq / count);
|
|
_output.WriteLine($"Known Methodology Deviation - RMSE: {rmse:F4}");
|
|
|
|
// Assert that we are essentially different (RMSE > 5.0 implies significant deviation)
|
|
// If they accidentally matched (e.g. if we broke our logic to match Skender), this should fail.
|
|
Assert.True(rmse > 5.0, "QuanTAlib STC matches Skender STC, which suggests regression to Single Smoothed logic.");
|
|
|
|
// Assert values are valid
|
|
for (int i = skip; i < qResult.Count; i++)
|
|
{
|
|
Assert.True(double.IsFinite(qResult[i].Value));
|
|
Assert.InRange(qResult[i].Value, 0, 100);
|
|
}
|
|
}
|
|
|
|
// ── Cross-library: OoplesFinance ──────────────────────────────────────────
|
|
[Fact]
|
|
public void Stc_MatchesOoples_Structural()
|
|
{
|
|
var ooplesData = _testData.SkenderQuotes.Select(static q => new TickerData
|
|
{
|
|
Date = q.Date,
|
|
Open = (double)q.Open,
|
|
High = (double)q.High,
|
|
Low = (double)q.Low,
|
|
Close = (double)q.Close,
|
|
Volume = (double)q.Volume
|
|
}).ToList();
|
|
|
|
var stockData = new StockData(ooplesData);
|
|
var oResult = stockData.CalculateSchaffTrendCycle();
|
|
var oValues = oResult.OutputValues.Values.First();
|
|
|
|
var stc = new Stc(kPeriod: 10, dPeriod: 3, fastLength: 23, slowLength: 50, smoothing: StcSmoothing.Ema);
|
|
var qValues = new List<double>();
|
|
foreach (var item in _testData.Data)
|
|
{
|
|
qValues.Add(stc.Update(item).Value);
|
|
}
|
|
|
|
Assert.True(oValues.Count > 0, "Ooples STC must produce output");
|
|
int finiteCount = 0;
|
|
for (int i = 50; i < Math.Min(oValues.Count, qValues.Count); i++)
|
|
{
|
|
if (double.IsFinite(oValues[i]) && double.IsFinite(qValues[i]))
|
|
{
|
|
finiteCount++;
|
|
}
|
|
}
|
|
Assert.True(finiteCount > 100, $"Expected >100 finite STC pairs, got {finiteCount}");
|
|
_output.WriteLine($"STC Ooples structural: {finiteCount} finite pairs verified.");
|
|
}
|
|
}
|