investing-algorithm-framework 3.7.0__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 (256) hide show
  1. investing_algorithm_framework/__init__.py +168 -45
  2. investing_algorithm_framework/app/__init__.py +32 -1
  3. investing_algorithm_framework/app/algorithm/__init__.py +7 -0
  4. investing_algorithm_framework/app/algorithm/algorithm.py +239 -0
  5. investing_algorithm_framework/app/algorithm/algorithm_factory.py +114 -0
  6. investing_algorithm_framework/app/analysis/__init__.py +15 -0
  7. investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
  8. investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
  9. investing_algorithm_framework/app/analysis/permutation.py +116 -0
  10. investing_algorithm_framework/app/analysis/ranking.py +297 -0
  11. investing_algorithm_framework/app/app.py +1933 -589
  12. investing_algorithm_framework/app/app_hook.py +28 -0
  13. investing_algorithm_framework/app/context.py +1725 -0
  14. investing_algorithm_framework/app/eventloop.py +590 -0
  15. investing_algorithm_framework/app/reporting/__init__.py +27 -0
  16. investing_algorithm_framework/app/reporting/ascii.py +921 -0
  17. investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
  18. investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
  19. investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
  20. investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
  21. investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
  22. investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
  23. investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
  24. investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
  25. investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
  26. investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
  27. investing_algorithm_framework/app/reporting/generate.py +185 -0
  28. investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
  29. investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
  30. investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
  31. investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
  32. investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
  33. investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
  34. investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
  35. investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
  36. investing_algorithm_framework/app/stateless/action_handlers/__init__.py +4 -2
  37. investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
  38. investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +1 -1
  39. investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
  40. investing_algorithm_framework/app/strategy.py +664 -84
  41. investing_algorithm_framework/app/task.py +5 -3
  42. investing_algorithm_framework/app/web/__init__.py +2 -1
  43. investing_algorithm_framework/app/web/create_app.py +4 -2
  44. investing_algorithm_framework/cli/__init__.py +0 -0
  45. investing_algorithm_framework/cli/cli.py +226 -0
  46. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
  47. investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
  48. investing_algorithm_framework/cli/initialize_app.py +603 -0
  49. investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
  50. investing_algorithm_framework/cli/templates/app.py.template +18 -0
  51. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
  52. investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
  53. investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
  54. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  55. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  56. investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
  57. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
  58. investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
  59. investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
  60. investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
  61. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
  62. investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
  63. investing_algorithm_framework/cli/templates/env.example.template +2 -0
  64. investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
  65. investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
  66. investing_algorithm_framework/cli/templates/readme.md.template +135 -0
  67. investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
  68. investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
  69. investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
  70. investing_algorithm_framework/create_app.py +40 -6
  71. investing_algorithm_framework/dependency_container.py +72 -56
  72. investing_algorithm_framework/domain/__init__.py +71 -47
  73. investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
  74. investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
  75. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
  76. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
  77. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
  78. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  79. investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
  80. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  81. investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
  82. investing_algorithm_framework/domain/config.py +59 -91
  83. investing_algorithm_framework/domain/constants.py +13 -38
  84. investing_algorithm_framework/domain/data_provider.py +334 -0
  85. investing_algorithm_framework/domain/data_structures.py +3 -2
  86. investing_algorithm_framework/domain/exceptions.py +51 -1
  87. investing_algorithm_framework/domain/models/__init__.py +17 -12
  88. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  89. investing_algorithm_framework/domain/models/data/data_source.py +214 -0
  90. investing_algorithm_framework/domain/models/data/data_type.py +46 -0
  91. investing_algorithm_framework/domain/models/event.py +35 -0
  92. investing_algorithm_framework/domain/models/market/market_credential.py +55 -1
  93. investing_algorithm_framework/domain/models/order/order.py +77 -83
  94. investing_algorithm_framework/domain/models/order/order_status.py +2 -2
  95. investing_algorithm_framework/domain/models/order/order_type.py +1 -3
  96. investing_algorithm_framework/domain/models/portfolio/portfolio.py +81 -3
  97. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +26 -3
  98. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
  99. investing_algorithm_framework/domain/models/position/__init__.py +2 -1
  100. investing_algorithm_framework/domain/models/position/position.py +12 -0
  101. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  102. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  103. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  104. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  105. investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
  106. investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
  107. investing_algorithm_framework/domain/models/time_frame.py +37 -0
  108. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  109. investing_algorithm_framework/domain/models/time_unit.py +66 -2
  110. investing_algorithm_framework/domain/models/trade/__init__.py +8 -1
  111. investing_algorithm_framework/domain/models/trade/trade.py +295 -171
  112. investing_algorithm_framework/domain/models/trade/trade_status.py +9 -2
  113. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
  114. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
  115. investing_algorithm_framework/domain/order_executor.py +112 -0
  116. investing_algorithm_framework/domain/portfolio_provider.py +118 -0
  117. investing_algorithm_framework/domain/services/__init__.py +2 -9
  118. investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -6
  119. investing_algorithm_framework/domain/services/state_handler.py +38 -0
  120. investing_algorithm_framework/domain/strategy.py +1 -29
  121. investing_algorithm_framework/domain/utils/__init__.py +12 -7
  122. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  123. investing_algorithm_framework/domain/utils/dates.py +57 -0
  124. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  125. investing_algorithm_framework/domain/utils/polars.py +53 -0
  126. investing_algorithm_framework/domain/utils/random.py +29 -0
  127. investing_algorithm_framework/download_data.py +108 -0
  128. investing_algorithm_framework/infrastructure/__init__.py +31 -18
  129. investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
  130. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1143 -0
  131. investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
  132. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  133. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  134. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
  135. investing_algorithm_framework/infrastructure/models/__init__.py +6 -11
  136. investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -1
  137. investing_algorithm_framework/infrastructure/models/order/order.py +35 -49
  138. investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
  139. investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
  140. investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
  141. investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -0
  142. investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -5
  143. investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
  144. investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
  145. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
  146. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
  147. investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
  148. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  149. investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
  150. investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
  151. investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
  152. investing_algorithm_framework/infrastructure/repositories/__init__.py +8 -0
  153. investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
  154. investing_algorithm_framework/infrastructure/repositories/order_repository.py +5 -0
  155. investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +1 -1
  156. investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
  157. investing_algorithm_framework/infrastructure/repositories/repository.py +81 -27
  158. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
  159. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
  160. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
  161. investing_algorithm_framework/infrastructure/services/__init__.py +4 -4
  162. investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
  163. investing_algorithm_framework/infrastructure/services/aws/state_handler.py +113 -0
  164. investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
  165. investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
  166. investing_algorithm_framework/services/__init__.py +113 -16
  167. investing_algorithm_framework/services/backtesting/__init__.py +0 -7
  168. investing_algorithm_framework/services/backtesting/backtest_service.py +566 -359
  169. investing_algorithm_framework/services/configuration_service.py +77 -11
  170. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  171. investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
  172. investing_algorithm_framework/services/market_credential_service.py +16 -1
  173. investing_algorithm_framework/services/metrics/__init__.py +114 -0
  174. investing_algorithm_framework/services/metrics/alpha.py +0 -0
  175. investing_algorithm_framework/services/metrics/beta.py +0 -0
  176. investing_algorithm_framework/services/metrics/cagr.py +60 -0
  177. investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
  178. investing_algorithm_framework/services/metrics/drawdown.py +181 -0
  179. investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
  180. investing_algorithm_framework/services/metrics/exposure.py +210 -0
  181. investing_algorithm_framework/services/metrics/generate.py +358 -0
  182. investing_algorithm_framework/services/metrics/mean_daily_return.py +83 -0
  183. investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
  184. investing_algorithm_framework/services/metrics/recovery.py +113 -0
  185. investing_algorithm_framework/services/metrics/returns.py +452 -0
  186. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  187. investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
  188. investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
  189. investing_algorithm_framework/services/metrics/standard_deviation.py +157 -0
  190. investing_algorithm_framework/services/metrics/trades.py +500 -0
  191. investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  192. investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  193. investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  194. investing_algorithm_framework/services/metrics/volatility.py +97 -0
  195. investing_algorithm_framework/services/metrics/win_rate.py +177 -0
  196. investing_algorithm_framework/services/order_service/__init__.py +3 -1
  197. investing_algorithm_framework/services/order_service/order_backtest_service.py +76 -89
  198. investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
  199. investing_algorithm_framework/services/order_service/order_service.py +407 -326
  200. investing_algorithm_framework/services/portfolios/__init__.py +3 -1
  201. investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +37 -3
  202. investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +22 -8
  203. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
  204. investing_algorithm_framework/services/portfolios/portfolio_service.py +96 -28
  205. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +97 -28
  206. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +116 -313
  207. investing_algorithm_framework/services/positions/__init__.py +7 -0
  208. investing_algorithm_framework/services/positions/position_service.py +210 -0
  209. investing_algorithm_framework/services/repository_service.py +8 -2
  210. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  211. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
  212. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  213. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  214. investing_algorithm_framework/services/trade_service/__init__.py +7 -1
  215. investing_algorithm_framework/services/trade_service/trade_service.py +1013 -315
  216. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  217. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  218. investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
  219. investing_algorithm_framework-7.19.15.dist-info/RECORD +263 -0
  220. investing_algorithm_framework-7.19.15.dist-info/entry_points.txt +3 -0
  221. investing_algorithm_framework/app/algorithm.py +0 -1105
  222. investing_algorithm_framework/domain/graphs.py +0 -382
  223. investing_algorithm_framework/domain/metrics/__init__.py +0 -6
  224. investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -11
  225. investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -43
  226. investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
  227. investing_algorithm_framework/domain/models/backtesting/backtest_report.py +0 -580
  228. investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -243
  229. investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
  230. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
  231. investing_algorithm_framework/domain/services/market_data_sources.py +0 -344
  232. investing_algorithm_framework/domain/services/market_service.py +0 -153
  233. investing_algorithm_framework/domain/singleton.py +0 -9
  234. investing_algorithm_framework/domain/utils/backtesting.py +0 -472
  235. investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -12
  236. investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -559
  237. investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -254
  238. investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py +0 -47
  239. investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
  240. investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -455
  241. investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
  242. investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
  243. investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -350
  244. investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +0 -53
  245. investing_algorithm_framework/services/backtesting/graphs.py +0 -61
  246. investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -8
  247. investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -150
  248. investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -189
  249. investing_algorithm_framework/services/position_service.py +0 -31
  250. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -264
  251. investing_algorithm_framework-3.7.0.dist-info/METADATA +0 -339
  252. investing_algorithm_framework-3.7.0.dist-info/RECORD +0 -147
  253. /investing_algorithm_framework/{domain → services}/metrics/price_efficiency.py +0 -0
  254. /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
  255. {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
  256. {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
@@ -0,0 +1,96 @@
1
+ from datetime import datetime, timezone
2
+ from dateutil.parser import parse
3
+ from logging import getLogger
4
+
5
+ from investing_algorithm_framework.domain.exceptions import \
6
+ OperationalException
7
+
8
+ logger = getLogger("investing_algorithm_framework")
9
+
10
+
11
+ class BacktestDateRange:
12
+ """
13
+ Represents a date range for a backtest. This class
14
+ will check that the start and end dates are valid for a backtest.
15
+
16
+ Attributes:
17
+ _start_date (datetime): The start date of the backtest.
18
+ _end_date (datetime): The end date of the backtest. If not provided,
19
+ it defaults to the current UTC time.
20
+ _name (str): An optional name for the backtest date range.
21
+ """
22
+ def __init__(self, start_date, end_date=None, name=None):
23
+
24
+ if isinstance(start_date, str):
25
+ start_date = parse(start_date)
26
+
27
+ if end_date is not None and isinstance(end_date, str):
28
+ end_date = parse(end_date)
29
+
30
+ if end_date is None:
31
+ self._end_date = datetime.now(tz=timezone.utc)
32
+
33
+ # Check if start_date end end_date are utc datetime objects
34
+ time_zone_info = start_date.tzinfo
35
+
36
+ if time_zone_info is None or time_zone_info is not timezone.utc:
37
+ logger.warning(
38
+ "Start date must be a UTC datetime object. "
39
+ f"Received: {start_date}"
40
+ )
41
+ # Convert to UTC if not already
42
+ start_date = start_date.astimezone(timezone.utc)
43
+
44
+ time_zone_info = end_date.tzinfo
45
+
46
+ if time_zone_info is None or time_zone_info is not timezone.utc:
47
+ logger.warning(
48
+ "End date must be a UTC datetime object. "
49
+ f"Received: {end_date}"
50
+ )
51
+ # Convert to UTC if not already
52
+ end_date = end_date.astimezone(timezone.utc)
53
+
54
+ self._start_date = start_date
55
+ self._end_date = end_date
56
+ self._name = name
57
+
58
+ if end_date < start_date:
59
+ raise ValueError(
60
+ "End date cannot be before start date for a backtest "
61
+ "date range. " +
62
+ f"(start_date: {start_date}, end_date: {end_date})"
63
+ )
64
+
65
+ # Check if the start date is rounded to the nearest hour
66
+ if start_date.minute != 0 or start_date.second != 0 \
67
+ or start_date.microsecond != 0:
68
+ raise OperationalException(
69
+ "Start date must be rounded to the nearest hour. "
70
+ f"Received: {start_date}"
71
+ )
72
+ # Check if the end date is rounded to the nearest hour
73
+ if end_date.minute != 0 or end_date.second != 0 \
74
+ or end_date.microsecond != 0:
75
+ raise OperationalException(
76
+ "End date must be rounded to the nearest hour. "
77
+ f"Received: {end_date}"
78
+ )
79
+
80
+ @property
81
+ def start_date(self):
82
+ return self._start_date
83
+
84
+ @property
85
+ def end_date(self):
86
+ return self._end_date
87
+
88
+ @property
89
+ def name(self):
90
+ return self._name
91
+
92
+ def __repr__(self):
93
+ return f"{self.name}: {self._start_date} - {self._end_date}"
94
+
95
+ def __str__(self):
96
+ return self.__repr__()
@@ -0,0 +1,242 @@
1
+ from enum import Enum
2
+
3
+
4
+ class BacktestEvaluationFocus(Enum):
5
+ """
6
+ Enumeration for backtest evaluation focus areas.
7
+
8
+ The available metrics are:
9
+ - backtest_start_date
10
+ - backtest_end_date
11
+ - equity_curve
12
+ - final_value
13
+ - total_growth
14
+ - total_growth_percentage
15
+ - total_net_gain
16
+ - total_net_gain_percentage
17
+ - total_loss
18
+ - total_loss_percentage
19
+ - cumulative_return
20
+ - cumulative_return_series
21
+ - cagr
22
+ - sharpe_ratio
23
+ - rolling_sharpe_ratio
24
+ - sortino_ratio
25
+ - calmar_ratio
26
+ - profit_factor
27
+ - annual_volatility
28
+ - monthly_returns
29
+ - yearly_returns
30
+ - drawdown_series
31
+ - max_drawdown
32
+ - max_drawdown_absolute
33
+ - max_daily_drawdown
34
+ - max_drawdown_duration
35
+ - trades_per_year
36
+ - trade_per_day
37
+ - exposure_ratio
38
+ - cumulative_exposure
39
+ - best_trade
40
+ - worst_trade
41
+ - number_of_positive_trades
42
+ - percentage_positive_trades
43
+ - number_of_negative_trades
44
+ - percentage_negative_trades
45
+ - average_trade_duration
46
+ - average_trade_size
47
+ - average_trade_loss
48
+ - average_trade_loss_percentage
49
+ - average_trade_gain
50
+ - average_trade_gain_percentage
51
+ - average_trade_return
52
+ - average_trade_return_percentage
53
+ - median_trade_return
54
+ - number_of_trades
55
+ - number_of_trades_closed
56
+ - number_of_trades_opened
57
+ - number_of_trades_open_at_end
58
+ - win_rate
59
+ - current_win_rate
60
+ - win_loss_ratio
61
+ - current_win_loss_ratio
62
+ - percentage_winning_months
63
+ - percentage_winning_years
64
+ - average_monthly_return
65
+ - average_monthly_return_losing_months
66
+ - average_monthly_return_winning_months
67
+ - best_month
68
+ - best_year
69
+ - worst_month
70
+ - worst_year
71
+ - total_number_of_days
72
+ - current_average_trade_gain
73
+ - current_average_trade_return
74
+ - current_average_trade_duration
75
+ - current_average_trade_loss
76
+ """
77
+ BALANCED = "balanced"
78
+ PROFIT = "profit"
79
+ FREQUENCY = "frequency"
80
+ RISK_ADJUSTED = "risk_adjusted"
81
+
82
+ @staticmethod
83
+ def from_string(value: str):
84
+
85
+ if isinstance(value, str):
86
+
87
+ for entry in BacktestEvaluationFocus:
88
+
89
+ if value.upper() == entry.value:
90
+ return entry
91
+
92
+ raise ValueError(
93
+ f"Could not convert {value} to BacktestEvaluationFocus"
94
+ )
95
+ return None
96
+
97
+ @staticmethod
98
+ def from_value(value):
99
+
100
+ if isinstance(value, str):
101
+ return BacktestEvaluationFocus.from_string(value)
102
+
103
+ if isinstance(value, BacktestEvaluationFocus):
104
+
105
+ for entry in BacktestEvaluationFocus:
106
+
107
+ if value == entry:
108
+ return entry
109
+
110
+ raise ValueError(
111
+ f"Could not convert {value} to BacktestEvaluationFocus"
112
+ )
113
+
114
+ def equals(self, other):
115
+
116
+ if isinstance(other, Enum):
117
+ return self.value == other.value
118
+ else:
119
+ return BacktestEvaluationFocus.from_string(other) == self
120
+
121
+ def get_weights(self):
122
+ """
123
+ Get evaluation weights for different focus areas.
124
+ Returns a dictionary with metric weights where:
125
+ - Positive weights favor higher values
126
+ - Negative weights favor lower values (penalties)
127
+ - Zero weights ignore the metric
128
+ """
129
+
130
+ if self == BacktestEvaluationFocus.BALANCED:
131
+ return {
132
+ # Core profitability metrics (moderate weight)
133
+ "total_net_gain_percentage": 2.0,
134
+ "cagr": 1.5,
135
+ "average_trade_return_percentage": 1.0,
136
+
137
+ # Risk-adjusted returns (important for balance)
138
+ "sharpe_ratio": 2.0,
139
+ "sortino_ratio": 1.5,
140
+ "calmar_ratio": 1.0,
141
+ "profit_factor": 1.5,
142
+
143
+ # Risk management (penalties for bad metrics)
144
+ "max_drawdown": -1.5,
145
+ "max_drawdown_duration": -0.5,
146
+ "annual_volatility": -0.8,
147
+
148
+ # Trading consistency
149
+ "win_rate": 1.5,
150
+ "win_loss_ratio": 1.0,
151
+ "number_of_trades": 0.8, # Some activity needed
152
+
153
+ # Efficiency metrics
154
+ "exposure_ratio": 0.5,
155
+ "trades_per_year": 0.3,
156
+ }
157
+
158
+ elif self == BacktestEvaluationFocus.PROFIT:
159
+ return {
160
+ # Maximize absolute and relative profits
161
+ "total_net_gain_percentage": 3.0,
162
+ "cagr": 2.5,
163
+ "total_net_gain": 2.0,
164
+ "average_trade_return_percentage": 1.5,
165
+ "best_trade": 1.0,
166
+
167
+ # Profit consistency
168
+ "win_rate": 2.0,
169
+ "profit_factor": 2.0,
170
+ "percentage_positive_trades": 1.0,
171
+
172
+ # Risk secondary (but still important)
173
+ "sharpe_ratio": 1.0,
174
+ "max_drawdown": -1.0,
175
+
176
+ # Activity level (need some trades)
177
+ "number_of_trades": 0.5,
178
+
179
+ # Monthly/yearly consistency
180
+ "percentage_winning_months": 0.8,
181
+ "average_monthly_return": 1.0,
182
+ }
183
+
184
+ elif self == BacktestEvaluationFocus.FREQUENCY:
185
+ return {
186
+ # High trading activity with good results
187
+ "number_of_trades": 3.0,
188
+ "trades_per_year": 2.5,
189
+ "exposure_ratio": 2.0,
190
+
191
+ # Profitability per trade (scaled for frequency)
192
+ "average_trade_return_percentage": 2.0,
193
+ "win_rate": 2.5,
194
+ "total_net_gain_percentage": 1.5,
195
+
196
+ # Consistency across many trades
197
+ "win_loss_ratio": 1.5,
198
+ "percentage_positive_trades": 1.0,
199
+
200
+ # Risk management for frequent trading
201
+ "max_drawdown": -1.5,
202
+ "sharpe_ratio": 1.0,
203
+ "profit_factor": 1.2,
204
+
205
+ # Duration efficiency
206
+ "average_trade_duration": -0.3, # Prefer shorter trades
207
+ }
208
+
209
+ elif self == BacktestEvaluationFocus.RISK_ADJUSTED:
210
+ return {
211
+ # Risk-adjusted performance metrics (highest priority)
212
+ "sharpe_ratio": 3.0,
213
+ "sortino_ratio": 2.5,
214
+ "calmar_ratio": 2.0,
215
+
216
+ # Risk management (strong penalties)
217
+ "max_drawdown": -3.0,
218
+ "max_drawdown_duration": -1.5,
219
+ "annual_volatility": -2.0,
220
+ "worst_trade": -1.0,
221
+
222
+ # Consistent performance
223
+ "win_rate": 2.0,
224
+ "win_loss_ratio": 1.5,
225
+ "percentage_winning_months": 1.5,
226
+
227
+ # Stable returns
228
+ "average_trade_return_percentage": 1.5,
229
+ "total_net_gain_percentage": 1.0,
230
+ "profit_factor": 1.8,
231
+
232
+ # Reasonable activity
233
+ "number_of_trades": 0.5,
234
+
235
+ # Downside protection
236
+ "average_trade_loss_percentage": -1.0,
237
+ "percentage_negative_trades": -1.0,
238
+ }
239
+
240
+ # Fallback to balanced if unknown focus
241
+ return self.get_weights() \
242
+ if self != BacktestEvaluationFocus.BALANCED else {}