investing-algorithm-framework 7.19.14__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 (260) hide show
  1. investing_algorithm_framework/__init__.py +197 -0
  2. investing_algorithm_framework/app/__init__.py +47 -0
  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 +2204 -0
  12. investing_algorithm_framework/app/app_hook.py +28 -0
  13. investing_algorithm_framework/app/context.py +1667 -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/__init__.py +35 -0
  37. investing_algorithm_framework/app/stateless/action_handlers/__init__.py +84 -0
  38. investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +8 -0
  39. investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +15 -0
  40. investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +40 -0
  41. investing_algorithm_framework/app/stateless/exception_handler.py +40 -0
  42. investing_algorithm_framework/app/strategy.py +675 -0
  43. investing_algorithm_framework/app/task.py +41 -0
  44. investing_algorithm_framework/app/web/__init__.py +5 -0
  45. investing_algorithm_framework/app/web/controllers/__init__.py +13 -0
  46. investing_algorithm_framework/app/web/controllers/orders.py +20 -0
  47. investing_algorithm_framework/app/web/controllers/portfolio.py +20 -0
  48. investing_algorithm_framework/app/web/controllers/positions.py +18 -0
  49. investing_algorithm_framework/app/web/create_app.py +20 -0
  50. investing_algorithm_framework/app/web/error_handler.py +59 -0
  51. investing_algorithm_framework/app/web/responses.py +20 -0
  52. investing_algorithm_framework/app/web/run_strategies.py +4 -0
  53. investing_algorithm_framework/app/web/schemas/__init__.py +12 -0
  54. investing_algorithm_framework/app/web/schemas/order.py +12 -0
  55. investing_algorithm_framework/app/web/schemas/portfolio.py +22 -0
  56. investing_algorithm_framework/app/web/schemas/position.py +15 -0
  57. investing_algorithm_framework/app/web/setup_cors.py +6 -0
  58. investing_algorithm_framework/cli/__init__.py +0 -0
  59. investing_algorithm_framework/cli/cli.py +207 -0
  60. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +499 -0
  61. investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
  62. investing_algorithm_framework/cli/initialize_app.py +603 -0
  63. investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
  64. investing_algorithm_framework/cli/templates/app.py.template +18 -0
  65. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
  66. investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
  67. investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
  68. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  69. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  70. investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
  71. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
  72. investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
  73. investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
  74. investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
  75. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
  76. investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
  77. investing_algorithm_framework/cli/templates/env.example.template +2 -0
  78. investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
  79. investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
  80. investing_algorithm_framework/cli/templates/readme.md.template +135 -0
  81. investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
  82. investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
  83. investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
  84. investing_algorithm_framework/create_app.py +54 -0
  85. investing_algorithm_framework/dependency_container.py +155 -0
  86. investing_algorithm_framework/domain/__init__.py +148 -0
  87. investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
  88. investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
  89. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
  90. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
  91. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
  92. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  93. investing_algorithm_framework/domain/backtesting/backtest_run.py +435 -0
  94. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  95. investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
  96. investing_algorithm_framework/domain/config.py +111 -0
  97. investing_algorithm_framework/domain/constants.py +83 -0
  98. investing_algorithm_framework/domain/data_provider.py +334 -0
  99. investing_algorithm_framework/domain/data_structures.py +42 -0
  100. investing_algorithm_framework/domain/decimal_parsing.py +40 -0
  101. investing_algorithm_framework/domain/exceptions.py +112 -0
  102. investing_algorithm_framework/domain/models/__init__.py +43 -0
  103. investing_algorithm_framework/domain/models/app_mode.py +34 -0
  104. investing_algorithm_framework/domain/models/base_model.py +25 -0
  105. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  106. investing_algorithm_framework/domain/models/data/data_source.py +214 -0
  107. investing_algorithm_framework/domain/models/data/data_type.py +46 -0
  108. investing_algorithm_framework/domain/models/event.py +35 -0
  109. investing_algorithm_framework/domain/models/market/__init__.py +5 -0
  110. investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
  111. investing_algorithm_framework/domain/models/order/__init__.py +6 -0
  112. investing_algorithm_framework/domain/models/order/order.py +384 -0
  113. investing_algorithm_framework/domain/models/order/order_side.py +36 -0
  114. investing_algorithm_framework/domain/models/order/order_status.py +37 -0
  115. investing_algorithm_framework/domain/models/order/order_type.py +30 -0
  116. investing_algorithm_framework/domain/models/portfolio/__init__.py +9 -0
  117. investing_algorithm_framework/domain/models/portfolio/portfolio.py +169 -0
  118. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +93 -0
  119. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +208 -0
  120. investing_algorithm_framework/domain/models/position/__init__.py +4 -0
  121. investing_algorithm_framework/domain/models/position/position.py +68 -0
  122. investing_algorithm_framework/domain/models/position/position_snapshot.py +47 -0
  123. investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
  124. investing_algorithm_framework/domain/models/strategy_profile.py +33 -0
  125. investing_algorithm_framework/domain/models/time_frame.py +153 -0
  126. investing_algorithm_framework/domain/models/time_interval.py +124 -0
  127. investing_algorithm_framework/domain/models/time_unit.py +149 -0
  128. investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
  129. investing_algorithm_framework/domain/models/tracing/trace.py +23 -0
  130. investing_algorithm_framework/domain/models/trade/__init__.py +13 -0
  131. investing_algorithm_framework/domain/models/trade/trade.py +388 -0
  132. investing_algorithm_framework/domain/models/trade/trade_risk_type.py +34 -0
  133. investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
  134. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +267 -0
  135. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +303 -0
  136. investing_algorithm_framework/domain/order_executor.py +112 -0
  137. investing_algorithm_framework/domain/portfolio_provider.py +118 -0
  138. investing_algorithm_framework/domain/positions/__init__.py +4 -0
  139. investing_algorithm_framework/domain/positions/position_size.py +41 -0
  140. investing_algorithm_framework/domain/services/__init__.py +11 -0
  141. investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
  142. investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
  143. investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
  144. investing_algorithm_framework/domain/services/rounding_service.py +27 -0
  145. investing_algorithm_framework/domain/services/state_handler.py +38 -0
  146. investing_algorithm_framework/domain/stateless_actions.py +7 -0
  147. investing_algorithm_framework/domain/strategy.py +44 -0
  148. investing_algorithm_framework/domain/utils/__init__.py +27 -0
  149. investing_algorithm_framework/domain/utils/csv.py +104 -0
  150. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  151. investing_algorithm_framework/domain/utils/dates.py +57 -0
  152. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  153. investing_algorithm_framework/domain/utils/polars.py +53 -0
  154. investing_algorithm_framework/domain/utils/random.py +41 -0
  155. investing_algorithm_framework/domain/utils/signatures.py +17 -0
  156. investing_algorithm_framework/domain/utils/stoppable_thread.py +26 -0
  157. investing_algorithm_framework/domain/utils/synchronized.py +12 -0
  158. investing_algorithm_framework/download_data.py +108 -0
  159. investing_algorithm_framework/infrastructure/__init__.py +50 -0
  160. investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
  161. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1143 -0
  162. investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
  163. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  164. investing_algorithm_framework/infrastructure/database/__init__.py +10 -0
  165. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +120 -0
  166. investing_algorithm_framework/infrastructure/models/__init__.py +16 -0
  167. investing_algorithm_framework/infrastructure/models/decimal_parser.py +14 -0
  168. investing_algorithm_framework/infrastructure/models/model_extension.py +6 -0
  169. investing_algorithm_framework/infrastructure/models/order/__init__.py +4 -0
  170. investing_algorithm_framework/infrastructure/models/order/order.py +124 -0
  171. investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
  172. investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
  173. investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +4 -0
  174. investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +37 -0
  175. investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +114 -0
  176. investing_algorithm_framework/infrastructure/models/position/__init__.py +4 -0
  177. investing_algorithm_framework/infrastructure/models/position/position.py +63 -0
  178. investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +23 -0
  179. investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
  180. investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
  181. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +40 -0
  182. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +41 -0
  183. investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
  184. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  185. investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
  186. investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
  187. investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
  188. investing_algorithm_framework/infrastructure/repositories/__init__.py +21 -0
  189. investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
  190. investing_algorithm_framework/infrastructure/repositories/order_repository.py +96 -0
  191. investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +30 -0
  192. investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +56 -0
  193. investing_algorithm_framework/infrastructure/repositories/position_repository.py +66 -0
  194. investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +21 -0
  195. investing_algorithm_framework/infrastructure/repositories/repository.py +299 -0
  196. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
  197. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +23 -0
  198. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +23 -0
  199. investing_algorithm_framework/infrastructure/services/__init__.py +7 -0
  200. investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
  201. investing_algorithm_framework/infrastructure/services/aws/state_handler.py +113 -0
  202. investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
  203. investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
  204. investing_algorithm_framework/services/__init__.py +132 -0
  205. investing_algorithm_framework/services/backtesting/__init__.py +5 -0
  206. investing_algorithm_framework/services/backtesting/backtest_service.py +651 -0
  207. investing_algorithm_framework/services/configuration_service.py +96 -0
  208. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  209. investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
  210. investing_algorithm_framework/services/market_credential_service.py +40 -0
  211. investing_algorithm_framework/services/metrics/__init__.py +114 -0
  212. investing_algorithm_framework/services/metrics/alpha.py +0 -0
  213. investing_algorithm_framework/services/metrics/beta.py +0 -0
  214. investing_algorithm_framework/services/metrics/cagr.py +60 -0
  215. investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
  216. investing_algorithm_framework/services/metrics/drawdown.py +181 -0
  217. investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
  218. investing_algorithm_framework/services/metrics/exposure.py +210 -0
  219. investing_algorithm_framework/services/metrics/generate.py +358 -0
  220. investing_algorithm_framework/services/metrics/mean_daily_return.py +83 -0
  221. investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
  222. investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
  223. investing_algorithm_framework/services/metrics/recovery.py +113 -0
  224. investing_algorithm_framework/services/metrics/returns.py +452 -0
  225. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  226. investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
  227. investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
  228. investing_algorithm_framework/services/metrics/standard_deviation.py +157 -0
  229. investing_algorithm_framework/services/metrics/trades.py +500 -0
  230. investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  231. investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  232. investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  233. investing_algorithm_framework/services/metrics/volatility.py +97 -0
  234. investing_algorithm_framework/services/metrics/win_rate.py +177 -0
  235. investing_algorithm_framework/services/order_service/__init__.py +9 -0
  236. investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
  237. investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
  238. investing_algorithm_framework/services/order_service/order_service.py +826 -0
  239. investing_algorithm_framework/services/portfolios/__init__.py +16 -0
  240. investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
  241. investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +75 -0
  242. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
  243. investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
  244. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
  245. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
  246. investing_algorithm_framework/services/positions/__init__.py +7 -0
  247. investing_algorithm_framework/services/positions/position_service.py +210 -0
  248. investing_algorithm_framework/services/positions/position_snapshot_service.py +18 -0
  249. investing_algorithm_framework/services/repository_service.py +40 -0
  250. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  251. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +132 -0
  252. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +66 -0
  253. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +41 -0
  254. investing_algorithm_framework/services/trade_service/__init__.py +3 -0
  255. investing_algorithm_framework/services/trade_service/trade_service.py +1083 -0
  256. investing_algorithm_framework-7.19.14.dist-info/LICENSE +201 -0
  257. investing_algorithm_framework-7.19.14.dist-info/METADATA +459 -0
  258. investing_algorithm_framework-7.19.14.dist-info/RECORD +260 -0
  259. investing_algorithm_framework-7.19.14.dist-info/WHEEL +4 -0
  260. investing_algorithm_framework-7.19.14.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,214 @@
