mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-29 02:07:42 +00:00
269 lines
9.6 KiB
Markdown
269 lines
9.6 KiB
Markdown
|
|
# API Reference
|
|||
|
|
|
|||
|
|
QuanTAlib employs a Tri-Modal Architecture to unify high-performance batch processing with low-latency streaming updates. This design addresses the fundamental tension in quantitative finance: backtesting requires processing millions of bars quickly, while live trading requires sub-microsecond updates with zero allocation.
|
|||
|
|
|
|||
|
|
All indicators inherit from `AbstractBase` and implement `ITValuePublisher`. The API is consistent across every indicator in the library.
|
|||
|
|
|
|||
|
|
## Core Interface
|
|||
|
|
|
|||
|
|
Every indicator exposes these properties and methods:
|
|||
|
|
|
|||
|
|
### Properties
|
|||
|
|
|
|||
|
|
| Property | Type | Description |
|
|||
|
|
| :------- | :--- | :---------- |
|
|||
|
|
| `Name` | `string` | Descriptive identifier (e.g., `"Sma(14)"`) |
|
|||
|
|
| `Last` | `TValue` | Most recent calculated value (timestamp + value) |
|
|||
|
|
| `IsHot` | `bool` | True when enough data has accumulated for valid output |
|
|||
|
|
| `WarmupPeriod` | `int` | Samples required before `IsHot` becomes true |
|
|||
|
|
| `Pub` | `event` | Fires when a new value is calculated (reactive mode) |
|
|||
|
|
|
|||
|
|
### Methods
|
|||
|
|
|
|||
|
|
| Method | Signature | Purpose |
|
|||
|
|
| :----- | :-------- | :------ |
|
|||
|
|
| `Update` | `TValue Update(TValue input, bool isNew = true)` | Process single value (streaming) |
|
|||
|
|
| `Batch` | `static void Batch(ReadOnlySpan<double>, Span<double>, int)` | Bulk calculation (batch) |
|
|||
|
|
| `Prime` | `void Prime(ReadOnlySpan<double> source)` | Initialize state from history |
|
|||
|
|
| `Reset` | `void Reset()` | Clear state, return to initial condition |
|
|||
|
|
|
|||
|
|
## Mode A: Batch Processing
|
|||
|
|
|
|||
|
|
**Use case:** Backtesting, historical analysis, optimization runs.
|
|||
|
|
|
|||
|
|
Batch mode provides stateless, SIMD-accelerated processing. Zero heap allocation. Maximum throughput.
|
|||
|
|
|
|||
|
|
### Span-Based (Zero Allocation)
|
|||
|
|
|
|||
|
|
The fastest path. Operates directly on memory spans. Uses AVX2/AVX-512/NEON instructions where available.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
double[] prices = LoadHistoricalData(); // 1,000,000 bars
|
|||
|
|
double[] results = new double[prices.Length];
|
|||
|
|
|
|||
|
|
// In-place calculation, zero allocation
|
|||
|
|
Sma.Batch(prices.AsSpan(), results.AsSpan(), period: 14);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Performance: 500,000 bars in ~320 ¼s on modern hardware.
|
|||
|
|
|
|||
|
|
### TSeries-Based (Convenience)
|
|||
|
|
|
|||
|
|
Wrapper for timestamp-aligned series. Slightly slower, but handles metadata.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
TSeries history = LoadTimeSeriesData();
|
|||
|
|
TSeries smaValues = Sma.Batch(history, period: 14);
|
|||
|
|
|
|||
|
|
// Timestamps preserved and aligned
|
|||
|
|
Console.WriteLine($"SMA at {smaValues[100].Time}: {smaValues[100].Value}");
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Mode B: Streaming Updates
|
|||
|
|
|
|||
|
|
**Use case:** Live trading, real-time charting, tick-by-tick processing.
|
|||
|
|
|
|||
|
|
Streaming mode handles sequential data with O(1) complexity per update. Internal state (circular buffers, running sums) enables sub-microsecond latency.
|
|||
|
|
|
|||
|
|
### Standard Update
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
var sma = new Sma(period: 14);
|
|||
|
|
|
|||
|
|
foreach (var bar in liveDataFeed)
|
|||
|
|
{
|
|||
|
|
TValue result = sma.Update(new TValue(bar.Time, bar.Close));
|
|||
|
|
|
|||
|
|
if (result.IsHot)
|
|||
|
|
{
|
|||
|
|
// Valid output, safe to use for trading decisions
|
|||
|
|
ProcessSignal(result.Value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Bar Correction (isNew Parameter)
|
|||
|
|
|
|||
|
|
Markets send corrections. The `isNew` parameter distinguishes between new bars and updates to the current bar.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
var indicator = new Sma(14);
|
|||
|
|
|
|||
|
|
// Bar opens at 09:30:00
|
|||
|
|
indicator.Update(new TValue(time_0930, 100.0), isNew: true);
|
|||
|
|
|
|||
|
|
// Ticks update current bar (same timestamp)
|
|||
|
|
indicator.Update(new TValue(time_0930, 100.5), isNew: false); // Correction
|
|||
|
|
indicator.Update(new TValue(time_0930, 101.2), isNew: false); // Correction
|
|||
|
|
indicator.Update(new TValue(time_0930, 100.8), isNew: false); // Correction
|
|||
|
|
|
|||
|
|
// New bar opens at 09:31:00
|
|||
|
|
indicator.Update(new TValue(time_0931, 101.0), isNew: true);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
When `isNew: false`, the indicator rolls back to the previous state before applying the new value. No cumulative drift from repeated corrections.
|
|||
|
|
|
|||
|
|
### Reactive Chaining
|
|||
|
|
|
|||
|
|
Indicators subscribe to `ITValuePublisher` sources. Updates propagate automatically.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
var source = new TSeries();
|
|||
|
|
var sma = new Sma(source, period: 14); // Subscribes to source
|
|||
|
|
var ema = new Ema(sma, period: 5); // Subscribes to sma
|
|||
|
|
|
|||
|
|
// Single add triggers cascade: source ’ sma ’ ema
|
|||
|
|
source.Add(new TValue(DateTime.UtcNow, 100.0));
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Event-based chaining enables complex indicator pipelines without manual orchestration.
|
|||
|
|
|
|||
|
|
## Mode C: Priming
|
|||
|
|
|
|||
|
|
**Use case:** Transitioning from historical data to live streaming.
|
|||
|
|
|
|||
|
|
Priming hydrates a streaming instance using the minimal tail of historical data. The indicator processes only enough history to fill its internal buffers, then becomes ready for live updates.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
var indicator = new Sma(period: 14);
|
|||
|
|
double[] history = LoadHistoricalData(); // 100,000 bars
|
|||
|
|
|
|||
|
|
// Processes only the last ~14 bars needed for state
|
|||
|
|
// O(warmup) initialization instead of O(history)
|
|||
|
|
indicator.Prime(history.AsSpan());
|
|||
|
|
|
|||
|
|
Console.WriteLine(indicator.IsHot); // true
|
|||
|
|
Console.WriteLine(indicator.Last); // Contains valid value
|
|||
|
|
|
|||
|
|
// Ready for live data
|
|||
|
|
indicator.Update(nextLiveTick);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## One-Shot Hybrid (Calculate)
|
|||
|
|
|
|||
|
|
Combines batch processing with priming. Returns both the complete historical results and a warmed-up instance ready for streaming.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
TSeries history = LoadTimeSeriesData();
|
|||
|
|
|
|||
|
|
// Single call: batch process history + prime indicator
|
|||
|
|
var (results, indicator) = Sma.Calculate(history, period: 14);
|
|||
|
|
|
|||
|
|
// 'results' contains full calculated history
|
|||
|
|
PlotChart(results);
|
|||
|
|
|
|||
|
|
// 'indicator' is warmed up, ready for live updates
|
|||
|
|
indicator.Update(nextLiveTick);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
This pattern eliminates the common mistake of running batch calculation, then creating a separate streaming instance that starts cold.
|
|||
|
|
|
|||
|
|
## Validity and Convergence
|
|||
|
|
|
|||
|
|
### IsHot Property
|
|||
|
|
|
|||
|
|
`IsHot` indicates whether the indicator has accumulated enough data for mathematically valid output.
|
|||
|
|
|
|||
|
|
| Indicator Type | Warmup Period | IsHot Becomes True |
|
|||
|
|
| :------------- | :------------ | :----------------- |
|
|||
|
|
| Fixed-window (SMA, RSI) | `period` | After `period` bars |
|
|||
|
|
| Recursive (EMA, MACD) | `~3 × period` | After convergence threshold |
|
|||
|
|
| Multi-component (Bollinger) | `max(period, stddev_period)` | After longest component |
|
|||
|
|
|
|||
|
|
### Streaming Context
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
var sma = new Sma(10);
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 15; i++)
|
|||
|
|
{
|
|||
|
|
var result = sma.Update(new TValue(DateTime.UtcNow, prices[i]));
|
|||
|
|
Console.WriteLine($"Bar {i}: IsHot = {result.IsHot}");
|
|||
|
|
}
|
|||
|
|
// Bars 0-8: IsHot = false
|
|||
|
|
// Bars 9-14: IsHot = true
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Batch Context
|
|||
|
|
|
|||
|
|
Batch output contains "cold" values at the beginning. The number of cold values equals `WarmupPeriod`.
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
TSeries results = Sma.Batch(history, period: 14);
|
|||
|
|
|
|||
|
|
// Skip cold values when analyzing
|
|||
|
|
for (int i = 13; i < results.Count; i++) // Start at index 13 (period - 1)
|
|||
|
|
{
|
|||
|
|
ProcessValidValue(results[i]);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
For recursive indicators (EMA, DEMA, T3), the warmup extends beyond the nominal period. A 14-period EMA requires approximately 42 bars (3 × period) to converge within 1% of the true value.
|
|||
|
|
|
|||
|
|
## Architecture Diagram
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
|