API Reference¶
Auto-generated from source docstrings.
Core¶
Engine
¶
Engine(
feed,
strategy,
config=None,
*,
contract_specs=None,
market_impact_model=None,
execution_limits=None,
)
Event-driven backtesting engine.
The Engine orchestrates the backtest by iterating through market data, managing the broker, and calling the strategy on each bar.
Execution Flow
- Initialize strategy (on_start)
- For each bar: a. Update broker with current prices b. Process pending exits (NEXT_BAR_OPEN mode) c. Evaluate position rules (stops, trails) d. Process pending orders e. Call strategy.on_data() f. Process new orders (SAME_BAR mode) g. Update water marks h. Record equity
- Close open positions
- Finalize strategy (on_end)
Attributes:
| Name | Type | Description |
|---|---|---|
feed |
DataFeed providing price and signal data |
|
strategy |
Strategy implementing trading logic |
|
broker |
Broker handling order execution and positions |
|
config |
BacktestConfig with all behavioral settings |
|
equity_curve |
list[tuple[datetime, float]]
|
List of (timestamp, equity) tuples |
Example
from ml4t.backtest import Engine, DataFeed, Strategy, BacktestConfig
class MyStrategy(Strategy): ... def on_data(self, timestamp, data, context, broker): ... for asset, bar in data.items(): ... if bar.get('signal', 0) > 0.5: ... broker.submit_order(asset, 100)
feed = DataFeed(prices_df=df) engine = Engine(feed=feed, strategy=MyStrategy()) result = engine.run() print(result['total_return'])
Source code in src/ml4t/backtest/engine.py
run
¶
Run backtest and return structured results.
Returns:
| Type | Description |
|---|---|
BacktestResult
|
BacktestResult with trades, equity curve, metrics, and export methods. |
BacktestResult
|
Call .to_dict() for backward-compatible dictionary output. |
Source code in src/ml4t/backtest/engine.py
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
run_dict
¶
Run backtest and return dictionary (backward compatible).
This is equivalent to run().to_dict() but more explicit for code that requires dictionary output.
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with metrics, trades, and equity curve. |
Source code in src/ml4t/backtest/engine.py
from_config
classmethod
¶
from_config(
feed,
strategy,
config,
*,
contract_specs=None,
market_impact_model=None,
execution_limits=None,
)
Create an Engine instance from a BacktestConfig.
Equivalent to Engine(feed, strategy, config). Kept as a convenience
for code that reads more clearly with a named constructor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feed
|
DataFeed
|
DataFeed with price data |
required |
strategy
|
Strategy
|
Strategy to execute |
required |
config
|
BacktestConfig
|
BacktestConfig with all behavioral settings |
required |
contract_specs
|
dict[str, Any] | None
|
Per-asset contract specifications (futures multipliers, etc.) |
None
|
market_impact_model
|
Any | None
|
Market impact model for fill simulation |
None
|
execution_limits
|
Any | None
|
Execution limits (max order size, etc.) |
None
|
Returns:
| Type | Description |
|---|---|
Engine
|
Configured Engine instance |
Source code in src/ml4t/backtest/engine.py
run_backtest
¶
run_backtest(
prices,
strategy,
signals=None,
context=None,
config=None,
*,
feed_spec=None,
contract=None,
contract_specs=None,
market_impact_model=None,
execution_limits=None,
)
Run a backtest with minimal setup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prices
|
DataFrame | str
|
Price DataFrame or path to parquet file |
required |
strategy
|
Strategy
|
Strategy instance to execute |
required |
signals
|
DataFrame | str | None
|
Optional signals DataFrame or path |
None
|
context
|
DataFrame | str | None
|
Optional context DataFrame or path |
None
|
config
|
BacktestConfig | str | None
|
BacktestConfig instance, preset name (str), or None for defaults |
None
|
feed_spec
|
Any | None
|
Optional shared dataset contract for schema and temporal metadata |
None
|
contract
|
Any | None
|
Alias for feed_spec |
None
|
contract_specs
|
dict[str, Any] | None
|
Per-asset contract specifications (futures multipliers, etc.) |
None
|
market_impact_model
|
Any | None
|
Market impact model for fill simulation |
None
|
execution_limits
|
Any | None
|
Execution limits (max order size, etc.) |
None
|
Returns:
| Type | Description |
|---|---|
BacktestResult
|
BacktestResult with metrics, trades, equity curve, and export methods. |
Example
Using config preset¶
result = run_backtest(prices_df, strategy, config="backtrader") print(result.metrics["sharpe"])
Using custom config¶
config = BacktestConfig.from_preset("backtrader") config.commission_rate = 0.002 result = run_backtest(prices_df, strategy, config=config)
Futures with contract specs¶
from ml4t.backtest import ContractSpec, AssetClass specs = {"ES": ContractSpec(symbol="ES", asset_class=AssetClass.FUTURE, multiplier=50.0)} result = run_backtest(prices_df, strategy, config=config, contract_specs=specs)
Source code in src/ml4t/backtest/engine.py
Strategy
¶
DataFeed
¶
DataFeed(
prices_path=None,
signals_path=None,
context_path=None,
prices_df=None,
signals_df=None,
context_df=None,
*,
feed_spec=None,
contract=None,
entity_col=None,
timestamp_col=None,
price_col=None,
open_col=None,
high_col=None,
low_col=None,
close_col=None,
volume_col=None,
bid_col=None,
ask_col=None,
mid_col=None,
bid_size_col=None,
ask_size_col=None,
)
Polars-based multi-asset data feed with signals and context.
Pre-partitions data by timestamp at initialization for O(1) lookups during iteration. DataFrames are stored in their native format and converted to dicts only at iteration time, reducing memory usage ~10x for large datasets.
Memory Efficiency
- 1M bars: ~100 MB (was ~1 GB with pre-converted dicts)
- 10M bars: ~1 GB (vs ~10+ GB with dicts)
Usage
feed = DataFeed(prices_df=prices, signals_df=signals) for timestamp, assets_data, context in feed: # assets_data: {"AAPL": {"close": 150.0, "signals": {...}}, ...} process(timestamp, assets_data)
Source code in src/ml4t/backtest/datafeed.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | |
Configuration¶
BacktestConfig
dataclass
¶
BacktestConfig(
allow_short_selling=False,
allow_leverage=False,
initial_margin=0.5,
long_maintenance_margin=0.25,
short_maintenance_margin=0.3,
fixed_margin_schedule=None,
short_cash_policy=CREDIT,
execution_price=OPEN,
mark_price=PRICE,
execution_mode=NEXT_BAR,
stop_fill_mode=STOP_PRICE,
stop_level_basis=FILL_PRICE,
trail_hwm_source=CLOSE,
initial_hwm_source=FILL_PRICE,
trail_stop_timing=LAGGED,
share_type=FRACTIONAL,
commission_type=PERCENTAGE,
commission_rate=0.001,
commission_per_share=0.0,
commission_per_trade=0.0,
commission_minimum=0.0,
slippage_type=PERCENTAGE,
slippage_rate=0.001,
slippage_fixed=0.0,
stop_slippage_rate=0.0,
initial_cash=100000.0,
cash_buffer_pct=0.0,
settlement_delay=0,
settlement_reduces_buying_power=True,
reject_on_insufficient_cash=True,
skip_cash_validation=False,
partial_fills_allowed=False,
fill_ordering=EXIT_FIRST,
entry_order_priority=SUBMISSION,
next_bar_submission_precheck=False,
next_bar_simple_cash_check=False,
buying_power_reservation=False,
next_bar_queue_shadow_validation=False,
immediate_fill=False,
rebalance_mode=INCREMENTAL,
rebalance_headroom_pct=1.0,
missing_price_policy=SKIP,
late_asset_policy=ALLOW,
late_asset_min_bars=1,
calendar=None,
timezone="UTC",
data_frequency=DAILY,
enforce_sessions=False,
preset_name=None,
feed_spec=None,
metadata=dict(),
)
Complete configuration for backtesting behavior.
All behavioral differences between frameworks are captured here. Load presets to match specific frameworks exactly.
This is the single source of truth for all backtest settings. Broker and Engine are configured entirely from this dataclass.
from_preset
classmethod
¶
Load a predefined configuration preset.
Available presets: - "default": Sensible defaults for general use - "backtrader": Match Backtrader's default behavior - "vectorbt": Match VectorBT's default behavior - "zipline": Match Zipline's default behavior - "lean": Match QuantConnect LEAN's default behavior - "realistic": Conservative settings for realistic simulation
Source code in src/ml4t/backtest/config.py
from_yaml
classmethod
¶
Load config from YAML file.
Source code in src/ml4t/backtest/config.py
from_dict
classmethod
¶
Create config from dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict
|
Nested config dictionary |
required |
preset_name
|
str | None
|
Optional metadata label |
None
|
strict
|
bool
|
If True, reject unknown sections/keys |
True
|
Source code in src/ml4t/backtest/config.py
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 | |
to_yaml
¶
to_dict
¶
Convert config to dictionary for serialization.
Source code in src/ml4t/backtest/config.py
validate
¶
Validate configuration and return warnings for edge cases.
Checks for configurations that may produce unexpected results or indicate potential issues. Returns a list of warning messages.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
warn
|
bool
|
If True, emit warnings via warnings.warn(). Default True. |
True
|
Returns:
| Type | Description |
|---|---|
list[str]
|
List of warning message strings (empty if no issues found). |
Example
config = BacktestConfig(execution_mode=ExecutionMode.SAME_BAR) warnings = config.validate()
["SAME_BAR execution has look-ahead bias risk..."]¶
Source code in src/ml4t/backtest/config.py
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | |
describe
¶
Return human-readable description of configuration.
Source code in src/ml4t/backtest/config.py
961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | |
profiles
¶
Centralized profile definitions for framework-aligned behavior.
get_profile_config
¶
Return a deep copy of nested config data for the named profile.
Source code in src/ml4t/backtest/profiles.py
Broker¶
Broker
¶
Broker(
initial_cash=100000.0,
commission_model=None,
slippage_model=None,
stop_slippage_rate=0.0,
execution_mode=SAME_BAR,
execution_price=CLOSE,
mark_price=PRICE,
stop_fill_mode=STOP_PRICE,
stop_level_basis=FILL_PRICE,
trail_hwm_source=CLOSE,
initial_hwm_source=FILL_PRICE,
trail_stop_timing=LAGGED,
allow_short_selling=False,
allow_leverage=False,
initial_margin=0.5,
long_maintenance_margin=0.25,
short_maintenance_margin=0.3,
fixed_margin_schedule=None,
short_cash_policy=CREDIT,
execution_limits=None,
market_impact_model=None,
contract_specs=None,
share_type=FRACTIONAL,
fill_ordering=EXIT_FIRST,
entry_order_priority=SUBMISSION,
next_bar_submission_precheck=False,
next_bar_simple_cash_check=False,
buying_power_reservation=False,
next_bar_queue_shadow_validation=False,
immediate_fill=False,
reject_on_insufficient_cash=True,
skip_cash_validation=False,
cash_buffer_pct=0.0,
partial_fills_allowed=False,
rebalance_headroom_pct=1.0,
missing_price_policy=SKIP,
late_asset_policy=ALLOW,
late_asset_min_bars=1,
settlement_delay=0,
settlement_reduces_buying_power=True,
)
Broker interface - same for backtest and live trading.
Source code in src/ml4t/backtest/broker.py
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | |
submit_order
¶
submit_order(
asset,
quantity,
side=None,
order_type=MARKET,
limit_price=None,
stop_price=None,
trail_amount=None,
_options=None,
)
Submit a new order to the broker.
Creates and queues an order for execution. Orders are validated by the Gatekeeper before fills to ensure account constraints are met.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset
|
str
|
Asset symbol (e.g., "AAPL", "BTC-USD") |
required |
quantity
|
float
|
Number of shares/units. Positive = buy, negative = sell (if side is not specified) |
required |
side
|
OrderSide | None
|
OrderSide.BUY or OrderSide.SELL. If None, inferred from quantity sign |
None
|
order_type
|
OrderType
|
Order type (MARKET, LIMIT, STOP, TRAILING_STOP) |
MARKET
|
limit_price
|
float | None
|
Limit price for LIMIT orders |
None
|
stop_price
|
float | None
|
Stop/trigger price for STOP orders |
None
|
trail_amount
|
float | None
|
Trail distance for TRAILING_STOP orders |
None
|
Returns:
| Type | Description |
|---|---|
Order | None
|
Order object if submitted successfully, None if rejected |
Order | None
|
(e.g., same-bar re-entry after stop exit in VBT Pro mode) |
Examples:
Market buy¶
order = broker.submit_order("AAPL", 100)
Market sell (using negative quantity)¶
order = broker.submit_order("AAPL", -100)
Limit buy¶
order = broker.submit_order("AAPL", 100, order_type=OrderType.LIMIT, limit_price=150.0)
Stop sell (stop-loss)¶
order = broker.submit_order("AAPL", -100, order_type=OrderType.STOP, stop_price=145.0)
Source code in src/ml4t/backtest/broker.py
submit_bracket
¶
submit_bracket(
asset,
quantity,
take_profit,
stop_loss,
entry_type=MARKET,
entry_limit=None,
validate_prices=True,
)
Submit entry with take-profit and stop-loss.
Creates a bracket order with entry, take-profit limit, and stop-loss orders. The exit side is automatically determined from the entry direction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset
|
str
|
Asset symbol to trade |
required |
quantity
|
float
|
Position size (positive for long, negative for short) |
required |
take_profit
|
float
|
Take-profit price level (LIMIT order) |
required |
stop_loss
|
float
|
Stop-loss price level (STOP order) |
required |
entry_type
|
OrderType
|
Entry order type (default MARKET) |
MARKET
|
entry_limit
|
float | None
|
Entry limit price (if entry_type is LIMIT) |
None
|
validate_prices
|
bool
|
If True, validate that TP/SL prices are sensible for the position direction (default True) |
True
|
Returns:
| Type | Description |
|---|---|
tuple[Order, Order, Order] | None
|
Tuple of (entry_order, take_profit_order, stop_loss_order) or None if any fails. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If validate_prices=True and prices are inverted for direction. |
Notes
For LONG entries (quantity > 0): - take_profit should be > reference_price (profit on up move) - stop_loss should be < reference_price (exit on down move)
For SHORT entries (quantity < 0): - take_profit should be < reference_price (profit on down move) - stop_loss should be > reference_price (exit on up move)
Reference price is entry_limit (if LIMIT order) or current market price.
Source code in src/ml4t/backtest/broker.py
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 | |
close_position
¶
Close an open position for the given asset.
Submits a market order to fully close the position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset
|
str
|
Asset symbol to close |
required |
Returns:
| Type | Description |
|---|---|
Order | None
|
Order object if position exists and order submitted, None otherwise |
Source code in src/ml4t/backtest/broker.py
cancel_order
¶
get_position
¶
Get the current position for an asset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset
|
str
|
Asset symbol |
required |
Returns:
| Type | Description |
|---|---|
Position | None
|
Position object if position exists, None otherwise |
Source code in src/ml4t/backtest/broker.py
get_positions
¶
Get all current positions.
Returns:
| Type | Description |
|---|---|
dict[str, Position]
|
Dictionary mapping asset symbols to Position objects |
get_cash
¶
Get current cash balance.
Returns:
| Type | Description |
|---|---|
float
|
Current cash balance (can be negative for margin accounts) |
get_account_value
¶
get_rejected_orders
¶
Get all rejected orders, optionally filtered by asset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
asset
|
str | None
|
If provided, filter to only this asset's rejected orders |
None
|
Returns:
| Type | Description |
|---|---|
list[Order]
|
List of rejected Order objects with rejection_reason populated |
Source code in src/ml4t/backtest/broker.py
set_position_rules
¶
Set position rules globally or per-asset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rules
|
PositionRule
|
PositionRule or RuleChain to apply |
required |
asset
|
str | None
|
If provided, apply only to this asset; otherwise global |
None
|
Source code in src/ml4t/backtest/broker.py
rebalance_to_weights
¶
Rebalance portfolio to target weights.
Calculates orders needed to achieve target portfolio allocation. Processes sells before buys to free up capital.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target_weights
|
dict[str, float]
|
Dict of {asset: weight} where weights are decimals (0.10 = 10%). Weights should sum to <= 1.0. |
required |
order_type
|
OrderType
|
Order type for all orders (default MARKET) |
MARKET
|
Returns:
| Type | Description |
|---|---|
list[Order]
|
List of submitted orders (may include None for rejected orders) |
Example
Equal weight three stocks¶
broker.rebalance_to_weights({ "AAPL": 0.33, "GOOGL": 0.33, "MSFT": 0.34, })
Source code in src/ml4t/backtest/broker.py
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 | |
Domain Types¶
Order
dataclass
¶
Order(
asset,
side,
quantity,
order_type=MARKET,
limit_price=None,
stop_price=None,
trail_amount=None,
parent_id=None,
rebalance_id=None,
order_id="",
status=PENDING,
created_at=None,
filled_at=None,
filled_price=None,
filled_quantity=0.0,
rejection_reason=None,
_created_bar_index=0,
_signal_price=None,
_risk_exit_reason=None,
_exit_reason=None,
_risk_fill_price=None,
)
Fill
dataclass
¶
Fill(
order_id,
asset,
side,
quantity,
price,
timestamp,
rebalance_id=None,
commission=0.0,
slippage=0.0,
order_type="",
limit_price=None,
stop_price=None,
price_source="",
reference_price=None,
quote_mid_price=None,
bid_price=None,
ask_price=None,
spread=None,
bid_size=None,
ask_size=None,
available_size=None,
)
Trade
dataclass
¶
Trade(
symbol,
entry_time,
exit_time,
entry_price,
exit_price,
quantity,
pnl,
pnl_percent,
bars_held,
fees=0.0,
exit_slippage=0.0,
exit_reason="signal",
status="closed",
mfe=0.0,
mae=0.0,
entry_slippage=0.0,
multiplier=1.0,
entry_quote_mid_price=None,
entry_bid_price=None,
entry_ask_price=None,
entry_spread=None,
entry_available_size=None,
exit_quote_mid_price=None,
exit_bid_price=None,
exit_ask_price=None,
exit_spread=None,
exit_available_size=None,
metadata=None,
)
Round-trip trade (closed or open).
This dataclass is part of the cross-library API specification, designed to produce identical Parquet output across Python, Numba, and Rust implementations.
For open trades (status="open"), exit_time and exit_price represent mark-to-market values at the end of the backtest period.
Schema Alignment (v0.1.0a6): - symbol: Asset identifier (was 'asset' in earlier versions) - fees: Total transaction fees (was 'commission') - mfe/mae: Max favorable/adverse excursion (was 'max_favorable_excursion'/'max_adverse_excursion') - direction: Derived property from quantity sign
Position
dataclass
¶
Position(
asset,
quantity,
entry_price,
entry_time,
current_price=None,
bars_held=0,
high_water_mark=None,
low_water_mark=None,
max_favorable_excursion=0.0,
max_adverse_excursion=0.0,
initial_quantity=None,
context=dict(),
multiplier=1.0,
entry_commission=0.0,
entry_slippage=0.0,
)
Unified position tracking for strategy and accounting.
Supports both long and short positions with: - Weighted average cost basis tracking - Mark-to-market price tracking - Risk metrics (MFE/MAE, water marks) - Contract multipliers for futures
Attributes:
| Name | Type | Description |
|---|---|---|
asset |
str
|
Asset identifier (e.g., "AAPL", "ES") |
quantity |
float
|
Position size (positive=long, negative=short) |
entry_price |
float
|
Weighted average entry price (cost basis) |
entry_time |
datetime
|
Timestamp when position was first opened |
current_price |
float | None
|
Latest mark-to-market price (updated each bar) |
bars_held |
int
|
Number of bars this position has been held |
Examples:
Long position: Position("AAPL", 100, 150.0, datetime.now()) -> quantity=100, unrealized_pnl depends on current_price
Short position: Position("AAPL", -100, 150.0, datetime.now()) -> quantity=-100, profit if price drops
market_value
property
¶
Current market value of the position.
For long positions: positive value (asset on balance sheet) For short positions: negative value (liability on balance sheet)
Returns:
| Type | Description |
|---|---|
float
|
Market value = quantity × current_price |
unrealized_pnl
¶
Calculate unrealized P&L including contract multiplier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_price
|
float | None
|
Price to calculate P&L at. If None, uses self.current_price. |
None
|
Returns:
| Type | Description |
|---|---|
float
|
Unrealized P&L = (current_price - entry_price) × quantity × multiplier |
Source code in src/ml4t/backtest/types.py
pnl_percent
¶
Calculate direction-aware percentage return on position.
For long positions: (price - entry) / entry For short positions: (entry - price) / entry
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_price
|
float | None
|
Price to calculate return at. If None, uses self.current_price. |
None
|
Source code in src/ml4t/backtest/types.py
notional_value
¶
Calculate notional value of position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_price
|
float | None
|
Price to calculate value at. If None, uses self.current_price. |
None
|
Source code in src/ml4t/backtest/types.py
update_water_marks
¶
update_water_marks(
current_price,
bar_high=None,
bar_low=None,
use_high_for_hwm=False,
use_low_for_lwm=False,
)
Update high/low water marks and excursion tracking.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_price
|
float
|
Current bar's close price |
required |
bar_high
|
float | None
|
Bar's high price (used for HWM if use_high_for_hwm=True) |
None
|
bar_low
|
float | None
|
Bar's low price (used for LWM if use_low_for_lwm=True) |
None
|
use_high_for_hwm
|
bool
|
If True, use bar_high for HWM (VBT Pro OHLC mode). If False, use current_price (close) for HWM (default). |
False
|
use_low_for_lwm
|
bool
|
If True, use bar_low for LWM (VBT Pro OHLC mode). If False, use current_price (close) for LWM (default). |
False
|
Source code in src/ml4t/backtest/types.py
__repr__
¶
String representation for debugging.
Source code in src/ml4t/backtest/types.py
Enums¶
OrderType
¶
Bases: Enum
OrderSide
¶
Bases: Enum
ExecutionMode
¶
Bases: str, Enum
Order execution timing mode.
StopFillMode
¶
Bases: str, Enum
Stop/take-profit fill price mode.
Different frameworks handle stop order fills differently: - STOP_PRICE: Fill at exact stop/target price (standard model, default) Matches VectorBT Pro with OHLC and Backtrader behavior - CLOSE_PRICE: Fill at bar's close price when stop triggers Matches VectorBT Pro with close-only data - BAR_EXTREME: Fill at bar's low (stop-loss) or high (take-profit) Worst/best case model (conservative/optimistic) - NEXT_BAR_OPEN: Fill at next bar's open price when stop triggers Matches Zipline behavior (strategy-level stops)
CommissionType
¶
Bases: str, Enum
Commission calculation method.
SlippageType
¶
Bases: str, Enum
Slippage calculation method.
FillOrdering
¶
Bases: str, Enum
Order processing sequence within a single bar.
Controls how pending orders are sequenced during fill processing:
EXIT_FIRST (default):
All exits → mark-to-market → all entries (with gatekeeper validation).
Capital-efficient: exits free cash before entries need it.
Matches VectorBT call_seq='auto' behavior.
FIFO
Orders process in submission order with sequential cash updates. Each order's gatekeeper check sees cash from all prior fills. Matches Backtrader's submission-order processing.
SEQUENTIAL
Orders process in submission order (typically alphabetical by asset) without exit/entry separation. Cash updates after each individual fill. Unlike EXIT_FIRST, exits do not pre-free cash for later entries. Matches LEAN's per-order sequential buying-power model.
Results¶
BacktestResult
dataclass
¶
BacktestResult(
trades,
equity_curve,
fills,
metrics,
predictions=None,
config=None,
equity=None,
trade_analyzer=None,
portfolio_state=list(),
_trades_df=None,
_equity_df=None,
_fills_df=None,
_portfolio_state_df=None,
)
Structured backtest result with export capabilities.
This class wraps the raw output from Engine.run() and provides: - DataFrame conversion methods (trades, equity, daily P&L) - Parquet export/import for persistence - Integration with ml4t.diagnostic library - Backward-compatible dict export
Attributes:
| Name | Type | Description |
|---|---|---|
trades |
list[Trade]
|
List of completed Trade objects |
equity_curve |
list[tuple[datetime, float]]
|
List of (timestamp, portfolio_value) tuples |
fills |
list[Fill]
|
List of Fill objects (all order fills) |
predictions |
DataFrame | None
|
Raw prediction DataFrame passed into the backtest (optional) |
metrics |
dict[str, Any]
|
Dictionary of computed performance metrics |
config |
BacktestConfig | None
|
BacktestConfig used for the backtest (optional) |
equity |
EquityCurve | None
|
EquityCurve analytics object |
trade_analyzer |
TradeAnalyzer | None
|
TradeAnalyzer analytics object |
to_fills_dataframe
¶
Convert fills to Polars DataFrame.
Source code in src/ml4t/backtest/result.py
to_portfolio_state_dataframe
¶
Convert portfolio state snapshots to Polars DataFrame.
Returns DataFrame with columns
timestamp, equity, cash, gross_exposure, net_exposure, open_positions
Returns:
| Type | Description |
|---|---|
DataFrame
|
Polars DataFrame with one row per bar, sorted by timestamp |
Source code in src/ml4t/backtest/result.py
to_predictions_dataframe
¶
Return the raw prediction DataFrame used as backtest input.
to_trades_dataframe
¶
Convert trades to Polars DataFrame.
Returns DataFrame with columns
symbol, entry_time, exit_time, entry_price, exit_price, quantity, direction, pnl, pnl_percent, bars_held, fees, exit_slippage, mfe, mae, entry_slippage, multiplier, gross_pnl, net_return, total_slippage_cost, cost_drag, exit_reason, status
Cost decomposition columns
gross_pnl: Price-move P&L before fees net_return: Direction-aware net return including fees total_slippage_cost: Entry + exit slippage in dollars cost_drag: Total cost as fraction of notional
The status column indicates "closed" (actually exited) or "open" (mark-to-market at end of backtest).
Returns:
| Type | Description |
|---|---|
DataFrame
|
Polars DataFrame with one row per trade |
Source code in src/ml4t/backtest/result.py
to_equity_dataframe
¶
Convert equity curve to Polars DataFrame.
Returns DataFrame with columns
timestamp, equity, return, cumulative_return, drawdown, high_water_mark
Returns:
| Type | Description |
|---|---|
DataFrame
|
Polars DataFrame with one row per bar, sorted by timestamp |
Source code in src/ml4t/backtest/result.py
to_dict
¶
Export as dictionary (backward compatible with Engine.run()).
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Dictionary with all metrics and raw data |
Source code in src/ml4t/backtest/result.py
to_parquet
¶
Export backtest result to Parquet files.
Creates directory structure
{path}/ trades.parquet fills.parquet predictions.parquet equity.parquet portfolio_state.parquet daily_pnl.parquet metrics.json config.yaml (if config available) spec.yaml (if config available)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Directory path to write files |
required |
include
|
list[str] | None
|
Components to include. Default: all. Options: ["trades", "fills", "predictions", "equity", "portfolio_state", "daily_pnl", "metrics", "config"] |
None
|
compression
|
Literal['lz4', 'uncompressed', 'snappy', 'gzip', 'brotli', 'zstd']
|
Parquet compression codec (default: "zstd") |
'zstd'
|
Returns:
| Type | Description |
|---|---|
dict[str, Path]
|
Dict mapping component names to file paths |
Source code in src/ml4t/backtest/result.py
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | |
Execution: Market Impact¶
LinearImpact
dataclass
¶
Bases: MarketImpactModel
Linear market impact model.
Impact = coefficient * (quantity / volume) * price
Simple model where impact scales linearly with participation rate. Appropriate for liquid markets with moderate order sizes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coefficient
|
float
|
Impact scaling factor (default 0.1) Higher values = more impact per unit participation |
0.1
|
permanent_fraction
|
float
|
Fraction of impact that is permanent (0-1) Remainder is temporary and reverts |
0.5
|
calculate
¶
Calculate linear impact.
Source code in src/ml4t/backtest/execution/impact.py
SquareRootImpact
dataclass
¶
Bases: MarketImpactModel
Square root market impact model (Almgren-Chriss style).
Impact = coefficient * sigma * sqrt(quantity / ADV) * price
Based on academic market microstructure research. Impact scales with the square root of order size, which matches empirical observations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coefficient
|
float
|
Scaling factor (default 0.5, typical range 0.1-1.0) |
0.5
|
volatility
|
float
|
Daily volatility (sigma, default 0.02 = 2%) |
0.02
|
adv_factor
|
float
|
Average daily volume as multiple of bar volume (default 1.0 for daily bars, 390 for minute bars) |
1.0
|
Example
model = SquareRootImpact(coefficient=0.5, volatility=0.02)
For order = 1% of ADV at 2% vol, $100 price:¶
Impact = 0.5 * 0.02 * sqrt(0.01) * 100 = $0.10¶
calculate
¶
Calculate square root impact.
Source code in src/ml4t/backtest/execution/impact.py
PowerLawImpact
dataclass
¶
Bases: MarketImpactModel
Generalized power law impact model.
Impact = coefficient * (quantity / volume)^exponent * price
Flexible model that can represent various impact regimes. - exponent = 1.0: Linear (like LinearImpact) - exponent = 0.5: Square root (like SquareRootImpact) - exponent < 0.5: Concave (impact flattens for large orders) - exponent > 1.0: Convex (impact accelerates for large orders)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
coefficient
|
float
|
Scaling factor (default 0.1) |
0.1
|
exponent
|
float
|
Power law exponent (default 0.5) |
0.5
|
min_impact
|
float
|
Minimum impact per trade (fixed cost, default 0) |
0.0
|
Example
model = PowerLawImpact(coefficient=0.1, exponent=0.6)
calculate
¶
Calculate power law impact.
Source code in src/ml4t/backtest/execution/impact.py
Risk: Position Rules¶
StopLoss
dataclass
¶
Exit when stop price is breached during the bar.
Stop orders trigger when the bar's price range touches the stop level. Fill price depends on StopFillMode configuration: - STOP_PRICE: Fill at exact stop price (standard model, default) - BAR_EXTREME: Fill at bar's low (matches VectorBT Pro behavior)
For long positions: stop triggers if bar_low <= stop_price For short positions: stop triggers if bar_high >= stop_price
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pct
|
float
|
Maximum loss as decimal (0.05 = 5% loss triggers exit) |
required |
Example
rule = StopLoss(pct=0.05) # Exit at -5%
evaluate
¶
Exit if stop price was breached during the bar.
Source code in src/ml4t/backtest/risk/position/static.py
TakeProfit
dataclass
¶
Exit when target price is reached during the bar.
Take-profit orders trigger when the bar's price range touches the target. Fill price depends on StopFillMode configuration: - STOP_PRICE: Fill at exact target price (standard model, default) - BAR_EXTREME: Fill at bar's high (matches VectorBT Pro behavior)
For long positions: triggers if bar_high >= target_price For short positions: triggers if bar_low <= target_price
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pct
|
float
|
Target profit as decimal (0.10 = 10% profit triggers exit) |
required |
Example
rule = TakeProfit(pct=0.10) # Exit at +10%
evaluate
¶
Exit if target price was reached during the bar.
Source code in src/ml4t/backtest/risk/position/static.py
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | |
TimeExit
dataclass
¶
Exit after holding for a specified number of bars.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_bars
|
int
|
Maximum bars to hold position |
required |
Example
rule = TimeExit(max_bars=20) # Exit after 20 bars
evaluate
¶
Exit if held too long.
Source code in src/ml4t/backtest/risk/position/static.py
TrailingStop
dataclass
¶
Exit when price retraces from high water mark.
For longs: Exit if price drops X% from highest price since entry For shorts: Exit if price rises X% from lowest price since entry
Fill price depends on StopFillMode configuration: - STOP_PRICE: Fill at exact trail level (default) - CLOSE_PRICE: Fill at bar's close price (VBT Pro behavior)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pct
|
float
|
Trail percentage as decimal (0.05 = 5% trail) |
required |
Example
rule = TrailingStop(pct=0.05) # 5% trailing stop
evaluate
¶
Exit if price retraces beyond trail.
Uses bar_low/bar_high for intrabar trigger detection. Handles gap-through: if bar opens beyond stop level, fill at open.
Fill price depends on StopFillMode configuration: - STOP_PRICE: Fill at exact trail level (default) - CLOSE_PRICE: Fill at bar's close price - BAR_EXTREME: Fill at bar's low (long) or high (short)
Water mark timing depends on TrailStopTiming configuration: - LAGGED: Use water mark from PREVIOUS bar (default, 1-bar lag) - INTRABAR: Compute "live" water mark using current bar's extreme, then check. VBT Pro compatible: respects StopFillMode for fill price.
Gap-through handling: When bar opens beyond the stop level (gap down for longs, gap up for shorts), the fill is at the open price regardless of StopFillMode. This matches VBT Pro behavior.
Source code in src/ml4t/backtest/risk/position/dynamic.py
RuleChain
dataclass
¶
Evaluate rules in order, first non-HOLD action wins.
This is the most common composition pattern - rules are checked in priority order and the first rule to trigger takes effect.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rules
|
list[PositionRule]
|
List of rules to evaluate in order |
required |
Example
chain = RuleChain([ StopLoss(pct=0.05), # Highest priority ScaledExit([(0.10, 0.5)]), # Second priority TighteningTrailingStop([...]), # Third priority TimeExit(bars=20), # Lowest priority ])
evaluate
¶
Evaluate rules in order, return first non-HOLD action.
Source code in src/ml4t/backtest/risk/position/composite.py
AllOf
dataclass
¶
All rules must return non-HOLD for the action to trigger.
Useful for requiring multiple conditions to be true before exiting. Returns the first rule's action details (pct, stop_price, etc.).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rules
|
list[PositionRule]
|
List of rules that must all agree |
required |
Example
Exit only if both profitable AND held long enough¶
rule = AllOf([ TakeProfit(pct=0.0), # Must be profitable TimeExit(bars=5), # Must have held 5+ bars ])
evaluate
¶
Return action only if ALL rules return non-HOLD.
Source code in src/ml4t/backtest/risk/position/composite.py
AnyOf
dataclass
¶
First rule to return non-HOLD wins (alias for RuleChain).
Semantically equivalent to RuleChain but named for clarity when composing complex rule logic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rules
|
list[PositionRule]
|
List of rules where any can trigger |
required |
Example
Exit on stop-loss OR signal¶
rule = AnyOf([ StopLoss(pct=0.05), SignalExit(threshold=0.5), ])
evaluate
¶
Return first non-HOLD action (same as RuleChain).
Source code in src/ml4t/backtest/risk/position/composite.py
Risk: Portfolio Limits¶
MaxDrawdownLimit
dataclass
¶
Bases: PortfolioLimit
Halt trading when drawdown exceeds threshold.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_drawdown
|
float
|
Maximum allowed drawdown (0.0-1.0) Default 0.20 = 20% max drawdown |
0.2
|
action
|
str
|
Action when breached ("warn", "reduce", "halt") Default "halt" - stops all new trades |
'halt'
|
warn_threshold
|
float | None
|
Optional earlier threshold for warnings |
None
|
Example
limit = MaxDrawdownLimit(max_drawdown=0.20, warn_threshold=0.15)
Warns at 15% drawdown, halts at 20%¶
MaxPositionsLimit
dataclass
¶
Bases: PortfolioLimit
Limit maximum number of open positions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_positions
|
int
|
Maximum number of simultaneous positions |
10
|
action
|
str
|
Action when breached ("warn", "halt") |
'halt'
|
MaxExposureLimit
dataclass
¶
Bases: PortfolioLimit
Limit maximum exposure to a single asset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_exposure_pct
|
float
|
Maximum position size as % of equity (0.0-1.0) Default 0.10 = 10% max per asset |
0.1
|
action
|
str
|
Action when breached |
'warn'
|
Example
limit = MaxExposureLimit(max_exposure_pct=0.10)
No single position can be > 10% of portfolio¶
DailyLossLimit
dataclass
¶
Bases: PortfolioLimit
Halt trading when daily loss exceeds threshold.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_daily_loss_pct
|
float
|
Maximum daily loss as % of equity (0.0-1.0) Default 0.02 = 2% max daily loss |
0.02
|
action
|
str
|
Action when breached |
'halt'
|
Strategy Templates¶
SignalFollowingStrategy
¶
Bases: Strategy
Template for strategies that follow pre-computed signals.
Use this when you have ML predictions, technical indicators, or any pre-computed signal column in your DataFrame.
Class Attributes
signal_column: Name of the signal column in data (default: "signal") position_size: Fraction of equity per position (default: 0.10) allow_shorts: Whether to allow short positions (default: False)
Example
class MyMLStrategy(SignalFollowingStrategy): ... signal_column = "rf_prediction" ... position_size = 0.05 ... ... def should_enter_long(self, signal): ... return signal > 0.7 ... ... def should_exit(self, signal): ... return signal < 0.3
should_enter_long
abstractmethod
¶
Return True to open a long position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal
|
float
|
Current signal value for the asset |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if should enter long position |
should_exit
abstractmethod
¶
Return True to close current position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal
|
float
|
Current signal value for the asset |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if should exit position |
should_enter_short
¶
Return True to open a short position.
Override this method for short strategies. Default returns False.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
signal
|
float
|
Current signal value for the asset |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if should enter short position |
Source code in src/ml4t/backtest/strategies/templates.py
on_data
¶
Process each bar and generate orders based on signals.
Source code in src/ml4t/backtest/strategies/templates.py
MomentumStrategy
¶
Bases: Strategy
Template for momentum/trend-following strategies.
Enters long when asset has positive momentum over lookback period, exits when momentum turns negative.
Class Attributes
lookback: Number of bars for momentum calculation (default: 20) entry_threshold: Minimum return to enter (default: 0.05 = 5%) exit_threshold: Return level to exit (default: -0.02 = -2%) position_size: Fraction of equity per position (default: 0.10)
Example
class MyMomentum(MomentumStrategy): ... lookback = 60 # 60-day momentum ... entry_threshold = 0.10 # Enter on 10% gain ... exit_threshold = 0.0 # Exit when momentum turns negative
Source code in src/ml4t/backtest/strategies/templates.py
calculate_momentum
¶
Calculate momentum as return over lookback period.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prices
|
list[float]
|
List of prices (most recent last) |
required |
Returns:
| Type | Description |
|---|---|
float
|
Return from first to last price |
Source code in src/ml4t/backtest/strategies/templates.py
on_data
¶
Process each bar and trade based on momentum.
Source code in src/ml4t/backtest/strategies/templates.py
MeanReversionStrategy
¶
Bases: Strategy
Template for mean-reversion strategies.
Buys when price is below moving average by a threshold, sells when price reverts to the mean.
Class Attributes
lookback: Number of bars for mean calculation (default: 20) entry_zscore: Z-score threshold to enter (default: -2.0) exit_zscore: Z-score threshold to exit (default: 0.0) position_size: Fraction of equity per position (default: 0.10)
Example
class MyMeanReversion(MeanReversionStrategy): ... lookback = 30 ... entry_zscore = -2.5 # More extreme entry ... exit_zscore = 0.5 # Take profit above mean
Source code in src/ml4t/backtest/strategies/templates.py
calculate_zscore
¶
Calculate z-score of current price vs historical distribution.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prices
|
list[float]
|
Historical prices |
required |
current
|
float
|
Current price |
required |
Returns:
| Type | Description |
|---|---|
float | None
|
Z-score or None if insufficient data |
Source code in src/ml4t/backtest/strategies/templates.py
on_data
¶
Process each bar and trade based on mean reversion.
Source code in src/ml4t/backtest/strategies/templates.py
LongShortStrategy
¶
Bases: Strategy
Template for long/short equity strategies.
Ranks assets by a signal and goes long top N, short bottom N.
Class Attributes
signal_column: Column to rank assets by (default: "signal") long_count: Number of assets to go long (default: 5) short_count: Number of assets to go short (default: 5) position_size: Fraction of equity per position (default: 0.05) rebalance_frequency: Bars between rebalancing (default: 20)
Example
class MyLongShort(LongShortStrategy): ... signal_column = "momentum_score" ... long_count = 10 ... short_count = 10 ... rebalance_frequency = 21 # Monthly
Source code in src/ml4t/backtest/strategies/templates.py
on_prepare
¶
Resolve optional schedule-based rebalance gating before the run starts.
Source code in src/ml4t/backtest/strategies/templates.py
rank_assets
¶
Rank assets by signal and return long/short lists.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
dict[str, dict]
|
Current bar data for all assets |
required |
Returns:
| Type | Description |
|---|---|
tuple[list[str], list[str]]
|
Tuple of (long_assets, short_assets) |
Source code in src/ml4t/backtest/strategies/templates.py
on_data
¶
Rebalance portfolio periodically based on rankings.