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,270 +0,0 @@
1
- import logging
2
- from datetime import datetime
3
-
4
- import polars
5
- from dateutil.parser import parse
6
-
7
- from investing_algorithm_framework.domain import OHLCVMarketDataSource, \
8
- BacktestMarketDataSource, OperationalException, TickerMarketDataSource, \
9
- DATETIME_FORMAT
10
-
11
- logger = logging.getLogger(__name__)
12
-
13
-
14
- class CSVOHLCVMarketDataSource(OHLCVMarketDataSource):
15
- """
16
- Implementation of a OHLCV data source that reads OHLCV data
17
- from a csv file. Market data source that reads OHLCV data from a csv file.
18
- """
19
-
20
- def empty(self, end_date):
21
- data = self.get_data(end_date=end_date, config={})
22
- return len(data) == 0
23
-
24
- def __init__(
25
- self,
26
- csv_file_path,
27
- market=None,
28
- symbol=None,
29
- identifier=None,
30
- window_size=None,
31
- ):
32
- super().__init__(
33
- identifier=identifier,
34
- market=market,
35
- symbol=symbol,
36
- time_frame=None,
37
- window_size=window_size,
38
- )
39
- self._csv_file_path = csv_file_path
40
- self._columns = [
41
- "Datetime", "Open", "High", "Low", "Close", "Volume"
42
- ]
43
-
44
- df = polars.read_csv(self._csv_file_path)
45
-
46
- # Check if all column names are in the csv file
47
- if not all(column in df.columns for column in self._columns):
48
- # Identify missing columns
49
- missing_columns = [column for column in self._columns if
50
- column not in df.columns]
51
- raise OperationalException(
52
- f"Csv file {self._csv_file_path} does not contain "
53
- f"all required ohlcv columns. "
54
- f"Missing columns: {missing_columns}"
55
- )
56
-
57
- self.data = self._load_data(self.csv_file_path)
58
- first_row = self.data.head(1)
59
- last_row = self.data.tail(1)
60
- self._start_date_data_source = first_row["Datetime"][0]
61
- self._end_date_data_source = last_row["Datetime"][0]
62
-
63
- @property
64
- def csv_file_path(self):
65
- return self._csv_file_path
66
-
67
- def _load_data(self, file_path):
68
- return polars.read_csv(
69
- file_path,
70
- schema_overrides={"Datetime": polars.Datetime},
71
- low_memory=True
72
- ).with_columns(
73
- polars.col("Datetime").cast(
74
- polars.Datetime(time_unit="ms", time_zone="UTC")
75
- )
76
- )
77
-
78
- def get_data(
79
- self,
80
- start_date: datetime = None,
81
- end_date: datetime = None,
82
- config=None,
83
- ):
84
- """
85
- Get the data from the csv file. The data can be filtered by
86
- the start_date and end_date in the kwargs. backtest_index_date
87
- can also be provided to filter the data, where this will be used
88
- as start_date.
89
-
90
- Args:
91
- **kwargs: Keyword arguments that can contain the following:
92
- start_date (datetime): The start date to filter the data.
93
- end_date (datetime): The end date to filter the data.
94
- backtest_index_date (datetime): The backtest index date to
95
- filter the data. This will be used as start_date.
96
-
97
- Returns:
98
- df (polars.DataFrame): The data from the csv file.
99
- """
100
-
101
- if start_date is None and end_date is None:
102
- return self.data
103
-
104
- if end_date is not None and start_date is not None:
105
-
106
- if end_date < start_date:
107
- raise OperationalException(
108
- f"End date {end_date} is before the start date "
109
- f"{start_date}"
110
- )
111
-
112
- if start_date > self._end_date_data_source:
113
- return polars.DataFrame()
114
-
115
- df = self.data
116
- df = df.filter(
117
- (df['Datetime'] >= start_date)
118
- & (df['Datetime'] <= end_date)
119
- )
120
- return df
121
-
122
- if start_date is not None:
123
-
124
- if start_date < self._start_date_data_source:
125
- return polars.DataFrame()
126
-
127
- if start_date > self._end_date_data_source:
128
- return polars.DataFrame()
129
-
130
- df = self.data
131
- df = df.filter(
132
- (df['Datetime'] >= start_date)
133
- )
134
- df = df.head(self.window_size)
135
- return df
136
-
137
- if end_date is not None:
138
-
139
- if end_date < self._start_date_data_source:
140
- return polars.DataFrame()
141
-
142
- if end_date > self._end_date_data_source:
143
- return polars.DataFrame()
144
-
145
- df = self.data
146
- df = df.filter(
147
- (df['Datetime'] <= end_date)
148
- )
149
- df = df.tail(self.window_size)
150
- return df
151
-
152
- return polars.read_csv(
153
- self.csv_file_path, columns=self._columns, separator=","
154
- )
155
-
156
- def dataframe_to_list_of_lists(self, dataframe, columns):
157
- # Extract selected columns from DataFrame and convert
158
- # to a list of lists
159
- data_list_of_lists = dataframe[columns].values.tolist()
160
- return data_list_of_lists
161
-
162
- def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
163
- pass
164
-
165
-
166
- class CSVTickerMarketDataSource(TickerMarketDataSource):
167
-
168
- def __init__(
169
- self,
170
- identifier,
171
- market,
172
- symbol,
173
- csv_file_path,
174
- ):
175
- super().__init__(
176
- identifier=identifier,
177
- market=market,
178
- symbol=symbol,
179
- )
180
- self._csv_file_path = csv_file_path
181
- self._columns = [
182
- "Datetime", "Open", "High", "Low", "Close", "Volume"
183
- ]
184
- df = polars.read_csv(self._csv_file_path)
185
-
186
- if not all(column in df.columns for column in self._columns):
187
- # Identify missing columns
188
- missing_columns = [column for column in self._columns if
189
- column not in df.columns]
190
- raise OperationalException(
191
- f"Csv file {self._csv_file_path} does not contain "
192
- f"all required ohlcv columns. "
193
- f"Missing columns: {missing_columns}"
194
- )
195
-
196
- first_row = df.head(1)
197
- last_row = df.tail(1)
198
- self._start_date_data_source = parse(first_row["Datetime"][0])
199
- self._end_date_data_source = parse(last_row["Datetime"][0])
200
-
201
- @property
202
- def csv_file_path(self):
203
- return self._csv_file_path
204
-
205
- def get_data(
206
- self,
207
- start_date: datetime = None,
208
- end_date: datetime = None,
209
- config=None,
210
- ):
211
-
212
- if end_date is None:
213
- raise OperationalException("Date is required to get ticker data")
214
-
215
- date = end_date
216
-
217
- if not isinstance(date, datetime):
218
-
219
- if isinstance(date, str):
220
- date = parse(date)
221
- else:
222
- raise OperationalException(
223
- "Date value should be either a string or datetime object"
224
- )
225
-
226
- if date < self._start_date_data_source:
227
- raise OperationalException(
228
- f"Date {date} is before the start date "
229
- f"of the data source {self._start_date_data_source}"
230
- )
231
-
232
- if date > self._end_date_data_source:
233
- raise OperationalException(
234
- f"Date {date} is after the end date "
235
- f"of the data source {self._end_date_data_source}"
236
- )
237
-
238
- # Filter the data based on the backtest index date and the end date
239
- df = polars.read_csv(self._csv_file_path)
240
- df = df.filter(
241
- (df['Datetime'] >= date.strftime(DATETIME_FORMAT))
242
- )
243
-
244
- # Check if the dataframe is empty
245
- if df.shape[0] == 0:
246
- raise OperationalException(
247
- f"No ticker data found for {self.symbol} "
248
- f"at {date.strftime(DATETIME_FORMAT)}"
249
- )
250
-
251
- first_row = df.head(1)[0]
252
-
253
- # Calculate the bid and ask price based on the high and low price
254
- return {
255
- "symbol": self.symbol,
256
- "bid": float((first_row["Low"][0])
257
- + float(first_row["High"][0])) / 2,
258
- "ask": float((first_row["Low"][0])
259
- + float(first_row["High"][0])) / 2,
260
- "datetime": first_row["Datetime"][0],
261
- }
262
-
263
- def dataframe_to_list_of_lists(self, dataframe, columns):
264
- # Extract selected columns from DataFrame and convert
265
- # to a list of lists
266
- data_list_of_lists = dataframe[columns].values.tolist()
267
- return data_list_of_lists
268
-
269
- def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
270
- pass
@@ -1,312 +0,0 @@
1
- from datetime import datetime, timedelta, timezone
2
-
3
- from dateutil import parser
4
- from pandas import DataFrame
5
- import polars as pl
6
-
7
- from investing_algorithm_framework.domain import OHLCVMarketDataSource, \
8
- BacktestMarketDataSource, OperationalException, TimeFrame, sync_timezones
9
-
10
-
11
- class PandasOHLCVBacktestMarketDataSource(
12
- OHLCVMarketDataSource, BacktestMarketDataSource
13
- ):
14
- """
15
- PandasOHLCVBacktestMarketDataSource implementation
16
- of a OHLCVMarketDataSource. This implementation uses a pandas
17
- dataframe to provide data to the strategy.
18
- """
19
- backtest_data_directory = None
20
- backtest_data_end_date = None
21
- total_minutes_time_frame = None
22
- column_names = ["Datetime", "Open", "High", "Low", "Close", "Volume"]
23
-
24
- def __init__(
25
- self,
26
- identifier,
27
- market,
28
- symbol,
29
- time_frame,
30
- dataframe=None,
31
- window_size=None,
32
- ):
33
- super().__init__(
34
- identifier=identifier,
35
- market=market,
36
- symbol=symbol,
37
- time_frame=time_frame,
38
- window_size=window_size,
39
- )
40
- self.dataframe = dataframe
41
- self._start_date_data_source = None
42
- self._end_date_data_source = None
43
- self.backtest_end_index = self.window_size
44
- self.backtest_start_index = 0
45
- self.window_cache = {}
46
-
47
- def prepare_data(
48
- self,
49
- config,
50
- backtest_start_date,
51
- backtest_end_date,
52
- ):
53
- """
54
- Prepare data implementation of ccxt based ohlcv backtest market
55
- data source
56
-
57
- This implementation will check if the data source already exists before
58
- pulling all the data. This optimization will prevent downloading
59
- of unnecessary resources.
60
-
61
- When downloading the data it will use the ccxt library.
62
-
63
- Args:
64
- config (dict): the configuration of the data source
65
- backtest_start_date (datetime): the start date of the backtest
66
- backtest_end_date (datetime): the end date of the backtest
67
- time_frame (string): the time frame of the data
68
- window_size (int): the total amount of candle sticks that need to
69
- be returned
70
-
71
- Returns:
72
- None
73
- """
74
-
75
- if config is None:
76
- config = self.config
77
-
78
- # Calculating the backtest data start date
79
- backtest_data_start_date = \
80
- backtest_start_date - timedelta(
81
- minutes=(
82
- (self.window_size + 1) *
83
- TimeFrame.from_value(self.time_frame).amount_of_minutes
84
- )
85
- )
86
-
87
- self.backtest_data_start_date = backtest_data_start_date \
88
- .replace(microsecond=0)
89
- self.backtest_data_end_date = backtest_end_date.replace(microsecond=0)
90
-
91
- if not isinstance(self.dataframe, DataFrame):
92
- raise OperationalException(
93
- "Provided dataframe is not a pandas dataframe"
94
- )
95
-
96
- if not set(self.column_names).issubset(self.dataframe.columns):
97
- raise OperationalException(
98
- "Provided dataframe does not have all required columns. "
99
- "Your pandas dataframe should have the following columns: "
100
- "Datetime, Open, High, Low, Close, Volume"
101
- )
102
-
103
- # Get first and last row and check if backtest start and end dates
104
- # are within the dataframe
105
- first_row = self.dataframe.head(1)
106
- last_row = self.dataframe.tail(1)
107
-
108
- if backtest_end_date > last_row["Datetime"].iloc[0]:
109
- raise OperationalException(
110
- f"Backtest end date {backtest_end_date} is "
111
- f"after the end date of the data source "
112
- f"{last_row['Datetime'].iloc[0]}"
113
- )
114
-
115
- if backtest_data_start_date < first_row["Datetime"].iloc[0]:
116
- raise OperationalException(
117
- f"Backtest start date {backtest_data_start_date} is "
118
- f"before the start date of the data source "
119
- f"{first_row['Datetime'][0]}"
120
- )
121
-
122
- self._precompute_sliding_windows() # Precompute sliding windows!
123
-
124
- def _precompute_sliding_windows(self):
125
- """
126
- Precompute all sliding windows for fast retrieval.
127
-
128
- A sliding window is calculated as a subset of the data. It will
129
- take for each timestamp in the data a window of size `window_size`
130
- and stores it in a cache with the last timestamp of the window.
131
- """
132
- self.window_cache = {}
133
- timestamps = self.dataframe["Datetime"].to_list()
134
-
135
- for i in range(len(timestamps) - self.window_size + 1):
136
- # Use last timestamp as key
137
- end_time = timestamps[i + self.window_size - 1]
138
-
139
- # Convert end_time datetime object to UTC
140
- if isinstance(end_time, str):
141
- end_time = parser.parse(end_time)
142
- elif isinstance(end_time, datetime):
143
- end_time = end_time
144
-
145
- self.window_cache[end_time] = \
146
- self.dataframe.iloc[i:i + self.window_size]
147
-
148
- def get_data(
149
- self,
150
- date,
151
- config=None,
152
- ):
153
- """
154
- Get data implementation of ccxt based ohlcv backtest market data
155
- source. This implementation will use polars to load and filter the
156
- data.
157
- """
158
-
159
- data = self.window_cache.get(date)
160
-
161
- if data is not None:
162
- data = pl.from_pandas(data)
163
- return data
164
-
165
- # Find closest previous timestamp
166
- sorted_timestamps = sorted(self.window_cache.keys())
167
-
168
- closest_date = None
169
- for ts in reversed(sorted_timestamps):
170
- date = sync_timezones(ts, date)
171
-
172
- if ts <= date:
173
- closest_date = ts
174
- break
175
-
176
- data = self.window_cache.get(closest_date) if closest_date else None
177
-
178
- if data is not None:
179
- data = pl.from_pandas(data)
180
-
181
- return data
182
-
183
- def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
184
- # Ignore this method for now
185
- pass
186
-
187
- def empty(self):
188
- return False
189
-
190
-
191
- class PandasOHLCVMarketDataSource(OHLCVMarketDataSource):
192
- """
193
- PandasOHLCVMarketDataSource implementation of a OHLCVMarketDataSource
194
- using a pandas dataframe to provide data to the strategy.
195
-
196
- """
197
-
198
- """
199
- PandasOHLCVBacktestMarketDataSource implementation
200
- of a OHLCVMarketDataSource. This implementation uses a pandas
201
- dataframe to provide data to the strategy.
202
- """
203
- backtest_data_directory = None
204
- backtest_data_end_date = None
205
- total_minutes_time_frame = None
206
- column_names = ["Datetime", "Open", "High", "Low", "Close", "Volume"]
207
-
208
- def __init__(
209
- self,
210
- identifier,
211
- market,
212
- symbol,
213
- time_frame,
214
- dataframe=None,
215
- window_size=None,
216
- ):
217
- super().__init__(
218
- identifier=identifier,
219
- market=market,
220
- symbol=symbol,
221
- time_frame=time_frame,
222
- window_size=window_size,
223
- )
224
- self.dataframe = dataframe
225
- self._start_date_data_source = None
226
- self._end_date_data_source = None
227
- self.backtest_end_index = self.window_size
228
- self.backtest_start_index = 0
229
-
230
- def get_data(
231
- self,
232
- start_date: datetime = None,
233
- end_date: datetime = None,
234
- config=None,
235
- ):
236
- """
237
- Implementation of get_data for CCXTOHLCVMarketDataSource.
238
- This implementation uses the CCXTMarketService to get the OHLCV data.
239
-
240
- Args:
241
- start_date: datetime (optional) - the start date of the data. The
242
- first candle stick should close to this date.
243
- end_date: datetime (optional) - the end date of the data. The last
244
- candle stick should close to this date.
245
- storage_path: string (optional) - the storage path specifies the
246
- directory where the data is written to or read from.
247
- If set the data provider will write all its downloaded data
248
- to this location. Also, it will check if the
249
- data already exists at the storage location. If this is the
250
- case it will return this.
251
-
252
- Returns
253
- polars.DataFrame with the OHLCV data
254
- """
255
-
256
- # Calculate the start and end dates
257
- if start_date is None or end_date is None:
258
-
259
- if start_date is None:
260
-
261
- if end_date is None:
262
- end_date = datetime.now(tz=timezone.utc)
263
-
264
- if self.window_size is None:
265
- raise OperationalException(
266
- "Window_size should be defined before the " +
267
- "get_data method can be called. Make sure to set " +
268
- "the window_size attribute on your " +
269
- "CCXTOHLCVMarketDataSource or provide a start_date " +
270
- "and end_date to the get_data method."
271
- )
272
-
273
- start_date = self.create_start_date(
274
- end_date=end_date,
275
- time_frame=self.time_frame,
276
- window_size=self.window_size
277
- )
278
- else:
279
- end_date = self.create_end_date(
280
- start_date=start_date,
281
- time_frame=self.time_frame,
282
- window_size=self.window_size
283
- )
284
- # Return the dataframe sliced by the start and end date
285
- start_date = sync_timezones(
286
- self.dataframe["Datetime"].dt.tz, start_date
287
- )
288
- end_date = sync_timezones(
289
- self.dataframe["Datetime"].dt.tz, end_date
290
- )
291
- data = self.dataframe[
292
- (self.dataframe["Datetime"] >= start_date) &
293
- (self.dataframe["Datetime"] <= end_date)
294
- ]
295
-
296
- if data is not None:
297
- data = pl.from_pandas(data)
298
-
299
- return data
300
-
301
- def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
302
- return PandasOHLCVBacktestMarketDataSource(
303
- identifier=self.identifier,
304
- market=self.market,
305
- symbol=self.symbol,
306
- time_frame=self.time_frame,
307
- dataframe=self.dataframe,
308
- window_size=self.window_size
309
- )
310
-
311
- def empty(self):
312
- return False
@@ -1,5 +0,0 @@
1
- from .ccxt_market_service import CCXTMarketService
2
-
3
- __all__ = [
4
- "CCXTMarketService",
5
- ]