A backtesting framework for cryptocurrency trading strategies on Binance
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crypto_backtester_binance-1.0.0.tar.gz.
File metadata
- Download URL: crypto_backtester_binance-1.0.0.tar.gz
- Upload date:
- Size: 263.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69440f52d5938d359ac6c50ffc2cd27be60f96029c2afcc80035d7f612b4d9ad
|
|
| MD5 |
6b68dc003debd29eb56fabb4e5039d83
|
|
| BLAKE2b-256 |
c045e5096c89aceb8f528a4983b55a408940f075dfc1c795357013b2d3201938
|
File details
Details for the file crypto_backtester_binance-1.0.0-py3-none-any.whl.
File metadata
- Download URL: crypto_backtester_binance-1.0.0-py3-none-any.whl
- Upload date:
- Size: 27.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c39c0f3952f623671ee342c13eeb3d9dd1d76846eed7c42a438dc439b6a04e5d
|
|
| MD5 |
fa17eaf07b849fe92e288859348843d6
|
|
| BLAKE2b-256 |
0cbe3d7946320600ae626da3b713699968cdb2eb6eacd215c29cb651e4b11984
|