investing-algorithm-framework 8.7.3__tar.gz → 8.8.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.7.3 → investing_algorithm_framework-8.8.0}/PKG-INFO +3 -2
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/README.md +2 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/__init__.py +5 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/app.py +94 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/context.py +335 -13
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/eventloop.py +89 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/backtest_report.py +23 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/templates/dashboard.js +52 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/dependency_container.py +7 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/__init__.py +7 -2
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_metrics.py +23 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/exceptions.py +30 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/__init__.py +4 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/data/data_source.py +23 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/order/order.py +32 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/order/order_type.py +2 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/portfolio/__init__.py +3 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +6 -0
- investing_algorithm_framework-8.8.0/investing_algorithm_framework/domain/models/portfolio/sync.py +111 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/base_url.py +32 -2
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/order/order.py +4 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +38 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/repository.py +2 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +74 -2
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/__init__.py +3 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/__init__.py +5 -3
- investing_algorithm_framework-8.8.0/investing_algorithm_framework/services/metrics/_returns_helper.py +70 -0
- investing_algorithm_framework-8.8.0/investing_algorithm_framework/services/metrics/cagr.py +81 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/drawdown.py +108 -1
- investing_algorithm_framework-8.8.0/investing_algorithm_framework/services/metrics/equity_curve.py +77 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/generate.py +12 -2
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/mean_daily_return.py +19 -7
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/returns.py +45 -16
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/sharpe_ratio.py +4 -5
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/standard_deviation.py +31 -55
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/value_at_risk.py +14 -8
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/volatility.py +16 -35
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/order_service/order_backtest_service.py +31 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/order_service/order_service.py +69 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/__init__.py +3 -1
- investing_algorithm_framework-8.8.0/investing_algorithm_framework/services/portfolios/broker_balance_tracker.py +330 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +63 -1
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/pyproject.toml +1 -1
- investing_algorithm_framework-8.7.3/investing_algorithm_framework/services/metrics/cagr.py +0 -60
- investing_algorithm_framework-8.7.3/investing_algorithm_framework/services/metrics/equity_curve.py +0 -27
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/LICENSE +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/analysis/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/analysis/backtest_data_ranges.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/analysis/markdown.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/analysis/ranking.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/algorithm/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/algorithm/algorithm.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/algorithm/algorithm_factory.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/app_hook.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/ascii.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/backtest_report_old.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/equity_curve.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/line_chart.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/generate.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/trades_table.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/tables/utils.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/templates/dashboard.css +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/templates/dashboard_template.html.j2 +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/strategy.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/task.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/create_app.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/error_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/responses.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/cli.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/deploy_to_aws_lambda.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/deploy_to_azure_function.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/initialize_app.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/mcp_server.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/.gitignore.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/app.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/app_azure_function.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/app_web.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/azure_function_host.json.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/data_providers.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/env.example.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/env_azure_function.example.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/market_data_providers.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/readme.md.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/requirements.txt.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/run_backtest.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/templates/strategy.py.template +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/cli/validate_backtest_checkpoints.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/create_app.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/algorithm_id.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_date_range.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_run.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/backtest_utils.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/bundle.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/combine_backtests.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/consistency.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/templates/backtest.html +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/templates/finterion-dark.png +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/backtesting/templates/finterion-light.png +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/blotter.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/config.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/constants.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/data_provider.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/data_structures.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/datetime_parsing.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/fx.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/app_mode.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/base_model.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/data/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/data/data_type.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/event.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/position/position.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/position/position_size.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/risk_rules/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/risk_rules/scaling_rule.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/risk_rules/trading_cost.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/snapshot_interval.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/tracing/trace.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/trade/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/trade/trade.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/trade/trade_status.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/models/trade/trade_take_profit.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/order_executor.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/custom_factor.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/factor.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/factors/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/factors/builtin.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/filter.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/pipeline/pipeline.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/portfolio_provider.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/services/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/services/rounding_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/services/state_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/strategy.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/csv.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/custom_tqdm.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/dates.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/polars.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/random.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/download_data.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/alpha_vantage.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/ccxt.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/csv.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/csv_url.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/json_url.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/ohlcv_base.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/pandas.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/parquet_url.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/polygon.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/data_providers/yahoo.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/order/trade_allocation.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/order_trade_association.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/trades/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/trades/trade.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/order_executors/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/trade_allocation_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/trade_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/aws/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/aws/state_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/azure/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/azure/state_handler.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/backtesting/checkpoint_manifest.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/notebook/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/notebook/magic.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/configuration_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/data_providers/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/data_providers/data.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/data_providers/data_provider_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/alpha.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/beta.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/calmar_ratio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/consistency.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/exposure.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/price_efficiency.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/profit_factor.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/recovery.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/risk_free_rate.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/sortino_ratio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/trades.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/metrics/win_rate.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/order_service/order_executor_lookup.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/pipeline/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/pipeline/pipeline_engine.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/pipeline/vector_pipeline_engine.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/portfolio_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/positions/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/positions/position_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/positions/position_snapshot_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/repository_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_order_evaluator/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_service/__init__.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_service/trade_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.0}/investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +0 -0
- {investing_algorithm_framework-8.7.3 → investing_algorithm_framework-8.8.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.8.0
|
|
4
4
|
Summary: A framework for creating trading bots
|
|
5
5
|
Author: MDUYN
|
|
6
6
|
Requires-Python: >=3.10,<4.0
|
|
@@ -129,7 +129,8 @@ This framework is built around the full loop: **create strategies → vector bac
|
|
|
129
129
|
- 📄 **[One-Click HTML Report](https://coding-kitties.github.io/investing-algorithm-framework/Getting%20Started/backtest-reports)** — Self-contained file, no server, dark & light theme, shareable
|
|
130
130
|
- 📦 **[Custom `.iafbt` Backtest Bundle Format](https://coding-kitties.github.io/investing-algorithm-framework/Data/backtest_data)** — 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.
|
|
131
131
|
- 🌐 **[Load External Data](https://coding-kitties.github.io/investing-algorithm-framework/Data/external-data)** — Fetch CSV, JSON, or Parquet from any URL with caching and auto-refresh
|
|
132
|
-
-
|
|
132
|
+
- � **[Per-Market Deposit Schedules & Portfolio Sync](https://coding-kitties.github.io/investing-algorithm-framework/Advanced%20Concepts/portfolio-sync)** — Declare recurring or one-shot external cash flows on a market with `deposit_schedule=` / `auto_sync=True`. Backtests simulate the deposits; live mode reconciles with the broker — same `context.sync_portfolio()` API in both modes.
|
|
133
|
+
- �📝 **[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()`
|
|
133
134
|
- 🚀 **[Build → Backtest → Deploy](https://coding-kitties.github.io/investing-algorithm-framework/Getting%20Started/application-setup)** — Local dev, cloud deploy (AWS / Azure), or monetize on Finterion
|
|
134
135
|
|
|
135
136
|
</details>
|
|
@@ -85,7 +85,8 @@ This framework is built around the full loop: **create strategies → vector bac
|
|
|
85
85
|
- 📄 **[One-Click HTML Report](https://coding-kitties.github.io/investing-algorithm-framework/Getting%20Started/backtest-reports)** — Self-contained file, no server, dark & light theme, shareable
|
|
86
86
|
- 📦 **[Custom `.iafbt` Backtest Bundle Format](https://coding-kitties.github.io/investing-algorithm-framework/Data/backtest_data)** — 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.
|
|
87
87
|
- 🌐 **[Load External Data](https://coding-kitties.github.io/investing-algorithm-framework/Data/external-data)** — Fetch CSV, JSON, or Parquet from any URL with caching and auto-refresh
|
|
88
|
-
-
|
|
88
|
+
- � **[Per-Market Deposit Schedules & Portfolio Sync](https://coding-kitties.github.io/investing-algorithm-framework/Advanced%20Concepts/portfolio-sync)** — Declare recurring or one-shot external cash flows on a market with `deposit_schedule=` / `auto_sync=True`. Backtests simulate the deposits; live mode reconciles with the broker — same `context.sync_portfolio()` API in both modes.
|
|
89
|
+
- �📝 **[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()`
|
|
89
90
|
- 🚀 **[Build → Backtest → Deploy](https://coding-kitties.github.io/investing-algorithm-framework/Getting%20Started/application-setup)** — Local dev, cloud deploy (AWS / Azure), or monetize on Finterion
|
|
90
91
|
|
|
91
92
|
</details>
|
|
@@ -35,7 +35,8 @@ from .domain import ApiException, combine_backtests, PositionSize, \
|
|
|
35
35
|
Pipeline, Factor, CustomFactor, Filter, \
|
|
36
36
|
Returns, AverageDollarVolume, AverageTradedValue, SMA, RSI, \
|
|
37
37
|
Volatility, StaticPerSymbol, CrossSectionalMean, RollingBeta, \
|
|
38
|
-
Neutralize
|
|
38
|
+
Neutralize, \
|
|
39
|
+
SyncResult, ScheduledDeposit, PortfolioOutOfSyncError
|
|
39
40
|
from .infrastructure import AzureBlobStorageStateHandler, \
|
|
40
41
|
CSVOHLCVDataProvider, CSVTickerDataProvider, CSVURLDataProvider, \
|
|
41
42
|
JSONURLDataProvider, ParquetURLDataProvider, \
|
|
@@ -285,6 +286,9 @@ __all__ = [
|
|
|
285
286
|
"get_normalized_stability",
|
|
286
287
|
"get_consistency_score",
|
|
287
288
|
"get_stability_score",
|
|
289
|
+
"SyncResult",
|
|
290
|
+
"ScheduledDeposit",
|
|
291
|
+
"PortfolioOutOfSyncError",
|
|
288
292
|
]
|
|
289
293
|
|
|
290
294
|
|
|
@@ -2242,6 +2242,9 @@ class App:
|
|
|
2242
2242
|
initial_balance=None,
|
|
2243
2243
|
fee_percentage=0.0,
|
|
2244
2244
|
slippage_percentage=0.0,
|
|
2245
|
+
deposit_schedule=None,
|
|
2246
|
+
auto_sync=False,
|
|
2247
|
+
auto_sync_error_mode="raise",
|
|
2245
2248
|
):
|
|
2246
2249
|
"""
|
|
2247
2250
|
Function to add a market to the app. This function is a utility
|
|
@@ -2260,10 +2263,28 @@ class App:
|
|
|
2260
2263
|
slippage_percentage: Default slippage percentage for all
|
|
2261
2264
|
trades on this market (e.g. 0.05 for 0.05%). Can be
|
|
2262
2265
|
overridden per-symbol via TradingCost on the strategy.
|
|
2266
|
+
deposit_schedule: Optional list of
|
|
2267
|
+
:class:`ScheduledDeposit` describing simulated external
|
|
2268
|
+
cash flows landing on this market during a backtest
|
|
2269
|
+
(e.g. monthly paychecks). Ignored in live mode — for
|
|
2270
|
+
live deployments the broker is the source of truth and
|
|
2271
|
+
``Context.sync_portfolio()`` queries it directly.
|
|
2272
|
+
auto_sync: When ``True``, the framework automatically calls
|
|
2273
|
+
``Context.sync_portfolio(market=market)`` before every
|
|
2274
|
+
strategy iteration so deposits/withdrawals are absorbed
|
|
2275
|
+
without strategy code having to opt in. Defaults to
|
|
2276
|
+
``False`` (explicit opt-in via ``context.sync_portfolio()``).
|
|
2277
|
+
auto_sync_error_mode: How auto-sync handles failures. One of
|
|
2278
|
+
``"raise"`` (loud, default — best for development),
|
|
2279
|
+
``"warn"`` (log and continue with stale state — best for
|
|
2280
|
+
live trading where transient broker glitches should not
|
|
2281
|
+
crash the bot), or ``"halt"`` (log, disable auto-sync
|
|
2282
|
+
for this market, and continue).
|
|
2263
2283
|
|
|
2264
2284
|
Returns:
|
|
2265
2285
|
None
|
|
2266
2286
|
"""
|
|
2287
|
+
deposit_schedule = self._normalize_deposit_schedule(deposit_schedule)
|
|
2267
2288
|
|
|
2268
2289
|
portfolio_configuration = PortfolioConfiguration(
|
|
2269
2290
|
market=market,
|
|
@@ -2271,6 +2292,7 @@ class App:
|
|
|
2271
2292
|
initial_balance=initial_balance,
|
|
2272
2293
|
fee_percentage=fee_percentage,
|
|
2273
2294
|
slippage_percentage=slippage_percentage,
|
|
2295
|
+
deposit_schedule=deposit_schedule,
|
|
2274
2296
|
)
|
|
2275
2297
|
|
|
2276
2298
|
self.add_portfolio_configuration(portfolio_configuration)
|
|
@@ -2281,6 +2303,78 @@ class App:
|
|
|
2281
2303
|
)
|
|
2282
2304
|
self.add_market_credential(market_credential)
|
|
2283
2305
|
|
|
2306
|
+
tracker = self.container.broker_balance_tracker()
|
|
2307
|
+
if deposit_schedule:
|
|
2308
|
+
tracker.set_schedule(market, deposit_schedule)
|
|
2309
|
+
if auto_sync:
|
|
2310
|
+
tracker.set_auto_sync(market, True)
|
|
2311
|
+
tracker.set_auto_sync_error_mode(market, auto_sync_error_mode)
|
|
2312
|
+
|
|
2313
|
+
@staticmethod
|
|
2314
|
+
def _normalize_deposit_schedule(deposit_schedule):
|
|
2315
|
+
"""Coerce a deposit_schedule argument to a validated list.
|
|
2316
|
+
|
|
2317
|
+
Accepts ``None`` (treated as no schedule), a list/tuple of
|
|
2318
|
+
:class:`ScheduledDeposit`, or rejects anything else with a clear
|
|
2319
|
+
error. Notably rejects passing a single ``ScheduledDeposit``
|
|
2320
|
+
directly (which would be iterable over its dataclass fields and
|
|
2321
|
+
produce nonsense).
|
|
2322
|
+
"""
|
|
2323
|
+
from investing_algorithm_framework.domain import ScheduledDeposit
|
|
2324
|
+
if deposit_schedule is None:
|
|
2325
|
+
return []
|
|
2326
|
+
if isinstance(deposit_schedule, ScheduledDeposit):
|
|
2327
|
+
raise OperationalException(
|
|
2328
|
+
"deposit_schedule must be a list of ScheduledDeposit, not a "
|
|
2329
|
+
"single ScheduledDeposit. Wrap it: [ScheduledDeposit(...)]."
|
|
2330
|
+
)
|
|
2331
|
+
if not isinstance(deposit_schedule, (list, tuple)):
|
|
2332
|
+
raise OperationalException(
|
|
2333
|
+
"deposit_schedule must be a list of ScheduledDeposit, got "
|
|
2334
|
+
f"{type(deposit_schedule).__name__}."
|
|
2335
|
+
)
|
|
2336
|
+
for entry in deposit_schedule:
|
|
2337
|
+
if not isinstance(entry, ScheduledDeposit):
|
|
2338
|
+
raise OperationalException(
|
|
2339
|
+
"deposit_schedule entries must be ScheduledDeposit, "
|
|
2340
|
+
f"got {type(entry).__name__}."
|
|
2341
|
+
)
|
|
2342
|
+
return list(deposit_schedule)
|
|
2343
|
+
|
|
2344
|
+
def add_deposit_schedule(self, market, schedule):
|
|
2345
|
+
"""Register simulated external deposits for a backtested market.
|
|
2346
|
+
|
|
2347
|
+
Equivalent to passing ``deposit_schedule=`` to :meth:`add_market`,
|
|
2348
|
+
but usable after the market has already been registered. Replaces
|
|
2349
|
+
any previously registered schedule for this market.
|
|
2350
|
+
|
|
2351
|
+
Args:
|
|
2352
|
+
market: Market identifier.
|
|
2353
|
+
schedule: Iterable of :class:`ScheduledDeposit`.
|
|
2354
|
+
|
|
2355
|
+
Returns:
|
|
2356
|
+
None
|
|
2357
|
+
"""
|
|
2358
|
+
self.container.broker_balance_tracker().set_schedule(
|
|
2359
|
+
market, self._normalize_deposit_schedule(schedule)
|
|
2360
|
+
)
|
|
2361
|
+
|
|
2362
|
+
def set_market_auto_sync(self, market, enabled=True):
|
|
2363
|
+
"""Toggle automatic ``sync_portfolio`` before each strategy iteration.
|
|
2364
|
+
|
|
2365
|
+
Args:
|
|
2366
|
+
market: Market identifier.
|
|
2367
|
+
enabled: When ``True`` (the default), the framework calls
|
|
2368
|
+
``Context.sync_portfolio(market=market)`` immediately before
|
|
2369
|
+
each strategy ``run_strategy`` invocation.
|
|
2370
|
+
|
|
2371
|
+
Returns:
|
|
2372
|
+
None
|
|
2373
|
+
"""
|
|
2374
|
+
self.container.broker_balance_tracker().set_auto_sync(
|
|
2375
|
+
market, enabled
|
|
2376
|
+
)
|
|
2377
|
+
|
|
2284
2378
|
def set_blotter(self, blotter):
|
|
2285
2379
|
"""
|
|
2286
2380
|
Set a blotter for order book management. The blotter sits
|
|
@@ -5,12 +5,16 @@ from typing import List
|
|
|
5
5
|
from investing_algorithm_framework.services import ConfigurationService, \
|
|
6
6
|
MarketCredentialService, OrderService, PortfolioConfigurationService, \
|
|
7
7
|
PortfolioService, PositionService, TradeService, DataProviderService, \
|
|
8
|
-
TradeStopLossService, TradeTakeProfitService
|
|
8
|
+
TradeStopLossService, TradeTakeProfitService, BrokerBalanceTracker
|
|
9
|
+
from investing_algorithm_framework.services.portfolios import (
|
|
10
|
+
PortfolioProviderLookup,
|
|
11
|
+
)
|
|
9
12
|
from investing_algorithm_framework.domain import OrderStatus, OrderType, \
|
|
10
13
|
OrderSide, OperationalException, Portfolio, RoundingService, \
|
|
11
14
|
BACKTESTING_FLAG, INDEX_DATETIME, Order, \
|
|
12
15
|
Position, Trade, TradeStatus, MarketCredential, TradeStopLoss, \
|
|
13
|
-
TradeTakeProfit
|
|
16
|
+
TradeTakeProfit, SyncResult, PortfolioOutOfSyncError, Environment, \
|
|
17
|
+
ENVIRONMENT
|
|
14
18
|
|
|
15
19
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
16
20
|
|
|
@@ -33,7 +37,9 @@ class Context:
|
|
|
33
37
|
trade_service: TradeService,
|
|
34
38
|
trade_stop_loss_service: TradeStopLossService,
|
|
35
39
|
trade_take_profit_service: TradeTakeProfitService,
|
|
36
|
-
data_provider_service: DataProviderService
|
|
40
|
+
data_provider_service: DataProviderService,
|
|
41
|
+
portfolio_provider_lookup: PortfolioProviderLookup = None,
|
|
42
|
+
broker_balance_tracker: BrokerBalanceTracker = None,
|
|
37
43
|
):
|
|
38
44
|
self.configuration_service: ConfigurationService = \
|
|
39
45
|
configuration_service
|
|
@@ -50,6 +56,10 @@ class Context:
|
|
|
50
56
|
trade_stop_loss_service
|
|
51
57
|
self.trade_take_profit_service: TradeTakeProfitService = \
|
|
52
58
|
trade_take_profit_service
|
|
59
|
+
self.portfolio_provider_lookup: PortfolioProviderLookup = \
|
|
60
|
+
portfolio_provider_lookup
|
|
61
|
+
self.broker_balance_tracker: BrokerBalanceTracker = \
|
|
62
|
+
broker_balance_tracker
|
|
53
63
|
self._blotter = None
|
|
54
64
|
self._fx_rate_provider = None
|
|
55
65
|
self._base_currency = None
|
|
@@ -134,7 +144,8 @@ class Context:
|
|
|
134
144
|
execute=True,
|
|
135
145
|
validate=True,
|
|
136
146
|
sync=True,
|
|
137
|
-
validate_symbol=False
|
|
147
|
+
validate_symbol=False,
|
|
148
|
+
stop_price=None,
|
|
138
149
|
) -> Order:
|
|
139
150
|
"""
|
|
140
151
|
Function to create an order. This function will create an order
|
|
@@ -154,6 +165,8 @@ class Context:
|
|
|
154
165
|
with the portfolio of the algorithm.
|
|
155
166
|
validate_symbol: Default False. If set to True,
|
|
156
167
|
validates that target_symbol is not the trading_symbol.
|
|
168
|
+
stop_price: Required for STOP and STOP_LIMIT order types.
|
|
169
|
+
The trigger price at which the order activates.
|
|
157
170
|
|
|
158
171
|
Returns:
|
|
159
172
|
The order created
|
|
@@ -173,6 +186,9 @@ class Context:
|
|
|
173
186
|
"trading_symbol": portfolio.trading_symbol,
|
|
174
187
|
}
|
|
175
188
|
|
|
189
|
+
if stop_price is not None:
|
|
190
|
+
order_data["stop_price"] = stop_price
|
|
191
|
+
|
|
176
192
|
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
177
193
|
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
178
194
|
order_data["created_at"] = \
|
|
@@ -884,6 +900,280 @@ class Context:
|
|
|
884
900
|
{"portfolio": portfolio.id, "symbol": trading_symbol}
|
|
885
901
|
).get_amount()
|
|
886
902
|
|
|
903
|
+
def sync_portfolio(
|
|
904
|
+
self,
|
|
905
|
+
market: str = None,
|
|
906
|
+
allow_withdrawals: bool = False,
|
|
907
|
+
tolerance: float = 1e-9,
|
|
908
|
+
) -> SyncResult:
|
|
909
|
+
"""Reconcile the local portfolio's unallocated balance with the broker.
|
|
910
|
+
|
|
911
|
+
This is the **canonical entry point** for "make my strategy aware of
|
|
912
|
+
cash that arrived (or left) my account out-of-band". The contract is
|
|
913
|
+
identical across live and backtest modes:
|
|
914
|
+
|
|
915
|
+
1. Ask the broker (live: registered :class:`PortfolioProvider`;
|
|
916
|
+
backtest: simulated :class:`BrokerBalanceTracker`) what the
|
|
917
|
+
trading-symbol balance currently is.
|
|
918
|
+
2. In live mode, subtract cash reserved for orders the framework
|
|
919
|
+
knows about but the exchange has not yet acknowledged
|
|
920
|
+
(``OrderStatus.CREATED``). Without this, the natural race
|
|
921
|
+
between local order creation and exchange acknowledgement
|
|
922
|
+
would surface as a phantom "deposit".
|
|
923
|
+
3. Compute ``delta = adjusted_broker_available - local_unallocated``.
|
|
924
|
+
4. ``abs(delta) <= tolerance`` → no-op.
|
|
925
|
+
5. ``delta > 0`` → an external deposit landed; absorb it by topping
|
|
926
|
+
up ``unallocated``.
|
|
927
|
+
6. ``delta < 0`` → the broker reports *less* than the framework
|
|
928
|
+
expected (an external withdrawal, an out-of-band fill, an
|
|
929
|
+
unrecorded fee, …). By default this raises
|
|
930
|
+
:class:`PortfolioOutOfSyncError` because silently shrinking
|
|
931
|
+
the strategy's working capital is almost always the wrong
|
|
932
|
+
thing to do. Pass ``allow_withdrawals=True`` to explicitly
|
|
933
|
+
accept the drain.
|
|
934
|
+
|
|
935
|
+
The absorbed cash flow is recorded on the
|
|
936
|
+
:class:`BrokerBalanceTracker` so the snapshot service can attach
|
|
937
|
+
it to the next portfolio snapshot's ``cash_flow`` field, which in
|
|
938
|
+
turn lets return metrics (CAGR, monthly/yearly returns) compute
|
|
939
|
+
true time-weighted returns instead of being inflated by deposits.
|
|
940
|
+
|
|
941
|
+
Args:
|
|
942
|
+
market: Market identifier. Defaults to the first registered
|
|
943
|
+
portfolio. Case-insensitive.
|
|
944
|
+
allow_withdrawals: When ``True``, negative deltas drain
|
|
945
|
+
``unallocated`` instead of raising. The drain is still
|
|
946
|
+
refused if it would push ``unallocated`` below zero.
|
|
947
|
+
tolerance: Absolute drift below which the sync is treated as
|
|
948
|
+
a noop. Defaults to ``1e-9`` to swallow floating-point
|
|
949
|
+
dust. Useful to bump (e.g. ``1.0``) for live mode if
|
|
950
|
+
small fee/rounding glitches keep tripping the check.
|
|
951
|
+
|
|
952
|
+
Returns:
|
|
953
|
+
:class:`SyncResult` describing the outcome.
|
|
954
|
+
|
|
955
|
+
Raises:
|
|
956
|
+
PortfolioOutOfSyncError: On negative delta when
|
|
957
|
+
``allow_withdrawals=False``, or when the resulting
|
|
958
|
+
``unallocated`` would be negative.
|
|
959
|
+
OperationalException: When live mode is configured but no
|
|
960
|
+
:class:`PortfolioProvider` / :class:`MarketCredential`
|
|
961
|
+
is registered for the market.
|
|
962
|
+
"""
|
|
963
|
+
if tolerance < 0:
|
|
964
|
+
raise OperationalException(
|
|
965
|
+
f"sync_portfolio: tolerance must be non-negative, got "
|
|
966
|
+
f"{tolerance}."
|
|
967
|
+
)
|
|
968
|
+
portfolio = self._resolve_portfolio_for_sync(market)
|
|
969
|
+
market_id = portfolio.market
|
|
970
|
+
previous_unallocated = float(portfolio.get_unallocated() or 0.0)
|
|
971
|
+
|
|
972
|
+
broker_available, reserved = self._fetch_broker_available(
|
|
973
|
+
portfolio, previous_unallocated
|
|
974
|
+
)
|
|
975
|
+
|
|
976
|
+
delta = broker_available - previous_unallocated
|
|
977
|
+
|
|
978
|
+
if abs(delta) <= tolerance:
|
|
979
|
+
return SyncResult(
|
|
980
|
+
market=market_id,
|
|
981
|
+
kind="noop",
|
|
982
|
+
delta=delta,
|
|
983
|
+
broker_available=broker_available,
|
|
984
|
+
previous_unallocated=previous_unallocated,
|
|
985
|
+
new_unallocated=previous_unallocated,
|
|
986
|
+
within_tolerance=delta != 0,
|
|
987
|
+
reserved_for_pending_orders=reserved,
|
|
988
|
+
)
|
|
989
|
+
|
|
990
|
+
if delta < 0 and not allow_withdrawals:
|
|
991
|
+
raise PortfolioOutOfSyncError(
|
|
992
|
+
f"Portfolio out of sync on market '{market_id}': local "
|
|
993
|
+
f"unallocated {previous_unallocated} > broker available "
|
|
994
|
+
f"{broker_available} (delta {delta}, "
|
|
995
|
+
f"{reserved} reserved for pending orders). This usually "
|
|
996
|
+
f"means an external withdrawal happened, an order filled "
|
|
997
|
+
f"out-of-band, or fees were charged the framework did not "
|
|
998
|
+
f"see. Pass allow_withdrawals=True to drain unallocated, "
|
|
999
|
+
f"or investigate the broker account.",
|
|
1000
|
+
market=market_id,
|
|
1001
|
+
local_unallocated=previous_unallocated,
|
|
1002
|
+
broker_available=broker_available,
|
|
1003
|
+
delta=delta,
|
|
1004
|
+
)
|
|
1005
|
+
|
|
1006
|
+
new_unallocated = broker_available
|
|
1007
|
+
if new_unallocated < 0:
|
|
1008
|
+
raise PortfolioOutOfSyncError(
|
|
1009
|
+
f"Refusing to set unallocated to a negative value on market "
|
|
1010
|
+
f"'{market_id}': broker reports {broker_available}, which is "
|
|
1011
|
+
f"below zero. Investigate the broker account.",
|
|
1012
|
+
market=market_id,
|
|
1013
|
+
local_unallocated=previous_unallocated,
|
|
1014
|
+
broker_available=broker_available,
|
|
1015
|
+
delta=delta,
|
|
1016
|
+
)
|
|
1017
|
+
|
|
1018
|
+
kind = "deposit" if delta > 0 else "withdrawal"
|
|
1019
|
+
self._apply_unallocated_change(portfolio, new_unallocated)
|
|
1020
|
+
|
|
1021
|
+
# Record the cash flow so the next portfolio snapshot gets a
|
|
1022
|
+
# non-zero ``cash_flow`` and TWR-aware metrics work correctly.
|
|
1023
|
+
if self.broker_balance_tracker is not None:
|
|
1024
|
+
self.broker_balance_tracker.record_cash_flow(market_id, delta)
|
|
1025
|
+
|
|
1026
|
+
logger.info(
|
|
1027
|
+
"sync_portfolio[%s] %s: local %.6f -> %.6f (broker reports %.6f, "
|
|
1028
|
+
"delta %+.6f, reserved %.6f)",
|
|
1029
|
+
market_id, kind, previous_unallocated, new_unallocated,
|
|
1030
|
+
broker_available, delta, reserved,
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
return SyncResult(
|
|
1034
|
+
market=market_id,
|
|
1035
|
+
kind=kind,
|
|
1036
|
+
delta=delta,
|
|
1037
|
+
broker_available=broker_available,
|
|
1038
|
+
previous_unallocated=previous_unallocated,
|
|
1039
|
+
new_unallocated=new_unallocated,
|
|
1040
|
+
within_tolerance=False,
|
|
1041
|
+
reserved_for_pending_orders=reserved,
|
|
1042
|
+
)
|
|
1043
|
+
|
|
1044
|
+
def _resolve_portfolio_for_sync(self, market) -> Portfolio:
|
|
1045
|
+
if market is not None:
|
|
1046
|
+
# Portfolio.market is canonically uppercased on creation; match
|
|
1047
|
+
# case-insensitively so users can pass "binance" or "BINANCE".
|
|
1048
|
+
normalized = str(market).upper()
|
|
1049
|
+
portfolio = self.portfolio_service.find({"market": normalized})
|
|
1050
|
+
if portfolio is None:
|
|
1051
|
+
portfolio = self.portfolio_service.find({"market": market})
|
|
1052
|
+
else:
|
|
1053
|
+
portfolios = self.portfolio_service.get_all()
|
|
1054
|
+
if not portfolios:
|
|
1055
|
+
raise OperationalException(
|
|
1056
|
+
"sync_portfolio: no portfolio registered. "
|
|
1057
|
+
"Did you call app.add_market(...)?"
|
|
1058
|
+
)
|
|
1059
|
+
portfolio = portfolios[0]
|
|
1060
|
+
if portfolio is None:
|
|
1061
|
+
raise OperationalException(
|
|
1062
|
+
f"sync_portfolio: no portfolio found for market '{market}'."
|
|
1063
|
+
)
|
|
1064
|
+
return portfolio
|
|
1065
|
+
|
|
1066
|
+
def _fetch_broker_available(
|
|
1067
|
+
self, portfolio: Portfolio, previous_unallocated: float
|
|
1068
|
+
) -> tuple:
|
|
1069
|
+
"""Returns (broker_available, reserved_for_pending_orders)."""
|
|
1070
|
+
config = self.configuration_service.get_config()
|
|
1071
|
+
environment = config.get(ENVIRONMENT)
|
|
1072
|
+
|
|
1073
|
+
is_backtest = environment in (
|
|
1074
|
+
Environment.BACKTEST.value,
|
|
1075
|
+
Environment.BACKTEST,
|
|
1076
|
+
)
|
|
1077
|
+
|
|
1078
|
+
if is_backtest:
|
|
1079
|
+
if self.broker_balance_tracker is None:
|
|
1080
|
+
# No tracker wired (legacy app construction); deposits cannot
|
|
1081
|
+
# be simulated → broker == local.
|
|
1082
|
+
return previous_unallocated, 0.0
|
|
1083
|
+
pending = self.broker_balance_tracker.consume_pending(
|
|
1084
|
+
portfolio.market
|
|
1085
|
+
)
|
|
1086
|
+
return previous_unallocated + pending, 0.0
|
|
1087
|
+
|
|
1088
|
+
# Live mode
|
|
1089
|
+
if self.portfolio_provider_lookup is None:
|
|
1090
|
+
raise OperationalException(
|
|
1091
|
+
"sync_portfolio: no PortfolioProviderLookup wired into the "
|
|
1092
|
+
"context. This usually means the app was constructed without "
|
|
1093
|
+
"the standard dependency container."
|
|
1094
|
+
)
|
|
1095
|
+
market_credential = self.market_credential_service.get(
|
|
1096
|
+
portfolio.market
|
|
1097
|
+
)
|
|
1098
|
+
if market_credential is None:
|
|
1099
|
+
raise OperationalException(
|
|
1100
|
+
f"sync_portfolio: no market credential registered for "
|
|
1101
|
+
f"market '{portfolio.market}'. Live broker reconciliation "
|
|
1102
|
+
f"requires API credentials."
|
|
1103
|
+
)
|
|
1104
|
+
provider = self.portfolio_provider_lookup.get_portfolio_provider(
|
|
1105
|
+
portfolio.market
|
|
1106
|
+
)
|
|
1107
|
+
if provider is None:
|
|
1108
|
+
raise OperationalException(
|
|
1109
|
+
f"sync_portfolio: no PortfolioProvider registered for market "
|
|
1110
|
+
f"'{portfolio.market}'."
|
|
1111
|
+
)
|
|
1112
|
+
position = provider.get_position(
|
|
1113
|
+
portfolio, portfolio.trading_symbol, market_credential
|
|
1114
|
+
)
|
|
1115
|
+
raw = float(position.amount) if position is not None else 0.0
|
|
1116
|
+
|
|
1117
|
+
# Subtract cash reserved for orders the framework has issued but
|
|
1118
|
+
# the exchange has not yet acknowledged. ``free`` from the broker
|
|
1119
|
+
# already excludes acknowledged open orders, but not those in
|
|
1120
|
+
# CREATED state — without this adjustment a brief race window
|
|
1121
|
+
# between create_order() and the exchange ack would surface as a
|
|
1122
|
+
# phantom "deposit" of the order's cost.
|
|
1123
|
+
reserved = self._reserved_cash_for_pending_orders(portfolio)
|
|
1124
|
+
return raw - reserved, reserved
|
|
1125
|
+
|
|
1126
|
+
def _reserved_cash_for_pending_orders(
|
|
1127
|
+
self, portfolio: Portfolio
|
|
1128
|
+
) -> float:
|
|
1129
|
+
"""Sum of trading-symbol cash locked by orders the framework has
|
|
1130
|
+
created but the exchange has not yet filled or cancelled.
|
|
1131
|
+
|
|
1132
|
+
Buys consume cash; sells release it. Only ``CREATED`` orders are
|
|
1133
|
+
counted because the broker's ``free`` balance already excludes
|
|
1134
|
+
acknowledged open orders.
|
|
1135
|
+
"""
|
|
1136
|
+
try:
|
|
1137
|
+
created_orders = self.order_service.get_all({
|
|
1138
|
+
"portfolio_id": portfolio.id,
|
|
1139
|
+
"status": OrderStatus.CREATED.value,
|
|
1140
|
+
})
|
|
1141
|
+
except Exception: # noqa: BLE001
|
|
1142
|
+
return 0.0
|
|
1143
|
+
reserved = 0.0
|
|
1144
|
+
for order in created_orders or []:
|
|
1145
|
+
try:
|
|
1146
|
+
price = float(order.get_price() or 0.0)
|
|
1147
|
+
amount = float(
|
|
1148
|
+
order.get_remaining() or order.get_amount() or 0.0
|
|
1149
|
+
)
|
|
1150
|
+
except Exception: # noqa: BLE001
|
|
1151
|
+
continue
|
|
1152
|
+
if OrderSide.BUY.equals(order.get_order_side()):
|
|
1153
|
+
reserved += price * amount
|
|
1154
|
+
# Sells release cash on fill; not counted here.
|
|
1155
|
+
return reserved
|
|
1156
|
+
|
|
1157
|
+
def _apply_unallocated_change(
|
|
1158
|
+
self, portfolio: Portfolio, new_unallocated: float
|
|
1159
|
+
) -> None:
|
|
1160
|
+
self.portfolio_service.update(
|
|
1161
|
+
portfolio.id, {"unallocated": new_unallocated}
|
|
1162
|
+
)
|
|
1163
|
+
# Keep the trading-symbol position in lockstep, mirroring the
|
|
1164
|
+
# behaviour of PortfolioSyncService.sync_unallocated().
|
|
1165
|
+
try:
|
|
1166
|
+
trading_position = self.position_service.find({
|
|
1167
|
+
"portfolio": portfolio.id,
|
|
1168
|
+
"symbol": portfolio.trading_symbol,
|
|
1169
|
+
})
|
|
1170
|
+
except Exception: # noqa: BLE001 — repository raises on miss
|
|
1171
|
+
trading_position = None
|
|
1172
|
+
if trading_position is not None:
|
|
1173
|
+
self.position_service.update(
|
|
1174
|
+
trading_position.id, {"amount": new_unallocated}
|
|
1175
|
+
)
|
|
1176
|
+
|
|
887
1177
|
def get_total_size(self):
|
|
888
1178
|
"""
|
|
889
1179
|
Returns the total size of the portfolio.
|
|
@@ -2092,6 +2382,14 @@ class Context:
|
|
|
2092
2382
|
|
|
2093
2383
|
return self.trade_stop_loss_service.get_all(query_params)
|
|
2094
2384
|
|
|
2385
|
+
def _get_url_provider_cache_key(self, url, headers):
|
|
2386
|
+
# Delegates to the canonical helper so the in-memory provider
|
|
2387
|
+
# dict and the on-disk cache filename stay in lockstep — see
|
|
2388
|
+
# ``url_cache_key`` for rationale.
|
|
2389
|
+
from investing_algorithm_framework.infrastructure \
|
|
2390
|
+
.data_providers.base_url import url_cache_key
|
|
2391
|
+
return url_cache_key(url, headers)
|
|
2392
|
+
|
|
2095
2393
|
def fetch_csv(
|
|
2096
2394
|
self,
|
|
2097
2395
|
url,
|
|
@@ -2099,6 +2397,7 @@ class Context:
|
|
|
2099
2397
|
date_format=None,
|
|
2100
2398
|
cache=True,
|
|
2101
2399
|
refresh_interval=None,
|
|
2400
|
+
headers=None,
|
|
2102
2401
|
pre_process=None,
|
|
2103
2402
|
post_process=None,
|
|
2104
2403
|
):
|
|
@@ -2118,6 +2417,10 @@ class Context:
|
|
|
2118
2417
|
cache (bool): Cache fetched data locally (default: True).
|
|
2119
2418
|
refresh_interval (str, optional): Re-fetch interval
|
|
2120
2419
|
(e.g., "1d", "1h").
|
|
2420
|
+
headers (dict, optional): HTTP headers to send with the
|
|
2421
|
+
request. Header values are redacted (replaced
|
|
2422
|
+
with "***") in ``DataSource.to_dict``, so
|
|
2423
|
+
secrets do not leak into diagnostic payloads.
|
|
2121
2424
|
pre_process (callable, optional): Transform raw CSV text
|
|
2122
2425
|
before parsing.
|
|
2123
2426
|
post_process (callable, optional): Transform the parsed
|
|
@@ -2141,20 +2444,23 @@ class Context:
|
|
|
2141
2444
|
if not hasattr(self, '_csv_url_providers'):
|
|
2142
2445
|
self._csv_url_providers = {}
|
|
2143
2446
|
|
|
2144
|
-
|
|
2447
|
+
provider_key = self._get_url_provider_cache_key(url, headers)
|
|
2448
|
+
|
|
2449
|
+
if provider_key not in self._csv_url_providers:
|
|
2145
2450
|
provider = CSVURLDataProvider(
|
|
2146
2451
|
url=url,
|
|
2147
2452
|
date_column=date_column,
|
|
2148
2453
|
date_format=date_format,
|
|
2149
2454
|
cache=cache,
|
|
2150
2455
|
refresh_interval=refresh_interval,
|
|
2456
|
+
headers=headers,
|
|
2151
2457
|
pre_process=pre_process,
|
|
2152
2458
|
post_process=post_process,
|
|
2153
2459
|
)
|
|
2154
2460
|
provider.config = self.configuration_service.get_config()
|
|
2155
|
-
self._csv_url_providers[
|
|
2461
|
+
self._csv_url_providers[provider_key] = provider
|
|
2156
2462
|
|
|
2157
|
-
return self._csv_url_providers[
|
|
2463
|
+
return self._csv_url_providers[provider_key].get_data()
|
|
2158
2464
|
|
|
2159
2465
|
def fetch_json(
|
|
2160
2466
|
self,
|
|
@@ -2163,6 +2469,7 @@ class Context:
|
|
|
2163
2469
|
date_format=None,
|
|
2164
2470
|
cache=True,
|
|
2165
2471
|
refresh_interval=None,
|
|
2472
|
+
headers=None,
|
|
2166
2473
|
pre_process=None,
|
|
2167
2474
|
post_process=None,
|
|
2168
2475
|
):
|
|
@@ -2185,6 +2492,10 @@ class Context:
|
|
|
2185
2492
|
cache (bool): Cache fetched data locally (default: True).
|
|
2186
2493
|
refresh_interval (str, optional): Re-fetch interval
|
|
2187
2494
|
(e.g., "1d", "1h").
|
|
2495
|
+
headers (dict, optional): HTTP headers to send with the
|
|
2496
|
+
request. Header values are redacted (replaced
|
|
2497
|
+
with "***") in ``DataSource.to_dict``, so
|
|
2498
|
+
secrets do not leak into diagnostic payloads.
|
|
2188
2499
|
pre_process (callable, optional): Transform raw JSON text
|
|
2189
2500
|
before parsing.
|
|
2190
2501
|
post_process (callable, optional): Transform the parsed
|
|
@@ -2207,20 +2518,23 @@ class Context:
|
|
|
2207
2518
|
if not hasattr(self, '_json_url_providers'):
|
|
2208
2519
|
self._json_url_providers = {}
|
|
2209
2520
|
|
|
2210
|
-
|
|
2521
|
+
provider_key = self._get_url_provider_cache_key(url, headers)
|
|
2522
|
+
|
|
2523
|
+
if provider_key not in self._json_url_providers:
|
|
2211
2524
|
provider = JSONURLDataProvider(
|
|
2212
2525
|
url=url,
|
|
2213
2526
|
date_column=date_column,
|
|
2214
2527
|
date_format=date_format,
|
|
2215
2528
|
cache=cache,
|
|
2216
2529
|
refresh_interval=refresh_interval,
|
|
2530
|
+
headers=headers,
|
|
2217
2531
|
pre_process=pre_process,
|
|
2218
2532
|
post_process=post_process,
|
|
2219
2533
|
)
|
|
2220
2534
|
provider.config = self.configuration_service.get_config()
|
|
2221
|
-
self._json_url_providers[
|
|
2535
|
+
self._json_url_providers[provider_key] = provider
|
|
2222
2536
|
|
|
2223
|
-
return self._json_url_providers[
|
|
2537
|
+
return self._json_url_providers[provider_key].get_data()
|
|
2224
2538
|
|
|
2225
2539
|
def fetch_parquet(
|
|
2226
2540
|
self,
|
|
@@ -2229,6 +2543,7 @@ class Context:
|
|
|
2229
2543
|
date_format=None,
|
|
2230
2544
|
cache=True,
|
|
2231
2545
|
refresh_interval=None,
|
|
2546
|
+
headers=None,
|
|
2232
2547
|
post_process=None,
|
|
2233
2548
|
):
|
|
2234
2549
|
"""
|
|
@@ -2247,6 +2562,10 @@ class Context:
|
|
|
2247
2562
|
cache (bool): Cache fetched data locally (default: True).
|
|
2248
2563
|
refresh_interval (str, optional): Re-fetch interval
|
|
2249
2564
|
(e.g., "1d", "1h").
|
|
2565
|
+
headers (dict, optional): HTTP headers to send with the
|
|
2566
|
+
request. Header values are redacted (replaced
|
|
2567
|
+
with "***") in ``DataSource.to_dict``, so
|
|
2568
|
+
secrets do not leak into diagnostic payloads.
|
|
2250
2569
|
post_process (callable, optional): Transform the parsed
|
|
2251
2570
|
DataFrame.
|
|
2252
2571
|
|
|
@@ -2266,19 +2585,22 @@ class Context:
|
|
|
2266
2585
|
if not hasattr(self, '_parquet_url_providers'):
|
|
2267
2586
|
self._parquet_url_providers = {}
|
|
2268
2587
|
|
|
2269
|
-
|
|
2588
|
+
provider_key = self._get_url_provider_cache_key(url, headers)
|
|
2589
|
+
|
|
2590
|
+
if provider_key not in self._parquet_url_providers:
|
|
2270
2591
|
provider = ParquetURLDataProvider(
|
|
2271
2592
|
url=url,
|
|
2272
2593
|
date_column=date_column,
|
|
2273
2594
|
date_format=date_format,
|
|
2274
2595
|
cache=cache,
|
|
2275
2596
|
refresh_interval=refresh_interval,
|
|
2597
|
+
headers=headers,
|
|
2276
2598
|
post_process=post_process,
|
|
2277
2599
|
)
|
|
2278
2600
|
provider.config = self.configuration_service.get_config()
|
|
2279
|
-
self._parquet_url_providers[
|
|
2601
|
+
self._parquet_url_providers[provider_key] = provider
|
|
2280
2602
|
|
|
2281
|
-
return self._parquet_url_providers[
|
|
2603
|
+
return self._parquet_url_providers[provider_key].get_data()
|
|
2282
2604
|
|
|
2283
2605
|
def batch_order(self, orders, market=None):
|
|
2284
2606
|
"""
|