investing-algorithm-framework 6.9.1__py3-none-any.whl → 7.19.15__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.
Potentially problematic release.
This version of investing-algorithm-framework might be problematic. Click here for more details.
- investing_algorithm_framework/__init__.py +147 -44
- investing_algorithm_framework/app/__init__.py +23 -6
- investing_algorithm_framework/app/algorithm/algorithm.py +5 -41
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +17 -10
- investing_algorithm_framework/app/analysis/__init__.py +15 -0
- investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
- investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
- investing_algorithm_framework/app/analysis/permutation.py +116 -0
- investing_algorithm_framework/app/analysis/ranking.py +297 -0
- investing_algorithm_framework/app/app.py +1322 -707
- investing_algorithm_framework/app/context.py +196 -88
- investing_algorithm_framework/app/eventloop.py +590 -0
- investing_algorithm_framework/app/reporting/__init__.py +16 -5
- investing_algorithm_framework/app/reporting/ascii.py +57 -202
- investing_algorithm_framework/app/reporting/backtest_report.py +284 -170
- investing_algorithm_framework/app/reporting/charts/__init__.py +10 -2
- 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 +11 -26
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +1 -1
- investing_algorithm_framework/app/reporting/generate.py +100 -114
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +40 -32
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +34 -27
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +23 -19
- investing_algorithm_framework/app/reporting/tables/trades_table.py +1 -1
- investing_algorithm_framework/app/reporting/tables/utils.py +1 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +10 -16
- investing_algorithm_framework/app/strategy.py +315 -175
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/cli/cli.py +30 -12
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +131 -34
- investing_algorithm_framework/cli/initialize_app.py +20 -1
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +18 -6
- 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_requirements.txt.template +2 -2
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +1 -1
- investing_algorithm_framework/create_app.py +3 -5
- investing_algorithm_framework/dependency_container.py +25 -39
- investing_algorithm_framework/domain/__init__.py +45 -38
- investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
- investing_algorithm_framework/domain/config.py +27 -0
- investing_algorithm_framework/domain/constants.py +6 -34
- investing_algorithm_framework/domain/data_provider.py +200 -56
- investing_algorithm_framework/domain/exceptions.py +34 -1
- investing_algorithm_framework/domain/models/__init__.py +10 -19
- investing_algorithm_framework/domain/models/base_model.py +0 -6
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +214 -0
- investing_algorithm_framework/domain/models/{market_data_type.py → data/data_type.py} +7 -7
- investing_algorithm_framework/domain/models/market/market_credential.py +6 -0
- investing_algorithm_framework/domain/models/order/order.py +34 -13
- investing_algorithm_framework/domain/models/order/order_status.py +1 -1
- investing_algorithm_framework/domain/models/order/order_type.py +1 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +14 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +5 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +51 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +9 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- 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 +0 -1
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
- investing_algorithm_framework/domain/models/time_frame.py +7 -0
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +63 -1
- investing_algorithm_framework/domain/models/trade/__init__.py +0 -2
- investing_algorithm_framework/domain/models/trade/trade.py +56 -32
- investing_algorithm_framework/domain/models/trade/trade_status.py +8 -2
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +106 -41
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +161 -99
- investing_algorithm_framework/domain/order_executor.py +19 -0
- investing_algorithm_framework/domain/portfolio_provider.py +20 -1
- investing_algorithm_framework/domain/services/__init__.py +0 -13
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +5 -1
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +17 -14
- investing_algorithm_framework/download_data.py +40 -10
- investing_algorithm_framework/infrastructure/__init__.py +13 -25
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +7 -4
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +811 -546
- investing_algorithm_framework/infrastructure/data_providers/csv.py +433 -122
- 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 +81 -0
- investing_algorithm_framework/infrastructure/models/__init__.py +0 -13
- investing_algorithm_framework/infrastructure/models/order/order.py +9 -3
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +27 -8
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +21 -7
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +2 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +16 -2
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +6 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +6 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +0 -4
- investing_algorithm_framework/services/__init__.py +105 -8
- investing_algorithm_framework/services/backtesting/backtest_service.py +536 -476
- investing_algorithm_framework/services/configuration_service.py +14 -4
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/__init__.py +48 -17
- investing_algorithm_framework/{app/reporting → services}/metrics/drawdown.py +10 -10
- investing_algorithm_framework/{app/reporting → services}/metrics/equity_curve.py +2 -2
- investing_algorithm_framework/{app/reporting → services}/metrics/exposure.py +60 -2
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/profit_factor.py +36 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/recovery.py +2 -2
- investing_algorithm_framework/{app/reporting → services}/metrics/returns.py +146 -147
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/{app/reporting/metrics/sharp_ratio.py → services/metrics/sharpe_ratio.py} +6 -10
- investing_algorithm_framework/{app/reporting → services}/metrics/sortino_ratio.py +3 -7
- investing_algorithm_framework/services/metrics/trades.py +500 -0
- investing_algorithm_framework/services/metrics/volatility.py +97 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/win_rate.py +70 -3
- investing_algorithm_framework/services/order_service/order_backtest_service.py +21 -31
- investing_algorithm_framework/services/order_service/order_service.py +9 -71
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -2
- investing_algorithm_framework/services/portfolios/portfolio_service.py +3 -13
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +62 -96
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -3
- investing_algorithm_framework/services/repository_service.py +5 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -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 +7 -1
- investing_algorithm_framework/services/trade_service/trade_service.py +51 -29
- 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.19.15.dist-info/METADATA +537 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/RECORD +159 -148
- investing_algorithm_framework/app/reporting/evaluation.py +0 -243
- investing_algorithm_framework/app/reporting/metrics/risk_free_rate.py +0 -8
- investing_algorithm_framework/app/reporting/metrics/volatility.py +0 -69
- investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -3
- investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -9
- investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -47
- investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
- investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
- investing_algorithm_framework/domain/models/backtesting/backtest_results.py +0 -440
- investing_algorithm_framework/domain/models/data_source.py +0 -21
- investing_algorithm_framework/domain/models/date_range.py +0 -64
- investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -34
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -48
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/services/market_data_sources.py +0 -543
- investing_algorithm_framework/domain/services/market_service.py +0 -153
- investing_algorithm_framework/domain/services/observable.py +0 -51
- investing_algorithm_framework/domain/services/observer.py +0 -19
- investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -16
- investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -746
- investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -270
- investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -312
- investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
- investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -471
- investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
- investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
- investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -322
- investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -10
- investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -269
- investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -350
- investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -377
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -296
- investing_algorithm_framework-6.9.1.dist-info/METADATA +0 -440
- /investing_algorithm_framework/{app/reporting → services}/metrics/alpha.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/beta.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/cagr.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/calmar_ratio.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/mean_daily_return.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/price_efficiency.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/standard_deviation.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/treynor_ratio.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/ulcer.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/value_at_risk.py +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/entry_points.txt +0 -0
|
@@ -1,29 +1,56 @@
|
|
|
1
|
-
from
|
|
1
|
+
from .app import App, Algorithm, \
|
|
2
2
|
TradingStrategy, StatelessAction, Task, AppHook, Context, \
|
|
3
|
-
add_html_report,
|
|
4
|
-
|
|
5
|
-
pretty_print_orders, pretty_print_backtest
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
add_html_report, BacktestReport, save_backtests_to_directory, \
|
|
4
|
+
pretty_print_trades, pretty_print_positions, \
|
|
5
|
+
pretty_print_orders, pretty_print_backtest, select_backtest_date_ranges, \
|
|
6
|
+
get_equity_curve_with_drawdown_chart, load_backtests_from_directory, \
|
|
7
|
+
get_rolling_sharpe_ratio_chart, rank_results, \
|
|
8
|
+
get_monthly_returns_heatmap_chart, create_weights, \
|
|
9
|
+
get_yearly_returns_bar_chart, get_entry_and_exit_signals, \
|
|
10
|
+
get_ohlcv_data_completeness_chart, get_equity_curve_chart
|
|
11
|
+
from .domain import ApiException, combine_backtests, PositionSize, \
|
|
12
|
+
OrderType, OperationalException, OrderStatus, OrderSide, \
|
|
13
|
+
TimeUnit, TimeInterval, Order, Portfolio, Backtest, DataError, \
|
|
14
|
+
Position, TimeFrame, INDEX_DATETIME, MarketCredential, TakeProfitRule, \
|
|
15
|
+
PortfolioConfiguration, RESOURCE_DIRECTORY, AWS_LAMBDA_LOGGING_CONFIG, \
|
|
16
|
+
Trade, APP_MODE, AppMode, DATETIME_FORMAT, \
|
|
17
|
+
BacktestDateRange, convert_polars_to_pandas, BacktestRun, \
|
|
18
|
+
DEFAULT_LOGGING_CONFIG, DataType, DataProvider, StopLossRule, \
|
|
19
|
+
TradeStatus, generate_backtest_summary_metrics, \
|
|
17
20
|
APPLICATION_DIRECTORY, DataSource, OrderExecutor, PortfolioProvider, \
|
|
18
|
-
SnapshotInterval, AWS_S3_STATE_BUCKET_NAME
|
|
19
|
-
from
|
|
20
|
-
|
|
21
|
-
CCXTTickerMarketDataSource, CSVOHLCVMarketDataSource, \
|
|
22
|
-
CSVTickerMarketDataSource, AzureBlobStorageStateHandler, \
|
|
23
|
-
PandasOHLCVBacktestMarketDataSource, PandasOHLCVMarketDataSource, \
|
|
21
|
+
SnapshotInterval, AWS_S3_STATE_BUCKET_NAME, BacktestEvaluationFocus
|
|
22
|
+
from .infrastructure import AzureBlobStorageStateHandler, \
|
|
23
|
+
CSVOHLCVDataProvider, CCXTOHLCVDataProvider, PandasOHLCVDataProvider, \
|
|
24
24
|
AWSS3StorageStateHandler
|
|
25
25
|
from .create_app import create_app
|
|
26
26
|
from .download_data import download
|
|
27
|
+
from .services import get_annual_volatility, get_sortino_ratio, \
|
|
28
|
+
get_drawdown_series, get_max_drawdown, get_equity_curve, \
|
|
29
|
+
get_price_efficiency_ratio, get_sharpe_ratio, \
|
|
30
|
+
get_profit_factor, get_cumulative_profit_factor_series, \
|
|
31
|
+
get_rolling_profit_factor_series, get_cagr, \
|
|
32
|
+
get_standard_deviation_returns, get_standard_deviation_downside_returns, \
|
|
33
|
+
get_max_drawdown_absolute, get_total_return, get_exposure_ratio, \
|
|
34
|
+
get_average_trade_duration, get_win_rate, get_win_loss_ratio, \
|
|
35
|
+
get_calmar_ratio, get_trade_frequency, get_yearly_returns, \
|
|
36
|
+
get_monthly_returns, get_best_year, get_best_month, get_worst_year, \
|
|
37
|
+
get_worst_month, get_best_trade, get_worst_trade, \
|
|
38
|
+
get_average_yearly_return, get_average_trade_gain, \
|
|
39
|
+
get_average_trade_loss, get_average_monthly_return, \
|
|
40
|
+
get_percentage_winning_months, get_max_drawdown_duration, \
|
|
41
|
+
get_max_daily_drawdown, get_trades_per_day, \
|
|
42
|
+
get_trades_per_year, get_average_monthly_return_losing_months, \
|
|
43
|
+
get_average_monthly_return_winning_months, get_percentage_winning_years, \
|
|
44
|
+
get_rolling_sharpe_ratio, create_backtest_metrics, get_total_growth, \
|
|
45
|
+
get_total_loss, get_cumulative_exposure, get_median_trade_return, \
|
|
46
|
+
get_average_trade_return, get_risk_free_rate_us, get_cumulative_return, \
|
|
47
|
+
get_cumulative_return_series, get_current_average_trade_return, \
|
|
48
|
+
get_current_average_trade_gain, get_current_average_trade_duration, \
|
|
49
|
+
get_current_average_trade_loss, get_negative_trades, \
|
|
50
|
+
get_positive_trades, get_number_of_trades, get_current_win_rate, \
|
|
51
|
+
get_current_win_loss_ratio, create_backtest_metrics_for_backtest, \
|
|
52
|
+
TradeTakeProfitService, TradeStopLossService
|
|
53
|
+
|
|
27
54
|
|
|
28
55
|
__all__ = [
|
|
29
56
|
"Algorithm",
|
|
@@ -32,8 +59,6 @@ __all__ = [
|
|
|
32
59
|
"AppHook",
|
|
33
60
|
"create_app",
|
|
34
61
|
"ApiException",
|
|
35
|
-
"TradingDataType",
|
|
36
|
-
"TradingTimeFrame",
|
|
37
62
|
"OrderType",
|
|
38
63
|
"OrderStatus",
|
|
39
64
|
"OrderSide",
|
|
@@ -47,36 +72,21 @@ __all__ = [
|
|
|
47
72
|
"StatelessAction",
|
|
48
73
|
"Task",
|
|
49
74
|
"pretty_print_backtest",
|
|
50
|
-
"
|
|
75
|
+
"INDEX_DATETIME",
|
|
51
76
|
"Trade",
|
|
52
77
|
"TimeFrame",
|
|
53
|
-
"CCXTOrderBookMarketDataSource",
|
|
54
|
-
"CCXTTickerMarketDataSource",
|
|
55
|
-
"CCXTOHLCVMarketDataSource",
|
|
56
|
-
"OHLCVMarketDataSource",
|
|
57
|
-
"OrderBookMarketDataSource",
|
|
58
|
-
"TickerMarketDataSource",
|
|
59
|
-
"CSVOHLCVMarketDataSource",
|
|
60
|
-
"CSVTickerMarketDataSource",
|
|
61
78
|
"MarketCredential",
|
|
62
|
-
"MarketService",
|
|
63
79
|
"OperationalException",
|
|
64
|
-
"BacktestReportsEvaluation",
|
|
65
|
-
"SYMBOLS",
|
|
66
|
-
"RESERVED_BALANCES",
|
|
67
80
|
"APP_MODE",
|
|
68
81
|
"AppMode",
|
|
69
82
|
"DATETIME_FORMAT",
|
|
70
|
-
"
|
|
83
|
+
"Backtest",
|
|
71
84
|
"BacktestDateRange",
|
|
72
85
|
"convert_polars_to_pandas",
|
|
73
|
-
"DateRange",
|
|
74
86
|
"AzureBlobStorageStateHandler",
|
|
75
87
|
"DEFAULT_LOGGING_CONFIG",
|
|
76
88
|
"BacktestReport",
|
|
77
89
|
"TradeStatus",
|
|
78
|
-
"MarketDataType",
|
|
79
|
-
"TradeRiskType",
|
|
80
90
|
"Context",
|
|
81
91
|
"APPLICATION_DIRECTORY",
|
|
82
92
|
"download",
|
|
@@ -86,11 +96,104 @@ __all__ = [
|
|
|
86
96
|
"DataSource",
|
|
87
97
|
"OrderExecutor",
|
|
88
98
|
"PortfolioProvider",
|
|
89
|
-
"PandasOHLCVBacktestMarketDataSource",
|
|
90
|
-
"PandasOHLCVMarketDataSource",
|
|
91
99
|
"SnapshotInterval",
|
|
92
|
-
"add_metrics",
|
|
93
100
|
"add_html_report",
|
|
94
101
|
"AWSS3StorageStateHandler",
|
|
95
|
-
"AWS_S3_STATE_BUCKET_NAME"
|
|
102
|
+
"AWS_S3_STATE_BUCKET_NAME",
|
|
103
|
+
"AWS_LAMBDA_LOGGING_CONFIG",
|
|
104
|
+
'select_backtest_date_ranges',
|
|
105
|
+
'DataType',
|
|
106
|
+
'CSVOHLCVDataProvider',
|
|
107
|
+
"CCXTOHLCVDataProvider",
|
|
108
|
+
"DataProvider",
|
|
109
|
+
"get_annual_volatility",
|
|
110
|
+
"get_sortino_ratio",
|
|
111
|
+
"get_drawdown_series",
|
|
112
|
+
"get_max_drawdown",
|
|
113
|
+
"get_equity_curve",
|
|
114
|
+
"get_price_efficiency_ratio",
|
|
115
|
+
"get_sharpe_ratio",
|
|
116
|
+
"get_profit_factor",
|
|
117
|
+
"get_cumulative_profit_factor_series",
|
|
118
|
+
"get_rolling_profit_factor_series",
|
|
119
|
+
"get_sharpe_ratio",
|
|
120
|
+
"get_cagr",
|
|
121
|
+
"get_standard_deviation_returns",
|
|
122
|
+
"get_standard_deviation_downside_returns",
|
|
123
|
+
"get_max_drawdown_absolute",
|
|
124
|
+
"get_total_return",
|
|
125
|
+
"get_exposure_ratio",
|
|
126
|
+
"get_cumulative_exposure",
|
|
127
|
+
"get_average_trade_duration",
|
|
128
|
+
"get_win_rate",
|
|
129
|
+
"get_win_loss_ratio",
|
|
130
|
+
"get_calmar_ratio",
|
|
131
|
+
"get_trade_frequency",
|
|
132
|
+
"get_yearly_returns",
|
|
133
|
+
"get_monthly_returns",
|
|
134
|
+
"get_best_year",
|
|
135
|
+
"get_best_month",
|
|
136
|
+
"get_worst_year",
|
|
137
|
+
"get_worst_month",
|
|
138
|
+
"get_best_trade",
|
|
139
|
+
"get_worst_trade",
|
|
140
|
+
"get_average_yearly_return",
|
|
141
|
+
"get_average_trade_gain",
|
|
142
|
+
"get_average_trade_loss",
|
|
143
|
+
"get_average_monthly_return",
|
|
144
|
+
"get_percentage_winning_months",
|
|
145
|
+
"get_average_trade_duration",
|
|
146
|
+
"get_trade_frequency",
|
|
147
|
+
"get_win_rate",
|
|
148
|
+
"get_win_loss_ratio",
|
|
149
|
+
"get_calmar_ratio",
|
|
150
|
+
"get_max_drawdown_absolute",
|
|
151
|
+
"get_max_drawdown_duration",
|
|
152
|
+
"get_max_daily_drawdown",
|
|
153
|
+
"get_trades_per_day",
|
|
154
|
+
"get_trades_per_year",
|
|
155
|
+
"get_average_monthly_return_losing_months",
|
|
156
|
+
"get_average_monthly_return_winning_months",
|
|
157
|
+
"get_percentage_winning_years",
|
|
158
|
+
"get_rolling_sharpe_ratio",
|
|
159
|
+
"create_backtest_metrics",
|
|
160
|
+
"PandasOHLCVDataProvider",
|
|
161
|
+
"get_equity_curve_with_drawdown_chart",
|
|
162
|
+
"get_rolling_sharpe_ratio_chart",
|
|
163
|
+
"get_monthly_returns_heatmap_chart",
|
|
164
|
+
"get_yearly_returns_bar_chart",
|
|
165
|
+
"get_ohlcv_data_completeness_chart",
|
|
166
|
+
"rank_results",
|
|
167
|
+
"create_weights",
|
|
168
|
+
"get_entry_and_exit_signals",
|
|
169
|
+
"BacktestEvaluationFocus",
|
|
170
|
+
"combine_backtests",
|
|
171
|
+
"PositionSize",
|
|
172
|
+
"get_median_trade_return",
|
|
173
|
+
"get_average_trade_return",
|
|
174
|
+
"get_risk_free_rate_us",
|
|
175
|
+
"get_cumulative_return",
|
|
176
|
+
"get_cumulative_return_series",
|
|
177
|
+
"get_total_loss",
|
|
178
|
+
"get_total_growth",
|
|
179
|
+
"generate_backtest_summary_metrics",
|
|
180
|
+
"get_equity_curve_chart",
|
|
181
|
+
"get_current_win_rate",
|
|
182
|
+
"get_current_win_loss_ratio",
|
|
183
|
+
"get_current_average_trade_loss",
|
|
184
|
+
"get_current_average_trade_duration",
|
|
185
|
+
"get_current_average_trade_gain",
|
|
186
|
+
"get_current_average_trade_return",
|
|
187
|
+
"get_negative_trades",
|
|
188
|
+
"get_positive_trades",
|
|
189
|
+
"get_number_of_trades",
|
|
190
|
+
"BacktestRun",
|
|
191
|
+
"load_backtests_from_directory",
|
|
192
|
+
"save_backtests_to_directory",
|
|
193
|
+
"DataError",
|
|
194
|
+
"create_backtest_metrics_for_backtest",
|
|
195
|
+
"TakeProfitRule",
|
|
196
|
+
"StopLossRule",
|
|
197
|
+
"TradeStopLossService",
|
|
198
|
+
"TradeTakeProfitService"
|
|
96
199
|
]
|
|
@@ -5,9 +5,16 @@ from investing_algorithm_framework.app.task import Task
|
|
|
5
5
|
from investing_algorithm_framework.app.web import create_flask_app
|
|
6
6
|
from .algorithm import Algorithm
|
|
7
7
|
from .context import Context
|
|
8
|
-
from .reporting import add_html_report,
|
|
9
|
-
BacktestReport, pretty_print_backtest,
|
|
10
|
-
|
|
8
|
+
from .reporting import add_html_report, \
|
|
9
|
+
BacktestReport, pretty_print_backtest, pretty_print_trades, \
|
|
10
|
+
pretty_print_positions, pretty_print_orders, \
|
|
11
|
+
get_equity_curve_with_drawdown_chart, \
|
|
12
|
+
get_rolling_sharpe_ratio_chart, \
|
|
13
|
+
get_monthly_returns_heatmap_chart, \
|
|
14
|
+
get_yearly_returns_bar_chart, get_equity_curve_chart, \
|
|
15
|
+
get_ohlcv_data_completeness_chart, get_entry_and_exit_signals
|
|
16
|
+
from .analysis import select_backtest_date_ranges, rank_results, \
|
|
17
|
+
create_weights, load_backtests_from_directory, save_backtests_to_directory
|
|
11
18
|
|
|
12
19
|
|
|
13
20
|
__all__ = [
|
|
@@ -20,11 +27,21 @@ __all__ = [
|
|
|
20
27
|
"AppHook",
|
|
21
28
|
"Context",
|
|
22
29
|
"add_html_report",
|
|
23
|
-
"add_metrics",
|
|
24
30
|
"BacktestReport",
|
|
25
31
|
"pretty_print_backtest",
|
|
26
|
-
"BacktestReportsEvaluation",
|
|
27
32
|
"pretty_print_trades",
|
|
28
33
|
"pretty_print_positions",
|
|
29
|
-
"pretty_print_orders"
|
|
34
|
+
"pretty_print_orders",
|
|
35
|
+
"select_backtest_date_ranges",
|
|
36
|
+
"get_equity_curve_with_drawdown_chart",
|
|
37
|
+
"get_rolling_sharpe_ratio_chart",
|
|
38
|
+
"get_monthly_returns_heatmap_chart",
|
|
39
|
+
"get_yearly_returns_bar_chart",
|
|
40
|
+
"get_ohlcv_data_completeness_chart",
|
|
41
|
+
"rank_results",
|
|
42
|
+
"create_weights",
|
|
43
|
+
"get_entry_and_exit_signals",
|
|
44
|
+
"get_equity_curve_chart",
|
|
45
|
+
"load_backtests_from_directory",
|
|
46
|
+
"save_backtests_to_directory"
|
|
30
47
|
]
|
|
@@ -6,7 +6,7 @@ from typing import List
|
|
|
6
6
|
from investing_algorithm_framework.app.app_hook import AppHook
|
|
7
7
|
from investing_algorithm_framework.app.strategy import TradingStrategy
|
|
8
8
|
from investing_algorithm_framework.domain import OperationalException, \
|
|
9
|
-
|
|
9
|
+
DataSource
|
|
10
10
|
|
|
11
11
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
12
12
|
|
|
@@ -32,8 +32,9 @@ class Algorithm:
|
|
|
32
32
|
strategy=None,
|
|
33
33
|
strategies=None,
|
|
34
34
|
tasks: List = None,
|
|
35
|
-
data_sources: List[
|
|
36
|
-
on_strategy_run_hooks=None
|
|
35
|
+
data_sources: List[DataSource] = None,
|
|
36
|
+
on_strategy_run_hooks=None,
|
|
37
|
+
metadata=None
|
|
37
38
|
):
|
|
38
39
|
self._name = name
|
|
39
40
|
self._context = {}
|
|
@@ -46,6 +47,7 @@ class Algorithm:
|
|
|
46
47
|
self._tasks = []
|
|
47
48
|
self._data_sources = []
|
|
48
49
|
self._on_strategy_run_hooks = []
|
|
50
|
+
self.metadata = metadata
|
|
49
51
|
|
|
50
52
|
if data_sources is not None:
|
|
51
53
|
self._data_sources = data_sources
|
|
@@ -210,9 +212,6 @@ class Algorithm:
|
|
|
210
212
|
"with the same id in the algorithm"
|
|
211
213
|
)
|
|
212
214
|
|
|
213
|
-
if strategy.market_data_sources is not None:
|
|
214
|
-
self.add_data_sources(strategy.market_data_sources)
|
|
215
|
-
|
|
216
215
|
self._strategies.append(strategy)
|
|
217
216
|
|
|
218
217
|
def add_task(self, task):
|
|
@@ -221,41 +220,6 @@ class Algorithm:
|
|
|
221
220
|
|
|
222
221
|
self._tasks.append(task)
|
|
223
222
|
|
|
224
|
-
def add_data_source(self, data_source) -> None:
|
|
225
|
-
"""
|
|
226
|
-
Function to add a data source to the app. The data source should
|
|
227
|
-
be an instance of DataSource.
|
|
228
|
-
|
|
229
|
-
Args:
|
|
230
|
-
data_source: Instance of DataSource
|
|
231
|
-
|
|
232
|
-
Returns:
|
|
233
|
-
None
|
|
234
|
-
"""
|
|
235
|
-
if inspect.isclass(data_source):
|
|
236
|
-
if not issubclass(data_source, MarketDataSource):
|
|
237
|
-
raise OperationalException(
|
|
238
|
-
"Data source should be an instance of MarketDataSource"
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
data_source = data_source()
|
|
242
|
-
|
|
243
|
-
self.data_sources.append(data_source)
|
|
244
|
-
|
|
245
|
-
def add_data_sources(self, data_sources) -> None:
|
|
246
|
-
"""
|
|
247
|
-
Function to add a list of data sources to the app. The data sources
|
|
248
|
-
should be instances of DataSource.
|
|
249
|
-
|
|
250
|
-
Args:
|
|
251
|
-
data_sources: List of DataSource
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
None
|
|
255
|
-
"""
|
|
256
|
-
for data_source in data_sources:
|
|
257
|
-
self.add_data_source(data_source)
|
|
258
|
-
|
|
259
223
|
def add_on_strategy_run_hook(self, app_hook):
|
|
260
224
|
"""
|
|
261
225
|
Function to add a hook that will be called when a strategy is run.
|
|
@@ -56,7 +56,6 @@ class AlgorithmFactory:
|
|
|
56
56
|
strategies=None,
|
|
57
57
|
tasks=None,
|
|
58
58
|
on_strategy_run_hooks=None,
|
|
59
|
-
data_sources=None
|
|
60
59
|
) -> Algorithm:
|
|
61
60
|
"""
|
|
62
61
|
Create an instance of the specified algorithm type.
|
|
@@ -69,7 +68,6 @@ class AlgorithmFactory:
|
|
|
69
68
|
tasks (list): List of Task instances.
|
|
70
69
|
on_strategy_run_hooks (list): List of hooks to be called
|
|
71
70
|
when a strategy is run.
|
|
72
|
-
data_sources (list): List of MarketDataSource instances.
|
|
73
71
|
|
|
74
72
|
Returns:
|
|
75
73
|
Algorithm: Instance of Algorithm.
|
|
@@ -78,21 +76,30 @@ class AlgorithmFactory:
|
|
|
78
76
|
strategies = strategies or []
|
|
79
77
|
tasks = tasks or []
|
|
80
78
|
on_strategy_run_hooks = on_strategy_run_hooks or []
|
|
81
|
-
data_sources =
|
|
79
|
+
data_sources = []
|
|
82
80
|
|
|
83
|
-
if algorithm is not None:
|
|
81
|
+
if algorithm is not None and isinstance(algorithm, Algorithm):
|
|
82
|
+
if name is None:
|
|
83
|
+
name = algorithm.name
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
strategies.extend(algorithm.strategies)
|
|
86
|
+
tasks.extend(algorithm.tasks)
|
|
87
|
+
on_strategy_run_hooks.extend(algorithm.on_strategy_run_hooks)
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
algorithm.
|
|
89
|
+
if hasattr(algorithm, 'data_sources'):
|
|
90
|
+
data_sources.extend(algorithm.data_sources)
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
if strategy is not None:
|
|
93
|
+
strategies.append(strategy)
|
|
94
|
+
data_sources.extend(strategy.data_sources)
|
|
95
|
+
|
|
96
|
+
for strategy_entry in strategies:
|
|
97
|
+
if strategy_entry.data_sources is not None \
|
|
98
|
+
and len(strategy_entry.data_sources):
|
|
99
|
+
data_sources.extend(strategy_entry.data_sources)
|
|
92
100
|
|
|
93
101
|
algorithm = Algorithm(
|
|
94
102
|
name=name,
|
|
95
|
-
strategy=strategy,
|
|
96
103
|
strategies=strategies,
|
|
97
104
|
tasks=tasks,
|
|
98
105
|
on_strategy_run_hooks=on_strategy_run_hooks,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .backtest_data_ranges import select_backtest_date_ranges
|
|
2
|
+
from .ranking import rank_results, create_weights, combine_backtest_metrics
|
|
3
|
+
from .permutation import create_ohlcv_permutation
|
|
4
|
+
from .backtest_utils import load_backtests_from_directory, \
|
|
5
|
+
save_backtests_to_directory
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"select_backtest_date_ranges",
|
|
9
|
+
"rank_results",
|
|
10
|
+
"create_weights",
|
|
11
|
+
"create_ohlcv_permutation",
|
|
12
|
+
"combine_backtest_metrics",
|
|
13
|
+
"load_backtests_from_directory",
|
|
14
|
+
"save_backtests_to_directory"
|
|
15
|
+
]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from typing import List, Union
|
|
3
|
+
|
|
4
|
+
from datetime import timezone
|
|
5
|
+
from investing_algorithm_framework.domain import BacktestDateRange, \
|
|
6
|
+
OperationalException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def select_backtest_date_ranges(
|
|
10
|
+
df: pd.DataFrame, window: Union[str, int] = '365D'
|
|
11
|
+
) -> List[BacktestDateRange]:
|
|
12
|
+
"""
|
|
13
|
+
Identifies the best upturn, worst downturn, and sideways periods
|
|
14
|
+
for the given window duration. This allows you to quickly select
|
|
15
|
+
interesting periods for backtesting.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
df (pd.DataFrame): DataFrame with a DateTime index
|
|
19
|
+
and 'Close' column.
|
|
20
|
+
window (Union[str, int]): Duration of the window
|
|
21
|
+
to analyze. Can be a string like '365D' or an
|
|
22
|
+
integer representing days.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
List[BacktestDateRange]: List of BacktestDateRange
|
|
26
|
+
objects representing the best upturn, worst
|
|
27
|
+
downturn, and most sideways periods.
|
|
28
|
+
"""
|
|
29
|
+
df = df.copy()
|
|
30
|
+
df = df.sort_index()
|
|
31
|
+
|
|
32
|
+
if isinstance(window, int):
|
|
33
|
+
window = pd.Timedelta(days=window)
|
|
34
|
+
elif isinstance(window, str):
|
|
35
|
+
window = pd.to_timedelta(window)
|
|
36
|
+
else:
|
|
37
|
+
raise OperationalException("window must be a string or integer")
|
|
38
|
+
|
|
39
|
+
# Check if the window is larger than the DataFrame
|
|
40
|
+
if len(df) == 0:
|
|
41
|
+
raise OperationalException("DataFrame is empty")
|
|
42
|
+
|
|
43
|
+
if df.index[-1] - df.index[0] < window:
|
|
44
|
+
raise OperationalException(
|
|
45
|
+
"Window duration is larger than the data duration"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if len(df) < 2 or df.index[-1] - df.index[0] < window:
|
|
49
|
+
raise OperationalException(
|
|
50
|
+
"DataFrame must contain at least two rows and span "
|
|
51
|
+
"the full window duration"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
best_upturn = {
|
|
55
|
+
"name": "UpTurn", "return": float('-inf'), "start": None, "end": None
|
|
56
|
+
}
|
|
57
|
+
worst_downturn = {
|
|
58
|
+
"name": "DownTurn", "return": float('inf'), "start": None, "end": None
|
|
59
|
+
}
|
|
60
|
+
most_sideways = {
|
|
61
|
+
"name": "SideWays",
|
|
62
|
+
"volatility": float('inf'),
|
|
63
|
+
"return": None,
|
|
64
|
+
"start": None,
|
|
65
|
+
"end": None
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for i in range(len(df)):
|
|
69
|
+
start_time = df.index[i]
|
|
70
|
+
end_time = start_time + window
|
|
71
|
+
window_df = df[(df.index >= start_time) & (df.index <= end_time)]
|
|
72
|
+
|
|
73
|
+
if len(window_df) < 2 or (window_df.index[-1] - start_time) < window:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
start_price = window_df['Close'].iloc[0]
|
|
77
|
+
end_price = window_df['Close'].iloc[-1]
|
|
78
|
+
ret = (end_price / start_price) - 1 # relative return
|
|
79
|
+
volatility = window_df['Close'].std()
|
|
80
|
+
|
|
81
|
+
# Ensure datetime for BacktestDateRange and with timezone utc
|
|
82
|
+
start_time = pd.Timestamp(start_time).to_pydatetime()
|
|
83
|
+
start_time = start_time.replace(tzinfo=timezone.utc)
|
|
84
|
+
end_time = pd.Timestamp(window_df.index[-1]).to_pydatetime()
|
|
85
|
+
end_time = end_time.replace(tzinfo=timezone.utc)
|
|
86
|
+
|
|
87
|
+
if ret > best_upturn["return"]:
|
|
88
|
+
best_upturn.update(
|
|
89
|
+
{"return": ret, "start": start_time, "end": end_time}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if ret < worst_downturn["return"]:
|
|
93
|
+
worst_downturn.update(
|
|
94
|
+
{"return": ret, "start": start_time, "end": end_time}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if volatility < most_sideways["volatility"]:
|
|
98
|
+
most_sideways.update({
|
|
99
|
+
"return": ret,
|
|
100
|
+
"volatility": volatility,
|
|
101
|
+
"start": start_time,
|
|
102
|
+
"end": end_time
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
return [
|
|
106
|
+
BacktestDateRange(
|
|
107
|
+
start_date=best_upturn['start'],
|
|
108
|
+
end_date=best_upturn['end'],
|
|
109
|
+
name=best_upturn['name']
|
|
110
|
+
),
|
|
111
|
+
BacktestDateRange(
|
|
112
|
+
start_date=worst_downturn['start'],
|
|
113
|
+
end_date=worst_downturn['end'],
|
|
114
|
+
name=worst_downturn['name']
|
|
115
|
+
),
|
|
116
|
+
BacktestDateRange(
|
|
117
|
+
start_date=most_sideways['start'],
|
|
118
|
+
end_date=most_sideways['end'],
|
|
119
|
+
name=most_sideways['name']
|
|
120
|
+
)
|
|
121
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import List, Union, Callable
|
|
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
|
+
dir_name_generation_function: Callable[[Backtest], str] = None,
|
|
17
|
+
filter_function: Callable[[Backtest], bool] = None
|
|
18
|
+
) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Saves a list of Backtest objects to the specified directory.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
backtests (List[Backtest]): List of Backtest objects to save.
|
|
24
|
+
directory_path (str): Path to the directory where backtests
|
|
25
|
+
will be saved.
|
|
26
|
+
dir_name_generation_function (Callable[[Backtest], str], optional):
|
|
27
|
+
A function that takes a Backtest object as input and returns
|
|
28
|
+
a string to be used as the directory name for that backtest.
|
|
29
|
+
If not provided, the backtest's metadata 'id' will be used.
|
|
30
|
+
Defaults to None.
|
|
31
|
+
filter_function (Callable[[Backtest], bool], optional): A function
|
|
32
|
+
that takes a Backtest object as input and returns True if the
|
|
33
|
+
backtest should be saved. Defaults to None.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
None
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
if not os.path.exists(directory_path):
|
|
40
|
+
os.makedirs(directory_path)
|
|
41
|
+
|
|
42
|
+
for backtest in backtests:
|
|
43
|
+
|
|
44
|
+
if filter_function is not None:
|
|
45
|
+
if not filter_function(backtest):
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
if dir_name_generation_function is not None:
|
|
49
|
+
dir_name = dir_name_generation_function(backtest)
|
|
50
|
+
else:
|
|
51
|
+
# Check if there is an ID in the backtest metadata
|
|
52
|
+
dir_name = backtest.metadata.get('id', None)
|
|
53
|
+
|
|
54
|
+
if dir_name is None:
|
|
55
|
+
logger.warning(
|
|
56
|
+
"Backtest metadata does not contain an 'id' field. "
|
|
57
|
+
"Generating a random directory name."
|
|
58
|
+
)
|
|
59
|
+
dir_name = str(Random().randint(100000, 999999))
|
|
60
|
+
|
|
61
|
+
backtest.save(os.path.join(directory_path, dir_name))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def load_backtests_from_directory(
|
|
65
|
+
directory_path: Union[str, Path],
|
|
66
|
+
filter_function: Callable[[Backtest], bool] = None
|
|
67
|
+
) -> List[Backtest]:
|
|
68
|
+
"""
|
|
69
|
+
Loads Backtest objects from the specified directory.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
directory_path (str): Path to the directory from which backtests
|
|
73
|
+
will be loaded.
|
|
74
|
+
filter_function (Callable[[Backtest], bool], optional): A function
|
|
75
|
+
that takes a Backtest object as input and returns True if the
|
|
76
|
+
backtest should be included in the result. Defaults to None.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
List[Backtest]: List of loaded Backtest objects.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
backtests = []
|
|
83
|
+
|
|
84
|
+
if not os.path.exists(directory_path):
|
|
85
|
+
logger.warning(
|
|
86
|
+
f"Directory {directory_path} does not exist. "
|
|
87
|
+
"No backtests loaded."
|
|
88
|
+
)
|
|
89
|
+
return backtests
|
|
90
|
+
|
|
91
|
+
for file_name in os.listdir(directory_path):
|
|
92
|
+
file_path = os.path.join(directory_path, file_name)
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
backtest = Backtest.open(file_path)
|
|
96
|
+
|
|
97
|
+
if filter_function is not None:
|
|
98
|
+
if not filter_function(backtest):
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
backtests.append(backtest)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(
|
|
104
|
+
f"Failed to load backtest from {file_path}: {e}"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return backtests
|