mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 04:58:08 +00:00
Enhance documentation and validation for various indicators
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OoplesFinance.StockIndicators;
|
||||
using OoplesFinance.StockIndicators.Enums;
|
||||
using OoplesFinance.StockIndicators.Models;
|
||||
using Skender.Stock.Indicators;
|
||||
using Tulip;
|
||||
using Xunit;
|
||||
@@ -152,4 +155,39 @@ public class HmaValidationTests : IDisposable
|
||||
}
|
||||
_output.WriteLine("HMA Span validated successfully against Skender");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_Ooples_Batch()
|
||||
{
|
||||
// Ooples uses Math.Round for sqrt(period) and period/2, while QuanTAlib uses integer truncation (floor).
|
||||
// This causes discrepancies for periods where the fractional part is >= 0.5 (e.g., sqrt(14) = 3.74 -> 4 vs 3).
|
||||
// We test only periods where the rounding logic yields the same result.
|
||||
int[] periods = { 9, 20, 50 };
|
||||
|
||||
// Prepare data for Ooples (List<TickerData>)
|
||||
var ooplesData = _testData.SkenderQuotes.Select(q => new TickerData
|
||||
{
|
||||
Date = q.Date,
|
||||
Close = (double)q.Close,
|
||||
High = (double)q.High,
|
||||
Low = (double)q.Low,
|
||||
Open = (double)q.Open,
|
||||
Volume = (double)q.Volume
|
||||
}).ToList();
|
||||
|
||||
foreach (var period in periods)
|
||||
{
|
||||
// Calculate QuanTAlib HMA (batch TSeries)
|
||||
var hma = new global::QuanTAlib.Hma(period);
|
||||
var qResult = hma.Update(_testData.Data);
|
||||
|
||||
// Calculate Ooples HMA
|
||||
var stockData = new StockData(ooplesData);
|
||||
var sResult = Calculations.CalculateHullMovingAverage(stockData, length: period).OutputValues.Values.First();
|
||||
|
||||
// Compare last 100 records
|
||||
ValidationHelper.VerifyData(qResult, sResult, (s) => s, 100, 1.0);
|
||||
}
|
||||
_output.WriteLine("HMA Batch(TSeries) validated successfully against Ooples");
|
||||
}
|
||||
}
|
||||
|
||||
+25
-11
@@ -31,23 +31,37 @@ Where $N$ is the period.
|
||||
|
||||
HMA is computationally more intensive than a simple WMA due to the three passes, but our implementation optimizes the intermediate step.
|
||||
|
||||
| Metric | Complexity | Notes |
|
||||
| Metric | Score | Notes |
|
||||
| :--- | :--- | :--- |
|
||||
| **Throughput** | High | 3x WMA cost + vector math |
|
||||
| **Complexity** | O(1) | Constant time update |
|
||||
| **Accuracy** | 8/10 | Excellent at tracking price action |
|
||||
| **Timeliness** | 9/10 | Very responsive, minimal lag |
|
||||
| **Overshoot** | 5/10 | Prone to overshoot due to lag correction |
|
||||
| **Smoothness** | 8/10 | Surprisingly smooth given its speed |
|
||||
| **Throughput** | ★★★★☆ | 3x WMA cost + vector math. |
|
||||
| **Allocations** | ★★★★★ | 0 bytes; hot path is allocation-free. |
|
||||
| **Complexity** | ★★★★★ | O(1) constant time update. |
|
||||
| **Precision** | ★★★★★ | `double` precision. |
|
||||
|
||||
### Zero-Allocation Design
|
||||
|
||||
HMA is implemented by chaining three `Wma` instances. Since `Wma` is zero-allocation, HMA inherits this property.
|
||||
|
||||
## Validation
|
||||
|
||||
Validated against Alan Hull's original formula and standard library implementations.
|
||||
Validated against Skender, Tulip, and Ooples.
|
||||
|
||||
| Provider | Error Tolerance | Notes |
|
||||
| Library | Status | Notes |
|
||||
| :--- | :--- | :--- |
|
||||
| **Fidelity** | $10^{-9}$ | Matches standard HMA |
|
||||
| **Skender** | $10^{-9}$ | Matches `GetHma` |
|
||||
| **Skender** | ✅ | Matches `GetHma`. |
|
||||
| **Tulip** | ✅ | Matches `hma`. |
|
||||
| **Ooples** | ✅ | Matches `CalculateHullMovingAverage` (with rounding caveats). |
|
||||
| **TA-Lib** | ❌ | Not implemented. |
|
||||
|
||||
### External Library Discrepancies
|
||||
|
||||
**OoplesFinance.StockIndicators**:
|
||||
Discrepancies exist due to different rounding methods for integer periods.
|
||||
|
||||
* **QuanTAlib**: Uses integer truncation (floor) for $N/2$ and $\sqrt{N}$.
|
||||
* **Ooples**: Uses `Math.Round` (nearest integer).
|
||||
|
||||
This results in different effective periods for $N=14$ ($\sqrt{14} \approx 3.74 \to 3$ vs $4$) and others where the fractional part $\ge 0.5$. Validation tests match exactly for periods where rounding logic aligns (e.g., $N=9, 20, 50$).
|
||||
|
||||
### Common Pitfalls
|
||||
|
||||
|
||||
Reference in New Issue
Block a user