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,112 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from investing_algorithm_framework.domain import Order
4
+
5
+
6
+ class OrderExecutor(ABC):
7
+ """
8
+ Abstract base class for order executors. The OrderExecutor class is
9
+ responsible for executing orders in a trading algorithm.
10
+
11
+ Attributes:
12
+ _priority (int): The priority of the order executor compared to
13
+ other order executors. The lower the number, the higher the
14
+ priority. The framework will use this priority when searching
15
+ for an order executor for a specific market.
16
+ _config (dict): Reference to the application configuration.
17
+ """
18
+
19
+ def __init__(self, priority=1):
20
+ self._priority = priority
21
+ self._config = None
22
+
23
+ @property
24
+ def priority(self):
25
+ """
26
+ Returns the priority of the order executor.
27
+ """
28
+ return self._priority
29
+
30
+ @property
31
+ def config(self):
32
+ """
33
+ Returns the configuration of the order executor.
34
+ This can be used to store any configuration that is needed
35
+ for the order executor.
36
+ """
37
+ return self._config
38
+
39
+ @config.setter
40
+ def config(self, config):
41
+ """
42
+ Setter for the app config. This will be used to set a reference
43
+ to the config of the Application when the app is started.
44
+ """
45
+ self._config = config
46
+
47
+ @abstractmethod
48
+ def execute_order(self, portfolio, order, market_credential) -> Order:
49
+ """
50
+ Executes an order for a given portfolio. The order executor should
51
+ create an order on the exchange or broker and return an order object
52
+ that reflects the order on the exchange or broker. This should be
53
+ done by setting the external_id of the order to the id of the order
54
+ on the exchange or broker.
55
+
56
+ !Important: This function should not throw an exception if the order
57
+ is not successfully executed. Instead, it should return an order
58
+ instance with the status set to OrderStatus.FAILED.
59
+
60
+ Args:
61
+ order: The order to be executed
62
+ portfolio: The portfolio in which the order will be executed
63
+ market_credential: The market credential to use for the order
64
+
65
+ Returns:
66
+ Order: Instance of the executed order. The order instance
67
+ should copy the id of the order that has been provided as a
68
+ """
69
+ raise NotImplementedError(
70
+ "Subclasses must implement this method."
71
+ )
72
+
73
+ @abstractmethod
74
+ def cancel_order(self, portfolio, order, market_credential) -> Order:
75
+ """
76
+ Cancels an order for a given portfolio. The order executor should
77
+ cancel the order on the exchange or broker and return an order
78
+ object that reflects the order on the exchange or broker.
79
+
80
+ Args:
81
+ order: The order to be canceled
82
+ portfolio: The portfolio in which the order was executed
83
+ market_credential: The market credential to use for the order
84
+
85
+ Returns:
86
+ Order: Instance of the canceled order.
87
+ """
88
+ raise NotImplementedError(
89
+ "Subclasses must implement this method."
90
+ )
91
+
92
+ @abstractmethod
93
+ def supports_market(self, market):
94
+ """
95
+ Checks if the order executor supports the given market.
96
+
97
+ Args:
98
+ market: The market to check
99
+
100
+ Returns:
101
+ bool: True if the order executor supports the market, False
102
+ otherwise.
103
+ """
104
+ raise NotImplementedError(
105
+ "Subclasses must implement this method."
106
+ )
107
+
108
+ def __repr__(self):
109
+ """
110
+ Returns a string representation of the order executor.
111
+ """
112
+ return f"{self.__class__.__name__}(priority={self._priority})"
@@ -0,0 +1,118 @@
1
+ from typing import Union
2
+ from abc import ABC, abstractmethod
3
+
4
+ from investing_algorithm_framework.domain import Order, Position
5
+
6
+
7
+ class PortfolioProvider(ABC):
8
+ """
9
+ Abstract base class for portfolio providers. The PortfolioProvider class
10
+ is responsible for managing and providing access to trading portfolios.
11
+
12
+ Attributes:
13
+ _priority (int): The priority of the portfolio provider compared to
14
+ other portfolio providers. The lower the number, the higher the
15
+ priority. The framework will use this priority when searching
16
+ for a portfolio provider for a specific symbol or market.
17
+ _config (dict): Reference to the application configuration.
18
+ """
19
+
20
+ def __init__(self, priority=1):
21
+ self._priority = priority
22
+ self._config = None
23
+
24
+ @property
25
+ def priority(self):
26
+ """
27
+ Returns the priority of the portfolio provider.
28
+ """
29
+ return self._priority
30
+
31
+ @priority.setter
32
+ def priority(self, value: int):
33
+ """
34
+ Sets the priority of the portfolio provider.
35
+ """
36
+ self._priority = value
37
+
38
+ @property
39
+ def config(self):
40
+ """
41
+ Returns the configuration of the order executor.
42
+ This can be used to store any configuration that is needed
43
+ for the order executor.
44
+ """
45
+ return self._config
46
+
47
+ @config.setter
48
+ def config(self, config):
49
+ """
50
+ Setter for the app config. This will be used to set a reference
51
+ to the config of the Application when the app is started.
52
+ """
53
+ self._config = config
54
+
55
+ @abstractmethod
56
+ def get_order(
57
+ self, portfolio, order, market_credential
58
+ ) -> Union[Order, None]:
59
+ """
60
+ Function to get an order from the exchange or broker. The returned
61
+ should be an order object that reflects the current state of the
62
+ order on the exchange or broker.
63
+
64
+ !IMPORTANT: This function should return None if the order is
65
+ not found or if the order is not available on the
66
+ exchange or broker. Please do not throw an exception if the
67
+ order is not found.
68
+
69
+ Args:
70
+ portfolio: Portfolio object
71
+ order: Order object from the database
72
+ market_credential: Market credential object
73
+
74
+ Returns:
75
+ Order: Order object reflecting the order on the exchange or broker
76
+ """
77
+ raise NotImplementedError("Subclasses must implement this method.")
78
+
79
+ @abstractmethod
80
+ def get_position(
81
+ self, portfolio, symbol, market_credential
82
+ ) -> Union[Position, None]:
83
+ """
84
+ Function to get the position for a given symbol in the portfolio.
85
+ The returned position should be an object that reflects the current
86
+ state of the position on the exchange or broker.
87
+
88
+ !IMPORTANT: This function should return None if the position is
89
+ not found or if the position is not available on the
90
+ exchange or broker. Please do not throw an exception if the
91
+ position is not found.
92
+
93
+ Args:
94
+ portfolio: Portfolio object
95
+ symbol: Symbol object
96
+ market_credential: MarketCredential object
97
+
98
+ Returns:
99
+ float: Position for the given symbol in the portfolio
100
+ """
101
+ raise NotImplementedError("Subclasses must implement this method.")
102
+
103
+ @abstractmethod
104
+ def supports_market(self, market) -> bool:
105
+ """
106
+ Function to check if the market is supported by the portfolio
107
+ provider.
108
+
109
+ Args:
110
+ market: Market object
111
+
112
+ Returns:
113
+ bool: True if the market is supported, False otherwise
114
+ """
115
+ raise NotImplementedError("Subclasses must implement this method.")
116
+
117
+ def __repr__(self):
118
+ return f"{self.__class__.__name__}(priority={self.priority})"
@@ -1,18 +1,11 @@
1
1
  from .market_credential_service import MarketCredentialService
