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:
Miha Kralj
2026-03-12 12:34:16 -07:00
parent 8937b0c0fa
commit 060649192f
1149 changed files with 1780 additions and 3316 deletions
-103
View File
@@ -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).