investing-algorithm-framework 6.9.1__py3-none-any.whl → 7.19.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of investing-algorithm-framework might be problematic. Click here for more details.

Files changed (192) hide show
  1. investing_algorithm_framework/__init__.py +147 -44
  2. investing_algorithm_framework/app/__init__.py +23 -6
  3. investing_algorithm_framework/app/algorithm/algorithm.py +5 -41
  4. investing_algorithm_framework/app/algorithm/algorithm_factory.py +17 -10
  5. investing_algorithm_framework/app/analysis/__init__.py +15 -0
  6. investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
  7. investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
  8. investing_algorithm_framework/app/analysis/permutation.py +116 -0
  9. investing_algorithm_framework/app/analysis/ranking.py +297 -0
  10. investing_algorithm_framework/app/app.py +1322 -707
  11. investing_algorithm_framework/app/context.py +196 -88
  12. investing_algorithm_framework/app/eventloop.py +590 -0
  13. investing_algorithm_framework/app/reporting/__init__.py +16 -5
  14. investing_algorithm_framework/app/reporting/ascii.py +57 -202
  15. investing_algorithm_framework/app/reporting/backtest_report.py +284 -170
  16. investing_algorithm_framework/app/reporting/charts/__init__.py +10 -2
  17. investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
  18. investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
  19. investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +11 -26
  20. investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
  21. investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
  22. investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +1 -1
  23. investing_algorithm_framework/app/reporting/generate.py +100 -114
  24. investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +40 -32
  25. investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +34 -27
  26. investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +23 -19
  27. investing_algorithm_framework/app/reporting/tables/trades_table.py +1 -1
  28. investing_algorithm_framework/app/reporting/tables/utils.py +1 -0
  29. investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +10 -16
  30. investing_algorithm_framework/app/strategy.py +315 -175
  31. investing_algorithm_framework/app/task.py +5 -3
  32. investing_algorithm_framework/cli/cli.py +30 -12
  33. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +131 -34
  34. investing_algorithm_framework/cli/initialize_app.py +20 -1
  35. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +18 -6
  36. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  37. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  38. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -2
  39. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +1 -1
  40. investing_algorithm_framework/create_app.py +3 -5
  41. investing_algorithm_framework/dependency_container.py +25 -39
  42. investing_algorithm_framework/domain/__init__.py +45 -38
  43. investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
  44. investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
  45. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
  46. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
  47. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
  48. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  49. investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
  50. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  51. investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
  52. investing_algorithm_framework/domain/config.py +27 -0
  53. investing_algorithm_framework/domain/constants.py +6 -34
  54. investing_algorithm_framework/domain/data_provider.py +200 -56
  55. investing_algorithm_framework/domain/exceptions.py +34 -1
  56. investing_algorithm_framework/domain/models/__init__.py +10 -19
  57. investing_algorithm_framework/domain/models/base_model.py +0 -6
  58. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  59. investing_algorithm_framework/domain/models/data/data_source.py +214 -0
  60. investing_algorithm_framework/domain/models/{market_data_type.py → data/data_type.py} +7 -7
  61. investing_algorithm_framework/domain/models/market/market_credential.py +6 -0
  62. investing_algorithm_framework/domain/models/order/order.py +34 -13
  63. investing_algorithm_framework/domain/models/order/order_status.py +1 -1
  64. investing_algorithm_framework/domain/models/order/order_type.py +1 -1
  65. investing_algorithm_framework/domain/models/portfolio/portfolio.py +14 -1
  66. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +5 -1
  67. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +51 -11
  68. investing_algorithm_framework/domain/models/position/__init__.py +2 -1
  69. investing_algorithm_framework/domain/models/position/position.py +9 -0
  70. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  71. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  72. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  73. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  74. investing_algorithm_framework/domain/models/snapshot_interval.py +0 -1
  75. investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
  76. investing_algorithm_framework/domain/models/time_frame.py +7 -0
  77. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  78. investing_algorithm_framework/domain/models/time_unit.py +63 -1
  79. investing_algorithm_framework/domain/models/trade/__init__.py +0 -2
  80. investing_algorithm_framework/domain/models/trade/trade.py +56 -32
  81. investing_algorithm_framework/domain/models/trade/trade_status.py +8 -2
  82. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +106 -41
  83. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +161 -99
  84. investing_algorithm_framework/domain/order_executor.py +19 -0
  85. investing_algorithm_framework/domain/portfolio_provider.py +20 -1
  86. investing_algorithm_framework/domain/services/__init__.py +0 -13
  87. investing_algorithm_framework/domain/strategy.py +1 -29
  88. investing_algorithm_framework/domain/utils/__init__.py +5 -1
  89. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  90. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  91. investing_algorithm_framework/domain/utils/polars.py +17 -14
  92. investing_algorithm_framework/download_data.py +40 -10
  93. investing_algorithm_framework/infrastructure/__init__.py +13 -25
  94. investing_algorithm_framework/infrastructure/data_providers/__init__.py +7 -4
  95. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +811 -546
  96. investing_algorithm_framework/infrastructure/data_providers/csv.py +433 -122
  97. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  98. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  99. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +81 -0
  100. investing_algorithm_framework/infrastructure/models/__init__.py +0 -13
  101. investing_algorithm_framework/infrastructure/models/order/order.py +9 -3
  102. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +27 -8
  103. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +21 -7
  104. investing_algorithm_framework/infrastructure/order_executors/__init__.py +2 -0
  105. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  106. investing_algorithm_framework/infrastructure/repositories/repository.py +16 -2
  107. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +2 -2
  108. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +6 -0
  109. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +6 -0
  110. investing_algorithm_framework/infrastructure/services/__init__.py +0 -4
  111. investing_algorithm_framework/services/__init__.py +105 -8
  112. investing_algorithm_framework/services/backtesting/backtest_service.py +536 -476
  113. investing_algorithm_framework/services/configuration_service.py +14 -4
  114. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  115. investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
  116. investing_algorithm_framework/{app/reporting → services}/metrics/__init__.py +48 -17
  117. investing_algorithm_framework/{app/reporting → services}/metrics/drawdown.py +10 -10
  118. investing_algorithm_framework/{app/reporting → services}/metrics/equity_curve.py +2 -2
  119. investing_algorithm_framework/{app/reporting → services}/metrics/exposure.py +60 -2
  120. investing_algorithm_framework/services/metrics/generate.py +358 -0
  121. investing_algorithm_framework/{app/reporting → services}/metrics/profit_factor.py +36 -0
  122. investing_algorithm_framework/{app/reporting → services}/metrics/recovery.py +2 -2
  123. investing_algorithm_framework/{app/reporting → services}/metrics/returns.py +146 -147
  124. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  125. investing_algorithm_framework/{app/reporting/metrics/sharp_ratio.py → services/metrics/sharpe_ratio.py} +6 -10
  126. investing_algorithm_framework/{app/reporting → services}/metrics/sortino_ratio.py +3 -7
  127. investing_algorithm_framework/services/metrics/trades.py +500 -0
  128. investing_algorithm_framework/services/metrics/volatility.py +97 -0
  129. investing_algorithm_framework/{app/reporting → services}/metrics/win_rate.py +70 -3
  130. investing_algorithm_framework/services/order_service/order_backtest_service.py +21 -31
  131. investing_algorithm_framework/services/order_service/order_service.py +9 -71
  132. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -2
  133. investing_algorithm_framework/services/portfolios/portfolio_service.py +3 -13
  134. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +62 -96
  135. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -3
  136. investing_algorithm_framework/services/repository_service.py +5 -2
  137. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  138. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
  139. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  140. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  141. investing_algorithm_framework/services/trade_service/__init__.py +7 -1
  142. investing_algorithm_framework/services/trade_service/trade_service.py +51 -29
  143. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  144. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  145. investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
  146. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/RECORD +159 -148
  147. investing_algorithm_framework/app/reporting/evaluation.py +0 -243
  148. investing_algorithm_framework/app/reporting/metrics/risk_free_rate.py +0 -8
  149. investing_algorithm_framework/app/reporting/metrics/volatility.py +0 -69
  150. investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -3
  151. investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -9
  152. investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -47
  153. investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
  154. investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
  155. investing_algorithm_framework/domain/models/backtesting/backtest_results.py +0 -440
  156. investing_algorithm_framework/domain/models/data_source.py +0 -21
  157. investing_algorithm_framework/domain/models/date_range.py +0 -64
  158. investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -34
  159. investing_algorithm_framework/domain/models/trading_data_types.py +0 -48
  160. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
  161. investing_algorithm_framework/domain/services/market_data_sources.py +0 -543
  162. investing_algorithm_framework/domain/services/market_service.py +0 -153
  163. investing_algorithm_framework/domain/services/observable.py +0 -51
  164. investing_algorithm_framework/domain/services/observer.py +0 -19
  165. investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -16
  166. investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -746
  167. investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -270
  168. investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -312
  169. investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
  170. investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -471
  171. investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
  172. investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
  173. investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -322
  174. investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -10
  175. investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -269
  176. investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -350
  177. investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -377
  178. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -296
  179. investing_algorithm_framework-6.9.1.dist-info/METADATA +0 -440
  180. /investing_algorithm_framework/{app/reporting → services}/metrics/alpha.py +0 -0
  181. /investing_algorithm_framework/{app/reporting → services}/metrics/beta.py +0 -0
  182. /investing_algorithm_framework/{app/reporting → services}/metrics/cagr.py +0 -0
  183. /investing_algorithm_framework/{app/reporting → services}/metrics/calmar_ratio.py +0 -0
  184. /investing_algorithm_framework/{app/reporting → services}/metrics/mean_daily_return.py +0 -0
  185. /investing_algorithm_framework/{app/reporting → services}/metrics/price_efficiency.py +0 -0
  186. /investing_algorithm_framework/{app/reporting → services}/metrics/standard_deviation.py +0 -0
  187. /investing_algorithm_framework/{app/reporting → services}/metrics/treynor_ratio.py +0 -0
  188. /investing_algorithm_framework/{app/reporting → services}/metrics/ulcer.py +0 -0
  189. /investing_algorithm_framework/{app/reporting → services}/metrics/value_at_risk.py +0 -0
  190. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
  191. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
  192. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/entry_points.txt +0 -0
