investing-algorithm-framework 7.16.18__tar.gz → 7.19.1__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.
Potentially problematic release.
This version of investing-algorithm-framework might be problematic. Click here for more details.
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/PKG-INFO +1 -1
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/__init__.py +7 -4
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/__init__.py +4 -2
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/analysis/__init__.py +5 -1
- investing_algorithm_framework-7.19.1/investing_algorithm_framework/app/analysis/backtest_utils.py +80 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/app.py +106 -16
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/__init__.py +3 -2
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest.py +58 -14
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest_metrics.py +8 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest_run.py +31 -7
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +6 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/combine_backtests.py +13 -4
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/data_provider.py +5 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/exceptions.py +17 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/data_providers/ccxt.py +35 -1
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/data_providers/csv.py +42 -4
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/data_providers/pandas.py +37 -3
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/data_providers/data_provider_service.py +1 -1
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/pyproject.toml +1 -1
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/LICENSE +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/README.md +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/algorithm/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/algorithm/algorithm.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/algorithm/algorithm_factory.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/analysis/backtest_data_ranges.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/analysis/permutation.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/analysis/ranking.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/app_hook.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/context.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/eventloop.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/ascii.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/backtest_report.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/equity_curve.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/line_chart.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/generate.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/trades_table.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/tables/utils.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/strategy.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/task.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/create_app.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/error_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/responses.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/cli.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/deploy_to_aws_lambda.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/deploy_to_azure_function.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/initialize_app.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/.gitignore.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/app.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/app_azure_function.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/app_web.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/azure_function_host.json.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/data_providers.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/env.example.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/env_azure_function.example.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/market_data_providers.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/readme.md.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/requirements.txt.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/run_backtest.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/cli/templates/strategy.py.template +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/create_app.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/dependency_container.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest_date_range.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/config.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/constants.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/data_structures.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/app_mode.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/base_model.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/data/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/data/data_source.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/data/data_type.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/event.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/order/order.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/position/position.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/snapshot_interval.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/tracing/trace.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/trade/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/trade/trade.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/trade/trade_status.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/models/trade/trade_take_profit.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/order_executor.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/portfolio_provider.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/positions/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/positions/position_size.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/services/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/services/rounding_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/services/state_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/strategy.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/csv.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/custom_tqdm.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/dates.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/polars.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/random.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/download_data.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/data_providers/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/order/order.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/order/order_metadata.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/order_trade_association.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/trades/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/trades/trade.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/order_executors/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/trade_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/services/aws/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/services/aws/state_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/services/azure/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/infrastructure/services/azure/state_handler.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/backtesting/backtest_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/configuration_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/data_providers/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/alpha.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/beta.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/cagr.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/calmar_ratio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/drawdown.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/equity_curve.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/exposure.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/generate.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/mean_daily_return.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/price_efficiency.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/profit_factor.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/recovery.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/returns.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/risk_free_rate.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/sharpe_ratio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/sortino_ratio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/standard_deviation.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/trades.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/volatility.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/metrics/win_rate.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/order_service/order_backtest_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/order_service/order_executor_lookup.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/order_service/order_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/portfolio_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/positions/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/positions/position_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/positions/position_snapshot_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/repository_service.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/trade_order_evaluator/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/trade_service/__init__.py +0 -0
- {investing_algorithm_framework-7.16.18 → investing_algorithm_framework-7.19.1}/investing_algorithm_framework/services/trade_service/trade_service.py +0 -0
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
from .app import App, Algorithm, \
|
|
2
2
|
TradingStrategy, StatelessAction, Task, AppHook, Context, \
|
|
3
|
-
add_html_report, BacktestReport, \
|
|
3
|
+
add_html_report, BacktestReport, save_backtests_to_directory, \
|
|
4
4
|
pretty_print_trades, pretty_print_positions, \
|
|
5
5
|
pretty_print_orders, pretty_print_backtest, select_backtest_date_ranges, \
|
|
6
|
-
get_equity_curve_with_drawdown_chart, \
|
|
6
|
+
get_equity_curve_with_drawdown_chart, load_backtests_from_directory, \
|
|
7
7
|
get_rolling_sharpe_ratio_chart, rank_results, \
|
|
8
8
|
get_monthly_returns_heatmap_chart, create_weights, \
|
|
9
9
|
get_yearly_returns_bar_chart, get_entry_and_exit_signals, \
|
|
10
10
|
get_ohlcv_data_completeness_chart, get_equity_curve_chart
|
|
11
11
|
from .domain import ApiException, combine_backtests, PositionSize, \
|
|
12
12
|
OrderType, OperationalException, OrderStatus, OrderSide, \
|
|
13
|
-
TimeUnit, TimeInterval, Order, Portfolio, Backtest, \
|
|
13
|
+
TimeUnit, TimeInterval, Order, Portfolio, Backtest, DataError, \
|
|
14
14
|
Position, TimeFrame, INDEX_DATETIME, MarketCredential, \
|
|
15
15
|
PortfolioConfiguration, RESOURCE_DIRECTORY, AWS_LAMBDA_LOGGING_CONFIG, \
|
|
16
16
|
Trade, SYMBOLS, RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT, \
|
|
@@ -189,5 +189,8 @@ __all__ = [
|
|
|
189
189
|
"get_negative_trades",
|
|
190
190
|
"get_positive_trades",
|
|
191
191
|
"get_number_of_trades",
|
|
192
|
-
"BacktestRun"
|
|
192
|
+
"BacktestRun",
|
|
193
|
+
"load_backtests_from_directory",
|
|
194
|
+
"save_backtests_to_directory",
|
|
195
|
+
"DataError"
|
|
193
196
|
]
|
|
@@ -14,7 +14,7 @@ from .reporting import add_html_report, \
|
|
|
14
14
|
get_yearly_returns_bar_chart, get_equity_curve_chart, \
|
|
15
15
|
get_ohlcv_data_completeness_chart, get_entry_and_exit_signals
|
|
16
16
|
from .analysis import select_backtest_date_ranges, rank_results, \
|
|
17
|
-
create_weights
|
|
17
|
+
create_weights, load_backtests_from_directory, save_backtests_to_directory
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
__all__ = [
|
|
@@ -41,5 +41,7 @@ __all__ = [
|
|
|
41
41
|
"rank_results",
|
|
42
42
|
"create_weights",
|
|
43
43
|
"get_entry_and_exit_signals",
|
|
44
|
-
"get_equity_curve_chart"
|
|
44
|
+
"get_equity_curve_chart",
|
|
45
|
+
"load_backtests_from_directory",
|
|
46
|
+
"save_backtests_to_directory"
|
|
45
47
|
]
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from .backtest_data_ranges import select_backtest_date_ranges
|
|
2
2
|
from .ranking import rank_results, create_weights, combine_backtest_metrics
|
|
3
3
|
from .permutation import create_ohlcv_permutation
|
|
4
|
+
from .backtest_utils import load_backtests_from_directory, \
|
|
5
|
+
save_backtests_to_directory
|
|
4
6
|
|
|
5
7
|
__all__ = [
|
|
6
8
|
"select_backtest_date_ranges",
|
|
7
9
|
"rank_results",
|
|
8
10
|
"create_weights",
|
|
9
11
|
"create_ohlcv_permutation",
|
|
10
|
-
"combine_backtest_metrics"
|
|
12
|
+
"combine_backtest_metrics",
|
|
13
|
+
"load_backtests_from_directory",
|
|
14
|
+
"save_backtests_to_directory"
|
|
11
15
|
]
|
investing_algorithm_framework-7.19.1/investing_algorithm_framework/app/analysis/backtest_utils.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List, Union
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
from random import Random
|
|
6
|
+
|
|
7
|
+
from investing_algorithm_framework.domain import Backtest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
logger = getLogger("investing_algorithm_framework")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def save_backtests_to_directory(
|
|
14
|
+
backtests: List[Backtest],
|
|
15
|
+
directory_path: Union[str, Path]
|
|
16
|
+
) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Saves a list of Backtest objects to the specified directory.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
backtests (List[Backtest]): List of Backtest objects to save.
|
|
22
|
+
directory_path (str): Path to the directory where backtests
|
|
23
|
+
will be saved.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
None
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
if not os.path.exists(directory_path):
|
|
30
|
+
os.makedirs(directory_path)
|
|
31
|
+
|
|
32
|
+
for backtest in backtests:
|
|
33
|
+
# Check if there is an ID in the backtest metadata
|
|
34
|
+
backtest_id = backtest.metadata.get('id')
|
|
35
|
+
|
|
36
|
+
if backtest_id is None:
|
|
37
|
+
logger.warning(
|
|
38
|
+
"Backtest is missing 'id' in metadata. "
|
|
39
|
+
"Generating a random ID as name for backtest file."
|
|
40
|
+
)
|
|
41
|
+
backtest_id = str(Random().randint(100000, 999999))
|
|
42
|
+
|
|
43
|
+
backtest.save(os.path.join(directory_path, backtest_id))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def load_backtests_from_directory(
|
|
47
|
+
directory_path: Union[str, Path]
|
|
48
|
+
) -> List[Backtest]:
|
|
49
|
+
"""
|
|
50
|
+
Loads Backtest objects from the specified directory.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
directory_path (str): Path to the directory from which backtests
|
|
54
|
+
will be loaded.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
List[Backtest]: List of loaded Backtest objects.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
backtests = []
|
|
61
|
+
|
|
62
|
+
if not os.path.exists(directory_path):
|
|
63
|
+
logger.warning(
|
|
64
|
+
f"Directory {directory_path} does not exist. "
|
|
65
|
+
"No backtests loaded."
|
|
66
|
+
)
|
|
67
|
+
return backtests
|
|
68
|
+
|
|
69
|
+
for file_name in os.listdir(directory_path):
|
|
70
|
+
file_path = os.path.join(directory_path, file_name)
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
backtest = Backtest.open(file_path)
|
|
74
|
+
backtests.append(backtest)
|
|
75
|
+
except Exception as e:
|
|
76
|
+
logger.error(
|
|
77
|
+
f"Failed to load backtest from {file_path}: {e}"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
return backtests
|
|
@@ -5,6 +5,7 @@ import threading
|
|
|
5
5
|
from datetime import datetime, timezone
|
|
6
6
|
from typing import List, Optional, Any, Dict, Tuple
|
|
7
7
|
|
|
8
|
+
import pandas as pd
|
|
8
9
|
from flask import Flask
|
|
9
10
|
|
|
10
11
|
from investing_algorithm_framework.app.algorithm import Algorithm
|
|
@@ -16,7 +17,7 @@ from investing_algorithm_framework.domain import DATABASE_NAME, TimeUnit, \
|
|
|
16
17
|
SQLALCHEMY_DATABASE_URI, OperationalException, StateHandler, \
|
|
17
18
|
BACKTESTING_START_DATE, BACKTESTING_END_DATE, APP_MODE, MarketCredential, \
|
|
18
19
|
AppMode, BacktestDateRange, DATABASE_DIRECTORY_NAME, DataSource, \
|
|
19
|
-
BACKTESTING_INITIAL_AMOUNT, SNAPSHOT_INTERVAL, Backtest, \
|
|
20
|
+
BACKTESTING_INITIAL_AMOUNT, SNAPSHOT_INTERVAL, Backtest, DataError, \
|
|
20
21
|
PortfolioConfiguration, SnapshotInterval, DataType, combine_backtests, \
|
|
21
22
|
PortfolioProvider, OrderExecutor, ImproperlyConfigured, \
|
|
22
23
|
DataProvider, INDEX_DATETIME, tqdm, BacktestPermutationTest, \
|
|
@@ -32,6 +33,7 @@ from .app_hook import AppHook
|
|
|
32
33
|
from .eventloop import EventLoopService
|
|
33
34
|
from .analysis import create_ohlcv_permutation
|
|
34
35
|
|
|
36
|
+
|
|
35
37
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
36
38
|
COLOR_RESET = '\033[0m'
|
|
37
39
|
COLOR_GREEN = '\033[92m'
|
|
@@ -789,6 +791,70 @@ class App:
|
|
|
789
791
|
.market_credential_service()
|
|
790
792
|
return market_credential_service.get_all()
|
|
791
793
|
|
|
794
|
+
def check_data_completeness(
|
|
795
|
+
self,
|
|
796
|
+
strategies: List[TradingStrategy],
|
|
797
|
+
backtest_date_range: BacktestDateRange
|
|
798
|
+
) -> None:
|
|
799
|
+
"""
|
|
800
|
+
Function to check the data completeness for a set of strategies
|
|
801
|
+
over a given backtest date range. This method checks if all data
|
|
802
|
+
sources required by the strategies have complete data for the
|
|
803
|
+
specified date range.
|
|
804
|
+
|
|
805
|
+
Args:
|
|
806
|
+
strategies (List[TradingStrategy]): List of strategy objects
|
|
807
|
+
to check data completeness for.
|
|
808
|
+
backtest_date_range (BacktestDateRange): The date range to
|
|
809
|
+
check data completeness for.
|
|
810
|
+
Returns:
|
|
811
|
+
None
|
|
812
|
+
"""
|
|
813
|
+
data_sources = []
|
|
814
|
+
|
|
815
|
+
for strategy in strategies:
|
|
816
|
+
data_sources.extend(strategy.data_sources)
|
|
817
|
+
|
|
818
|
+
self.initialize_data_sources_backtest(
|
|
819
|
+
data_sources,
|
|
820
|
+
backtest_date_range,
|
|
821
|
+
show_progress=True
|
|
822
|
+
)
|
|
823
|
+
data_provider_service = self.container.data_provider_service()
|
|
824
|
+
|
|
825
|
+
for strategy in strategies:
|
|
826
|
+
|
|
827
|
+
for data_source in strategy.data_sources:
|
|
828
|
+
|
|
829
|
+
if DataType.OHLCV.equals(data_source.data_type):
|
|
830
|
+
df = data_provider_service.get_ohlcv_data(
|
|
831
|
+
symbol=data_source.symbol,
|
|
832
|
+
start_date=backtest_date_range.start_date,
|
|
833
|
+
end_date=backtest_date_range.end_date,
|
|
834
|
+
pandas=True
|
|
835
|
+
)
|
|
836
|
+
df = df.copy()
|
|
837
|
+
df['Datetime'] = pd.to_datetime(df['Datetime'])
|
|
838
|
+
df = df.sort_values('Datetime')\
|
|
839
|
+
.tail(data_source.window_size)
|
|
840
|
+
start = df['Datetime'].iloc[0]
|
|
841
|
+
end = df['Datetime'].iloc[-1]
|
|
842
|
+
freq = pd.to_timedelta(data_source.time_frame.value)
|
|
843
|
+
expected = pd.date_range(start, end, freq=freq)
|
|
844
|
+
actual = df['Datetime']
|
|
845
|
+
missing = expected.difference(actual)
|
|
846
|
+
|
|
847
|
+
# Calculate the percentage completeness
|
|
848
|
+
completeness = len(actual) / len(expected) * 100
|
|
849
|
+
|
|
850
|
+
if completeness < 100:
|
|
851
|
+
raise DataError(
|
|
852
|
+
f"Data completeness for data source "
|
|
853
|
+
f"{data_source.identifier} "
|
|
854
|
+
f"({data_source.symbol}) is {completeness:.2f}% "
|
|
855
|
+
f"complete. Missing data points: {len(missing)}"
|
|
856
|
+
)
|
|
857
|
+
|
|
792
858
|
def run_vector_backtests(
|
|
793
859
|
self,
|
|
794
860
|
initial_amount,
|
|
@@ -801,6 +867,7 @@ class App:
|
|
|
801
867
|
show_progress: bool = True,
|
|
802
868
|
market: Optional[str] = None,
|
|
803
869
|
trading_symbol: Optional[str] = None,
|
|
870
|
+
continue_on_error: bool = False,
|
|
804
871
|
) -> List[Backtest]:
|
|
805
872
|
"""
|
|
806
873
|
Run vectorized backtests for a set of strategies. The provided
|
|
@@ -848,6 +915,10 @@ class App:
|
|
|
848
915
|
trading_symbol (str): The trading symbol to use for the backtest.
|
|
849
916
|
This is used to create a portfolio configuration if no
|
|
850
917
|
portfolio configuration is provided in the strategy.
|
|
918
|
+
continue_on_error (bool): Whether to continue running other
|
|
919
|
+
backtests if an error occurs in one of the backtests. If set
|
|
920
|
+
to True, the backtest will return an empty Backtest instance
|
|
921
|
+
in case of an error. If set to False, the error will be raised.
|
|
851
922
|
|
|
852
923
|
Returns:
|
|
853
924
|
List[Backtest]: List of Backtest instances for each strategy
|
|
@@ -956,7 +1027,8 @@ class App:
|
|
|
956
1027
|
show_data_initialization_progress: bool = True,
|
|
957
1028
|
initial_amount: float = None,
|
|
958
1029
|
market: str = None,
|
|
959
|
-
trading_symbol: str = None
|
|
1030
|
+
trading_symbol: str = None,
|
|
1031
|
+
continue_on_error: bool = False,
|
|
960
1032
|
) -> Backtest:
|
|
961
1033
|
"""
|
|
962
1034
|
Run vectorized backtests for a strategy. The provided
|
|
@@ -1008,6 +1080,10 @@ class App:
|
|
|
1008
1080
|
that the portfolio will start with. If not provided,
|
|
1009
1081
|
the initial amount from the portfolio configuration will
|
|
1010
1082
|
be used.
|
|
1083
|
+
continue_on_error (bool): Whether to continue running other
|
|
1084
|
+
backtests if an error occurs in one of the backtests. If set
|
|
1085
|
+
to True, the backtest will return an empty Backtest instance
|
|
1086
|
+
in case of an error. If set to False, the error will be raised.
|
|
1011
1087
|
|
|
1012
1088
|
Returns:
|
|
1013
1089
|
Backtest: Instance of Backtest
|
|
@@ -1040,21 +1116,35 @@ class App:
|
|
|
1040
1116
|
|
|
1041
1117
|
backtest_service = self.container.backtest_service()
|
|
1042
1118
|
backtest_service.validate_strategy_for_vector_backtest(strategy)
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
backtest_runs=[run],
|
|
1053
|
-
risk_free_rate=risk_free_rate,
|
|
1054
|
-
backtest_summary=generate_backtest_summary_metrics(
|
|
1055
|
-
[run.backtest_metrics]
|
|
1119
|
+
|
|
1120
|
+
try:
|
|
1121
|
+
run = backtest_service.create_vector_backtest(
|
|
1122
|
+
strategy=strategy,
|
|
1123
|
+
backtest_date_range=backtest_date_range,
|
|
1124
|
+
risk_free_rate=risk_free_rate,
|
|
1125
|
+
market=market,
|
|
1126
|
+
trading_symbol=trading_symbol,
|
|
1127
|
+
initial_amount=initial_amount
|
|
1056
1128
|
)
|
|
1057
|
-
|
|
1129
|
+
backtest = Backtest(
|
|
1130
|
+
backtest_runs=[run],
|
|
1131
|
+
risk_free_rate=risk_free_rate,
|
|
1132
|
+
backtest_summary=generate_backtest_summary_metrics(
|
|
1133
|
+
[run.backtest_metrics]
|
|
1134
|
+
)
|
|
1135
|
+
)
|
|
1136
|
+
except Exception as e:
|
|
1137
|
+
logger.error(
|
|
1138
|
+
f"Error occurred during vector backtest for strategy "
|
|
1139
|
+
f"{strategy.strategy_id}: {str(e)}"
|
|
1140
|
+
)
|
|
1141
|
+
if continue_on_error:
|
|
1142
|
+
backtest = Backtest(
|
|
1143
|
+
backtest_runs=[],
|
|
1144
|
+
risk_free_rate=risk_free_rate,
|
|
1145
|
+
)
|
|
1146
|
+
else:
|
|
1147
|
+
raise e
|
|
1058
1148
|
|
|
1059
1149
|
# Add the metadata to the backtest
|
|
1060
1150
|
if metadata is None:
|
|
@@ -15,7 +15,7 @@ from .constants import ITEMIZE, ITEMIZED, PER_PAGE, PAGE, ENVIRONMENT, \
|
|
|
15
15
|
from .data_provider import DataProvider
|
|
16
16
|
from .data_structures import PeekableQueue
|
|
17
17
|
from .decimal_parsing import parse_decimal_to_string, parse_string_to_decimal
|
|
18
|
-
from .exceptions import OperationalException, ApiException, \
|
|
18
|
+
from .exceptions import OperationalException, ApiException, DataError, \
|
|
19
19
|
PermissionDeniedApiException, ImproperlyConfigured, NetworkError
|
|
20
20
|
from .models import OrderStatus, OrderSide, OrderType, TimeInterval, \
|
|
21
21
|
TimeUnit, TimeFrame, PortfolioConfiguration, Portfolio, Position, \
|
|
@@ -143,5 +143,6 @@ __all__ = [
|
|
|
143
143
|
"BacktestEvaluationFocus",
|
|
144
144
|
'combine_backtests',
|
|
145
145
|
'PositionSize',
|
|
146
|
-
'generate_backtest_summary_metrics'
|
|
146
|
+
'generate_backtest_summary_metrics',
|
|
147
|
+
'DataError'
|
|
147
148
|
]
|
|
@@ -14,6 +14,7 @@ from .backtest_run import BacktestRun
|
|
|
14
14
|
from .backtest_permutation_test import BacktestPermutationTest
|
|
15
15
|
from .backtest_date_range import BacktestDateRange
|
|
16
16
|
from .backtest_summary_metrics import BacktestSummaryMetrics
|
|
17
|
+
from .combine_backtests import generate_backtest_summary_metrics
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
logger = getLogger(__name__)
|
|
@@ -177,13 +178,19 @@ class Backtest:
|
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
@staticmethod
|
|
180
|
-
def open(
|
|
181
|
+
def open(
|
|
182
|
+
directory_path: Union[str, Path],
|
|
183
|
+
backtest_date_ranges: List[BacktestDateRange] = None
|
|
184
|
+
) -> 'Backtest':
|
|
181
185
|
"""
|
|
182
186
|
Open a backtest report from a directory and return a Backtest instance.
|
|
183
187
|
|
|
184
188
|
Args:
|
|
185
189
|
directory_path (str): The path to the directory containing the
|
|
186
190
|
backtest report files.
|
|
191
|
+
backtest_date_ranges (List[BacktestDateRange], optional): A list of
|
|
192
|
+
date ranges to filter the backtest runs. If provided, only
|
|
193
|
+
backtest runs matching these date ranges will be loaded.
|
|
187
194
|
|
|
188
195
|
Returns:
|
|
189
196
|
Backtest: An instance of Backtest with the loaded metrics
|
|
@@ -214,13 +221,59 @@ class Backtest:
|
|
|
214
221
|
except json.JSONDecodeError as e:
|
|
215
222
|
logger.error(f"Error decoding id JSON: {e}")
|
|
216
223
|
id = None
|
|
217
|
-
# Load combined backtest metrics if available
|
|
218
224
|
|
|
219
|
-
|
|
225
|
+
# Load all backtest runs
|
|
226
|
+
runs_dir = os.path.join(directory_path, "runs")
|
|
227
|
+
|
|
228
|
+
if os.path.isdir(runs_dir):
|
|
229
|
+
for dir_name in os.listdir(runs_dir):
|
|
230
|
+
run_path = os.path.join(runs_dir, dir_name)
|
|
231
|
+
if os.path.isdir(run_path):
|
|
232
|
+
|
|
233
|
+
if backtest_date_ranges is not None:
|
|
234
|
+
temp_run = BacktestRun.open(run_path)
|
|
235
|
+
match_found = False
|
|
236
|
+
|
|
237
|
+
for date_range in backtest_date_ranges:
|
|
238
|
+
if (
|
|
239
|
+
temp_run.backtest_start_date ==
|
|
240
|
+
date_range.start_date and
|
|
241
|
+
temp_run.backtest_end_date ==
|
|
242
|
+
date_range.end_date
|
|
243
|
+
):
|
|
244
|
+
|
|
245
|
+
if date_range.name is not None:
|
|
246
|
+
if (
|
|
247
|
+
temp_run.backtest_date_range_name ==
|
|
248
|
+
date_range.name
|
|
249
|
+
):
|
|
250
|
+
match_found = True
|
|
251
|
+
break
|
|
252
|
+
else:
|
|
253
|
+
match_found = True
|
|
254
|
+
break
|
|
255
|
+
|
|
256
|
+
if not match_found:
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
backtest_runs.append(BacktestRun.open(run_path))
|
|
260
|
+
|
|
261
|
+
# Load combined backtests summary
|
|
262
|
+
if backtest_date_ranges is not None:
|
|
263
|
+
summary_file = os.path.join(directory_path, "summary.json")
|
|
264
|
+
|
|
265
|
+
if os.path.isfile(summary_file):
|
|
266
|
+
backtest_summary_metrics = \
|
|
267
|
+
BacktestSummaryMetrics.open(summary_file)
|
|
268
|
+
else:
|
|
269
|
+
# Generate new summary from loaded backtest runs
|
|
270
|
+
temp_metrics = []
|
|
271
|
+
for br in backtest_runs:
|
|
272
|
+
if br.backtest_metrics:
|
|
273
|
+
temp_metrics.append(br.backtest_metrics)
|
|
220
274
|
|
|
221
|
-
if os.path.isfile(summary_file):
|
|
222
275
|
backtest_summary_metrics = \
|
|
223
|
-
|
|
276
|
+
generate_backtest_summary_metrics(temp_metrics)
|
|
224
277
|
|
|
225
278
|
# Load backtest permutation test metrics
|
|
226
279
|
perm_test_dir = os.path.join(directory_path, "permutation_tests")
|
|
@@ -233,15 +286,6 @@ class Backtest:
|
|
|
233
286
|
BacktestPermutationTest.open(perm_test_file)
|
|
234
287
|
)
|
|
235
288
|
|
|
236
|
-
# Load all backtest runs
|
|
237
|
-
runs_dir = os.path.join(directory_path, "runs")
|
|
238
|
-
|
|
239
|
-
if os.path.isdir(runs_dir):
|
|
240
|
-
for dir_name in os.listdir(runs_dir):
|
|
241
|
-
run_path = os.path.join(runs_dir, dir_name)
|
|
242
|
-
if os.path.isdir(run_path):
|
|
243
|
-
backtest_runs.append(BacktestRun.open(run_path))
|
|
244
|
-
|
|
245
289
|
# Load metadata if available
|
|
246
290
|
meta_file = os.path.join(directory_path, "metadata.json")
|
|
247
291
|
|
|
@@ -104,8 +104,12 @@ class BacktestMetrics:
|
|
|
104
104
|
still open at the end of the backtest.
|
|
105
105
|
win_rate (float): The win rate of the trades, expressed
|
|
106
106
|
as a percentage.
|
|
107
|
+
current_win_rate (float): The current win rate of the trades,
|
|
108
|
+
including open trades.
|
|
107
109
|
win_loss_ratio (float): The ratio of winning trades
|
|
108
110
|
to losing trades.
|
|
111
|
+
current_win_loss_ratio (float): The current ratio of winning
|
|
112
|
+
trades to losing trades, including open trades.
|
|
109
113
|
percentage_winning_months (float): The percentage of months
|
|
110
114
|
with positive returns.
|
|
111
115
|
percentage_winning_years (float): The percentage of years with
|
|
@@ -193,7 +197,9 @@ class BacktestMetrics:
|
|
|
193
197
|
number_of_trades_opened: int = 0
|
|
194
198
|
number_of_trades_open_at_end: int = 0
|
|
195
199
|
win_rate: float = 0.0
|
|
200
|
+
current_win_rate: float = 0.0
|
|
196
201
|
win_loss_ratio: float = 0.0
|
|
202
|
+
current_win_loss_ratio: float = 0.0
|
|
197
203
|
percentage_winning_months: float = 0.0
|
|
198
204
|
percentage_winning_years: float = 0.0
|
|
199
205
|
average_monthly_return: float = 0.0
|
|
@@ -289,7 +295,9 @@ class BacktestMetrics:
|
|
|
289
295
|
"number_of_trades_closed": self.number_of_trades_closed,
|
|
290
296
|
"number_of_trades_opened": self.number_of_trades_opened,
|
|
291
297
|
"win_rate": self.win_rate,
|
|
298
|
+
"current_win_rate": self.current_win_rate,
|
|
292
299
|
"win_loss_ratio": self.win_loss_ratio,
|
|
300
|
+
"current_win_loss_ratio": self.current_win_loss_ratio,
|
|
293
301
|
"percentage_winning_months": self.percentage_winning_months,
|
|
294
302
|
"percentage_winning_years": self.percentage_winning_years,
|
|
295
303
|
"average_monthly_return": self.average_monthly_return,
|
|
@@ -251,17 +251,41 @@ class BacktestRun:
|
|
|
251
251
|
# Remove backtest_metrics to avoid redundancy
|
|
252
252
|
data.pop("backtest_metrics", None)
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
# Ensure datetime objects are in UTC before formatting
|
|
255
|
+
backtest_start_date = self.backtest_start_date
|
|
256
|
+
|
|
257
|
+
if backtest_start_date.tzinfo is None:
|
|
258
|
+
# Naive datetime - treat as UTC
|
|
259
|
+
backtest_start_date = backtest_start_date.replace(
|
|
260
|
+
tzinfo=timezone.utc
|
|
261
|
+
)
|
|
262
|
+
else:
|
|
263
|
+
# Timezone-aware - convert to UTC
|
|
264
|
+
backtest_start_date = backtest_start_date.astimezone(
|
|
265
|
+
timezone.utc
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
backtest_end_date = self.backtest_end_date
|
|
269
|
+
if backtest_end_date.tzinfo is None:
|
|
270
|
+
backtest_end_date = backtest_end_date.replace(
|
|
271
|
+
tzinfo=timezone.utc
|
|
272
|
+
)
|
|
273
|
+
else:
|
|
274
|
+
backtest_end_date = backtest_end_date.astimezone(timezone.utc)
|
|
275
|
+
|
|
276
|
+
created_at = self.created_at
|
|
277
|
+
if created_at.tzinfo is None:
|
|
278
|
+
created_at = created_at.replace(tzinfo=timezone.utc)
|
|
279
|
+
else:
|
|
280
|
+
created_at = created_at.astimezone(timezone.utc)
|
|
281
|
+
|
|
282
|
+
data["backtest_start_date"] = backtest_start_date.strftime(
|
|
255
283
|
"%Y-%m-%d %H:%M:%S"
|
|
256
284
|
)
|
|
257
|
-
data["backtest_end_date"] =
|
|
285
|
+
data["backtest_end_date"] = backtest_end_date.strftime(
|
|
258
286
|
"%Y-%m-%d %H:%M:%S"
|
|
259
287
|
)
|
|
260
|
-
|
|
261
|
-
if self.created_at.tzinfo is None:
|
|
262
|
-
self.created_at = self.created_at.replace(tzinfo=timezone.utc)
|
|
263
|
-
|
|
264
|
-
data["created_at"] = self.created_at.strftime(
|
|
288
|
+
data["created_at"] = created_at.strftime(
|
|
265
289
|
"%Y-%m-%d %H:%M:%S"
|
|
266
290
|
)
|
|
267
291
|
json.dump(data, f, default=str)
|
|
@@ -48,7 +48,9 @@ class BacktestSummaryMetrics:
|
|
|
48
48
|
max_drawdown_duration (int): Duration of the maximum drawdown.
|
|
49
49
|
trades_per_year (float): Average trades executed per year.
|
|
50
50
|
win_rate (float): Percentage of winning trades.
|
|
51
|
+
current_win_rate (float): Win rate over recent trades.
|
|
51
52
|
win_loss_ratio (float): Ratio of average win to average loss.
|
|
53
|
+
current_win_loss_ratio (float): Win/loss ratio over recent trades.
|
|
52
54
|
number_of_trades (int): Total number of trades executed.
|
|
53
55
|
cumulative_exposure (float): Total exposure over the backtest period.
|
|
54
56
|
exposure_ratio (float): Ratio of exposure to available capital.
|
|
@@ -81,7 +83,9 @@ class BacktestSummaryMetrics:
|
|
|
81
83
|
max_drawdown_duration: int = None
|
|
82
84
|
trades_per_year: float = None
|
|
83
85
|
win_rate: float = None
|
|
86
|
+
current_win_rate: float = None
|
|
84
87
|
win_loss_ratio: float = None
|
|
88
|
+
current_win_loss_ratio: float = None
|
|
85
89
|
number_of_trades: int = None
|
|
86
90
|
number_of_trades_closed: int = None
|
|
87
91
|
cumulative_exposure: float = None
|
|
@@ -123,7 +127,9 @@ class BacktestSummaryMetrics:
|
|
|
123
127
|
"max_drawdown_duration": self.max_drawdown_duration,
|
|
124
128
|
"trades_per_year": self.trades_per_year,
|
|
125
129
|
"win_rate": self.win_rate,
|
|
130
|
+
"current_win_rate": self.current_win_rate,
|
|
126
131
|
"win_loss_ratio": self.win_loss_ratio,
|
|
132
|
+
"current_win_loss_ratio": self.current_win_loss_ratio,
|
|
127
133
|
"number_of_trades": self.number_of_trades,
|
|
128
134
|
"number_of_trades_closed": self.number_of_trades_closed,
|
|
129
135
|
"cumulative_exposure": self.cumulative_exposure,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import List
|
|
2
2
|
|
|
3
|
-
from .backtest import Backtest
|
|
4
3
|
from .backtest_summary_metrics import BacktestSummaryMetrics
|
|
5
4
|
from .backtest_metrics import BacktestMetrics
|
|
6
5
|
|
|
@@ -27,9 +26,7 @@ def safe_weighted_mean(values, weights):
|
|
|
27
26
|
) / total_weight if total_weight > 0 else None
|
|
28
27
|
|
|
29
28
|
|
|
30
|
-
def combine_backtests(
|
|
31
|
-
backtests: List[Backtest],
|
|
32
|
-
) -> Backtest:
|
|
29
|
+
def combine_backtests(backtests):
|
|
33
30
|
"""
|
|
34
31
|
Combine multiple backtests into a single backtest by aggregating
|
|
35
32
|
their results.
|
|
@@ -72,6 +69,8 @@ def combine_backtests(
|
|
|
72
69
|
risk_free_rate = backtest.risk_free_rate
|
|
73
70
|
break
|
|
74
71
|
|
|
72
|
+
from .backtest import Backtest
|
|
73
|
+
|
|
75
74
|
backtest = Backtest(
|
|
76
75
|
backtest_summary=summary,
|
|
77
76
|
metadata=metadata,
|
|
@@ -184,10 +183,18 @@ def generate_backtest_summary_metrics(
|
|
|
184
183
|
[b.win_rate for b in backtest_metrics],
|
|
185
184
|
[b.total_number_of_days for b in backtest_metrics]
|
|
186
185
|
)
|
|
186
|
+
current_win_rate = safe_weighted_mean(
|
|
187
|
+
[b.current_win_rate for b in backtest_metrics],
|
|
188
|
+
[b.total_number_of_days for b in backtest_metrics]
|
|
189
|
+
)
|
|
187
190
|
win_loss_ratio = safe_weighted_mean(
|
|
188
191
|
[b.win_loss_ratio for b in backtest_metrics],
|
|
189
192
|
[b.total_number_of_days for b in backtest_metrics]
|
|
190
193
|
)
|
|
194
|
+
current_win_loss_ratio = safe_weighted_mean(
|
|
195
|
+
[b.current_win_loss_ratio for b in backtest_metrics],
|
|
196
|
+
[b.total_number_of_days for b in backtest_metrics]
|
|
197
|
+
)
|
|
191
198
|
number_of_trades = sum(
|
|
192
199
|
b.number_of_trades for b in backtest_metrics
|
|
193
200
|
if b.number_of_trades is not None
|
|
@@ -251,7 +258,9 @@ def generate_backtest_summary_metrics(
|
|
|
251
258
|
max_drawdown_duration=max_drawdown_duration,
|
|
252
259
|
trades_per_year=trades_per_year,
|
|
253
260
|
win_rate=win_rate,
|
|
261
|
+
current_win_rate=current_win_rate,
|
|
254
262
|
win_loss_ratio=win_loss_ratio,
|
|
263
|
+
current_win_loss_ratio=current_win_loss_ratio,
|
|
255
264
|
number_of_trades=number_of_trades,
|
|
256
265
|
number_of_trades_closed=number_of_trades_closed,
|
|
257
266
|
cumulative_exposure=cumulative_exposure,
|
|
@@ -240,6 +240,7 @@ class DataProvider(ABC):
|
|
|
240
240
|
backtest_index_date: datetime,
|
|
241
241
|
backtest_start_date: datetime = None,
|
|
242
242
|
backtest_end_date: datetime = None,
|
|
243
|
+
data_source: DataSource = None,
|
|
243
244
|
) -> Any:
|
|
244
245
|
"""
|
|
245
246
|
Fetches backtest data for a given datasource
|
|
@@ -251,6 +252,10 @@ class DataProvider(ABC):
|
|
|
251
252
|
backtest data.
|
|
252
253
|
backtest_end_date (datetime): The end date for the
|
|
253
254
|
backtest data.
|
|
255
|
+
data_source (Optional[DataSource]): The data source
|
|
256
|
+
specification that is used to fetch the data.
|
|
257
|
+
This param is optional and can be used to
|
|
258
|
+
help identify errors in data fetching.
|
|
254
259
|
|
|
255
260
|
Returns:
|
|
256
261
|
Any: The data for the given symbol and date range.
|
|
@@ -84,3 +84,20 @@ class NetworkError(Exception):
|
|
|
84
84
|
"status": "error",
|
|
85
85
|
"message": self.error_message
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class DataError(Exception):
|
|
90
|
+
"""
|
|
91
|
+
Class DataError: Exception class indicating a problem occurred
|
|
92
|
+
during data retrieval or processing
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __init__(self, message) -> None:
|
|
96
|
+
super(DataError, self).__init__(message)
|
|
97
|
+
self.error_message = message
|
|
98
|
+
|
|
99
|
+
def to_response(self):
|
|
100
|
+
return {
|
|
101
|
+
"status": "error",
|
|
102
|
+
"message": self.error_message
|
|
103
|
+
}
|