Quickstart: C#
Verified against the Rust reference. Every one of Wickra's 514 indicators is replayed through all 10 languages and checked bit-for-bit against the Rust core's golden fixtures in CI — the math here is provably identical to every other binding (how).
A five-minute tour of the Wickra C# binding — the first language shim on the C ABI hub. By the end you will have streamed an RSI, run a batch SMA, and read a multi-output MACD, all as idiomatic C#.
Install
The binding ships on NuGet as Wickra with the native library prebuilt for every supported platform (Linux, macOS, Windows — x64 and arm64); there is nothing to compile.
dotnet add package WickraIt targets .NET 8 and later.
The class shape
Every indicator is an IDisposable class over an opaque native handle, with the same operations as the C ABI underneath:
using Wickra;
using var sma = new Sma(14); // throws ArgumentException on invalid params
int w = sma.WarmupPeriod(); // updates until ready: 14
double v = sma.Update(42.0); // NaN while warming up
bool ready = sma.IsReady(); // false until warmed up
sma.Reset(); // back to a fresh state
// disposed (freed) at the end of the using scopeThe alt-chart bar builders (RenkoBars, KagiBars, …) have no WarmupPeriod / IsReady — a candle can complete 0..n bars, so they have no warmup.
Update never revisits the history behind the tick. Prefer using for deterministic cleanup; a SafeHandle also frees the handle from the finalizer, so a missed Dispose never leaks permanently.
Streaming and batch side by side
using Wickra;
// 1. Streaming: feed Wilder's textbook example into RSI(14).
using var rsi = new Rsi(14);
double[] prices =
{
44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42,
45.84, 46.08, 45.89, 46.03, 45.61, 46.28, 46.28, 46.00,
};
for (var i = 0; i < prices.Length; i++)
{
var r = rsi.Update(prices[i]);
if (double.IsFinite(r)) // NaN during the 15-bar warmup
{
Console.WriteLine($"tick {i + 1,2} rsi={r:F4}");
}
}
// 2. Batch: one SMA(3) call over five prices writes NaN at warmup.
using var sma = new Sma(3);
double[] outValues = sma.Batch(new double[] { 1, 2, 3, 4, 5 });
// outValues -> { NaN, NaN, 2.0, 3.0, 4.0 }The first RSI value lands on tick 15. Batch output is bit-for-bit identical to feeding the same inputs through Update one at a time.
The opt-in fast batch
Every single-output Batch has a Span<double> overload that writes into a buffer you reuse, and a BatchFast twin in both forms; MACD, MacdFix and Bollinger Bands have a record-array BatchFast:
var output = new double[prices.Length];
using var sma = new Sma(20);
sma.Batch(prices, output); // exact, no allocation
using var ema = new Ema(20);
double[] fast = ema.BatchFast(prices); // or ema.BatchFast(prices, output)The fast batch runs a SIMD kernel where the indicator has one (moving averages, RSI, ATR, MACD and MACDFIX, Bollinger Bands, the Chaikin oscillator, skewness, Pearson correlation and more). The kernel reassociates the arithmetic, so each value agrees with the exact batch to within a few units in the last place rather than bit for bit; NaN placement and length are identical, and the result is the same on every platform. Where an indicator has no kernel, the fast batch is the exact batch. Keep the exact batch wherever you compare against streaming bit for bit; reach for the fast one when throughput is the point. See Streaming vs Batch.
Multi-output indicators
Indicators with several outputs (MACD, Bollinger, ADX, …) return a nullable record struct — null while warming up, a value once one is ready:
using var macd = new MacdIndicator(12, 26, 9);
foreach (var price in feed)
{
if (macd.Update(price) is { } m)
{
Console.WriteLine($"macd={m.Macd:F4} signal={m.Signal:F4} hist={m.Histogram:F4}");
}
}Candle-input indicators (ATR, ADX, OBV, …) take the OHLCV fields plus a timestamp, e.g. atr.Update(open, high, low, close, volume, timestamp).
A deeper example
examples/csharp/backtest runs a basket of indicators over an OHLCV series; the examples/csharp/ directory also has a multi-indicator streaming demo, multi-timeframe resampling, a Parallel.For fan-out, three strategy examples, and Binance fetch/live examples. Build the C ABI once, then run any of them:
cargo build -p wickra-c --release
dotnet run --project examples/csharp/streamingSee also
- Quickstart: C — the C ABI hub the C# binding links against.
- Streaming vs Batch — the
batch == repeated updatecontract that holds across every binding. - Indicators overview — the full catalogue.
- Source: https://github.com/wickra-lib/wickra