@@ -1,543 +0,0 @@
1
- import csv
2
- import logging
3
- import os
4
- from abc import abstractmethod, ABC
5
- from datetime import datetime, timedelta
6
-
7
- import polars
8
-
9
- from investing_algorithm_framework.domain import TimeFrame, \
10
- OperationalException
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
-
15
- class BacktestMarketDataSource(ABC):
16
- column_names = []
17
-
18
- def __init__(
19
- self,
20
- identifier,
21
- market,
22
- symbol,
23
- backtest_data_start_date=None,
24
- backtest_data_index_date=None,
25
- ):
26
- self._identifier = identifier
27
- self._market = market
28
- self._symbol = symbol
29
- self._backtest_data_start_date = backtest_data_start_date
30
- self._backtest_data_index_date = backtest_data_index_date
31
-
32
- @property
33
- def config(self):
34
- return self._config
35
-
36
- @config.setter
37
- def config(self, value):
38
- self._config = value
39
-
40
- def _data_source_exists(self, file_path):
41
- """
42
- Function to check if the data source exists.
43
- This function will check if the file exists and if the column names
44
- are correct.
45
-
46
- This function will return True if the file exists and the column names
47
- are correct. If the file does not exist or the column names are not
48
- correct, this function will return False.
49
-
50
- This function prevents the backtest datasource to download the data
51
- every time the backtest is run.
52
-
53
- Args:
54
- file_path: str - the file path of the data storage file
55
-
56
- Returns:
57
- bool - True if the file exists and the column names are correct,
58
- """
59
-
60
- try:
61
- if os.path.isfile(file_path):
62
- df = polars.read_csv(file_path)
63
-
64
- if df.columns != self.column_names:
65
- raise OperationalException(
66
- f"Wrong column names on {file_path}, required "
67
- f"column names are {self.column_names}"
68
- )
69
- else:
70
- return False
71
-
72
- return True
73
- except Exception:
74
- return False
75
-
76
- def write_data_to_file_path(self, data_file, data):
77
- """
78
- Function to write data to a csv file.
79
- This function will write the column names and all the data to the
80
- file.
81
- """
82
- with open(data_file, "w") as file:
83
- column_headers = self.column_names
84
- writer = csv.writer(file)
85
- writer.writerow(column_headers)
86
- rows = data
87
- writer.writerows(rows)
88
-
89
- @abstractmethod
90
- def prepare_data(
91
- self,
92
- config,
93
- backtest_start_date,
94
- backtest_end_date,
95
- ):
96
- """
97
- Function to prepare the data for the backtest.
98
- This function needs to be implemented by the child class.
99
-
100
- Args:
101
- config: dict - the configuration of the application
102
- backtest_start_date: datetime - the start date of the backtest
103
- backtest_end_date: datetime - the end date of the backtest
104
-
105
- Returns:
106
- None
107
- """
108
- pass
109
-
110
- @abstractmethod
111
- def get_data(self, date, config):
112
- """
113
- Function to get the data for the backtest. This function needs to be
114
- implemented by the child class.
115
-
116
- Args:
117
- date: datetime - the date for which the data is required
118
- config: dict - the configuration of the application
119
- """
120
- pass
121
-
122
- @property
123
- def identifier(self):
124
- return self._identifier
125
-
126
- def get_identifier(self):
127
- return self.identifier
128
-
129
- @property
130
- def market(self):
131
- return self._market
132
-
133
- def get_market(self):
134
- return self.market
135
-
136
- @property
137
- def symbol(self):
138
- return self._symbol
139
-
140
- def get_symbol(self):
141
- return self.symbol
142
-
143
- @abstractmethod
144
- def empty(self):
145
- pass
146
-
147
- @property
148
- def market_credential_service(self):
149
- return self._market_credential_service
150
-
151
- @market_credential_service.setter
152
- def market_credential_service(self, value):
153
- self._market_credential_service = value
154
-
155
- @property
156
- def backtest_data_start_date(self):
157
- return self._backtest_data_start_date
158
-
159
- @backtest_data_start_date.setter
160
- def backtest_data_start_date(self, value):
161
- self._backtest_data_start_date = value
162
-
163
- @property
164
- def backtest_data_index_date(self):
165
- return self._backtest_data_index_date
166
-
167
- @backtest_data_index_date.setter
168
- def backtest_data_index_date(self, value):
169
- self._backtest_data_index_date = value
170
-
171
-
172
- class MarketDataSource(ABC):
173
-
174
- def __init__(
175
- self,
176
- market,
177
- symbol,
178
- identifier=None,
179
- storage_path=None
180
- ):
181
- self._identifier = identifier
182
- self._market = market
183
- self._symbol = symbol
184
- self._market_credential_service = None
185
- self._config = None
186
- self._storage_path = storage_path
187
-
188
- if self._identifier is None:
189
- self._identifier = f"{self.market}_{self.symbol}"
190
-
191
- @property
192
- def config(self):
193
- return self._config
194
-
195
- @config.setter
196
- def config(self, value):
197
- self._config = value
198
-
199
- def initialize(self, config):
200
- pass
201
-
202
- @property
203
- def identifier(self):
204
- return self._identifier
205
-
206
- @identifier.setter
207
- def identifier(self, value):
208
- self._identifier = value
209
-
210
- def get_identifier(self):
211
- return self.identifier
212
-
213
- @property
214
- def market(self):
215
- return self._market
216
-
217
- def get_market(self):
218
- return self.market
219
-
220
- @property
221
- def symbol(self):
222
- return self._symbol
223
-
224
- def get_symbol(self):
225
- return self.symbol
226
-
227
- @property
228
- def storage_path(self):
229
- return self._storage_path
230
-
231
- def get_storage_path(self):
232
- return self.storage_path
233
-
234
- @abstractmethod
235
- def get_data(
236
- self,
237
- start_date: datetime = None,
238
- end_date: datetime = None,
239
- config=None,
240
- ):
241
- """
242
- Get data from the market data source.
243
-
244
- Args:
245
- config (dict): the configuration of the application
246
- start_date (optional) (datetime): the start date of the data
247
- end_date (optional) (datetime): the end date of the data
248
-
249
- Returns:
250
- DataFrame: the data from the market data source
251
- """
252
- pass
253
-
254
- @abstractmethod
255
- def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
256
- pass
257
-
258
- @property
259
- def market_credential_service(self):
260
- return self._market_credential_service
261
-
262
- @market_credential_service.setter
263
- def market_credential_service(self, value):
264
- self._market_credential_service = value
265
-
266
- @staticmethod
267
- def get_file_name_symbol(file_path):
268
- """
269
- Static function that extracts the symbol from a give data filepath,
270
- given that the data file path is in the format
271
- {DATA_TYPE}_{TARGET_SYMBOL}_{TRADING_SYMBOL}_{MARKET}_
272
- {time_frame}_{START_DATETIME}_{END_DATETIME}.csv
273
-
274
- Parameters:
275
- file_path: str - the given file path of
276
- the data storage file
277
-
278
- Returns:
279
- string representing the symbol
280
- """
281
- parts = file_path.split("_")
282
-
283
- if len(parts) < 6:
284
- return None
285
-
286
- return "".join([parts[1], '/', parts[2]])
287
-
288
- @staticmethod
289
- def get_file_name_time_frame(file_path):
290
- """
291
- Static function that extracts the time_frame from a give data filepath,
292
- given that the data file path is in the format
293
- {DATA_TYPE}_{TARGET_SYMBOL}_{TRADING_SYMBOL}_{MARKET}_
294
- {time_frame}_{START_DATETIME}_{END_DATETIME}.csv
295
-
296
- Parameters:
297
- file_path: str - the given file path of the data storage file
298
-
299
- Returns:
300
- string representing the time_frame
301
- """
302
- parts = file_path.split("_")
303
-
304
- if len(parts) < 6:
305
- return None
306
-
307
- return TimeFrame.from_string(parts[4])
308
-
309
- @staticmethod
310
- def get_file_name_market(file_path):
311
- """
312
- Static function that extracts the time_frame from a give data filepath,
313
- given that the data file path is in the format
314
- {DATA_TYPE}_{TARGET_SYMBOL}_{TRADING_SYMBOL}_{MARKET}
315
- _{time_frame}_{START_DATETIME}_{END_DATETIME}.csv
316
-
317
- Parameters:
318
- file_path: str - the given file path of the data storage file
319
-
320
- Returns:
321
- string representing the market
322
- """
323
- parts = file_path.split("_")
324
-
325
- if len(parts) < 6:
326
- return None
327
-
328
- return TimeFrame.from_string(parts[3])
329
-
330
- @staticmethod
331
- def get_file_name_start_datetime(file_path):
332
- """
333
- Static function that extracts the time_frame from a give data filepath,
334
- given that the data file path is in the format
335
- {DATA_TYPE}_{TARGET_SYMBOL}_{TRADING_SYMBOL}_{MARKET}_
336
- {time_frame}_{START_DATETIME}_{END_DATETIME}.csv
337
-
338
- Parameters:
339
- file_path: str - the given file path of the data storage file
340
-
341
- Returns:
342
- string representing the start datetime
343
- """
344
- parts = file_path.split("_")
345
-
346
- if len(parts) < 6:
347
- return None
348
-
349
- return TimeFrame.from_string(parts[5])
350
-
351
- @staticmethod
352
- def get_file_name_end_datetime(file_path):
353
- """
354
- Static function that extracts the time_frame
355
- from a give data filepath, given that the data file
356
- path is in the format
357
- {DATA_TYPE}_{TARGET_SYMBOL}_{TRADING_SYMBOL}_{MARKET}_
358
- {time_frame}_{START_DATETIME}_{END_DATETIME}.csv
359
-
360
- Parameters:
361
- file_path: str - the given file path of the data storage file
362
-
363
- Returns:
364
- string representing the end datetime
365
- """
366
- parts = file_path.split("_")
367
-
368
- if len(parts) < 6:
369
- return None
370
-
371
- return TimeFrame.from_string(parts[6])
372
-
373
- @staticmethod
374
- def create_storage_file_path(
375
- storage_path,
376
- data_type,
377
- symbol,
378
- market,
379
- time_frame,
380
- start_datetime,
381
- end_datetime,
382
- ):
383
- """
384
- Static function that creates a storage file path given the parameters
385
-
386
- Parameters:
387
- storage_path: str - the storage path of the data storage file
388
- data_type: str - the type of data
389
- symbol: str - the asset symbol
390
- market: str - the market
391
- time_frame: str - the time_frame
392
- start_datetime: datetime - the start datetime
393
- end_datetime: datetime - the end datetime
394
-
395
- Returns:
396
- string representing the storage file path
397
- """
398
-
399
- target_symbol, trading_symbol = symbol.split('/')
400
- path = os.path.join(
401
- storage_path,
402
- f"{data_type}_{target_symbol}_{trading_symbol}_{market}_" +
403
- f"{time_frame}_{start_datetime}_{end_datetime}.csv"
404
- )
405
- return path
406
-
407
-
408
- class OHLCVMarketDataSource(MarketDataSource, ABC):
409
- """
410
- Abstract class for ohlcv market data sources.
411
- """
412
- def __init__(
413
- self,
414
- market,
415
- symbol,
416
- time_frame,
417
- identifier=None,
418
- window_size=None,
419
- storage_path=None,
420
- ):
421
- super().__init__(
422
- identifier=identifier,
423
- market=market,
424
- symbol=symbol,
425
- storage_path=storage_path
426
- )
427
- self._window_size = window_size
428
- self._time_frame = time_frame
429
-
430
- @property
431
- def time_frame(self):
432
- return self._time_frame
433
-
434
- def get_time_frame(self):
435
- return self.time_frame
436
-
437
- def create_start_date(self, end_date, time_frame, window_size):
438
- minutes = TimeFrame.from_value(time_frame).amount_of_minutes
439
- return end_date - timedelta(minutes=window_size * minutes)
440
-
441
- def create_end_date(self, start_date, time_frame, window_size):
442
- minutes = TimeFrame.from_value(time_frame).amount_of_minutes
443
- return start_date + timedelta(minutes=window_size * minutes)
444
-
445
- @property
446
- def window_size(self):
447
- return self._window_size
448
-
449
- @window_size.setter
450
- def window_size(self, value):
451
-
452
- if not isinstance(value, int):
453
- raise OperationalException(
454
- "Window size must be an integer"
455
- )
456
-
457
- self._window_size = value
458
-
459
- def get_date_ranges(
460
- self,
461
- start_date: datetime,
462
- end_date: datetime,
463
- window_size: int,
464
- time_frame
465
- ):
466
- """
467
- Function to get the date ranges of the market data source based
468
- on the window size and the time_frame. The date ranges
469
- will be calculated based on the start date and the end date.
470
-
471
- Args:
472
- start_date: datetime - The start date
473
- end_date: datetime - The end date
474
- window_size: int - The window size
475
- time_frame: str - The time frame
476
-
477
- Returns:
478
- list - A list of tuples with the date ranges
479
- """
480
-
481
- if start_date > end_date:
482
- raise OperationalException(
483
- "Start date must be before end date"
484
- )
485
-
486
- time_frame = TimeFrame.from_value(time_frame)
487
- new_end_date = start_date + timedelta(
488
- minutes=window_size * time_frame.amount_of_minutes
489
- )
490
- ranges = [(start_date, new_end_date)]
491
- start_date = new_end_date
492
-
493
- if new_end_date > end_date:
494
- return [(start_date, end_date)]
495
-
496
- while start_date < end_date:
497
- new_end_date = start_date + timedelta(
498
- minutes=self.window_size * time_frame.amount_of_minutes
499
- )
500
-
501
- if new_end_date > end_date:
502
- new_end_date = end_date
503
-
504
- ranges.append((start_date, new_end_date))
505
- start_date = new_end_date
506
-
507
- return ranges
508
-
509
-
510
- class TickerMarketDataSource(MarketDataSource, ABC):
511
- """
512
- Abstract class for ticker market data sources.
513
- """
514
-
515
- def __init__(
516
- self,
517
- identifier,
518
- market=None,
519
- symbol=None,
520
- ):
521
- super().__init__(
522
- identifier=identifier,
523
- market=market,
524
- symbol=symbol,
525
- )
526
-
527
-
528
- class OrderBookMarketDataSource(MarketDataSource, ABC):
529
- """
530
- Abstract class for order book market data sources.
531
- """
532
-
533
- def __init__(
534
- self,
535
- identifier,
536
- market,
537
- symbol,
538
- ):
539
- super().__init__(
540
- identifier=identifier,
541
- market=market,
542
- symbol=symbol,
543
- )
@@ -1,153 +0,0 @@
1
- import logging
2
- from abc import ABC, abstractmethod
3
- from datetime import datetime
4
- from typing import Dict
5
-
6
- from polars import DataFrame
7
-
8
- logger = logging.getLogger("investing_algorithm_framework")
9
-
10
-
11
- class MarketService(ABC):
12
-
13
- def __init__(self, market_credential_service):
14
- self._market_credential_service = market_credential_service
15
- self._config = None
16
-
17
- @property
18
- def config(self):
19
- return self._config
20
-
21
- @config.setter
22
- def config(self, value):
23
- self._config = value
24
-
25
- @abstractmethod
26
- def pair_exists(
27
- self,
28
- market,
29
- target_symbol: str,
30
- trading_symbol: str,
31
- ):
32
- raise NotImplementedError()
33
-
34
- @abstractmethod
35
- def get_ticker(self, symbol, market):
36
- raise NotImplementedError()
37
-
38
- @abstractmethod
39
- def get_tickers(self, symbols, market):
40
- raise NotImplementedError()
41
-
42
- @abstractmethod
43
- def get_order_book(self, symbol, market):
44
- raise NotImplementedError()
45
-
46
- @abstractmethod
47
- def get_order_books(self, symbols, market):
48
- raise NotImplementedError()
49
-
50
- @abstractmethod
51
- def get_order(self, order, market):
52
- raise NotImplementedError()
53
-
54
- @abstractmethod
55
- def get_orders(self, symbol, market, since: datetime = None):
56
- raise NotImplementedError()
57
-
58
- @abstractmethod
59
- def get_balance(self, market) -> Dict[str, float]:
60
- raise NotImplementedError()
61
-
62
- @abstractmethod
63
- def create_limit_buy_order(
64
- self,
65
- target_symbol: str,
66
- trading_symbol: str,
67
- amount: float,
68
- price: float,
69
- market
70
- ):
71
- raise NotImplementedError()
72
-
73
- @abstractmethod
74
- def create_limit_sell_order(
75
- self,
76
- target_symbol: str,
77
- trading_symbol: str,
78
- amount: float,
79
- price: float,
80
- market
81
- ):
82
- raise NotImplementedError()
83
-
84
- @abstractmethod
85
- def create_market_sell_order(
86
- self,
87
- target_symbol: str,
88
- trading_symbol: str,
89
- amount: float,
90
- market
91
- ):
92
- raise NotImplementedError()
93
-
94
- @abstractmethod
95
- def cancel_order(self, order, market):
96
- raise NotImplementedError()
97
-
98
- @abstractmethod
99
- def get_open_orders(
100
- self, market, target_symbol: str = None, trading_symbol: str = None
101
- ):
102
- raise NotImplementedError()
103
-
104
- @abstractmethod
105
- def get_closed_orders(
106
- self, market, target_symbol: str = None, trading_symbol: str = None
107
- ):
108
- raise NotImplementedError()
109
-
110
- @abstractmethod
111
- def get_ohlcv(
112
- self, symbol, time_frame, from_timestamp, market, to_timestamp=None
113
- ) -> DataFrame:
114
- raise NotImplementedError()
115
-
116
- @abstractmethod
117
- def get_ohlcvs(
118
- self, symbols, time_frame, from_timestamp, market, to_timestamp=None
119
- ) -> Dict[str, DataFrame]:
120
- raise NotImplementedError()
121
-
122
- @property
123
- def market_credentials(self):
124
-
125
- if self._market_credential_service is None:
126
- return []
127
-
128
- return self._market_credential_service.get_all()
129
-
130
- def get_market_credentials(self):
131
- return self._market_credential_service.get_all()
132
-
133
- def get_market_credential(self, market):
134
-
135
- if self.market_credentials is None:
136
- return None
137
-
138
- if market is None:
139
- return None
140
-
141
- for market_data_credentials in self.market_credentials:
142
-
143
- if market_data_credentials.market.upper() == market.upper():
144
- return market_data_credentials
145
-
146
- return None
147
-
148
- @abstractmethod
149
- def get_symbols(self, market):
150
- """
151
- Get all available symbols for a market
152
- """
153
- raise NotImplementedError()