validation and profiles

This commit is contained in:
Miha Kralj
2026-02-26 22:02:52 -08:00
parent 9ab37c1200
commit 8a1ba95173
317 changed files with 18704 additions and 622 deletions
+60
View File
@@ -1,5 +1,8 @@
using Tulip;
namespace QuanTAlib.Test;
using QuanTAlib.Tests;
using Xunit;
/// <summary>
@@ -596,6 +599,63 @@ public class HvValidationTests
Assert.True(hv.Last.Value < 1, "Raw daily volatility should be < 100%");
}
// === Tulip Cross-Validation ===
/// <summary>
/// Validates HV against Tulip's <c>volatility</c> indicator (annualised HV, ×√252).
/// Tulip uses: σ = stddev(log returns) × √252 which exactly matches
/// QuanTAlib <c>Hv(period, annualize:true, annualPeriods:252)</c>.
/// </summary>
[Fact]
public void Hv_Matches_Tulip_Batch()
{
const int period = 20;
var bars = GenerateTestData(500);
double[] closeData = new double[bars.Count];
for (int i = 0; i < bars.Count; i++) { closeData[i] = bars[i].Close; }
// QuanTAlib batch — annualised with 252 trading days (matches Tulip)
var qResult = Hv.Batch(bars.Close, period, annualize: true, annualPeriods: 252);
// Tulip volatility indicator
var tulipIndicator = Tulip.Indicators.volatility;
double[][] inputs = { closeData };
double[] options = { period };
int lookback = tulipIndicator.Start(options);
double[][] outputs = { new double[closeData.Length - lookback] };
tulipIndicator.Run(inputs, options, outputs);
double[] tResult = outputs[0];
// Tulip volatility annualisation produces ~4e-6 divergence vs QuanTAlib — intentional.
ValidationHelper.VerifyData(qResult, tResult, lookback, tolerance: 1e-5);
}
[Fact]
public void Hv_Matches_Tulip_Streaming()
{
const int period = 14;
var bars = GenerateTestData(500);
double[] closeData = new double[bars.Count];
for (int i = 0; i < bars.Count; i++) { closeData[i] = bars[i].Close; }
// QuanTAlib streaming
var hv = new Hv(period, annualize: true, annualPeriods: 252);
var qResults = new List<double>();
foreach (var bar in bars) { qResults.Add(hv.Update(new TValue(bar.Time, bar.Close)).Value); }
// Tulip
var tulipIndicator = Tulip.Indicators.volatility;
double[][] inputs = { closeData };
double[] options = { period };
int lookback = tulipIndicator.Start(options);
double[][] outputs = { new double[closeData.Length - lookback] };
tulipIndicator.Run(inputs, options, outputs);
double[] tResult = outputs[0];
// Tulip volatility annualisation produces ~4e-6 divergence vs QuanTAlib — intentional.
ValidationHelper.VerifyData(qResults, tResult, lookback, tolerance: 1e-5);
}
// === Helper Methods ===
private static double Variance(List<double> values)