1
+ from dataclasses import dataclass
2
+ from datetime import datetime, timezone, timedelta
3
+ from typing import Union
4
+
5
+ from dateutil import parser
6
+
7
+ from investing_algorithm_framework.domain.models.time_frame import TimeFrame
8
+ from .data_type import DataType
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class DataSource:
13
+ """
14
+ Base class for data sources.
15
+ """
16
+ identifier: str = None
17
+ data_provider_identifier: str = None
18
+ data_type: Union[DataType, str] = None
19
+ symbol: str = None
20
+ window_size: int = None
21
+ time_frame: Union[TimeFrame, str] = None
22
+ market: str = None
23
+ storage_path: str = None
24
+ pandas: bool = False
25
+ date: Union[datetime, None] = None
26
+ start_date: Union[datetime, None] = None
27
+ end_date: Union[datetime, None] = None
28
+ save: bool = False
29
+
30
+ def __post_init__(self):
31
+ # Convert data_type and time_frame to their respective enums if needed
32
+ if isinstance(self.data_type, str):
33
+ object.__setattr__(self, 'data_type',
34
+ DataType.from_string(self.data_type))
35
+
36
+ if isinstance(self.time_frame, str):
37
+ object.__setattr__(self, 'time_frame',
38
+ TimeFrame.from_string(self.time_frame))
39
+
40
+ start_date = self.start_date
41
+ end_date = self.end_date
42
+
43
+ # Parse the start_date if it is a string and
44
+ # make sure its set to timezone utc
45
+ if start_date is None:
46
+
47
+ if isinstance(self.start_date, str):
48
+ start_date = parser.parse(start_date)
49
+
50
+ if start_date is not None:
51
+ object.__setattr__(
52
+ self,
53
+ 'start_date',
54
+ start_date.replace(tzinfo=timezone.utc)
55
+ )
56
+
57
+ # Parse the end_date if it is a string and
58
+ # make sure its set to timezone utc
59
+ if end_date is None:
60
+
61
+ if isinstance(self.end_date, str):
62
+ end_date = parser.parse(end_date)
63
+
64
+ if end_date is not None:
65
+ object.__setattr__(
66
+ self,
67
+ 'end_date',
68
+ end_date.replace(tzinfo=timezone.utc)
69
+ )
70
+
71
+ if self.market is not None:
72
+ object.__setattr__(self, 'market', self.market.upper())
73
+
74
+ if self.symbol is not None:
75
+ object.__setattr__(self, 'symbol', self.symbol.upper())
76
+
77
+ def get_identifier(self):
78
+ """
79
+ Returns the identifier or creates a unique identifier for the
80
+ data source based on its attributes.
81
+ """
82
+
83
+ if self.identifier is not None:
84
+ return self.identifier
85
+
86
+ if DataType.OHLCV.equals(self.data_type):
87
+ return (f"{self.data_type.value}_{self.market}_"
88
+ f"{self.symbol}_{self.time_frame.value}")
89
+
90
+ elif DataType.CUSTOM.equals(self.data_type):
91
+ identifier = "CUSTOM"
92
+
93
+ if self.symbol is not None:
94
+ identifier += f"_{self.symbol}"
95
+
96
+ if self.time_frame is not None:
97
+ identifier += f"_{self.time_frame.value}"
98
+
99
+ if self.market is not None:
100
+ identifier += f"_{self.market}"
101
+
102
+ if self.window_size is not None:
103
+ identifier += f"_{self.window_size}"
104
+
105
+ return identifier
106
+
107
+ def to_dict(self):
108
+ """
109
+ Converts the DataSource instance to a dictionary.
110
+ """
111
+ non_null_attributes = {
112
+ key: value for key, value in self.__dict__.items()
113
+ if value is not None
114
+ }
115
+ # Convert DataType and TimeFrame to their string representations
116
+ if self.data_type is not None:
117
+ non_null_attributes['data_type'] = self.data_type.value
118
+ if self.time_frame is not None:
119
+ non_null_attributes['time_frame'] = self.time_frame.value
120
+
121
+ return non_null_attributes
122
+
123
+ def __repr__(self):
124
+ return (
125
+ f"DataSource(identifier={self.identifier}, "
126
+ f"data_provider_identifier={self.data_provider_identifier}, "
127
+ f"data_type={self.data_type}, symbol={self.symbol}, "
128
+ f"window_size={self.window_size}, time_frame={self.time_frame}, "
129
+ f"market={self.market}, storage_path={self.storage_path}, "
130
+ f"pandas={self.pandas}, date={self.date}, "
131
+ f"start_date={self.start_date}, end_date={self.end_date}, "
132
+ f"save={self.save})"
133
+ )
134
+
135
+ def __eq__(self, other):
136
+ """
137
+ Compares two DataSource instances for equality.
138
+
139
+ OHLCV data sources are considered equal if they have:
140
+ - The same data_type (OHLCV), symbol, time_frame, and market.
141
+ - If no market and timeframe is specified, then
142
+ they are considered equal for the same symbol
143
+ and data_type.
144
+ """
145
+ if DataType.OHLCV.equals(self.data_type):
146
+
147
+ if other.time_frame is None and other.window_size is None:
148
+ return (self.data_type == other.data_type and
149
+ self.symbol == other.symbol)
150
+ elif self.time_frame is None and self.window_size is None:
151
+ return (self.data_type == other.data_type and
152
+ self.symbol == other.symbol)
153
+
154
+ return (self.time_frame == other.time_frame and
155
+ self.market == other.market and
156
+ self.symbol == other.symbol and
157
+ self.data_type == other.data_type)
158
+
159
+ elif DataType.CUSTOM.equals(self.data_type):
160
+ return (self.data_type == other.data_type and
161
+ self.symbol == other.symbol and
162
+ self.window_size == other.window_size and
163
+ self.time_frame == other.time_frame and
164
+ self.market == other.market)
165
+
166
+ elif DataType.TICKER.equals(self.data_type):
167
+ return (self.data_type == other.data_type and
168
+ self.symbol == other.symbol and
169
+ self.market == other.market)
170
+
171
+ return False
172
+
173
+ def create_start_date_data(self, index_date: datetime) -> datetime:
174
+
175
+ if self.window_size is None or self.time_frame is None:
176
+ return index_date
177
+
178
+ return index_date - \
179
+ (self.window_size * timedelta(
180
+ minutes=self.time_frame.amount_of_minutes
181
+ ))
182
+
183
+ def get_number_of_required_data_points(
184
+ self, start_date: datetime, end_date: datetime
185
+ ) -> int:
186
+ """
187
+ Returns the number of data points required based on the given
188
+ attributes of the data source. If the required number of data points
189
+ can't be determined, it returns None.
190
+
191
+ E.g., for OHLCV data source, it
192
+ calculates the number of data points needed between the
193
+ start_date and end_date based on the time frame.
194
+
195
+ Args:
196
+ start_date (datetime): The start date for the data points.
197
+ end_date (datetime): The end date for the data points.
198
+
199
+ Returns:
200
+ int: The number of required data points, or None if it can't
201
+ be determined.
202
+ """
203
+
204
+ if self.time_frame is None:
205
+ return None
206
+
207
+ delta = end_date - start_date
208
+ total_minutes = delta.total_seconds() / 60
209
+ data_points = total_minutes / self.time_frame.amount_of_minutes
210
+
211
+ if self.window_size is not None:
212
+ data_points += self.window_size
213
+
214
+ return int(data_points)
@@ -0,0 +1,46 @@
1
+ from enum import Enum
2
+
3
+
4
+ class DataType(Enum):
5
+ OHLCV = "OHLCV"
6
+ TICKER = "TICKER"
7
+ ORDER_BOOK = "ORDER_BOOK"
8
+ CUSTOM = "CUSTOM"
9
+
10
+ @staticmethod
11
+ def from_string(value: str):
12
+
13
+ if isinstance(value, str):
14
+
15
+ for entry in DataType:
16
+
17
+ if value.upper() == entry.value:
18
+ return entry
19
+
20
+ raise ValueError(
21
+ f"Could not convert {value} to DataType"
22
+ )
23
+
24
+ @staticmethod
25
+ def from_value(value):
26
+
27
+ if isinstance(value, str):
28
+ return DataType.from_string(value)
29
+
30
+ if isinstance(value, DataType):
31
+
32
+ for entry in DataType:
33
+
34
+ if value == entry:
35
+ return entry
36
+
37
+ raise ValueError(
38
+ f"Could not convert {value} to TimeFrame"
39
+ )
40
+
41
+ def equals(self, other):
42
+
43
+ if isinstance(other, Enum):
44
+ return self.value == other.value
45
+ else:
46
+ return DataType.from_string(other) == self
@@ -0,0 +1,35 @@
1
+ from enum import Enum
2
+
3
+
4
+ class Event(Enum):
5
+ PORTFOLIO_CREATED = "PORTFOLIO_CREATED"
6
+ ORDER_CREATED = "ORDER_CREATED"
7
+ TRADE_CLOSED = "TRADE_CLOSED"
8
+ STRATEGY_RUN = "STRATEGY_RUN"
9
+
10
+ @staticmethod
11
+ def from_string(value: str):
12
+
13
+ if isinstance(value, str):
14
+ for status in Event:
15
+
16
+ if value.upper() == status.value:
17
+ return status
18
+
19
+ raise ValueError("Could not convert value to Event")
20
+
21
+ @staticmethod
22
+ def from_value(value):
23
+
24
+ if isinstance(value, Event):
25
+ for status in Event:
26
+
27
+ if value == status:
28
+ return status
29
+ elif isinstance(value, str):
30
+ return Event.from_string(value)
31
+
32
+ raise ValueError(f"Could not convert value {value} to Event")
33
+
34
+ def equals(self, other):
35
+ return Event.from_value(other) == self
@@ -0,0 +1,5 @@
1
+ from .market_credential import MarketCredential
2
+
3
+ __all__ = [
4
+ "MarketCredential",
5
+ ]
@@ -0,0 +1,88 @@
1
+ import os
2
+ import logging
3
+
4
+ from investing_algorithm_framework.domain.exceptions import \
5
+ OperationalException
6
+
7
+ logger = logging.getLogger("investing_algorithm_framework")
8
+
9
+
10
+ class MarketCredential:
11
+ """
12
+ Market credential model to store the api key and secret key for a market.
13
+ """
14
+ def __init__(
15
+ self, market: str, api_key: str = None, secret_key: str = None
16
+ ):
17
+ self._api_key = api_key
18
+ self._secret_key = secret_key
19
+ self._market = market
20
+
21
+ def initialize(self):
22
+ """
23
+ Internal helper to initialize the market credential.
24
+ """
25
+ logger.info(f"Initializing market credential for {self.market}")
26
+
27
+ if self.api_key is None:
28
+ logger.info(
29
+ "Reading api key from environment variable"
30
+ f" {self.market.upper()}_API_KEY"
31
+ )
32
+
33
+ # Check if environment variable is set
34
+ environment_variable = f"{self.market.upper()}_API_KEY"
35
+ self._api_key = os.getenv(environment_variable)
36
+
37
+ if self.api_key is None:
38
+ raise OperationalException(
39
+ f"Market credential for market {self.market}"
40
+ " requires an api key, either"
41
+ " as an argument or as an environment variable"
42
+ f" named as {self._market.upper()}_API_KEY"
43
+ )
44
+
45
+ if self.secret_key is None:
46
+ logger.info(
47
+ "Reading secret key from environment variable"
48
+ f" {self.market.upper()}_SECRET_KEY"
49
+ )
50
+
51
+ # Check if environment variable is set
52
+ environment_variable = f"{self.market.upper()}_SECRET_KEY"
53
+ self._secret_key = os.getenv(environment_variable)
54
+
55
+ if self.api_key is not None:
56
+ self._api_key = self.api_key.strip()
57
+
58
+ if self.secret_key is not None:
59
+ self._secret_key = self.secret_key.strip()
60
+
61
+ def get_api_key(self):
62
+ return self.api_key
63
+
64
+ def get_secret_key(self):
65
+ return self.secret_key
66
+
67
+ def get_market(self):
68
+ return self.market
69
+
70
+ @property
71
+ def market(self):
72
+ return self._market
73
+
74
+ @market.setter
75
+ def market(self, market):
76
+ self._market = market
77
+
78
+ @property
79
+ def api_key(self):
80
+ return self._api_key
81
+
82
+ @property
83
+ def secret_key(self):
84
+ return self._secret_key
85
+
86
+ def __repr__(self):
87
+ return f"MarketCredential(" \
88
+ f"{self.market}, {self.api_key}, {self.secret_key}"
@@ -0,0 +1,6 @@
1
+ from .order import Order
2
+ from .order_side import OrderSide
3
+ from .order_status import OrderStatus
4
+ from .order_type import OrderType
5
+
6
+ __all__ = ["OrderType", "OrderStatus", "OrderSide", "Order"]