investing-algorithm-framework 6.9.1__py3-none-any.whl → 7.19.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of investing-algorithm-framework might be problematic. Click here for more details.

Files changed (192) hide show
  1. investing_algorithm_framework/__init__.py +147 -44
  2. investing_algorithm_framework/app/__init__.py +23 -6
  3. investing_algorithm_framework/app/algorithm/algorithm.py +5 -41
  4. investing_algorithm_framework/app/algorithm/algorithm_factory.py +17 -10
  5. investing_algorithm_framework/app/analysis/__init__.py +15 -0
  6. investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
  7. investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
  8. investing_algorithm_framework/app/analysis/permutation.py +116 -0
  9. investing_algorithm_framework/app/analysis/ranking.py +297 -0
  10. investing_algorithm_framework/app/app.py +1322 -707
  11. investing_algorithm_framework/app/context.py +196 -88
  12. investing_algorithm_framework/app/eventloop.py +590 -0
  13. investing_algorithm_framework/app/reporting/__init__.py +16 -5
  14. investing_algorithm_framework/app/reporting/ascii.py +57 -202
  15. investing_algorithm_framework/app/reporting/backtest_report.py +284 -170
  16. investing_algorithm_framework/app/reporting/charts/__init__.py +10 -2
  17. investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
  18. investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
  19. investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +11 -26
  20. investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
  21. investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
  22. investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +1 -1
  23. investing_algorithm_framework/app/reporting/generate.py +100 -114
  24. investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +40 -32
  25. investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +34 -27
  26. investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +23 -19
  27. investing_algorithm_framework/app/reporting/tables/trades_table.py +1 -1
  28. investing_algorithm_framework/app/reporting/tables/utils.py +1 -0
  29. investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +10 -16
  30. investing_algorithm_framework/app/strategy.py +315 -175
  31. investing_algorithm_framework/app/task.py +5 -3
  32. investing_algorithm_framework/cli/cli.py +30 -12
  33. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +131 -34
  34. investing_algorithm_framework/cli/initialize_app.py +20 -1
  35. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +18 -6
  36. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  37. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  38. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -2
  39. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +1 -1
  40. investing_algorithm_framework/create_app.py +3 -5
  41. investing_algorithm_framework/dependency_container.py +25 -39
  42. investing_algorithm_framework/domain/__init__.py +45 -38
  43. investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
  44. investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
  45. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
  46. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
  47. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
  48. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  49. investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
  50. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  51. investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
  52. investing_algorithm_framework/domain/config.py +27 -0
  53. investing_algorithm_framework/domain/constants.py +6 -34
  54. investing_algorithm_framework/domain/data_provider.py +200 -56
  55. investing_algorithm_framework/domain/exceptions.py +34 -1
  56. investing_algorithm_framework/domain/models/__init__.py +10 -19
  57. investing_algorithm_framework/domain/models/base_model.py +0 -6
  58. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  59. investing_algorithm_framework/domain/models/data/data_source.py +214 -0
  60. investing_algorithm_framework/domain/models/{market_data_type.py → data/data_type.py} +7 -7
  61. investing_algorithm_framework/domain/models/market/market_credential.py +6 -0
  62. investing_algorithm_framework/domain/models/order/order.py +34 -13
  63. investing_algorithm_framework/domain/models/order/order_status.py +1 -1
  64. investing_algorithm_framework/domain/models/order/order_type.py +1 -1
  65. investing_algorithm_framework/domain/models/portfolio/portfolio.py +14 -1
  66. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +5 -1
  67. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +51 -11
  68. investing_algorithm_framework/domain/models/position/__init__.py +2 -1
  69. investing_algorithm_framework/domain/models/position/position.py +9 -0
  70. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  71. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  72. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  73. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  74. investing_algorithm_framework/domain/models/snapshot_interval.py +0 -1
  75. investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
  76. investing_algorithm_framework/domain/models/time_frame.py +7 -0
  77. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  78. investing_algorithm_framework/domain/models/time_unit.py +63 -1
  79. investing_algorithm_framework/domain/models/trade/__init__.py +0 -2
  80. investing_algorithm_framework/domain/models/trade/trade.py +56 -32
  81. investing_algorithm_framework/domain/models/trade/trade_status.py +8 -2
  82. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +106 -41
  83. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +161 -99
  84. investing_algorithm_framework/domain/order_executor.py +19 -0
  85. investing_algorithm_framework/domain/portfolio_provider.py +20 -1
  86. investing_algorithm_framework/domain/services/__init__.py +0 -13
  87. investing_algorithm_framework/domain/strategy.py +1 -29
  88. investing_algorithm_framework/domain/utils/__init__.py +5 -1
  89. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  90. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  91. investing_algorithm_framework/domain/utils/polars.py +17 -14
  92. investing_algorithm_framework/download_data.py +40 -10
  93. investing_algorithm_framework/infrastructure/__init__.py +13 -25
  94. investing_algorithm_framework/infrastructure/data_providers/__init__.py +7 -4
  95. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +811 -546
  96. investing_algorithm_framework/infrastructure/data_providers/csv.py +433 -122
  97. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  98. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  99. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +81 -0
  100. investing_algorithm_framework/infrastructure/models/__init__.py +0 -13
  101. investing_algorithm_framework/infrastructure/models/order/order.py +9 -3
  102. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +27 -8
  103. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +21 -7
  104. investing_algorithm_framework/infrastructure/order_executors/__init__.py +2 -0
  105. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  106. investing_algorithm_framework/infrastructure/repositories/repository.py +16 -2
  107. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +2 -2
  108. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +6 -0
  109. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +6 -0
  110. investing_algorithm_framework/infrastructure/services/__init__.py +0 -4
  111. investing_algorithm_framework/services/__init__.py +105 -8
  112. investing_algorithm_framework/services/backtesting/backtest_service.py +536 -476
  113. investing_algorithm_framework/services/configuration_service.py +14 -4
  114. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  115. investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
  116. investing_algorithm_framework/{app/reporting → services}/metrics/__init__.py +48 -17
  117. investing_algorithm_framework/{app/reporting → services}/metrics/drawdown.py +10 -10
  118. investing_algorithm_framework/{app/reporting → services}/metrics/equity_curve.py +2 -2
  119. investing_algorithm_framework/{app/reporting → services}/metrics/exposure.py +60 -2
  120. investing_algorithm_framework/services/metrics/generate.py +358 -0
  121. investing_algorithm_framework/{app/reporting → services}/metrics/profit_factor.py +36 -0
  122. investing_algorithm_framework/{app/reporting → services}/metrics/recovery.py +2 -2
  123. investing_algorithm_framework/{app/reporting → services}/metrics/returns.py +146 -147
  124. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  125. investing_algorithm_framework/{app/reporting/metrics/sharp_ratio.py → services/metrics/sharpe_ratio.py} +6 -10
  126. investing_algorithm_framework/{app/reporting → services}/metrics/sortino_ratio.py +3 -7
  127. investing_algorithm_framework/services/metrics/trades.py +500 -0
  128. investing_algorithm_framework/services/metrics/volatility.py +97 -0
  129. investing_algorithm_framework/{app/reporting → services}/metrics/win_rate.py +70 -3
  130. investing_algorithm_framework/services/order_service/order_backtest_service.py +21 -31
  131. investing_algorithm_framework/services/order_service/order_service.py +9 -71
  132. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -2
  133. investing_algorithm_framework/services/portfolios/portfolio_service.py +3 -13
  134. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +62 -96
  135. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -3
  136. investing_algorithm_framework/services/repository_service.py +5 -2
  137. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  138. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
  139. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  140. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  141. investing_algorithm_framework/services/trade_service/__init__.py +7 -1
  142. investing_algorithm_framework/services/trade_service/trade_service.py +51 -29
  143. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  144. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  145. investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
  146. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/RECORD +159 -148
  147. investing_algorithm_framework/app/reporting/evaluation.py +0 -243
  148. investing_algorithm_framework/app/reporting/metrics/risk_free_rate.py +0 -8
  149. investing_algorithm_framework/app/reporting/metrics/volatility.py +0 -69
  150. investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -3
  151. investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -9
  152. investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -47
  153. investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
  154. investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
  155. investing_algorithm_framework/domain/models/backtesting/backtest_results.py +0 -440
  156. investing_algorithm_framework/domain/models/data_source.py +0 -21
  157. investing_algorithm_framework/domain/models/date_range.py +0 -64
  158. investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -34
  159. investing_algorithm_framework/domain/models/trading_data_types.py +0 -48
  160. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
  161. investing_algorithm_framework/domain/services/market_data_sources.py +0 -543
  162. investing_algorithm_framework/domain/services/market_service.py +0 -153
  163. investing_algorithm_framework/domain/services/observable.py +0 -51
  164. investing_algorithm_framework/domain/services/observer.py +0 -19
  165. investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -16
  166. investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -746
  167. investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -270
  168. investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -312
  169. investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
  170. investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -471
  171. investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
  172. investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
  173. investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -322
  174. investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -10
  175. investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -269
  176. investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -350
  177. investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -377
  178. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -296
  179. investing_algorithm_framework-6.9.1.dist-info/METADATA +0 -440
  180. /investing_algorithm_framework/{app/reporting → services}/metrics/alpha.py +0 -0
  181. /investing_algorithm_framework/{app/reporting → services}/metrics/beta.py +0 -0
  182. /investing_algorithm_framework/{app/reporting → services}/metrics/cagr.py +0 -0
  183. /investing_algorithm_framework/{app/reporting → services}/metrics/calmar_ratio.py +0 -0
  184. /investing_algorithm_framework/{app/reporting → services}/metrics/mean_daily_return.py +0 -0
  185. /investing_algorithm_framework/{app/reporting → services}/metrics/price_efficiency.py +0 -0
  186. /investing_algorithm_framework/{app/reporting → services}/metrics/standard_deviation.py +0 -0
  187. /investing_algorithm_framework/{app/reporting → services}/metrics/treynor_ratio.py +0 -0
  188. /investing_algorithm_framework/{app/reporting → services}/metrics/ulcer.py +0 -0
  189. /investing_algorithm_framework/{app/reporting → services}/metrics/value_at_risk.py +0 -0
  190. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
  191. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
  192. {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/entry_points.txt +0 -0
@@ -1,14 +1,16 @@
1
1
  import logging
2
+ from datetime import datetime, timezone
2
3
  from typing import List
3
4
 
4
5
  from investing_algorithm_framework.services import ConfigurationService, \
5
- MarketCredentialService, MarketDataSourceService, \
6
- OrderService, PortfolioConfigurationService, PortfolioService, \
7
- PositionService, TradeService
6
+ MarketCredentialService, OrderService, PortfolioConfigurationService, \
7
+ PortfolioService, PositionService, TradeService, DataProviderService, \
8
+ TradeStopLossService, TradeTakeProfitService
8
9
  from investing_algorithm_framework.domain import OrderStatus, OrderType, \
9
10
  OrderSide, OperationalException, Portfolio, RoundingService, \
10
- BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME, TradeRiskType, Order, \
11
- Position, Trade, TradeStatus, MarketService, MarketCredential
11
+ BACKTESTING_FLAG, INDEX_DATETIME, Order, \
12
+ Position, Trade, TradeStatus, MarketCredential, TradeStopLoss, \
13
+ TradeTakeProfit
12
14
 
13
15
  logger = logging.getLogger("investing_algorithm_framework")
14
16
 
@@ -28,9 +30,10 @@ class Context:
28
30
  position_service: PositionService,
29
31
  order_service: OrderService,
30
32
  market_credential_service: MarketCredentialService,
31
- market_data_source_service: MarketDataSourceService,
32
- market_service: MarketService,
33
33
  trade_service: TradeService,
34
+ trade_stop_loss_service: TradeStopLossService,
35
+ trade_take_profit_service: TradeTakeProfitService,
36
+ data_provider_service: DataProviderService
34
37
  ):
