mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 21:18:04 +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:
@@ -13,7 +13,6 @@
|
||||
| **PineScript** | [htit.pine](htit.pine) |
|
||||
| **Signature** | [htit_signature](htit_signature.md) |
|
||||
|
||||
|
||||
- HTIT (Hilbert Transform Instantaneous Trend) is a trend-following indicator that doesn't rely on simple averaging.
|
||||
- No configurable parameters; computation is stateless per bar.
|
||||
- Output range: Tracks input.
|
||||
@@ -179,100 +178,3 @@ The differences with Skender and Ooples arise from:
|
||||
1. **Initialization**: How the first few bars are handled.
|
||||
2. **Precision**: Hardcoded decimals vs exact fractions.
|
||||
3. **Period Constraints**: How strictly the [6, 50] bounds are enforced during intermediate steps.
|
||||
|
||||
## C# Implementation Considerations
|
||||
|
||||
### State Management
|
||||
|
||||
HTIT uses a compact record struct for Hilbert Transform state tracking:
|
||||
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
private record struct State(
|
||||
double I2, double Q2, double Re, double Im,
|
||||
double Period, double SmoothPeriod,
|
||||
double LastValidPrice, int Index
|
||||
);
|
||||
```
|
||||
|
||||
Bar correction uses simple state copy (no RingBuffer snapshot needed for state struct):
|
||||
|
||||
```csharp
|
||||
if (isNew) { _p_state = _state; _state.Index++; }
|
||||
else { _state = _p_state; }
|
||||
```
|
||||
|
||||
### Multiple RingBuffers
|
||||
|
||||
HTIT maintains six separate circular buffers for the multi-stage pipeline:
|
||||
|
||||
```csharp
|
||||
private readonly RingBuffer _priceBuffer; // 64 elements (for IT sum)
|
||||
private readonly RingBuffer _smoothBuffer; // 8 elements
|
||||
private readonly RingBuffer _detrenderBuffer; // 8 elements
|
||||
private readonly RingBuffer _i1Buffer; // 8 elements
|
||||
private readonly RingBuffer _q1Buffer; // 8 elements
|
||||
private readonly RingBuffer _itBuffer; // 8 elements
|
||||
```
|
||||
|
||||
The price buffer is larger (64) to support IT calculation over up to 50 bars.
|
||||
|
||||
### Precomputed Constants
|
||||
|
||||
High-precision rational constants avoid rounding accumulation:
|
||||
|
||||
```csharp
|
||||
private const double c1 = 5.0 / 52.0; // ~0.09615385
|
||||
private const double c2 = 15.0 / 26.0; // ~0.57692308
|
||||
private const double adjSlope = 3.0 / 40.0; // 0.075
|
||||
private const double adjIntercept = 27.0 / 50.0; // 0.54
|
||||
private const double TwoPi = 2.0 * Math.PI;
|
||||
```
|
||||
|
||||
### FMA Usage
|
||||
|
||||
Smoothing operations use FusedMultiplyAdd for precision:
|
||||
|
||||
```csharp
|
||||
_state.I2 = Math.FusedMultiplyAdd(0.2, i2_val, 0.8 * _p_state.I2);
|
||||
_state.Q2 = Math.FusedMultiplyAdd(0.2, q2_val, 0.8 * _p_state.Q2);
|
||||
_state.Re = Math.FusedMultiplyAdd(0.2, re_val, 0.8 * _p_state.Re);
|
||||
_state.Period = Math.FusedMultiplyAdd(0.2, period, 0.8 * prevPeriod);
|
||||
```
|
||||
|
||||
### Stack-Allocated Calculate Method
|
||||
|
||||
The static `Calculate(Span)` method uses stackalloc for zero-allocation batch processing:
|
||||
|
||||
```csharp
|
||||
Span<double> priceBuffer = stackalloc double[64];
|
||||
Span<double> smoothBuffer = stackalloc double[8];
|
||||
// ... etc
|
||||
const int Mask63 = 63; // Power-of-2 masking for circular index
|
||||
const int Mask7 = 7;
|
||||
```
|
||||
|
||||
### Memory Layout
|
||||
|
||||
| Field | Type | Size | Purpose |
|
||||
| :--- | :--- | :---: | :--- |
|
||||
| `_priceBuffer` | RingBuffer | ~8B+512B | Price history (64×8B) |
|
||||
| `_smoothBuffer` | RingBuffer | ~8B+64B | Smoothed prices (8×8B) |
|
||||
| `_detrenderBuffer` | RingBuffer | ~8B+64B | Detrender output |
|
||||
| `_i1Buffer` | RingBuffer | ~8B+64B | In-phase component |
|
||||
| `_q1Buffer` | RingBuffer | ~8B+64B | Quadrature component |
|
||||
| `_itBuffer` | RingBuffer | ~8B+64B | Instantaneous trend |
|
||||
| `_state` | State | ~64B | Current Hilbert state |
|
||||
| `_p_state` | State | ~64B | Previous state for rollback |
|
||||
| **Total** | | **~960B** | Per indicator instance |
|
||||
|
||||
### Numerical Robustness
|
||||
|
||||
Uses `Math.Atan2` for proper quadrant handling in phase calculation, avoiding division-by-zero issues that plague `atan(y/x)` implementations.
|
||||
|
||||
### Common Pitfalls
|
||||
|
||||
1. **Warmup**: This indicator needs significant warmup (at least 12 bars, ideally 50+) for the feedback loops (period smoothing) to stabilize. Don't trust the first 50 bars.
|
||||
2. **Lag**: While it adapts, the trendline still lags because it's essentially a dynamic SMA. The advantage is that the period is optimal for the current market condition, not that it has zero lag.
|
||||
3. **Complexity**: Debugging this is a nightmare. Trust the math.
|
||||
4. **Ranging Markets**: In a pure range, the "trend" should be flat. HTIT handles this well because the cycle cancellation works best when the cycle is clear.
|
||||
|
||||
Reference in New Issue
Block a user