ml4t-backtest 0.1.0a2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ml4t_backtest-0.1.0a2/.gitignore +36 -0
- ml4t_backtest-0.1.0a2/PKG-INFO +163 -0
- ml4t_backtest-0.1.0a2/README.md +68 -0
- ml4t_backtest-0.1.0a2/pyproject.toml +244 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/__init__.py +67 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/_version.py +34 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/accounting/__init__.py +27 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/accounting/account.py +219 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/accounting/gatekeeper.py +262 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/accounting/policy.py +736 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/analysis.py +414 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/analytics/__init__.py +37 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/analytics/bridge.py +139 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/analytics/equity.py +132 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/analytics/metrics.py +180 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/analytics/trades.py +463 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/broker.py +1180 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/calendar.py +773 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/config.py +554 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/datafeed.py +147 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/engine.py +471 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/execution/__init__.py +46 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/execution/fill_executor.py +461 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/execution/impact.py +185 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/execution/limits.py +186 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/execution/rebalancer.py +351 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/execution/result.py +32 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/export.py +312 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/models.py +134 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/presets/backtrader.yaml +46 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/presets/default.yaml +45 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/presets/realistic.yaml +48 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/presets/vectorbt.yaml +46 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/presets/zipline.yaml +46 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/result.py +764 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/__init__.py +75 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/portfolio/__init__.py +44 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/portfolio/limits.py +601 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/portfolio/manager.py +213 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/position/__init__.py +34 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/position/composite.py +103 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/position/dynamic.py +345 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/position/protocol.py +38 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/position/signal.py +91 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/position/static.py +253 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/risk/types.py +147 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/sessions.py +279 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/strategies/__init__.py +43 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/strategies/templates.py +395 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/strategy.py +28 -0
- ml4t_backtest-0.1.0a2/src/ml4t/backtest/types.py +377 -0
- ml4t_backtest-0.1.0a2/tests/__init__.py +1 -0
- ml4t_backtest-0.1.0a2/tests/accounting/__init__.py +1 -0
- ml4t_backtest-0.1.0a2/tests/accounting/test_account_state.py +361 -0
- ml4t_backtest-0.1.0a2/tests/accounting/test_cash_account_policy.py +470 -0
- ml4t_backtest-0.1.0a2/tests/accounting/test_gatekeeper.py +517 -0
- ml4t_backtest-0.1.0a2/tests/accounting/test_margin_account_policy.py +663 -0
- ml4t_backtest-0.1.0a2/tests/accounting/test_position.py +411 -0
- ml4t_backtest-0.1.0a2/tests/execution/__init__.py +1 -0
- ml4t_backtest-0.1.0a2/tests/execution/test_impact.py +247 -0
- ml4t_backtest-0.1.0a2/tests/execution/test_limits.py +241 -0
- ml4t_backtest-0.1.0a2/tests/execution/test_rebalancer.py +723 -0
- ml4t_backtest-0.1.0a2/tests/risk/__init__.py +1 -0
- ml4t_backtest-0.1.0a2/tests/risk/test_composite_rules.py +277 -0
- ml4t_backtest-0.1.0a2/tests/risk/test_dynamic_rules.py +567 -0
- ml4t_backtest-0.1.0a2/tests/risk/test_portfolio_limits.py +1006 -0
- ml4t_backtest-0.1.0a2/tests/risk/test_portfolio_manager.py +316 -0
- ml4t_backtest-0.1.0a2/tests/risk/test_signal_rules.py +221 -0
- ml4t_backtest-0.1.0a2/tests/risk/test_static_rules.py +465 -0
- ml4t_backtest-0.1.0a2/tests/test_analysis.py +623 -0
- ml4t_backtest-0.1.0a2/tests/test_broker.py +2464 -0
- ml4t_backtest-0.1.0a2/tests/test_calendar.py +500 -0
- ml4t_backtest-0.1.0a2/tests/test_calendar_integration.py +462 -0
- ml4t_backtest-0.1.0a2/tests/test_core.py +737 -0
- ml4t_backtest-0.1.0a2/tests/test_datafeed_memory.py +232 -0
- ml4t_backtest-0.1.0a2/tests/test_diagnostic_integration.py +147 -0
- ml4t_backtest-0.1.0a2/tests/test_export.py +410 -0
- ml4t_backtest-0.1.0a2/tests/test_result.py +583 -0
- ml4t_backtest-0.1.0a2/tests/test_sessions.py +289 -0
- ml4t_backtest-0.1.0a2/tests/test_strategy_templates.py +325 -0
- ml4t_backtest-0.1.0a2/tests/test_trade_mfe_mae.py +356 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
*.egg-info/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
eggs/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
ENV/
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.idea/
|
|
20
|
+
.vscode/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
|
|
24
|
+
# Testing
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.tox/
|
|
29
|
+
.nox/
|
|
30
|
+
|
|
31
|
+
# mypy
|
|
32
|
+
.mypy_cache/
|
|
33
|
+
|
|
34
|
+
# Jupyter
|
|
35
|
+
.ipynb_checkpoints/
|
|
36
|
+
src/ml4t/backtest/_version.py
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ml4t-backtest
|
|
3
|
+
Version: 0.1.0a2
|
|
4
|
+
Summary: State-of-the-art event-driven backtesting engine for quantitative trading
|
|
5
|
+
Project-URL: Homepage, https://github.com/ml4t/ml4t-backtest
|
|
6
|
+
Project-URL: Documentation, https://ml4t-backtest.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/ml4t/ml4t-backtest
|
|
8
|
+
Project-URL: Issues, https://github.com/ml4t/ml4t-backtest/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/ml4t/ml4t-backtest/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: QuantLab Team <info@quantlab.io>
|
|
11
|
+
Maintainer-email: QuantLab Contributors <dev@quantlab.io>
|
|
12
|
+
License: MIT
|
|
13
|
+
Keywords: algorithmic-trading,backtesting,event-driven,execution,finance,polars,portfolio,quantitative-finance,risk-management,simulation,trading
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
25
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
27
|
+
Classifier: Typing :: Typed
|
|
28
|
+
Requires-Python: >=3.11
|
|
29
|
+
Requires-Dist: numba>=0.57.0
|
|
30
|
+
Requires-Dist: numpy>=1.24.0
|
|
31
|
+
Requires-Dist: pandas-market-calendars>=4.0.0
|
|
32
|
+
Requires-Dist: pandas>=2.0.0
|
|
33
|
+
Requires-Dist: polars>=0.20.0
|
|
34
|
+
Requires-Dist: pyarrow>=14.0.0
|
|
35
|
+
Requires-Dist: pydantic<3.0.0,>=1.10.0
|
|
36
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
37
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
38
|
+
Requires-Dist: sortedcontainers>=2.4.0
|
|
39
|
+
Requires-Dist: structlog>=23.0.0
|
|
40
|
+
Requires-Dist: tables>=3.8.0
|
|
41
|
+
Provides-Extra: advanced
|
|
42
|
+
Requires-Dist: cvxpy>=1.3.0; extra == 'advanced'
|
|
43
|
+
Requires-Dist: networkx>=3.0; extra == 'advanced'
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Requires-Dist: cvxpy>=1.3.0; extra == 'all'
|
|
46
|
+
Requires-Dist: dash>=2.11.0; extra == 'all'
|
|
47
|
+
Requires-Dist: hypothesis>=6.80.0; extra == 'all'
|
|
48
|
+
Requires-Dist: ipdb>=0.13.0; extra == 'all'
|
|
49
|
+
Requires-Dist: ipython>=8.14.0; extra == 'all'
|
|
50
|
+
Requires-Dist: matplotlib>=3.7.0; extra == 'all'
|
|
51
|
+
Requires-Dist: mypy>=1.5.0; extra == 'all'
|
|
52
|
+
Requires-Dist: myst-parser>=2.0.0; extra == 'all'
|
|
53
|
+
Requires-Dist: nbsphinx>=0.9.0; extra == 'all'
|
|
54
|
+
Requires-Dist: networkx>=3.0; extra == 'all'
|
|
55
|
+
Requires-Dist: plotly>=5.15.0; extra == 'all'
|
|
56
|
+
Requires-Dist: pre-commit>=3.3.0; extra == 'all'
|
|
57
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'all'
|
|
58
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'all'
|
|
59
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'all'
|
|
60
|
+
Requires-Dist: pytest-timeout>=2.1.0; extra == 'all'
|
|
61
|
+
Requires-Dist: pytest-xdist>=3.3.0; extra == 'all'
|
|
62
|
+
Requires-Dist: pytest>=7.4.0; extra == 'all'
|
|
63
|
+
Requires-Dist: ruff>=0.1.0; extra == 'all'
|
|
64
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.24.0; extra == 'all'
|
|
65
|
+
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == 'all'
|
|
66
|
+
Requires-Dist: sphinx>=7.0.0; extra == 'all'
|
|
67
|
+
Provides-Extra: comparison
|
|
68
|
+
Requires-Dist: backtrader>=1.9.0; extra == 'comparison'
|
|
69
|
+
Requires-Dist: vectorbt>=0.24.0; extra == 'comparison'
|
|
70
|
+
Requires-Dist: zipline-reloaded>=2.4.0; extra == 'comparison'
|
|
71
|
+
Provides-Extra: dev
|
|
72
|
+
Requires-Dist: hypothesis>=6.80.0; extra == 'dev'
|
|
73
|
+
Requires-Dist: ipdb>=0.13.0; extra == 'dev'
|
|
74
|
+
Requires-Dist: ipython>=8.14.0; extra == 'dev'
|
|
75
|
+
Requires-Dist: mypy>=1.5.0; extra == 'dev'
|
|
76
|
+
Requires-Dist: pre-commit>=3.3.0; extra == 'dev'
|
|
77
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
78
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'dev'
|
|
79
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
80
|
+
Requires-Dist: pytest-timeout>=2.1.0; extra == 'dev'
|
|
81
|
+
Requires-Dist: pytest-xdist>=3.3.0; extra == 'dev'
|
|
82
|
+
Requires-Dist: pytest>=7.4.0; extra == 'dev'
|
|
83
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
84
|
+
Provides-Extra: docs
|
|
85
|
+
Requires-Dist: myst-parser>=2.0.0; extra == 'docs'
|
|
86
|
+
Requires-Dist: nbsphinx>=0.9.0; extra == 'docs'
|
|
87
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.24.0; extra == 'docs'
|
|
88
|
+
Requires-Dist: sphinx-rtd-theme>=1.3.0; extra == 'docs'
|
|
89
|
+
Requires-Dist: sphinx>=7.0.0; extra == 'docs'
|
|
90
|
+
Provides-Extra: viz
|
|
91
|
+
Requires-Dist: dash>=2.11.0; extra == 'viz'
|
|
92
|
+
Requires-Dist: matplotlib>=3.7.0; extra == 'viz'
|
|
93
|
+
Requires-Dist: plotly>=5.15.0; extra == 'viz'
|
|
94
|
+
Description-Content-Type: text/markdown
|
|
95
|
+
|
|
96
|
+
# ml4t-backtest
|
|
97
|
+
|
|
98
|
+
Event-driven backtesting engine for ML4T quantitative trading strategies.
|
|
99
|
+
|
|
100
|
+
## Features
|
|
101
|
+
|
|
102
|
+
- **Event-Driven Architecture**: Point-in-time correctness with no look-ahead bias
|
|
103
|
+
- **Exit-First Processing**: Matches real broker order execution behavior
|
|
104
|
+
- **VectorBT Validation**: Results validated against VectorBT Pro
|
|
105
|
+
- **Account Policies**: Cash and margin account support
|
|
106
|
+
- **Minimal Core**: ~2,800 lines of focused, maintainable code
|
|
107
|
+
- **100k+ events/sec**: High-performance event processing
|
|
108
|
+
|
|
109
|
+
## Installation
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pip install ml4t-backtest
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Quick Start
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
from ml4t.backtest import Engine, Strategy, BacktestConfig
|
|
119
|
+
|
|
120
|
+
class SimpleMovingAverage(Strategy):
|
|
121
|
+
def __init__(self, fast=10, slow=30):
|
|
122
|
+
self.fast = fast
|
|
123
|
+
self.slow = slow
|
|
124
|
+
|
|
125
|
+
def on_bar(self, bar):
|
|
126
|
+
fast_ma = bar.close_ma(self.fast)
|
|
127
|
+
slow_ma = bar.close_ma(self.slow)
|
|
128
|
+
|
|
129
|
+
if fast_ma > slow_ma and self.position == 0:
|
|
130
|
+
self.buy(size=100)
|
|
131
|
+
elif fast_ma < slow_ma and self.position > 0:
|
|
132
|
+
self.close()
|
|
133
|
+
|
|
134
|
+
config = BacktestConfig(
|
|
135
|
+
initial_cash=100_000,
|
|
136
|
+
commission=0.001,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
engine = Engine(data, SimpleMovingAverage(), config)
|
|
140
|
+
result = engine.run()
|
|
141
|
+
|
|
142
|
+
print(f"Total Return: {result.total_return:.2%}")
|
|
143
|
+
print(f"Sharpe Ratio: {result.metrics['sharpe']:.2f}")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Documentation
|
|
147
|
+
|
|
148
|
+
- **[AGENT.md](AGENT.md)**: Comprehensive API reference for agents and developers
|
|
149
|
+
- **[api.yaml](api.yaml)**: Machine-readable API specification
|
|
150
|
+
|
|
151
|
+
## Part of ML4T
|
|
152
|
+
|
|
153
|
+
This library is part of the ML4T quantitative trading toolkit:
|
|
154
|
+
|
|
155
|
+
- **ml4t-data**: Market data acquisition and storage
|
|
156
|
+
- **ml4t-engineer**: Feature engineering and indicators
|
|
157
|
+
- **ml4t-diagnostic**: Statistical validation and evaluation
|
|
158
|
+
- **ml4t-backtest**: Event-driven backtesting (this library)
|
|
159
|
+
- **ml4t-live**: Live trading platform
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT License - see LICENSE for details.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# ml4t-backtest
|
|
2
|
+
|
|
3
|
+
Event-driven backtesting engine for ML4T quantitative trading strategies.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Event-Driven Architecture**: Point-in-time correctness with no look-ahead bias
|
|
8
|
+
- **Exit-First Processing**: Matches real broker order execution behavior
|
|
9
|
+
- **VectorBT Validation**: Results validated against VectorBT Pro
|
|
10
|
+
- **Account Policies**: Cash and margin account support
|
|
11
|
+
- **Minimal Core**: ~2,800 lines of focused, maintainable code
|
|
12
|
+
- **100k+ events/sec**: High-performance event processing
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install ml4t-backtest
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from ml4t.backtest import Engine, Strategy, BacktestConfig
|
|
24
|
+
|
|
25
|
+
class SimpleMovingAverage(Strategy):
|
|
26
|
+
def __init__(self, fast=10, slow=30):
|
|
27
|
+
self.fast = fast
|
|
28
|
+
self.slow = slow
|
|
29
|
+
|
|
30
|
+
def on_bar(self, bar):
|
|
31
|
+
fast_ma = bar.close_ma(self.fast)
|
|
32
|
+
slow_ma = bar.close_ma(self.slow)
|
|
33
|
+
|
|
34
|
+
if fast_ma > slow_ma and self.position == 0:
|
|
35
|
+
self.buy(size=100)
|
|
36
|
+
elif fast_ma < slow_ma and self.position > 0:
|
|
37
|
+
self.close()
|
|
38
|
+
|
|
39
|
+
config = BacktestConfig(
|
|
40
|
+
initial_cash=100_000,
|
|
41
|
+
commission=0.001,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
engine = Engine(data, SimpleMovingAverage(), config)
|
|
45
|
+
result = engine.run()
|
|
46
|
+
|
|
47
|
+
print(f"Total Return: {result.total_return:.2%}")
|
|
48
|
+
print(f"Sharpe Ratio: {result.metrics['sharpe']:.2f}")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Documentation
|
|
52
|
+
|
|
53
|
+
- **[AGENT.md](AGENT.md)**: Comprehensive API reference for agents and developers
|
|
54
|
+
- **[api.yaml](api.yaml)**: Machine-readable API specification
|
|
55
|
+
|
|
56
|
+
## Part of ML4T
|
|
57
|
+
|
|
58
|
+
This library is part of the ML4T quantitative trading toolkit:
|
|
59
|
+
|
|
60
|
+
- **ml4t-data**: Market data acquisition and storage
|
|
61
|
+
- **ml4t-engineer**: Feature engineering and indicators
|
|
62
|
+
- **ml4t-diagnostic**: Statistical validation and evaluation
|
|
63
|
+
- **ml4t-backtest**: Event-driven backtesting (this library)
|
|
64
|
+
- **ml4t-live**: Live trading platform
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT License - see LICENSE for details.
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# ml4t.backtest - Event-driven backtesting with institutional-grade correctness guarantees
|
|
2
|
+
# Independent package configuration for standalone distribution
|
|
3
|
+
|
|
4
|
+
[build-system]
|
|
5
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
6
|
+
build-backend = "hatchling.build"
|
|
7
|
+
|
|
8
|
+
[tool.hatch.version]
|
|
9
|
+
source = "vcs"
|
|
10
|
+
|
|
11
|
+
[tool.hatch.build.hooks.vcs]
|
|
12
|
+
version-file = "src/ml4t/backtest/_version.py"
|
|
13
|
+
|
|
14
|
+
[tool.hatch.build.targets.wheel]
|
|
15
|
+
packages = ["src/ml4t"]
|
|
16
|
+
namespaces = true
|
|
17
|
+
|
|
18
|
+
[tool.hatch.build.targets.sdist]
|
|
19
|
+
include = [
|
|
20
|
+
"/src",
|
|
21
|
+
"/tests",
|
|
22
|
+
"/README.md",
|
|
23
|
+
"/LICENSE",
|
|
24
|
+
"/CHANGELOG.md",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project]
|
|
28
|
+
name = "ml4t-backtest"
|
|
29
|
+
dynamic = ["version"]
|
|
30
|
+
description = "State-of-the-art event-driven backtesting engine for quantitative trading"
|
|
31
|
+
readme = "README.md"
|
|
32
|
+
license = { text = "MIT" }
|
|
33
|
+
authors = [
|
|
34
|
+
{ name = "QuantLab Team", email = "info@quantlab.io" },
|
|
35
|
+
]
|
|
36
|
+
maintainers = [
|
|
37
|
+
{ name = "QuantLab Contributors", email = "dev@quantlab.io" },
|
|
38
|
+
]
|
|
39
|
+
keywords = [
|
|
40
|
+
"finance",
|
|
41
|
+
"backtesting",
|
|
42
|
+
"trading",
|
|
43
|
+
"simulation",
|
|
44
|
+
"event-driven",
|
|
45
|
+
"quantitative-finance",
|
|
46
|
+
"algorithmic-trading",
|
|
47
|
+
"portfolio",
|
|
48
|
+
"risk-management",
|
|
49
|
+
"execution",
|
|
50
|
+
"polars",
|
|
51
|
+
]
|
|
52
|
+
classifiers = [
|
|
53
|
+
"Development Status :: 4 - Beta",
|
|
54
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
55
|
+
"Intended Audience :: Developers",
|
|
56
|
+
"Intended Audience :: Science/Research",
|
|
57
|
+
"License :: OSI Approved :: MIT License",
|
|
58
|
+
"Operating System :: OS Independent",
|
|
59
|
+
"Programming Language :: Python :: 3",
|
|
60
|
+
"Programming Language :: Python :: 3.11",
|
|
61
|
+
"Programming Language :: Python :: 3.12",
|
|
62
|
+
"Programming Language :: Python :: 3.13",
|
|
63
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
64
|
+
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
65
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
66
|
+
"Typing :: Typed",
|
|
67
|
+
]
|
|
68
|
+
requires-python = ">=3.11"
|
|
69
|
+
|
|
70
|
+
# Core dependencies
|
|
71
|
+
dependencies = [
|
|
72
|
+
# Data processing
|
|
73
|
+
"polars>=0.20.0",
|
|
74
|
+
"pandas>=2.0.0",
|
|
75
|
+
"numpy>=1.24.0",
|
|
76
|
+
"pyarrow>=14.0.0",
|
|
77
|
+
"tables>=3.8.0", # PyTables for HDF5 support
|
|
78
|
+
# Event system
|
|
79
|
+
"sortedcontainers>=2.4.0", # Efficient priority queue
|
|
80
|
+
# Performance optimization
|
|
81
|
+
"numba>=0.57.0",
|
|
82
|
+
# Configuration and validation
|
|
83
|
+
"pydantic>=1.10.0,<3.0.0", # Configuration schema and validation
|
|
84
|
+
"PyYAML>=6.0.0", # YAML configuration support
|
|
85
|
+
# Utilities
|
|
86
|
+
"structlog>=23.0.0",
|
|
87
|
+
"python-dateutil>=2.8.0",
|
|
88
|
+
# Market calendars (needed for clock module)
|
|
89
|
+
"pandas-market-calendars>=4.0.0",
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
[project.optional-dependencies]
|
|
93
|
+
# Visualization and reporting
|
|
94
|
+
viz = [
|
|
95
|
+
"plotly>=5.15.0",
|
|
96
|
+
"matplotlib>=3.7.0",
|
|
97
|
+
"dash>=2.11.0", # Interactive dashboards
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
# Advanced execution models
|
|
101
|
+
advanced = [
|
|
102
|
+
"networkx>=3.0", # Order routing graphs
|
|
103
|
+
"cvxpy>=1.3.0", # Portfolio optimization
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
# Comparison libraries (for benchmarking)
|
|
107
|
+
comparison = [
|
|
108
|
+
"vectorbt>=0.24.0",
|
|
109
|
+
"backtrader>=1.9.0",
|
|
110
|
+
"zipline-reloaded>=2.4.0",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Development dependencies
|
|
114
|
+
dev = [
|
|
115
|
+
"pytest>=7.4.0",
|
|
116
|
+
"pytest-cov>=4.1.0",
|
|
117
|
+
"pytest-xdist>=3.3.0",
|
|
118
|
+
"pytest-timeout>=2.1.0",
|
|
119
|
+
"pytest-benchmark>=4.0.0",
|
|
120
|
+
"pytest-asyncio>=0.21.0",
|
|
121
|
+
"hypothesis>=6.80.0",
|
|
122
|
+
"ruff>=0.1.0",
|
|
123
|
+
"mypy>=1.5.0",
|
|
124
|
+
"ipython>=8.14.0",
|
|
125
|
+
"ipdb>=0.13.0",
|
|
126
|
+
"pre-commit>=3.3.0",
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
# Documentation dependencies
|
|
130
|
+
docs = [
|
|
131
|
+
"sphinx>=7.0.0",
|
|
132
|
+
"sphinx-rtd-theme>=1.3.0",
|
|
133
|
+
"sphinx-autodoc-typehints>=1.24.0",
|
|
134
|
+
"myst-parser>=2.0.0",
|
|
135
|
+
"nbsphinx>=0.9.0",
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
# All optional dependencies
|
|
139
|
+
all = [
|
|
140
|
+
"ml4t-backtest[viz,advanced,dev,docs]",
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
[project.urls]
|
|
144
|
+
Homepage = "https://github.com/ml4t/ml4t-backtest"
|
|
145
|
+
Documentation = "https://ml4t-backtest.readthedocs.io"
|
|
146
|
+
Repository = "https://github.com/ml4t/ml4t-backtest"
|
|
147
|
+
Issues = "https://github.com/ml4t/ml4t-backtest/issues"
|
|
148
|
+
Changelog = "https://github.com/ml4t/ml4t-backtest/blob/main/CHANGELOG.md"
|
|
149
|
+
|
|
150
|
+
[tool.pytest.ini_options]
|
|
151
|
+
testpaths = ["tests"]
|
|
152
|
+
python_files = ["test_*.py"]
|
|
153
|
+
python_classes = ["Test*"]
|
|
154
|
+
python_functions = ["test_*"]
|
|
155
|
+
addopts = [
|
|
156
|
+
"-ra",
|
|
157
|
+
"--strict-markers",
|
|
158
|
+
"--ignore=tests/private", # Exclude private/commercial dependency tests
|
|
159
|
+
"--ignore=tests/validation", # Exclude optional cross-framework validation tests
|
|
160
|
+
"--cov=ml4t.backtest",
|
|
161
|
+
"--cov-report=term-missing",
|
|
162
|
+
"--cov-report=html",
|
|
163
|
+
]
|
|
164
|
+
markers = [
|
|
165
|
+
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
|
|
166
|
+
"integration: marks tests as integration tests",
|
|
167
|
+
"benchmark: marks benchmark tests",
|
|
168
|
+
"unit: marks unit tests",
|
|
169
|
+
"private: requires commercial dependencies (vectorbtpro) - excluded by default",
|
|
170
|
+
"requires_comparison: requires optional comparison frameworks (vectorbt, backtrader, zipline)",
|
|
171
|
+
]
|
|
172
|
+
filterwarnings = [
|
|
173
|
+
"ignore::DeprecationWarning",
|
|
174
|
+
"ignore::PendingDeprecationWarning",
|
|
175
|
+
"ignore::UserWarning:vectorbt", # VectorBT accessor registration warnings
|
|
176
|
+
"ignore::tables.NaturalNameWarning", # PyTables naming warnings
|
|
177
|
+
"ignore::FutureWarning:zipline", # Zipline compatibility warnings
|
|
178
|
+
"ignore::pytest.PytestReturnNotNoneWarning", # Some tests return values for direct execution
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
[tool.ruff]
|
|
182
|
+
line-length = 100
|
|
183
|
+
target-version = "py311"
|
|
184
|
+
fix = true
|
|
185
|
+
exclude = [
|
|
186
|
+
"validation/*", # Standalone scripts run in isolated venvs
|
|
187
|
+
"docs/*", # Documentation artifacts
|
|
188
|
+
".claude/*", # Claude workspace files
|
|
189
|
+
".serena/*", # Serena workspace files
|
|
190
|
+
]
|
|
191
|
+
|
|
192
|
+
[tool.ruff.lint]
|
|
193
|
+
select = [
|
|
194
|
+
"E", # pycodestyle errors
|
|
195
|
+
"W", # pycodestyle warnings
|
|
196
|
+
"F", # pyflakes
|
|
197
|
+
"I", # isort
|
|
198
|
+
"B", # flake8-bugbear
|
|
199
|
+
"C4", # flake8-comprehensions
|
|
200
|
+
"UP", # pyupgrade
|
|
201
|
+
"ARG", # flake8-unused-arguments
|
|
202
|
+
"SIM", # flake8-simplify
|
|
203
|
+
]
|
|
204
|
+
ignore = [
|
|
205
|
+
"E501", # line too long (handled by formatter)
|
|
206
|
+
"B008", # do not perform function calls in argument defaults
|
|
207
|
+
"B905", # zip without explicit strict parameter
|
|
208
|
+
"ARG002", # unused method arguments (intentional in strategy callbacks)
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
[tool.ruff.lint.per-file-ignores]
|
|
212
|
+
"tests/*" = ["ARG001", "ARG002"] # Test functions often have unused fixtures
|
|
213
|
+
|
|
214
|
+
[tool.mypy]
|
|
215
|
+
python_version = "3.11"
|
|
216
|
+
strict = false
|
|
217
|
+
warn_return_any = false # numpy/pandas return Any, too many false positives
|
|
218
|
+
warn_unused_ignores = true
|
|
219
|
+
disallow_untyped_defs = false
|
|
220
|
+
disallow_any_unimported = false
|
|
221
|
+
no_implicit_optional = true
|
|
222
|
+
check_untyped_defs = true
|
|
223
|
+
show_error_codes = true
|
|
224
|
+
warn_redundant_casts = true
|
|
225
|
+
ignore_missing_imports = true
|
|
226
|
+
|
|
227
|
+
[tool.coverage.run]
|
|
228
|
+
source = ["src/ml4t/backtest"]
|
|
229
|
+
omit = [
|
|
230
|
+
"*/tests/*",
|
|
231
|
+
"*/__init__.py",
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
[tool.coverage.report]
|
|
235
|
+
exclude_lines = [
|
|
236
|
+
"pragma: no cover",
|
|
237
|
+
"def __repr__",
|
|
238
|
+
"if self.debug:",
|
|
239
|
+
"if __name__ == .__main__.:",
|
|
240
|
+
"raise NotImplementedError",
|
|
241
|
+
"pass",
|
|
242
|
+
"except ImportError:",
|
|
243
|
+
"@abstractmethod",
|
|
244
|
+
]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""ML4T Backtest - Event-driven backtesting engine.
|
|
2
|
+
|
|
3
|
+
A minimal, event-driven backtesting engine with:
|
|
4
|
+
- Point-in-time correctness
|
|
5
|
+
- Exit-first order processing
|
|
6
|
+
- Cash and margin account policies
|
|
7
|
+
- VectorBT-validated results
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
>>> from ml4t.backtest import Engine, Strategy, BacktestConfig
|
|
11
|
+
>>>
|
|
12
|
+
>>> class MyStrategy(Strategy):
|
|
13
|
+
... def on_bar(self, bar):
|
|
14
|
+
... if self.position == 0:
|
|
15
|
+
... self.buy(size=100)
|
|
16
|
+
>>>
|
|
17
|
+
>>> result = Engine(data, MyStrategy()).run()
|
|
18
|
+
>>> print(result.metrics)
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from ml4t.backtest.types import (
|
|
22
|
+
Order,
|
|
23
|
+
OrderType,
|
|
24
|
+
OrderSide,
|
|
25
|
+
Fill,
|
|
26
|
+
Position,
|
|
27
|
+
Trade,
|
|
28
|
+
)
|
|
29
|
+
from ml4t.backtest.config import BacktestConfig
|
|
30
|
+
from ml4t.backtest.strategy import Strategy
|
|
31
|
+
from ml4t.backtest.engine import Engine
|
|
32
|
+
from ml4t.backtest.broker import Broker
|
|
33
|
+
from ml4t.backtest.datafeed import DataFeed
|
|
34
|
+
from ml4t.backtest.result import BacktestResult
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
from ml4t.backtest._version import __version__
|
|
38
|
+
except ImportError:
|
|
39
|
+
__version__ = "0.0.0.dev0"
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
# Core types
|
|
43
|
+
"Order",
|
|
44
|
+
"OrderType",
|
|
45
|
+
"OrderSide",
|
|
46
|
+
"Fill",
|
|
47
|
+
"Position",
|
|
48
|
+
"Trade",
|
|
49
|
+
# Main classes
|
|
50
|
+
"BacktestConfig",
|
|
51
|
+
"Strategy",
|
|
52
|
+
"Engine",
|
|
53
|
+
"Broker",
|
|
54
|
+
"DataFeed",
|
|
55
|
+
"BacktestResult",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def list_order_types() -> list[str]:
|
|
60
|
+
"""List available order types."""
|
|
61
|
+
return [t.name for t in OrderType]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def list_presets() -> list[str]:
|
|
65
|
+
"""List available configuration presets."""
|
|
66
|
+
from ml4t.backtest import presets
|
|
67
|
+
return [name for name in dir(presets) if not name.startswith('_')]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '0.1.0a2'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 0, 'a2')
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Accounting module for backtesting engine.
|
|
2
|
+
|
|
3
|
+
Provides proper accounting constraints for both cash accounts (no leverage, no shorts)
|
|
4
|
+
and margin accounts (leverage enabled, shorts allowed).
|
|
5
|
+
|
|
6
|
+
Key Components:
|
|
7
|
+
- Position: Unified position tracking (from types module)
|
|
8
|
+
- AccountPolicy: Interface for account type constraints
|
|
9
|
+
- CashAccountPolicy: Cash account constraints (cash >= 0, no shorts)
|
|
10
|
+
- MarginAccountPolicy: Margin account constraints (NLV/BP/MM calculations)
|
|
11
|
+
- AccountState: Account state management and position tracking
|
|
12
|
+
- Gatekeeper: Order validation before execution
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from ..types import Position
|
|
16
|
+
from .account import AccountState
|
|
17
|
+
from .gatekeeper import Gatekeeper
|
|
18
|
+
from .policy import AccountPolicy, CashAccountPolicy, MarginAccountPolicy
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"Position",
|
|
22
|
+
"AccountPolicy",
|
|
23
|
+
"CashAccountPolicy",
|
|
24
|
+
"MarginAccountPolicy",
|
|
25
|
+
"AccountState",
|
|
26
|
+
"Gatekeeper",
|
|
27
|
+
]
|