2
- from .market_data_sources import MarketDataSource, TickerMarketDataSource, \
3
- OHLCVMarketDataSource, OrderBookMarketDataSource, BacktestMarketDataSource
4
- from .market_service import MarketService
5
2
  from .portfolios import AbstractPortfolioSyncService
6
3
  from .rounding_service import RoundingService
4
+ from .state_handler import StateHandler
7
5
 
8
6
  __all__ = [
9
- "MarketDataSource",
10
- "TickerMarketDataSource",
11
- "OHLCVMarketDataSource",
12
- "OrderBookMarketDataSource",
13
- "BacktestMarketDataSource",
14
- "MarketService",
15
7
  "MarketCredentialService",
16
8
  "AbstractPortfolioSyncService",
17
9
  "RoundingService",
10
+ "StateHandler",
18
11
  ]
@@ -5,11 +5,5 @@ class AbstractPortfolioSyncService:
5
5
  def sync_unallocated(self, portfolio):
6
6
  pass
7
7
 
8
- def sync_positions(self, portfolio):
9
- pass
10
-
11
8
  def sync_orders(self, portfolio):
12
9
  pass
13
-
14
- def sync_trades(self, portfolio):
15
- pass
@@ -0,0 +1,38 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class StateHandler(ABC):
5
+ """
6
+ Abstract base class for state handlers.
7
+
8
+ This class defines the
9
+ interface for state handlers, which are responsible for
10
+ saving and loading state information.
11
+ """
12
+
13
+ @abstractmethod
14
+ def initialize(self):
15
+ """
16
+ Initialize the state handler.
17
+ """
18
+ pass
19
+
20
+ @abstractmethod
21
+ def save(self, target_directory: str):
22
+ """
23
+ Save the state to the specified directory.
24
+
25
+ Args:
26
+ target_directory (str): Directory to save the state
27
+ """
28
+ pass
29
+
30
+ @abstractmethod
31
+ def load(self, target_directory: str):
32
+ """
33
+ Load the state from the specified directory.
34
+
35
+ Args:
36
+ target_directory (str): Directory to load the state
37
+ """
38
+ pass
@@ -1,4 +1,4 @@
1
- from .models import TradingTimeFrame, TradingDataType, TimeUnit
1
+ from .models import TimeUnit
2
2
 
