Crypto Backtester
A backtesting framework for cryptocurrency trading strategies on Binance. Supports spot and perpetual futures markets with risk management, position sizing, and performance analytics.
Features
- Historical Data Collection: Automated collection and caching of OHLCV, trades, funding rates, and open interest data
- Strategy Backtesting: Run strategies over historical data with configurable time steps
- Risk Management: User-defined position manager for custom risk screening and position sizing
- OMS Simulation: Order management system that tracks positions, balances, and trade history
- Performance Metrics: Returns, Sharpe ratio, drawdown, and permutation testing
- Multiple Market Types: Support for both spot and perpetual futures markets
Prerequisites
- Python 3.11 or higher
- pip or uv package manager
Installation
From PyPI (recommended)
pip install crypto-backtester-binance
From Source
git clone https://github.com/LevRoz630/crypto-backtester.git
cd crypto-backtester
pip install -e .
With development dependencies:
pip install -e ".[dev,test,docs]"
Data Directory
The framework will automatically download and cache historical data. You can specify a custom path when initializing the Backtester, or it defaults to ./historical_data.
Project Structure
crypto-backtester-binance/
├── src/crypto_backtester_binance/ # Core library
│ ├── backtester.py # Main backtest orchestrator
│ ├── oms_simulation.py # Order management system
│ ├── hist_data.py # Historical data collector
│ └── utils.py # Utility functions
├── examples/ # Example scripts
│ ├── position_manager.py # Reference position manager (user-defined)
│ ├── 01_simple_backtest.py # Buy-and-hold strategy
│ ├── 02_momentum_strategy.py # SMA crossover strategy
│ └── 03_long_short_strategy.py # Long BTC / Short Alts
├── tests/ # Test suite
├── docs/ # Documentation
└── historical_data/ # Cached data (created on first run)
Quick Start
Running Your First Backtest
from datetime import datetime, timedelta, UTC
from typing import Any
from crypto_backtester_binance.backtester import Backtester
from crypto_backtester_binance.hist_data import HistoricalDataCollector
from crypto_backtester_binance.oms_simulation import OMSClient
# Define a simple strategy
class HoldStrategy:
def __init__(self, symbols: list[str], lookback_days: int = 0):
self.symbols = symbols
self.lookback_days = lookback_days
self.has_bought = False
def run_strategy(self, oms_client: OMSClient, data_manager: HistoricalDataCollector):
orders = []
if not self.has_bought:
for symbol in self.symbols:
orders.append({"symbol": symbol, "instrument_type": "future", "side": "LONG"})
self.has_bought = True
return orders
# Define a position manager (user-defined risk management)
class SimplePositionManager:
def filter_orders(
self, orders: list[dict[str, Any]], oms_client: Any, data_manager: HistoricalDataCollector
) -> list[dict[str, Any]] | None:
"""Add position sizing to orders. Must return orders with 'value' field."""
if not orders:
return None
# Simple equal-weight allocation: 10% of balance per order
budget = oms_client.balance["USDT"] * 0.1 / len(orders)
return [{**order, "value": budget} for order in orders]
# Initialize backtester
backtester = Backtester(historical_data_dir="./historical_data")
# Create strategy and position manager
strategy = HoldStrategy(symbols=["BTC-USDT", "ETH-USDT", "SOL-USDT"])
position_manager = SimplePositionManager()
# Set backtest period
start_date = datetime.now(UTC) - timedelta(days=50)
end_date = datetime.now(UTC) - timedelta(days=1)
# Run backtest
results = backtester.run_backtest(
strategy=strategy,
position_manager=position_manager,
start_date=start_date,
end_date=end_date,
time_step=timedelta(days=1),
market_type="futures",
)
# View results
print(f"Total Return: {results['total_return']:.2%}")
print(f"Sharpe Ratio: {results['sharpe_ratio']:.2f}")
print(f"Max Drawdown: {results['max_drawdown']:.2%}")
# Generate plots
backtester.plot_portfolio_value()
backtester.plot_positions(results)
The first run will download historical data automatically. Subsequent runs use cached data.
Running Example Scripts
# Simple buy-and-hold
python examples/01_simple_backtest.py
# Momentum strategy (SMA crossover)
python examples/02_momentum_strategy.py
# Long BTC / Short Alts
python examples/03_long_short_strategy.py
Creating Custom Strategies
A strategy must implement the run_strategy method that returns a list of order dictionaries:
from datetime import timedelta
from crypto_backtester_binance.hist_data import HistoricalDataCollector
from crypto_backtester_binance.oms_simulation import OMSClient
class MyStrategy:
def __init__(self, symbols: list[str], lookback_days: int):
self.symbols = symbols
self.lookback_days = lookback_days
def run_strategy(
self,
oms_client: OMSClient,
data_manager: HistoricalDataCollector,
) -> list[dict]:
"""
Generate trading orders based on strategy logic.
Returns:
List of order dictionaries with keys:
- symbol: str (e.g., "BTC-USDT")
- instrument_type: str ("spot" or "future")
- side: str ("LONG", "SHORT", or "CLOSE")
- value: float (optional, USDT notional)
"""
orders = []
for symbol in self.symbols:
# Load historical data
data = data_manager.load_data_period(
symbol=symbol,
timeframe="1h",
data_type="mark_ohlcv_futures",
start_date=oms_client.current_time - timedelta(days=self.lookback_days),
end_date=oms_client.current_time,
)
# Your strategy logic here...
orders.append({
"symbol": symbol,
"instrument_type": "future",
"side": "LONG", # or "SHORT" or "CLOSE"
})
return orders
Configuration
Market Types
"futures": Uses perpetual futures data with margin-based positions
Time Steps
Supported time deltas map to data timeframes:
timedelta(minutes=1)→"1m"timedelta(minutes=5)→"5m"timedelta(minutes=15)→"15m"(default)timedelta(minutes=30)→"30m"timedelta(hours=1)→"1h"
Position Manager
The position manager is user-defined - you create it to match your risk management needs.
It must implement a filter_orders method with this signature:
def filter_orders(
self,
orders: list[dict],
oms_client: OMSClient,
data_manager: HistoricalDataCollector
) -> list[dict] | None:
"""
Process orders from strategy before execution.
Args:
orders: Raw orders from strategy
oms_client: Access to balance, positions, current time
data_manager: Access to historical data
Returns:
List of orders with 'value' field set, or None to skip
"""
See examples/position_manager.py for a reference implementation with:
- Volatility-based risk screening
- Inverse-volatility position sizing
- Budget enforcement
Documentation
Building Documentation
If you installed with [docs]:
# Build static HTML
mkdocs build
# Serve locally for preview
mkdocs serve
Then open http://127.0.0.1:8000 in your browser.
Documentation Structure
- Overview: Architecture and data flow (
docs/overview.md) - API Reference: Auto-generated from docstrings (
docs/api/) - Examples: Strategy implementations (
examples/)
Permutation Testing
Test strategy significance using randomized returns:
results = backtester.run_permutation_backtest(
strategy=strategy,
position_manager=position_manager,
start_date=start_date,
end_date=end_date,
time_step=timedelta(days=1),
market_type="futures",
permutations=100, # Number of random permutations
)
print(f"P-value: {results['p_value']:.4f}")
print(f"Observed Sharpe: {results['sharpe_ratio']:.2f}")
Troubleshooting
Data Download Issues
- Ensure you have internet connectivity for first-time data collection
- Check that the
historical_datadirectory is writable - Data is cached in Parquet format for fast subsequent loads
Import Errors
If you see import errors, ensure the package is installed:
pip install crypto-backtester-binance
Or for development:
pip install -e .
Memory Issues
For large backtests:
- Reduce
lookback_daysin your strategy - Use longer
time_stepintervals - Process data in chunks
License
See LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Support
For issues and questions, please open an issue on the repository.
Metadata
Release files for crypto-backtester-binance 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| crypto_backtester_binance-1.0.0.tar.gz | 263.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| crypto_backtester_binance-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 290.7 kB
Release files / crypto_backtester_binance-1.0.0.tar.gz
| Download URL | crypto_backtester_binance-1.0.0.tar.gz |
|---|---|
| Size | 263.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
69440f52d5938d359ac6c50ffc2cd27be60f96029c2afcc80035d7f612b4d9ad
|
|
BLAKE2b-256 checksum How to use checksums |
c045e5096c89aceb8f528a4983b55a408940f075dfc1c795357013b2d3201938
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / crypto_backtester_binance-1.0.0-py3-none-any.whl
| Download URL | crypto_backtester_binance-1.0.0-py3-none-any.whl |
|---|---|
| Size | 27.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c39c0f3952f623671ee342c13eeb3d9dd1d76846eed7c42a438dc439b6a04e5d
|
|
BLAKE2b-256 checksum How to use checksums |
0cbe3d7946320600ae626da3b713699968cdb2eb6eacd215c29cb651e4b11984
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|