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,334 @@
1
+ from typing import List, Any, Union
2
+ from abc import ABC, abstractmethod
3
+ from datetime import datetime
4
+ from investing_algorithm_framework.domain.exceptions import \
5
+ ImproperlyConfigured
6
+ from investing_algorithm_framework.domain.models.time_frame import TimeFrame
7
+ from investing_algorithm_framework.domain.models.data.data_type import DataType
8
+ from investing_algorithm_framework.domain.models.data.data_source import \
9
+ DataSource
10
+
11
+
12
+ class DataProvider(ABC):
13
+ """
14
+ Abstract base class for data providers. The DataProvider class
15
+ is responsible for fetching and preparing data for trading
16
+ algorithms.
17
+
18
+ Attributes:
19
+ data_type (DataType): The type of data to be
20
+ fetched (e.g., OHLCV, TICKER, CUSTOM_DATA).
21
+ symbol (Optional[List[str]]): A list supported symbols that the
22
+ data provider can provide data for. The framework will use this
23
+ list when searching for a data provider for a specific symbol.
24
+ Example: ["AAPL/USD", "GOOGL/USD", "MSFT/USD"]
25
+ priority (int): The priority of the data provider. The lower the
26
+ number, the higher the priority. The framework will use this
27
+ priority when searching for a data provider for a specific symbol.
28
+ Example: 0 is the highest priority, 1 is the second-highest
29
+ priority, etc. This is useful when multiple data providers
30
+ support the same symbol or market. The framework will use the
31
+ data provider with the highest priority.
32
+ time_frame (Optional[str]): The time frame for the data. This is
33
+ useful for data providers that support multiple time frames.
34
+ Example: "1m", "5m", "1h", "1d"
35
+ window_size (Optional[int]): The window size for the data. This is
36
+ useful for data providers that support multiple window sizes.
37
+ Example: 100, 200, 500
38
+ storage_path (Optional[str]): The path to the storage location
39
+ for the data. This is useful for data providers that support
40
+ saving data to a file
41
+ """
42
+ data_type: DataType = None
43
+ data_provider_identifier: str = None
44
+
45
+ def __init__(
46
+ self,
47
+ data_provider_identifier: str = None,
48
+ data_type: str = None,
49
+ symbol: str = None,
50
+ market: str = None,
51
+ priority: int = 0,
52
+ time_frame=None,
53
+ window_size=None,
54
+ storage_path=None,
55
+ storage_directory=None,
56
+ config=None,
57
+ ):
58
+ """
59
+ Initializes the DataProvider. The data provider should be defined
60
+ with a data_type and a data_provider_identifier. The data_type
61
+ should be a valid DataType, and the data_provider_identifier
62
+ should be a unique identifier for the data provider.
63
+
64
+ Args:
65
+ data_provider_identifier (str): The unique identifier for the
66
+ data provider. This is used to identify the data provider
67
+ in the framework. It should be a unique string that identifies
68
+ the data provider. Example: "binance",
69
+ "coinbase", "custom_feed_data"
70
+ data_type (str): The type of data to be fetched
71
+ (e.g., "OHLCV", "TICKER", "CUSTOM_DATA")
72
+ symbol (str): The symbol to fetch data for. This is optional and
73
+ can be set later. Example: "AAPL/USD", "BTC/USD"
74
+ market (str): The market to fetch data for.
75
+ This is optional and can be set later.
76
+ Example: "BINANCE", "COINBASE"
77
+ priority (int): The priority of the data provider. The lower the
78
+ number, the higher the priority. This is useful when multiple
79
+ data providers support the same symbol or market. The framework
80
+ will use the data provider with the highest priority.
81
+ Example: 0 is the highest priority, 1 is the second-highest
82
+ priority, etc.
83
+ time_frame (str): The time frame for the data. This is optional and
84
+ can be set later. This is useful for data providers
85
+ that support multiple time frames.
86
+ Example: "1m", "5m", "1h", "1d"
87
+ window_size (int): The window size for the data. This is optional
88
+ and can be set later. This is useful for data providers that
89
+ support multiple window sizes. Example: 100, 200, 500
90
+ storage_path (str): The path to the storage location for the data.
91
+ This is optional and can be set later. This is useful for data
92
+ providers that support saving data to a file.
93
+ Example: "/path/to/data"
94
+ """
95
+ self._data_type = None
96
+ self._time_frame = None
97
+
98
+ if data_type is not None:
99
+ self.data_type = DataType.from_value(data_type)
100
+
101
+ if time_frame is not None:
102
+ self.time_frame = TimeFrame.from_value(time_frame)
103
+
104
+ if data_provider_identifier is not None:
105
+ self.data_provider_identifier = data_provider_identifier
106
+
107
+ self.symbol = symbol
108
+
109
+ if self.symbol is not None:
110
+ self.symbol = self.symbol.upper()
111
+
112
+ self.market = market
113
+
114
+ if self.market is not None:
115
+ self.market = self.market.upper()
116
+
117
+ self.priority = priority
118
+ self._config = config
119
+ self.window_size = window_size
120
+ self.storage_path = storage_path
121
+ self.storage_directory = storage_directory
122
+ self._market_credentials = None
123
+
124
+ # Check if the data provider is properly configured
125
+ if self.data_type is None:
126
+ raise ImproperlyConfigured(
127
+ "DataProvider must be initialized "
128
+ "with a data_type. Either pass it as a parameter in "
129
+ "the constructor or set it as a class attribute."
130
+ )
131
+
132
+ if self.data_provider_identifier is None:
133
+ raise ImproperlyConfigured(
134
+ "DataProvider must be initialized with a "
135
+ "data_provider_identifier. Either pass it as a parameter "
136
+ "in the constructor or set it as a class attribute."
137
+ )
138
+
139
+ @property
140
+ def market_credentials(self):
141
+ """
142
+ Returns the market credentials for the data provider.
143
+ """
144
+ return self._market_credentials
145
+
146
+ @market_credentials.setter
147
+ def market_credentials(self, value: List):
148
+ """
149
+ Sets the market credentials for the data provider.
150
+ """
151
+ self._market_credentials = value
152
+
153
+ def get_credential(self, market: str):
154
+ """
155
+ Returns the credentials for the given market.
156
+ """
157
+ if self.market_credentials is None:
158
+ return None
159
+ for credential in self.market_credentials:
160
+ if credential.market == market:
161
+ return credential
162
+ return None
163
+
164
+ @property
165
+ def config(self):
166
+ return self._config
167
+
168
+ @config.setter
169
+ def config(self, value):
170
+ self._config = value
171
+
172
+ @abstractmethod
173
+ def has_data(
174
+ self,
175
+ data_source: DataSource,
176
+ start_date: datetime = None,
177
+ end_date: datetime = None,
178
+ ) -> bool:
179
+ """
180
+ Checks if the data provider has data for the given parameters.
181
+
182
+ Args:
183
+ data_source (DataSource): The data source specification that
184
+ matches a data provider.
185
+ start_date (datetime): The start date for the data.
186
+ end_date (datetime): The end date for the data.
187
+
188
+ Returns:
189
+ bool: True if the data provider has data for the given parameters,
190
+ """
191
+ raise NotImplementedError("Subclasses should implement this method.")
192
+
193
+ @abstractmethod
194
+ def get_data(
195
+ self,
196
+ date: datetime = None,
197
+ start_date: datetime = None,
198
+ end_date: datetime = None,
199
+ save: bool = False,
200
+ ) -> Any:
201
+ """
202
+ Fetches data for a given symbol and date range.
203
+
204
+ Args:
205
+ start_date (datetime): The start date for the data.
206
+ end_date (datetime): The end date for the data.
207
+ date (datetime): The specific date for which to fetch data.
208
+ save (bool): Whether to save the data to the storage path.
209
+
210
+ Returns:
211
+ Any: The data for the given symbol and date range.
212
+ This can be a DataFrame, a list, or any other data structure
213
+ depending on the implementation.
214
+ """
215
+ raise NotImplementedError("Subclasses should implement this method.")
216
+
217
+ @abstractmethod
218
+ def prepare_backtest_data(
219
+ self,
220
+ backtest_start_date,
221
+ backtest_end_date,
222
+ ) -> None:
223
+ """
224
+ Prepares backtest data for a given symbol and date range.
225
+
226
+ Args:
227
+ backtest_start_date (datetime): The start date for the
228
+ backtest data.
229
+ backtest_end_date (datetime): The end date for the
230
+ backtest data.
231
+
232
+ Returns:
233
+ None
234
+ """
235
+ raise NotImplementedError("Subclasses should implement this method.")
236
+
237
+ @abstractmethod
238
+ def get_backtest_data(
239
+ self,
240
+ backtest_index_date: datetime,
241
+ backtest_start_date: datetime = None,
242
+ backtest_end_date: datetime = None,
243
+ data_source: DataSource = None,
244
+ ) -> Any:
245
+ """
246
+ Fetches backtest data for a given datasource
247
+
248
+ Args:
249
+ backtest_index_date (datetime): The date for which to fetch
250
+ backtest data.
251
+ backtest_start_date (datetime): The start date for the
252
+ backtest data.
253
+ backtest_end_date (datetime): The end date for the
254
+ backtest data.
255
+ data_source (Optional[DataSource]): The data source
256
+ specification that is used to fetch the data.
257
+ This param is optional and can be used to
258
+ help identify errors in data fetching.
259
+
260
+ Returns:
261
+ Any: The data for the given symbol and date range.
262
+ This can be a DataFrame, a list, or any other data structure
263
+ depending on the implementation.
264
+ """
265
+ raise NotImplementedError("Subclasses should implement this method.")
266
+
267
+ @abstractmethod
268
+ def copy(self, data_source: DataSource) -> "DataProvider":
269
+ """
270
+ Returns a copy of the data provider instance based on a
271
+ given data source. The data source is previously matched
272
+ with the 'has_data' method. Then a new instance of the data
273
+ provider must be registered in the framework so that each
274
+ data source has its own instance of the data provider.
275
+
276
+ Args:
277
+ data_source (DataSource): The data source specification that
278
+ matches a data provider.
279
+
280
+ Returns:
281
+ DataProvider: A new instance of the data provider with the same
282
+ configuration.
283
+ """
284
+ raise NotImplementedError("Subclasses should implement this method.")
285
+
286
+ @abstractmethod
287
+ def get_number_of_data_points(
288
+ self,
289
+ start_date: datetime,
290
+ end_date: datetime,
291
+ ) -> int:
292
+ """
293
+ Returns the number of data points available between the
294
+ given start and end dates.
295
+
296
+ Args:
297
+ start_date (datetime): The start date for the data points.
298
+ end_date (datetime): The end date for the data points.
299
+ Returns:
300
+ int: The number of data points available between the
301
+ given start and end dates.
302
+ """
303
+ raise NotImplementedError("Subclasses should implement this method.")
304
+
305
+ @abstractmethod
306
+ def get_missing_data_dates(
307
+ self,
308
+ start_date: datetime,
309
+ end_date: datetime,
310
+ ) -> List[datetime]:
311
+ """
312
+ Returns a list of dates for which data is missing between the
313
+ given start and end dates.
314
+
315
+ Args:
316
+ start_date (datetime): The start date for checking missing data.
317
+ end_date (datetime): The end date for checking missing data.
318
+
319
+ Returns:
320
+ List[datetime]: A list of dates for which data is missing
321
+ between the given start and end dates.
322
+ """
323
+ raise NotImplementedError("Subclasses should implement this method.")
324
+
325
+ @abstractmethod
326
+ def get_data_source_file_path(self) -> Union[str, None]:
327
+ """
328
+ Returns the file path for the given data source if applicable.
329
+
330
+ Returns:
331
+ Union[str, None]: The file path for the data source or None
332
+ if not applicable.
333
+ """
334
+ raise NotImplementedError("Subclasses should implement this method.")
@@ -0,0 +1,42 @@
1
+ class PeekableQueue:
2
+ def __init__(self, items=[]):
3
+ self.queue = items
4
+ self.index = 0
5
+
6
+ def enqueue(self, item):
7
+ self.queue.append(item)
8
+
9
+ def dequeue(self):
10
+ if not self.is_empty():
11
+ return self.queue.pop(0)
12
+ else:
13
+ raise IndexError("Queue is empty")
14
+
15
+ def peek(self):
16
+ if not self.is_empty():
17
+ return self.queue[0]
18
+ else:
19
+ raise IndexError("Queue is empty")
20
+
21
+ def is_empty(self):
22
+ return len(self.queue) == 0
23
+
24
+ def __len__(self):
25
+ return len(self.queue)
26
+
27
+ @property
28
+ def size(self):
29
+ return len(self.queue)
30
+
31
+ def __iter__(self):
32
+ self.index = 0
33
+ return self
34
+
35
+ def __next__(self):
36
+ if self.index < len(self.queue):
37
+ result = self.queue[self.index]
38
+ self.index += 1
39
+ return result
40
+ else:
41
+ self.index = 0 # Reset index for next iteration
42
+ raise StopIteration
@@ -0,0 +1,40 @@
1
+ from decimal import Decimal, getcontext
2
+
3
+
4
+ def count_number_of_decimals(value) -> int:
5
+ value = str(value)
6
+ if "." in value:
7
+ return len(value) - value.index(".") - 1
8
+ else:
9
+ return 0
10
+
11
+
12
+ def parse_decimal(value) -> Decimal:
13
+ getcontext().prec = count_number_of_decimals(value)
14
+ return Decimal(value)
15
+
16
+
17
+ def parse_decimal_to_string(decimal, precision=None):
18
+
19
+ if decimal is None:
20
+ return None
21
+
22
+ if isinstance(decimal, str):
23
+ return decimal
24
+
25
+ value_str = str(Decimal(decimal))
26
+
27
+ if precision is None:
28
+ return value_str
29
+
30
+ value_decimal = Decimal(value_str)
31
+ value_with_precision = format(value_decimal, f'.{precision}f')
32
+ return value_with_precision
33
+
34
+
35
+ def parse_string_to_decimal(value):
36
+
37
+ if value is None:
38
+ return None
39
+
40
+ return Decimal(value)
@@ -0,0 +1,112 @@
1
+ class ApiException(Exception):
2
+
3
+ def __init__(self, message: str = None, status_code: int = 400):
4
+ super(ApiException, self).__init__(message)
5
+ self._message = message
6
+ self._status_code = status_code
7
+
8
+ @property
9
+ def error_message(self):
10
+
11
+ if self._message is None:
12
+ return "An error occurred"
13
+
14
+ return self._message
15
+
16
+ @property
17
+ def status_code(self):
18
+
19
+ if self._status_code is None:
20
+ return 500
21
+
22
+ return self._status_code
23
+
24
+
25
+ class PermissionDeniedApiException(ApiException):
26
+
27
+ def __init__(self):
28
+ super(PermissionDeniedApiException, self).__init__(
29
+ message="Permission denied", status_code=401
30
+ )
31
+
32
+
33
+ class ImproperlyConfigured(Exception):
34
+ """
35
+ Class ImproperlyConfigured: Exception class indicating a problem with
36
+ the configuration of the investing_algorithm_framework
37
+ """
38
+ def __init__(self, message) -> None:
39
+ super(ImproperlyConfigured, self).__init__(message)
40
+ self.error_message = message
41
+
42
+ def to_response(self):
43
+ return {
44
+ "status": "error",
45
+ "message": self.error_message
46
+ }
47
+
48
+
49
+ class OperationalException(Exception):
50
+ """
51
+ Class OperationalException: Exception class indicating a problem occurred
52
+ during running of the investing_algorithm_framework.
53
+
54
+ This exception is used to indicate that an error occurred during the
55
+ operation of the investing_algorithm_framework, such as during a backtest,
56
+ strategy execution, or any other operational aspect of the framework.
57
+
58
+ Attributes:
59
+ message (str): The error message to be returned in the response.
60
+ """
61
+ def __init__(self, message) -> None:
62
+ super(OperationalException, self).__init__(message)
63
+ self.error_message = message
64
+
65
+ def to_response(self):
66
+ return {
67
+ "status": "error",
68
+ "message": self.error_message
69
+ }
70
+
71
+
72
+ class NetworkError(Exception):
73
+ """
74
+ Class NetworkError: Exception class indicating a problem occurred
75
+ during making a netwok request
76
+ """
77
+
78
+ def __init__(self, message) -> None:
79
+ super(NetworkError, self).__init__(message)
80
+ self.error_message = message
81
+
82
+ def to_response(self):
83
+ return {
84
+ "status": "error",
85
+ "message": self.error_message
86
+ }
87
+
88
+
89
+ class DataError(Exception):
90
+ """
91
+ Class DataError: Exception class indicating a problem occurred
92
+ during data retrieval or processing
93
+ """
94
+
95
+ def __init__(
96
+ self,
97
+ message,
98
+ data_source_file_path: str = None,
99
+ number_of_missing_data_points: int = None,
100
+ total_number_of_data_points: int = None,
101
+ ) -> None:
102
+ super(DataError, self).__init__(message)
103
+ self.error_message = message
104
+ self.data_source_file_path = data_source_file_path
105
+ self.number_of_missing_data_points = number_of_missing_data_points
106
+ self.total_number_of_data_points = total_number_of_data_points
107
+
108
+ def to_response(self):
109
+ return {
110
+ "status": "error",
111
+ "message": self.error_message
112
+ }
@@ -0,0 +1,43 @@
1
+ from .app_mode import AppMode
2
+ from .market import MarketCredential
3
+ from .order import OrderStatus, OrderSide, OrderType, Order
4
+ from .portfolio import PortfolioConfiguration, Portfolio, PortfolioSnapshot
5
+ from .position import Position, PositionSnapshot
6
+ from .strategy_profile import StrategyProfile
7
+ from .time_frame import TimeFrame
8
+ from .time_interval import TimeInterval
9
+ from .time_unit import TimeUnit
10
+ from .trade import Trade, TradeStatus, TradeStopLoss, TradeTakeProfit, \
11
+ TradeRiskType
12
+ from .snapshot_interval import SnapshotInterval
13
+ from .event import Event
14
+ from .data import DataSource, DataType
15
+
16
+ __all__ = [
17
+ "OrderStatus",
18
+ "OrderSide",
19
+ "OrderType",
20
+ "Order",
21
+ "TimeFrame",
22
+ "TimeInterval",
23
+ "TimeUnit",
24
+ "PortfolioConfiguration",
25
+ "Position",
26
+ "Portfolio",
27
+ "PositionSnapshot",
28
+ "PortfolioSnapshot",
29
+ "StrategyProfile",
30
+ "Trade",
31
+ "MarketCredential",
32
+ "TradeStatus",
33
+ "DataType",
34
+ "AppMode",
35
+ "DataSource",
36
+ "AppMode",
37
+ "TradeStopLoss",
38
+ "TradeTakeProfit",
39
+ "TradeRiskType",
40
+ "DataSource",
41
+ "SnapshotInterval",
42
+ "Event",
43
+ ]
@@ -0,0 +1,34 @@
1
+ from enum import Enum
2
+
3
+
4
+ class AppMode(Enum):
5
+ STATELESS = "STATELESS"
6
+ DEFAULT = "DEFAULT"
7
+ WEB = "WEB"
8
+
9
+ @staticmethod
10
+ def from_string(value: str):
11
+
12
+ if isinstance(value, str):
13
+ for status in AppMode:
14
+
15
+ if value.upper() == status.value:
16
+ return status
17
+
18
+ raise ValueError("Could not convert value to AppMode")
19
+
20
+ @staticmethod
21
+ def from_value(value):
22
+
23
+ if isinstance(value, AppMode):
24
+ for status in AppMode:
25
+
26
+ if value == status:
27
+ return status
28
+ elif isinstance(value, str):
29
+ return AppMode.from_string(value)
30
+
31
+ raise ValueError(f"Could not convert value {value} to AppMode")
32
+
33
+ def equals(self, other):
34
+ return AppMode.from_value(other) == self
@@ -0,0 +1,25 @@
1
+ class BaseModel:
2
+
3
+ def repr(self, **fields) -> str:
4
+ """
5
+ Helper for __repr__
6
+ """
7
+
8
+ field_strings = []
9
+ at_least_one_attached_attribute = False
10
+
11
+ for key, field in fields.items():
12
+ field_strings.append(f'{key}={field!r}')
13
+ at_least_one_attached_attribute = True
14
+
15
+ if at_least_one_attached_attribute:
16
+ return f"<{self.__class__.__name__}({','.join(field_strings)})>"
17
+
18
+ return f"<{self.__class__.__name__} {id(self)}>"
19
+
20
+ def update(self, data):
21
+
22
+ for attr, value in data.items():
23
+
24
+ if value is not None:
25
+ setattr(self, attr, value)
@@ -0,0 +1,7 @@
1
+ from .data_source import DataSource
2
+ from .data_type import DataType
3
+
4
+ __all__ = [
5
+ "DataSource",
6
+ "DataType",
7
+ ]