investing-algorithm-framework 1.5__py3-none-any.whl → 7.25.6__py3-none-any.whl
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/__init__.py +192 -16
- investing_algorithm_framework/analysis/__init__.py +16 -0
- investing_algorithm_framework/analysis/backtest_data_ranges.py +202 -0
- investing_algorithm_framework/analysis/data.py +170 -0
- investing_algorithm_framework/analysis/markdown.py +91 -0
- investing_algorithm_framework/analysis/ranking.py +298 -0
- investing_algorithm_framework/app/__init__.py +29 -4
- investing_algorithm_framework/app/algorithm/__init__.py +7 -0
- investing_algorithm_framework/app/algorithm/algorithm.py +193 -0
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +118 -0
- investing_algorithm_framework/app/app.py +2220 -379
- investing_algorithm_framework/app/app_hook.py +28 -0
- investing_algorithm_framework/app/context.py +1724 -0
- investing_algorithm_framework/app/eventloop.py +620 -0
- investing_algorithm_framework/app/reporting/__init__.py +27 -0
- investing_algorithm_framework/app/reporting/ascii.py +921 -0
- investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
- investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
- investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
- investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
- investing_algorithm_framework/app/reporting/generate.py +185 -0
- investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
- investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
- investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
- investing_algorithm_framework/app/stateless/action_handlers/__init__.py +6 -3
- investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +2 -1
- investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
- investing_algorithm_framework/app/strategy.py +867 -60
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/app/web/__init__.py +2 -1
- investing_algorithm_framework/app/web/controllers/__init__.py +2 -2
- investing_algorithm_framework/app/web/controllers/orders.py +3 -2
- investing_algorithm_framework/app/web/controllers/positions.py +2 -2
- investing_algorithm_framework/app/web/create_app.py +4 -2
- investing_algorithm_framework/app/web/schemas/position.py +1 -0
- investing_algorithm_framework/cli/__init__.py +0 -0
- investing_algorithm_framework/cli/cli.py +231 -0
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
- investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
- investing_algorithm_framework/cli/initialize_app.py +603 -0
- investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
- investing_algorithm_framework/cli/templates/app.py.template +18 -0
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
- investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
- investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
- investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
- investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
- investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
- investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
- investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
- investing_algorithm_framework/cli/templates/env.example.template +2 -0
- investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
- investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
- investing_algorithm_framework/cli/templates/readme.md.template +135 -0
- investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
- investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
- investing_algorithm_framework/cli/validate_backtest_checkpoints.py +197 -0
- investing_algorithm_framework/create_app.py +40 -7
- investing_algorithm_framework/dependency_container.py +100 -47
- investing_algorithm_framework/domain/__init__.py +97 -30
- investing_algorithm_framework/domain/algorithm_id.py +69 -0
- investing_algorithm_framework/domain/backtesting/__init__.py +25 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +548 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +113 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +241 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +470 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +663 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/backtest_utils.py +198 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +392 -0
- investing_algorithm_framework/domain/config.py +59 -136
- investing_algorithm_framework/domain/constants.py +18 -37
- investing_algorithm_framework/domain/data_provider.py +334 -0
- investing_algorithm_framework/domain/data_structures.py +42 -0
- investing_algorithm_framework/domain/exceptions.py +51 -1
- investing_algorithm_framework/domain/models/__init__.py +26 -19
- investing_algorithm_framework/domain/models/app_mode.py +34 -0
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +222 -0
- investing_algorithm_framework/domain/models/data/data_type.py +46 -0
- investing_algorithm_framework/domain/models/event.py +35 -0
- investing_algorithm_framework/domain/models/market/__init__.py +5 -0
- investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
- investing_algorithm_framework/domain/models/order/__init__.py +3 -4
- investing_algorithm_framework/domain/models/order/order.py +198 -65
- investing_algorithm_framework/domain/models/order/order_status.py +2 -2
- investing_algorithm_framework/domain/models/order/order_type.py +1 -3
- investing_algorithm_framework/domain/models/portfolio/__init__.py +6 -2
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +98 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -43
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +20 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -2
- investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
- investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
- investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -141
- investing_algorithm_framework/domain/models/time_frame.py +94 -98
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +66 -2
- investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
- investing_algorithm_framework/domain/models/tracing/trace.py +23 -0
- investing_algorithm_framework/domain/models/trade/__init__.py +11 -0
- investing_algorithm_framework/domain/models/trade/trade.py +389 -0
- investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
- investing_algorithm_framework/domain/order_executor.py +112 -0
- investing_algorithm_framework/domain/portfolio_provider.py +118 -0
- investing_algorithm_framework/domain/services/__init__.py +11 -0
- investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
- investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
- investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
- investing_algorithm_framework/domain/services/rounding_service.py +27 -0
- investing_algorithm_framework/domain/services/state_handler.py +38 -0
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +15 -5
- investing_algorithm_framework/domain/utils/csv.py +22 -0
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/dates.py +57 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +53 -0
- investing_algorithm_framework/domain/utils/random.py +29 -0
- investing_algorithm_framework/download_data.py +244 -0
- investing_algorithm_framework/infrastructure/__init__.py +37 -11
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1152 -0
- investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
- investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
- investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
- investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
- investing_algorithm_framework/infrastructure/models/__init__.py +7 -3
- investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
- investing_algorithm_framework/infrastructure/models/order/order.py +53 -53
- investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
- investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
- investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -2
- investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -6
- investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +3 -1
- investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
- investing_algorithm_framework/infrastructure/repositories/__init__.py +10 -4
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +16 -5
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +84 -30
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +9 -4
- investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
- investing_algorithm_framework/infrastructure/services/aws/state_handler.py +193 -0
- investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
- investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
- investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +2596 -0
- investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +285 -0
- investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +468 -0
- investing_algorithm_framework/services/__init__.py +123 -15
- investing_algorithm_framework/services/configuration_service.py +77 -11
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +1058 -0
- investing_algorithm_framework/services/market_credential_service.py +40 -0
- investing_algorithm_framework/services/metrics/__init__.py +119 -0
- investing_algorithm_framework/services/metrics/alpha.py +0 -0
- investing_algorithm_framework/services/metrics/beta.py +0 -0
- investing_algorithm_framework/services/metrics/cagr.py +60 -0
- investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
- investing_algorithm_framework/services/metrics/drawdown.py +218 -0
- investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
- investing_algorithm_framework/services/metrics/exposure.py +210 -0
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/services/metrics/mean_daily_return.py +84 -0
- investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
- investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
- investing_algorithm_framework/services/metrics/recovery.py +113 -0
- investing_algorithm_framework/services/metrics/returns.py +452 -0
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
- investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
- investing_algorithm_framework/services/metrics/standard_deviation.py +156 -0
- investing_algorithm_framework/services/metrics/trades.py +473 -0
- investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- investing_algorithm_framework/services/metrics/volatility.py +118 -0
- investing_algorithm_framework/services/metrics/win_rate.py +177 -0
- investing_algorithm_framework/services/order_service/__init__.py +9 -0
- investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
- investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
- investing_algorithm_framework/services/order_service/order_service.py +826 -0
- investing_algorithm_framework/services/portfolios/__init__.py +16 -0
- investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
- investing_algorithm_framework/services/{portfolio_configuration_service.py → portfolios/portfolio_configuration_service.py} +27 -12
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
- investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
- investing_algorithm_framework/services/positions/__init__.py +7 -0
- investing_algorithm_framework/services/positions/position_service.py +210 -0
- investing_algorithm_framework/services/repository_service.py +8 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +117 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
- investing_algorithm_framework/services/trade_service/__init__.py +9 -0
- investing_algorithm_framework/services/trade_service/trade_service.py +1099 -0
- investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
- investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
- investing_algorithm_framework-7.25.6.dist-info/METADATA +535 -0
- investing_algorithm_framework-7.25.6.dist-info/RECORD +268 -0
- {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/WHEEL +1 -2
- investing_algorithm_framework-7.25.6.dist-info/entry_points.txt +3 -0
- investing_algorithm_framework/app/algorithm.py +0 -630
- investing_algorithm_framework/domain/models/backtest_profile.py +0 -414
- investing_algorithm_framework/domain/models/market_data/__init__.py +0 -11
- investing_algorithm_framework/domain/models/market_data/asset_price.py +0 -50
- investing_algorithm_framework/domain/models/market_data/ohlcv.py +0 -105
- investing_algorithm_framework/domain/models/market_data/order_book.py +0 -63
- investing_algorithm_framework/domain/models/market_data/ticker.py +0 -92
- investing_algorithm_framework/domain/models/order/order_fee.py +0 -45
- investing_algorithm_framework/domain/models/trade.py +0 -78
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/singleton.py +0 -9
- investing_algorithm_framework/domain/utils/backtesting.py +0 -82
- investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
- investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
- investing_algorithm_framework/infrastructure/services/market_backtest_service.py +0 -360
- investing_algorithm_framework/infrastructure/services/market_service.py +0 -410
- investing_algorithm_framework/infrastructure/services/performance_service.py +0 -192
- investing_algorithm_framework/services/backtest_service.py +0 -268
- investing_algorithm_framework/services/market_data_service.py +0 -77
- investing_algorithm_framework/services/order_backtest_service.py +0 -122
- investing_algorithm_framework/services/order_service.py +0 -752
- investing_algorithm_framework/services/portfolio_service.py +0 -164
- investing_algorithm_framework/services/portfolio_snapshot_service.py +0 -68
- investing_algorithm_framework/services/position_cost_service.py +0 -5
- investing_algorithm_framework/services/position_service.py +0 -63
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -225
- investing_algorithm_framework-1.5.dist-info/AUTHORS.md +0 -8
- investing_algorithm_framework-1.5.dist-info/METADATA +0 -230
- investing_algorithm_framework-1.5.dist-info/RECORD +0 -119
- investing_algorithm_framework-1.5.dist-info/top_level.txt +0 -1
- /investing_algorithm_framework/{infrastructure/services/performance_backtest_service.py → app/reporting/tables/stop_loss_table.py} +0 -0
- /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
- {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from logging import getLogger
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
logger = getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class BacktestSummaryMetrics:
|
|
12
|
+
"""
|
|
13
|
+
Represents the summarized results of a backtest,
|
|
14
|
+
focusing on key headline performance and risk metrics.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
total_net_gain (float): Total net gain from the backtest.
|
|
18
|
+
total_net_gain_percentage (float): Total net gain percentage
|
|
19
|
+
from the backtest.
|
|
20
|
+
total_loss (float): Total gross loss from all trades.
|
|
21
|
+
total_loss_percentage (float): Total gross loss percentage.
|
|
22
|
+
total_growth (float): Total growth from the backtest.
|
|
23
|
+
total_growth_percentage (float): Total growth percentage
|
|
24
|
+
from the backtest.
|
|
25
|
+
average_net_gain (float): Average returns across multiple backtests.
|
|
26
|
+
average_net_gain_percentage (float): Average return percentage across
|
|
27
|
+
multiple backtests.
|
|
28
|
+
average_growth (float): Average growth across multiple backtests.
|
|
29
|
+
average_growth_percentage (float): Average growth percentage across
|
|
30
|
+
multiple backtests.
|
|
31
|
+
average_loss (float): Average loss across multiple backtests.
|
|
32
|
+
average_loss_percentage (float): Average loss percentage across
|
|
33
|
+
multiple backtests.
|
|
34
|
+
average_trade_return (float): Average return per trade.
|
|
35
|
+
average_trade_return_percentage (float): Average return percentage
|
|
36
|
+
per trade.
|
|
37
|
+
average_trade_loss (float): Total gross loss from all trades.
|
|
38
|
+
average_trade_loss_percentage (float): Average trade loss percentage.
|
|
39
|
+
average_trade_gain (float): Average gain from winning trades.
|
|
40
|
+
average_trade_gain_percentage (float): Average gain percentage
|
|
41
|
+
cagr (float): Compound annual growth rate of the backtest.
|
|
42
|
+
sharpe_ratio (float): Sharpe ratio, risk-adjusted return.
|
|
43
|
+
sortino_ratio (float): Sortino ratio, downside-risk adjusted return.
|
|
44
|
+
calmar_ratio (float): CAGR relative to max drawdown.
|
|
45
|
+
profit_factor (float): Total profit / total loss.
|
|
46
|
+
annual_volatility (float): Annualized volatility of returns.
|
|
47
|
+
max_drawdown (float): Maximum drawdown observed.
|
|
48
|
+
max_drawdown_duration (int): Duration of the maximum drawdown.
|
|
49
|
+
trades_per_year (float): Average trades executed per year.
|
|
50
|
+
win_rate (float): Percentage of winning trades.
|
|
51
|
+
current_win_rate (float): Win rate over recent trades.
|
|
52
|
+
win_loss_ratio (float): Ratio of average win to average loss.
|
|
53
|
+
current_win_loss_ratio (float): Win/loss ratio over recent trades.
|
|
54
|
+
number_of_trades (int): Total number of trades executed.
|
|
55
|
+
cumulative_exposure (float): Total exposure over the backtest period.
|
|
56
|
+
exposure_ratio (float): Ratio of exposure to available capital.
|
|
57
|
+
"""
|
|
58
|
+
total_net_gain: float = None
|
|
59
|
+
total_net_gain_percentage: float = None
|
|
60
|
+
total_growth: float = None
|
|
61
|
+
total_growth_percentage: float = None
|
|
62
|
+
total_loss: float = None
|
|
63
|
+
total_loss_percentage: float = None
|
|
64
|
+
average_net_gain: float = None
|
|
65
|
+
average_net_gain_percentage: float = None
|
|
66
|
+
average_growth: float = None
|
|
67
|
+
average_growth_percentage: float = None
|
|
68
|
+
average_loss: float = None
|
|
69
|
+
average_loss_percentage: float = None
|
|
70
|
+
average_trade_return: float = None
|
|
71
|
+
average_trade_return_percentage: float = None
|
|
72
|
+
average_trade_loss: float = None
|
|
73
|
+
average_trade_loss_percentage: float = None
|
|
74
|
+
average_trade_gain: float = None
|
|
75
|
+
average_trade_gain_percentage: float = None
|
|
76
|
+
cagr: float = None
|
|
77
|
+
sharpe_ratio: float = None
|
|
78
|
+
sortino_ratio: float = None
|
|
79
|
+
calmar_ratio: float = None
|
|
80
|
+
profit_factor: float = None
|
|
81
|
+
annual_volatility: float = None
|
|
82
|
+
max_drawdown: float = None
|
|
83
|
+
max_drawdown_duration: int = None
|
|
84
|
+
trades_per_year: float = None
|
|
85
|
+
win_rate: float = None
|
|
86
|
+
current_win_rate: float = None
|
|
87
|
+
win_loss_ratio: float = None
|
|
88
|
+
current_win_loss_ratio: float = None
|
|
89
|
+
number_of_trades: int = None
|
|
90
|
+
number_of_trades_closed: int = None
|
|
91
|
+
cumulative_exposure: float = None
|
|
92
|
+
exposure_ratio: float = None
|
|
93
|
+
|
|
94
|
+
def to_dict(self) -> dict:
|
|
95
|
+
"""
|
|
96
|
+
Convert the BacktestSummaryMetrics instance to a dictionary.
|
|
97
|
+
"""
|
|
98
|
+
return {
|
|
99
|
+
"total_net_gain": self.total_net_gain,
|
|
100
|
+
"total_net_gain_percentage": self.total_net_gain_percentage,
|
|
101
|
+
"total_growth": self.total_growth,
|
|
102
|
+
"total_growth_percentage": self.total_growth_percentage,
|
|
103
|
+
"total_loss": self.total_loss,
|
|
104
|
+
"total_loss_percentage": self.total_loss_percentage,
|
|
105
|
+
"average_loss": self.average_loss,
|
|
106
|
+
"average_loss_percentage": self.average_loss_percentage,
|
|
107
|
+
"average_net_gain": self.average_net_gain,
|
|
108
|
+
"average_net_gain_percentage": self.average_net_gain_percentage,
|
|
109
|
+
"average_growth": self.average_growth,
|
|
110
|
+
"average_growth_percentage": self.average_growth_percentage,
|
|
111
|
+
"average_trade_return": self.average_trade_return,
|
|
112
|
+
"average_trade_return_percentage":
|
|
113
|
+
self.average_trade_return_percentage,
|
|
114
|
+
"average_trade_loss": self.average_trade_loss,
|
|
115
|
+
"average_trade_loss_percentage":
|
|
116
|
+
self.average_trade_loss_percentage,
|
|
117
|
+
"average_trade_gain": self.average_trade_gain,
|
|
118
|
+
"average_trade_gain_percentage":
|
|
119
|
+
self.average_trade_gain_percentage,
|
|
120
|
+
"cagr": self.cagr,
|
|
121
|
+
"sharpe_ratio": self.sharpe_ratio,
|
|
122
|
+
"sortino_ratio": self.sortino_ratio,
|
|
123
|
+
"calmar_ratio": self.calmar_ratio,
|
|
124
|
+
"profit_factor": self.profit_factor,
|
|
125
|
+
"annual_volatility": self.annual_volatility,
|
|
126
|
+
"max_drawdown": self.max_drawdown,
|
|
127
|
+
"max_drawdown_duration": self.max_drawdown_duration,
|
|
128
|
+
"trades_per_year": self.trades_per_year,
|
|
129
|
+
"win_rate": self.win_rate,
|
|
130
|
+
"current_win_rate": self.current_win_rate,
|
|
131
|
+
"win_loss_ratio": self.win_loss_ratio,
|
|
132
|
+
"current_win_loss_ratio": self.current_win_loss_ratio,
|
|
133
|
+
"number_of_trades": self.number_of_trades,
|
|
134
|
+
"number_of_trades_closed": self.number_of_trades_closed,
|
|
135
|
+
"cumulative_exposure": self.cumulative_exposure,
|
|
136
|
+
"exposure_ratio": self.exposure_ratio,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
def save(self, file_path: str | Path) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Save the summary metrics to a JSON file.
|
|
142
|
+
"""
|
|
143
|
+
with open(file_path, 'w') as file:
|
|
144
|
+
json.dump(self.to_dict(), file, indent=4, default=str)
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def open(file_path: str | Path) -> 'BacktestSummaryMetrics':
|
|
148
|
+
"""
|
|
149
|
+
Load summary metrics from a JSON file.
|
|
150
|
+
"""
|
|
151
|
+
if not os.path.exists(file_path):
|
|
152
|
+
raise FileNotFoundError(f"Metrics file not found at {file_path}")
|
|
153
|
+
|
|
154
|
+
with open(file_path, 'r') as file:
|
|
155
|
+
data = json.load(file)
|
|
156
|
+
|
|
157
|
+
return BacktestSummaryMetrics(**data)
|
|
158
|
+
|
|
159
|
+
def __repr__(self):
|
|
160
|
+
return json.dumps(
|
|
161
|
+
self.to_dict(), indent=4, sort_keys=True, default=str
|
|
162
|
+
)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from logging import getLogger
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from random import Random
|
|
5
|
+
from typing import List, Union, Callable
|
|
6
|
+
|
|
7
|
+
from investing_algorithm_framework.domain.exceptions import \
|
|
8
|
+
OperationalException
|
|
9
|
+
from investing_algorithm_framework.domain.utils.custom_tqdm import tqdm
|
|
10
|
+
|
|
11
|
+
from .backtest import Backtest
|
|
12
|
+
|
|
13
|
+
logger = getLogger("investing_algorithm_framework")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def save_backtests_to_directory(
|
|
17
|
+
backtests: List[Backtest],
|
|
18
|
+
directory_path: Union[str, Path],
|
|
19
|
+
backtest_date_range=None,
|
|
20
|
+
dir_name_generation_function: Callable[[Backtest], str] = None,
|
|
21
|
+
number_of_backtests_to_save: int = None,
|
|
22
|
+
filter_function: Callable[[Backtest], bool] = None,
|
|
23
|
+
show_progress: bool = False
|
|
24
|
+
) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Saves a list of Backtest objects to the specified directory.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
backtests (List[Backtest]): List of Backtest objects to save.
|
|
30
|
+
directory_path (str): Path to the directory where backtests
|
|
31
|
+
will be saved.
|
|
32
|
+
backtest_date_range (BacktestDateRange, optional): Date range
|
|
33
|
+
to filter backtests before saving. If provided, only backtest runs
|
|
34
|
+
with this date range will be saved. Defaults to None.
|
|
35
|
+
dir_name_generation_function (Callable[[Backtest], str], optional):
|
|
36
|
+
A function that takes a Backtest object as input and returns
|
|
37
|
+
a string to be used as the directory name for that backtest.
|
|
38
|
+
If not provided, the backtest's algorithm_id will be used.
|
|
39
|
+
Defaults to None.
|
|
40
|
+
number_of_backtests_to_save (int, optional): Maximum number of
|
|
41
|
+
backtests to save. If None, all backtests will be saved.
|
|
42
|
+
filter_function (Callable[[Backtest], bool], optional): A function
|
|
43
|
+
that takes a Backtest object as input and returns True if the
|
|
44
|
+
backtest should be saved. Defaults to None.
|
|
45
|
+
show_progress (bool, optional): Whether to display a progress bar
|
|
46
|
+
while saving backtests. Defaults to False.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
None
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
if not os.path.exists(directory_path):
|
|
53
|
+
os.makedirs(directory_path)
|
|
54
|
+
|
|
55
|
+
if show_progress:
|
|
56
|
+
backtests = tqdm(backtests, desc="Saving backtests")
|
|
57
|
+
|
|
58
|
+
for backtest in backtests:
|
|
59
|
+
|
|
60
|
+
# Check if we have reached the limit of backtests to save
|
|
61
|
+
if number_of_backtests_to_save is not None:
|
|
62
|
+
if number_of_backtests_to_save <= 0:
|
|
63
|
+
break
|
|
64
|
+
|
|
65
|
+
number_of_backtests_to_save -= 1
|
|
66
|
+
|
|
67
|
+
if filter_function is not None:
|
|
68
|
+
if not filter_function(backtest):
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
if dir_name_generation_function is not None:
|
|
72
|
+
dir_name = dir_name_generation_function(backtest)
|
|
73
|
+
else:
|
|
74
|
+
|
|
75
|
+
if not hasattr(backtest, "algorithm_id"):
|
|
76
|
+
raise OperationalException(
|
|
77
|
+
"algorithm_id is not set in backtest instance,"
|
|
78
|
+
"cannot generate directory name automatically, "
|
|
79
|
+
"please make sure to set the algorithm_id field "
|
|
80
|
+
"in your strategies or provide "
|
|
81
|
+
"a dir_name_generation_function."
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Check if there is an ID in the backtest metadata
|
|
85
|
+
dir_name = backtest.algorithm_id
|
|
86
|
+
|
|
87
|
+
if dir_name is None:
|
|
88
|
+
logger.warning(
|
|
89
|
+
"Backtest algorithm_id is None. "
|
|
90
|
+
"Generating a random directory name."
|
|
91
|
+
)
|
|
92
|
+
dir_name = str(Random().randint(100000, 999999))
|
|
93
|
+
|
|
94
|
+
backtest.save(
|
|
95
|
+
os.path.join(directory_path, dir_name),
|
|
96
|
+
backtest_date_ranges=[backtest_date_range]
|
|
97
|
+
if backtest_date_range else None
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def load_backtests_from_directory(
|
|
102
|
+
directory_path: Union[str, Path],
|
|
103
|
+
filter_function: Callable[[Backtest], bool] = None,
|
|
104
|
+
number_of_backtests_to_load: int = None,
|
|
105
|
+
show_progress: bool = False
|
|
106
|
+
) -> List[Backtest]:
|
|
107
|
+
"""
|
|
108
|
+
Loads Backtest objects from the specified directory.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
directory_path (str): Path to the directory from which backtests
|
|
112
|
+
will be loaded.
|
|
113
|
+
filter_function (Callable[[Backtest], bool], optional): A function
|
|
114
|
+
that takes a Backtest object as input and returns True if the
|
|
115
|
+
backtest should be included in the result. Defaults to None.
|
|
116
|
+
number_of_backtests_to_load (int, optional): Maximum number of
|
|
117
|
+
backtests to load. If None, all backtests will be loaded.
|
|
118
|
+
show_progress (bool, optional): Whether to display a progress bar
|
|
119
|
+
while loading backtests. Defaults to False.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
List[Backtest]: List of loaded Backtest objects.
|
|
123
|
+
"""
|
|
124
|
+
|
|
125
|
+
backtests = []
|
|
126
|
+
|
|
127
|
+
if not os.path.exists(directory_path):
|
|
128
|
+
logger.warning(
|
|
129
|
+
f"Directory {directory_path} does not exist. "
|
|
130
|
+
"No backtests loaded."
|
|
131
|
+
)
|
|
132
|
+
return backtests
|
|
133
|
+
|
|
134
|
+
dirs = os.listdir(directory_path)
|
|
135
|
+
|
|
136
|
+
if show_progress:
|
|
137
|
+
dirs = tqdm(dirs, desc="Loading backtests")
|
|
138
|
+
|
|
139
|
+
for file_name in dirs:
|
|
140
|
+
|
|
141
|
+
# Check if the filename is not the checkpoints.json file or
|
|
142
|
+
# a python file
|
|
143
|
+
if file_name == "checkpoints.json" or file_name.endswith(".py"):
|
|
144
|
+
continue
|
|
145
|
+
|
|
146
|
+
# Check if we have reached the limit of backtests to load
|
|
147
|
+
if number_of_backtests_to_load is not None:
|
|
148
|
+
if number_of_backtests_to_load <= 0:
|
|
149
|
+
break
|
|
150
|
+
number_of_backtests_to_load -= 1
|
|
151
|
+
|
|
152
|
+
file_path = os.path.join(directory_path, file_name)
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
|
|
156
|
+
# Add step-by-step debugging
|
|
157
|
+
try:
|
|
158
|
+
backtest = Backtest.open(file_path)
|
|
159
|
+
except KeyError as ke:
|
|
160
|
+
logger.error(
|
|
161
|
+
f"KeyError during Backtest.open for {file_path}: {ke}"
|
|
162
|
+
)
|
|
163
|
+
import traceback
|
|
164
|
+
logger.error(
|
|
165
|
+
f"Backtest.open KeyError "
|
|
166
|
+
f"traceback: {traceback.format_exc()}"
|
|
167
|
+
)
|
|
168
|
+
continue # Skip this backtest and continue with the next one
|
|
169
|
+
except Exception as be:
|
|
170
|
+
logger.error(
|
|
171
|
+
f"Other error during Backtest.open for {file_path}: {be}"
|
|
172
|
+
)
|
|
173
|
+
import traceback
|
|
174
|
+
logger.error(
|
|
175
|
+
f"Backtest.open error traceback: {traceback.format_exc()}"
|
|
176
|
+
)
|
|
177
|
+
continue # Skip this backtest and continue with the next one
|
|
178
|
+
|
|
179
|
+
if filter_function is not None:
|
|
180
|
+
try:
|
|
181
|
+
if not filter_function(backtest):
|
|
182
|
+
continue
|
|
183
|
+
except Exception as fe:
|
|
184
|
+
logger.error(
|
|
185
|
+
f"Error in filter_function for {file_path}: {fe}"
|
|
186
|
+
)
|
|
187
|
+
continue
|
|
188
|
+
|
|
189
|
+
backtests.append(backtest)
|
|
190
|
+
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.error(
|
|
193
|
+
f"Unexpected top-level error loading "
|
|
194
|
+
f"backtest from {file_path}: {e}"
|
|
195
|
+
)
|
|
196
|
+
import traceback
|
|
197
|
+
|
|
198
|
+
return backtests
|