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:
@@ -91,111 +91,3 @@ Each SMA component benefits from SIMD prefix-sum optimization:
|
||||
| **Skender** | ✅ | Matches composite `SMA(SMA)` logic. |
|
||||
| **Tulip** | ✅ | Matches `trima` exactly. |
|
||||
| **Ooples** | N/A | Not implemented. |
|
||||
|
||||
## C# Implementation Considerations
|
||||
|
||||
QuanTAlib's TRIMA uses cascaded SMA composition, achieving O(1) streaming updates by leveraging the O(1) nature of each internal SMA. The implementation demonstrates clean indicator composition:
|
||||
|
||||
### Composition Architecture
|
||||
|
||||
```csharp
|
||||
[SkipLocalsInit]
|
||||
public sealed class Trima : AbstractBase
|
||||
{
|
||||
private readonly Sma _sma1;
|
||||
private readonly Sma _sma2;
|
||||
|
||||
public Trima(int period)
|
||||
{
|
||||
int p1 = (period + 1) / 2;
|
||||
int p2 = period / 2 + 1;
|
||||
|
||||
_sma1 = new Sma(p1);
|
||||
_sma2 = new Sma(p2);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
TRIMA delegates all complexity to its internal SMA instances. Each SMA maintains its own O(1) running sum, so the cascade is also O(1).
|
||||
|
||||
### Key Optimizations
|
||||
|
||||
| Technique | Implementation | Benefit |
|
||||
| :--- | :--- | :--- |
|
||||
| **SMA delegation** | Two internal `Sma` instances | O(1) streaming via running sums |
|
||||
| **Zero state** | No additional fields beyond SMAs | Minimal memory footprint |
|
||||
| **Inline cascade** | `_sma2.Update(_sma1.Update(input))` | No intermediate allocation |
|
||||
| **ArrayPool** | Batch uses rented buffer for SMA1 output | Zero allocation in batch mode |
|
||||
| **Warmup composition** | `WarmupPeriod = p1 + p2 - 1` | Correct cascaded warmup |
|
||||
|
||||
### Streaming Update
|
||||
|
||||
```csharp
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override TValue Update(TValue input, bool isNew = true)
|
||||
{
|
||||
_isNew = isNew;
|
||||
TValue v1 = _sma1.Update(input, isNew);
|
||||
TValue v2 = _sma2.Update(v1, isNew);
|
||||
|
||||
Last = v2;
|
||||
PubEvent(Last, isNew);
|
||||
return Last;
|
||||
}
|
||||
```
|
||||
|
||||
The `isNew` flag propagates through both SMAs, enabling bar correction at both levels.
|
||||
|
||||
### Memory Layout
|
||||
|
||||
| Field | Type | Size | Purpose |
|
||||
| :--- | :--- | :---: | :--- |
|
||||
| `_period` | int | 4 bytes | Original period |
|
||||
| `_sma1` | Sma | ~48 + 8×P₁ bytes | First smoothing stage |
|
||||
| `_sma2` | Sma | ~48 + 8×P₂ bytes | Second smoothing stage |
|
||||
| `_handler` | delegate | 8 bytes | Event handler reference |
|
||||
| `_isNew` | bool | 1 byte | Current bar state |
|
||||
| **Instance total** | | **~110 + 8N bytes** | N = period |
|
||||
|
||||
### Batch Processing
|
||||
|
||||
```csharp
|
||||
public static void Batch(ReadOnlySpan<double> source, Span<double> output, int period)
|
||||
{
|
||||
int p1 = (period + 1) / 2;
|
||||
int p2 = period / 2 + 1;
|
||||
|
||||
double[] tempArray = ArrayPool<double>.Shared.Rent(source.Length);
|
||||
Span<double> tempSpan = tempArray.AsSpan(0, source.Length);
|
||||
|
||||
try
|
||||
{
|
||||
Sma.Batch(source, tempSpan, p1); // First SMA pass
|
||||
Sma.Batch(tempSpan, output, p2); // Second SMA pass
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<double>.Shared.Return(tempArray);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Uses ArrayPool for the intermediate buffer to avoid heap allocation per batch.
|
||||
|
||||
### Bar Correction Propagation
|
||||
|
||||
The `isNew` flag propagates through both internal SMAs:
|
||||
|
||||
```csharp
|
||||
// isNew=false triggers rollback in BOTH SMAs
|
||||
TValue v1 = _sma1.Update(input, isNew); // SMA1 rolls back its running sum
|
||||
TValue v2 = _sma2.Update(v1, isNew); // SMA2 rolls back based on corrected SMA1 output
|
||||
```
|
||||
|
||||
This ensures consistent bar correction across the entire cascade.
|
||||
|
||||
### Common Pitfalls
|
||||
|
||||
1. **Lag**: TRIMA has more lag than SMA, EMA, or WMA. It is a lagging indicator, not a leading one.
|
||||
2. **Signal Generation**: Due to its lag, TRIMA is poor for crossover signals. It is best used for visual trend identification or as a baseline for envelopes (e.g., TMA Bands).
|
||||
3. **Even/Odd Periods**: The exact calculation of $P_1$ and $P_2$ differs slightly between implementations for even periods. QuanTAlib matches the standard definition used by TA-Lib.
|
||||
|
||||
Reference in New Issue
Block a user