investing-algorithm-framework 8.6.1__tar.gz → 8.7.0__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.
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/PKG-INFO +5 -1
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/README.md +1 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/__init__.py +20 -1
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/eventloop.py +262 -1
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/backtest_report.py +53 -7
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/strategy.py +59 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/cli.py +70 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/__init__.py +42 -1
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/__init__.py +19 -2
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest.py +125 -3
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest_metrics.py +47 -19
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +53 -2
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest_run.py +124 -103
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +8 -1
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/backtesting/backtest_utils.py +713 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/backtesting/bundle.py +351 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/datetime_parsing.py +29 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/order/order.py +5 -2
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +5 -4
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/trade/trade.py +7 -4
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +9 -7
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/trade/trade_take_profit.py +8 -5
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/__init__.py +40 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/custom_factor.py +34 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/factor.py +538 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/factors/__init__.py +26 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/factors/builtin.py +496 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/filter.py +98 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/domain/pipeline/pipeline.py +142 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +41 -17
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +23 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +80 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/generate.py +61 -20
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/sharpe_ratio.py +6 -2
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/services/pipeline/__init__.py +5 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/services/pipeline/pipeline_engine.py +174 -0
- investing_algorithm_framework-8.7.0/investing_algorithm_framework/services/pipeline/vector_pipeline_engine.py +219 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/pyproject.toml +4 -1
- investing_algorithm_framework-8.6.1/investing_algorithm_framework/domain/backtesting/backtest_utils.py +0 -297
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/LICENSE +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/analysis/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/analysis/backtest_data_ranges.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/analysis/markdown.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/analysis/ranking.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/algorithm/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/algorithm/algorithm.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/algorithm/algorithm_factory.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/app.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/app_hook.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/context.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/ascii.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/backtest_report_old.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/equity_curve.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/line_chart.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/generate.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/trades_table.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/tables/utils.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/templates/dashboard.css +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/templates/dashboard.js +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/templates/dashboard_template.html.j2 +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/task.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/create_app.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/error_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/responses.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/deploy_to_aws_lambda.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/deploy_to_azure_function.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/initialize_app.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/mcp_server.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/.gitignore.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/app.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/app_azure_function.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/app_web.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/azure_function_host.json.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/data_providers.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/env.example.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/env_azure_function.example.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/market_data_providers.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/readme.md.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/requirements.txt.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/run_backtest.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/templates/strategy.py.template +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/cli/validate_backtest_checkpoints.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/create_app.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/dependency_container.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/algorithm_id.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest_date_range.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/combine_backtests.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/consistency.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/templates/backtest.html +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/templates/finterion-dark.png +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/backtesting/templates/finterion-light.png +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/blotter.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/config.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/constants.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/data_provider.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/data_structures.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/exceptions.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/fx.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/app_mode.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/base_model.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/data/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/data/data_source.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/data/data_type.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/event.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/position/position.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/position/position_size.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/risk_rules/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/risk_rules/scaling_rule.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/risk_rules/trading_cost.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/snapshot_interval.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/tracing/trace.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/trade/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/models/trade/trade_status.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/order_executor.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/portfolio_provider.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/services/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/services/rounding_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/services/state_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/strategy.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/csv.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/custom_tqdm.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/dates.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/polars.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/random.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/download_data.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/alpha_vantage.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/base_url.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/ccxt.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/csv.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/csv_url.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/json_url.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/ohlcv_base.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/pandas.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/parquet_url.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/polygon.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/data_providers/yahoo.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/order/order.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/order/trade_allocation.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/order_trade_association.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/trades/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/trades/trade.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/order_executors/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/trade_allocation_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/trade_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/aws/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/aws/state_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/azure/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/azure/state_handler.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/infrastructure/services/backtesting/checkpoint_manifest.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/notebook/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/notebook/magic.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/configuration_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/data_providers/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/data_providers/data.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/data_providers/data_provider_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/alpha.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/beta.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/cagr.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/calmar_ratio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/consistency.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/drawdown.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/equity_curve.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/exposure.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/mean_daily_return.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/price_efficiency.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/profit_factor.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/recovery.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/returns.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/risk_free_rate.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/sortino_ratio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/standard_deviation.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/trades.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/volatility.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/metrics/win_rate.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/order_service/order_backtest_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/order_service/order_executor_lookup.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/order_service/order_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/portfolio_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/positions/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/positions/position_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/positions/position_snapshot_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/repository_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_order_evaluator/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_service/__init__.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_service/trade_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +0 -0
- {investing_algorithm_framework-8.6.1 → investing_algorithm_framework-8.7.0}/investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: investing-algorithm-framework
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.7.0
|
|
4
4
|
Summary: A framework for creating trading bots
|
|
5
5
|
Author: MDUYN
|
|
6
6
|
Requires-Python: >=3.10,<4.0
|
|
@@ -27,9 +27,11 @@ Requires-Dist: ccxt (>=4.2.48)
|
|
|
27
27
|
Requires-Dist: dependency-injector (>=4.40.0)
|
|
28
28
|
Requires-Dist: jupyter (>=1.0.0)
|
|
29
29
|
Requires-Dist: marshmallow (>=3.5.0)
|
|
30
|
+
Requires-Dist: msgpack (>=1.0.0)
|
|
30
31
|
Requires-Dist: plotly (>=6.1.2,<7.0.0)
|
|
31
32
|
Requires-Dist: polars[numpy,pandas] (>=0.20.10)
|
|
32
33
|
Requires-Dist: polygon-api-client (>=1.14.0,<2.0.0) ; extra == "polygon" or extra == "all"
|
|
34
|
+
Requires-Dist: pyarrow (>=14.0.0)
|
|
33
35
|
Requires-Dist: python-dateutil (>=2.8.2)
|
|
34
36
|
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
35
37
|
Requires-Dist: schedule (>=1.1.0)
|
|
@@ -37,6 +39,7 @@ Requires-Dist: tabulate (>=0.9.0)
|
|
|
37
39
|
Requires-Dist: tqdm (>=4.66.1)
|
|
38
40
|
Requires-Dist: wrapt (>=1.16.0)
|
|
39
41
|
Requires-Dist: yfinance (>=0.2.61,<0.3.0) ; extra == "yahoo" or extra == "all"
|
|
42
|
+
Requires-Dist: zstandard (>=0.20.0)
|
|
40
43
|
Description-Content-Type: text/markdown
|
|
41
44
|
|
|
42
45
|
<h1 align="center">
|
|
@@ -124,6 +127,7 @@ This framework is built around the full loop: **create strategies → vector bac
|
|
|
124
127
|
- 🎯 **Return Scenario Projections** — Good, average, bad & very bad year projections from backtest data
|
|
125
128
|
- 📉 **Benchmark Comparison** — Beat-rate analysis vs Buy & Hold, DCA, risk-free & custom benchmarks
|
|
126
129
|
- 📄 **One-Click HTML Report** — Self-contained file, no server, dark & light theme, shareable
|
|
130
|
+
- 📦 **Custom `.iafbt` Backtest Bundle Format** — An explicit, versioned, compressed, language-portable container (zstd + msgpack with magic-byte header) plus a separate parquet index for fast filtering without loading. ~21× smaller and ~27× fewer files than standard filebased directory layouts, with parallel I/O for fast load/save of large amounts of backtests.
|
|
127
131
|
- 🌐 **Load External Data** — Fetch CSV, JSON, or Parquet from any URL with caching and auto-refresh
|
|
128
132
|
- � **[Record Custom Variables](https://coding-kitties.github.io/investing-algorithm-framework/Advanced%20Concepts/recording-variables)** — Track any indicator or metric during backtests with `context.record()`
|
|
129
133
|
- �🚀 **Build → Backtest → Deploy** — Local dev, cloud deploy (AWS / Azure), or monetize on Finterion
|
|
@@ -83,6 +83,7 @@ This framework is built around the full loop: **create strategies → vector bac
|
|
|
83
83
|
- 🎯 **Return Scenario Projections** — Good, average, bad & very bad year projections from backtest data
|
|
84
84
|
- 📉 **Benchmark Comparison** — Beat-rate analysis vs Buy & Hold, DCA, risk-free & custom benchmarks
|
|
85
85
|
- 📄 **One-Click HTML Report** — Self-contained file, no server, dark & light theme, shareable
|
|
86
|
+
- 📦 **Custom `.iafbt` Backtest Bundle Format** — An explicit, versioned, compressed, language-portable container (zstd + msgpack with magic-byte header) plus a separate parquet index for fast filtering without loading. ~21× smaller and ~27× fewer files than standard filebased directory layouts, with parallel I/O for fast load/save of large amounts of backtests.
|
|
86
87
|
- 🌐 **Load External Data** — Fetch CSV, JSON, or Parquet from any URL with caching and auto-refresh
|
|
87
88
|
- � **[Record Custom Variables](https://coding-kitties.github.io/investing-algorithm-framework/Advanced%20Concepts/recording-variables)** — Track any indicator or metric during backtests with `context.record()`
|
|
88
89
|
- �🚀 **Build → Backtest → Deploy** — Local dev, cloud deploy (AWS / Azure), or monetize on Finterion
|
|
@@ -30,7 +30,11 @@ from .domain import ApiException, combine_backtests, PositionSize, \
|
|
|
30
30
|
VolumeImpactSlippage, \
|
|
31
31
|
CommissionModel, NoCommission, PercentageCommission, FixedCommission, \
|
|
32
32
|
FillModel, FullFill, VolumeBasedFill, \
|
|
33
|
-
FXRateProvider, StaticFXRateProvider
|
|
33
|
+
FXRateProvider, StaticFXRateProvider, \
|
|
34
|
+
Pipeline, Factor, CustomFactor, Filter, \
|
|
35
|
+
Returns, AverageDollarVolume, AverageTradedValue, SMA, RSI, \
|
|
36
|
+
Volatility, StaticPerSymbol, CrossSectionalMean, RollingBeta, \
|
|
37
|
+
Neutralize
|
|
34
38
|
from .infrastructure import AzureBlobStorageStateHandler, \
|
|
35
39
|
CSVOHLCVDataProvider, CSVTickerDataProvider, CSVURLDataProvider, \
|
|
36
40
|
JSONURLDataProvider, ParquetURLDataProvider, \
|
|
@@ -256,6 +260,21 @@ __all__ = [
|
|
|
256
260
|
"VolumeBasedFill",
|
|
257
261
|
"FXRateProvider",
|
|
258
262
|
"StaticFXRateProvider",
|
|
263
|
+
# Pipeline API (Phase 1, see docs/design/pipeline-api.md)
|
|
264
|
+
"Pipeline",
|
|
265
|
+
"Factor",
|
|
266
|
+
"CustomFactor",
|
|
267
|
+
"Filter",
|
|
268
|
+
"Returns",
|
|
269
|
+
"AverageDollarVolume",
|
|
270
|
+
"AverageTradedValue",
|
|
271
|
+
"SMA",
|
|
272
|
+
"RSI",
|
|
273
|
+
"Volatility",
|
|
274
|
+
"StaticPerSymbol",
|
|
275
|
+
"CrossSectionalMean",
|
|
276
|
+
"RollingBeta",
|
|
277
|
+
"Neutralize",
|
|
259
278
|
"load_ipython_extension",
|
|
260
279
|
"get_cv_consistency",
|
|
261
280
|
"get_normalized_stability",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from datetime import datetime, timedelta, timezone
|
|
2
2
|
from time import sleep
|
|
3
|
-
from typing import List, Set, Dict
|
|
3
|
+
from typing import List, Set, Dict, FrozenSet, Tuple, Optional, Type
|
|
4
4
|
from logging import getLogger
|
|
5
5
|
|
|
6
6
|
import polars as pl
|
|
@@ -10,6 +10,7 @@ from investing_algorithm_framework.domain import Environment, ENVIRONMENT, \
|
|
|
10
10
|
TradeStatus, SNAPSHOT_INTERVAL, SnapshotInterval, OperationalException, \
|
|
11
11
|
LAST_SNAPSHOT_DATETIME, INDEX_DATETIME
|
|
12
12
|
from investing_algorithm_framework.services import TradeOrderEvaluator
|
|
13
|
+
from investing_algorithm_framework.services.pipeline import PipelineEngine
|
|
13
14
|
|
|
14
15
|
from .algorithm import Algorithm
|
|
15
16
|
from .strategy import TradingStrategy
|
|
@@ -82,6 +83,19 @@ class EventLoopService:
|
|
|
82
83
|
self.data_sources = set()
|
|
83
84
|
self.next_run_times = {}
|
|
84
85
|
self.history = {}
|
|
86
|
+
self._pipeline_engine = PipelineEngine()
|
|
87
|
+
|
|
88
|
+
# Per (strategy_id, pipeline_cls) cache of the most recent
|
|
89
|
+
# universe-refresh: (refresh_at, frozen surviving-symbol set).
|
|
90
|
+
# Populated when a pipeline declares
|
|
91
|
+
# ``refresh_universe_every`` so the engine can skip re-running
|
|
92
|
+
# the universe filter every bar.
|
|
93
|
+
self._pipeline_universe_cache: Dict[
|
|
94
|
+
Tuple[str, Type], Tuple[datetime, FrozenSet[str]]
|
|
95
|
+
] = {}
|
|
96
|
+
# One-shot flag: live-mode envelope validation runs once per
|
|
97
|
+
# process. Reset by ``cleanup`` so a new run re-validates.
|
|
98
|
+
self._pipelines_live_validated: bool = False
|
|
85
99
|
|
|
86
100
|
@staticmethod
|
|
87
101
|
def _get_data_sources_for_iteration(
|
|
@@ -330,6 +344,11 @@ class EventLoopService:
|
|
|
330
344
|
None
|
|
331
345
|
"""
|
|
332
346
|
self._portfolio_snapshot_service.save_all(self._snapshots)
|
|
347
|
+
# Reset per-run pipeline state so a subsequent run re-runs
|
|
348
|
+
# live envelope validation and starts with a fresh universe
|
|
349
|
+
# cache.
|
|
350
|
+
self._pipeline_universe_cache.clear()
|
|
351
|
+
self._pipelines_live_validated = False
|
|
333
352
|
|
|
334
353
|
def start(
|
|
335
354
|
self,
|
|
@@ -443,6 +462,232 @@ class EventLoopService:
|
|
|
443
462
|
|
|
444
463
|
self.cleanup()
|
|
445
464
|
|
|
465
|
+
# ------------------------------------------------------------------ #
|
|
466
|
+
# Pipeline live-mode helpers (#503 phase 3b/3c/3d)
|
|
467
|
+
# ------------------------------------------------------------------ #
|
|
468
|
+
# Envelope: v1 of live pipelines supports daily timeframes only and
|
|
469
|
+
# caps universes at 50 symbols per pipeline. Any sub-daily timeframe
|
|
470
|
+
# on a strategy that declares pipelines, or a strategy whose total
|
|
471
|
+
# OHLCV symbol set exceeds the cap, raises at first iteration when
|
|
472
|
+
# running outside backtest mode. See #503.
|
|
473
|
+
_LIVE_MAX_PIPELINE_SYMBOLS: int = 50
|
|
474
|
+
_LIVE_MIN_TIMEFRAME_MINUTES: int = 24 * 60 # daily
|
|
475
|
+
|
|
476
|
+
def _validate_live_envelope(
|
|
477
|
+
self, strategies: List[TradingStrategy]
|
|
478
|
+
) -> None:
|
|
479
|
+
"""Validate the v1 live-pipeline envelope (max 50 symbols /
|
|
480
|
+
daily-or-coarser timeframes). Called once per run when env is
|
|
481
|
+
not BACKTEST. Raises :class:`OperationalException` on
|
|
482
|
+
violation."""
|
|
483
|
+
for strategy in strategies or []:
|
|
484
|
+
pipelines = getattr(strategy, "pipelines", None)
|
|
485
|
+
if not pipelines:
|
|
486
|
+
continue
|
|
487
|
+
|
|
488
|
+
ohlcv_sources = [
|
|
489
|
+
ds for ds in (strategy.data_sources or [])
|
|
490
|
+
if DataType.OHLCV.equals(ds.data_type)
|
|
491
|
+
]
|
|
492
|
+
|
|
493
|
+
sub_daily = [
|
|
494
|
+
ds for ds in ohlcv_sources
|
|
495
|
+
if ds.time_frame is not None
|
|
496
|
+
and ds.time_frame.amount_of_minutes
|
|
497
|
+
< self._LIVE_MIN_TIMEFRAME_MINUTES
|
|
498
|
+
]
|
|
499
|
+
if sub_daily:
|
|
500
|
+
desc = ", ".join(
|
|
501
|
+
f"{ds.symbol}@{ds.time_frame.value}"
|
|
502
|
+
for ds in sub_daily
|
|
503
|
+
)
|
|
504
|
+
raise OperationalException(
|
|
505
|
+
f"Strategy '{strategy.strategy_id}' declares "
|
|
506
|
+
f"pipelines but uses sub-daily OHLCV timeframes "
|
|
507
|
+
f"in live mode: {desc}. v1 of the live pipeline "
|
|
508
|
+
f"engine supports daily timeframes only — see "
|
|
509
|
+
f"#503. Use a daily timeframe or run the strategy "
|
|
510
|
+
f"in backtest mode."
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
unique_symbols = {ds.symbol for ds in ohlcv_sources}
|
|
514
|
+
unique_symbols.discard(None)
|
|
515
|
+
if len(unique_symbols) > self._LIVE_MAX_PIPELINE_SYMBOLS:
|
|
516
|
+
raise OperationalException(
|
|
517
|
+
f"Strategy '{strategy.strategy_id}' declares "
|
|
518
|
+
f"pipelines over {len(unique_symbols)} symbols, "
|
|
519
|
+
f"which exceeds the v1 live cap of "
|
|
520
|
+
f"{self._LIVE_MAX_PIPELINE_SYMBOLS}. Reduce the "
|
|
521
|
+
f"universe or run the strategy in backtest mode "
|
|
522
|
+
f"(see #503)."
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
def _maybe_validate_live_envelope(
|
|
526
|
+
self, strategies: List[TradingStrategy], environment: str
|
|
527
|
+
) -> None:
|
|
528
|
+
"""One-shot envelope validation; no-op for BACKTEST mode."""
|
|
529
|
+
if self._pipelines_live_validated:
|
|
530
|
+
return
|
|
531
|
+
if Environment.BACKTEST.equals(environment):
|
|
532
|
+
self._pipelines_live_validated = True
|
|
533
|
+
return
|
|
534
|
+
self._validate_live_envelope(strategies)
|
|
535
|
+
self._pipelines_live_validated = True
|
|
536
|
+
|
|
537
|
+
def _filter_symbols_for_universe_cache(
|
|
538
|
+
self,
|
|
539
|
+
strategy_id: str,
|
|
540
|
+
pipeline_cls: Type,
|
|
541
|
+
symbol_to_identifier: Dict[str, str],
|
|
542
|
+
as_of: datetime,
|
|
543
|
+
) -> Optional[Dict[str, str]]:
|
|
544
|
+
"""If ``pipeline_cls`` declares ``refresh_universe_every`` and
|
|
545
|
+
we have a cached surviving-symbol set still inside the cadence,
|
|
546
|
+
return a restricted ``symbol_to_identifier`` mapping. Returning
|
|
547
|
+
``None`` means "no cache hit — run a full universe evaluation".
|
|
548
|
+
"""
|
|
549
|
+
cadence: Optional[timedelta] = getattr(
|
|
550
|
+
pipeline_cls, "refresh_universe_every", None
|
|
551
|
+
)
|
|
552
|
+
if cadence is None or cadence <= timedelta(0):
|
|
553
|
+
return None
|
|
554
|
+
|
|
555
|
+
cache_key = (strategy_id, pipeline_cls)
|
|
556
|
+
cached = self._pipeline_universe_cache.get(cache_key)
|
|
557
|
+
if cached is None:
|
|
558
|
+
return None
|
|
559
|
+
|
|
560
|
+
last_refresh, symbols = cached
|
|
561
|
+
# Normalise tz so naive backtest datetimes and aware live
|
|
562
|
+
# datetimes compare cleanly.
|
|
563
|
+
if last_refresh.tzinfo is None and as_of.tzinfo is not None:
|
|
564
|
+
cmp_as_of = as_of.replace(tzinfo=None)
|
|
565
|
+
elif last_refresh.tzinfo is not None and as_of.tzinfo is None:
|
|
566
|
+
cmp_as_of = as_of.replace(tzinfo=last_refresh.tzinfo)
|
|
567
|
+
else:
|
|
568
|
+
cmp_as_of = as_of
|
|
569
|
+
if cmp_as_of - last_refresh >= cadence:
|
|
570
|
+
return None # cadence elapsed → refresh
|
|
571
|
+
|
|
572
|
+
# Cache hit: restrict the symbol set, skipping the universe
|
|
573
|
+
# filter entirely on this iteration.
|
|
574
|
+
return {
|
|
575
|
+
sym: ident
|
|
576
|
+
for sym, ident in symbol_to_identifier.items()
|
|
577
|
+
if sym in symbols
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
def _run_pipelines(
|
|
581
|
+
self,
|
|
582
|
+
strategy: TradingStrategy,
|
|
583
|
+
data: Dict,
|
|
584
|
+
data_object: Dict,
|
|
585
|
+
as_of: datetime,
|
|
586
|
+
) -> None:
|
|
587
|
+
"""Compute cross-sectional pipelines attached to ``strategy``
|
|
588
|
+
and inject their outputs into ``data`` keyed by pipeline
|
|
589
|
+
class name.
|
|
590
|
+
|
|
591
|
+
Strategies without ``pipelines`` skip this entirely (zero cost).
|
|
592
|
+
|
|
593
|
+
Live-mode hardening (#503):
|
|
594
|
+
|
|
595
|
+
* The v1 envelope (max 50 symbols, daily-or-coarser timeframes)
|
|
596
|
+
is validated once per run.
|
|
597
|
+
* Pipelines that declare ``refresh_universe_every`` reuse the
|
|
598
|
+
last surviving symbol set within the cadence — saving the
|
|
599
|
+
cost of evaluating the universe filter every bar.
|
|
600
|
+
* In non-backtest environments, a single failing pipeline is
|
|
601
|
+
logged and skipped (the iteration continues with an empty
|
|
602
|
+
output) instead of killing the whole event loop. Backtests
|
|
603
|
+
keep raising so failures stay deterministic.
|
|
604
|
+
"""
|
|
605
|
+
pipelines = getattr(strategy, "pipelines", None)
|
|
606
|
+
if not pipelines:
|
|
607
|
+
return
|
|
608
|
+
|
|
609
|
+
config = self._configuration_service.get_config()
|
|
610
|
+
environment = config[ENVIRONMENT]
|
|
611
|
+
is_backtest = Environment.BACKTEST.equals(environment)
|
|
612
|
+
|
|
613
|
+
# Map symbol -> data-source identifier from the strategy's
|
|
614
|
+
# OHLCV data sources. If a symbol appears on multiple data
|
|
615
|
+
# sources (e.g. multiple timeframes) the first OHLCV match wins.
|
|
616
|
+
symbol_to_identifier: Dict[str, str] = {}
|
|
617
|
+
for ds in strategy.data_sources or []:
|
|
618
|
+
if not DataType.OHLCV.equals(ds.data_type):
|
|
619
|
+
continue
|
|
620
|
+
if ds.symbol is None or ds.symbol in symbol_to_identifier:
|
|
621
|
+
continue
|
|
622
|
+
symbol_to_identifier[ds.symbol] = ds.get_identifier()
|
|
623
|
+
|
|
624
|
+
if not symbol_to_identifier:
|
|
625
|
+
logger.warning(
|
|
626
|
+
"Strategy %s declares pipelines but has no OHLCV data "
|
|
627
|
+
"sources to feed them; pipelines will be skipped.",
|
|
628
|
+
strategy.strategy_id,
|
|
629
|
+
)
|
|
630
|
+
return
|
|
631
|
+
|
|
632
|
+
for pipeline_cls in pipelines:
|
|
633
|
+
# 3c: universe-refresh cache. If the pipeline declares a
|
|
634
|
+
# refresh cadence and we're inside it, restrict the panel
|
|
635
|
+
# input to the cached symbols.
|
|
636
|
+
cached_mapping = self._filter_symbols_for_universe_cache(
|
|
637
|
+
strategy_id=strategy.strategy_id,
|
|
638
|
+
pipeline_cls=pipeline_cls,
|
|
639
|
+
symbol_to_identifier=symbol_to_identifier,
|
|
640
|
+
as_of=as_of,
|
|
641
|
+
)
|
|
642
|
+
mapping = (
|
|
643
|
+
cached_mapping
|
|
644
|
+
if cached_mapping is not None
|
|
645
|
+
else symbol_to_identifier
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
try:
|
|
649
|
+
output = self._pipeline_engine.evaluate(
|
|
650
|
+
pipeline_cls=pipeline_cls,
|
|
651
|
+
data_object=data_object,
|
|
652
|
+
symbol_to_identifier=mapping,
|
|
653
|
+
as_of=as_of,
|
|
654
|
+
)
|
|
655
|
+
except Exception:
|
|
656
|
+
# 3d: live-mode resilience. In live trading a single
|
|
657
|
+
# pipeline failure must not kill the iteration —
|
|
658
|
+
# surface an empty frame and log so the rest of the
|
|
659
|
+
# strategies can still run. Backtests re-raise so
|
|
660
|
+
# failures stay deterministic.
|
|
661
|
+
logger.exception(
|
|
662
|
+
"Pipeline %s failed during evaluation at %s",
|
|
663
|
+
pipeline_cls.__name__,
|
|
664
|
+
as_of,
|
|
665
|
+
)
|
|
666
|
+
if is_backtest:
|
|
667
|
+
raise
|
|
668
|
+
output = self._pipeline_engine._empty_output(
|
|
669
|
+
pipeline_cls
|
|
670
|
+
)
|
|
671
|
+
|
|
672
|
+
# 3c: refresh the universe cache when we just ran a full
|
|
673
|
+
# evaluation (cached_mapping was None) and the pipeline
|
|
674
|
+
# declares a cadence.
|
|
675
|
+
cadence = getattr(
|
|
676
|
+
pipeline_cls, "refresh_universe_every", None
|
|
677
|
+
)
|
|
678
|
+
if (
|
|
679
|
+
cadence is not None
|
|
680
|
+
and cadence > timedelta(0)
|
|
681
|
+
and cached_mapping is None
|
|
682
|
+
and "symbol" in output.columns
|
|
683
|
+
):
|
|
684
|
+
surviving = frozenset(output["symbol"].to_list())
|
|
685
|
+
self._pipeline_universe_cache[
|
|
686
|
+
(strategy.strategy_id, pipeline_cls)
|
|
687
|
+
] = (as_of, surviving)
|
|
688
|
+
|
|
689
|
+
data[pipeline_cls.__name__] = output
|
|
690
|
+
|
|
446
691
|
def _run_iteration(
|
|
447
692
|
self,
|
|
448
693
|
strategies: List[TradingStrategy] = None,
|
|
@@ -470,6 +715,11 @@ class EventLoopService:
|
|
|
470
715
|
environment = config[ENVIRONMENT]
|
|
471
716
|
current_datetime = config[INDEX_DATETIME]
|
|
472
717
|
|
|
718
|
+
# Validate the live-pipeline envelope (max 50 symbols /
|
|
719
|
+
# daily-or-coarser timeframes) once per run. No-op for
|
|
720
|
+
# backtests. See #503 phase 3b.
|
|
721
|
+
self._maybe_validate_live_envelope(strategies, environment)
|
|
722
|
+
|
|
473
723
|
# Step 1: Collect all data for the strategies and for the
|
|
474
724
|
# pending orders
|
|
475
725
|
open_orders = self._order_service.get_all(
|
|
@@ -553,6 +803,17 @@ class EventLoopService:
|
|
|
553
803
|
else:
|
|
554
804
|
data = {}
|
|
555
805
|
|
|
806
|
+
# Step 5b: Run any cross-sectional pipelines attached to
|
|
807
|
+
# the strategy (Phase 1 of the Pipeline API, see
|
|
808
|
+
# docs/design/pipeline-api.md). Strategies without
|
|
809
|
+
# ``pipelines`` skip this entirely.
|
|
810
|
+
self._run_pipelines(
|
|
811
|
+
strategy=strategy,
|
|
812
|
+
data=data,
|
|
813
|
+
data_object=data_object,
|
|
814
|
+
as_of=current_datetime,
|
|
815
|
+
)
|
|
816
|
+
|
|
556
817
|
for on_strategy_run_hook in \
|
|
557
818
|
self._algorithm.on_strategy_run_hooks:
|
|
558
819
|
on_strategy_run_hook.execute(
|
|
@@ -12,7 +12,7 @@ from datetime import datetime, timedelta
|
|
|
12
12
|
from jinja2 import Environment, FileSystemLoader
|
|
13
13
|
|
|
14
14
|
from investing_algorithm_framework.domain import (
|
|
15
|
-
Backtest, OperationalException, tqdm
|
|
15
|
+
Backtest, OperationalException, tqdm, BUNDLE_EXT
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
@@ -217,9 +217,15 @@ class BacktestReport:
|
|
|
217
217
|
|
|
218
218
|
@staticmethod
|
|
219
219
|
def _is_backtest(backtest_path):
|
|
220
|
+
if not os.path.exists(backtest_path):
|
|
221
|
+
return False
|
|
222
|
+
# Bundle file (.iafbt)
|
|
223
|
+
if os.path.isfile(backtest_path) and \
|
|
224
|
+
backtest_path.endswith(BUNDLE_EXT):
|
|
225
|
+
return True
|
|
226
|
+
# Legacy directory layout
|
|
220
227
|
return (
|
|
221
|
-
os.path.
|
|
222
|
-
and os.path.isdir(backtest_path)
|
|
228
|
+
os.path.isdir(backtest_path)
|
|
223
229
|
and os.path.isfile(
|
|
224
230
|
os.path.join(backtest_path, "algorithm_id.json")
|
|
225
231
|
)
|
|
@@ -231,6 +237,7 @@ class BacktestReport:
|
|
|
231
237
|
backtests: List[Backtest] = None,
|
|
232
238
|
directory_path: Union[str, List[str], None] = None,
|
|
233
239
|
show_progress: bool = False,
|
|
240
|
+
workers: Union[int, None] = None,
|
|
234
241
|
) -> "BacktestReport":
|
|
235
242
|
loaded = []
|
|
236
243
|
source_tags = []
|
|
@@ -254,7 +261,7 @@ class BacktestReport:
|
|
|
254
261
|
if BacktestReport._is_backtest(dp):
|
|
255
262
|
backtest_paths.append((dp, tag))
|
|
256
263
|
else:
|
|
257
|
-
for root, dirs,
|
|
264
|
+
for root, dirs, files in os.walk(dp):
|
|
258
265
|
for dir_name in dirs:
|
|
259
266
|
subdir = os.path.join(
|
|
260
267
|
root, dir_name
|
|
@@ -265,6 +272,11 @@ class BacktestReport:
|
|
|
265
272
|
backtest_paths.append(
|
|
266
273
|
(subdir, tag)
|
|
267
274
|
)
|
|
275
|
+
for file_name in files:
|
|
276
|
+
if file_name.endswith(BUNDLE_EXT):
|
|
277
|
+
backtest_paths.append(
|
|
278
|
+
(os.path.join(root, file_name), tag)
|
|
279
|
+
)
|
|
268
280
|
|
|
269
281
|
iterator = backtest_paths
|
|
270
282
|
if show_progress:
|
|
@@ -273,9 +285,43 @@ class BacktestReport:
|
|
|
273
285
|
desc="Loading backtests",
|
|
274
286
|
)
|
|
275
287
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
288
|
+
# Parallel load is opt-in (workers > 1). ProcessPoolExecutor
|
|
289
|
+
# startup costs typically dwarf the per-backtest decode for
|
|
290
|
+
# batches < ~30, so keep default behaviour serial. Pass
|
|
291
|
+
# ``workers=N`` (or ``-1`` for cpu_count) to load large
|
|
292
|
+
# batches in parallel.
|
|
293
|
+
from investing_algorithm_framework.domain.backtesting.\
|
|
294
|
+
backtest_utils import (
|
|
295
|
+
_load_one_dispatch, _resolve_workers,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
n = len(backtest_paths)
|
|
299
|
+
resolved_workers = (
|
|
300
|
+
_resolve_workers(workers) if workers is not None else 1
|
|
301
|
+
)
|
|
302
|
+
if resolved_workers > 1 and n >= 4:
|
|
303
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
304
|
+
|
|
305
|
+
items = [
|
|
306
|
+
(path, "bundle" if path.endswith(BUNDLE_EXT) else "dir")
|
|
307
|
+
for path, _ in backtest_paths
|
|
308
|
+
]
|
|
309
|
+
with ProcessPoolExecutor(max_workers=resolved_workers) as ex:
|
|
310
|
+
results = list(
|
|
311
|
+
tqdm(
|
|
312
|
+
ex.map(_load_one_dispatch, items),
|
|
313
|
+
total=n,
|
|
314
|
+
desc="Loading backtests",
|
|
315
|
+
disable=not show_progress,
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
for bt, (_, tag) in zip(results, backtest_paths):
|
|
319
|
+
loaded.append(bt)
|
|
320
|
+
source_tags.append(tag)
|
|
321
|
+
else:
|
|
322
|
+
for path, tag in iterator:
|
|
323
|
+
loaded.append(Backtest.open(path))
|
|
324
|
+
source_tags.append(tag)
|
|
279
325
|
|
|
280
326
|
for bt in backtests:
|
|
281
327
|
if not isinstance(bt, Backtest):
|
|
@@ -48,6 +48,7 @@ class TradingStrategy:
|
|
|
48
48
|
strategy_id: str = None
|
|
49
49
|
decorated = None
|
|
50
50
|
data_sources: List[DataSource] = []
|
|
51
|
+
pipelines: List[type] = []
|
|
51
52
|
traces = None
|
|
52
53
|
context: Context = None
|
|
53
54
|
metadata: Dict[str, Any] = None
|
|
@@ -131,6 +132,13 @@ class TradingStrategy:
|
|
|
131
132
|
self.data_sources = list(class_data_sources) \
|
|
132
133
|
if class_data_sources else []
|
|
133
134
|
|
|
135
|
+
# Initialize pipelines as a new list per instance. Pipelines
|
|
136
|
+
# are class-attribute opt-in (Phase 1 of the Pipeline API,
|
|
137
|
+
# see docs/design/pipeline-api.md). When empty, the engine
|
|
138
|
+
# is never invoked and there is zero behavioural change.
|
|
139
|
+
class_pipelines = getattr(self.__class__, 'pipelines', [])
|
|
140
|
+
self.pipelines = list(class_pipelines) if class_pipelines else []
|
|
141
|
+
|
|
134
142
|
if decorated is not None:
|
|
135
143
|
self.decorated = decorated
|
|
136
144
|
|
|
@@ -186,6 +194,57 @@ class TradingStrategy:
|
|
|
186
194
|
f"interval or use a smaller data timeframe."
|
|
187
195
|
)
|
|
188
196
|
|
|
197
|
+
# Validate that every declared pipeline has enough warmup on
|
|
198
|
+
# the strategy's OHLCV data sources to compute its longest
|
|
199
|
+
# factor window. Without this check a live strategy starts
|
|
200
|
+
# silently emitting NaN columns until enough bars accrue.
|
|
201
|
+
# Tracked under #503 (Phase 3 — live hardening).
|
|
202
|
+
if self.pipelines:
|
|
203
|
+
ohlcv_sources = [
|
|
204
|
+
ds for ds in self.data_sources
|
|
205
|
+
if DataType.OHLCV.equals(ds.data_type)
|
|
206
|
+
]
|
|
207
|
+
if not ohlcv_sources:
|
|
208
|
+
raise OperationalException(
|
|
209
|
+
f"Strategy '{self.strategy_id}' declares "
|
|
210
|
+
f"{len(self.pipelines)} pipeline(s) but has no "
|
|
211
|
+
f"OHLCV data sources. Pipelines build their panel "
|
|
212
|
+
f"from the strategy's OHLCV data sources — add at "
|
|
213
|
+
f"least one DataSource(data_type=DataType.OHLCV, "
|
|
214
|
+
f"...) to data_sources."
|
|
215
|
+
)
|
|
216
|
+
for pipeline_cls in self.pipelines:
|
|
217
|
+
required = pipeline_cls.required_window()
|
|
218
|
+
# We compare against each OHLCV source's warmup_window
|
|
219
|
+
# (canonical) / window_size (legacy alias) — the
|
|
220
|
+
# framework keeps them in sync, but a source may
|
|
221
|
+
# legitimately leave both unset, which we treat as
|
|
222
|
+
# "insufficient" because the pipeline cannot guarantee
|
|
223
|
+
# a full window of data.
|
|
224
|
+
short_sources = [
|
|
225
|
+
ds for ds in ohlcv_sources
|
|
226
|
+
if ds.warmup_window is None
|
|
227
|
+
or ds.warmup_window < required
|
|
228
|
+
]
|
|
229
|
+
if short_sources:
|
|
230
|
+
short_desc = ", ".join(
|
|
231
|
+
f"{ds.symbol}@{ds.time_frame.value if ds.time_frame else '?'}" # noqa: E501
|
|
232
|
+
f" (warmup_window="
|
|
233
|
+
f"{ds.warmup_window if ds.warmup_window is not None else 'unset'})" # noqa: E501
|
|
234
|
+
for ds in short_sources
|
|
235
|
+
)
|
|
236
|
+
raise OperationalException(
|
|
237
|
+
f"Strategy '{self.strategy_id}' pipeline "
|
|
238
|
+
f"'{pipeline_cls.__name__}' requires a "
|
|
239
|
+
f"warmup window of {required} bars but the "
|
|
240
|
+
f"following OHLCV data source(s) have an "
|
|
241
|
+
f"insufficient warmup_window: {short_desc}. "
|
|
242
|
+
f"Set warmup_window>={required} on each OHLCV "
|
|
243
|
+
f"DataSource the pipeline relies on, otherwise "
|
|
244
|
+
f"the pipeline will emit NaN columns until "
|
|
245
|
+
f"enough bars accrue."
|
|
246
|
+
)
|
|
247
|
+
|
|
189
248
|
# Initialize stop_losses as a new list per instance
|
|
190
249
|
if stop_losses is not None:
|
|
191
250
|
self.stop_losses = list(stop_losses)
|
|
@@ -250,3 +250,73 @@ def mcp(directory):
|
|
|
250
250
|
|
|
251
251
|
|
|
252
252
|
cli.add_command(mcp)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@click.command(name="migrate-backtests")
|
|
256
|
+
@click.option(
|
|
257
|
+
"--src", "-s",
|
|
258
|
+
required=True,
|
|
259
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
260
|
+
help="Source directory containing legacy backtest sub-directories.",
|
|
261
|
+
)
|
|
262
|
+
@click.option(
|
|
263
|
+
"--dst", "-d",
|
|
264
|
+
required=True,
|
|
265
|
+
type=click.Path(file_okay=False, dir_okay=True),
|
|
266
|
+
help="Destination directory for the new ``.iafbt`` bundle files.",
|
|
267
|
+
)
|
|
268
|
+
@click.option(
|
|
269
|
+
"--workers", "-w", type=int, default=None,
|
|
270
|
+
help="Number of parallel workers (default: min(8, CPU count)).",
|
|
271
|
+
)
|
|
272
|
+
@click.option(
|
|
273
|
+
"--no-index", is_flag=True, default=False,
|
|
274
|
+
help="Skip writing index.parquet at the destination.",
|
|
275
|
+
)
|
|
276
|
+
@click.option(
|
|
277
|
+
"--include-ohlcv", is_flag=True, default=False,
|
|
278
|
+
help="Include OHLCV data in the destination bundles.",
|
|
279
|
+
)
|
|
280
|
+
@click.option(
|
|
281
|
+
"--no-skip-existing", is_flag=True, default=False,
|
|
282
|
+
help="Re-migrate even if the destination bundle already exists.",
|
|
283
|
+
)
|
|
284
|
+
@click.option(
|
|
285
|
+
"--delete-source", is_flag=True, default=False,
|
|
286
|
+
help=(
|
|
287
|
+
"Delete each source directory/bundle after its destination "
|
|
288
|
+
"has been written successfully. Use with care."
|
|
289
|
+
),
|
|
290
|
+
)
|
|
291
|
+
def migrate_backtests_cmd(
|
|
292
|
+
src, dst, workers, no_index, include_ohlcv, no_skip_existing,
|
|
293
|
+
delete_source,
|
|
294
|
+
):
|
|
295
|
+
"""Convert a directory of legacy backtest folders into the bundled
|
|
296
|
+
binary format introduced in issue #487.
|
|
297
|
+
|
|
298
|
+
The new ``.iafbt`` format is a single zstd-compressed MessagePack
|
|
299
|
+
file per backtest. Loading bundled directories is dramatically
|
|
300
|
+
faster than the legacy multi-file layout for large batches.
|
|
301
|
+
|
|
302
|
+
Migration is streamed (load+save fused per worker) so memory
|
|
303
|
+
usage stays roughly constant regardless of source size, and
|
|
304
|
+
interrupted runs can be resumed (existing destination bundles
|
|
305
|
+
are skipped by default).
|
|
306
|
+
"""
|
|
307
|
+
from investing_algorithm_framework.domain import migrate_backtests
|
|
308
|
+
|
|
309
|
+
n = migrate_backtests(
|
|
310
|
+
src,
|
|
311
|
+
dst,
|
|
312
|
+
workers=workers,
|
|
313
|
+
show_progress=True,
|
|
314
|
+
write_index=not no_index,
|
|
315
|
+
include_ohlcv=include_ohlcv,
|
|
316
|
+
skip_existing=not no_skip_existing,
|
|
317
|
+
delete_source=delete_source,
|
|
318
|
+
)
|
|
319
|
+
click.echo(f"Migrated {n} backtest(s) from {src} to {dst}")
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
cli.add_command(migrate_backtests_cmd)
|