quantbt-engine 1.0.7__tar.gz → 1.0.8__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.
Files changed (225) hide show
  1. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/CHANGELOG.md +19 -0
  2. {quantbt_engine-1.0.7/src/quantbt_engine.egg-info → quantbt_engine-1.0.8}/PKG-INFO +52 -7
  3. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/README.md +51 -6
  4. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/pyproject.toml +1 -1
  5. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/__init__.py +3 -1
  6. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_portfolio.py +53 -2
  7. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_vectorized.py +61 -3
  8. quantbt_engine-1.0.8/src/quantbt/benchmarks/run_phase49b_wfo_performance.py +342 -0
  9. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/results.py +30 -0
  10. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/endpoint.py +126 -9
  11. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/walkforward.py +975 -66
  12. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8/src/quantbt_engine.egg-info}/PKG-INFO +52 -7
  13. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/SOURCES.txt +4 -0
  14. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase42c_ci_release.py +19 -6
  15. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46a_correctness_certification.py +1 -1
  16. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46f_packaging_release.py +4 -2
  17. quantbt_engine-1.0.8/tests/test_phase49a_walkforward_schedules.py +433 -0
  18. quantbt_engine-1.0.8/tests/test_phase49b_wfo_performance.py +314 -0
  19. quantbt_engine-1.0.8/tests/test_phase50_nested_mode1_causal.py +258 -0
  20. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/LICENSE +0 -0
  21. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/MANIFEST.in +0 -0
  22. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/setup.cfg +0 -0
  23. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/__init__.py +0 -0
  24. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/__init__.py +0 -0
  25. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/_dependency.py +0 -0
  26. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/backend.py +0 -0
  27. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/instruments.py +0 -0
  28. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/options.py +0 -0
  29. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/reports.py +0 -0
  30. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/__init__.py +0 -0
  31. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/_native_event_rust.py +0 -0
  32. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_event.py +0 -0
  33. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_option.py +0 -0
  34. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backtester.py +0 -0
  35. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/__init__.py +0 -0
  36. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/compare_phase9_parity.py +0 -0
  37. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/gamma_scalping_backtestsample.py +0 -0
  38. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/profile_phase7.py +0 -0
  39. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_arbitrage_phase_e.py +0 -0
  40. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_optimization_overhead.py +0 -0
  41. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_options_engine.py +0 -0
  42. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_pct_equity_nautilus_smoke.py +0 -0
  43. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase12_arbitrage_cert.py +0 -0
  44. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase12_benchmark_nautilus_cert.py +0 -0
  45. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase13_portfolio_report.py +0 -0
  46. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase13_wfo_cache.py +0 -0
  47. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase14_service_loop.py +0 -0
  48. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase15a_nautilus_certification.py +0 -0
  49. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase15b_synthetic_depth.py +0 -0
  50. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase16_performance_debt.py +0 -0
  51. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase30e_reactive_runner.py +0 -0
  52. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase31_intrabar.py +0 -0
  53. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase34a_native_event_memory.py +0 -0
  54. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase34b_native_event_prepared_score.py +0 -0
  55. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase34c_native_event_single_pass.py +0 -0
  56. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase7.py +0 -0
  57. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_portfolio_real_parity.py +0 -0
  58. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/__init__.py +0 -0
  59. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/arbitrage.py +0 -0
  60. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/basket.py +0 -0
  61. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/certification.py +0 -0
  62. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/constraints.py +0 -0
  63. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/engine.py +0 -0
  64. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/event.py +0 -0
  65. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/execution_contract.py +0 -0
  66. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/execution_depth.py +0 -0
  67. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/intrabar_kernel.py +0 -0
  68. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/intrabar_reference.py +0 -0
  69. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/intrabar_session.py +0 -0
  70. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/market_tape.py +0 -0
  71. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/native_event_capabilities.py +0 -0
  72. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/native_event_parity.py +0 -0
  73. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/order_compiler.py +0 -0
  74. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/orders.py +0 -0
  75. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/portfolio.py +0 -0
  76. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/preprocessor.py +0 -0
  77. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/reactive.py +0 -0
  78. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/schema.py +0 -0
  79. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/scopes.py +0 -0
  80. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/structured_orders.py +0 -0
  81. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/types.py +0 -0
  82. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/vectorized.py +0 -0
  83. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/engines.py +0 -0
  84. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/metrics/__init__.py +0 -0
  85. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/metrics/options_analytics.py +0 -0
  86. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/metrics/performance.py +0 -0
  87. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/__init__.py +0 -0
  88. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/callbacks.py +0 -0
  89. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/candidate_selection.py +0 -0
  90. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/config.py +0 -0
  91. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/constraints.py +0 -0
  92. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluator.py +0 -0
  93. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/__init__.py +0 -0
  94. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/arbitrage.py +0 -0
  95. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/generic.py +0 -0
  96. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/grid_dca.py +0 -0
  97. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/intrabar.py +0 -0
  98. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/native_event.py +0 -0
  99. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/options.py +0 -0
  100. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/portfolio.py +0 -0
  101. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/signal.py +0 -0
  102. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/multiseed.py +0 -0
  103. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/objectives.py +0 -0
  104. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/optimizer.py +0 -0
  105. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/result.py +0 -0
  106. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/samplers.py +0 -0
  107. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/space.py +0 -0
  108. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/__init__.py +0 -0
  109. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/cache.py +0 -0
  110. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/conventions.py +0 -0
  111. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/data.py +0 -0
  112. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/execution.py +0 -0
  113. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/fees.py +0 -0
  114. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/greeks.py +0 -0
  115. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/hedging.py +0 -0
  116. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/iv.py +0 -0
  117. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/ledger.py +0 -0
  118. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/lifecycle.py +0 -0
  119. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/margin.py +0 -0
  120. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/packages.py +0 -0
  121. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/pricing.py +0 -0
  122. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/schema.py +0 -0
  123. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/selectors.py +0 -0
  124. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/strategy.py +0 -0
  125. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/surface.py +0 -0
  126. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/tape.py +0 -0
  127. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/templates/__init__.py +0 -0
  128. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/templates/packages.py +0 -0
  129. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/portfolio.py +0 -0
  130. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/py.typed +0 -0
  131. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/__init__.py +0 -0
  132. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/arbitrage_audit.py +0 -0
  133. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/nautilus_bundle.py +0 -0
  134. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/nautilus_certification.py +0 -0
  135. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/nautilus_diagnostics.py +0 -0
  136. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/parity.py +0 -0
  137. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/portfolio_audit.py +0 -0
  138. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/portfolio_nautilus.py +0 -0
  139. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/sizing/__init__.py +0 -0
  140. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/sizing/fast.py +0 -0
  141. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/sizing/modes.py +0 -0
  142. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/viz/__init__.py +0 -0
  143. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/viz/plots.py +0 -0
  144. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/viz/themes.py +0 -0
  145. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/dependency_links.txt +0 -0
  146. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/requires.txt +0 -0
  147. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/top_level.txt +0 -0
  148. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_endpoint.py +0 -0
  149. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_metrics_intraday_scope.py +0 -0
  150. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_core.py +0 -0
  151. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_evaluators.py +0 -0
  152. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_integration.py +0 -0
  153. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_phase33b.py +0 -0
  154. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_samplers.py +0 -0
  155. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_pct_equity_nautilus_smoke.py +0 -0
  156. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase0_baseline.py +0 -0
  157. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_native_portfolio_backend.py +0 -0
  158. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_native_portfolio_full_surface.py +0 -0
  159. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_engine_spec.py +0 -0
  160. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_institutional_scenarios.py +0 -0
  161. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_nautilus_validation.py +0 -0
  162. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_real_parity_script.py +0 -0
  163. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase12_arbitrage_certification.py +0 -0
  164. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase12_benchmark_nautilus_cert.py +0 -0
  165. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase13_arbitrage_certification_cleanup.py +0 -0
  166. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase13_portfolio_report_parity.py +0 -0
  167. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase14_service_loop_benchmark.py +0 -0
  168. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase14c_prepared_report_levels.py +0 -0
  169. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase15a_nautilus_certification.py +0 -0
  170. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase15b_synthetic_depth.py +0 -0
  171. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase16_prepared_service_context.py +0 -0
  172. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase1_schema.py +0 -0
  173. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase2_native_vectorized.py +0 -0
  174. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30a_native_event_lifecycle_contract.py +0 -0
  175. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30b_native_event_lifecycle_kernel.py +0 -0
  176. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30c_native_event_endpoint_lifecycle.py +0 -0
  177. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30d_native_event_reactive_runner.py +0 -0
  178. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30e_native_event_incremental_runner.py +0 -0
  179. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31_merge_blockers.py +0 -0
  180. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31a_execution_correctness_contract.py +0 -0
  181. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31b_market_tape_intrabar_oracle.py +0 -0
  182. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31c_intrabar_kernel.py +0 -0
  183. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31d_certification.py +0 -0
  184. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31h_intrabar_session_reference.py +0 -0
  185. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase34a_native_event_artifacts.py +0 -0
  186. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase34b_native_event_prepared_score.py +0 -0
  187. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase34c_native_event_single_pass.py +0 -0
  188. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase3_native_event.py +0 -0
  189. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase42_packaging_layout.py +0 -0
  190. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase45a_source_tree_sync.py +0 -0
  191. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase45d_native_event_zero_object.py +0 -0
  192. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46b_score_rss.py +0 -0
  193. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46c_import_graph.py +0 -0
  194. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase47a_grid_adapter.py +0 -0
  195. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase47c_grid_parity.py +0 -0
  196. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase47d_grid_optimizer.py +0 -0
  197. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48a_release_surfaces.py +0 -0
  198. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48b_release_hygiene.py +0 -0
  199. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48c_event_driven_facade.py +0 -0
  200. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48f_release_gate.py +0 -0
  201. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase4_basket.py +0 -0
  202. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_1_nautilus_report_bundle.py +0 -0
  203. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_3_arbitrage_audit.py +0 -0
  204. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_3_institutional_simulations.py +0 -0
  205. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_3_portfolio_audit.py +0 -0
  206. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_4_debt_domain_validation.py +0 -0
  207. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_4_endpoint_depth.py +0 -0
  208. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_4_nautilus_depth.py +0 -0
  209. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_nautilus_adapter.py +0 -0
  210. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase6_public_api.py +0 -0
  211. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase7_benchmark_suite.py +0 -0
  212. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_a.py +0 -0
  213. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_b.py +0 -0
  214. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_c.py +0 -0
  215. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_d.py +0 -0
  216. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_e.py +0 -0
  217. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_f.py +0 -0
  218. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_g.py +0 -0
  219. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_h.py +0 -0
  220. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase9_performance_parity.py +0 -0
  221. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_pre48e_native_event_fast_paths.py +0 -0
  222. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_real.py +0 -0
  223. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_real_endpoints.py +0 -0
  224. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_shared_quantity_constraints.py +0 -0
  225. {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_walkforward_phase1.py +0 -0
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to `quantbt-engine` are documented here.
4
4
 
5
+ ## [1.0.8] - 2026-08-12
6
+
7
+ ### Changed
8
+
9
+ - Added strict nested causal retraining for
10
+ `mode_1_decay + optimization_schedule="per_fold_causal"`. Mode 1 decay now
11
+ uses inner IS-only folds while each outer OOS segment remains untouched until
12
+ its parameters are frozen.
13
+ - Added explicit chronological validation metadata so consumers can distinguish
14
+ retrospective global calibration, selection-adjusted OOS, and strict outer
15
+ OOS evaluation without breaking legacy result fields.
16
+ - Added a bounded-RSS release test runner that executes deterministic pytest
17
+ shards in fresh processes; CI and publish workflows use the same selection.
18
+
19
+ ### Verification
20
+
21
+ - Root/source mirror, prepared/reference WFO parity, nested-fold causality,
22
+ and the full non-real-data release suite passed before this version bump.
23
+
5
24
  ## [1.0.7] - 2026-08-04
6
25
 
7
26
  This is the first independently installable core package release line.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantbt-engine
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Transparent, high-performance quantitative backtesting engine
5
5
  Author-email: Vu Cong Minh <vugioan11022002@gmail.com>
6
6
  License-Expression: MIT
@@ -218,6 +218,21 @@ tape. Normal `.backtest(...)` remains defensive and backward-compatible.
218
218
  Cython/C++ remains deferred because the larger benchmark still points to
219
219
  facade/report overhead rather than pure Numba kernels.
220
220
 
221
+ Latest Phase 49B WFO benchmark (1,000 daily bars, identical seeds, folds,
222
+ trials, strategies, account settings, and accounting kernels):
223
+
224
+ | WFO workload | Phase 49A reference | Phase 49B prepared/scalar | Speedup | Parity |
225
+ |---|---:|---:|---:|---|
226
+ | Portfolio global, 1 study x 16 trials | 0.386s | 0.330s | 1.17x | exact |
227
+ | Single-symbol causal, 6 studies x 16 trials | 4.051s | 1.781s | 2.27x | exact |
228
+
229
+ Phase 49B prepares aligned WFO fold state once, scores trials directly from
230
+ accounting arrays, and compacts completed Optuna ledgers. It does not cache user
231
+ strategy signals or alter objectives. The isolated warm peak-RSS difference was
232
+ within +/-0.15%, so the result is reported as an RSS plateau rather than a memory
233
+ reduction. Reproduce it with
234
+ `python benchmarks/run_phase49b_wfo_performance.py --rows 1000 --trials 16`.
235
+
221
236
  Latest Phase 31 intrabar execution benchmark:
222
237
 
223
238
  | Route | Workload | Runtime | Throughput | Ratio | Parity |
@@ -263,7 +278,7 @@ wheel:
263
278
 
264
279
  | Release artifact | Current status | Backend policy |
265
280
  |---|---|---|
266
- | `quantbt-engine==1.0.7` wheel/sdist | release-ready after local/TestPyPI approval | Python canonical; all existing endpoints remain available |
281
+ | `quantbt-engine==1.0.8` wheel/sdist | release-ready after local/TestPyPI approval | Python canonical; all existing endpoints remain available |
267
282
  | `quantbt-native` PyO3 wheel | experimental, not published | explicit `native_backend="rust"` only |
268
283
  | `quantbt-engine[native]` | intentionally empty | no dependency is advertised before native certification |
269
284
 
@@ -330,7 +345,7 @@ Raw Phase 47D artifacts are kept under
330
345
 
331
346
  ### Phase 48F final release handoff
332
347
 
333
- The core `quantbt-engine` 1.0.7 artifact gate is now implemented locally and
348
+ The core `quantbt-engine` 1.0.8 artifact gate is now implemented locally and
334
349
  in the release workflows: exact version/ref validation, wheel and sdist
335
350
  `twine check`, archive allowlist and secret scan, clean import plus `pip check`,
336
351
  and a SHA256 release manifest. The TestPyPI workflow is manual and OIDC
@@ -639,15 +654,19 @@ fills, positions, account state, and performance report.
639
654
  Install the released core package:
640
655
 
641
656
  ```bash
642
- pip install quantbt-engine==1.0.7
657
+ pip install quantbt-engine==1.0.8
643
658
  ```
644
659
 
645
- Optional reports and third-party validation:
660
+ Optional optimization, reports, and third-party validation:
646
661
 
647
662
  ```bash
648
- pip install "quantbt-engine[reports,validation]==1.0.7"
663
+ pip install "quantbt-engine[optimization,reports,validation]==1.0.8"
649
664
  ```
650
665
 
666
+ Walk-forward parameter search specifically requires the `optimization` extra.
667
+ Read the [causal WFO guide](docs/walkforward_causal.md) before reporting OOS
668
+ metrics from a fold-local schedule.
669
+
651
670
  Development from this repository:
652
671
 
653
672
  ```bash
@@ -672,7 +691,7 @@ pip install -e /root/bobby/pool_alpha/quantbt
672
691
  ```
673
692
 
674
693
  After the release is approved, downstream services should use
675
- `pip install quantbt-engine==1.0.7` and keep the unchanged import
694
+ `pip install quantbt-engine==1.0.8` and keep the unchanged import
676
695
  `from quantbt import QuantBTEndpoint`.
677
696
 
678
697
  ## Quick Start
@@ -803,6 +822,31 @@ result = wf.backtest(data=df, param_ranges=param_ranges)
803
822
  wf.show_metrics(scope="auto")
804
823
  ```
805
824
 
825
+ Multi-fold WFO keeps `optimization_schedule="global"` as the compatible
826
+ default. Phase 49A also exposes two explicit fold-local schedules:
827
+
828
+ - `mode_1_decay + per_fold_decay`: one study per fold, with same-fold OOS used
829
+ for final decay candidate selection (`selection_adjusted_oos`);
830
+ - `mode_4_is_only_robust + per_fold_causal`: one study per fold, with strict
831
+ IS-only selection before outer OOS execution.
832
+ - `mode_1_decay + per_fold_causal`: one outer study per fold, where Mode 1
833
+ decay is measured only on explicit nested inner folds contained in that
834
+ outer IS window; outer OOS remains untouched until parameters are frozen.
835
+
836
+ Both schedules stitch one continuous target tape and run accounting once with
837
+ `fold_boundary_position_policy="carry"`. See the [causal WFO guide]
838
+ (docs/walkforward_causal.md), [docs/endpoint.md](docs/endpoint.md), and
839
+ [methodology/walk_forward.md](methodology/walk_forward.md) for selection claims,
840
+ strictness boundaries, and audit metadata.
841
+
842
+ Phase 49B keeps this API stable. Endpoint-backed optimization prepares market
843
+ and fold state once and uses scalar-only trial reports by default. Audit the
844
+ lifecycle through `prepared_wfo_context`, `prepared_scoring_cache`,
845
+ `trial_ledger_mode`, and `performance_profile` in walk-forward metadata.
846
+ Nested Mode 1 also records `inner_validation`, `inner_fold_table`, and
847
+ `chronological_validation_claim` so services can distinguish retrospective,
848
+ selection-adjusted, and strict outer-OOS results.
849
+
806
850
  `scope="auto"` reports only the tested/OOS segment for walk-forward and
807
851
  train/test runs. Pass `scope="full"` when you need to audit the full stitched
808
852
  timeline.
@@ -852,6 +896,7 @@ backend, endpoint, or strategy route to use.
852
896
  | Market/limit/stop fill behavior | [Order fill policies](docs/order_fill_policies.md) |
853
897
  | Nautilus validation and report bundles | [Nautilus backend](docs/nautilus_backend.md) |
854
898
  | Pair, basket, hedge-ratio package behavior | [Pair and basket guide](docs/pair_basket_guide.md) |
899
+ | Causal WFO schedules, outer-OOS claims, and audit metadata | [Causal WFO guide](docs/walkforward_causal.md) |
855
900
  | Walk-forward methodology and anti-leakage scoring | [Walk-forward methodology](docs/walkforward_methodology_vi.md) |
856
901
  | Runnable smoke templates | [Examples index](examples/README.md) |
857
902
 
@@ -168,6 +168,21 @@ tape. Normal `.backtest(...)` remains defensive and backward-compatible.
168
168
  Cython/C++ remains deferred because the larger benchmark still points to
169
169
  facade/report overhead rather than pure Numba kernels.
170
170
 
171
+ Latest Phase 49B WFO benchmark (1,000 daily bars, identical seeds, folds,
172
+ trials, strategies, account settings, and accounting kernels):
173
+
174
+ | WFO workload | Phase 49A reference | Phase 49B prepared/scalar | Speedup | Parity |
175
+ |---|---:|---:|---:|---|
176
+ | Portfolio global, 1 study x 16 trials | 0.386s | 0.330s | 1.17x | exact |
177
+ | Single-symbol causal, 6 studies x 16 trials | 4.051s | 1.781s | 2.27x | exact |
178
+
179
+ Phase 49B prepares aligned WFO fold state once, scores trials directly from
180
+ accounting arrays, and compacts completed Optuna ledgers. It does not cache user
181
+ strategy signals or alter objectives. The isolated warm peak-RSS difference was
182
+ within +/-0.15%, so the result is reported as an RSS plateau rather than a memory
183
+ reduction. Reproduce it with
184
+ `python benchmarks/run_phase49b_wfo_performance.py --rows 1000 --trials 16`.
185
+
171
186
  Latest Phase 31 intrabar execution benchmark:
172
187
 
173
188
  | Route | Workload | Runtime | Throughput | Ratio | Parity |
@@ -213,7 +228,7 @@ wheel:
213
228
 
214
229
  | Release artifact | Current status | Backend policy |
215
230
  |---|---|---|
216
- | `quantbt-engine==1.0.7` wheel/sdist | release-ready after local/TestPyPI approval | Python canonical; all existing endpoints remain available |
231
+ | `quantbt-engine==1.0.8` wheel/sdist | release-ready after local/TestPyPI approval | Python canonical; all existing endpoints remain available |
217
232
  | `quantbt-native` PyO3 wheel | experimental, not published | explicit `native_backend="rust"` only |
218
233
  | `quantbt-engine[native]` | intentionally empty | no dependency is advertised before native certification |
219
234
 
@@ -280,7 +295,7 @@ Raw Phase 47D artifacts are kept under
280
295
 
281
296
  ### Phase 48F final release handoff
282
297
 
283
- The core `quantbt-engine` 1.0.7 artifact gate is now implemented locally and
298
+ The core `quantbt-engine` 1.0.8 artifact gate is now implemented locally and
284
299
  in the release workflows: exact version/ref validation, wheel and sdist
285
300
  `twine check`, archive allowlist and secret scan, clean import plus `pip check`,
286
301
  and a SHA256 release manifest. The TestPyPI workflow is manual and OIDC
@@ -589,15 +604,19 @@ fills, positions, account state, and performance report.
589
604
  Install the released core package:
590
605
 
591
606
  ```bash
592
- pip install quantbt-engine==1.0.7
607
+ pip install quantbt-engine==1.0.8
593
608
  ```
594
609
 
595
- Optional reports and third-party validation:
610
+ Optional optimization, reports, and third-party validation:
596
611
 
597
612
  ```bash
598
- pip install "quantbt-engine[reports,validation]==1.0.7"
613
+ pip install "quantbt-engine[optimization,reports,validation]==1.0.8"
599
614
  ```
600
615
 
616
+ Walk-forward parameter search specifically requires the `optimization` extra.
617
+ Read the [causal WFO guide](docs/walkforward_causal.md) before reporting OOS
618
+ metrics from a fold-local schedule.
619
+
601
620
  Development from this repository:
602
621
 
603
622
  ```bash
@@ -622,7 +641,7 @@ pip install -e /root/bobby/pool_alpha/quantbt
622
641
  ```
623
642
 
624
643
  After the release is approved, downstream services should use
625
- `pip install quantbt-engine==1.0.7` and keep the unchanged import
644
+ `pip install quantbt-engine==1.0.8` and keep the unchanged import
626
645
  `from quantbt import QuantBTEndpoint`.
627
646
 
628
647
  ## Quick Start
@@ -753,6 +772,31 @@ result = wf.backtest(data=df, param_ranges=param_ranges)
753
772
  wf.show_metrics(scope="auto")
754
773
  ```
755
774
 
775
+ Multi-fold WFO keeps `optimization_schedule="global"` as the compatible
776
+ default. Phase 49A also exposes two explicit fold-local schedules:
777
+
778
+ - `mode_1_decay + per_fold_decay`: one study per fold, with same-fold OOS used
779
+ for final decay candidate selection (`selection_adjusted_oos`);
780
+ - `mode_4_is_only_robust + per_fold_causal`: one study per fold, with strict
781
+ IS-only selection before outer OOS execution.
782
+ - `mode_1_decay + per_fold_causal`: one outer study per fold, where Mode 1
783
+ decay is measured only on explicit nested inner folds contained in that
784
+ outer IS window; outer OOS remains untouched until parameters are frozen.
785
+
786
+ Both schedules stitch one continuous target tape and run accounting once with
787
+ `fold_boundary_position_policy="carry"`. See the [causal WFO guide]
788
+ (docs/walkforward_causal.md), [docs/endpoint.md](docs/endpoint.md), and
789
+ [methodology/walk_forward.md](methodology/walk_forward.md) for selection claims,
790
+ strictness boundaries, and audit metadata.
791
+
792
+ Phase 49B keeps this API stable. Endpoint-backed optimization prepares market
793
+ and fold state once and uses scalar-only trial reports by default. Audit the
794
+ lifecycle through `prepared_wfo_context`, `prepared_scoring_cache`,
795
+ `trial_ledger_mode`, and `performance_profile` in walk-forward metadata.
796
+ Nested Mode 1 also records `inner_validation`, `inner_fold_table`, and
797
+ `chronological_validation_claim` so services can distinguish retrospective,
798
+ selection-adjusted, and strict outer-OOS results.
799
+
756
800
  `scope="auto"` reports only the tested/OOS segment for walk-forward and
757
801
  train/test runs. Pass `scope="full"` when you need to audit the full stitched
758
802
  timeline.
@@ -802,6 +846,7 @@ backend, endpoint, or strategy route to use.
802
846
  | Market/limit/stop fill behavior | [Order fill policies](docs/order_fill_policies.md) |
803
847
  | Nautilus validation and report bundles | [Nautilus backend](docs/nautilus_backend.md) |
804
848
  | Pair, basket, hedge-ratio package behavior | [Pair and basket guide](docs/pair_basket_guide.md) |
849
+ | Causal WFO schedules, outer-OOS claims, and audit metadata | [Causal WFO guide](docs/walkforward_causal.md) |
805
850
  | Walk-forward methodology and anti-leakage scoring | [Walk-forward methodology](docs/walkforward_methodology_vi.md) |
806
851
  | Runnable smoke templates | [Examples index](examples/README.md) |
807
852
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantbt-engine"
7
- version = "1.0.7"
7
+ version = "1.0.8"
8
8
  description = "Transparent, high-performance quantitative backtesting engine"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.14"
@@ -110,6 +110,7 @@ _LAZY_EXPORTS = {
110
110
  "WalkForwardConfig",
111
111
  "WalkForwardEngine",
112
112
  "WalkForwardFold",
113
+ "PreparedWalkForwardContext",
113
114
  "WalkForwardResult",
114
115
  "WalkForwardTrialRecord",
115
116
  "benchmark_walkforward_kernels",
@@ -499,7 +500,7 @@ from .metrics import (
499
500
  )
500
501
 
501
502
 
502
- __version__ = "1.0.7"
503
+ __version__ = "1.0.8"
503
504
  __author__ = "quantbt"
504
505
 
505
506
  __all__ = [
@@ -667,6 +668,7 @@ __all__ = [
667
668
  "WalkForwardConfig",
668
669
  "WalkForwardEngine",
669
670
  "WalkForwardFold",
671
+ "PreparedWalkForwardContext",
670
672
  "WalkForwardResult",
671
673
  "WalkForwardTrialRecord",
672
674
  "WalkForwardBenchmarkSnapshot",
@@ -36,7 +36,7 @@ from ..core.preprocessor import (
36
36
  prepare_funding,
37
37
  validate_datetime,
38
38
  )
39
- from ..core.results import BacktestResultV2
39
+ from ..core.results import BacktestResultV2, BacktestScalarScoreResult
40
40
  from ..core.schema import AccountConfig
41
41
  from ..core.schema import ExecutionConfig, InstrumentSpec
42
42
  from ..sizing.fast import scale_signal_notional_matrix
@@ -96,7 +96,8 @@ class NativePortfolioBackend:
96
96
  min_qty: Optional[Union[float, Dict[str, float]]] = None,
97
97
  min_notional: Optional[Union[float, Dict[str, float]]] = None,
98
98
  report_level: Optional[str] = None,
99
- ) -> BacktestResultV2:
99
+ _scalar_score_trading_days: Optional[int] = None,
100
+ ) -> Union[BacktestResultV2, BacktestScalarScoreResult]:
100
101
  idx = validate_datetime(datetime_index)
101
102
  if positions is None and raw_signal_matrix is None:
102
103
  raise ValueError("positions or raw_signal_matrix is required")
@@ -253,6 +254,46 @@ class NativePortfolioBackend:
253
254
  tradable=tradable_mask,
254
255
  )
255
256
 
257
+ if _scalar_score_trading_days is not None:
258
+ from ..metrics.performance import compute_performance_metrics
259
+
260
+ returns_arr = np.zeros_like(equity_arr, dtype=np.float64)
261
+ if len(equity_arr) > 1:
262
+ returns_arr[1:] = np.divide(
263
+ equity_arr[1:] - equity_arr[:-1],
264
+ equity_arr[:-1],
265
+ out=np.zeros(len(equity_arr) - 1, dtype=np.float64),
266
+ where=equity_arr[:-1] != 0.0,
267
+ )
268
+ metrics = compute_performance_metrics(
269
+ timestamps=idx,
270
+ equity=equity_arr,
271
+ returns=returns_arr,
272
+ positions=pos_arr,
273
+ symbols=symbol_list,
274
+ initial_capital=float(self.config.account.initial_capital),
275
+ liquidated=bool(liq_flag),
276
+ trading_days=int(_scalar_score_trading_days),
277
+ )
278
+ final_positions = (
279
+ np.asarray(pos_arr[-1], dtype=np.float64).copy()
280
+ if len(pos_arr)
281
+ else np.zeros(len(symbol_list), dtype=np.float64)
282
+ )
283
+ return BacktestScalarScoreResult(
284
+ final_equity=float(equity_arr[-1]),
285
+ final_positions=final_positions,
286
+ metrics=metrics,
287
+ liquidated=bool(liq_flag),
288
+ liquidation_bar=int(liq_idx),
289
+ metadata={
290
+ "backend": "native_portfolio",
291
+ "score_scalar": True,
292
+ "score_pandas_materialized": False,
293
+ "trading_days": int(_scalar_score_trading_days),
294
+ },
295
+ )
296
+
256
297
  result = self._build_result(
257
298
  idx=idx,
258
299
  symbol_list=symbol_list,
@@ -292,6 +333,16 @@ class NativePortfolioBackend:
292
333
  result.metadata["portfolio_contract_report"] = validate_portfolio_result_contract(result, spec, tolerance=1e-8)
293
334
  return result
294
335
 
336
+ def score_signals(self, *, trading_days: int = 365, **kwargs) -> BacktestScalarScoreResult:
337
+ """Run the portfolio accounting kernel and retain scalar metrics only."""
338
+ result = self.run_signals(
339
+ **kwargs,
340
+ _scalar_score_trading_days=int(trading_days),
341
+ )
342
+ if not isinstance(result, BacktestScalarScoreResult): # pragma: no cover - guarded above
343
+ raise RuntimeError("native_portfolio scalar score unexpectedly materialized a public result")
344
+ return result
345
+
295
346
  def prepare_market_arrays(
296
347
  self,
297
348
  datetime_index: Union[pd.DatetimeIndex, pd.Series],
@@ -24,7 +24,7 @@ from ..core.preprocessor import (
24
24
  validate_datetime,
25
25
  )
26
26
  from ..core.constraints import build_quantity_constraints, quantize_target_units_matrix
27
- from ..core.results import BacktestResultV2
27
+ from ..core.results import BacktestResultV2, BacktestScalarScoreResult
28
28
  from ..core.schema import (
29
29
  AccountConfig,
30
30
  BasketLegSpec,
@@ -276,7 +276,8 @@ class NativeVectorizedBackend:
276
276
  market_arrays: Optional[PreparedMarketArrays] = None,
277
277
  raw_signal_matrix: Optional[np.ndarray] = None,
278
278
  high_low_source: str = "provided",
279
- ) -> BacktestResultV2:
279
+ _scalar_score_trading_days: Optional[int] = None,
280
+ ) -> Union[BacktestResultV2, BacktestScalarScoreResult]:
280
281
  contract_sizes = self._per_symbol_array(contract_size, symbol_list, default=1.0)
281
282
  constraints = build_quantity_constraints(
282
283
  symbol_list,
@@ -330,6 +331,46 @@ class NativeVectorizedBackend:
330
331
  use_funding=bool(self.config.use_funding),
331
332
  )
332
333
 
334
+ if _scalar_score_trading_days is not None:
335
+ from ..metrics.performance import compute_performance_metrics
336
+
337
+ returns_arr = np.zeros_like(equity_arr, dtype=np.float64)
338
+ if len(equity_arr) > 1:
339
+ returns_arr[1:] = np.divide(
340
+ equity_arr[1:] - equity_arr[:-1],
341
+ equity_arr[:-1],
342
+ out=np.zeros(len(equity_arr) - 1, dtype=np.float64),
343
+ where=equity_arr[:-1] != 0.0,
344
+ )
345
+ metrics = compute_performance_metrics(
346
+ timestamps=idx,
347
+ equity=equity_arr,
348
+ returns=returns_arr,
349
+ positions=pos_arr,
350
+ symbols=symbol_list,
351
+ initial_capital=float(self.config.account.initial_capital),
352
+ liquidated=bool(liq_flag),
353
+ trading_days=int(_scalar_score_trading_days),
354
+ )
355
+ final_positions = (
356
+ np.asarray(pos_arr[-1], dtype=np.float64).copy()
357
+ if len(pos_arr)
358
+ else np.zeros(len(symbol_list), dtype=np.float64)
359
+ )
360
+ return BacktestScalarScoreResult(
361
+ final_equity=float(equity_arr[-1]),
362
+ final_positions=final_positions,
363
+ metrics=metrics,
364
+ liquidated=bool(liq_flag),
365
+ liquidation_bar=int(liq_idx),
366
+ metadata={
367
+ "backend": "native_vectorized",
368
+ "score_scalar": True,
369
+ "score_pandas_materialized": False,
370
+ "trading_days": int(_scalar_score_trading_days),
371
+ },
372
+ )
373
+
333
374
  equity = pd.Series(equity_arr, index=idx, name="equity")
334
375
  returns = equity.pct_change().fillna(0.0)
335
376
  positions = pd.DataFrame(
@@ -413,7 +454,8 @@ class NativeVectorizedBackend:
413
454
  min_notional: Optional[Union[float, Dict[str, float]]] = None,
414
455
  market_arrays: Optional[PreparedMarketArrays] = None,
415
456
  raw_signal_matrix: Optional[np.ndarray] = None,
416
- ) -> BacktestResultV2:
457
+ _scalar_score_trading_days: Optional[int] = None,
458
+ ) -> Union[BacktestResultV2, BacktestScalarScoreResult]:
417
459
  """
418
460
  Scale raw position signals into target units, then run the V2 kernel.
419
461
 
@@ -487,6 +529,7 @@ class NativeVectorizedBackend:
487
529
  min_qty=min_qty,
488
530
  min_notional=min_notional,
489
531
  high_low_source=high_low_source,
532
+ _scalar_score_trading_days=_scalar_score_trading_days,
490
533
  )
491
534
 
492
535
  if close_dict is None:
@@ -528,6 +571,21 @@ class NativeVectorizedBackend:
528
571
  min_notional=min_notional,
529
572
  )
530
573
 
574
+ def score_signals(self, *, trading_days: int = 365, **kwargs) -> BacktestScalarScoreResult:
575
+ """Score prepared signal-notional targets without pandas report paths."""
576
+ hedge_type = str(kwargs.get("hedge_type", "signal_notional")).lower().strip()
577
+ if hedge_type not in {"signal_notional", "signal"}:
578
+ raise NotImplementedError(
579
+ "native_vectorized scalar scoring currently supports signal_notional only"
580
+ )
581
+ result = self.run_signals(
582
+ **kwargs,
583
+ _scalar_score_trading_days=int(trading_days),
584
+ )
585
+ if not isinstance(result, BacktestScalarScoreResult): # pragma: no cover - guarded above
586
+ raise RuntimeError("native_vectorized scalar score unexpectedly materialized a public result")
587
+ return result
588
+
531
589
  def run_basis_arbitrage(
532
590
  self,
533
591
  datetime_index: Union[pd.DatetimeIndex, pd.Series],