3
3
 
4
4
  class Strategy:
@@ -11,9 +11,6 @@ class Strategy:
11
11
  worker_id=None,
12
12
  symbols=None,
13
13
  limit=None,
14
- trading_data_type=None,
15
- trading_data_types=None,
16
- trading_time_frame=None,
17
14
  ):
18
15
  self._market = market
19
16
  self._time_unit = TimeUnit.from_value(time_unit).value
@@ -22,19 +19,6 @@ class Strategy:
22
19
  self._limit = limit
23
20
  self._worker_id = worker_id
24
21
 
25
- if trading_data_type is not None:
26
- self._trading_data_type = TradingDataType \
27
- .from_value(trading_data_type)
28
-
29
- if trading_data_types is not None:
30
- trading_data_types = [TradingDataType.from_value(trading_data_type)
31
- for trading_data_type in trading_data_types]
32
- self._trading_data_types = trading_data_types
33
-
34
- if trading_time_frame is not None:
35
- self._trading_time_frame = TradingTimeFrame \
36
- .from_value(trading_time_frame)
37
-
38
22
  @property
39
23
  def market(self):
40
24
  return self._market
@@ -55,18 +39,6 @@ class Strategy:
55
39
  def limit(self):
56
40
  return self._limit
57
41
 
58
- @property
59
- def trading_data_type(self):
60
- return self._trading_data_type
61
-
62
- @property
63
- def trading_data_types(self):
64
- return self._trading_data_types
65
-
66
- @property
67
- def trading_time_frame(self):
68
- return self._trading_time_frame
69
-
70
42
  @property
71
43
  def worker_id(self):
72
44
  return self._worker_id
@@ -1,22 +1,27 @@
1
- from .backtesting import pretty_print_backtest, load_backtest_report, \
2
- pretty_print_backtest_reports_evaluation, load_backtest_reports
3
1
  from .csv import get_total_amount_of_rows, append_dict_as_row_to_csv, \
4
2
  add_column_headers_to_csv, csv_to_list, load_csv_into_dict
5
- from .random import random_string
3
+ from .random import random_string, random_number
6
4
  from .stoppable_thread import StoppableThread
7
5
  from .synchronized import synchronized
