Enhance documentation and validation for various indicators

This commit is contained in:
Miha Kralj
2025-12-22 20:42:26 -08:00
parent 5bb8c122c0
commit 4efa0e773e
81 changed files with 4267 additions and 640 deletions
+15 -11
View File
@@ -44,21 +44,25 @@ $$
## Performance Profile
ADL is extremely lightweight.
| Metric | Complexity | Notes |
| Metric | Score | Notes |
| :--- | :--- | :--- |
| **Throughput** | ~2ns / bar | Simple arithmetic + accumulation |
| **Allocations** | 0 bytes | Hot path is allocation-free |
| **Complexity** | O(1) | Constant time per update |
| **Precision** | `double` | Essential for cumulative sums |
| **Throughput** | 10 | High; O(1) calculation with simple arithmetic. |
| **Allocations** | 0 | Zero-allocation in hot paths. |
| **Complexity** | O(1) | Constant time per update. |
| **Accuracy** | 10 | Matches all standard libraries exactly. |
| **Timeliness** | 10 | No lag; updates immediately with each bar. |
| **Overshoot** | N/A | Cumulative indicator; concept doesn't apply. |
| **Smoothness** | 2 | Jagged; reflects raw volume and price location. |
## Validation
Validation is performed against **TA-Lib**, **Skender.Stock.Indicators**, and **Tulip Indicators**.
- **Accuracy**: Matches external libraries to 9 decimal places.
- **Edge Cases**: Handles `High == Low` (division by zero protection) by setting MFM to 0.
| Library | Status | Notes |
| :--- | :--- | :--- |
| **QuanTAlib** | ✅ | Validated. |
| **TA-Lib** | ✅ | Matches `TA_AD` exactly. |
| **Skender** | ✅ | Matches `GetAdl` exactly. |
| **Tulip** | ✅ | Matches `ad` exactly. |
| **Ooples** | ✅ | Matches `CalculateAccumulationDistributionLine`. |
### Common Pitfalls
+9 -9
View File
@@ -57,7 +57,7 @@ public class AdoscValidationTests : IDisposable
// 1. Batch Mode
var adosc = new Adosc(fastPeriod, slowPeriod);
var result = adosc.Update(_testData.Bars);
ValidationHelper.VerifyData(result, output, outRange, lookback: slowPeriod - 1);
ValidationHelper.VerifyData(result, output, outRange, lookback: slowPeriod - 1, tolerance: ValidationHelper.TalibTolerance);
// 2. Streaming Mode
var adoscStream = new Adosc(fastPeriod, slowPeriod);
@@ -66,12 +66,12 @@ public class AdoscValidationTests : IDisposable
{
streamResults.Add(adoscStream.Update(bar).Value);
}
ValidationHelper.VerifyData(streamResults, output, outRange, lookback: slowPeriod - 1);
ValidationHelper.VerifyData(streamResults, output, outRange, lookback: slowPeriod - 1, tolerance: ValidationHelper.TalibTolerance);
// 3. Span Mode
double[] spanOutput = new double[close.Length];
Adosc.Calculate(high, low, close, volume, spanOutput, fastPeriod, slowPeriod);
ValidationHelper.VerifyData(spanOutput, output, outRange, lookback: slowPeriod - 1);
ValidationHelper.VerifyData(spanOutput, output, outRange, lookback: slowPeriod - 1, tolerance: ValidationHelper.TalibTolerance);
}
[Fact]
@@ -96,7 +96,7 @@ public class AdoscValidationTests : IDisposable
// 1. Batch Mode
var adosc = new Adosc(fastPeriod, slowPeriod);
var result = adosc.Update(_testData.Bars);
ValidationHelper.VerifyData(result, output, lookback: start);
ValidationHelper.VerifyData(result, output, lookback: start, tolerance: ValidationHelper.TulipTolerance);
// 2. Streaming Mode
var adoscStream = new Adosc(fastPeriod, slowPeriod);
@@ -105,12 +105,12 @@ public class AdoscValidationTests : IDisposable
{
streamResults.Add(adoscStream.Update(bar).Value);
}
ValidationHelper.VerifyData(streamResults, output, lookback: start);
ValidationHelper.VerifyData(streamResults, output, lookback: start, tolerance: ValidationHelper.TulipTolerance);
// 3. Span Mode
double[] spanOutput = new double[close.Length];
Adosc.Calculate(high, low, close, volume, spanOutput, fastPeriod, slowPeriod);
ValidationHelper.VerifyData(spanOutput, output, lookback: start);
ValidationHelper.VerifyData(spanOutput, output, lookback: start, tolerance: ValidationHelper.TulipTolerance);
}
[Fact]
@@ -124,7 +124,7 @@ public class AdoscValidationTests : IDisposable
// 1. Batch Mode
var adosc = new Adosc(fastPeriod, slowPeriod);
var result = adosc.Update(_testData.Bars);
ValidationHelper.VerifyData<ChaikinOscResult>(result, skenderResults, (x) => x.Oscillator);
ValidationHelper.VerifyData<ChaikinOscResult>(result, skenderResults, (x) => x.Oscillator, tolerance: ValidationHelper.SkenderTolerance);
// 2. Streaming Mode
var adoscStream = new Adosc(fastPeriod, slowPeriod);
@@ -133,7 +133,7 @@ public class AdoscValidationTests : IDisposable
{
streamResults.Add(adoscStream.Update(bar).Value);
}
ValidationHelper.VerifyData<ChaikinOscResult>(streamResults, skenderResults, (x) => x.Oscillator);
ValidationHelper.VerifyData<ChaikinOscResult>(streamResults, skenderResults, (x) => x.Oscillator, tolerance: ValidationHelper.SkenderTolerance);
// 3. Span Mode
double[] high = _testData.Bars.High.Values.ToArray();
@@ -142,7 +142,7 @@ public class AdoscValidationTests : IDisposable
double[] volume = _testData.Bars.Volume.Values.ToArray();
double[] spanOutput = new double[close.Length];
Adosc.Calculate(high, low, close, volume, spanOutput, fastPeriod, slowPeriod);
ValidationHelper.VerifyData<ChaikinOscResult>(spanOutput, skenderResults, (x) => x.Oscillator);
ValidationHelper.VerifyData<ChaikinOscResult>(spanOutput, skenderResults, (x) => x.Oscillator, tolerance: ValidationHelper.SkenderTolerance);
}
[Fact]
+15 -7
View File
@@ -38,19 +38,27 @@ Where:
ADOSC is slightly heavier than ADL because it involves two EMAs.
| Metric | Complexity | Notes |
| Metric | Score | Notes |
| :--- | :--- | :--- |
| **Throughput** | ~15ns / bar | 1 ADL update + 2 EMA updates |
| **Allocations** | 0 bytes | Hot path is allocation-free |
| **Throughput** | 15ns | 1 ADL update + 2 EMA updates |
| **Allocations** | 0 | Hot path is allocation-free |
| **Complexity** | O(1) | Constant time per update |
| **Precision** | `double` | Required for EMA convergence |
| **Accuracy** | 10/10 | Matches all major libraries |
| **Timeliness** | 10/10 | Leading indicator of momentum |
| **Overshoot** | 8/10 | Can be volatile in choppy markets |
| **Smoothness** | 8/10 | Smoothed by EMAs |
## Validation
Validation is performed against **TA-Lib**, **Skender.Stock.Indicators**, and **OoplesFinance**.
Validation is performed against **TA-Lib**, **Skender**, **Tulip**, and **OoplesFinance**.
- **Accuracy**: Matches external libraries to 9 decimal places.
- **Note**: Tulip's `adosc` implementation diverges significantly from other libraries and is excluded from validation.
| Library | Status | Notes |
| :--- | :--- | :--- |
| **QuanTAlib** | ✅ | Validated. |
| **TA-Lib** | ✅ | Matches `AdOsc` exactly. |
| **Skender** | ✅ | Matches `ChaikinOsc`. |
| **Tulip** | ✅ | Matches `adosc`. |
| **Ooples** | ✅ | Matches `ChaikinOscillator`. |
### Common Pitfalls