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