quantbt-engine 1.0.7__py3-none-any.whl
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.
- quantbt/__init__.py +862 -0
- quantbt/adapters/__init__.py +5 -0
- quantbt/adapters/nautilus/__init__.py +42 -0
- quantbt/adapters/nautilus/_dependency.py +53 -0
- quantbt/adapters/nautilus/backend.py +639 -0
- quantbt/adapters/nautilus/instruments.py +275 -0
- quantbt/adapters/nautilus/options.py +465 -0
- quantbt/adapters/nautilus/reports.py +231 -0
- quantbt/backends/__init__.py +29 -0
- quantbt/backends/_native_event_rust.py +2168 -0
- quantbt/backends/native_event.py +5048 -0
- quantbt/backends/native_option.py +796 -0
- quantbt/backends/native_portfolio.py +928 -0
- quantbt/backends/native_vectorized.py +1299 -0
- quantbt/backtester.py +485 -0
- quantbt/benchmarks/__init__.py +1 -0
- quantbt/benchmarks/compare_phase9_parity.py +302 -0
- quantbt/benchmarks/gamma_scalping_backtestsample.py +802 -0
- quantbt/benchmarks/profile_phase7.py +415 -0
- quantbt/benchmarks/run_arbitrage_phase_e.py +160 -0
- quantbt/benchmarks/run_optimization_overhead.py +195 -0
- quantbt/benchmarks/run_options_engine.py +272 -0
- quantbt/benchmarks/run_pct_equity_nautilus_smoke.py +227 -0
- quantbt/benchmarks/run_phase12_arbitrage_cert.py +402 -0
- quantbt/benchmarks/run_phase12_benchmark_nautilus_cert.py +430 -0
- quantbt/benchmarks/run_phase13_portfolio_report.py +97 -0
- quantbt/benchmarks/run_phase13_wfo_cache.py +162 -0
- quantbt/benchmarks/run_phase14_service_loop.py +694 -0
- quantbt/benchmarks/run_phase15a_nautilus_certification.py +514 -0
- quantbt/benchmarks/run_phase15b_synthetic_depth.py +175 -0
- quantbt/benchmarks/run_phase16_performance_debt.py +389 -0
- quantbt/benchmarks/run_phase30e_reactive_runner.py +161 -0
- quantbt/benchmarks/run_phase31_intrabar.py +441 -0
- quantbt/benchmarks/run_phase34a_native_event_memory.py +179 -0
- quantbt/benchmarks/run_phase34b_native_event_prepared_score.py +173 -0
- quantbt/benchmarks/run_phase34c_native_event_single_pass.py +176 -0
- quantbt/benchmarks/run_phase7.py +654 -0
- quantbt/benchmarks/run_portfolio_real_parity.py +537 -0
- quantbt/core/__init__.py +323 -0
- quantbt/core/arbitrage.py +767 -0
- quantbt/core/basket.py +234 -0
- quantbt/core/certification.py +274 -0
- quantbt/core/constraints.py +155 -0
- quantbt/core/engine.py +1144 -0
- quantbt/core/event.py +869 -0
- quantbt/core/execution_contract.py +197 -0
- quantbt/core/execution_depth.py +613 -0
- quantbt/core/intrabar_kernel.py +1906 -0
- quantbt/core/intrabar_reference.py +907 -0
- quantbt/core/intrabar_session.py +156 -0
- quantbt/core/market_tape.py +480 -0
- quantbt/core/native_event_capabilities.py +121 -0
- quantbt/core/native_event_parity.py +336 -0
- quantbt/core/order_compiler.py +422 -0
- quantbt/core/orders.py +319 -0
- quantbt/core/portfolio.py +392 -0
- quantbt/core/preprocessor.py +256 -0
- quantbt/core/reactive.py +173 -0
- quantbt/core/results.py +341 -0
- quantbt/core/schema.py +211 -0
- quantbt/core/scopes.py +96 -0
- quantbt/core/structured_orders.py +378 -0
- quantbt/core/types.py +87 -0
- quantbt/core/vectorized.py +203 -0
- quantbt/endpoint.py +4465 -0
- quantbt/engines.py +1014 -0
- quantbt/metrics/__init__.py +45 -0
- quantbt/metrics/options_analytics.py +46 -0
- quantbt/metrics/performance.py +541 -0
- quantbt/optimization/__init__.py +94 -0
- quantbt/optimization/callbacks.py +116 -0
- quantbt/optimization/candidate_selection.py +397 -0
- quantbt/optimization/config.py +84 -0
- quantbt/optimization/constraints.py +22 -0
- quantbt/optimization/evaluator.py +21 -0
- quantbt/optimization/evaluators/__init__.py +32 -0
- quantbt/optimization/evaluators/arbitrage.py +22 -0
- quantbt/optimization/evaluators/generic.py +34 -0
- quantbt/optimization/evaluators/grid_dca.py +22 -0
- quantbt/optimization/evaluators/intrabar.py +54 -0
- quantbt/optimization/evaluators/native_event.py +51 -0
- quantbt/optimization/evaluators/options.py +22 -0
- quantbt/optimization/evaluators/portfolio.py +42 -0
- quantbt/optimization/evaluators/signal.py +43 -0
- quantbt/optimization/multiseed.py +176 -0
- quantbt/optimization/objectives.py +221 -0
- quantbt/optimization/optimizer.py +500 -0
- quantbt/optimization/result.py +80 -0
- quantbt/optimization/samplers.py +84 -0
- quantbt/optimization/space.py +223 -0
- quantbt/options/__init__.py +215 -0
- quantbt/options/cache.py +116 -0
- quantbt/options/conventions.py +158 -0
- quantbt/options/data.py +177 -0
- quantbt/options/execution.py +600 -0
- quantbt/options/fees.py +135 -0
- quantbt/options/greeks.py +173 -0
- quantbt/options/hedging.py +232 -0
- quantbt/options/iv.py +188 -0
- quantbt/options/ledger.py +263 -0
- quantbt/options/lifecycle.py +94 -0
- quantbt/options/margin.py +311 -0
- quantbt/options/packages.py +147 -0
- quantbt/options/pricing.py +191 -0
- quantbt/options/schema.py +227 -0
- quantbt/options/selectors.py +281 -0
- quantbt/options/strategy.py +249 -0
- quantbt/options/surface.py +142 -0
- quantbt/options/tape.py +226 -0
- quantbt/options/templates/__init__.py +33 -0
- quantbt/options/templates/packages.py +354 -0
- quantbt/portfolio.py +606 -0
- quantbt/py.typed +1 -0
- quantbt/reporting/__init__.py +38 -0
- quantbt/reporting/arbitrage_audit.py +211 -0
- quantbt/reporting/nautilus_bundle.py +758 -0
- quantbt/reporting/nautilus_certification.py +226 -0
- quantbt/reporting/nautilus_diagnostics.py +225 -0
- quantbt/reporting/parity.py +496 -0
- quantbt/reporting/portfolio_audit.py +206 -0
- quantbt/reporting/portfolio_nautilus.py +140 -0
- quantbt/sizing/__init__.py +3 -0
- quantbt/sizing/fast.py +67 -0
- quantbt/sizing/modes.py +162 -0
- quantbt/viz/__init__.py +4 -0
- quantbt/viz/plots.py +310 -0
- quantbt/viz/themes.py +102 -0
- quantbt/walkforward.py +3136 -0
- quantbt_engine-1.0.7.dist-info/METADATA +891 -0
- quantbt_engine-1.0.7.dist-info/RECORD +133 -0
- quantbt_engine-1.0.7.dist-info/WHEEL +5 -0
- quantbt_engine-1.0.7.dist-info/licenses/LICENSE +21 -0
- quantbt_engine-1.0.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Execution contract taxonomy for QuantBT backtest engines.
|
|
3
|
+
|
|
4
|
+
The contract object is deliberately small and serializable. It describes what a
|
|
5
|
+
backend promises to simulate; hot kernels receive integer codes compiled from
|
|
6
|
+
these records in later phases.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from dataclasses import asdict, dataclass
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Dict, Mapping
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SignalPhase(str, Enum):
|
|
17
|
+
BAR_OPEN = "bar_open"
|
|
18
|
+
BAR_CLOSE = "bar_close"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FillPhase(str, Enum):
|
|
22
|
+
SAME_OPEN = "same_open"
|
|
23
|
+
SAME_CLOSE = "same_close"
|
|
24
|
+
NEXT_OPEN = "next_open"
|
|
25
|
+
NEXT_CLOSE = "next_close"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class MarketFillPolicy(str, Enum):
|
|
29
|
+
CLOSE = "close"
|
|
30
|
+
OPEN = "open"
|
|
31
|
+
NEXT_OPEN = "next_open"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class StopGapPolicy(str, Enum):
|
|
35
|
+
OPEN_WORSE_THAN_TRIGGER = "open_worse_than_trigger"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TakeProfitGapPolicy(str, Enum):
|
|
39
|
+
LIMIT_PRICE_CONSERVATIVE = "limit_price_conservative"
|
|
40
|
+
OPEN_PRICE_IMPROVEMENT = "open_price_improvement"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class IntrabarSameBarPolicy(str, Enum):
|
|
44
|
+
CONSERVATIVE = "conservative"
|
|
45
|
+
STOP_FIRST = "stop_first"
|
|
46
|
+
TP_FIRST = "tp_first"
|
|
47
|
+
OHLC_PATH = "ohlc_path"
|
|
48
|
+
OLHC_PATH = "olhc_path"
|
|
49
|
+
REJECT_AMBIGUOUS = "reject_ambiguous"
|
|
50
|
+
LOWER_TIMEFRAME_REQUIRED = "lower_timeframe_required"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TrailingUpdatePhase(str, Enum):
|
|
54
|
+
NONE = "none"
|
|
55
|
+
NEXT_BAR = "next_bar"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class FundingPhase(str, Enum):
|
|
59
|
+
POSITION_AT_EVENT = "position_at_event"
|
|
60
|
+
POSITION_AT_CLOSE = "position_at_close"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class LiquidationPriority(str, Enum):
|
|
64
|
+
LIQUIDATION_FIRST_AT_GAP = "liquidation_first_at_gap"
|
|
65
|
+
USER_STOP_FIRST = "user_stop_first"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class AmbiguityPolicy(str, Enum):
|
|
69
|
+
FLAG_AND_CONSERVATIVE = "flag_and_conservative"
|
|
70
|
+
REJECT = "reject"
|
|
71
|
+
LOWER_TIMEFRAME_REQUIRED = "lower_timeframe_required"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass(frozen=True)
|
|
75
|
+
class ExecutionContract:
|
|
76
|
+
engine_id: str
|
|
77
|
+
signal_phase: SignalPhase
|
|
78
|
+
entry_fill_phase: FillPhase
|
|
79
|
+
market_fill_policy: MarketFillPolicy
|
|
80
|
+
stop_gap_policy: StopGapPolicy = StopGapPolicy.OPEN_WORSE_THAN_TRIGGER
|
|
81
|
+
take_profit_gap_policy: TakeProfitGapPolicy = TakeProfitGapPolicy.LIMIT_PRICE_CONSERVATIVE
|
|
82
|
+
same_bar_policy: IntrabarSameBarPolicy = IntrabarSameBarPolicy.CONSERVATIVE
|
|
83
|
+
trailing_update_phase: TrailingUpdatePhase = TrailingUpdatePhase.NONE
|
|
84
|
+
funding_phase: FundingPhase = FundingPhase.POSITION_AT_EVENT
|
|
85
|
+
liquidation_priority: LiquidationPriority = LiquidationPriority.LIQUIDATION_FIRST_AT_GAP
|
|
86
|
+
close_on_last_bar: bool = True
|
|
87
|
+
ambiguity_policy: AmbiguityPolicy = AmbiguityPolicy.FLAG_AND_CONSERVATIVE
|
|
88
|
+
strict_data: bool = True
|
|
89
|
+
|
|
90
|
+
def __post_init__(self) -> None:
|
|
91
|
+
if not self.engine_id:
|
|
92
|
+
raise ValueError("engine_id is required")
|
|
93
|
+
|
|
94
|
+
@classmethod
|
|
95
|
+
def close_target(cls) -> "ExecutionContract":
|
|
96
|
+
return cls(
|
|
97
|
+
engine_id="close_target_v2",
|
|
98
|
+
signal_phase=SignalPhase.BAR_CLOSE,
|
|
99
|
+
entry_fill_phase=FillPhase.SAME_CLOSE,
|
|
100
|
+
market_fill_policy=MarketFillPolicy.CLOSE,
|
|
101
|
+
trailing_update_phase=TrailingUpdatePhase.NONE,
|
|
102
|
+
close_on_last_bar=False,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def next_open(cls) -> "ExecutionContract":
|
|
107
|
+
return cls(
|
|
108
|
+
engine_id="next_open_v1",
|
|
109
|
+
signal_phase=SignalPhase.BAR_CLOSE,
|
|
110
|
+
entry_fill_phase=FillPhase.NEXT_OPEN,
|
|
111
|
+
market_fill_policy=MarketFillPolicy.NEXT_OPEN,
|
|
112
|
+
trailing_update_phase=TrailingUpdatePhase.NONE,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
@classmethod
|
|
116
|
+
def intrabar_bracket(
|
|
117
|
+
cls,
|
|
118
|
+
*,
|
|
119
|
+
same_bar_policy: IntrabarSameBarPolicy = IntrabarSameBarPolicy.CONSERVATIVE,
|
|
120
|
+
trailing_update_phase: TrailingUpdatePhase = TrailingUpdatePhase.NEXT_BAR,
|
|
121
|
+
take_profit_gap_policy: TakeProfitGapPolicy = TakeProfitGapPolicy.LIMIT_PRICE_CONSERVATIVE,
|
|
122
|
+
close_on_last_bar: bool = True,
|
|
123
|
+
) -> "ExecutionContract":
|
|
124
|
+
return cls(
|
|
125
|
+
engine_id="intrabar_bracket_v1",
|
|
126
|
+
signal_phase=SignalPhase.BAR_CLOSE,
|
|
127
|
+
entry_fill_phase=FillPhase.NEXT_OPEN,
|
|
128
|
+
market_fill_policy=MarketFillPolicy.NEXT_OPEN,
|
|
129
|
+
same_bar_policy=same_bar_policy,
|
|
130
|
+
trailing_update_phase=trailing_update_phase,
|
|
131
|
+
take_profit_gap_policy=take_profit_gap_policy,
|
|
132
|
+
close_on_last_bar=close_on_last_bar,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
@classmethod
|
|
136
|
+
def fill_replay(cls) -> "ExecutionContract":
|
|
137
|
+
return cls(
|
|
138
|
+
engine_id="fill_replay_v1",
|
|
139
|
+
signal_phase=SignalPhase.BAR_CLOSE,
|
|
140
|
+
entry_fill_phase=FillPhase.NEXT_OPEN,
|
|
141
|
+
market_fill_policy=MarketFillPolicy.NEXT_OPEN,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def event_lifecycle(cls) -> "ExecutionContract":
|
|
146
|
+
return cls(
|
|
147
|
+
engine_id="event_lifecycle_v2",
|
|
148
|
+
signal_phase=SignalPhase.BAR_CLOSE,
|
|
149
|
+
entry_fill_phase=FillPhase.NEXT_OPEN,
|
|
150
|
+
market_fill_policy=MarketFillPolicy.NEXT_OPEN,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def to_metadata(self) -> Dict:
|
|
154
|
+
payload = asdict(self)
|
|
155
|
+
for key, value in list(payload.items()):
|
|
156
|
+
if isinstance(value, Enum):
|
|
157
|
+
payload[key] = value.value
|
|
158
|
+
return payload
|
|
159
|
+
|
|
160
|
+
@classmethod
|
|
161
|
+
def from_metadata(cls, metadata: Mapping | "ExecutionContract") -> "ExecutionContract":
|
|
162
|
+
if isinstance(metadata, ExecutionContract):
|
|
163
|
+
return metadata
|
|
164
|
+
payload = dict(metadata or {})
|
|
165
|
+
if not payload:
|
|
166
|
+
raise ValueError("execution contract metadata is empty")
|
|
167
|
+
return cls(
|
|
168
|
+
engine_id=str(payload["engine_id"]),
|
|
169
|
+
signal_phase=SignalPhase(payload["signal_phase"]),
|
|
170
|
+
entry_fill_phase=FillPhase(payload["entry_fill_phase"]),
|
|
171
|
+
market_fill_policy=MarketFillPolicy(payload["market_fill_policy"]),
|
|
172
|
+
stop_gap_policy=StopGapPolicy(payload.get("stop_gap_policy", StopGapPolicy.OPEN_WORSE_THAN_TRIGGER.value)),
|
|
173
|
+
take_profit_gap_policy=TakeProfitGapPolicy(payload.get("take_profit_gap_policy", TakeProfitGapPolicy.LIMIT_PRICE_CONSERVATIVE.value)),
|
|
174
|
+
same_bar_policy=IntrabarSameBarPolicy(payload.get("same_bar_policy", IntrabarSameBarPolicy.CONSERVATIVE.value)),
|
|
175
|
+
trailing_update_phase=TrailingUpdatePhase(payload.get("trailing_update_phase", TrailingUpdatePhase.NONE.value)),
|
|
176
|
+
funding_phase=FundingPhase(payload.get("funding_phase", FundingPhase.POSITION_AT_EVENT.value)),
|
|
177
|
+
liquidation_priority=LiquidationPriority(payload.get("liquidation_priority", LiquidationPriority.LIQUIDATION_FIRST_AT_GAP.value)),
|
|
178
|
+
close_on_last_bar=bool(payload.get("close_on_last_bar", True)),
|
|
179
|
+
ambiguity_policy=AmbiguityPolicy(payload.get("ambiguity_policy", AmbiguityPolicy.FLAG_AND_CONSERVATIVE.value)),
|
|
180
|
+
strict_data=bool(payload.get("strict_data", True)),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
EXECUTION_CONTRACT_REGISTRY: Dict[str, ExecutionContract] = {
|
|
185
|
+
"close_target_v2": ExecutionContract.close_target(),
|
|
186
|
+
"next_open_v1": ExecutionContract.next_open(),
|
|
187
|
+
"intrabar_bracket_v1": ExecutionContract.intrabar_bracket(),
|
|
188
|
+
"fill_replay_v1": ExecutionContract.fill_replay(),
|
|
189
|
+
"event_lifecycle_v2": ExecutionContract.event_lifecycle(),
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_execution_contract(engine_id: str) -> ExecutionContract:
|
|
194
|
+
key = str(engine_id).lower().strip()
|
|
195
|
+
if key not in EXECUTION_CONTRACT_REGISTRY:
|
|
196
|
+
raise KeyError(f"unknown execution contract {engine_id!r}")
|
|
197
|
+
return EXECUTION_CONTRACT_REGISTRY[key]
|