investing-algorithm-framework 1.3.1__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 (282) hide show
  1. investing_algorithm_framework/__init__.py +195 -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 +31 -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 +2233 -264
  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/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/action_handlers/__init__.py +6 -3
  37. investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
  38. investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +2 -1
  39. investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
  40. investing_algorithm_framework/app/stateless/exception_handler.py +1 -1
  41. investing_algorithm_framework/app/strategy.py +873 -52
  42. investing_algorithm_framework/app/task.py +5 -3
  43. investing_algorithm_framework/app/web/__init__.py +2 -1
  44. investing_algorithm_framework/app/web/controllers/__init__.py +2 -2
  45. investing_algorithm_framework/app/web/controllers/orders.py +4 -3
  46. investing_algorithm_framework/app/web/controllers/portfolio.py +1 -1
  47. investing_algorithm_framework/app/web/controllers/positions.py +3 -3
  48. investing_algorithm_framework/app/web/create_app.py +4 -2
  49. investing_algorithm_framework/app/web/error_handler.py +1 -1
  50. investing_algorithm_framework/app/web/schemas/order.py +2 -2
  51. investing_algorithm_framework/app/web/schemas/position.py +1 -0
  52. investing_algorithm_framework/cli/__init__.py +0 -0
  53. investing_algorithm_framework/cli/cli.py +231 -0
  54. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
  55. investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
  56. investing_algorithm_framework/cli/initialize_app.py +603 -0
  57. investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
  58. investing_algorithm_framework/cli/templates/app.py.template +18 -0
  59. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
  60. investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
  61. investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
  62. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  63. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  64. investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
  65. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
  66. investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
  67. investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
  68. investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
  69. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
  70. investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
  71. investing_algorithm_framework/cli/templates/env.example.template +2 -0
  72. investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
  73. investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
  74. investing_algorithm_framework/cli/templates/readme.md.template +135 -0
  75. investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
  76. investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
  77. investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
  78. investing_algorithm_framework/cli/validate_backtest_checkpoints.py +197 -0
  79. investing_algorithm_framework/create_app.py +43 -9
  80. investing_algorithm_framework/dependency_container.py +121 -33
  81. investing_algorithm_framework/domain/__init__.py +109 -22
  82. investing_algorithm_framework/domain/algorithm_id.py +69 -0
  83. investing_algorithm_framework/domain/backtesting/__init__.py +25 -0
  84. investing_algorithm_framework/domain/backtesting/backtest.py +548 -0
  85. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +113 -0
  86. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +241 -0
  87. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +470 -0
  88. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  89. investing_algorithm_framework/domain/backtesting/backtest_run.py +663 -0
  90. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  91. investing_algorithm_framework/domain/backtesting/backtest_utils.py +198 -0
  92. investing_algorithm_framework/domain/backtesting/combine_backtests.py +392 -0
  93. investing_algorithm_framework/domain/config.py +60 -138
  94. investing_algorithm_framework/domain/constants.py +23 -34
  95. investing_algorithm_framework/domain/data_provider.py +334 -0
  96. investing_algorithm_framework/domain/data_structures.py +42 -0
  97. investing_algorithm_framework/domain/decimal_parsing.py +40 -0
  98. investing_algorithm_framework/domain/exceptions.py +51 -1
  99. investing_algorithm_framework/domain/models/__init__.py +29 -14
  100. investing_algorithm_framework/domain/models/app_mode.py +34 -0
  101. investing_algorithm_framework/domain/models/base_model.py +3 -1
  102. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  103. investing_algorithm_framework/domain/models/data/data_source.py +222 -0
  104. investing_algorithm_framework/domain/models/data/data_type.py +46 -0
  105. investing_algorithm_framework/domain/models/event.py +35 -0
  106. investing_algorithm_framework/domain/models/market/__init__.py +5 -0
  107. investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
  108. investing_algorithm_framework/domain/models/order/__init__.py +3 -4
  109. investing_algorithm_framework/domain/models/order/order.py +243 -86
  110. investing_algorithm_framework/domain/models/order/order_status.py +2 -2
  111. investing_algorithm_framework/domain/models/order/order_type.py +1 -3
  112. investing_algorithm_framework/domain/models/portfolio/__init__.py +7 -2
  113. investing_algorithm_framework/domain/models/portfolio/portfolio.py +134 -1
  114. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -37
  115. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +208 -0
  116. investing_algorithm_framework/domain/models/position/__init__.py +3 -2
  117. investing_algorithm_framework/domain/models/position/position.py +29 -0
  118. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  119. investing_algorithm_framework/domain/models/position/{position_cost.py → position_snapshot.py} +16 -8
  120. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  121. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  122. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -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 +94 -98
  126. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  127. investing_algorithm_framework/domain/models/time_unit.py +111 -2
  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 +11 -0
  131. investing_algorithm_framework/domain/models/trade/trade.py +389 -0
  132. investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
  133. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
  134. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
  135. investing_algorithm_framework/domain/order_executor.py +112 -0
  136. investing_algorithm_framework/domain/portfolio_provider.py +118 -0
  137. investing_algorithm_framework/domain/services/__init__.py +11 -0
  138. investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
  139. investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
  140. investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
  141. investing_algorithm_framework/domain/services/rounding_service.py +27 -0
  142. investing_algorithm_framework/domain/services/state_handler.py +38 -0
  143. investing_algorithm_framework/domain/strategy.py +1 -29
  144. investing_algorithm_framework/domain/utils/__init__.py +16 -4
  145. investing_algorithm_framework/domain/utils/csv.py +22 -0
  146. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  147. investing_algorithm_framework/domain/utils/dates.py +57 -0
  148. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  149. investing_algorithm_framework/domain/utils/polars.py +53 -0
  150. investing_algorithm_framework/domain/utils/random.py +29 -0
  151. investing_algorithm_framework/download_data.py +244 -0
  152. investing_algorithm_framework/infrastructure/__init__.py +39 -11
  153. investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
  154. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1152 -0
  155. investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
  156. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  157. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  158. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +87 -13
  159. investing_algorithm_framework/infrastructure/models/__init__.py +13 -4
  160. investing_algorithm_framework/infrastructure/models/decimal_parser.py +14 -0
  161. investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
  162. investing_algorithm_framework/infrastructure/models/order/order.py +73 -73
  163. investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
  164. investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
  165. investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +3 -2
  166. investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +37 -0
  167. investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +57 -3
  168. investing_algorithm_framework/infrastructure/models/position/__init__.py +2 -2
  169. investing_algorithm_framework/infrastructure/models/position/position.py +16 -11
  170. investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +23 -0
  171. investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
  172. investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
  173. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
  174. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
  175. investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
  176. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  177. investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
  178. investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
  179. investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
  180. investing_algorithm_framework/infrastructure/repositories/__init__.py +13 -5
  181. investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
  182. investing_algorithm_framework/infrastructure/repositories/order_repository.py +32 -19
  183. investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
  184. investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +56 -0
  185. investing_algorithm_framework/infrastructure/repositories/position_repository.py +47 -4
  186. investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +21 -0
  187. investing_algorithm_framework/infrastructure/repositories/repository.py +85 -31
  188. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
  189. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
  190. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
  191. investing_algorithm_framework/infrastructure/services/__init__.py +9 -2
  192. investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
  193. investing_algorithm_framework/infrastructure/services/aws/state_handler.py +193 -0
  194. investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
  195. investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
  196. investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +9 -0
  197. investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +2596 -0
  198. investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +285 -0
  199. investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +468 -0
  200. investing_algorithm_framework/services/__init__.py +127 -10
  201. investing_algorithm_framework/services/configuration_service.py +95 -0
  202. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  203. investing_algorithm_framework/services/data_providers/data_provider_service.py +1058 -0
  204. investing_algorithm_framework/services/market_credential_service.py +40 -0
  205. investing_algorithm_framework/services/metrics/__init__.py +119 -0
  206. investing_algorithm_framework/services/metrics/alpha.py +0 -0
  207. investing_algorithm_framework/services/metrics/beta.py +0 -0
  208. investing_algorithm_framework/services/metrics/cagr.py +60 -0
  209. investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
  210. investing_algorithm_framework/services/metrics/drawdown.py +218 -0
  211. investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
  212. investing_algorithm_framework/services/metrics/exposure.py +210 -0
  213. investing_algorithm_framework/services/metrics/generate.py +358 -0
  214. investing_algorithm_framework/services/metrics/mean_daily_return.py +84 -0
  215. investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
  216. investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
  217. investing_algorithm_framework/services/metrics/recovery.py +113 -0
  218. investing_algorithm_framework/services/metrics/returns.py +452 -0
  219. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  220. investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
  221. investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
  222. investing_algorithm_framework/services/metrics/standard_deviation.py +156 -0
  223. investing_algorithm_framework/services/metrics/trades.py +473 -0
  224. investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  225. investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  226. investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  227. investing_algorithm_framework/services/metrics/volatility.py +118 -0
  228. investing_algorithm_framework/services/metrics/win_rate.py +177 -0
  229. investing_algorithm_framework/services/order_service/__init__.py +9 -0
  230. investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
  231. investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
  232. investing_algorithm_framework/services/order_service/order_service.py +826 -0
  233. investing_algorithm_framework/services/portfolios/__init__.py +16 -0
  234. investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
  235. investing_algorithm_framework/services/{portfolio_configuration_service.py → portfolios/portfolio_configuration_service.py} +27 -12
  236. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
  237. investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
  238. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
  239. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
  240. investing_algorithm_framework/services/positions/__init__.py +7 -0
  241. investing_algorithm_framework/services/positions/position_service.py +210 -0
  242. investing_algorithm_framework/services/positions/position_snapshot_service.py +18 -0
  243. investing_algorithm_framework/services/repository_service.py +8 -2
  244. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  245. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +117 -0
  246. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  247. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  248. investing_algorithm_framework/services/trade_service/__init__.py +9 -0
  249. investing_algorithm_framework/services/trade_service/trade_service.py +1099 -0
  250. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  251. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  252. investing_algorithm_framework-7.25.6.dist-info/METADATA +535 -0
  253. investing_algorithm_framework-7.25.6.dist-info/RECORD +268 -0
  254. {investing_algorithm_framework-1.3.1.dist-info → investing_algorithm_framework-7.25.6.dist-info}/WHEEL +1 -2
  255. investing_algorithm_framework-7.25.6.dist-info/entry_points.txt +3 -0
  256. investing_algorithm_framework/app/algorithm.py +0 -410
  257. investing_algorithm_framework/domain/models/market_data/__init__.py +0 -11
  258. investing_algorithm_framework/domain/models/market_data/asset_price.py +0 -50
  259. investing_algorithm_framework/domain/models/market_data/ohlcv.py +0 -76
  260. investing_algorithm_framework/domain/models/market_data/order_book.py +0 -63
  261. investing_algorithm_framework/domain/models/market_data/ticker.py +0 -92
  262. investing_algorithm_framework/domain/models/order/order_fee.py +0 -45
  263. investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
  264. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -205
  265. investing_algorithm_framework/domain/singleton.py +0 -9
  266. investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
  267. investing_algorithm_framework/infrastructure/models/position/position_cost.py +0 -32
  268. investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
  269. investing_algorithm_framework/infrastructure/repositories/position_cost_repository.py +0 -16
  270. investing_algorithm_framework/infrastructure/services/market_service.py +0 -422
  271. investing_algorithm_framework/services/market_data_service.py +0 -75
  272. investing_algorithm_framework/services/order_service.py +0 -464
  273. investing_algorithm_framework/services/portfolio_service.py +0 -105
  274. investing_algorithm_framework/services/position_cost_service.py +0 -5
  275. investing_algorithm_framework/services/position_service.py +0 -50
  276. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -219
  277. investing_algorithm_framework/setup_logging.py +0 -40
  278. investing_algorithm_framework-1.3.1.dist-info/AUTHORS.md +0 -8
  279. investing_algorithm_framework-1.3.1.dist-info/METADATA +0 -172
  280. investing_algorithm_framework-1.3.1.dist-info/RECORD +0 -103
  281. investing_algorithm_framework-1.3.1.dist-info/top_level.txt +0 -1
  282. {investing_algorithm_framework-1.3.1.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
@@ -0,0 +1,9 @@
1
+ from .trade import SQLTrade
2
+ from .trade_stop_loss import SQLTradeStopLoss
3
+ from .trade_take_profit import SQLTradeTakeProfit
4
+
5
+ __all__ = [
6
+ "SQLTrade",
7
+ "SQLTradeStopLoss",
8
+ "SQLTradeTakeProfit",
9
+ ]
@@ -0,0 +1,130 @@
1
+ from sqlalchemy import Column, Integer, String, DateTime, Float
2
+ from sqlalchemy.orm import relationship
3
+
4
+ from investing_algorithm_framework.domain import Trade, TradeStatus
5
+ from investing_algorithm_framework.infrastructure.database import SQLBaseModel
6
+ from investing_algorithm_framework.infrastructure.models.model_extension \
7
+ import SQLAlchemyModelExtension
8
+ from investing_algorithm_framework.infrastructure.models\
9
+ .order_trade_association import order_trade_association
10
+
11
+
12
+ class SQLTrade(Trade, SQLBaseModel, SQLAlchemyModelExtension):
13
+ """
14
+ SQL Trade model
15
+
16
+ A trade is a combination of a buy and sell order that has been opened or
17
+ closed.
18
+
19
+ A trade is considered opened when a buy order is executed and there is
20
+ no corresponding sell order. A trade is considered closed when a sell
21
+ order is executed and the amount of the sell order is equal or larger
22
+ to the amount of the buy order.
23
+
24
+ A single sell order can close multiple buy orders. Also, a single
25
+ buy order can be closed by multiple sell orders.
26
+
27
+ Attributes:
28
+ orders: str, the id of the buy order
29
+ target_symbol: str, the target symbol of the trade
30
+ trading_symbol: str, the trading symbol of the trade
31
+ closed_at: datetime, the datetime when the trade was closed
32
+ amount: float, the amount of the trade
33
+ available_amount: float, the available amount of the trade
34
+ remaining: float, the remaining amount that is not filled by the
35
+ buy order that opened the trade.
36
+ filled_amount: float, the filled amount of the trade by the buy
37
+ order that opened the trade.
38
+ net_gain: float, the net gain of the trade
39
+ last_reported_price: float, the last reported price of the trade
40
+ last_reported_price_datetime: datetime, the datetime when the last
41
+ reported price was reported
42
+ created_at: datetime, the datetime when the trade was created
43
+ updated_at: datetime, the datetime when the trade was last updated
44
+ status: str, the status of the trade
45
+ """
46
+
47
+ __tablename__ = "trades"
48
+ id = Column(Integer, primary_key=True, unique=True)
49
+ orders = relationship(
50
+ 'SQLOrder',
51
+ secondary=order_trade_association,
52
+ back_populates='trades',
53
+ lazy='joined'
54
+ )
55
+ target_symbol = Column(String)
56
+ trading_symbol = Column(String)
57
+ closed_at = Column(DateTime, default=None)
58
+ opened_at = Column(DateTime, default=None)
59
+ open_price = Column(Float, default=None)
60
+ amount = Column(Float, default=None)
61
+ available_amount = Column(Float, default=None)
62
+ filled_amount = Column(Float, default=None)
63
+ remaining = Column(Float, default=None)
64
+ net_gain = Column(Float, default=0)
65
+ cost = Column(Float, default=0)
66
+ last_reported_price = Column(Float, default=None)
67
+ last_reported_price_datetime = Column(DateTime, default=None)
68
+ high_water_mark = Column(Float, default=None)
69
+ high_water_mark_datetime = Column(DateTime, default=None)
70
+ updated_at = Column(DateTime, default=None)
71
+ status = Column(String, default=TradeStatus.CREATED.value)
72
+ # Stop losses should be actively loaded
73
+ stop_losses = relationship(
74
+ 'SQLTradeStopLoss',
75
+ back_populates='trade',
76
+ lazy='joined'
77
+ )
78
+ # Take profits should be actively loaded
79
+ take_profits = relationship(
80
+ 'SQLTradeTakeProfit',
81
+ back_populates='trade',
82
+ lazy='joined'
83
+ )
84
+
85
+ def __init__(
86
+ self,
87
+ buy_order,
88
+ target_symbol,
89
+ trading_symbol,
90
+ opened_at,
91
+ amount,
92
+ available_amount,
93
+ filled_amount,
94
+ remaining,
95
+ status=TradeStatus.CREATED.value,
96
+ closed_at=None,
97
+ updated_at=None,
98
+ net_gain=0,
99
+ cost=0,
100
+ last_reported_price=None,
101
+ last_reported_price_datetime=None,
102
+ high_water_mark=None,
103
+ high_water_mark_datetime=None,
104
+ sell_orders=[],
105
+ stop_losses=[],
106
+ take_profits=[],
107
+ ):
108
+ self.orders = [buy_order]
109
+ self.open_price = buy_order.price
110
+ self.target_symbol = target_symbol
111
+ self.trading_symbol = trading_symbol
112
+ self.closed_at = closed_at
113
+ self.amount = amount
114
+ self.available_amount = available_amount
115
+ self.filled_amount = filled_amount
116
+ self.remaining = remaining
117
+ self.net_gain = net_gain
118
+ self.cost = cost
119
+ self.last_reported_price = last_reported_price
120
+ self.last_reported_price_datetime = last_reported_price_datetime
121
+ self.high_water_mark = high_water_mark
122
+ self.high_water_mark_datetime = high_water_mark_datetime
123
+ self.opened_at = opened_at
124
+ self.updated_at = updated_at
125
+ self.status = status
126
+ self.stop_losses = stop_losses
127
+ self.take_profits = take_profits
128
+
129
+ if sell_orders is not None:
130
+ self.orders.extend(sell_orders)
@@ -0,0 +1,59 @@
1
+ from sqlalchemy import Column, Integer, String, Float, ForeignKey, Boolean, \
2
+ DateTime
3
+ from sqlalchemy.orm import relationship
4
+
5
+ from investing_algorithm_framework.domain import TradeStopLoss
6
+ from investing_algorithm_framework.infrastructure.database import SQLBaseModel
7
+ from investing_algorithm_framework.infrastructure.models.model_extension \
8
+ import SQLAlchemyModelExtension
9
+
10
+
11
+ class SQLTradeStopLoss(TradeStopLoss, SQLBaseModel, SQLAlchemyModelExtension):
12
+ """
13
+ SQLTradeStopLoss model
14
+
15
+ A trade stop loss is a stop loss strategy for a trade.
16
+
17
+ Attributes:
18
+ - trade (Trade): the trade that the take profit is for
19
+ - percentage (float): the stop loss percentage
20
+ - trailing (bool): indicates whether the stop loss is trailing
21
+ - sell_percentage (float) the percentage of the trade to sell
22
+ when the stop loss is triggered.
23
+ - open_price (float): the price at which the trade was opened.
24
+ - high_water_mark (float): the highest price reached since the trade
25
+ was opened.
26
+ - high_water_mark_date (String): the date when the high water mark
27
+ was reached.
28
+ - stop_loss_price (float): the calculated stop loss price based on
29
+ the high watermark and percentage.
30
+ - sell_prices (String): a serialized list of prices at which
31
+ stop losses were executed.
32
+ - sell_dates (String): a serialized list of dates when
33
+ stop losses were executed.
34
+ - sell_amount (float): the total amount sold due to stop losses.
35
+ - sold_amount (float): the total amount that has been sold due
36
+ to stop losses.
37
+ - active (bool): indicates whether the stop loss is currently active.
38
+ """
39
+
40
+ __tablename__ = "trade_stop_losses"
41
+ id = Column(Integer, primary_key=True, unique=True)
42
+ trade_id = Column(Integer, ForeignKey('trades.id'))
43
+ trade = relationship('SQLTrade', back_populates='stop_losses')
44
+ trailing = Column(Boolean)
45
+ percentage = Column(Float)
46
+ sell_percentage = Column(Float)
47
+ open_price = Column(Float)
48
+ high_water_mark = Column(Float)
49
+ high_water_mark_date = Column(String)
50
+ stop_loss_price = Column(Float)
51
+ sell_prices = Column(String)
52
+ sell_dates = Column(String)
53
+ sell_amount = Column(Float)
54
+ sold_amount = Column(Float)
55
+ active = Column(Boolean)
56
+ triggered = Column(Boolean, default=False)
57
+ triggered_at = Column(DateTime, default=None)
58
+ created_at = Column(DateTime)
59
+ updated_at = Column(DateTime, default=None)
@@ -0,0 +1,55 @@
1
+ from sqlalchemy import Column, Integer, String, Float, ForeignKey, Boolean, \
2
+ DateTime
3
+ from sqlalchemy.orm import relationship
4
+
5
+ from investing_algorithm_framework.domain import TradeTakeProfit
6
+ from investing_algorithm_framework.infrastructure.database import SQLBaseModel
7
+ from investing_algorithm_framework.infrastructure.models.model_extension \
8
+ import SQLAlchemyModelExtension
9
+
10
+
11
+ class SQLTradeTakeProfit(
12
+ TradeTakeProfit, SQLBaseModel, SQLAlchemyModelExtension
13
+ ):
14
+ """
15
+ SQLTradeTakeProfit model
16
+
17
+ A trade take profit is a take profit strategy for a trade.
18
+
19
+ Attributes:
20
+ - trade (Trade): the trade that the take profit is for
21
+ - percentage (float): the take profit percentage
22
+ - trailing (bool): indicates whether the take profit is trailing
23
+ - sell_percentage (float) the percentage of the trade to sell
24
+ when the take profit is triggered.
25
+ - target_price (float): the target price at which to take profit.
26
+ - sell_prices (String): a serialized list of prices at which
27
+ take profits were executed.
28
+ - sell_dates (String): a serialized list of dates when
29
+ take profits were executed.
30
+ - sell_amount (float): the total amount sold due to take profits.
31
+ - sold_amount (float): the total amount that has been sold due
32
+ to take profits.
33
+ - active (bool): indicates whether the take profit is currently active.
34
+ """
35
+
36
+ __tablename__ = "trade_take_profits"
37
+ id = Column(Integer, primary_key=True, unique=True)
38
+ trade_id = Column(Integer, ForeignKey('trades.id'))
39
+ trade = relationship('SQLTrade', back_populates='take_profits')
40
+ trailing = Column(Boolean)
41
+ percentage = Column(Float)
42
+ sell_percentage = Column(Float)
43
+ open_price = Column(Float)
44
+ high_water_mark = Column(Float)
45
+ high_water_mark_date = Column(String)
46
+ sell_prices = Column(String)
47
+ take_profit_price = Column(Float)
48
+ sell_amount = Column(Float)
49
+ sell_dates = Column(String)
50
+ sold_amount = Column(Float)
51
+ active = Column(Boolean)
52
+ triggered = Column(Boolean, default=False)
53
+ triggered_at = Column(DateTime, default=None)
54
+ created_at = Column(DateTime)
55
+ updated_at = Column(DateTime, default=None)
@@ -0,0 +1,21 @@
1
+ from .ccxt_order_executor import CCXTOrderExecutor
2
+ from .backtest_oder_executor import BacktestOrderExecutor
3
+
4
+
5
+ def get_default_order_executors():
6
+ """
7
+ Function to get the default order executors.
8
+
9
+ Returns:
10
+ list: List of default order executors.
11
+ """
12
+ return [
13
+ CCXTOrderExecutor(),
14
+ ]
15
+
16
+
17
+ __all__ = [
18
+ 'CCXTOrderExecutor',
19
+ 'BacktestOrderExecutor',
20
+ 'get_default_order_executors',
21
+ ]
@@ -0,0 +1,28 @@
1
+ from investing_algorithm_framework.domain import OrderExecutor, OrderStatus, \
2
+ INDEX_DATETIME, Order
3
+
4
+
5
+ class BacktestOrderExecutor(OrderExecutor):
6
+ """
7
+ Backtest implementation of order executor. This executor is used to
8
+ simulate order execution in a backtesting environment.
9
+
10
+ !Important: This executor does not actually execute orders on any market.
11
+ It should be used only for backtesting purposes.
12
+ """
13
+
14
+ def execute_order(self, portfolio, order, market_credential) -> Order:
15
+ order.status = OrderStatus.OPEN.value
16
+ order.remaining = order.get_amount()
17
+ order.filled = 0
18
+ order.updated_at = self.config[INDEX_DATETIME]
19
+ return order
20
+
21
+ def cancel_order(self, portfolio, order, market_credential) -> Order:
22
+ order.status = OrderStatus.CANCELED.value
23
+ order.remaining = 0
24
+ order.updated_at = self.config[INDEX_DATETIME]
25
+ return order
26
+
27
+ def supports_market(self, market):
28
+ return True
@@ -0,0 +1,200 @@
1
+ from logging import getLogger
2
+
3
+ import ccxt
4
+
5
+ from investing_algorithm_framework.domain import OrderExecutor, \
6
+ OperationalException, Order, OrderStatus, OrderSide, OrderType, \
7
+ MarketCredential
8
+
9
+ logger = getLogger("investing_algorithm_framework")
10
+
11
+
12
+ class CCXTOrderExecutor(OrderExecutor):
13
+ """
14
+ CCXTOrderExecutor is a class that implements the OrderExecutor
15
+ interface for executing orders using the CCXT library.
16
+ """
17
+
18
+ def execute_order(self, portfolio, order, market_credential) -> Order:
19
+ """
20
+ Executes an order for a given portfolio on a CCXT exchange.
21
+
22
+ Args:
23
+ order: The order to be executed
24
+ portfolio: The portfolio in which the order will be executed
25
+ market_credential: The market credential to use for the order
26
+
27
+ Returns:
28
+ Order: Instance of the executed order. The order instance
29
+ should copy the id of the order that has been provided as a
30
+ """
31
+ market = portfolio.market
32
+ exchange = self.initialize_exchange(market, market_credential)
33
+ symbol = order.get_symbol()
34
+ amount = order.get_amount()
35
+ price = order.get_price()
36
+ order_type = order.get_order_type()
37
+ order_side = order.get_order_side()
38
+
39
+ try:
40
+ if OrderType.LIMIT.equals(order_type):
41
+ if OrderSide.BUY.equals(order_side):
42
+
43
+ # Check if the exchange supports the
44
+ # createLimitBuyOrder method
45
+ if not hasattr(exchange, "createLimitBuyOrder"):
46
+ raise OperationalException(
47
+ f"Exchange {market} does not support "
48
+ f"functionality createLimitBuyOrder"
49
+ )
50
+
51
+ # Create a limit buy order
52
+ external_order = exchange.createLimitBuyOrder(
53
+ symbol, amount, price,
54
+ )
55
+ else:
56
+ # Check if the exchange supports
57
+ # the createLimitSellOrder method
58
+ if not hasattr(exchange, "createLimitSellOrder"):
59
+ raise OperationalException(
60
+ f"Exchange {market} does not support "
61
+ f"functionality createLimitSellOrder"
62
+ )
63
+
64
+ # Create a limit sell order
65
+ external_order = exchange.createLimitSellOrder(
66
+ symbol, amount, price,
67
+ )
68
+ else:
69
+ raise OperationalException(
70
+ f"Order type {order_type} not supported "
71
+ f"by CCXT OrderExecutor"
72
+ )
73
+
74
+ external_order = Order.from_ccxt_order(external_order)
75
+ external_order.id = order.id
76
+ return external_order
77
+ except Exception as e:
78
+ logger.exception(e)
79
+ raise OperationalException("Could not create limit buy order")
80
+
81
+ def cancel_order(self, portfolio, order, market_credential) -> Order:
82
+ """
83
+ Cancels an order for a given portfolio on a CCXT exchange.
84
+
85
+ Args:
86
+ order: The order to be canceled
87
+ portfolio: The portfolio in which the order was executed
88
+ market_credential: The market credential to use for the order
89
+
90
+ Returns:
91
+ Order: Instance of the canceled order.
92
+ """
93
+ market = portfolio.market
94
+ exchange = self.initialize_exchange(market, market_credential)
95
+
96
+ if not exchange.has['cancelOrder']:
97
+ raise OperationalException(
98
+ f"Exchange {market} does not support "
99
+ f"functionality cancelOrder"
100
+ )
101
+
102
+ try:
103
+ exchange.cancelOrder(
104
+ order.get_external_id(),
105
+ f"{order.get_target_symbol()}/{order.get_trading_symbol()}"
106
+ )
107
+ order.status = OrderStatus.CANCELED.value
108
+ return order
109
+ except Exception as e:
110
+ logger.exception(e)
111
+ raise OperationalException("Could not cancel order")
112
+
113
+ @staticmethod
114
+ def initialize_exchange(market, market_credential):
115
+ """
116
+ Function to initialize the exchange for the market.
117
+
118
+ Args:
119
+ market (str): The market to initialize the exchange for
120
+ market_credential (MarketCredential): The market credential to use
121
+ for the exchange
122
+
123
+ Returns:
124
+
125
+ """
126
+ market = market.lower()
127
+
128
+ if not hasattr(ccxt, market):
129
+ raise OperationalException(
130
+ f"No ccxt exchange for market id {market}"
131
+ )
132
+
133
+ exchange_class = getattr(ccxt, market)
134
+
135
+ if exchange_class is None:
136
+ raise OperationalException(
137
+ f"No market service found for market id {market}"
138
+ )
139
+
140
+ # Check the credentials for the exchange
141
+ CCXTOrderExecutor.check_credentials(exchange_class, market_credential)
142
+ exchange = exchange_class({
143
+ 'apiKey': market_credential.api_key,
144
+ 'secret': market_credential.secret_key,
145
+ })
146
+ return exchange
147
+
148
+ @staticmethod
149
+ def check_credentials(
150
+ exchange_class, market_credential: MarketCredential
151
+ ):
152
+ """
153
+ Function to check if the credentials are valid for the exchange.
154
+
155
+ Args:
156
+ exchange_class: The exchange class to check the credentials for
157
+ market_credential: The market credential to use for the exchange
158
+
159
+ Raises:
160
+ OperationalException: If the credentials are not valid
161
+
162
+ Returns:
163
+ None
164
+ """
165
+ exchange = exchange_class()
166
+ credentials_info = exchange.requiredCredentials
167
+ market = market_credential.get_market()
168
+
169
+ if ('apiKey' in credentials_info
170
+ and credentials_info["apiKey"]
171
+ and market_credential.get_api_key() is None):
172
+ raise OperationalException(
173
+ f"Market credential for market {market}"
174
+ " requires an api key, either"
175
+ " as an argument or as an environment variable"
176
+ f" named as {market.upper()}_API_KEY"
177
+ )
178
+
179
+ if ('secret' in credentials_info
180
+ and credentials_info["secret"]
181
+ and market_credential.get_secret_key() is None):
182
+ raise OperationalException(
183
+ f"Market credential for market {market}"
184
+ " requires a secret key, either"
185
+ " as an argument or as an environment variable"
186
+ f" named as {market.upper()}_SECRET_KEY"
187
+ )
188
+
189
+ def supports_market(self, market):
190
+ """
191
+ Function to check if the market is supported by the portfolio
192
+ provider.
193
+
194
+ Args:
195
+ market: Market object
196
+
197
+ Returns:
198
+ bool: True if the market is supported, False otherwise
199
+ """
200
+ return hasattr(ccxt, market.lower())
@@ -0,0 +1,19 @@
1
+ from .ccxt_portfolio_provider import CCXTPortfolioProvider
2
+
3
+
4
+ def get_default_portfolio_providers():
5
+ """
6
+ Function to get the default portfolio providers.
7
+
8
+ Returns:
9
+ list: List of default portfolio providers.
10
+ """
11
+ return [
12
+ CCXTPortfolioProvider(),
13
+ ]
14
+
15
+
16
+ __all__ = [
17
+ "CCXTPortfolioProvider",
18
+ "get_default_portfolio_providers",
19
+ ]