6
+ from .polars import convert_polars_to_pandas
7
+ from .dates import is_timezone_aware, sync_timezones, get_timezone
8
+ from .jupyter_notebook_detection import is_jupyter_notebook
9
+ from .custom_tqdm import tqdm
8
10
 
9
11
  __all__ = [
10
12
  'synchronized',
11
13
  'StoppableThread',
12
14
  'random_string',
15
+ 'random_number',
13
16
  'get_total_amount_of_rows',
14
17
  'append_dict_as_row_to_csv',
15
18
  'add_column_headers_to_csv',
16
19
  'csv_to_list',
17
- 'pretty_print_backtest',
18
- 'pretty_print_backtest_reports_evaluation',
19
20
  'load_csv_into_dict',
20
- 'load_backtest_report',
21
- 'load_backtest_reports',
21
+ 'convert_polars_to_pandas',
22
+ 'is_timezone_aware',
23
+ 'sync_timezones',
24
+ 'get_timezone',
25
+ 'is_jupyter_notebook',
26
+ 'tqdm'
22
27
  ]
@@ -0,0 +1,22 @@
1
+ from tqdm.notebook import tqdm as tqdm_notebook
2
+ from tqdm import tqdm as tqdm_terminal
3
+
4
+ from .jupyter_notebook_detection import is_jupyter_notebook
5
+
6
+
7
+ def tqdm(*args, **kwargs):
8
+ """
9
+ Returns a tqdm progress bar that adapts to the
10
+ environment (Jupyter Notebook or terminal).
11
+
12
+ Args:
13
+ *args: Positional arguments for tqdm.
14
+ **kwargs: Keyword arguments for tqdm.
15
+
16
+ Returns:
17
+ tqdm object: A tqdm progress bar.
18
+ """
19
+ if is_jupyter_notebook():
20
+ return tqdm_notebook(*args, **kwargs)
21
+ else:
22
+ return tqdm_terminal(*args, **kwargs)
@@ -0,0 +1,57 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+ import pytz
4
+
5
+
6
+ def is_timezone_aware(dt: datetime) -> bool:
7
+ """
8
+ Check if a datetime object is timezone-aware.
9
+
10
+ Args:
11
+ dt (datetime): The datetime object to check.
12
+
13
+ Returns:
14
+ bool: True if the datetime is timezone-aware, False otherwise.
15
+ """
16
+ return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
17
+
18
+
19
+ def get_timezone(dt: datetime) -> Optional[pytz.tzinfo.BaseTzInfo]:
20
+ """
21
+ Returns the timezone info from a datetime object.
22
+
23
+ Args:
24
+ dt (datetime): The datetime object to check.
25
+
26
+ Returns:
27
+ pytz timezone info if available, otherwise None.
28
+ """
29
+ if dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None:
30
+ return dt.tzinfo
31
+ return None
32
+
33
+
34
+ def sync_timezones(reference_dt: datetime, naive_dt: datetime) -> datetime:
35
+ """
36
+ Synchronize a naive datetime with the timezone of a reference datetime.
37
+
38
+ Args:
39
+ reference_dt (datetime): A timezone-aware datetime to
40
+ use as a reference.
41
+ naive_dt (datetime): A naive datetime to be synchronized.
42
+
43
+ Returns:
44
+ Datetime: A timezone-aware datetime that matches the
45
+ timezone of the reference.
46
+ """
47
+ tz = get_timezone(reference_dt)
48
+
49
+ if tz is None:
50
+ return naive_dt
51
+
52
+ # Check if tz has a localize method (pytz)
53
+ if hasattr(tz, 'localize'):
54
+ return tz.localize(naive_dt)
55
+ else:
56
+ # fallback (e.g., zoneinfo or other)
57
+ return naive_dt.replace(tzinfo=tz)
@@ -0,0 +1,19 @@
1
+ def is_jupyter_notebook():
2
+ """
3
+ Check if the code is running in a Jupyter Notebook environment.
4
+
5
+ Returns:
6
+ bool: True if running in a Jupyter Notebook, False otherwise.
7
+ """
8
+ try:
9
+ # Check for the presence of the 'IPython' module
10
+ from IPython import get_ipython
11
+ return 'IPKernelApp' in get_ipython().config
12
+ except ImportError:
13
+ return False
14
+ except AttributeError:
15
+ # If get_ipython() does not have 'config', it is not a Jupyter Notebook
16
+ return False
17
+ except Exception:
18
+ # Catch any other exceptions and return False
19
+ return False
@@ -0,0 +1,53 @@
1
+ import pandas as pd
2
+ from polars import DataFrame as PolarsDataFrame
3
+
4
+
5
+ def convert_polars_to_pandas(
6
+ data: PolarsDataFrame,
7
+ remove_duplicates=True,
8
+ add_index=True,
9
+ add_datetime_column=True,
10
+ datetime_column_name="Datetime"
11
+ ):
12
+ """
13
+ Function to convert polars dataframe to pandas dataframe.
14
+
15
+ The function will set the index to the datetime column. The reason
16
+ for this is that You can filter with clean, readable code in a faster way
17
+ then with filtering on a column that is not the index.
18
+
19
+ Args:
20
+ data:Polars Dataframe - The original polars dataframe
21
+ remove_duplicates: Boolean - If set to true, all duplicate
22
+ dates will be removed from the dataframe
23
+ add_index: Boolean - If set to true, an index will
24
+ be added to the dataframe
25
+ add_datetime_column: Boolean - If set to true, a datetime
26
+ column will be added to the dataframe
27
+ datetime_column_name: String - the column name that has the
28
+ datetime object. By default this is set to column name Datetime
29
+ This is only used if add_index is set to True
30
+
31
+ Returns:
32
+ DataFrame: Pandas DataFrame that has been converted
33
+ from a Polars DataFrame
34
+ """
35
+
36
+ if not isinstance(data, PolarsDataFrame):
37
+ raise ValueError("Data must be a Polars DataFrame")
38
+
39
+ df = data.to_pandas().copy()
40
+
41
+ if add_datetime_column and datetime_column_name not in df.columns:
42
+ df[datetime_column_name] = pd.to_datetime(df.index)
43
+
44
+ # Ensure datetime column is datetime type
45
+ df[datetime_column_name] = pd.to_datetime(df[datetime_column_name])
46
+
47
+ if remove_duplicates:
48
+ df = df.drop_duplicates(subset=datetime_column_name, keep="first")
49
+
50
+ if add_index:
51
+ df.set_index(datetime_column_name, inplace=True)
52
+
53
+ return df
@@ -3,6 +3,16 @@ import string
3
3
 
