A high-performance backtesting engine for algorithmic trading strategies in .NET.
High-Performance Backtest.Net is a specialized backtesting library designed for quantitative trading applications. It processes multi-timeframe candlestick data across multiple symbols, simulating tick-by-tick strategy execution with proper warmup periods and OHLC handling.
- Multi-Symbol Support: Process multiple trading symbols in parallel
- Multi-Timeframe: Handle multiple timeframes per symbol with automatic synchronization
- Performance Optimized: 10 iteratively optimized engine versions with zero-allocation patterns
- Data Splitting: Intelligent data partitioning for memory-efficient large-scale backtests
- Cancellation Support: Graceful async cancellation with progress tracking
| Feature | Description |
|---|---|
| EngineV10 | Latest engine with Span-based iteration, binary search, and parallel processing |
| SymbolDataSplitter | Partitions large datasets into memory-efficient chunks |
| Warmup Handling | Configurable warmup candle counts per timeframe |
| OHLC Simulation | Accurate current-candle OHLC handling during backtest |
| Progress Tracking | Real-time progress from 0-100% |
| SIMD Acceleration | Leverages SimdLinq for vectorized operations |
The library implements sophisticated performance techniques:
- Zero-Allocation Hot Paths: Uses
Span<T>andCollectionsMarshal.AsSpan - Parallel Processing:
Parallel.ForEachfor symbol-level parallelism - Binary Search: O(log n) candlestick lookups
- Aggressive Inlining:
[MethodImpl(MethodImplOptions.AggressiveInlining)] - Sealed Classes: JIT optimization hints
dotnet add package Backtest.Net<PackageReference Include="Backtest.Net" Version="4.1.14" />Note
Requires .NET 9.0 or later.
using Backtest.Net.Engines;
using Backtest.Net.SymbolsData;
using Backtest.Net.SymbolDataSplitters;
using Backtest.Net.Timeframes;
using Backtest.Net.Enums;
// 1. Prepare your symbol data (candlesticks per timeframe)
// Candlestick properties: OpenTime, Open, High, Low, Close, CloseTime, Volume
var symbolsData = new List<SymbolDataV2>
{
new SymbolDataV2
{
Symbol = "BTCUSDT",
Timeframes = new List<TimeframeV2>
{
new TimeframeV2
{
Timeframe = CandlestickInterval.OneMinute,
Candlesticks = yourOneMinuteCandles
},
new TimeframeV2
{
Timeframe = CandlestickInterval.OneHour,
Candlesticks = yourOneHourCandles
}
}
}
};
// 2. Split data for efficient processing
var splitter = new SymbolDataSplitterV2(
daysPerSplit: 30,
warmupCandlesCount: 100,
backtestingStartDateTime: new DateTime(2024, 1, 1)
);
var splitData = await splitter.SplitAsyncV2(symbolsData);
// 3. Create and configure the engine
var engine = new EngineV10(
warmupCandlesCount: 100,
sortCandlesInDescOrder: false,
useFullCandleForCurrent: false
);
// 4. Set up your strategy callback
engine.OnTick = async (symbolData) =>
{
foreach (var symbol in symbolData)
{
var latestCandle = symbol.Timeframes[0].Candlesticks[^1];
// Your strategy logic here
Console.WriteLine($"{symbol.Symbol}: Close = {latestCandle.Close}");
}
};
// 5. Run the backtest
await engine.RunAsync(splitData);
Console.WriteLine($"Progress: {engine.GetProgress()}%");using var cts = new CancellationTokenSource();
engine.OnCancellationFinishedDelegate = () =>
{
Console.WriteLine("Backtest cancelled gracefully");
};
// Cancel after 30 seconds
cts.CancelAfter(TimeSpan.FromSeconds(30));
await engine.RunAsync(splitData, cts.Token);| Engine | Description | Use Case |
|---|---|---|
EngineV8 |
SymbolDataV2 support | Standard workloads |
EngineV9 |
Optimized OHLC handling | Memory-sensitive scenarios |
EngineV10 |
Full optimization suite | Production recommended |
Tip
Use EngineV10 for new projects. It provides the best performance through zero-allocation patterns and parallel processing.
Performance benchmarks run on Apple M3 Max with .NET 9.0, processing 4 million candlesticks (1 symbol × 4 timeframes × 1,000,000 candles each):
| Method | Mean | Error | StdDev | Gen0 | Allocated |
|---|---|---|---|---|---|
| EngineV8Run | 125.7 ns | 0.45 ns | 0.42 ns | 0.0620 | 520 B |
| EngineV9Run | 128.4 ns | 2.31 ns | 2.16 ns | 0.0629 | 528 B |
| EngineV10Run | 102.0 ns | 2.00 ns | 1.96 ns | 0.0545 | 456 B |
Key findings:
- EngineV10 is ~19% faster than EngineV8 and ~21% faster than EngineV9
- EngineV10 allocates 12% less memory than EngineV8
- All engines maintain sub-microsecond per-tick latency
Benchmarks run with BenchmarkDotNet v0.15.8 on macOS Tahoe 26.2, Apple M3 Max, .NET 9.0.8
- .NET 9.0 SDK or later
- Git
git clone https://github.com/islero/High-Performance-Backtest.Net.git
cd High-Performance-Backtest.Net
dotnet builddotnet testcd benchmarks/Backtest.Net.Benchmarks
dotnet run -c Releasedotnet formatThis project follows Semantic Versioning.
| Branch | Version Format | NuGet Feed |
|---|---|---|
master |
X.Y.Z (stable) |
nuget.org |
beta |
X.Y.Z-beta.N (prerelease) |
nuget.org |
- Update version in
src/Backtest.Net/Backtest.Net.csproj - Create GitHub Release with tag
vX.Y.Z - CI automatically publishes to NuGet
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
This project is licensed under the GNU Lesser General Public License v3.0.
- SimdLinq - SIMD-accelerated LINQ operations
- BenchmarkDotNet - Performance benchmarking
Built for the algorithmic trading community