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.

Files changed (192) hide show
  1. investing_algorithm_framework/__init__.py +147 -44
  2. investing_algorithm_framework/app/__init__.py +23 -6
  3. investing_algorithm_framework/app/algorithm/algorithm.py +5 -41
  4. investing_algorithm_framework/app/algorithm/algorithm_factory.py +17 -10
  5. investing_algorithm_framework/app/analysis/__init__.py +15 -0
  6. investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
  7. investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
  8. investing_algorithm_framework/app/analysis/permutation.py +116 -0
  9. investing_algorithm_framework/app/analysis/ranking.py +297 -0
  10. investing_algorithm_framework/app/app.py +1322 -707
  11. investing_algorithm_framework/app/context.py +196 -88
  12. investing_algorithm_framework/app/eventloop.py +590 -0
  13. investing_algorithm_framework/app/reporting/__init__.py +16 -5
  14. investing_algorithm_framework/app/reporting/ascii.py +57 -202
  15. investing_algorithm_framework/app/reporting/backtest_report.py +284 -170
  16. investing_algorithm_framework/app/reporting/charts/__init__.py +10 -2
  17. investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
  18. investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
  19. investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +11 -26
  20. investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
  21. investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
  22. investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +1 -1
  23. investing_algorithm_framework/app/reporting/generate.py +100 -114
  24. investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +40 -32
  25. investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +34 -27
  26. investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +23 -19
  27. investing_algorithm_framework/app/reporting/tables/trades_table.py +1 -1
  28. investing_algorithm_framework/app/reporting/tables/utils.py +1 -0
  29. investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +10 -16
  30. investing_algorithm_framework/app/strategy.py +315 -175
  31. investing_algorithm_framework/app/task.py +5 -3
  32. investing_algorithm_framework/cli/cli.py +30 -12
  33. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +131 -34
  34. investing_algorithm_framework/cli/initialize_app.py +20 -1
  35. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +18 -6
  36. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  37. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  38. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -2
  39. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +1 -1
  40. investing_algorithm_framework/create_app.py +3 -5
  41. investing_algorithm_framework/dependency_container.py +25 -39
  42. investing_algorithm_framework/domain/__init__.py +45 -38
  43. investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
  44. investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
  45. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
  46. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
  47. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
  48. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  49. investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
  50. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  51. investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
  52. investing_algorithm_framework/domain/config.py +27 -0
  53. investing_algorithm_framework/domain/constants.py +6 -34
  54. investing_algorithm_framework/domain/data_provider.py +200 -56
  55. investing_algorithm_framework/domain/exceptions.py +34 -1
  56. investing_algorithm_framework/domain/models/__init__.py +10 -19
  57. investing_algorithm_framework/domain/models/base_model.py +0 -6
  58. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  59. investing_algorithm_framework/domain/models/data/data_source.py +214 -0
  60. investing_algorithm_framework/domain/models/{market_data_type.py → data/data_type.py} +7 -7
  61. investing_algorithm_framework/domain/models/market/market_credential.py +6 -0
  62. investing_algorithm_framework/domain/models/order/order.py +34 -13
  63. investing_algorithm_framework/domain/models/order/order_status.py +1 -1
  64. investing_algorithm_framework/domain/models/order/order_type.py +1 -1
  65. investing_algorithm_framework/domain/models/portfolio/portfolio.py +14 -1
  66. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +5 -1
  67. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +51 -11
  68. investing_algorithm_framework/domain/models/position/__init__.py +2 -1
  69. investing_algorithm_framework/domain/models/position/position.py +9 -0
  70. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  71. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  72. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  73. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  74. investing_algorithm_framework/domain/models/snapshot_interval.py +0 -1
  75. investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
  76. investing_algorithm_framework/domain/models/time_frame.py +7 -0
  77. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  78. investing_algorithm_framework/domain/models/time_unit.py +63 -1
  79. investing_algorithm_framework/domain/models/trade/__init__.py +0 -2
  80. investing_algorithm_framework/domain/models/trade/trade.py +56 -32
  81. investing_algorithm_framework/domain/models/trade/trade_status.py +8 -2
  82. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +106 -41
  83. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +161 -99
  84. investing_algorithm_framework/domain/order_executor.py +19 -0
  85. investing_algorithm_framework/domain/portfolio_provider.py +20 -1
  86. investing_algorithm_framework/domain/services/__init__.py +0 -13
  87. investing_algorithm_framework/domain/strategy.py +1 -29
  88. investing_algorithm_framework/domain/utils/__init__.py +5 -1
  89. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  90. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  91. investing_algorithm_framework/domain/utils/polars.py +17 -14
  92. investing_algorithm_framework/download_data.py +40 -10
  93. investing_algorithm_framework/infrastructure/__init__.py +13 -25
  94. investing_algorithm_framework/infrastructure/data_providers/__init__.py +7 -4
  95. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +811 -546
  96. investing_algorithm_framework/infrastructure/data_providers/csv.py +433 -122
  97. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  98. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  99. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +81 -0
  100. investing_algorithm_framework/infrastructure/models/__init__.py +0 -13
  101. investing_algorithm_framework/infrastructure/models/order/order.py +9 -3
  102. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +27 -8
  103. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +21 -7
  104. investing_algorithm_framework/infrastructure/order_executors/__init__.py +2 -0
  105. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  106. investing_algorithm_framework/infrastructure/repositories/repository.py +16 -2
  107. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +2 -2
  108. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +6 -0
  109. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +6 -0
  110. investing_algorithm_framework/infrastructure/services/__init__.py +0 -4
  111. investing_algorithm_framework/services/__init__.py +105 -8
  112. investing_algorithm_framework/services/backtesting/backtest_service.py +536 -476
  113. investing_algorithm_framework/services/configuration_service.py +14 -4
  114. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  115. investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
  116. investing_algorithm_framework/{app/reporting → services}/metrics/__init__.py +48 -17
  117. investing_algorithm_framework/{app/reporting → services}/metrics/drawdown.py +10 -10
  118. investing_algorithm_framework/{app/reporting → services}/metrics/equity_curve.py +2 -2
  119. investing_algorithm_framework/{app/reporting → services}/metrics/exposure.py +60 -2
  120. investing_algorithm_framework/services/metrics/generate.py +358 -0
  121. investing_algorithm_framework/{app/reporting → services}/metrics/profit_factor.py +36 -0
  122. investing_algorithm_framework/{app/reporting → services}/metrics/recovery.py +2 -2
  123. investing_algorithm_framework/{app/reporting → services}/metrics/returns.py +146 -147
  124. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  125. investing_algorithm_framework/{app/reporting/metrics/sharp_ratio.py → services/metrics/sharpe_ratio.py} +6 -10
  126. investing_algorithm_framework/{app/reporting → services}/metrics/sortino_ratio.py +3 -7
  127. investing_algorithm_framework/services/metrics/trades.py +500 -0
  128. investing_algorithm_framework/services/metrics/volatility.py +97 -0
  129. investing_algorithm_framework/{app/reporting → services}/metrics/win_rate.py +70 -3
  130. investing_algorithm_framework/services/order_service/order_backtest_service.py +21 -31
  131. investing_algorithm_framework/services/order_service/order_service.py +9 -71
  132. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -2
  133. investing_algorithm_framework/services/portfolios/portfolio_service.py +3 -13
  134. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +62 -96
  135. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -3
  136. investing_algorithm_framework/services/repository_service.py +5 -2
  137. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  138. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
  139. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  140. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  141. investing_algorithm_framework/services/trade_service/__init__.py +7 -1
  142. investing_algorithm_framework/services/trade_service/trade_service.py +51 -29
  143. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  144. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  145. investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
  146. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/RECORD +159 -148
  147. investing_algorithm_framework/app/reporting/evaluation.py +0 -243
  148. investing_algorithm_framework/app/reporting/metrics/risk_free_rate.py +0 -8
  149. investing_algorithm_framework/app/reporting/metrics/volatility.py +0 -69
  150. investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -3
  151. investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -9
  152. investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -47
  153. investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
  154. investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
  155. investing_algorithm_framework/domain/models/backtesting/backtest_results.py +0 -440
  156. investing_algorithm_framework/domain/models/data_source.py +0 -21
  157. investing_algorithm_framework/domain/models/date_range.py +0 -64
  158. investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -34
  159. investing_algorithm_framework/domain/models/trading_data_types.py +0 -48
  160. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
  161. investing_algorithm_framework/domain/services/market_data_sources.py +0 -543
  162. investing_algorithm_framework/domain/services/market_service.py +0 -153
  163. investing_algorithm_framework/domain/services/observable.py +0 -51
  164. investing_algorithm_framework/domain/services/observer.py +0 -19
  165. investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -16
  166. investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -746
  167. investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -270
  168. investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -312
  169. investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
  170. investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -471
  171. investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
  172. investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
  173. investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -322
  174. investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -10
  175. investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -269
  176. investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -350
  177. investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -377
  178. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -296
  179. investing_algorithm_framework-6.9.1.dist-info/METADATA +0 -440
  180. /investing_algorithm_framework/{app/reporting → services}/metrics/alpha.py +0 -0
  181. /investing_algorithm_framework/{app/reporting → services}/metrics/beta.py +0 -0
  182. /investing_algorithm_framework/{app/reporting → services}/metrics/cagr.py +0 -0
  183. /investing_algorithm_framework/{app/reporting → services}/metrics/calmar_ratio.py +0 -0
  184. /investing_algorithm_framework/{app/reporting → services}/metrics/mean_daily_return.py +0 -0
  185. /investing_algorithm_framework/{app/reporting → services}/metrics/price_efficiency.py +0 -0
  186. /investing_algorithm_framework/{app/reporting → services}/metrics/standard_deviation.py +0 -0
  187. /investing_algorithm_framework/{app/reporting → services}/metrics/treynor_ratio.py +0 -0
  188. /investing_algorithm_framework/{app/reporting → services}/metrics/ulcer.py +0 -0
  189. /investing_algorithm_framework/{app/reporting → services}/metrics/value_at_risk.py +0 -0
  190. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
  191. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
  192. {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 investing_algorithm_framework.app import App, Algorithm, \
1
+ from .app import App, Algorithm, \
2
2
  TradingStrategy, StatelessAction, Task, AppHook, Context, \
3
- add_html_report, add_metrics, BacktestReport, \
4
- BacktestReportsEvaluation, pretty_print_trades, pretty_print_positions, \
5
- pretty_print_orders, pretty_print_backtest
6
- from investing_algorithm_framework.domain import ApiException, \
7
- TradingDataType, TradingTimeFrame, OrderType, OperationalException, \
8
- OrderStatus, OrderSide, TimeUnit, TimeInterval, Order, Portfolio, \
9
- Position, TimeFrame, BACKTESTING_INDEX_DATETIME, MarketCredential, \
10
- PortfolioConfiguration, RESOURCE_DIRECTORY, \
11
- Trade, OHLCVMarketDataSource, OrderBookMarketDataSource, SYMBOLS, \
12
- TickerMarketDataSource, MarketService, \
13
- RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT, \
14
- BacktestDateRange, convert_polars_to_pandas, \
15
- DateRange, DEFAULT_LOGGING_CONFIG, \
16
- BacktestResult, TradeStatus, MarketDataType, TradeRiskType, \
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 investing_algorithm_framework.infrastructure import \
20
- CCXTOrderBookMarketDataSource, CCXTOHLCVMarketDataSource, \
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
- "BACKTESTING_INDEX_DATETIME",
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
- "BacktestResult",
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, add_metrics, \
9
- BacktestReport, pretty_print_backtest, BacktestReportsEvaluation, \
10
- pretty_print_trades, pretty_print_positions, pretty_print_orders
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
- MarketDataSource
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[MarketDataSource] = None,
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 = data_sources or []
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
- for task in tasks:
86
- algorithm.add_task(task)
85
+ strategies.extend(algorithm.strategies)
86
+ tasks.extend(algorithm.tasks)
87
+ on_strategy_run_hooks.extend(algorithm.on_strategy_run_hooks)
87
88
 
88
- for app_hook in on_strategy_run_hooks:
89
- algorithm.add_on_strategy_run_hook(app_hook)
89
+ if hasattr(algorithm, 'data_sources'):
90
+ data_sources.extend(algorithm.data_sources)
90
91
 
91
- return algorithm
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