Files
QuanTAlib/docs/api.md
T

269 lines
9.6 KiB
Markdown
Raw Normal View History

# 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

 QuanTAlib Tri-Modal API 
$
 
 Historical Data Live Data 
   
 ¼  
   
  Batch    
  Mode    
 ,   
    
  Results   
 ¼ ¼ ¼ 
   
 Backtest   Streaming  
  Output   Mode  
  , 
  
 $ 
   
 ¼ ¼ 
   
  Prime   IsHot  
  Mode  Hydrate State  = true  
   
 

```
## Error Handling
### Invalid Parameters
Constructors validate parameters and throw `ArgumentException` with the parameter name.
```csharp
try
{
var sma = new Sma(period: 0); // Invalid
}
catch (ArgumentException ex)
{
// ex.ParamName == "period"
// ex.Message contains "must be greater than 0"
}
```
### NaN and Infinity Handling
When input contains non-finite values (`NaN`, `+`, `-`), QuanTAlib substitutes the last valid value. This prevents NaN propagation through indicator chains.
```csharp
var sma = new Sma(14);
sma.Update(new TValue(t1, 100.0)); // Valid
sma.Update(new TValue(t2, double.NaN)); // Uses 100.0 internally
sma.Update(new TValue(t3, 101.0)); // Valid
```
The output never contains NaN unless all inputs were NaN.
## Thread Safety
QuanTAlib indicators are not thread-safe. Each indicator instance should be accessed from a single thread. For multi-threaded scenarios, create separate indicator instances per thread or implement external synchronization.