4
4
 
5
5
  def random_string(n, spaces: bool = False):
6
+ """
7
+ Function to generate a random string of n characters.
8
+
9
+ Args:
10
+ n: number of characters
11
+ spaces: if True, include spaces in the string
12
+
13
+ Returns:
14
+ str: Random string of n characters
15
+ """
6
16
 
7
17
  if spaces:
8
18
  return ''.join(
@@ -10,3 +20,22 @@ def random_string(n, spaces: bool = False):
10
20
  )
11
21
 
12
22
  return ''.join(random.choice(string.ascii_lowercase) for _ in range(n))
23
+
24
+
25
+ def random_number(n, variable_size: bool = False):
26
+ """
27
+ Function to generate a random number of n digits.
28
+
29
+ Args:
30
+ n: number of digits
31
+ variable_size: if True, the number of digits will be variable
32
+ between 1 and n
33
+
34
+ Returns:
35
+ int: Random number of n digits
36
+ """
37
+
38
+ if variable_size:
39
+ n = random.randint(1, n)
40
+
41
+ return int(''.join(random.choice(string.digits) for _ in range(n)))
@@ -0,0 +1,108 @@
1
+ from pathlib import Path
2
+ from dateutil import parser
3
+ from datetime import timezone, datetime
4
+ import pandas
5
+ import polars
6
+ from typing import Union
7
+ from investing_algorithm_framework.services import DataProviderService, \
8
+ ConfigurationService, MarketCredentialService
9
+ from investing_algorithm_framework.infrastructure import \
10
+ get_default_data_providers
11
+ from investing_algorithm_framework.domain import DataSource, \
12
+ OperationalException, DataType
13
+
14
+
15
+ def download(
16
+ symbol: str,
17
+ market: str = None,
18
+ date: Union[datetime, str] = None,
19
+ time_frame: str = None,
20
+ data_type: Union[str, DataType] = DataType.OHLCV,
21
+ start_date: Union[datetime, str] = None,
22
+ end_date: Union[datetime, str] = None,
23
+ window_size: int = 200,
24
+ pandas: bool = True,
25
+ save: bool = True,
26
+ storage_path: Union[str, Path] = None,
27
+ ) -> Union[pandas.DataFrame, polars.DataFrame]:
28
+ """
29
+ Download market data from the specified source. This function
30
+ uses the MarketDataSourceService to get the data provider
31
+ for the given set of parameters.
32
+
33
+ Args:
34
+ symbol (str): The symbol to download data for.
35
+ market (str): The market to download data from.
36
+ data_type (str): The type of data to
37
+ download (e.g., "ohlcv", "ticker").
38
+ start_date (str): The start date for the data download.
39
+ end_date (str): The end date for the data download.
40
+ window_size (int): The size of the data window.
41
+ pandas (bool): Whether to return the data as a pandas DataFrame.
42
+ save (bool): Whether to save the downloaded data.
43
+ storage_path (str): The directory to save the downloaded data.
44
+ time_frame (str): The time frame for the data download.
45
+ date (str): The date for the data download.
46
+ window_size (int): The size of the data window.
47
+ pandas (bool): Whether to return the data as a pandas DataFrame.
48
+
49
+ Returns:
50
+ None
51
+ """
52
+ configuration_service = ConfigurationService()
53
+ market_credential_service = MarketCredentialService()
54
+ data_provider_service = DataProviderService(
55
+ default_data_providers=get_default_data_providers(),
56
+ configuration_service=configuration_service,
57
+ market_credential_service=market_credential_service,
58
+ )
59
+
60
+ if start_date is not None and isinstance(start_date, str):
61
+ start_date = parser.parse(start_date)
62
+ start_date = start_date.replace(tzinfo=timezone.utc)
63
+
64
+ if end_date is not None and isinstance(end_date, str):
65
+ end_date = parser.parse(end_date)
66
+ end_date = end_date.replace(tzinfo=timezone.utc)
67
+
68
+ if date is not None and isinstance(date, str):
69
+ date = parser.parse(date)
70
+ date = date.replace(tzinfo=timezone.utc)
71
+
72
+ # Check if all the datetime parameters are in UTC
73
+ if date is not None \
74
+ and (date.tzinfo is None or date.tzinfo != timezone.utc):
75
+ raise OperationalException("Date must be a UTC datetime object")
76
+
77
+ if start_date is not None \
78
+ and (
79
+ start_date.tzinfo is None or start_date.tzinfo != timezone.utc
80
+ ):
81
+ raise OperationalException("Start date must be a UTC datetime object")
82
+
83
+ if end_date is not None \
84
+ and (end_date.tzinfo is None or end_date.tzinfo != timezone.utc):
85
+ raise OperationalException("End date must be a UTC datetime object")
86
+
87
+ data_source = DataSource(
88
+ symbol=symbol,
89
+ market=market,
90
+ data_type=data_type,
91
+ time_frame=time_frame,
92
+ date=date,
93
+ start_date=start_date,
94
+ end_date=end_date,
95
+ window_size=window_size,
96
+ pandas=pandas,
97
+ save=save,
98
+ storage_path=storage_path
99
+ )
100
+ data_provider_service.index_data_providers(
101
+ data_sources=[data_source]
102
+ )
103
+ return data_provider_service.get_data(
104
+ data_source=data_source,
105
+ date=date,
106
+ start_date=start_date,
107
+ end_date=end_date,
108
+ )