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.
Files changed (133) hide show
  1. quantbt/__init__.py +862 -0
  2. quantbt/adapters/__init__.py +5 -0
  3. quantbt/adapters/nautilus/__init__.py +42 -0
  4. quantbt/adapters/nautilus/_dependency.py +53 -0
  5. quantbt/adapters/nautilus/backend.py +639 -0
  6. quantbt/adapters/nautilus/instruments.py +275 -0
  7. quantbt/adapters/nautilus/options.py +465 -0
  8. quantbt/adapters/nautilus/reports.py +231 -0
  9. quantbt/backends/__init__.py +29 -0
  10. quantbt/backends/_native_event_rust.py +2168 -0
  11. quantbt/backends/native_event.py +5048 -0
  12. quantbt/backends/native_option.py +796 -0
  13. quantbt/backends/native_portfolio.py +928 -0
  14. quantbt/backends/native_vectorized.py +1299 -0
  15. quantbt/backtester.py +485 -0
  16. quantbt/benchmarks/__init__.py +1 -0
  17. quantbt/benchmarks/compare_phase9_parity.py +302 -0
  18. quantbt/benchmarks/gamma_scalping_backtestsample.py +802 -0
  19. quantbt/benchmarks/profile_phase7.py +415 -0
  20. quantbt/benchmarks/run_arbitrage_phase_e.py +160 -0
  21. quantbt/benchmarks/run_optimization_overhead.py +195 -0
  22. quantbt/benchmarks/run_options_engine.py +272 -0
  23. quantbt/benchmarks/run_pct_equity_nautilus_smoke.py +227 -0
  24. quantbt/benchmarks/run_phase12_arbitrage_cert.py +402 -0
  25. quantbt/benchmarks/run_phase12_benchmark_nautilus_cert.py +430 -0
  26. quantbt/benchmarks/run_phase13_portfolio_report.py +97 -0
  27. quantbt/benchmarks/run_phase13_wfo_cache.py +162 -0
  28. quantbt/benchmarks/run_phase14_service_loop.py +694 -0
  29. quantbt/benchmarks/run_phase15a_nautilus_certification.py +514 -0
  30. quantbt/benchmarks/run_phase15b_synthetic_depth.py +175 -0
  31. quantbt/benchmarks/run_phase16_performance_debt.py +389 -0
  32. quantbt/benchmarks/run_phase30e_reactive_runner.py +161 -0
  33. quantbt/benchmarks/run_phase31_intrabar.py +441 -0
  34. quantbt/benchmarks/run_phase34a_native_event_memory.py +179 -0
  35. quantbt/benchmarks/run_phase34b_native_event_prepared_score.py +173 -0
  36. quantbt/benchmarks/run_phase34c_native_event_single_pass.py +176 -0
  37. quantbt/benchmarks/run_phase7.py +654 -0
  38. quantbt/benchmarks/run_portfolio_real_parity.py +537 -0
  39. quantbt/core/__init__.py +323 -0
  40. quantbt/core/arbitrage.py +767 -0
  41. quantbt/core/basket.py +234 -0
  42. quantbt/core/certification.py +274 -0
  43. quantbt/core/constraints.py +155 -0
  44. quantbt/core/engine.py +1144 -0
  45. quantbt/core/event.py +869 -0
  46. quantbt/core/execution_contract.py +197 -0
  47. quantbt/core/execution_depth.py +613 -0
  48. quantbt/core/intrabar_kernel.py +1906 -0
  49. quantbt/core/intrabar_reference.py +907 -0
  50. quantbt/core/intrabar_session.py +156 -0
  51. quantbt/core/market_tape.py +480 -0
  52. quantbt/core/native_event_capabilities.py +121 -0
  53. quantbt/core/native_event_parity.py +336 -0
  54. quantbt/core/order_compiler.py +422 -0
  55. quantbt/core/orders.py +319 -0
  56. quantbt/core/portfolio.py +392 -0
  57. quantbt/core/preprocessor.py +256 -0
  58. quantbt/core/reactive.py +173 -0
  59. quantbt/core/results.py +341 -0
  60. quantbt/core/schema.py +211 -0
  61. quantbt/core/scopes.py +96 -0
  62. quantbt/core/structured_orders.py +378 -0
  63. quantbt/core/types.py +87 -0
  64. quantbt/core/vectorized.py +203 -0
  65. quantbt/endpoint.py +4465 -0
  66. quantbt/engines.py +1014 -0
  67. quantbt/metrics/__init__.py +45 -0
  68. quantbt/metrics/options_analytics.py +46 -0
  69. quantbt/metrics/performance.py +541 -0
  70. quantbt/optimization/__init__.py +94 -0
  71. quantbt/optimization/callbacks.py +116 -0
  72. quantbt/optimization/candidate_selection.py +397 -0
  73. quantbt/optimization/config.py +84 -0
  74. quantbt/optimization/constraints.py +22 -0
  75. quantbt/optimization/evaluator.py +21 -0
  76. quantbt/optimization/evaluators/__init__.py +32 -0
  77. quantbt/optimization/evaluators/arbitrage.py +22 -0
  78. quantbt/optimization/evaluators/generic.py +34 -0
  79. quantbt/optimization/evaluators/grid_dca.py +22 -0
  80. quantbt/optimization/evaluators/intrabar.py +54 -0
  81. quantbt/optimization/evaluators/native_event.py +51 -0
  82. quantbt/optimization/evaluators/options.py +22 -0
  83. quantbt/optimization/evaluators/portfolio.py +42 -0
  84. quantbt/optimization/evaluators/signal.py +43 -0
  85. quantbt/optimization/multiseed.py +176 -0
  86. quantbt/optimization/objectives.py +221 -0
  87. quantbt/optimization/optimizer.py +500 -0
  88. quantbt/optimization/result.py +80 -0
  89. quantbt/optimization/samplers.py +84 -0
  90. quantbt/optimization/space.py +223 -0
  91. quantbt/options/__init__.py +215 -0
  92. quantbt/options/cache.py +116 -0
  93. quantbt/options/conventions.py +158 -0
  94. quantbt/options/data.py +177 -0
  95. quantbt/options/execution.py +600 -0
  96. quantbt/options/fees.py +135 -0
  97. quantbt/options/greeks.py +173 -0
  98. quantbt/options/hedging.py +232 -0
  99. quantbt/options/iv.py +188 -0
  100. quantbt/options/ledger.py +263 -0
  101. quantbt/options/lifecycle.py +94 -0
  102. quantbt/options/margin.py +311 -0
  103. quantbt/options/packages.py +147 -0
  104. quantbt/options/pricing.py +191 -0
  105. quantbt/options/schema.py +227 -0
  106. quantbt/options/selectors.py +281 -0
  107. quantbt/options/strategy.py +249 -0
  108. quantbt/options/surface.py +142 -0
  109. quantbt/options/tape.py +226 -0
  110. quantbt/options/templates/__init__.py +33 -0
  111. quantbt/options/templates/packages.py +354 -0
  112. quantbt/portfolio.py +606 -0
  113. quantbt/py.typed +1 -0
  114. quantbt/reporting/__init__.py +38 -0
  115. quantbt/reporting/arbitrage_audit.py +211 -0
  116. quantbt/reporting/nautilus_bundle.py +758 -0
  117. quantbt/reporting/nautilus_certification.py +226 -0
  118. quantbt/reporting/nautilus_diagnostics.py +225 -0
  119. quantbt/reporting/parity.py +496 -0
  120. quantbt/reporting/portfolio_audit.py +206 -0
  121. quantbt/reporting/portfolio_nautilus.py +140 -0
  122. quantbt/sizing/__init__.py +3 -0
  123. quantbt/sizing/fast.py +67 -0
  124. quantbt/sizing/modes.py +162 -0
  125. quantbt/viz/__init__.py +4 -0
  126. quantbt/viz/plots.py +310 -0
  127. quantbt/viz/themes.py +102 -0
  128. quantbt/walkforward.py +3136 -0
  129. quantbt_engine-1.0.7.dist-info/METADATA +891 -0
  130. quantbt_engine-1.0.7.dist-info/RECORD +133 -0
  131. quantbt_engine-1.0.7.dist-info/WHEEL +5 -0
  132. quantbt_engine-1.0.7.dist-info/licenses/LICENSE +21 -0
  133. quantbt_engine-1.0.7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Phase 13A WFO prepared market-cache benchmark.
