mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-25 22:08:05 +00:00
docs: remove C# Implementation Considerations sections, clean up temp scripts, reorganize test files
- 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
This commit is contained in:
@@ -267,109 +267,6 @@ JMA is proprietary. No open-source library implements it. Validation is performe
|
||||
|
||||
7. **Using isNew Incorrectly**: When processing live ticks within the same bar, use `Update(value, isNew: false)`. When a new bar opens, use `isNew: true` (default). Getting this wrong corrupts state and buffer snapshots.
|
||||
|
||||
## C# Implementation Considerations
|
||||
|
||||
### Dual RingBuffer Architecture
|
||||
|
||||
The implementation uses two `RingBuffer` instances:
|
||||
- `_devBuffer` (10 samples): Tracks local deviation for short-term volatility SMA
|
||||
- `_volBuffer` (128 samples): Maintains the volatility distribution for trimmed mean calculation
|
||||
|
||||
Both buffers support `Snapshot()` / `Restore()` for bar correction when `isNew=false`.
|
||||
|
||||
### State Record Struct with Auto Layout
|
||||
|
||||
All IIR filter state is packed into a `record struct` with `LayoutKind.Auto` for compiler-optimized field ordering:
|
||||
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
private record struct State
|
||||
{
|
||||
public double UpperBand;
|
||||
public double LowerBand;
|
||||
public double LastC0;
|
||||
public double LastC8;
|
||||
public double LastA8;
|
||||
public double LastJma;
|
||||
public double LastPrice;
|
||||
public int Bars;
|
||||
}
|
||||
```
|
||||
|
||||
### Precomputed Logarithms for Exp Optimization
|
||||
|
||||
Instead of computing `Math.Pow(base, exponent)` on every bar, the implementation precomputes `log(base)` and uses `Math.Exp(log_base * exponent)`:
|
||||
|
||||
```csharp
|
||||
_logLengthDivider = Math.Log(Math.Max(_lengthDivider, 1e-12));
|
||||
_logSqrtDivider = Math.Log(Math.Max(sqrtDivider, 1e-12));
|
||||
// Later: Math.Exp(_logLengthDivider * d) instead of Math.Pow(_lengthDivider, d)
|
||||
```
|
||||
|
||||
This replaces expensive `Math.Pow` (~80 cycles) with `Math.Exp` (~50 cycles).
|
||||
|
||||
### FusedMultiplyAdd for IIR Calculations
|
||||
|
||||
All EMA and IIR filter operations use `Math.FusedMultiplyAdd` for hardware-optimized precision:
|
||||
|
||||
```csharp
|
||||
double c0 = Math.FusedMultiplyAdd(_state.LastC0, alpha, decay * value);
|
||||
double c8 = Math.FusedMultiplyAdd(_state.LastC8, _lengthDivider, lengthDecay * (value - c0));
|
||||
double a8 = Math.FusedMultiplyAdd(_state.LastA8, alpha2, Math.FusedMultiplyAdd(_phaseParam, c8, c0 - prevJma) * coef);
|
||||
```
|
||||
|
||||
### Stack-Allocated Sorting Buffer
|
||||
|
||||
The trimmed mean calculation uses `stackalloc` instead of heap allocation:
|
||||
|
||||
```csharp
|
||||
Span<double> sorted = stackalloc double[count]; // max 1KB for 128 doubles
|
||||
_volBuffer.CopyTo(sorted);
|
||||
sorted.Sort();
|
||||
```
|
||||
|
||||
This eliminates GC pressure during the per-bar sort operation.
|
||||
|
||||
### SIMD-Accelerated Summation
|
||||
|
||||
The trimmed mean summation uses `SumSIMD()` extension method for vectorized addition of the 65 central values:
|
||||
|
||||
```csharp
|
||||
return sorted.Slice(start, len).SumSIMD() / len;
|
||||
```
|
||||
|
||||
### Bar Correction via State + Buffer Snapshots
|
||||
|
||||
The `_state` / `_p_state` pattern combined with buffer snapshots enables bar correction:
|
||||
|
||||
```csharp
|
||||
if (isNew)
|
||||
{
|
||||
_p_state = _state;
|
||||
_devBuffer.Snapshot();
|
||||
_volBuffer.Snapshot();
|
||||
}
|
||||
else
|
||||
{
|
||||
_state = _p_state;
|
||||
_devBuffer.Restore();
|
||||
_volBuffer.Restore();
|
||||
}
|
||||
```
|
||||
|
||||
### Aggressive Inlining
|
||||
|
||||
All hot-path methods are decorated with `[MethodImpl(MethodImplOptions.AggressiveInlining)]`:
|
||||
- `Step()`, `HandleStateSnapshot()`, `UpdateBands()`, `CalculateIIRFilter()`
|
||||
- `CalculateJurikExponent()`, `CalculateTrimmedMean()`
|
||||
|
||||
### Memory Layout Summary
|
||||
|
||||
- **Two RingBuffers**: 10 × 8 + 128 × 8 = 1,104 bytes
|
||||
- **State struct**: ~72 bytes (8 doubles + 1 int)
|
||||
- **Precomputed coefficients**: ~56 bytes (7 doubles)
|
||||
- **Total per instance**: ~1,250 bytes typical
|
||||
|
||||
## References
|
||||
|
||||
- Jurik Research. (1998-2005). "JMA White Papers." *jurikres.com* (archived).
|
||||
|
||||
Reference in New Issue
Block a user