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.
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/CHANGELOG.md +19 -0
- {quantbt_engine-1.0.7/src/quantbt_engine.egg-info → quantbt_engine-1.0.8}/PKG-INFO +52 -7
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/README.md +51 -6
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/pyproject.toml +1 -1
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/__init__.py +3 -1
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_portfolio.py +53 -2
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_vectorized.py +61 -3
- quantbt_engine-1.0.8/src/quantbt/benchmarks/run_phase49b_wfo_performance.py +342 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/results.py +30 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/endpoint.py +126 -9
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/walkforward.py +975 -66
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8/src/quantbt_engine.egg-info}/PKG-INFO +52 -7
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/SOURCES.txt +4 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase42c_ci_release.py +19 -6
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46a_correctness_certification.py +1 -1
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46f_packaging_release.py +4 -2
- quantbt_engine-1.0.8/tests/test_phase49a_walkforward_schedules.py +433 -0
- quantbt_engine-1.0.8/tests/test_phase49b_wfo_performance.py +314 -0
- quantbt_engine-1.0.8/tests/test_phase50_nested_mode1_causal.py +258 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/LICENSE +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/MANIFEST.in +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/setup.cfg +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/_dependency.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/backend.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/instruments.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/options.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/adapters/nautilus/reports.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/_native_event_rust.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_event.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backends/native_option.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/backtester.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/compare_phase9_parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/gamma_scalping_backtestsample.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/profile_phase7.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_arbitrage_phase_e.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_optimization_overhead.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_options_engine.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_pct_equity_nautilus_smoke.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase12_arbitrage_cert.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase12_benchmark_nautilus_cert.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase13_portfolio_report.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase13_wfo_cache.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase14_service_loop.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase15a_nautilus_certification.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase15b_synthetic_depth.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase16_performance_debt.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase30e_reactive_runner.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase31_intrabar.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase34a_native_event_memory.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase34b_native_event_prepared_score.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase34c_native_event_single_pass.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_phase7.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/benchmarks/run_portfolio_real_parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/arbitrage.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/basket.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/certification.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/constraints.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/engine.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/event.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/execution_contract.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/execution_depth.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/intrabar_kernel.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/intrabar_reference.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/intrabar_session.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/market_tape.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/native_event_capabilities.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/native_event_parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/order_compiler.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/orders.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/portfolio.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/preprocessor.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/reactive.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/schema.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/scopes.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/structured_orders.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/types.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/core/vectorized.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/engines.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/metrics/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/metrics/options_analytics.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/metrics/performance.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/callbacks.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/candidate_selection.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/config.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/constraints.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluator.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/arbitrage.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/generic.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/grid_dca.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/intrabar.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/native_event.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/options.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/portfolio.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/evaluators/signal.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/multiseed.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/objectives.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/optimizer.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/result.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/samplers.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/optimization/space.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/cache.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/conventions.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/data.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/execution.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/fees.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/greeks.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/hedging.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/iv.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/ledger.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/lifecycle.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/margin.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/packages.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/pricing.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/schema.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/selectors.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/strategy.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/surface.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/tape.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/templates/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/options/templates/packages.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/portfolio.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/py.typed +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/arbitrage_audit.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/nautilus_bundle.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/nautilus_certification.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/nautilus_diagnostics.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/portfolio_audit.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/reporting/portfolio_nautilus.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/sizing/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/sizing/fast.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/sizing/modes.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/viz/__init__.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/viz/plots.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt/viz/themes.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/dependency_links.txt +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/requires.txt +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/src/quantbt_engine.egg-info/top_level.txt +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_endpoint.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_metrics_intraday_scope.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_core.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_evaluators.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_integration.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_phase33b.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_optimization_samplers.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_pct_equity_nautilus_smoke.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase0_baseline.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_native_portfolio_backend.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_native_portfolio_full_surface.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_engine_spec.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_institutional_scenarios.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_nautilus_validation.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase11_portfolio_real_parity_script.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase12_arbitrage_certification.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase12_benchmark_nautilus_cert.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase13_arbitrage_certification_cleanup.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase13_portfolio_report_parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase14_service_loop_benchmark.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase14c_prepared_report_levels.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase15a_nautilus_certification.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase15b_synthetic_depth.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase16_prepared_service_context.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase1_schema.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase2_native_vectorized.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30a_native_event_lifecycle_contract.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30b_native_event_lifecycle_kernel.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30c_native_event_endpoint_lifecycle.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30d_native_event_reactive_runner.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase30e_native_event_incremental_runner.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31_merge_blockers.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31a_execution_correctness_contract.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31b_market_tape_intrabar_oracle.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31c_intrabar_kernel.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31d_certification.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase31h_intrabar_session_reference.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase34a_native_event_artifacts.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase34b_native_event_prepared_score.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase34c_native_event_single_pass.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase3_native_event.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase42_packaging_layout.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase45a_source_tree_sync.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase45d_native_event_zero_object.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46b_score_rss.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase46c_import_graph.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase47a_grid_adapter.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase47c_grid_parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase47d_grid_optimizer.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48a_release_surfaces.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48b_release_hygiene.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48c_event_driven_facade.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase48f_release_gate.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase4_basket.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_1_nautilus_report_bundle.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_3_arbitrage_audit.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_3_institutional_simulations.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_3_portfolio_audit.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_4_debt_domain_validation.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_4_endpoint_depth.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_4_nautilus_depth.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase5_nautilus_adapter.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase6_public_api.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase7_benchmark_suite.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_a.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_b.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_c.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_d.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_e.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_f.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_g.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase8_arbitrage_phase_h.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_phase9_performance_parity.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_pre48e_native_event_fast_paths.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_real.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_real_endpoints.py +0 -0
- {quantbt_engine-1.0.7 → quantbt_engine-1.0.8}/tests/test_shared_quantity_constraints.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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],
|