ml4t-live 0.1.0__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_live-0.1.0/.gitignore +41 -0
- ml4t_live-0.1.0/LICENSE +21 -0
- ml4t_live-0.1.0/PKG-INFO +410 -0
- ml4t_live-0.1.0/README.md +369 -0
- ml4t_live-0.1.0/pyproject.toml +150 -0
- ml4t_live-0.1.0/src/ml4t/live/__init__.py +138 -0
- ml4t_live-0.1.0/src/ml4t/live/_version.py +24 -0
- ml4t_live-0.1.0/src/ml4t/live/brokers/__init__.py +6 -0
- ml4t_live-0.1.0/src/ml4t/live/brokers/alpaca.py +969 -0
- ml4t_live-0.1.0/src/ml4t/live/brokers/ib.py +902 -0
- ml4t_live-0.1.0/src/ml4t/live/cli/__init__.py +1 -0
- ml4t_live-0.1.0/src/ml4t/live/cli/main.py +901 -0
- ml4t_live-0.1.0/src/ml4t/live/engine.py +1559 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/__init__.py +28 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/aggregator.py +409 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/alpaca_feed.py +621 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/crypto_feed.py +468 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/databento_feed.py +470 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/events.py +257 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/experimental.py +37 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/ib_feed.py +353 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/okx_feed.py +460 -0
- ml4t_live-0.1.0/src/ml4t/live/feeds/queue.py +198 -0
- ml4t_live-0.1.0/src/ml4t/live/lifecycle.py +213 -0
- ml4t_live-0.1.0/src/ml4t/live/orders.py +187 -0
- ml4t_live-0.1.0/src/ml4t/live/persistence.py +608 -0
- ml4t_live-0.1.0/src/ml4t/live/protocols.py +418 -0
- ml4t_live-0.1.0/src/ml4t/live/py.typed +0 -0
- ml4t_live-0.1.0/src/ml4t/live/runtime.py +994 -0
- ml4t_live-0.1.0/src/ml4t/live/safety.py +2654 -0
- ml4t_live-0.1.0/src/ml4t/live/state_migration.py +214 -0
- ml4t_live-0.1.0/src/ml4t/live/wrappers.py +359 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.so
|
|
5
|
+
.Python
|
|
6
|
+
build/
|
|
7
|
+
develop-eggs/
|
|
8
|
+
dist/
|
|
9
|
+
downloads/
|
|
10
|
+
eggs/
|
|
11
|
+
.eggs/
|
|
12
|
+
lib/
|
|
13
|
+
lib64/
|
|
14
|
+
parts/
|
|
15
|
+
sdist/
|
|
16
|
+
var/
|
|
17
|
+
wheels/
|
|
18
|
+
*.egg-info/
|
|
19
|
+
.installed.cfg
|
|
20
|
+
*.egg
|
|
21
|
+
.env
|
|
22
|
+
.venv/
|
|
23
|
+
venv/
|
|
24
|
+
ENV/
|
|
25
|
+
.mypy_cache/
|
|
26
|
+
.ruff_cache/
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
*.log
|
|
31
|
+
.DS_Store
|
|
32
|
+
*.tmp
|
|
33
|
+
/data/
|
|
34
|
+
logs/
|
|
35
|
+
site/
|
|
36
|
+
src/ml4t/live/_version.py
|
|
37
|
+
|
|
38
|
+
# Claude Code (local development only)
|
|
39
|
+
CLAUDE.md
|
|
40
|
+
.claude/
|
|
41
|
+
.ml4t_risk_state.json
|
ml4t_live-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Stefan Jansen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ml4t_live-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ml4t-live
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Live trading platform for ML4T strategies
|
|
5
|
+
Project-URL: Homepage, https://www.ml4trading.io/docs/live/
|
|
6
|
+
Project-URL: Documentation, https://www.ml4trading.io/docs/live/
|
|
7
|
+
Project-URL: Repository, https://github.com/ml4t/live
|
|
8
|
+
Project-URL: Issues, https://github.com/ml4t/live/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/ml4t/live/releases
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Python: <3.15,>=3.12
|
|
19
|
+
Requires-Dist: alpaca-py==0.43.5
|
|
20
|
+
Requires-Dist: ccxt<=4.5.71,>=4.5.31
|
|
21
|
+
Requires-Dist: httpx==0.28.1
|
|
22
|
+
Requires-Dist: ib-async==2.1.0
|
|
23
|
+
Requires-Dist: ml4t-backtest<0.2,>=0.1.0
|
|
24
|
+
Requires-Dist: ml4t-specs<0.2,>=0.1.1
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: packaging==26.3; extra == 'dev'
|
|
27
|
+
Requires-Dist: pre-commit>=3.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pyyaml==6.0.3; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
33
|
+
Requires-Dist: ty; extra == 'dev'
|
|
34
|
+
Provides-Extra: docs
|
|
35
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
|
|
36
|
+
Requires-Dist: mkdocs<2,>=1.6; extra == 'docs'
|
|
37
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
|
|
38
|
+
Provides-Extra: experimental
|
|
39
|
+
Requires-Dist: databento==0.83.0; extra == 'experimental'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
# ml4t-live
|
|
43
|
+
|
|
44
|
+
[](https://www.python.org/downloads/)
|
|
45
|
+
[](https://pypi.org/project/ml4t-live/)
|
|
46
|
+
[](https://opensource.org/licenses/MIT)
|
|
47
|
+
|
|
48
|
+
Live trading runtime for causal ML4T strategies.
|
|
49
|
+
|
|
50
|
+
## Part of the ML4T Library Ecosystem
|
|
51
|
+
|
|
52
|
+
This library is one of six interconnected libraries supporting the machine learning for trading workflow described in [Machine Learning for Trading](https://www.ml4trading.io/):
|
|
53
|
+
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
Together they cover data infrastructure, feature engineering, modeling, signal evaluation, strategy backtesting, and live deployment.
|
|
57
|
+
|
|
58
|
+
## What This Library Does
|
|
59
|
+
|
|
60
|
+
Deploying a backtested strategy to live markets requires careful handling of async broker connections, risk limits, and testing infrastructure. ml4t-live provides:
|
|
61
|
+
|
|
62
|
+
- Strategy portability under the shared lifecycle version 1 contract
|
|
63
|
+
- Two broker integrations: Interactive Brokers (TWS/Gateway) and Alpaca (stocks + crypto)
|
|
64
|
+
- A stable-supported OKX feed plus typed bar aggregation
|
|
65
|
+
- Explicit opt-in experimental adapters for Alpaca, IB, generic CCXT, and DataBento workflows
|
|
66
|
+
- Shadow mode for testing without placing real orders (VirtualPortfolio tracking)
|
|
67
|
+
- 16-parameter risk configuration: position limits, order limits, loss limits, price protection
|
|
68
|
+
- Kill switch with crash-safe state persistence (atomic JSON writes)
|
|
69
|
+
- Startup preflight, reconciliation, and JSONL execution journaling for operator workflows
|
|
70
|
+
- Async architecture with thread-safe sync bridge for strategy callbacks
|
|
71
|
+
|
|
72
|
+
The goal is gradual deployment: shadow mode first, then paper trading, then live with small positions.
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
## Installation
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv add ml4t-live
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Add the optional DataBento SDK only for deliberate experimental evaluation:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uv add 'ml4t-live[experimental]'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from ml4t.backtest import Strategy, OrderSide
|
|
92
|
+
from ml4t.live import LiveEngine, LiveRiskConfig, SafeBroker
|
|
93
|
+
from ml4t.live.brokers.alpaca import AlpacaBroker
|
|
94
|
+
from ml4t.live.feeds.alpaca_feed import AlpacaDataFeed
|
|
95
|
+
import asyncio
|
|
96
|
+
|
|
97
|
+
# A lifecycle-v1 strategy that uses only portable callbacks and broker operations
|
|
98
|
+
class MyStrategy(Strategy):
|
|
99
|
+
def on_data(self, timestamp, data, context, broker):
|
|
100
|
+
if not broker.get_position('SPY'):
|
|
101
|
+
broker.submit_order('SPY', 10, side=OrderSide.BUY)
|
|
102
|
+
|
|
103
|
+
async def main():
|
|
104
|
+
broker = AlpacaBroker(api_key="...", secret_key="...", paper=True)
|
|
105
|
+
feed = AlpacaDataFeed(
|
|
106
|
+
api_key="...", secret_key="...", symbols=["SPY"], experimental=True
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
config = LiveRiskConfig(
|
|
110
|
+
execution_mode="shadow", # No real orders
|
|
111
|
+
max_position_value=50_000,
|
|
112
|
+
)
|
|
113
|
+
safe = SafeBroker(broker, config)
|
|
114
|
+
|
|
115
|
+
engine = LiveEngine(MyStrategy(), safe, feed)
|
|
116
|
+
await engine.connect()
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
await engine.run()
|
|
120
|
+
finally:
|
|
121
|
+
await engine.stop()
|
|
122
|
+
|
|
123
|
+
asyncio.run(main())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Broker Integrations
|
|
127
|
+
|
|
128
|
+
### Alpaca
|
|
129
|
+
|
|
130
|
+
Stocks and crypto with paper trading by default:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from ml4t.live.brokers.alpaca import AlpacaBroker
|
|
134
|
+
|
|
135
|
+
broker = AlpacaBroker(
|
|
136
|
+
api_key="...",
|
|
137
|
+
secret_key="...",
|
|
138
|
+
paper=True, # Paper trading (default)
|
|
139
|
+
)
|
|
140
|
+
await broker.connect()
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Interactive Brokers
|
|
144
|
+
|
|
145
|
+
Full market access via TWS or IB Gateway:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from ml4t.live.brokers.ib import IBBroker
|
|
149
|
+
|
|
150
|
+
broker = IBBroker(port=7497) # TWS paper port
|
|
151
|
+
# broker = IBBroker(port=7496) # TWS live port
|
|
152
|
+
|
|
153
|
+
await broker.connect()
|
|
154
|
+
print(f"Connected: {broker.is_connected}")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Requirements:
|
|
158
|
+
- IB TWS or Gateway running
|
|
159
|
+
- API connections enabled in TWS settings
|
|
160
|
+
- Paper trading account for initial testing
|
|
161
|
+
|
|
162
|
+
## Data Feeds
|
|
163
|
+
|
|
164
|
+
| Feed | Source | Status | Coverage |
|
|
165
|
+
|------|--------|--------|----------|
|
|
166
|
+
| `AlpacaDataFeed` | Alpaca | experimental | US stocks + crypto, real-time bars/quotes/trades |
|
|
167
|
+
| `IBDataFeed` | Interactive Brokers | experimental | Multi-asset tick-by-tick data |
|
|
168
|
+
| `OKXFundingFeed` | OKX | stable-supported | Perpetual swaps with funding rates |
|
|
169
|
+
| `BarAggregator` | Any typed feed | stable-supported | Multi-feed aggregation + bar assembly |
|
|
170
|
+
| `DataBentoFeed` | DataBento | experimental | Historical replay + real-time streaming |
|
|
171
|
+
| `CryptoFeed` | CCXT | experimental | Generic exchange trades and candles |
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from ml4t.live.feeds.alpaca_feed import AlpacaDataFeed
|
|
175
|
+
from ml4t.live.feeds.crypto_feed import CryptoFeed
|
|
176
|
+
|
|
177
|
+
# Experimental stock + crypto feed via Alpaca
|
|
178
|
+
feed = AlpacaDataFeed(
|
|
179
|
+
api_key="...", secret_key="...",
|
|
180
|
+
symbols=["AAPL", "BTC/USD"],
|
|
181
|
+
feed="iex", # "iex" (free) or "sip" (premium)
|
|
182
|
+
experimental=True,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Experimental generic crypto adapter; not part of the stable support contract
|
|
186
|
+
feed = CryptoFeed(
|
|
187
|
+
exchange="binance",
|
|
188
|
+
symbols=["BTC/USDT", "ETH/USDT"],
|
|
189
|
+
timeframe="1m",
|
|
190
|
+
experimental=True,
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The experimental adapters require explicit opt-in and report their adapter-specific missing
|
|
195
|
+
guarantees on first use. The `experimental` package extra installs the DataBento SDK; the other
|
|
196
|
+
adapters are present in the default environment.
|
|
197
|
+
|
|
198
|
+
## Risk Configuration
|
|
199
|
+
|
|
200
|
+
`LiveRiskConfig` controls all safety parameters. Wrap any broker with `SafeBroker` to enforce them:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from ml4t.live import LiveRiskConfig, SafeBroker
|
|
204
|
+
|
|
205
|
+
config = LiveRiskConfig(
|
|
206
|
+
# Explicit execution routing
|
|
207
|
+
execution_mode="shadow", # Virtual orders only (no real execution)
|
|
208
|
+
|
|
209
|
+
# Position limits
|
|
210
|
+
max_position_value=50_000, # Max $ per position
|
|
211
|
+
max_position_shares=1000, # Max shares per position
|
|
212
|
+
max_total_exposure=200_000, # Max total $ across all positions
|
|
213
|
+
max_positions=20, # Max number of positions
|
|
214
|
+
|
|
215
|
+
# Order limits
|
|
216
|
+
max_order_value=10_000, # Max $ per order
|
|
217
|
+
max_order_shares=500, # Max shares per order
|
|
218
|
+
max_orders_per_minute=10, # Rate limiting
|
|
219
|
+
|
|
220
|
+
# Loss limits
|
|
221
|
+
max_daily_loss=5_000, # Stop trading if exceeded
|
|
222
|
+
max_drawdown_pct=0.05, # Stop if 5% drawdown
|
|
223
|
+
|
|
224
|
+
# Price protection
|
|
225
|
+
max_price_deviation_pct=0.05, # Fat finger: reject if >5% from market
|
|
226
|
+
max_data_staleness_seconds=60, # Reject if data older than 60s
|
|
227
|
+
dedup_window_seconds=1.0, # Block duplicate orders within 1s
|
|
228
|
+
|
|
229
|
+
# Asset restrictions
|
|
230
|
+
allowed_assets={"SPY", "QQQ"}, # Whitelist (empty = allow all)
|
|
231
|
+
|
|
232
|
+
# Startup and persistence
|
|
233
|
+
fail_on_reconciliation_mismatch=True,
|
|
234
|
+
journal_file=".ml4t_execution_journal.jsonl",
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
safe_broker = SafeBroker(broker, config)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Use `None` to disable an individual numeric limit. NaN and infinity are invalid. Order quantities
|
|
241
|
+
are signed only when `side` is omitted; an explicit side requires a positive unsigned quantity.
|
|
242
|
+
|
|
243
|
+
## Safety System
|
|
244
|
+
|
|
245
|
+
### Kill Switch
|
|
246
|
+
|
|
247
|
+
When drawdown exceeds `max_drawdown_pct`, the kill switch activates and blocks all new orders. The state persists across process restarts:
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
config = LiveRiskConfig(
|
|
251
|
+
execution_mode="shadow",
|
|
252
|
+
kill_switch_enabled=True,
|
|
253
|
+
max_drawdown_pct=0.05,
|
|
254
|
+
state_file=".ml4t_risk_state.json", # Atomic JSON writes
|
|
255
|
+
)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Virtual Portfolio
|
|
259
|
+
|
|
260
|
+
Shadow mode tracks positions internally without broker interaction:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from ml4t.live import VirtualPortfolio
|
|
264
|
+
|
|
265
|
+
portfolio = VirtualPortfolio(initial_cash=100_000)
|
|
266
|
+
# SafeBroker uses this automatically when execution_mode="shadow"
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### State Persistence
|
|
270
|
+
|
|
271
|
+
Risk state survives process crashes through a versioned, checksummed atomic file:
|
|
272
|
+
|
|
273
|
+
- `daily_loss` - Cumulative daily loss
|
|
274
|
+
- `orders_placed` - Orders placed today
|
|
275
|
+
- `high_water_mark` - Session high equity
|
|
276
|
+
- `kill_switch_activated` - Persists until manually reset
|
|
277
|
+
|
|
278
|
+
State and audit files use mode `0600`, reject unsafe ownership or symlinks, and permit one writer.
|
|
279
|
+
`SafeBroker` also writes a hash-chained JSONL execution journal with reconciliation, order,
|
|
280
|
+
kill-switch, and runtime health events. Audit failure blocks broker calls by default.
|
|
281
|
+
|
|
282
|
+
`LiveEngine` acquires the broker and feed transactionally. Startup failure, strategy failure,
|
|
283
|
+
cancellation, and normal completion release acquired resources in reverse order. Bounded recovery
|
|
284
|
+
does not repeat strategy startup callbacks; exhausted recovery and incomplete cleanup have distinct
|
|
285
|
+
public exceptions and a `failed` runtime state.
|
|
286
|
+
|
|
287
|
+
## Operator CLI
|
|
288
|
+
|
|
289
|
+
Use the CLI as a thin operator surface around the Python API:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
# Fail-fast startup check for a real broker session
|
|
293
|
+
uv run ml4t-live preflight ib --state-file .ml4t_risk_state.json --strict
|
|
294
|
+
|
|
295
|
+
# Human-readable state and recent journal tail
|
|
296
|
+
uv run ml4t-live status --state-file .ml4t_risk_state.json
|
|
297
|
+
|
|
298
|
+
# Bounded shadow soak
|
|
299
|
+
uv run ml4t-live shadow examples/shadow_mode_demo.py --feed okx --duration 60
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`preflight` is the operator readiness command: it checks broker reachability, balances, persisted
|
|
303
|
+
kill-switch state, startup reconciliation, and session state, and exits non-zero when the result is
|
|
304
|
+
degraded.
|
|
305
|
+
|
|
306
|
+
## Order Lifecycle
|
|
307
|
+
|
|
308
|
+
Strategies still place orders through the same synchronous wrapper interface, but pending orders can now be replaced in a normalized way:
|
|
309
|
+
|
|
310
|
+
```python
|
|
311
|
+
def on_data(self, timestamp, data, context, broker):
|
|
312
|
+
if broker.pending_orders:
|
|
313
|
+
broker.replace_order(broker.pending_orders[0].order_id, limit_price=189.5)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The default implementation uses a safe cancel-and-resubmit flow across supported brokers.
|
|
317
|
+
|
|
318
|
+
## Deployment Progression
|
|
319
|
+
|
|
320
|
+
1. **Shadow Mode** (1-2 weeks): Verify logic without real orders
|
|
321
|
+
2. **Paper Trading** (2-4 weeks): Test with paper account
|
|
322
|
+
3. **Live Micro** (1-2 weeks): Small positions ($100-500)
|
|
323
|
+
4. **Live Small** (ongoing): Gradual size increase
|
|
324
|
+
|
|
325
|
+
## Strategy Portability
|
|
326
|
+
|
|
327
|
+
A `Strategy` subclass can run in both environments when it satisfies lifecycle version 1 and uses
|
|
328
|
+
only the portable broker surface. Portability covers callback order and canonical strategy intent.
|
|
329
|
+
It does not make venue fills, latency, data subscriptions, risk decisions, or account state equal.
|
|
330
|
+
|
|
331
|
+
```python
|
|
332
|
+
from ml4t.backtest import Strategy
|
|
333
|
+
|
|
334
|
+
class MyStrategy(Strategy):
|
|
335
|
+
def on_data(self, timestamp, data, context, broker):
|
|
336
|
+
# Portable decision logic; execution outcomes remain runtime-specific.
|
|
337
|
+
pass
|
|
338
|
+
|
|
339
|
+
# Backtest
|
|
340
|
+
from ml4t.backtest import Engine
|
|
341
|
+
result = Engine(feed, MyStrategy(), config).run()
|
|
342
|
+
|
|
343
|
+
# Live
|
|
344
|
+
from ml4t.live import LiveEngine
|
|
345
|
+
await LiveEngine(MyStrategy(), safe_broker, live_feed).run()
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
See the [portability contract](docs/user-guide/backtest-to-live.md) and
|
|
349
|
+
[migration guide](docs/user-guide/migration.md) before moving an existing strategy.
|
|
350
|
+
|
|
351
|
+
## Documentation
|
|
352
|
+
|
|
353
|
+
- [Installation](docs/getting-started/installation.md) - setup instructions
|
|
354
|
+
- [Quick Start](docs/getting-started/quickstart.md) - first live strategy
|
|
355
|
+
- [Brokers](docs/user-guide/brokers.md) - IB and Alpaca setup
|
|
356
|
+
- [Data Feeds](docs/user-guide/feeds.md) - supported and experimental feed contracts
|
|
357
|
+
- [Risk Management](docs/user-guide/risk.md) - LiveRiskConfig and SafeBroker
|
|
358
|
+
- [Candidate Qualification](docs/qualification.md) - validate an exact candidate without release
|
|
359
|
+
|
|
360
|
+
## Stable Support Boundary
|
|
361
|
+
|
|
362
|
+
The stable candidate supports Linux with Python 3.12, 3.13, and 3.14. CI, wheel, and source
|
|
363
|
+
distribution qualification cover those interpreter versions. Windows, macOS, and Python 3.15 are
|
|
364
|
+
not part of this stable contract. IB and Alpaca broker adapters and the OKX feed are supported only
|
|
365
|
+
within the documented capabilities, reconciliation, causal-event, overload, and paper-account
|
|
366
|
+
boundaries. Alpaca, IB, DataBento, and generic CCXT feeds require explicit experimental opt-in.
|
|
367
|
+
|
|
368
|
+
## Technical Characteristics
|
|
369
|
+
|
|
370
|
+
- **Versioned lifecycle**: `on_start`, `on_prepare`, `on_data`, and `on_end` follow the
|
|
371
|
+
negotiated shared lifecycle contract
|
|
372
|
+
- **Async/sync bridge**: All synchronous strategy callbacks run on one dedicated worker thread;
|
|
373
|
+
broker I/O stays on the async event loop without event-loop re-entry
|
|
374
|
+
- **Exception behavior**: Strategy exceptions abort the run, invoke `on_end` once after a
|
|
375
|
+
successful run start, and are reraised after cleanup
|
|
376
|
+
- **Protocol-based**: `BrokerProtocol`, `AsyncBrokerProtocol`, `DataFeedProtocol` for extensibility
|
|
377
|
+
- **Virtual portfolio**: Shadow mode tracks positions without broker interaction
|
|
378
|
+
- **Atomic state**: Risk state persisted via POSIX-atomic file writes (crash-safe)
|
|
379
|
+
- **Rate limiting**: Built-in protection against order flooding
|
|
380
|
+
- **Type-safe**: Full type annotations throughout
|
|
381
|
+
|
|
382
|
+
## Related Libraries
|
|
383
|
+
|
|
384
|
+
- **ml4t-data**: Market data acquisition and storage
|
|
385
|
+
- **ml4t-engineer**: Feature engineering and technical indicators
|
|
386
|
+
- **ml4t-diagnostic**: Signal evaluation and statistical validation
|
|
387
|
+
- **ml4t-backtest**: Event-driven backtesting
|
|
388
|
+
|
|
389
|
+
## Development
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
git clone https://github.com/ml4t/live.git
|
|
393
|
+
cd ml4t-live
|
|
394
|
+
uv sync --all-extras --dev
|
|
395
|
+
uv run python scripts/qualification/run_stable_gate.py
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Safety Notice
|
|
399
|
+
|
|
400
|
+
This library is designed for paper trading and educational purposes. When transitioning to live trading:
|
|
401
|
+
|
|
402
|
+
- Always start with `execution_mode="shadow"`
|
|
403
|
+
- Set conservative position and order limits
|
|
404
|
+
- Enable `kill_switch_enabled=True` with a reasonable `max_drawdown_pct`
|
|
405
|
+
- Monitor virtual vs real positions carefully
|
|
406
|
+
- Use the deployment progression above
|
|
407
|
+
|
|
408
|
+
## License
|
|
409
|
+
|
|
410
|
+
MIT License - see [LICENSE](LICENSE) for details.
|