Professional Python Algorithmic Trading Backtesting Framework
English | 中文
- Performance Snapshot
- Introduction
- Key Features
- Quick Installation
- 5-Minute Quickstart
- Core Concepts
- Built-in Components
- Advanced Topics
- Project Architecture
- Testing
- API Documentation
- FAQ
- Contributing
- License
- 中文文档
The active dev branch carries the optimization work originally developed on the
development branch. Running the full 1,271-strategy regression suite
(tests/functional/strategies, -n 8) against the installed engine, dev
completes in about half the time of master.
| Metric | Master Branch | Dev Branch | Improvement |
|---|---|---|---|
| Total Execution Time | 438.96s (7m18s) | 236.36s (3m56s) | -46.2% |
| Speedup | 1.00x | 1.86x | ✓ |
| Strategies Tested | 1,271 | 1,271 | ✓ |
| Test Pass Rate | 100% (1271 passed) | 100% (1271 passed) | ✓ |
Benchmark:
pytest tests/functional/strategies -n 8on identical hardware (macOS, Python 3.11, 8 parallel xdist workers). Master measured via--use-installed-backtraderagainst the master build.
An earlier internal benchmark on a smaller 119-strategy sample showed a comparable ~45% reduction (553.12s → 305.36s).
| Strategy Category | Avg Speedup | Example |
|---|---|---|
| Simple MA Cross | 40-45% | test_03_two_ma: 2.6s → 1.5s |
| Multi-Indicator | 45-50% | test_09_dual_thrust: 59.2s → 26.9s |
| Multi-Data | 42-48% | test_02_multi_extend_data: 23.5s → 12.6s |
| Complex Strategies | 38-42% | test_08_kelter_strategy: 36.9s → 11.3s |
Backtrader is a powerful and flexible Python framework for backtesting trading strategies. This project is based on backtrader with extensive optimizations and feature enhancements, supporting low-frequency, mid-frequency, and high-frequency strategy development, backtesting, and live trading.
| Comparison | Backtrader | Other Frameworks |
|---|---|---|
| Learning Curve | ⭐⭐ Gentle | ⭐⭐⭐⭐ Steep |
| Development Efficiency | ⭐⭐⭐⭐⭐ Very High | ⭐⭐⭐ Average |
| Built-in Indicators | 50+ | 10-30 |
| Data Source Support | 20+ | 5-10 |
| Community Activity | ⭐⭐⭐⭐ Active | ⭐⭐ Average |
| Documentation | ⭐⭐⭐⭐⭐ Complete | ⭐⭐⭐ Average |
master: Stable release branchdev: Active development branch carrying performance optimizations and new features
Three backtesting modes supported:
├── runonce (Vectorized) - Batch computation, optimal performance
├── runnext (Event-driven) - Bar-by-bar, suitable for complex logic
└── Tick-level backtesting - Tick data support with tick+bar mixed mode
Trading frequency spectrum:
├── Low-frequency - Daily/weekly bars, position trading
├── Mid-frequency - Minute/hour bars, intraday trading
└── High-frequency - Tick-level data, market microstructure
- Plotly Interactive Charts: Supports 100k+ data points with zoom, pan, hover
- Bokeh Real-time Charts: Real-time data updates and multi-tab support
- Matplotlib Static Charts: Classic plotting for papers and reports
One-click generation of professional reports including:
- Equity curves and drawdown charts
- Sharpe ratio, Calmar ratio, SQN rating
- Detailed trade statistics and P&L analysis
- Export to HTML, PDF, JSON formats
Covering moving averages, momentum, volatility, trend indicators, and more.
- Tick-level backtesting: Process individual tick data for high-frequency strategy research
- Tick + Bar mixed mode: Combine tick and bar data in the same strategy
- Seamless live trading: Same strategy code works for backtesting and live trading
- Full spectrum coverage: Low-frequency (daily), mid-frequency (minute), and high-frequency (tick) — all unified
Comprehensive observer for real-time logging during backtests:
- Real-time file writing: Logs are appended on every bar (not just at the end)
current_position.json: Updated after each bar with the latest holdings- Strategy indicators: Optionally log strategy-calculated indicators in data files
- Configurable format: Tab-separated
.log(default) or standard.csv - MySQL persistence: Order/trade/position logs saved to MySQL (
bt_order,bt_trade,bt_position)
cerebro.addobserver(
bt.observers.TradeLogger,
log_dir='logs',
log_indicators=True,
file_format='log', # 'log' or 'csv'
# mysql_enabled=True, # optional MySQL persistence
# mysql_database='backtrder_web',
)Strategies, indicators, analyzers, and data sources can be independently extended.
CSV, Pandas, Yahoo Finance, Interactive Brokers, CCXT cryptocurrency, CTP futures, and more.
- Python: 3.8+ (3.11 recommended for ~15% performance boost)
- OS: Windows / macOS / Linux
- RAM: 4GB+ recommended
Note: This project is NOT on PyPI. Install from source only.
git clone https://github.com/cloudQuant/backtrader.git
cd backtrader
pip install -r requirements.txt
pip install -U .git clone https://gitee.com/yunjinqi/backtrader.git
cd backtrader
pip install -r requirements.txt
pip install -U .import backtrader as bt
print(f"Backtrader version: {bt.__version__}")
# Output: Backtrader version: 1.1.0pytest tests -n 4┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Prepare │ -> │ Write │ -> │ Run │
│ Data │ │ Strategy │ │ Backtest │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
v v v
CSV/Pandas/API Extend Strategy cerebro.run()
Implement next()
import backtrader as bt
class SmaCrossStrategy(bt.Strategy):
"""Moving Average Crossover Strategy:
- Buy when fast SMA crosses above slow SMA
- Sell when fast SMA crosses below slow SMA
"""
params = (
('fast_period', 10),
('slow_period', 30),
)
def __init__(self):
self.fast_sma = bt.indicators.SMA(self.data.close, period=self.params.fast_period)
self.slow_sma = bt.indicators.SMA(self.data.close, period=self.params.slow_period)
self.crossover = bt.indicators.CrossOver(self.fast_sma, self.slow_sma)
def next(self):
if not self.position:
if self.crossover > 0:
self.buy()
elif self.crossover < 0:
self.close()# Option 1: Load from CSV file
data = bt.feeds.GenericCSVData(
dataname='your_data.csv',
datetime=0, open=1, high=2, low=3, close=4, volume=5,
openinterest=-1, dtformat='%Y-%m-%d',
)
# Option 2: Load from Pandas DataFrame
import pandas as pd
df = pd.read_csv('your_data.csv', parse_dates=['date'], index_col='date')
data = bt.feeds.PandasData(dataname=df)
# Option 3: Download from Yahoo Finance
from datetime import datetime
data = bt.feeds.YahooFinanceData(
dataname='AAPL',
fromdate=datetime(2020, 1, 1),
todate=datetime(2023, 12, 31),
)cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(SmaCrossStrategy)
cerebro.broker.setcash(100000)
cerebro.broker.setcommission(commission=0.0003)
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
print(f'Starting: {cerebro.broker.getvalue():,.2f}')
results = cerebro.run()
print(f'Final: {cerebro.broker.getvalue():,.2f}')
strat = results[0]
print(f"Sharpe: {strat.analyzers.sharpe.get_analysis().get('sharperatio', 'N/A')}")
print(f"Max DD: {strat.analyzers.drawdown.get_analysis()['max']['drawdown']:.2f}%")# Plotly interactive charts (recommended)
cerebro.plot(backend='plotly', style='candle')
# Save to HTML
from backtrader.plot import PlotlyPlot
plotter = PlotlyPlot(style='candle')
figs = plotter.plot(results[0])
figs[0].write_html('backtest_chart.html')cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(Strategy)
cerebro.addanalyzer(Analyzer)
cerebro.broker.setcash(100000)
results = cerebro.run()
cerebro.plot()class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
self.sma = bt.indicators.SMA(period=self.params.period)
def next(self):
if self.data.close[0] > self.sma[0]:
self.buy()
def notify_order(self, order):
if order.status == order.Completed:
print(f'Order executed at {order.executed.price}')self.data.close[0] # Current bar
self.data.close[-1] # Previous bar
self.data.open[0] # Current open
self.data.high[0] # Current high
self.data.volume[0] # Current volumeself.buy() # Market buy
self.sell(price=100, exectype=bt.Order.Limit) # Limit sell
self.buy_bracket(price=100, stopprice=95, limitprice=110) # Bracket order
self.order_target_percent(target=0.5) # Target 50% position| Category | Indicators |
|---|---|
| Moving Averages | SMA, EMA, WMA, DEMA, TEMA, KAMA, HMA, ZLEMA |
| Momentum | RSI, ROC, Momentum, Williams %R, Ultimate Oscillator |
| Volatility | ATR, Bollinger Bands, Standard Deviation |
| Trend | ADX, Aroon, Parabolic SAR, Ichimoku, DPO |
| Oscillators | MACD, Stochastic, CCI, TSI, TRIX |
| Analyzer | Purpose |
|---|---|
SharpeRatio |
Risk-adjusted returns |
DrawDown |
Maximum drawdown |
TradeAnalyzer |
Trade statistics |
Returns |
Return analysis |
SQN |
System Quality Number |
| Data Source | Description |
|---|---|
GenericCSVData |
Generic CSV files |
PandasData |
Pandas DataFrame |
YahooFinanceData |
Yahoo Finance |
IBData |
Interactive Brokers |
CCXTFeed |
Cryptocurrency |
cerebro.optstrategy(
SmaCrossStrategy,
fast_period=range(5, 20, 5),
slow_period=range(20, 60, 10),
)
results = cerebro.run(maxcpus=4)cerebro.adddata(data1)
cerebro.adddata(data2)
# In strategy
price1 = self.datas[0].close[0]
price2 = self.datas[1].close[0]class MyIndicator(bt.Indicator):
lines = ('myline',)
params = (('period', 20),)
def __init__(self):
self.lines.myline = bt.indicators.SMA(self.data, period=self.params.period)cerebro.add_report_analyzers(riskfree_rate=0.02)
cerebro.run()
cerebro.generate_report('report.html', user='Trader', memo='Strategy Report')Backtrader uses a single logging entry point and is silent by default — it emits nothing until you opt in, and it never touches the root logger or a host application's logging setup.
import backtrader as bt
# Opt in: console + optional rotating file. Idempotent.
bt.configure_logging(level="INFO", log_file="run.log")
logger = bt.get_logger(__name__) # -> "backtrader.<module>"
logger.info("strategy started")
bt.set_level("DEBUG") # raise verbosity at runtime
bt.reset_logging() # back to the silent default (tests)| Level | When |
|---|---|
CRITICAL |
engine cannot continue |
ERROR |
recoverable failure (order rejected, data load failed) |
WARNING |
degraded / auto-corrected behavior |
INFO |
milestones (start/stop, fills) |
DEBUG |
per-bar diagnostics |
Framework code routes through backtrader.utils.log_message.get_logger rather
than the stdlib logging directly. See docs/LOGGING_GUIDELINES.md for the
full conventions (hot-path guard, exception-logging rules, print-vs-logging).
backtrader/
├── backtrader/ # Core codebase
│ ├── cerebro.py # Main engine
│ ├── strategy.py # Strategy base
│ ├── indicator.py # Indicator base
│ ├── analyzer.py # Analyzer base
│ ├── feed.py # Data feed base
│ ├── broker.py # Broker base
│ ├── indicators/ # 52 technical indicators
│ ├── analyzers/ # 17 analyzers
│ ├── feeds/ # 21 data sources
│ ├── plot/ # Visualization
│ └── reports/ # Report generation
├── examples/ # Example code
├── tests/ # Test cases (~2,800 tests)
└── docs/ # Documentation
The repository ships with around 2,800 tests covering unit, functional, integration, and performance suites. The functional strategy directory alone contains 1,271 inlined regression tests spanning 22 strategy categories (trend following, mean reversion, asset allocation, machine learning, options, pairs trading, etc.).
The strategy regression suite is large (~10 min for the full run), so tests are
split into tiers by measured per-file duration. The fastest ~35% of strategy
tests stay in the fast loop; the slowest ~65% are auto-tagged slow (no test
files are edited — the split is applied dynamically from a committed durations
file in conftest.py).
# Fast dev loop (~3.5 min): all non-strategy tests + the fastest ~35% of
# strategy tests. Best for "did my change break anything" iteration.
make test-fast # == pytest tests -m "not slow" -n 8 -q
# Slow tier (~7 min): only the slowest ~65% of strategy tests that test-fast skips
make test-slow # == pytest tests -m slow -n 8 -q
# Strategy regression only (all 1,271 strategy tests, ~4 min on `dev`)
make test-strategies # == pytest tests/functional/strategies -n 8 -q
# Full suite — everything in parallel (~10 min)
make test-all # == pytest tests -n 8 -qTune how many strategy tests stay in the fast loop with BT_SLOW_PERCENTILE
(default 35, i.e. keep the fastest 35%):
# Stricter sub-3-minute loop — keep only the fastest ~25% of strategy tests
BT_SLOW_PERCENTILE=25 make test-fast
# Broader coverage — keep the fastest ~50%
BT_SLOW_PERCENTILE=50 make test-fastRefresh the duration data after adding/removing strategy tests:
python scripts/refresh_strategy_durations.pypytest tests -n 8# Run only the strategies suite (1,271 tests, ~4 minutes on `dev`, ~7 on `master`)
pytest tests/functional/strategies -n 8
# Run a single strategy file
pytest tests/functional/strategies/others/test_0019_pattern_detection.py
# Run only the slow / fast tier explicitly
pytest tests -m slow -n 8
pytest tests -m "not slow" -n 8When you run pytest from the repository root, import backtrader resolves to
the local repo copy by default (the backtrader/ directory next to
conftest.py). This is what you want during development.
If you also have an older or release version installed via
pip install backtrader, you can switch the test suite to that copy on demand:
# Default — uses the local repo copy (development)
pytest tests/functional/strategies -n 8
# Switch to the installed (site-packages) copy via env var
BACKTRADER_USE_INSTALLED=1 pytest tests/functional/strategies -n 8
# Or via CLI flag
pytest tests/functional/strategies -n 8 --use-installed-backtraderThe active backtrader.__file__ is printed in the pytest session header so
you can confirm which copy each run picked up. The switch works under
pytest-xdist parallel mode as well.
Test fixtures live under tests/datas/. The MT5-formatted daily CSVs live in
tests/datas/mt5_1d_data/ and cover the symbols referenced by the inlined
regression suite (XAUUSD, XAGUSD, IVV, IEF, GLD, IWM, etc.).
- ReadTheDocs (EN): https://backtrader.readthedocs.io/en/latest/
- ReadTheDocs (ZH): https://backtrader-zh.readthedocs.io/zh-cn/latest/
- GitHub Pages: https://cloudquant.github.io/backtrader/
cd docs
pip install -r requirements.txt
make html
make serveimport backtrader as bt
# Cerebro
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(Strategy)
cerebro.broker.setcash(100000)
results = cerebro.run()
cerebro.plot()
# Strategy methods
self.buy(size=100)
self.sell(size=100)
self.close()
self.order_target_percent(target=0.5)
# Common indicators
bt.indicators.SMA(data, period=20)
bt.indicators.RSI(data, period=14)
bt.indicators.MACD(data)
bt.indicators.BollingerBands(data)cerebro.broker.set_slippage_fixed(0.01) # Fixed slippage
cerebro.broker.set_slippage_perc(0.001) # Percentage slippageclass FixedSizer(bt.Sizer):
params = (('stake', 100),)
def _getsizing(self, comminfo, cash, data, isbuy):
return self.params.stake
cerebro.addsizer(FixedSizer, stake=100)cerebro.addanalyzer(bt.analyzers.Transactions, _name='txn')
results = cerebro.run()
transactions = results[0].analyzers.txn.get_analysis()cerebro.run(runonce=True) # Use vectorized mode (default)
cerebro.run(maxcpus=4) # Use multiprocessing for optimizationWe welcome contributions to improve code quality, fix bugs, and enhance performance.
If you find that the dev branch produces different results than master
for the same strategy, this likely indicates an indicator calculation bug.
Please help us fix it.
Add a new test case that:
- ✅ Passes on both
masteranddevbranches - ✅ Demonstrates the bug or validates the fix
- ✅ Includes clear assertions and expected values
# Example: tests/functional/strategies/<category>/test_NNNN_your_indicator.py
import backtrader as bt
class TestYourIndicator(bt.Strategy):
def __init__(self):
self.indicator = bt.indicators.YourIndicator(self.data)
def next(self):
# Add assertions to validate correctness
pass
def test_your_indicator():
cerebro = bt.Cerebro()
# ... setup and run
assert result == expected_value# Option 1: Run the full optimization script (recommended)
bash scripts/optimize_code.sh
# Option 2: Run tests manually
pytest tests -n 4Both must pass without errors.
pytest tests -n 4 -vExpected output: all ~2,800 tests pass.
If you want to validate that the installed wheel still works (for example, before publishing a release), see Testing → Choosing Which backtrader to Test Against.
- Fork the repository
- Create a feature branch:
git checkout -b fix/indicator-name - Commit your changes:
git commit -m "fix: correct calculation in YourIndicator" - Push to your fork:
git push origin fix/indicator-name - Open a Pull Request with:
- Clear description of the issue
- Reference to the test case
- Explanation of the fix
We especially welcome contributions in:
- 🐛 Bug Fixes: Indicator calculation errors, edge cases
- ✅ Test Coverage: Additional test cases for existing indicators
- 📊 Performance: Further optimization opportunities
- 📚 Documentation: Improved examples and tutorials
- 🔧 Features: New indicators, analyzers, or data feeds
- Write clear, self-documenting code
- Add docstrings to all public methods
- Follow existing code style (enforced by
ruffandblack) - Keep changes focused and atomic
- Update documentation when adding features
THIS SOFTWARE IS PROVIDED FOR EDUCATIONAL AND RESEARCH PURPOSES ONLY.
⚠️ Trading Risk: Algorithmic trading involves substantial risk of loss. Past performance does not guarantee future results.- 🐛 Software Status: This project is under active development and may contain bugs or calculation errors.
- 💰 Financial Liability: You are solely responsible for any financial losses incurred from using this software.
- 🔍 Verification Required: Always verify backtest results against known benchmarks before live trading.
- 📊 No Warranty: This software is provided "AS IS" without warranty of any kind, express or implied.
By using this software, you acknowledge and accept all risks associated with algorithmic trading.
This project is licensed under GPLv3.
- GitHub: https://github.com/cloudQuant/backtrader
- Gitee: https://gitee.com/yunjinqi/backtrader
- Author Blog: https://yunjinqi.blog.csdn.net/
- ReadTheDocs (EN): https://backtrader.readthedocs.io/en/latest/
- ReadTheDocs (ZH): https://backtrader-zh.readthedocs.io/zh-cn/latest/
- GitHub Pages: https://cloudquant.github.io/backtrader/
If this project helps you, please give us a ⭐ Star!
English | 中文
当前活跃的 dev 分支承接了原 development 分支上的优化工作。在完整的 1,271 个策略
回归套件(tests/functional/strategies,-n 8)上,dev 分支的总执行时间相比
master 分支几乎缩短一半。
| 指标 | Master 分支 | Dev 分支 | 提升幅度 |
|---|---|---|---|
| 总执行时间 | 438.96 秒(7分18秒) | 236.36 秒(3分56秒) | -46.2% |
| 加速比 | 1.00x | 1.86x | ✓ |
| 测试策略数 | 1,271 | 1,271 | ✓ |
| 测试通过率 | 100%(1271 passed) | 100%(1271 passed) | ✓ |
基准测试:在相同硬件上运行
pytest tests/functional/strategies -n 8(macOS, Python 3.11,8 个并行 xdist 进程)。Master 通过--use-installed-backtrader指向 master 构建版本测得。
更早期在 119 个策略小样本上的内部基准也得到了相近的约 45% 降幅(553.12 秒 → 305.36 秒)。
- 移除元编程开销
- 消除动态元类属性拦截机制
- 采用显式描述符参数系统
- 结果:属性访问开销降低约 40%
- 经纪商性能增强
- 移除
BackBroker和CommInfoBase的全局__getattribute__重载 - 在热路径(
BackBroker.next()、_get_value())实现本地参数缓存 - 缓存高频访问参数(
mult、cash、stocklike) - 结果:经纪商操作速度提升 42.5%
- 移除
- 指标计算优化
- 优化布林带
once()方法,使用更快的 NaN 检查 - 减少冗余数组边界检查
- 缓存数学函数和常量
- 结果:指标计算速度提升 15-20%
- 优化布林带
- 减少内置函数调用
- 最小化热路径中的
isinstance()、hasattr()、len()调用 - 在适当场景使用类型恒等检查
- 结果:Python 层面开销降低约 10%
- 最小化热路径中的
| 策略类别 | 平均加速 | 示例 |
|---|---|---|
| 简单均线交叉 | 40-45% | test_03_two_ma: 2.6 秒 → 1.5 秒 |
| 多指标策略 | 45-50% | test_09_dual_thrust: 59.2 秒 → 26.9 秒 |
| 多数据源 | 42-48% | test_02_multi_extend_data: 23.5 秒 → 12.6 秒 |
| 复杂策略 | 38-42% | test_08_kelter_strategy: 36.9 秒 → 11.3 秒 |
Backtrader 是一个功能强大、灵活易用的 Python 量化交易回测框架。本项目基于 backtrader 进行了大量优化和功能扩展,支持 低频、中频、高频 全频段交易策略的研发、回测与实盘交易。
| 对比项 | Backtrader | 其他框架 |
|---|---|---|
| 学习曲线 | ⭐⭐ 平缓 | ⭐⭐⭐⭐ 陡峭 |
| 策略开发效率 | ⭐⭐⭐⭐⭐ 极高 | ⭐⭐⭐ 一般 |
| 内置指标数量 | 50+ | 10-30 |
| 数据源支持 | 20+ | 5-10 |
master:稳定发布分支dev:活跃开发分支,承载性能优化与新特性
- 🚀 高性能多频段回测引擎:支持向量化、事件驱动和 Tick 级别三种模式
- 🔄 Tick 级别回测与混合交易:支持 Tick 数据回测、Tick + Bar 混合模式,打通低频、中频、高频全频段交易
- 📊 丰富的可视化:Plotly 交互图表、Bokeh 实时图表
- 📈 专业回测报告:一键生成 HTML/PDF/JSON 格式报告
- 🔧 50+ 内置技术指标:均线、动量、波动率、趋势等
- 📝 TradeLogger 实时日志:回测过程中实时记录订单、交易、持仓、行情数据,支持 MySQL 持久化
- 📦 模块化架构:策略、指标、分析器可独立扩展
- 🌍 20+ 数据源支持:CSV、Pandas、Yahoo、IB、CCXT、CTP 期货等
- 🔗 回测与实盘无缝衔接:同一套策略代码可直接用于回测和实盘交易
注意:本项目未发布到 PyPI,请从源码安装。
# 从 GitHub 克隆
git clone https://github.com/cloudQuant/backtrader.git
cd backtrader
pip install -r requirements.txt
pip install -U .
# 或从 Gitee 镜像克隆
git clone https://gitee.com/yunjinqi/backtrader.git
cd backtrader
pip install -r requirements.txt
pip install -U .
# 验证安装
python -c "import backtrader as bt; print(bt.__version__)"import backtrader as bt
# 定义策略
class SmaCrossStrategy(bt.Strategy):
params = (('fast', 10), ('slow', 30))
def __init__(self):
fast_sma = bt.indicators.SMA(period=self.params.fast)
slow_sma = bt.indicators.SMA(period=self.params.slow)
self.crossover = bt.indicators.CrossOver(fast_sma, slow_sma)
def next(self):
if not self.position and self.crossover > 0:
self.buy()
elif self.position and self.crossover < 0:
self.close()
# 创建引擎
cerebro = bt.Cerebro()
cerebro.adddata(data)
cerebro.addstrategy(SmaCrossStrategy)
cerebro.broker.setcash(100000)
# 运行回测
results = cerebro.run()
cerebro.plot(backend='plotly')Backtrader 提供统一的日志入口,且默认完全静默——不主动调用就没有任何 输出,也不会修改 root logger 或干扰宿主程序的日志配置。
import backtrader as bt
# 开启日志:控制台 + 可选滚动文件,幂等
bt.configure_logging(level="INFO", log_file="run.log")
logger = bt.get_logger(__name__) # -> "backtrader.<模块名>"
logger.info("strategy started")
bt.set_level("DEBUG") # 运行时调高日志级别
bt.reset_logging() # 还原到默认静默状态(测试用)| 级别 | 使用场景 |
|---|---|
CRITICAL |
引擎无法继续 |
ERROR |
可恢复的失败(订单被拒、数据加载失败) |
WARNING |
降级 / 自动修正行为 |
INFO |
里程碑事件(启动/结束、成交) |
DEBUG |
每根 bar 的诊断信息 |
框架内部统一通过 backtrader.utils.log_message.get_logger 获取 logger,而非
直接 import logging。完整规范(热路径守护、异常日志写法、print 取舍)见
docs/LOGGING_GUIDELINES.md。
仓库自带约 2,800 个测试,覆盖单元、功能、集成和性能四个层级。仅
tests/functional/strategies/ 这一目录就有 1,271 个内联回归测试,分布在
22 个策略类别下(趋势跟踪、均值回归、资产配置、机器学习、期权、配对交易等)。
策略回归套件很大(全量约 10 分钟),因此按单测文件的实测耗时做了分级:最快的
~35% 策略测试留在快速档,其余最慢的 ~65% 自动标记为 slow(不改任何测试文件
——拆分由 conftest.py 读取已提交的耗时数据动态完成)。
# 快速开发回路(约 3.5 分钟):全部非策略测试 + 最快 ~35% 的策略测试。
# 最适合「改完代码看有没有引入 bug」的日常迭代。
make test-fast # 等价于 pytest tests -m "not slow" -n 8 -q
# 慢速档(约 7 分钟):test-fast 跳过的那最慢 ~65% 策略测试
make test-slow # 等价于 pytest tests -m slow -n 8 -q
# 只跑策略回归(全部 1,271 个策略测试,`dev` 约 4 分钟)
make test-strategies # 等价于 pytest tests/functional/strategies -n 8 -q
# 全量 —— 所有测试并行(约 10 分钟)
make test-all # 等价于 pytest tests -n 8 -q用环境变量 BT_SLOW_PERCENTILE 调节快速档里保留多少策略测试(默认 35,即保留
最快 35%):
# 更严格、压进 3 分钟内 —— 只保留最快 ~25% 的策略测试
BT_SLOW_PERCENTILE=25 make test-fast
# 覆盖更全 —— 保留最快 ~50%
BT_SLOW_PERCENTILE=50 make test-fast增删策略测试后刷新耗时数据:
python scripts/refresh_strategy_durations.pypytest tests -n 8# 只跑策略套件(1,271 个测试,`dev` 约 4 分钟,`master` 约 7 分钟)
pytest tests/functional/strategies -n 8
# 跑单个策略文件
pytest tests/functional/strategies/others/test_0019_pattern_detection.py
# 显式只跑慢速 / 快速档
pytest tests -m slow -n 8
pytest tests -m "not slow" -n 8从仓库根目录运行 pytest 时,import backtrader 默认解析到本地仓库副本(与
conftest.py 同级的 backtrader/ 目录)。开发期间这是你想要的行为。
如果你额外用 pip install backtrader 装过其他版本(比如稳定版或旧版本),可以
临时把测试切到已安装的那一份:
# 默认 —— 使用本地仓库代码(开发常用)
pytest tests/functional/strategies -n 8
# 通过环境变量切到 site-packages 安装的副本
BACKTRADER_USE_INSTALLED=1 pytest tests/functional/strategies -n 8
# 或通过命令行参数
pytest tests/functional/strategies -n 8 --use-installed-backtrader每次启动 pytest 都会在 session header 中打印当前生效的 backtrader.__file__,
方便确认本次跑的到底是哪一份。该开关在 pytest-xdist 并行模式下同样生效。
测试夹具放在 tests/datas/ 下。MT5 格式的日线 CSV 在
tests/datas/mt5_1d_data/,覆盖了内联回归套件引用的所有标的(XAUUSD、
XAGUSD、IVV、IEF、GLD、IWM 等)。
我们欢迎所有有助于提升代码质量、修复 bug 和增强性能的贡献。
如果您发现 dev 分支与 master 分支在相同策略下产生不同结果,这很可能表明
存在指标计算 bug。请帮助我们修复。
添加一个新的测试用例,要求:
- ✅ 在 master 和 dev 分支上都能通过
- ✅ 能够演示 bug 或验证修复
- ✅ 包含清晰的断言和预期值
# 方式 1:运行完整优化脚本(推荐)
bash scripts/optimize_code.sh
# 方式 2:手动运行测试
pytest tests -n 4两个命令都必须无错误通过。
pytest tests -n 4 -v预期输出:约 2,800 个测试全部通过。
- Fork 本仓库
- 创建功能分支:
git checkout -b fix/indicator-name - 提交更改:
git commit -m "fix: 修正 YourIndicator 的计算" - 推送到您的 fork:
git push origin fix/indicator-name - 创建 Pull Request,包含:
- 问题的清晰描述
- 测试用例的引用
- 修复方案的说明
我们特别欢迎以下方面的贡献:
- 🐛 Bug 修复:指标计算错误、边界情况处理
- ✅ 测试覆盖:为现有指标添加更多测试用例
- 📊 性能优化:进一步的优化机会
- 📚 文档完善:改进示例和教程
- 🔧 功能扩展:新指标、分析器或数据源
- 编写清晰、自文档化的代码
- 为所有公共方法添加文档字符串
- 遵循现有代码风格(由
ruff和black强制执行) - 保持更改集中和原子化
- 添加功能时更新文档
cerebro.broker.set_slippage_fixed(0.01) # 固定滑点
cerebro.broker.set_slippage_perc(0.001) # 百分比滑点class FixedSizer(bt.Sizer):
params = (('stake', 100),)
def _getsizing(self, comminfo, cash, data, isbuy):
return self.params.stake
cerebro.addsizer(FixedSizer, stake=100)cerebro.addanalyzer(bt.analyzers.Transactions, _name='txn')
results = cerebro.run()
transactions = results[0].analyzers.txn.get_analysis()cerebro.run(runonce=True) # 使用向量化模式(默认)
cerebro.run(maxcpus=4) # 参数优化时使用多进程本软件仅供教育和研究目的使用。
⚠️ 交易风险:算法交易存在重大亏损风险。历史业绩不代表未来表现。- 🐛 软件状态:本项目正在积极开发中,可能包含 bug 或计算错误。
- 💰 财务责任:使用本软件产生的任何财务损失由您自行承担。
- 🔍 验证要求:实盘交易前,务必对照已知基准验证回测结果。
- 📊 无担保:本软件按"原样"提供,不提供任何明示或暗示的担保。
使用本软件即表示您承认并接受算法交易相关的所有风险。
- GitHub: https://github.com/cloudQuant/backtrader
- Gitee: https://gitee.com/yunjinqi/backtrader
- 作者博客: https://yunjinqi.blog.csdn.net/
- 在线文档 (EN): https://backtrader.readthedocs.io/en/latest/
- 在线文档 (ZH): https://backtrader-zh.readthedocs.io/zh-cn/latest/
- GitHub Pages: https://cloudquant.github.io/backtrader/
如果本项目对您有帮助,请点个 ⭐ Star 支持我们!
Made with ❤️ by CloudQuant