35
38
  self.configuration_service: ConfigurationService = \
36
39
  configuration_service
@@ -41,10 +44,12 @@ class Context:
41
44
  self.order_service: OrderService = order_service
42
45
  self.market_credential_service: MarketCredentialService = \
43
46
  market_credential_service
44
- self.market_data_source_service: MarketDataSourceService = \
45
- market_data_source_service
46
- self.market_service: MarketService = market_service
47
+ self.data_provider_service: DataProviderService = data_provider_service
47
48
  self.trade_service: TradeService = trade_service
49
+ self.trade_stop_loss_service: TradeStopLossService = \
50
+ trade_stop_loss_service
51
+ self.trade_take_profit_service: TradeTakeProfitService = \
52
+ trade_take_profit_service
48
53
 
49
54
  @property
50
55
  def config(self):
@@ -110,7 +115,7 @@ class Context:
110
115
  if BACKTESTING_FLAG in self.configuration_service.config \
111
116
  and self.configuration_service.config[BACKTESTING_FLAG]:
112
117
  order_data["created_at"] = \
113
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
118
+ self.configuration_service.config[INDEX_DATETIME]
114
119
 
115
120
  return self.order_service.create(
116
121
  order_data, execute=execute, validate=validate, sync=sync
@@ -255,7 +260,7 @@ class Context:
255
260
  if BACKTESTING_FLAG in self.configuration_service.config \
256
261
  and self.configuration_service.config[BACKTESTING_FLAG]:
257
262
  order_data["created_at"] = \
258
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
263
+ self.configuration_service.config[INDEX_DATETIME]
259
264
 
260
265
  return self.order_service.create(
261
266
  order_data, execute=execute, validate=validate, sync=sync
@@ -333,7 +338,7 @@ class Context:
333
338
  if BACKTESTING_FLAG in self.configuration_service.config \
334
339
  and self.configuration_service.config[BACKTESTING_FLAG]:
335
340
  order_data["created_at"] = \
336
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
341
+ self.configuration_service.config[INDEX_DATETIME]
337
342
 
338
343
  return self.order_service.create(order_data)
339
344
 
@@ -404,7 +409,7 @@ class Context:
404
409
  if BACKTESTING_FLAG in self.configuration_service.config \
405
410
  and self.configuration_service.config[BACKTESTING_FLAG]:
406
411
  order_data["created_at"] = \
407
- self.configuration_service.config[BACKTESTING_INDEX_DATETIME]
412
+ self.configuration_service.config[INDEX_DATETIME]
408
413
  return self.order_service.create(
409
414
  order_data, execute=True, validate=True, sync=True
410
415
  )
@@ -424,9 +429,52 @@ class Context:
424
429
  """
425
430
 
426
431
  if market is None:
427
- return self.portfolio_service.get_all()[0]
432
+ portfolio = self.portfolio_service.get_all()[0]
433
+ else:
434
+ portfolio = self.portfolio_service.find({"market": market})
435
+
436
+ # Retrieve positions
437
+ positions = self.position_service.get_all(
438
+ {"portfolio": portfolio.id}
439
+ )
440
+
441
+ if BACKTESTING_FLAG in self.configuration_service.config \
442
+ and self.configuration_service.config[BACKTESTING_FLAG]:
443
+ date = self.configuration_service.config[INDEX_DATETIME]
444
+ else:
445
+ date = datetime.now(tz=timezone.utc)
446
+
447
+ allocated = 0.0
448
+
449
+ for position in positions:
450
+
451
+ if position.symbol != portfolio.trading_symbol:
452
+ ticker = self.data_provider_service.get_ticker_data(
453
+ symbol=f"{position.symbol}/{portfolio.trading_symbol}",
454
+ market=portfolio.market,
455
+ date=date
456
+ )
457
+ if ticker is not None and "bid" in ticker:
458
+ allocated += position.get_amount() * ticker["bid"]
459
+
460
+ portfolio.allocated = allocated
461
+ return portfolio
462
+
463
+ def get_latest_price(self, symbol, market=None):
464
+
465
+ if BACKTESTING_FLAG in self.configuration_service.config \
466
+ and self.configuration_service.config[BACKTESTING_FLAG]:
467
+ date = self.configuration_service.config[INDEX_DATETIME]
468
+ else:
469
+ date = datetime.now(tz=timezone.utc)
470
+
471
+ ticker = self.data_provider_service.get_ticker_data(
472
+ symbol=symbol,
473
+ market=market,
474
+ date=date
475
+ )
428
476
 
429
- return self.portfolio_service.find({"market": market})
477
+ return ticker['bid'] if ticker and 'bid' in ticker else None
430
478
 
431
479
  def get_portfolios(self):
432
480
  """
@@ -761,41 +809,6 @@ class Context:
761
809
  query_params["symbol"] = symbol
762
810
  return self.position_service.exists(query_params)
763
811
 
764
- def get_position_percentage_of_portfolio(
765
- self, symbol, market=None, identifier=None
766
- ) -> float:
767
- """
768
- Returns the percentage of the current total value of the portfolio
769
- that is allocated to a position. This is calculated by dividing
770
- the current value of the position by the total current value
771
- of the portfolio.
772
- """
773
-
774
- query_params = {}
775
-
776
- if market is not None:
777
- query_params["market"] = market
778
-
779
- if identifier is not None:
780
- query_params["identifier"] = identifier
781
-
782
- portfolios = self.portfolio_service.get_all(query_params)
783
-
784
- if not portfolios:
785
- raise OperationalException("No portfolio found.")
786
-
787
- portfolio = portfolios[0]
788
- position = self.position_service.find(
789
- {"portfolio": portfolio.id, "symbol": symbol}
790
- )
791
- full_symbol = f"{position.symbol.upper()}/" \
792
- f"{portfolio.trading_symbol.upper()}"
793
- ticker = self.market_data_source_service.get_ticker(
794
- symbol=full_symbol, market=market
795
- )
796
- total = self.get_unallocated() + self.get_allocated()
797
- return (position.amount * ticker["bid"] / total) * 100
798
-
799
812
  def get_position_percentage_of_portfolio_by_net_size(
800
813
  self, symbol, market=None, identifier=None
801
814
  ) -> float:
@@ -828,7 +841,12 @@ class Context:
828
841
  return (position.cost / net_size) * 100
829
842
 
830
843
  def close_position(
831
- self, position=None, symbol=None, portfolio=None, precision=None
844
+ self,
845
+ position=None,
846
+ symbol=None,
847
+ portfolio=None,
848
+ precision=None,
849
+ price=None
832
850
  ) -> Order:
833
851
  """
834
852
  Function to close a position. This function will close a position
@@ -841,6 +859,8 @@ class Context:
841
859
  symbol (Optional): The symbol of the asset
842
860
  portfolio (Optional): The portfolio where the position is located
843
861
  precision (Optional): The precision of the amount
862
+ price (Optional[Float]): The price with which the position needs
863
+ to be closed.
844
864
 
845
865
  Returns:
846
866
  Order: The order created to close the position
@@ -887,19 +907,25 @@ class Context:
887
907
 
888
908
  target_symbol = position.get_symbol()
889
909
  symbol = f"{target_symbol.upper()}/{portfolio.trading_symbol.upper()}"
890
- ticker = self.market_data_source_service.get_ticker(
891
- symbol=symbol, market=portfolio.market
892
- )
910
+
911
+ if price is None:
912
+ ticker = self.data_provider_service.get_ticker_data(
913
+ symbol=symbol,
914
+ market=portfolio.market,
915
+ date=self.config[INDEX_DATETIME]
916
+ )
917
+ price = ticker["bid"]
918
+
893
919
  logger.info(
894
920
  f"Closing position {position.symbol} "
895
921
  f"with amount {position.get_amount()} "
896
- f"at price {ticker['bid']}"
922
+ f"at price {price}"
897
923
  )
898
924
  return self.create_limit_order(
899
925
  target_symbol=position.symbol,
900
926
  amount=position.get_amount(),
901
927
  order_side=OrderSide.SELL.value,
902
- price=ticker["bid"],
928
+ price=price,
903
929
  precision=precision,
904
930
  )
905
931
 
@@ -951,8 +977,9 @@ class Context:
951
977
 
952
978
  symbol = f"{position.symbol.upper()}/" \
953
979
  f"{portfolio.trading_symbol.upper()}"
954
- ticker = self.market_data_source_service.get_ticker(
955
- symbol=symbol, market=market,
980
+ current_date = self.config[INDEX_DATETIME]
981
+ ticker = self.data_provider_service.get_ticker_data(
982
+ symbol=symbol, market=portfolio.market, date=current_date
956
983
  )
957
984
  allocated = allocated + \
958
985
  (position.get_amount() * ticker["bid"])
@@ -1351,11 +1378,12 @@ class Context:
1351
1378
 
1352
1379
  def add_stop_loss(
1353
1380
  self,
1354
- trade,
1381
+ trade: Trade,
1355
1382
  percentage: float,
1356
- trade_risk_type=TradeRiskType.FIXED,
1383
+ trailing: bool = False,
1357
1384
  sell_percentage: float = 100,
1358
- ):
1385
+ created_at: datetime = None,
1386
+ ) -> TradeStopLoss:
1359
1387
  """
1360
1388
  Function to add a stop loss to a trade.
1361
1389
 
@@ -1373,32 +1401,39 @@ class Context:
1373
1401
  * BTC price drops to $39,900 → SL level reached, trade closes.
1374
1402
 
1375
1403
  Args:
1376
- trade: Trade object representing the trade
1377
- percentage: float representing the percentage of the open price
1378
- that the stop loss should be set at
1379
- trade_risk_type: The type of the stop loss, fixed
1380
- or trailing
1381
- sell_percentage: float representing the percentage of the trade
1382
- that should be sold if the stop loss is triggered
1404
+ trade (Trade): Trade object representing the trade
1405
+ percentage (float): float representing the percentage
1406
+ of the open price that the stop loss should
1407
+ be set at. This must be a positive
1408
+ number, e.g. 5 for 5%, or 10 for 10%.
1409
+ trailing (bool): Whether the stop loss should be trailing
1410
+ or fixed.
1411
+ sell_percentage (float): float representing the
1412
+ percentage of the trade that should be sold if the
1413
+ stop loss is triggered
1414
+ created_at: datetime: The date and time when the stop loss
1415
+ was created. If not specified, the current date and time
1416
+ will be used.
1383
1417
 
1384
1418
  Returns:
1385
1419
  None
1386
1420
  """
1387
- self.trade_service.add_stop_loss(
1421
+ return self.trade_service.add_stop_loss(
1388
1422
  trade,
1389
1423
  percentage=percentage,
1390
- trade_risk_type=trade_risk_type,
1424
+ trailing=trailing,
1391
1425
  sell_percentage=sell_percentage,
1426
+ created_at=created_at,
1392
1427
  )
1393
- return self.trade_service.get(trade.id)
1394
1428
 
1395
1429
  def add_take_profit(
1396
1430
  self,
1397
- trade,
1431
+ trade: Trade,
1398
1432
  percentage: float,
1399
- trade_risk_type=TradeRiskType.FIXED,
1433
+ trailing: bool = False,
1400
1434
  sell_percentage: float = 100,
1401
- ) -> None:
1435
+ created_at: datetime = None,
1436
+ ) -> TradeTakeProfit:
1402
1437
  """
1403
1438
  Function to add a take profit to a trade. This function will add a
1404
1439
  take profit to the specified trade. If the take profit is triggered,
@@ -1418,24 +1453,30 @@ class Context:
1418
1453
  * BTC drops to $42,750 → Trade closes, securing profit.
1419
1454
 
1420
1455
  Args:
1421
- trade: Trade object representing the trade
1422
- percentage: float representing the percentage of the open price
1423
- that the stop loss should be set at
1424
- trade_risk_type: The type of the stop loss, fixed
1425
- or trailing
1426
- sell_percentage: float representing the percentage of the trade
1427
- that should be sold if the stop loss is triggered
1456
+ trade (Trade): Trade object representing the trade
1457
+ percentage (float): float representing the percentage
1458
+ of the open price that the stop loss should
1459
+ be set at. This must be a positive
1460
+ number, e.g. 5 for 5%, or 10 for 10%.
1461
+ trailing (bool): Whether the take profit should be trailing
1462
+ or fixed.
1463
+ sell_percentage (float): float representing the
1464
+ percentage of the trade that should be sold if the
1465
+ stop loss is triggered
1466
+ created_at: datetime: The date and time when the take profit
1467
+ was created. If not specified, the current date and time
1468
+ will be used.
1428
1469
 
1429
1470
  Returns:
1430
1471
  None
1431
1472
  """
1432
- self.trade_service.add_take_profit(
1473
+ return self.trade_service.add_take_profit(
1433
1474
  trade,
1434
1475
  percentage=percentage,
1435
- trade_risk_type=trade_risk_type,
1476
+ trailing=trailing,
1436
1477
  sell_percentage=sell_percentage,
1478
+ created_at=created_at,
1437
1479
  )
1438
- return self.trade_service.get(trade.id)
1439
1480
 
1440
1481
  def close_trade(self, trade, precision=None) -> None:
1441
1482
  """
@@ -1451,7 +1492,6 @@ class Context:
1451
1492
  Returns:
1452
1493
  None
1453
1494
  """
1454
-
1455
1495
  trade = self.trade_service.get(trade.id)
1456
1496
 
1457
1497
  if TradeStatus.CLOSED.equals(trade.status):
@@ -1479,8 +1519,10 @@ class Context:
1479
1519
  )
1480
1520
  amount = position.get_amount()
1481
1521
 
1482
- ticker = self.market_data_source_service.get_ticker(
1483
- symbol=trade.symbol, market=portfolio.market
1522
+ ticker = self.data_provider_service.get_ticker_data(
1523
+ symbol=trade.symbol,
1524
+ market=portfolio.market,
1525
+ date=self.config[INDEX_DATETIME]
1484
1526
  )
1485
1527
  logger.info(f"Closing trade {trade.id} {trade.symbol}")
1486
1528
  self.order_service.create(
@@ -1615,3 +1657,69 @@ class Context:
1615
1657
  List[MarketCredential]: A list of all market credentials
1616
1658
  """
1617
1659
  return self.market_credential_service.get_all()
1660
+
1661
+ def get_trading_symbol(self, portfolio_id=None):
1662
+ """
1663
+ Function to get the trading symbol of a portfolio. If the
1664
+ portfolio_id parameter is specified, the function will return
1665
+ the trading symbol of the portfolio with the specified id.
1666
+
1667
+ Args:
1668
+ portfolio_id: The id of the portfolio to get the trading symbol for
1669
+
1670
+ Returns:
1671
+ str: The trading symbol of the portfolio
1672
+ """
1673
+ if portfolio_id is None:
1674
+ if self.portfolio_service.count() > 1:
1675
+ raise OperationalException(
1676
+ "Multiple portfolios found. Please specify a "
1677
+ "portfolio identifier."
1678
+ )
1679
+ portfolio = self.portfolio_service.get_all()[0]
1680
+ else:
1681
+ portfolio = self.portfolio_service.get(portfolio_id)
1682
+
1683
+ return portfolio.trading_symbol
1684
+
1685
+ def get_take_profits(
1686
+ self, triggered: bool = None
1687
+ ) -> List[TradeTakeProfit]:
1688
+ """
1689
+ Function to get all take profits. If the triggered parameter
1690
+ is specified, the function will return all take profits that
1691
+ match the triggered status.
1692
+
1693
+ Args:
1694
+ triggered (bool): The triggered status of the take profits
1695
+
1696
+ Returns:
1697
+ List[TradeTakeProfit]: A list of take profits
1698
+ """
1699
+ query_params = {}
1700
+
1701
+ if triggered is not None:
1702
+ query_params["triggered"] = triggered
1703
+
1704
+ return self.trade_take_profit_service.get_all(query_params)
1705
+
1706
+ def get_stop_losses(
1707
+ self, triggered: bool = None
1708
+ ) -> List[TradeStopLoss]:
1709
+ """
1710
+ Function to get all stop losses. If the triggered parameter
1711
+ is specified, the function will return all stop losses that
1712
+ match the triggered status.
1713
+
1714
+ Args:
1715
+ triggered (bool): The triggered status of the stop losses
1716
+
1717
+ Returns:
1718
+ List[TradeStopLoss]: A list of stop losses
1719
+ """
1720
+ query_params = {}
1721
+
1722
+ if triggered is not None:
1723
+ query_params["triggered"] = triggered
1724
+
1725
+ return self.trade_stop_loss_service.get_all(query_params)