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
@@ -1,630 +0,0 @@
1
- import logging
2
- from typing import List
3
-
4
- from investing_algorithm_framework.domain import OrderStatus, OrderFee, \
5
- Position, Order, Portfolio, OrderType, OrderSide, ApiException, \
6
- BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME, Trade
7
-
8
- logger = logging.getLogger("investing_algorithm_framework")
9
-
10
-
11
- class Algorithm:
12
-
13
- def __init__(
14
- self,
15
- configuration_service,
16
- portfolio_configuration_service,
17
- portfolio_service,
18
- position_service,
19
- order_service,
20
- market_service,
21
- market_data_service,
22
- strategy_orchestrator_service,
23
- ):
24
- self.portfolio_service = portfolio_service
25
- self.position_service = position_service
26
- self.order_service = order_service
27
- self.market_service = market_service
28
- self.configuration_service = configuration_service
29
- self.portfolio_configuration_service = portfolio_configuration_service
30
- self.strategy_orchestrator_service = strategy_orchestrator_service
31
- self.market_data_service = market_data_service
32
-
33
- def start(self, number_of_iterations=None, stateless=False):
34
-
35
- if not stateless:
36
- self.strategy_orchestrator_service.start(
37
- algorithm=self,
38
- number_of_iterations=number_of_iterations
39
- )
40
-
41
- @property
42
- def config(self):
43
- return self.configuration_service.config
44
-
45
- @property
46
- def running(self) -> bool:
47
- return self.strategy_orchestrator_service.running
48
-
49
- def run_jobs(self):
50
- self.strategy_orchestrator_service.run_pending_jobs()
51
-
52
- def create_order(
53
- self,
54
- target_symbol,
55
- price,
56
- order_type,
57
- order_side,
58
- amount,
59
- market=None,
60
- execute=True,
61
- validate=True,
62
- sync=True
63
- ):
64
- portfolio = self.portfolio_service.find({"market": market})
65
- order_data = {
66
- "target_symbol": target_symbol,
67
- "price": price,
68
- "amount": amount,
69
- "order_type": order_type,
70
- "order_side": order_side,
71
- "portfolio_id": portfolio.id,
72
- "status": OrderStatus.CREATED.value,
73
- "trading_symbol": portfolio.trading_symbol,
74
- }
75
-
76
- if BACKTESTING_FLAG in self.configuration_service.config \
77
- and self.configuration_service.config[BACKTESTING_FLAG]:
78
- order_data["created_at"] = \
79
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
80
-
81
- return self.order_service.create(
82
- order_data, execute=execute, validate=validate, sync=sync
83
- )
84
-
85
- def create_limit_order(
86
- self,
87
- target_symbol,
88
- price,
89
- order_side,
90
- amount=None,
91
- percentage_of_portfolio=None,
92
- percentage_of_position=None,
93
- precision=3,
94
- market=None,
95
- execute=True,
96
- validate=True,
97
- sync=True
98
- ):
99
- portfolio = self.portfolio_service.find({"market": market})
100
-
101
- if percentage_of_portfolio is not None:
102
- if not OrderSide.BUY.equals(order_side):
103
- raise ApiException(
104
- "Percentage of portfolio is only supported for BUY orders."
105
- )
106
-
107
- percentage_of_portfolio = percentage_of_portfolio
108
- net_size = portfolio.get_net_size()
109
- size = net_size * percentage_of_portfolio / 100
110
- amount = size / price
111
- amount = self.round_down(amount, precision)
112
-
113
- elif percentage_of_position is not None:
114
-
115
- if not OrderSide.SELL.equals(order_side):
116
- raise ApiException(
117
- "Percentage of position is only supported for SELL orders."
118
- )
119
-
120
- position = self.position_service.find(
121
- {
122
- "symbol": target_symbol,
123
- "portfolio": portfolio.id
124
- }
125
- )
126
- amount = position.get_amount() * (percentage_of_position / 100)
127
-
128
- order_data = {
129
- "target_symbol": target_symbol,
130
- "price": price,
131
- "amount": amount,
132
- "order_type": OrderType.LIMIT.value,
133
- "order_side": OrderSide.from_value(order_side).value,
134
- "portfolio_id": portfolio.id,
135
- "status": OrderStatus.CREATED.value,
136
- "trading_symbol": portfolio.trading_symbol,
137
- }
138
-
139
- if BACKTESTING_FLAG in self.configuration_service.config \
140
- and self.configuration_service.config[BACKTESTING_FLAG]:
141
- order_data["created_at"] = \
142
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
143
-
144
- return self.order_service.create(
145
- order_data, execute=execute, validate=validate, sync=sync
146
- )
147
-
148
- def create_market_order(
149
- self,
150
- target_symbol,
151
- order_side,
152
- amount,
153
- market=None,
154
- execute=False,
155
- validate=False,
156
- sync=True
157
- ):
158
- portfolio = self.portfolio_service.find({"market": market})
159
- order_data = {
160
- "target_symbol": target_symbol,
161
- "amount": amount,
162
- "order_type": OrderType.MARKET.value,
163
- "order_side": OrderSide.from_value(order_side).value,
164
- "portfolio_id": portfolio.id,
165
- "status": OrderStatus.CREATED.value,
166
- "trading_symbol": portfolio.trading_symbol,
167
- }
168
-
169
- if BACKTESTING_FLAG in self.configuration_service.config \
170
- and self.configuration_service.config[BACKTESTING_FLAG]:
171
- order_data["created_at"] = \
172
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
173
-
174
- return self.order_service.create(
175
- order_data, execute=execute, validate=validate, sync=sync
176
- )
177
-
178
- def get_portfolio(self, market=None) -> Portfolio:
179
-
180
- if market is None:
181
- return self.portfolio_service.find({})
182
-
183
- return self.portfolio_service.find({{"market": market}})
184
-
185
- def get_unallocated(self, market=None) -> Position:
186
-
187
- if market:
188
- portfolio = self.portfolio_service.find({{"market": market}})
189
- else:
190
- portfolio = self.portfolio_service.find({})
191
-
192
- trading_symbol = portfolio.trading_symbol
193
- return self.position_service.find(
194
- {"portfolio": portfolio.id, "symbol": trading_symbol}
195
- ).get_amount()
196
-
197
- def reset(self):
198
- self._workers = []
199
- self._running_workers = []
200
-
201
- def get_order(
202
- self,
203
- reference_id=None,
204
- market=None,
205
- target_symbol=None,
206
- trading_symbol=None,
207
- order_side=None,
208
- order_type=None
209
- ) -> Order:
210
- query_params = {}
211
-
212
- if reference_id:
213
- query_params["reference_id"] = reference_id
214
-
215
- if target_symbol:
216
- query_params["target_symbol"] = target_symbol
217
-
218
- if trading_symbol:
219
- query_params["trading_symbol"] = trading_symbol
220
-
221
- if order_side:
222
- query_params["order_side"] = order_side
223
-
224
- if order_type:
225
- query_params["order_type"] = order_type
226
-
227
- if market:
228
- portfolio = self.portfolio_service.find({"market": market})
229
- positions = self.position_service.get_all(
230
- {"portfolio": portfolio.id}
231
- )
232
- query_params["position"] = [position.id for position in positions]
233
-
234
- return self.order_service.find(query_params)
235
-
236
- def get_orders(
237
- self,
238
- target_symbol=None,
239
- status=None,
240
- order_type=None,
241
- order_side=None,
242
- market=None
243
- ) -> List[Order]:
244
-
245
- if market is None:
246
- portfolio = self.portfolio_service.get_all()[0]
247
- else:
248
- portfolio = self.portfolio_service.find({"market": market})
249
-
250
- positions = self.position_service.get_all({"portfolio": portfolio.id})
251
- return self.order_service.get_all(
252
- {
253
- "position": [position.id for position in positions],
254
- "target_symbol": target_symbol,
255
- "status": status,
256
- "order_type": order_type,
257
- "order_side": order_side
258
- }
259
- )
260
-
261
- def get_order_fee(self, order_id) -> OrderFee:
262
- return self.order_service.get_order_fee(order_id)
263
-
264
- def get_positions(
265
- self,
266
- market=None,
267
- identifier=None,
268
- amount_gt=None,
269
- amount_gte=None,
270
- amount_lt=None,
271
- amount_lte=None
272
- ) -> List[Position]:
273
- query_params = {}
274
-
275
- if market is not None:
276
- query_params["market"] = market
277
-
278
- if identifier is not None:
279
- query_params["identifier"] = identifier
280
-
281
- if amount_gt is not None:
282
- query_params["amount_gt"] = amount_gt
283
-
284
- if amount_gte is not None:
285
- query_params["amount_gte"] = amount_gte
286
-
287
- if amount_lt is not None:
288
- query_params["amount_lt"] = amount_lt
289
-
290
- if amount_lte is not None:
291
- query_params["amount_lte"] = amount_lte
292
-
293
- portfolios = self.portfolio_service.get_all(query_params)
294
-
295
- if not portfolios:
296
- raise ApiException("No portfolio found.")
297
-
298
- portfolio = portfolios[0]
299
- return self.position_service.get_all(
300
- {"portfolio": portfolio.id}
301
- )
302
-
303
- def get_position(self, symbol, market=None, identifier=None) -> Position:
304
- query_params = {}
305
-
306
- if market is not None:
307
- query_params["market"] = market
308
-
309
- if identifier is not None:
310
- query_params["identifier"] = identifier
311
-
312
- portfolios = self.portfolio_service.get_all(query_params)
313
-
314
- if not portfolios:
315
- raise ApiException("No portfolio found.")
316
-
317
- portfolio = portfolios[0]
318
-
319
- try:
320
- return self.position_service.find(
321
- {"portfolio": portfolio.id, "symbol": symbol}
322
- )
323
- except ApiException:
324
- return None
325
-
326
- def has_position(
327
- self,
328
- symbol,
329
- market=None,
330
- identifier=None,
331
- amount_gt=0,
332
- amount_gte=None,
333
- amount_lt=None,
334
- amount_lte=None
335
- ):
336
- return self.position_exists(
337
- symbol,
338
- market,
339
- identifier,
340
- amount_gt,
341
- amount_gte,
342
- amount_lt,
343
- amount_lte
344
- )
345
-
346
- def position_exists(
347
- self,
348
- symbol,
349
- market=None,
350
- identifier=None,
351
- amount_gt=None,
352
- amount_gte=None,
353
- amount_lt=None,
354
- amount_lte=None
355
- ) -> bool:
356
- query_params = {}
357
-
358
- if market is not None:
359
- query_params["market"] = market
360
-
361
- if identifier is not None:
362
- query_params["identifier"] = identifier
363
-
364
- if amount_gt is not None:
365
- query_params["amount_gt"] = amount_gt
366
-
367
- if amount_gte is not None:
368
- query_params["amount_gte"] = amount_gte
369
-
370
- if amount_lt is not None:
371
- query_params["amount_lt"] = amount_lt
372
-
373
- if amount_lte is not None:
374
- query_params["amount_lte"] = amount_lte
375
-
376
- query_params["symbol"] = symbol
377
- return self.position_service.exists(query_params)
378
-
379
- def get_position_percentage(
380
- self, symbol, market=None, identifier=None
381
- ) -> float:
382
- query_params = {}
383
-
384
- if market is not None:
385
- query_params["market"] = market
386
-
387
- if identifier is not None:
388
- query_params["identifier"] = identifier
389
-
390
- portfolios = self.portfolio_service.get_all(query_params)
391
-
392
- if not portfolios:
393
- raise ApiException("No portfolio found.")
394
-
395
- portfolio = portfolios[0]
396
- position = self.position_service.find(
397
- {"portfolio": portfolio.id, "symbol": symbol}
398
- )
399
- ticker = self.market_service.get_ticker(
400
- f"{symbol.upper()}/{portfolio.trading_symbol.upper()}"
401
- )
402
- return (position.amount * ticker["bid"] /
403
- self.get_allocated(identifier=portfolio.identifier)) * 100
404
-
405
- def close_position(self, symbol, market=None, identifier=None):
406
- portfolio = self.portfolio_service.find(
407
- {"market": market, "identifier": identifier}
408
- )
409
- portfolio_config = self.portfolio_configuration_service.find(
410
- {"portfolio": portfolio.id}
411
- )
412
- self.market_service.initialize(portfolio_config)
413
- position = self.position_service.find(
414
- {"portfolio": portfolio.id, "symbol": symbol}
415
- )
416
-
417
- if position.get_amount() == 0:
418
- return
419
-
420
- for order in self.order_service \
421
- .get_all({
422
- "position": position.id, "status": OrderStatus.OPEN.value
423
- }):
424
- self.market_service.cancel_order(order.id)
425
-
426
- ticker = self.market_service.get_ticker(
427
- symbol=f"{symbol.upper()}/{portfolio.trading_symbol.upper()}"
428
- )
429
- self.create_limit_order(
430
- target_symbol=position.symbol,
431
- amount=position.get_amount(),
432
- order_side=OrderSide.SELL.value,
433
- price=ticker["bid"],
434
- )
435
-
436
- def add_strategies(self, strategies):
437
- self.strategy_orchestrator_service.add_strategies(strategies)
438
-
439
- def add_tasks(self, tasks):
440
- self.strategy_orchestrator_service.add_tasks(tasks)
441
-
442
- @property
443
- def strategies(self):
444
- return self.strategy_orchestrator_service.get_strategies()
445
-
446
- def get_strategy(self, strategy_id):
447
- for strategy in self.strategy_orchestrator_service.get_strategies():
448
- if strategy.worker_id == strategy_id:
449
- return strategy
450
-
451
- return None
452
-
453
- def get_allocated(self, market=None, identifier=None) -> float:
454
-
455
- if self.portfolio_configuration_service.count() > 1 \
456
- and identifier is None and market is None:
457
- raise ApiException(
458
- "Multiple portfolios found. Please specify a "
459
- "portfolio identifier."
460
- )
461
-
462
- if market is not None and identifier is not None:
463
- portfolio_configurations = self.portfolio_configuration_service \
464
- .get_all()
465
-
466
- else:
467
- query_params = {
468
- "market": market,
469
- "identifier": identifier
470
- }
471
- portfolio_configurations = [self.portfolio_configuration_service
472
- .find(query_params)]
473
-
474
- portfolios = []
475
-
476
- for portfolio_configuration in portfolio_configurations:
477
- portfolio = self.portfolio_service.find(
478
- {"identifier": portfolio_configuration.identifier}
479
- )
480
- portfolio.configuration = portfolio_configuration
481
- portfolios.append(portfolio)
482
-
483
- allocated = 0
484
-
485
- for portfolio in portfolios:
486
- positions = self.position_service.get_all(
487
- {"portfolio": portfolio.id}
488
- )
489
-
490
- for position in positions:
491
- if portfolio.trading_symbol == position.symbol:
492
- continue
493
-
494
- symbol = f"{position.symbol.upper()}/" \
495
- f"{portfolio.trading_symbol.upper()}"
496
- self.market_service.initialize(portfolio.configuration)
497
- price = self.market_service.get_ticker(symbol)
498
- allocated = allocated + \
499
- (position.get_amount() * price["bid"])
500
-
501
- return allocated
502
-
503
- def get_unfilled(self, market=None, identifier=None) -> float:
504
-
505
- if self.portfolio_configuration_service.count() > 1 \
506
- and identifier is None and market is None:
507
- raise ApiException(
508
- "Multiple portfolios found. Please specify a "
509
- "portfolio identifier."
510
- )
511
-
512
- if market is not None and identifier is not None:
513
- portfolio_configurations = self.portfolio_configuration_service \
514
- .get_all()
515
-
516
- else:
517
- query_params = {
518
- "market": market,
519
- "identifier": identifier
520
- }
521
- portfolio_configurations = [self.portfolio_configuration_service
522
- .find(query_params)]
523
-
524
- portfolios = []
525
-
526
- for portfolio_configuration in portfolio_configurations:
527
- portfolio = self.portfolio_service.find(
528
- {"identifier": portfolio_configuration.identifier}
529
- )
530
- portfolios.append(portfolio)
531
-
532
- unfilled = 0
533
-
534
- for portfolio in portfolios:
535
- orders = self.order_service.get_all(
536
- {"status": OrderStatus.OPEN.value, "portfolio": portfolio.id}
537
- )
538
- unfilled = unfilled \
539
- + sum(
540
- [order.get_amount() * order.get_price() for order in orders])
541
-
542
- return unfilled
543
-
544
- def get_portfolio_configurations(self):
545
- return self.portfolio_configuration_service.get_all()
546
-
547
- def has_open_buy_orders(self, target_symbol, identifier=None, market=None):
548
- query_params = {}
549
-
550
- if identifier is not None:
551
- portfolio = self.portfolio_service.find(
552
- {"identifier": identifier}
553
- )
554
- query_params["portfolio"] = portfolio.id
555
-
556
- if market is not None:
557
- portfolio = self.portfolio_service.find(
558
- {"market": market}
559
- )
560
- query_params["portfolio"] = portfolio.id
561
-
562
- query_params["target_symbol"] = target_symbol
563
- query_params["order_side"] = OrderSide.BUY.value
564
- query_params["status"] = OrderStatus.OPEN.value
565
- return self.order_service.exists(query_params)
566
-
567
- def has_open_sell_orders(self, target_symbol, identifier=None,
568
- market=None):
569
- query_params = {}
570
-
571
- if identifier is not None:
572
- portfolio = self.portfolio_service.find(
573
- {"identifier": identifier}
574
- )
575
- query_params["portfolio"] = portfolio.id
576
-
577
- if market is not None:
578
- portfolio = self.portfolio_service.find(
579
- {"market": market}
580
- )
581
- query_params["portfolio"] = portfolio.id
582
-
583
- query_params["target_symbol"] = target_symbol
584
- query_params["order_side"] = OrderSide.SELL.value
585
- query_params["status"] = OrderStatus.OPEN.value
586
- return self.order_service.exists(query_params)
587
-
588
- def has_open_orders(self, target_symbol, identifier=None, market=None):
589
- query_params = {}
590
-
591
- if identifier is not None:
592
- portfolio = self.portfolio_service.find(
593
- {"identifier": identifier}
594
- )
595
- query_params["portfolio"] = portfolio.id
596
-
597
- if market is not None:
598
- portfolio = self.portfolio_service.find(
599
- {"market": market}
600
- )
601
- query_params["portfolio"] = portfolio.id
602
-
603
- query_params["target_symbol"] = target_symbol
604
- query_params["status"] = OrderStatus.OPEN.value
605
- return self.order_service.exists(query_params)
606
-
607
- def check_pending_orders(self):
608
- self.order_service.check_pending_orders()
609
-
610
- def get_trades(self):
611
- buy_orders = self.order_service.get_all({
612
- "status": OrderStatus.CLOSED.value,
613
- "order_side": OrderSide.BUY.value
614
- })
615
- return [
616
- Trade(
617
- target_symbol=order.get_target_symbol(),
618
- trading_symbol=order.get_trading_symbol(),
619
- amount=order.get_amount(),
620
- open_price=order.get_price(),
621
- closed_price=order.get_trade_closed_price(),
622
- closed_at=order.get_trade_closed_at(),
623
- opened_at=order.get_created_at()
624
- ) for order in buy_orders
625
- if order.get_trade_closed_at() is not None
626
- ]
627
-
628
- def round_down(self, value, decimals):
629
- factor = 1 / (10 ** decimals)
630
- return (value // factor) * factor