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,850 @@
1
+ import logging
2
+ import pandas as pd
3
+ import polars as pl
4
+ from collections import defaultdict
5
+ from datetime import datetime
6
+ from typing import List, Tuple, Optional, Dict, Any
7
+
8
+ from investing_algorithm_framework.domain import DataProvider, \
9
+ OperationalException, ImproperlyConfigured, DataSource, DataType, \
10
+ BacktestDateRange, tqdm, convert_polars_to_pandas, TimeFrame
11
+
12
+ logger = logging.getLogger("investing_algorithm_framework")
13
+
14
+
15
+ class DataProviderIndex:
16
+ """
17
+ Efficient lookup for data providers in O(1) time.
18
+
19
+ Attributes:
20
+ data_providers (List[DataProvider]): List of data providers
21
+ data_providers_lookup (dict): Dictionary to store the lookup
22
+ for order executors based on market.
23
+ """
24
+ def __init__(self, data_providers=[]):
25
+ self.data_providers = data_providers
26
+ self.data_providers_lookup = defaultdict()
27
+ self.ohlcv_data_providers = defaultdict()
28
+ self.ohlcv_data_providers_no_market = defaultdict()
29
+ self.ohlcv_data_providers_with_timeframe = defaultdict()
30
+ self.ticker_data_providers = defaultdict()
31
+
32
+ def add(self, data_provider: DataProvider):
33
+ """
34
+ Add a data provider to the lookup.
35
+
36
+ Args:
37
+ data_provider (DataProvider): The data provider to be added.
38
+
39
+ Returns:
40
+ None
41
+ """
42
+ self.data_providers.append(data_provider)
43
+
44
+ def register(self, data_source: DataSource) -> DataProvider:
45
+ """
46
+ Register a data source in the DataProvider Index.
47
+
48
+
49
+ This method will go over all data providers and select the
50
+ best matching data provider for the data source.
51
+
52
+ If multiple data providers are found for the data source,
53
+ it will sort them by priority and pick the best one.
54
+
55
+ Args:
56
+ data_source (DataSource): The data source to register the
57
+ data provider for.
58
+
59
+ Returns:
60
+ None
61
+ """
62
+ matches = []
63
+
64
+ for data_provider in self.data_providers:
65
+
66
+ if data_provider.has_data(data_source):
67
+ matches.append(data_provider)
68
+
69
+ if len(matches) == 0:
70
+ params = data_source.to_dict()
71
+ raise ImproperlyConfigured(
72
+ f"No data provider found for given parameters: {params}."
73
+ f" Please make sure that you have registered a data provider "
74
+ f"provider for the market and symbol you are trying to use"
75
+ )
76
+ # Sort by priority and pick the best one
77
+ best_provider = sorted(matches, key=lambda x: x.priority)[0]
78
+ best_provider = best_provider.copy(data_source)
79
+ # Copy the data provider and set the attributes
80
+ self.data_providers_lookup[data_source] = best_provider
81
+
82
+ symbol = data_source.symbol
83
+ market = data_source.market
84
+ time_frame = data_source.time_frame
85
+
86
+ if DataType.OHLCV.equals(data_source.data_type):
87
+ if symbol not in self.ohlcv_data_providers:
88
+ self.ohlcv_data_providers[(symbol, market)] = best_provider
89
+ self.ohlcv_data_providers_no_market[symbol] = best_provider
90
+ self.ohlcv_data_providers_with_timeframe[
91
+ (symbol, market, time_frame)
92
+ ] = best_provider
93
+ else:
94
+ try:
95
+ # If the symbol already exists, we can update the provider
96
+ # has a more granular timeframe
97
+ existing_provider = self.ohlcv_data_providers[
98
+ (symbol, market)
99
+ ]
100
+
101
+ if existing_provider.time_frame > best_provider.time_frame:
102
+ self.ohlcv_data_providers[(symbol, market)] =\
103
+ best_provider
104
+
105
+ existing_provider = self.ohlcv_data_providers_no_market[
106
+ symbol
107
+ ]
108
+
109
+ if existing_provider.time_frame > best_provider.time_frame:
110
+ self.ohlcv_data_providers_no_market[symbol] =\
111
+ best_provider
112
+
113
+ time_frame_key = (symbol, market, time_frame)
114
+ self.ohlcv_data_providers_with_timeframe[
115
+ time_frame_key
116
+ ] = best_provider
117
+
118
+ except Exception:
119
+ # If the existing provider does not have a time_frame
120
+ # attribute, we can safely ignore this
121
+ pass
122
+
123
+ elif DataType.TICKER.equals(data_source.data_type):
124
+ if symbol not in self.ticker_data_providers:
125
+ self.ticker_data_providers[symbol] = best_provider
126
+
127
+ return best_provider
128
+
129
+ def register_backtest_data_source(
130
+ self,
131
+ data_source: DataSource,
132
+ backtest_date_range: BacktestDateRange
133
+ ) -> DataProvider:
134
+ """
135
+ Register a backtest data source for a given market and symbol.
136
+
137
+ This method will also check if the data provider supports
138
+ the market. If no data provider is found for the market and symbol,
139
+ it will raise an ImproperlyConfigured exception.
140
+
141
+ Args:
142
+ data_source (DataSource): The data source to register the
143
+ backtest data provider for.
144
+ backtest_date_range (BacktestDateRange): The date range for the
145
+ backtest data provider.
146
+
147
+ Returns:
148
+ DataProvider: The registered data provider.
149
+ """
150
+ matches = []
151
+
152
+ for data_provider in self.data_providers:
153
+
154
+ if data_provider.has_data(
155
+ data_source,
156
+ start_date=backtest_date_range.start_date,
157
+ end_date=backtest_date_range.end_date
158
+ ):
159
+ matches.append(data_provider)
160
+
161
+ if len(matches) == 0:
162
+ params = data_source.to_dict()
163
+ raise ImproperlyConfigured(
164
+ f"No data provider found for given parameters: {params}."
165
+ f" Please make sure that you have registered a data provider "
166
+ f"provider for the defined datasource. If you are using a "
167
+ "custom data provider, make sure it has a "
168
+ "data_provider_identifier set"
169
+ )
170
+
171
+ # Sort by priority and pick the best one (lowest priority first)
172
+ best_provider = sorted(matches, key=lambda x: x.priority)[0]
173
+ best_provider = best_provider.copy(data_source)
174
+ self.data_providers_lookup[data_source] = best_provider
175
+
176
+ symbol = data_source.symbol
177
+ market = data_source.market
178
+ time_frame = data_source.time_frame
179
+
180
+ if DataType.OHLCV.equals(data_source.data_type):
181
+
182
+ if symbol not in self.ohlcv_data_providers:
183
+ self.ohlcv_data_providers[(symbol, market)] = best_provider
184
+ self.ohlcv_data_providers_no_market[symbol] = best_provider
185
+ self.ohlcv_data_providers_with_timeframe[
186
+ (symbol, market, time_frame)
187
+ ] = best_provider
188
+ else:
189
+ try:
190
+ # If the symbol already exists, we can update the provider
191
+ # has a more granular timeframe
192
+ existing_provider = self.ohlcv_data_providers[
193
+ (symbol.upper(), market.upper())
194
+ ]
195
+ if existing_provider.time_frame > best_provider.time_frame:
196
+ self.ohlcv_data_providers[
197
+ (symbol.upper(), market.upper())
198
+ ] =\
199
+ best_provider
200
+
201
+ existing_provider = self.ohlcv_data_providers_no_market[
202
+ symbol
203
+ ]
204
+
205
+ if existing_provider.time_frame > best_provider.time_frame:
206
+ self.ohlcv_data_providers_no_market[symbol] = \
207
+ best_provider
208
+
209
+ time_frame_key = (symbol, market, data_source.time_frame)
210
+ self.ohlcv_data_providers_with_timeframe[
211
+ time_frame_key
212
+ ] = best_provider
213
+
214
+ except Exception:
215
+ # If the existing provider does not have a time_frame
216
+ # attribute, we can safely ignore this
217
+ pass
218
+
219
+ elif DataType.TICKER.equals(data_source.data_type):
220
+ if symbol not in self.ticker_data_providers:
221
+ self.ticker_data_providers[symbol] = best_provider
222
+
223
+ return best_provider
224
+
225
+ def get(self, data_source: DataSource) -> Optional[DataProvider]:
226
+ """
227
+ Get the data provider for a given data source.
228
+
229
+ Args:
230
+ data_source (DataSource): The data source to get the
231
+ data provider for.
232
+
233
+ Returns:
234
+ DataProvider: The data provider for the market and symbol,
235
+ """
236
+ return self.data_providers_lookup.get(data_source, None)
237
+
238
+ def find(self, data_source: DataSource) -> Optional[DataProvider]:
239
+ """
240
+ Find a data provider for a given data source.
241
+
242
+ Args:
243
+ data_source (DataSource): The data source to find the
244
+ data provider for.
245
+
246
+ Returns:
247
+ DataProvider: The data provider for the market and symbol,
248
+ or None if no provider is found.
249
+ """
250
+ return self.data_providers_lookup.get(data_source, None)
251
+
252
+ def get_all(self) -> List[Tuple[DataSource, DataProvider]]:
253
+ """
254
+ Get all registered data providers with corresponding DataSource.
255
+
256
+ Returns:
257
+ List[Tuple[DataSource, DataProvider]]: A list of all
258
+ data providers with corresponding data sources.
259
+ """
260
+ return [
261
+ (data_source, data_provider)
262
+ for data_source, data_provider
263
+ in self.data_providers_lookup.items()
264
+ ]
265
+
266
+ def reset(self):
267
+ """
268
+ Function to reset the order executor lookup table
269
+
270
+ Returns:
271
+ None
272
+ """
273
+ self.data_providers_lookup = defaultdict()
274
+ self.data_providers = []
275
+
276
+ def __len__(self):
277
+ """
278
+ Returns the number of data providers in the index.
279
+
280
+ Returns:
281
+ int: The number of data providers.
282
+ """
283
+ return len(self.data_providers_lookup)
284
+
285
+ def get_ohlcv_data_provider(
286
+ self,
287
+ symbol: str,
288
+ market: Optional[str] = None,
289
+ time_frame: Optional[str] = None
290
+ ) -> Optional[DataProvider]:
291
+ """
292
+ Get the OHLCV data provider for a given symbol and market.
293
+
294
+ Args:
295
+ symbol (str): The symbol to get the data provider for.
296
+ market (Optional[str]): The market to get the data provider for.
297
+ time_frame (Optional[str]): The time frame to get the
298
+ data provider for.
299
+
300
+ Returns:
301
+ DataProvider: The OHLCV data provider for the symbol and market,
302
+ or None if no provider is found.
303
+ """
304
+
305
+ if market is not None and time_frame is not None:
306
+ time_frame = TimeFrame.from_value(time_frame)
307
+ return self.ohlcv_data_providers_with_timeframe.get(
308
+ (symbol, market, time_frame), None
309
+ )
310
+
311
+ if market is None:
312
+ # If no market is specified
313
+ return self.ohlcv_data_providers_no_market.get(symbol, None)
314
+
315
+ return self.ohlcv_data_providers.get((symbol, market), None)
316
+
317
+ def get_ticker_data_provider(
318
+ self, symbol: str, market: str
319
+ ) -> Optional[DataProvider]:
320
+ """
321
+ Get the ticker data provider for a given symbol and market.
322
+
323
+ Args:
324
+ symbol (str): The symbol to get the data provider for.
325
+ market (str): The market to get the data provider for.
326
+
327
+ Returns:
328
+ DataProvider: The ticker data provider for the symbol and market,
329
+ or None if no provider is found.
330
+ """
331
+ return self.ticker_data_providers.get(symbol, None)
332
+
333
+
334
+ class DataProviderService:
335
+ data_provider_index: DataProviderIndex = None
336
+ backtest_mode = False
337
+
338
+ def __init__(
339
+ self,
340
+ configuration_service,
341
+ market_credential_service,
342
+ default_data_providers: List[DataProvider] = [],
343
+ ):
344
+ """
345
+ Initialize the DataProviderService with a list of data providers.
346
+
347
+ Args:
348
+ default_data_providers (List[DataProvider]): A list of default
349
+ data providers to use.
350
+ """
351
+ self.default_data_providers = default_data_providers
352
+ self.data_provider_index = DataProviderIndex(default_data_providers)
353
+ self.configuration_service = configuration_service
354
+ self.market_credential_service = market_credential_service
355
+
356
+ def get(self, data_source: DataSource) -> Optional[DataProvider]:
357
+ """
358
+ Get a registered data provider by its data source.
359
+
360
+ Args:
361
+ data_source (DataSource): The data source to get the
362
+ data provider for.
363
+
364
+ Returns:
365
+ Optional[DataProvider]: The registered data provider for
366
+ the data source, or None if not found.
367
+ """
368
+ return self.data_provider_index.get(data_source)
369
+
370
+ def get_data(
371
+ self,
372
+ data_source: DataSource,
373
+ date: datetime = None,
374
+ start_date: datetime = None,
375
+ end_date: datetime = None,
376
+ ):
377
+ """
378
+ Function to get data from the data provider.
379
+
380
+ Args:
381
+ data_source (DataSource): The data source specification that
382
+ matches a data provider.
383
+ date (datetime): The date to get data for.
384
+ start_date (datetime): The start date for the data.
385
+ end_date (datetime): The end date for the data.
386
+
387
+ Returns:
388
+ DataFrame: The data for the given symbol and market.
389
+ """
390
+ data_provider = self.data_provider_index.get(data_source=data_source)
391
+
392
+ if data_provider is None:
393
+ dict_data = data_source.to_dict()
394
+ self._throw_no_data_provider_exception(dict_data)
395
+
396
+ if self.configuration_service is not None:
397
+ data_provider.config = self.configuration_service.get_config()
398
+
399
+ return data_provider.get_data(
400
+ date=date,
401
+ start_date=start_date,
402
+ end_date=end_date,
403
+ save=data_source.save,
404
+ )
405
+
406
+ def get_ticker_data(self, symbol, market, date):
407
+ """
408
+ Function to get a ticker for a given data source.
409
+ The data source should have its market and symbol defined.
410
+ All other attributes are ignored of the data source
411
+ """
412
+ data_provider = self.data_provider_index.get_ticker_data_provider(
413
+ symbol=symbol, market=market
414
+ )
415
+
416
+ if data_provider is None:
417
+ ohlcv_data_provider = self.data_provider_index.\
418
+ get_ohlcv_data_provider(
419
+ symbol=symbol, market=market
420
+ )
421
+
422
+ if ohlcv_data_provider is None:
423
+ raise OperationalException(
424
+ "No ticker data provider found "
425
+ f"for symbol: {symbol} and market: {market} "
426
+ f"on date: {date}"
427
+ )
428
+ else:
429
+ if self.backtest_mode:
430
+ data = ohlcv_data_provider.get_backtest_data(
431
+ backtest_index_date=date,
432
+ )
433
+
434
+ if isinstance(data, pd.DataFrame):
435
+ # Convert to Polars DataFrame for consistency
436
+ data.index.name = "Datetime"
437
+ data = data.reset_index()
438
+ data = pl.from_pandas(data)
439
+ entry = data[-1]
440
+ return {
441
+ "symbol": symbol,
442
+ "market": market,
443
+ "datetime": entry["Datetime"][0],
444
+ "open": entry["Open"][0],
445
+ "high": entry["High"][0],
446
+ "low": entry["Low"][0],
447
+ "close": entry["Close"][0],
448
+ "volume": entry["Close"][0],
449
+ "ask": entry["Close"][0],
450
+ "bid": entry["Close"][0],
451
+ }
452
+ else:
453
+ data = ohlcv_data_provider.get_data(
454
+ date=date,
455
+ )
456
+
457
+ if isinstance(data, pd.DataFrame):
458
+ # Convert to Polars DataFrame for consistency
459
+ data.index.name = "Datetime"
460
+ data = data.reset_index()
461
+ data = pl.from_pandas(data)
462
+
463
+ entry = data[-1]
464
+ return {
465
+ "symbol": symbol,
466
+ "market": market,
467
+ "datetime": entry["Datetime"][0],
468
+ "open": entry["Open"][0],
469
+ "high": entry["High"][0],
470
+ "low": entry["Low"][0],
471
+ "close": entry["Close"][0],
472
+ "volume": entry["Close"][0],
473
+ "ask": entry["Close"][0],
474
+ "bid": entry["Close"][0],
475
+ }
476
+ else:
477
+
478
+ if self.backtest_mode:
479
+ return data_provider.get_backtest_data(
480
+ backtest_index_date=date,
481
+ )
482
+
483
+ else:
484
+ return data_provider.get_data(date=date)
485
+
486
+ def get_ohlcv_data(
487
+ self,
488
+ symbol: str,
489
+ market: str = None,
490
+ time_frame: str = None,
491
+ date: Optional[datetime] = None,
492
+ start_date: Optional[datetime] = None,
493
+ end_date: Optional[datetime] = None,
494
+ window_size: Optional[int] = None,
495
+ pandas: bool = False,
496
+ add_pandas_index: bool = True,
497
+ add_datetime_column: bool = False,
498
+ ):
499
+ """
500
+ Function to get OHLCV data from the data provider.
501
+
502
+ Args:
503
+ symbol (str): The symbol to get OHLCV data for.
504
+ market (str): The market to get OHLCV data for.
505
+ time_frame (str): The time frame to get OHLCV data for.
506
+ date (datetime): The date to get OHLCV data for.
507
+ start_date (datetime): The start date for the OHLCV data.
508
+ end_date (datetime): The end date for the OHLCV data.
509
+ window_size (int): The window size for the OHLCV data.
510
+ pandas (bool): Whether to return the data as a pandas DataFrame.
511
+ add_pandas_index (bool): Whether to add a pandas index to
512
+ the DataFrame if pandas is True.
513
+ add_datetime_column (bool): Whether to add a datetime column
514
+ to the DataFrame if pandas is True.
515
+
516
+ Returns:
517
+ DataFrame: The OHLCV data for the given symbol and market.
518
+ """
519
+ data_provider = self.data_provider_index.get_ohlcv_data_provider(
520
+ symbol=symbol,
521
+ market=market,
522
+ time_frame=time_frame
523
+ )
524
+
525
+ if data_provider is None:
526
+ if market is not None:
527
+ raise OperationalException(
528
+ "No OHLCV data provider found "
529
+ f"for symbol: {symbol} and market: {market}"
530
+ )
531
+ else:
532
+ raise OperationalException(
533
+ f"No OHLCV data provider found for symbol: {symbol}"
534
+ )
535
+
536
+ if self.backtest_mode:
537
+ data = data_provider.get_backtest_data(
538
+ backtest_index_date=date,
539
+ backtest_start_date=start_date,
540
+ backtest_end_date=end_date,
541
+ )
542
+ else:
543
+ data = data_provider.get_data(
544
+ date=date,
545
+ start_date=start_date,
546
+ end_date=end_date,
547
+ )
548
+
549
+ if pandas:
550
+ if isinstance(data, pl.DataFrame):
551
+ return convert_polars_to_pandas(
552
+ data,
553
+ add_index=add_pandas_index,
554
+ add_datetime_column=add_datetime_column
555
+ )
556
+ else:
557
+ return data
558
+
559
+ if isinstance(data, pd.DataFrame):
560
+ # Convert to Polars DataFrame for consistency
561
+ data.index.name = "Datetime"
562
+ data = data.reset_index()
563
+ data = pl.from_pandas(data)
564
+
565
+ return data
566
+
567
+ def get_backtest_data(
568
+ self,
569
+ data_source: DataSource,
570
+ backtest_index_date: datetime = None,
571
+ start_date: datetime = None,
572
+ end_date: datetime = None,
573
+ ):
574
+ """
575
+ Function to get backtest data from the data provider.
576
+
577
+ Args:
578
+ data_source (DataSource): The data source specification that
579
+ matches a data provider.
580
+ backtest_index_date (datetime): The current date of the backtest.
581
+ start_date (datetime): The start date for the data.
582
+ end_date (datetime): The end date for the data.
583
+
584
+ Returns:
585
+ DataFrame: The backtest data for the given symbol and market.
586
+ """
587
+ data_provider = self.data_provider_index.get(data_source=data_source)
588
+
589
+ if data_provider is None:
590
+ self._throw_no_data_provider_exception(data_source.to_dict())
591
+
592
+ return data_provider.get_backtest_data(
593
+ backtest_index_date=backtest_index_date,
594
+ backtest_start_date=start_date,
595
+ backtest_end_date=end_date,
596
+ data_source=data_source
597
+ )
598
+
599
+ def get_vectorized_backtest_data(
600
+ self,
601
+ data_sources: List[DataSource],
602
+ start_date: datetime = None,
603
+ end_date: datetime = None,
604
+ ) -> Dict[str, Any]:
605
+ """
606
+ Function to get vectorized backtest data from the data provider.
607
+
608
+ Args:
609
+ data_sources (List[DataSource]): The data sources to get
610
+ backtest data for.
611
+ start_date (datetime): The start date for the backtest data.
612
+ end_date (datetime): The end date for the backtest data.
613
+
614
+ Returns:
615
+ Dict[str, Any]: The vectorized backtest data for the
616
+ given data sources.
617
+ """
618
+ vectorized_data = {}
619
+
620
+ for data_source in data_sources:
621
+ data_start_date = data_source.create_start_date_data(start_date)
622
+ backtest_data = self.get_backtest_data(
623
+ data_source=data_source,
624
+ start_date=data_start_date,
625
+ end_date=end_date,
626
+ )
627
+ vectorized_data[data_source.get_identifier()] = backtest_data
628
+
629
+ return vectorized_data
630
+
631
+ def _throw_no_data_provider_exception(self, params):
632
+ """
633
+ Raise an exception if no data provider is found for the given params
634
+ """
635
+ non_null_params = {k: v for k, v in params.items() if v is not None}
636
+ if len(non_null_params) == 0:
637
+ raise OperationalException(
638
+ "No data provider found for the given parameters"
639
+ )
640
+
641
+ params = ", ".join(
642
+ [f"{k}: {v}" for k, v in non_null_params.items()]
643
+ )
644
+
645
+ raise OperationalException(
646
+ f"No data provider found for the given parameters: {params}"
647
+ )
648
+
649
+ def register_data_provider(
650
+ self, data_source: DataSource, data_provider: DataProvider
651
+ ) -> DataProvider:
652
+ """
653
+ Function to directly register a data provider for a given data source.
654
+
655
+ This method will not check if the data provider supports the
656
+ data source. It will directly register the data provider in the index.
657
+
658
+ Args:
659
+ data_source (DataSource): The data source to register the
660
+ data provider for.
661
+ data_provider (DataProvider): The data provider to register.
662
+
663
+ Returns:
664
+ DataProvider: The registered data provider.
665
+ """
666
+ data_provider = data_provider.copy(data_source)
667
+ self.data_provider_index.data_providers_lookup[data_source] = \
668
+ data_provider
669
+ return data_provider
670
+
671
+ def add_data_provider(
672
+ self, data_provider: DataProvider, priority: int = 3
673
+ ):
674
+ """
675
+ Add a data provider to the service.
676
+
677
+ Args:
678
+ data_provider (DataProvider): The data provider to add.
679
+ priority (int): The priority of the data provider.
680
+
681
+ Returns:
682
+ None
683
+ """
684
+ data_provider.priority = priority
685
+ data_provider.config = self.configuration_service.get_config()
686
+ self.data_provider_index.add(data_provider)
687
+
688
+ def index_data_providers(self, data_sources: List[DataSource]):
689
+ """
690
+ Index the data providers in the service.
691
+ This will create a fast lookup index for the data providers
692
+ based on the given parameters.
693
+
694
+ Args:
695
+ data_sources (List[DataSource]): The data sources to index.
696
+
697
+ Returns:
698
+ None
699
+ """
700
+
701
+ for data_source in data_sources:
702
+ self.data_provider_index.register(data_source)
703
+ logger.debug(
704
+ "Registered data provider for data source: {data_source}"
705
+ )
706
+
707
+ def index_backtest_data_providers(
708
+ self,
709
+ data_sources: List[DataSource],
710
+ backtest_date_range: BacktestDateRange,
711
+ show_progress: bool = True
712
+ ):
713
+ """
714
+ Index the data providers in the service.
715
+ This will create a fast lookup index for the data providers
716
+ based on the given parameters.
717
+
718
+ Args:
719
+ data_sources (List[DataSource]): The data sources to index.
720
+ backtest_date_range (BacktestDateRange): The date range for the
721
+ backtest data providers.
722
+ show_progress (bool): Whether to show progress while indexing
723
+ the data providers.
724
+
725
+ Returns:
726
+ None
727
+ """
728
+
729
+ # Filter out duplicate data_sources
730
+ unique_data_sources = set(data_sources)
731
+
732
+ if show_progress:
733
+
734
+ for data_source in tqdm(
735
+ unique_data_sources,
736
+ desc="Registering backtest data providers for data sources",
737
+ colour="green"
738
+ ):
739
+ self.data_provider_index.register_backtest_data_source(
740
+ data_source, backtest_date_range
741
+ )
742
+ logger.debug(
743
+ "Registered backtest "
744
+ f"data provider for data source: {data_source}"
745
+ )
746
+ else:
747
+ for data_source in unique_data_sources:
748
+ self.data_provider_index.register_backtest_data_source(
749
+ data_source, backtest_date_range
750
+ )
751
+ logger.debug(
752
+ "Registered backtest "
753
+ f"data provider for data source: {data_source}"
754
+ )
755
+
756
+ self.backtest_mode = True
757
+
758
+ def prepare_backtest_data(
759
+ self,
760
+ backtest_date_range: BacktestDateRange,
761
+ show_progress: bool = True
762
+ ):
763
+ """
764
+ Prepare the backtest data for all registered data providers.
765
+
766
+ Args:
767
+ backtest_date_range (BacktestDateRange): The date range for the
768
+ backtest data.
769
+ show_progress (bool): Whether to show progress while preparing
770
+ the backtest data.
771
+
772
+ Raises:
773
+ OperationalException: If no data providers are registered.
774
+
775
+ Returns:
776
+ None
777
+ """
778
+
779
+ if len(self.data_provider_index.data_providers_lookup) == 0:
780
+ raise OperationalException(
781
+ "No data providers registered. "
782
+ "Please register at least one data provider before preparing "
783
+ "backtest data."
784
+ )
785
+
786
+ logger.info(
787
+ "Preparing backtest data for all registered data providers"
788
+ )
789
+
790
+ if show_progress:
791
+ for data_source, data_provider in tqdm(
792
+ self.data_provider_index.get_all(),
793
+ desc="Preparing backtest data",
794
+ colour="green"
795
+ ):
796
+ try:
797
+ data_provider.prepare_backtest_data(
798
+ backtest_start_date=backtest_date_range.start_date,
799
+ backtest_end_date=backtest_date_range.end_date
800
+ )
801
+ except Exception as e:
802
+ logger.error(
803
+ f"Error preparing backtest data for {data_source}: {e}"
804
+ )
805
+ else:
806
+ for data_source, data_provider \
807
+ in self.data_provider_index.get_all():
808
+
809
+ try:
810
+ data_provider.prepare_backtest_data(
811
+ backtest_start_date=backtest_date_range.start_date,
812
+ backtest_end_date=backtest_date_range.end_date
813
+ )
814
+ except Exception as e:
815
+ logger.error(
816
+ f"Error preparing backtest data for {data_source}: {e}"
817
+ )
818
+
819
+ def get_data_files(self):
820
+ """
821
+ Function to get the data files for the market data sources.
822
+
823
+ Returns:
824
+ List[str]: A list of file paths for the data files.
825
+ """
826
+ data_files = []
827
+
828
+ for market_data_source in self.data_provider_index.data_providers:
829
+ if hasattr(market_data_source, 'file_path') and \
830
+ market_data_source.file_path is not None:
831
+ data_files.append(market_data_source.file_path)
832
+
833
+ return data_files
834
+
835
+ def get_all_registered_data_providers(self) -> List[DataProvider]:
836
+ """
837
+ Function to get all registered data providers.
838
+
839
+ Returns:
840
+ List[DataProvider]: A list of all registered data providers.
841
+ """
842
+ return self.data_provider_index.get_all()
843
+
844
+ def reset(self):
845
+ """
846
+ Function to reset all the data providers and the data provider
847
+ lookup index.
848
+ """
849
+ self.data_provider_index.reset()
850
+ self.backtest_mode = False