4
+
5
+ This runner verifies that portfolio WFO endpoint scoring can reuse prepared
6
+ market arrays across Optuna trials without changing selected params, objective,
7
+ or final backtest equity.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import argparse
13
+ import json
14
+ import sys
15
+ import time
16
+ from pathlib import Path
17
+ from typing import Dict
18
+
19
+ import numpy as np
20
+ import pandas as pd
21
+
22
+ PACKAGE_DIR = Path(__file__).resolve().parents[1]
23
+ PROJECT_DIR = PACKAGE_DIR.parent
24
+ if str(PROJECT_DIR) not in sys.path:
25
+ sys.path.insert(0, str(PROJECT_DIR))
26
+
27
+ from quantbt import QuantBTEndpoint # noqa: E402
28
+
29
+
30
+ def run_benchmark(rows: int = 720, trials: int = 16) -> Dict:
31
+ data = _make_data(rows)
32
+ _run_wfo(data, trials=max(2, min(int(trials), 4)), use_cache=True)
33
+ _run_wfo(data, trials=max(2, min(int(trials), 4)), use_cache=False)
34
+ cached_seconds, cached = _time_run(data, trials=trials, use_cache=True)
35
+ uncached_seconds, uncached = _time_run(data, trials=trials, use_cache=False)
36
+ cached_wf = cached.metadata["walk_forward"]
37
+ uncached_wf = uncached.metadata["walk_forward"]
38
+ cache_meta = cached_wf.get("prepared_scoring_cache", {})
39
+ final_equity_diff = float(abs(cached.equity.iloc[-1] - uncached.equity.iloc[-1]))
40
+ objective_diff = float(abs(cached_wf["best_trial"]["objective"] - uncached_wf["best_trial"]["objective"]))
41
+ params_match = cached_wf["params"] == uncached_wf["params"]
42
+ speedup = float(uncached_seconds / cached_seconds) if cached_seconds > 0.0 else 0.0
43
+ status = "pass" if final_equity_diff <= 1e-9 and objective_diff <= 1e-12 and params_match else "fail"
44
+ return {
45
+ "status": status,
46
+ "rows": int(rows),
47
+ "trials": int(trials),
48
+ "cached_seconds": float(cached_seconds),
49
+ "uncached_seconds": float(uncached_seconds),
50
+ "speedup": speedup,
51
+ "final_equity_diff": final_equity_diff,
52
+ "objective_diff": objective_diff,
53
+ "params_match": bool(params_match),
54
+ "selected_params": cached_wf["params"],
55
+ "cache_metadata": cache_meta,
56
+ }
57
+
58
+
59
+ def make_markdown(report: Dict) -> str:
60
+ cache = report["cache_metadata"]
61
+ lines = [
62
+ "# Phase 13A WFO Prepared Market Cache",
63
+ "",
64
+ f"Status: **{report['status']}**",
65
+ "",
66
+ f"- Rows: `{report['rows']}`",
67
+ f"- Optuna trials: `{report['trials']}`",
68
+ f"- Cached seconds: `{report['cached_seconds']:.6f}`",
69
+ f"- Uncached seconds: `{report['uncached_seconds']:.6f}`",
70
+ f"- Speedup: `{report['speedup']:.3f}x`",
71
+ f"- Final equity diff: `{report['final_equity_diff']}`",
72
+ f"- Objective diff: `{report['objective_diff']}`",
73
+ f"- Params match: `{report['params_match']}`",
74
+ f"- Selected params: `{report['selected_params']}`",
75
+ "",
76
+ "## Cache Metadata",
77
+ "",
78
+ f"- Enabled: `{cache.get('enabled')}`",
79
+ f"- Prepared runs: `{cache.get('prepared_runs')}`",
80
+ f"- Fallback runs: `{cache.get('fallback_runs')}`",
81
+ f"- Market cache hits: `{cache.get('market_cache_hits')}`",
82
+ f"- Market cache misses: `{cache.get('market_cache_misses')}`",
83
+ f"- Market cache entries: `{cache.get('market_cache_entries')}`",
84
+ "",
85
+ "The benchmark is a deterministic parity/reuse guard, not a universal speed claim.",
86
+ "Full WFO runtime can still be dominated by Optuna and report construction.",
87
+ ]
88
+ return "\n".join(lines) + "\n"
89
+
90
+
91
+ def _time_run(data: Dict[str, pd.DataFrame], *, trials: int, use_cache: bool):
92
+ start = time.perf_counter()
93
+ result = _run_wfo(data, trials=trials, use_cache=use_cache)
94
+ return time.perf_counter() - start, result
95
+
96
+
97
+ def _run_wfo(data: Dict[str, pd.DataFrame], *, trials: int, use_cache: bool):
98
+ def strategy(data, params, train_index, test_index, fold):
99
+ scale = float(params["scale"])
100
+ return pd.DataFrame({"BTC": scale, "ETH": -scale}, index=test_index)
101
+
102
+ endpoint = QuantBTEndpoint.train_test_split(
103
+ strategy_class=strategy,
104
+ test_start="2022-01-01",
105
+ target_mode="portfolio",
106
+ portfolio_mode="longshort",
107
+ optimization_mode="mode_1_decay",
108
+ optimization_config={
109
+ "scoring_backend": "endpoint",
110
+ "use_prepared_scoring_cache": bool(use_cache),
111
+ },
112
+ optuna_trials=int(trials),
113
+ random_seed=123,
114
+ initial_capital=100_000.0,
115
+ leverage=5.0,
116
+ alloc_per_trade=1_000.0,
117
+ fee=0.0,
118
+ use_funding=False,
119
+ )
120
+ return endpoint.backtest(data=data, param_ranges={"scale": (0.5, 1.5, 0.05)})
121
+
122
+
123
+ def _make_data(rows: int) -> Dict[str, pd.DataFrame]:
124
+ idx = pd.date_range("2021-01-01", periods=int(rows), freq="1D", tz="UTC")
125
+ x = np.linspace(0.0, 16.0, len(idx))
126
+ btc_close = 100.0 + np.sin(x) * 2.0 + np.arange(len(idx)) * 0.01
127
+ eth_close = 50.0 + np.cos(x) * 1.5 + np.arange(len(idx)) * 0.005
128
+ return {
129
+ "BTC": _frame(idx, btc_close),
130
+ "ETH": _frame(idx, eth_close),
131
+ }
132
+
133
+
134
+ def _frame(idx: pd.DatetimeIndex, close: np.ndarray) -> pd.DataFrame:
135
+ return pd.DataFrame(
136
+ {
137
+ "open": close,
138
+ "high": close * 1.01,
139
+ "low": close * 0.99,
140
+ "close": close,
141
+ "volume": 1_000.0,
142
+ },
143
+ index=idx,
144
+ )
145
+
146
+
147
+ def main() -> int:
148
+ parser = argparse.ArgumentParser()
149
+ parser.add_argument("--rows", type=int, default=720)
150
+ parser.add_argument("--trials", type=int, default=16)
151
+ parser.add_argument("--json", type=Path, default=PACKAGE_DIR / "benchmarks" / "phase13_wfo_cache.json")
152
+ parser.add_argument("--markdown", type=Path, default=PACKAGE_DIR / "benchmarks" / "phase13_wfo_cache.md")
153
+ args = parser.parse_args()
154
+ report = run_benchmark(rows=args.rows, trials=args.trials)
155
+ args.json.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n")
156
+ args.markdown.write_text(make_markdown(report))
157
+ print(json.dumps(report, indent=2, sort_keys=True))
158
+ return 0 if report["status"] == "pass" else 1
159
+
160
+
161
+ if __name__ == "__main__":
162
+ raise SystemExit(main())