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:
@@ -184,76 +184,6 @@ QuanTAlib validates HAMMA against its mathematical definition and internal consi
|
||||
| **Tulip** | ❌ | Not included. |
|
||||
| **Ooples** | ❌ | Not included. |
|
||||
|
||||
### C# Implementation Considerations
|
||||
|
||||
The QuanTAlib HAMMA implementation optimizes Hamming window convolution through precomputation and SIMD-accelerated dot products:
|
||||
|
||||
**Precomputed Weights with Inverse Sum**
|
||||
```csharp
|
||||
ComputeWeights(_weights, period, out _invWeightSum);
|
||||
// ...
|
||||
double twoPiOverPm1 = 2.0 * Math.PI / (period - 1);
|
||||
for (int i = 0; i < period; i++)
|
||||
{
|
||||
double w = 0.54 - 0.46 * Math.Cos(twoPiOverPm1 * i);
|
||||
weights[i] = w;
|
||||
sum += w;
|
||||
}
|
||||
invWeightSum = 1.0 / sum;
|
||||
```
|
||||
Trigonometric operations computed once at construction. Normalization uses multiplication by precomputed inverse rather than division per tick.
|
||||
|
||||
**State Record Struct**
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
private record struct State(double LastValidValue, bool IsInitialized);
|
||||
private State _state;
|
||||
private State _p_state;
|
||||
```
|
||||
Compiler optimizes field layout. The `IsInitialized` flag tracks whether valid data has been seen for proper NaN handling.
|
||||
|
||||
**SIMD-Accelerated Circular Buffer Dot Product**
|
||||
```csharp
|
||||
int part1Len = _period - head;
|
||||
double sum1 = internalBuf.Slice(head, part1Len).DotProduct(_weights.AsSpan(0, part1Len));
|
||||
double sum2 = internalBuf[..head].DotProduct(_weights.AsSpan(part1Len));
|
||||
return (sum1 + sum2) * _invWeightSum;
|
||||
```
|
||||
Full buffer splits into two `DotProduct` calls to handle circular wrap. The extension leverages AVX2/FMA intrinsics when available.
|
||||
|
||||
**Dual Allocation Strategy for Batch**
|
||||
```csharp
|
||||
double[]? weightsArray = period > 256 ? ArrayPool<double>.Shared.Rent(period) : null;
|
||||
Span<double> weights = period <= 256
|
||||
? stackalloc double[period]
|
||||
: weightsArray!.AsSpan(0, period);
|
||||
```
|
||||
Small periods use stack allocation; large periods use `ArrayPool` to avoid heap pressure while respecting stack limits.
|
||||
|
||||
**Incremental Weight Sum During Warmup**
|
||||
```csharp
|
||||
if (count < period)
|
||||
{
|
||||
count++;
|
||||
currentWeightSum += weights[period - count];
|
||||
}
|
||||
```
|
||||
Partial buffer normalization accumulates weight sum incrementally rather than recalculating each tick.
|
||||
|
||||
**Memory Layout**
|
||||
|
||||
| Field | Type | Size | Notes |
|
||||
|:------|:-----|-----:|:------|
|
||||
| `_period` | int | 4B | Window length |
|
||||
| `_weights` | double[] | 8B + L×8B | Hamming coefficients |
|
||||
| `_invWeightSum` | double | 8B | Precomputed 1/Σw |
|
||||
| `_buffer` | RingBuffer | ~40B + L×8B | Circular data buffer |
|
||||
| `_state` | State | 16B | Last valid + initialized flag |
|
||||
| `_p_state` | State | 16B | Previous state for rollback |
|
||||
| **Total** | | ~92B + 2L×8B | Plus object overhead |
|
||||
|
||||
For a typical 14-period: ~92 + 224 ≈ **316 bytes** per instance.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Confusing Hamming and Hanning**: Hamming uses 0.54/0.46 coefficients with edge weights of 0.08. Hanning uses 0.5/0.5 with edge weights of 0.0. They're different windows with different properties.
|
||||
|
||||
Reference in New Issue
Block a user