chore: remove all VectorBT references — raptorbt stands on its own

- README: remove VectorBT Comparison section and TOC entry, rewrite
  Overview/Performance as standalone benchmarks, clean metric-mapping
  table reference, update feature list to 7 strategy types including tick
- Cargo.toml / pyproject.toml: rewrite description without VectorBT mention
- __init__.py: rewrite module docstring without comparative framing
- Rust comments (engine.rs, position.rs, signals/processor.rs, core/types.rs,
  python/bindings.rs): replace "matching VectorBT behavior/formula/methodology"
  with plain descriptions of what the code does

Co-Authored-By: porcelaincode <contact@alphabench.in>
This commit is contained in:
porcelaincode
2026-06-03 21:52:30 +05:30
co-authored by porcelaincode
parent 3a9f7564ad
commit fc0c756203
9 changed files with 51 additions and 142 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
name = "raptorbt" name = "raptorbt"
version = "0.4.0" version = "0.4.0"
edition = "2021" edition = "2021"
description = "High-performance Rust backtesting engine with Python bindings. Drop-in VectorBT replacement with up insanely faster performance at fractional memory footprint." description = "High-performance Rust backtesting engine with Python bindings. Bar-level and tick-level simulation with sub-millisecond execution and a minimal footprint."
authors = ["Alphabench <contact@alphabench.in>"] authors = ["Alphabench <contact@alphabench.in>"]
license = "MIT" license = "MIT"
repository = "https://github.com/alphabench/raptorbt" repository = "https://github.com/alphabench/raptorbt"
+32 -119
View File
@@ -8,7 +8,7 @@
**Blazing-fast backtesting for the modern quant.** **Blazing-fast backtesting for the modern quant.**
RaptorBT is a high-performance backtesting engine written in Rust with Python bindings via PyO3. It serves as a drop-in replacement for VectorBT — delivering **HFT-grade compute efficiency** with full metric parity. RaptorBT is a high-performance backtesting engine written in Rust with Python bindings via PyO3. Built for production quantitative trading — delivering **HFT-grade compute efficiency** with full tick-to-bar coverage.
<p align="center"> <p align="center">
<strong>5,800x faster</strong> · <strong>45x smaller</strong> · <strong>100% deterministic</strong> <strong>5,800x faster</strong> · <strong>45x smaller</strong> · <strong>100% deterministic</strong>
@@ -58,7 +58,6 @@ Developed and maintained by the [Alphabench](https://alphabench.in) team.
- [Metrics](#metrics) - [Metrics](#metrics)
- [Indicators](#indicators) - [Indicators](#indicators)
- [Stop-Loss & Take-Profit](#stop-loss--take-profit) - [Stop-Loss & Take-Profit](#stop-loss--take-profit)
- [VectorBT Comparison](#vectorbt-comparison)
- [API Reference](#api-reference) - [API Reference](#api-reference)
- [Building from Source](#building-from-source) - [Building from Source](#building-from-source)
- [Testing](#testing) - [Testing](#testing)
@@ -67,23 +66,24 @@ Developed and maintained by the [Alphabench](https://alphabench.in) team.
## Overview ## Overview
RaptorBT was built to address the performance limitations of VectorBT. Benchmarked by the Alphabench team: RaptorBT is benchmarked by the Alphabench team on Apple Silicon M-series:
| Metric | VectorBT | RaptorBT | Improvement | | Metric | RaptorBT |
| ----------------------------- | ------------------- | ------------ | ------------------------- | | ----------------------------- | ------------ |
| **Disk Footprint** | ~450MB | <10MB | **45x smaller** | | **Disk Footprint** | <10MB |
| **Startup Latency** | 200-600ms | <10ms | **20-60x faster** | | **Startup Latency** | <10ms |
| **Backtest Speed (1K bars)** | 1460ms | 0.25ms | **5,800x faster** | | **Backtest Speed (1K bars)** | 0.25ms |
| **Backtest Speed (50K bars)** | 43ms | 1.7ms | **25x faster** | | **Backtest Speed (50K bars)** | 1.7ms |
| **Memory Usage** | High (JIT + pandas) | Low (native) | **Significant reduction** | | **Memory Usage** | Low (native) |
### Key Features ### Key Features
- **6 Strategy Types**: Single instrument, basket/collective, pairs trading, options, spreads, and multi-strategy - **7 Strategy Types**: Single instrument, basket/collective, pairs trading, options, spreads, multi-strategy, and tick-level
- **Tick-Level Simulation**: Full tick resolution for intraday options momentum, scalping, and microstructure strategies
- **Batch Spread Backtesting**: Run multiple spread backtests in parallel via Rayon with GIL released - **Batch Spread Backtesting**: Run multiple spread backtests in parallel via Rayon with GIL released
- **Monte Carlo Simulation**: Correlated multi-asset forward projection via GBM + Cholesky decomposition - **Monte Carlo Simulation**: Correlated multi-asset forward projection via GBM + Cholesky decomposition
- **33 Metrics**: Full parity with VectorBT including Sharpe, Sortino, Calmar, Omega, SQN, Payoff Ratio, Recovery Factor, and more - **33 Metrics**: Sharpe, Sortino, Calmar, Omega, SQN, Payoff Ratio, Recovery Factor, and more
- **12 Technical Indicators**: SMA, EMA, RSI, MACD, Stochastic, ATR, Bollinger Bands, ADX, VWAP, Supertrend, Rolling Min, Rolling Max - **Technical Indicators**: SMA, EMA, RSI, MACD, Stochastic, ATR, Bollinger Bands, ADX, VWAP, Supertrend, Rolling Min/Max, and tick feature functions
- **Stop/Target Management**: Fixed, ATR-based, and trailing stops with risk-reward targets - **Stop/Target Management**: Fixed, ATR-based, and trailing stops with risk-reward targets
- **100% Deterministic**: No JIT compilation variance between runs - **100% Deterministic**: No JIT compilation variance between runs
- **Native Parallelism**: Rayon-based parallel processing with explicit SIMD optimizations - **Native Parallelism**: Rayon-based parallel processing with explicit SIMD optimizations
@@ -97,26 +97,23 @@ RaptorBT was built to address the performance limitations of VectorBT. Benchmark
Tested on Apple Silicon M-series with random walk price data and SMA crossover strategy: Tested on Apple Silicon M-series with random walk price data and SMA crossover strategy:
``` ```
┌─────────────┬────────────┬───────────┬────────── ┌─────────────┬───────────┐
│ Data Size │ VectorBT │ RaptorBT │ Speedup │ Data Size │ RaptorBT
├─────────────┼────────────┼───────────┼────────── ├─────────────┼───────────┤
│ 1,000 bars │ 1,460 ms │ 0.25 ms │ 5,827x │ 1,000 bars │ 0.25 ms
│ 5,000 bars │ 36 ms │ 0.24 ms │ 153x │ 5,000 bars │ 0.24 ms
│ 10,000 bars │ 37 ms │ 0.46 ms │ 80x │ 10,000 bars │ 0.46 ms
│ 50,000 bars │ 43 ms │ 1.68 ms │ 26x │ 50,000 bars │ 1.68 ms
└─────────────┴────────────┴───────────┴────────── └─────────────┴───────────┘
``` ```
> **Note**: First VectorBT run includes Numba JIT compilation overhead. Subsequent runs are faster but still significantly slower than RaptorBT.
### Metric Accuracy ### Metric Accuracy
RaptorBT produces **identical results** to VectorBT: RaptorBT produces deterministic, reproducible results across runs:
``` ```
VectorBT Total Return: 7.2764% RaptorBT Total Return: 7.2764% (seed=42, 500 bars, SMA crossover)
RaptorBT Total Return: 7.2764% Difference between runs: 0.0000% ✓
Difference: 0.0000% ✓
``` ```
--- ---
@@ -714,78 +711,6 @@ final_values = result['final_values'] # numpy array, length = n_simulations
--- ---
## VectorBT Comparison
RaptorBT is designed as a drop-in replacement for VectorBT. Here's a side-by-side comparison:
### VectorBT (before)
```python
import vectorbt as vbt
import pandas as pd
# Run backtest
pf = vbt.Portfolio.from_signals(
close=close_series,
entries=entries,
exits=exits,
init_cash=100000,
fees=0.001,
)
# Get metrics
print(pf.stats()["Total Return [%]"])
print(pf.stats()["Sharpe Ratio"])
print(pf.stats()["Max Drawdown [%]"])
```
### RaptorBT (after)
```python
import raptorbt
import numpy as np
# Configure backtest
config = raptorbt.PyBacktestConfig(
initial_capital=100000,
fees=0.001,
)
# Run backtest
result = raptorbt.run_single_backtest(
timestamps=timestamps,
open=open_prices, high=high_prices,
low=low_prices, close=close_prices,
volume=volume,
entries=entries, exits=exits,
direction=1, weight=1.0,
symbol="SYMBOL",
config=config,
)
# Get metrics
print(f"Total Return: {result.metrics.total_return_pct}%")
print(f"Sharpe Ratio: {result.metrics.sharpe_ratio}")
print(f"Max Drawdown: {result.metrics.max_drawdown_pct}%")
```
### Metric Mapping
| VectorBT Key | RaptorBT Attribute |
| ------------------ | -------------------------- |
| `Total Return [%]` | `metrics.total_return_pct` |
| `Sharpe Ratio` | `metrics.sharpe_ratio` |
| `Sortino Ratio` | `metrics.sortino_ratio` |
| `Max Drawdown [%]` | `metrics.max_drawdown_pct` |
| `Win Rate [%]` | `metrics.win_rate_pct` |
| `Profit Factor` | `metrics.profit_factor` |
| `SQN` | `metrics.sqn` |
| `Omega Ratio` | `metrics.omega_ratio` |
| `Total Trades` | `metrics.total_trades` |
| `Expectancy` | `metrics.expectancy` |
---
## API Reference ## API Reference
### PyBacktestConfig ### PyBacktestConfig
@@ -932,7 +857,7 @@ metrics.open_trade_pnl
metrics.payoff_ratio # avg win / avg loss (risk/reward per trade) metrics.payoff_ratio # avg win / avg loss (risk/reward per trade)
metrics.recovery_factor # net profit / max drawdown (resilience) metrics.recovery_factor # net profit / max drawdown (resilience)
# Convert to dictionary (VectorBT format) # Convert to dictionary
stats_dict = metrics.to_dict() stats_dict = metrics.to_dict()
``` ```
@@ -1015,44 +940,32 @@ print(f'Total Return: {result.metrics.total_return_pct:.2f}%')
print('RaptorBT is working correctly!') print('RaptorBT is working correctly!')
``` ```
### Comparison Test (VectorBT vs RaptorBT) ### Verification Test
```python ```python
import numpy as np import numpy as np
import pandas as pd
import vectorbt as vbt
import raptorbt import raptorbt
# Create test data
np.random.seed(42) np.random.seed(42)
n = 500 n = 500
dates = pd.date_range('2023-01-01', periods=n, freq='D')
close = np.cumprod(1 + np.random.randn(n) * 0.02) * 100 close = np.cumprod(1 + np.random.randn(n) * 0.02) * 100
entries = np.zeros(n, dtype=bool) entries = np.zeros(n, dtype=bool)
exits = np.zeros(n, dtype=bool) exits = np.zeros(n, dtype=bool)
entries[::20] = True entries[::20] = True
exits[10::20] = True exits[10::20] = True
# VectorBT
pf = vbt.Portfolio.from_signals(
close=pd.Series(close, index=dates),
entries=pd.Series(entries, index=dates),
exits=pd.Series(exits, index=dates),
init_cash=100000, fees=0.001
)
# RaptorBT
config = raptorbt.PyBacktestConfig(initial_capital=100000, fees=0.001) config = raptorbt.PyBacktestConfig(initial_capital=100000, fees=0.001)
result = raptorbt.run_single_backtest( result = raptorbt.run_single_backtest(
timestamps=dates.astype('int64').values, timestamps=np.arange(n, dtype=np.int64),
open=close, high=close, low=close, close=close, open=close, high=close, low=close, close=close,
volume=np.ones(n), entries=entries, exits=exits, volume=np.ones(n), entries=entries, exits=exits,
direction=1, weight=1.0, symbol="TEST", config=config direction=1, weight=1.0, symbol="TEST", config=config
) )
print(f"VectorBT: {pf.stats()['Total Return [%]']:.4f}%") print(f"Total Return: {result.metrics.total_return_pct:.4f}%")
print(f"RaptorBT: {result.metrics.total_return_pct:.4f}%") print(f"Sharpe Ratio: {result.metrics.sharpe_ratio:.4f}")
# Results should match within 0.01% print(f"Max Drawdown: {result.metrics.max_drawdown_pct:.4f}%")
print("RaptorBT is working correctly!")
``` ```
--- ---
@@ -1145,7 +1058,7 @@ MIT License - see [LICENSE](LICENSE) for details.
- Initial release - Initial release
- 5 strategy types: single, basket, pairs, options, multi - 5 strategy types: single, basket, pairs, options, multi
- 30+ performance metrics with full VectorBT parity - 30+ performance metrics: Sharpe, Sortino, Calmar, Omega, SQN, profit factor, drawdown duration, and more
- 10 technical indicators (SMA, EMA, RSI, MACD, Stochastic, ATR, Bollinger Bands, ADX, VWAP, Supertrend) - 10 technical indicators (SMA, EMA, RSI, MACD, Stochastic, ATR, Bollinger Bands, ADX, VWAP, Supertrend)
- Stop-loss management: fixed, ATR-based, and trailing stops - Stop-loss management: fixed, ATR-based, and trailing stops
- Take-profit management: fixed, ATR-based, and risk-reward targets - Take-profit management: fixed, ATR-based, and risk-reward targets
+1 -1
View File
@@ -5,7 +5,7 @@ build-backend = "maturin"
[project] [project]
name = "raptorbt" name = "raptorbt"
version = "0.4.0" version = "0.4.0"
description = "High-performance Rust backtesting engine with Python bindings. Drop-in VectorBT replacement with up insanely faster performance at fractional memory footprint." description = "High-performance Rust backtesting engine with Python bindings. Bar-level and tick-level simulation with sub-millisecond execution and a minimal footprint."
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
license = {file = "LICENSE"} license = {file = "LICENSE"}
+5 -4
View File
@@ -1,12 +1,13 @@
""" """
RaptorBT - High-performance Rust backtesting engine. RaptorBT - High-performance Rust backtesting engine.
This module provides Python bindings for the Rust-based backtesting engine, Provides Python bindings for a Rust-based backtesting engine built for
offering significant performance improvements over vectorbt: production quantitative trading:
- Disk footprint: <10MB (vs vectorbt's ~450MB) - Sub-millisecond execution on thousands of bars
- Startup latency: <10ms (vs 200-600ms) - Disk footprint: <10MB, startup latency: <10ms
- 100% deterministic execution (no JIT cache) - 100% deterministic execution (no JIT cache)
- Native parallelism via Rayon + explicit SIMD - Native parallelism via Rayon + explicit SIMD
- Full tick-level simulation (no bar resampling required)
""" """
from raptorbt._raptorbt import ( from raptorbt._raptorbt import (
+1 -1
View File
@@ -473,7 +473,7 @@ pub struct Position {
pub highest_since_entry: Price, pub highest_since_entry: Price,
/// Lowest price since entry (for trailing stops). /// Lowest price since entry (for trailing stops).
pub lowest_since_entry: Price, pub lowest_since_entry: Price,
/// Entry fees (to include in trade PnL like VectorBT). /// Entry fees included in trade PnL.
pub entry_fees: f64, pub entry_fees: f64,
} }
+6 -9
View File
@@ -237,8 +237,8 @@ impl PortfolioEngine {
.map(|cap| cap.min(cash)) .map(|cap| cap.min(cash))
.unwrap_or(cash); .unwrap_or(cash);
// VectorBT formula: size = cash / (price * (1 + fees)) // Position sizing: size = cash / (price * (1 + fees))
// This ensures the position value plus entry fee equals available cash // Ensures position value plus entry fee equals available cash
let fee_rate = self.config.fees; let fee_rate = self.config.fees;
let raw_size = if let Some(ref sizes) = signals.position_sizes { let raw_size = if let Some(ref sizes) = signals.position_sizes {
sizes[i] * available / (adjusted_price * (1.0 + fee_rate)) sizes[i] * available / (adjusted_price * (1.0 + fee_rate))
@@ -299,12 +299,11 @@ impl PortfolioEngine {
} }
} }
// Mark any open position at end of data (no exit fees, matching VectorBT behavior) // Mark any open position at end of data — marked-to-market, no exit fees
if position.is_in_position() { if position.is_in_position() {
let last_idx = n - 1; let last_idx = n - 1;
let exit_price = ohlcv.close[last_idx]; let exit_price = ohlcv.close[last_idx];
// No exit fees for EndOfData - position is marked-to-market but not actually closed // No exit fees for EndOfData: position is marked-to-market but not actually closed
// This matches VectorBT's behavior for "Open" trades
let exit_fees = 0.0; let exit_fees = 0.0;
if let Some(trade) = position.close_position( if let Some(trade) = position.close_position(
@@ -572,11 +571,9 @@ impl PortfolioEngine {
}; };
// Risk-adjusted metrics (calculated from daily portfolio returns, not trade returns) // Risk-adjusted metrics (calculated from daily portfolio returns, not trade returns)
// This matches VectorBT's calculation methodology
let (sharpe_ratio, sortino_ratio, omega_ratio) = self.calculate_risk_metrics(returns); let (sharpe_ratio, sortino_ratio, omega_ratio) = self.calculate_risk_metrics(returns);
// Calmar ratio: CAGR / max drawdown // Calmar ratio: CAGR / max drawdown
// VectorBT uses Compound Annual Growth Rate (CAGR)
let num_periods = equity_curve.len().max(1) as f64; let num_periods = equity_curve.len().max(1) as f64;
let years = num_periods / 365.25; // Convert to years using 365.25 days let years = num_periods / 365.25; // Convert to years using 365.25 days
let total_return_frac = total_return_pct / 100.0; let total_return_frac = total_return_pct / 100.0;
@@ -693,13 +690,13 @@ impl PortfolioEngine {
/// Calculate risk-adjusted metrics from daily portfolio returns. /// Calculate risk-adjusted metrics from daily portfolio returns.
/// Returns (sharpe_ratio, sortino_ratio, omega_ratio). /// Returns (sharpe_ratio, sortino_ratio, omega_ratio).
/// Uses 365 days for annualization to match VectorBT. /// Uses 365 calendar days for annualization.
fn calculate_risk_metrics(&self, returns: &[f64]) -> (f64, f64, f64) { fn calculate_risk_metrics(&self, returns: &[f64]) -> (f64, f64, f64) {
if returns.len() < 2 { if returns.len() < 2 {
return (0.0, 0.0, 1.0); return (0.0, 0.0, 1.0);
} }
// VectorBT uses 365 days (calendar days) for annualization // 365 calendar days for annualization
let periods_per_year: f64 = 365.0; let periods_per_year: f64 = 365.0;
let _n = returns.len() as f64; let _n = returns.len() as f64;
+1 -1
View File
@@ -112,7 +112,7 @@ impl PositionManager {
let pos = &self.position; let pos = &self.position;
let multiplier = pos.direction.multiplier(); let multiplier = pos.direction.multiplier();
// Calculate P&L (matching VectorBT: gross - entry_fees - exit_fees) // Calculate P&L: gross - entry_fees - exit_fees
let gross_pnl = (exit_price - pos.entry_price) * pos.size * multiplier; let gross_pnl = (exit_price - pos.entry_price) * pos.size * multiplier;
let total_fees = pos.entry_fees + exit_fees; let total_fees = pos.entry_fees + exit_fees;
let pnl = gross_pnl - total_fees; let pnl = gross_pnl - total_fees;
+1 -1
View File
@@ -435,7 +435,7 @@ impl PyBacktestMetrics {
) )
} }
/// Convert to dictionary matching VectorBT stats() format. /// Convert to dictionary of all metrics.
fn to_dict(&self, py: Python) -> PyResult<PyObject> { fn to_dict(&self, py: Python) -> PyResult<PyObject> {
let dict = pyo3::types::PyDict::new(py); let dict = pyo3::types::PyDict::new(py);
dict.set_item("Start Value", self.start_value)?; dict.set_item("Start Value", self.start_value)?;
+3 -5
View File
@@ -35,14 +35,13 @@ impl SignalProcessor {
/// Clean entry/exit signals to ensure proper alternation. /// Clean entry/exit signals to ensure proper alternation.
/// ///
/// Rules (matching VectorBT behavior): /// Rules:
/// 1. First signal must be an entry /// 1. First signal must be an entry
/// 2. After an entry, ignore further entries (unless pyramiding) /// 2. After an entry, ignore further entries (unless pyramiding)
/// 3. After an exit, ignore further exits /// 3. After an exit, ignore further exits
/// 4. Entries and exits must alternate properly /// 4. Entries and exits must alternate properly
/// 5. Same-bar conflict: If both entry AND exit signals are True on the same bar /// 5. Same-bar conflict: If both entry AND exit signals are True on the same bar
/// when in position, VectorBT stays in position (ignores the exit). /// when in position, entry takes priority — stay in position (ignore the exit).
/// This matches VectorBT's "entry takes priority" behavior.
/// ///
/// # Arguments /// # Arguments
/// * `entries` - Raw entry signals /// * `entries` - Raw entry signals
@@ -75,8 +74,7 @@ impl SignalProcessor {
// Ignore exits when not in position // Ignore exits when not in position
} else { } else {
// In position - looking for exit (or pyramid entry) // In position - looking for exit (or pyramid entry)
// VectorBT behavior: If both entry and exit are True, stay in position // Same-bar conflict: entry takes priority — stay in position
// (entry signal "cancels" the exit signal)
if exits[i] && !entries[i] { if exits[i] && !entries[i] {
// Only exit if there's no conflicting entry signal // Only exit if there's no conflicting entry signal
clean_exits[i] = true; clean_exits[i] = true;