investing-algorithm-framework 2.4.0__tar.gz → 2.5.0__tar.gz

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 (132) hide show
  1. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/PKG-INFO +2 -2
  2. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/README.md +1 -1
  3. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/algorithm.py +58 -227
  4. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/app.py +19 -4
  5. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/strategy.py +13 -0
  6. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/dependency_container.py +14 -3
  7. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/__init__.py +2 -2
  8. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/__init__.py +2 -2
  9. investing_algorithm_framework-2.5.0/investing_algorithm_framework/domain/models/backtesting/__init__.py +6 -0
  10. investing_algorithm_framework-2.4.0/investing_algorithm_framework/domain/models/backtest_profile.py → investing_algorithm_framework-2.5.0/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +53 -4
  11. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order.py +36 -0
  12. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +1 -1
  13. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/__init__.py +6 -3
  14. investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/backtesting/__init__.py +8 -0
  15. investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +37 -0
  16. {investing_algorithm_framework-2.4.0/investing_algorithm_framework/services → investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/backtesting}/backtest_service.py +43 -20
  17. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +16 -14
  18. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/order_service/order_service.py +5 -0
  19. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_service/portfolio_service.py +3 -1
  20. investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/trade_service/__init__.py +3 -0
  21. investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/trade_service/trade_service.py +283 -0
  22. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/pyproject.toml +1 -1
  23. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/LICENSE +0 -0
  24. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/__init__.py +0 -0
  25. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/__init__.py +0 -0
  26. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
  27. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
  28. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
  29. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
  30. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
  31. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
  32. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/task.py +0 -0
  33. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/__init__.py +0 -0
  34. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
  35. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
  36. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
  37. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
  38. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/create_app.py +0 -0
  39. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/error_handler.py +0 -0
  40. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/responses.py +0 -0
  41. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
  42. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
  43. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
  44. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
  45. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
  46. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
  47. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/create_app.py +0 -0
  48. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/config.py +0 -0
  49. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/constants.py +0 -0
  50. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/data_structures.py +0 -0
  51. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
  52. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/exceptions.py +0 -0
  53. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/base_model.py +0 -0
  54. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
  55. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
  56. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
  57. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_fee.py +0 -0
  58. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
  59. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
  60. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
  61. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
  62. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
  63. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +0 -0
  64. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
  65. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
  66. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/position/position.py +0 -0
  67. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
  68. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
  69. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
  70. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
  71. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
  72. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/trade.py +0 -0
  73. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/trading_data_types.py +0 -0
  74. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/trading_time_frame.py +0 -0
  75. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/services/__init__.py +0 -0
  76. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/services/market_data_sources.py +0 -0
  77. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/services/market_service.py +0 -0
  78. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/singleton.py +0 -0
  79. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
  80. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/strategy.py +0 -0
  81. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
  82. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/backtesting.py +0 -0
  83. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/csv.py +0 -0
  84. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/random.py +0 -0
  85. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
  86. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
  87. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
  88. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
  89. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
  90. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
  91. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
  92. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
  93. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -0
  94. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -0
  95. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -0
  96. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
  97. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
  98. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/order/order.py +0 -0
  99. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -0
  100. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
  101. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio.py +0 -0
  102. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
  103. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
  104. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
  105. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
  106. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
  107. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -0
  108. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
  109. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
  110. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
  111. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
  112. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
  113. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
  114. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -0
  115. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -0
  116. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -0
  117. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -0
  118. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -0
  119. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/configuration_service.py +0 -0
  120. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_credential_service.py +0 -0
  121. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -0
  122. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -0
  123. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
  124. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/order_service/order_backtest_service.py +0 -0
  125. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_configuration_service.py +0 -0
  126. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_service/__init__.py +0 -0
  127. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_service/backtest_portfolio_service.py +0 -0
  128. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_snapshot_service.py +0 -0
  129. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/position_service.py +0 -0
  130. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/position_snapshot_service.py +0 -0
  131. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/repository_service.py +0 -0
  132. {investing_algorithm_framework-2.4.0 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: investing-algorithm-framework
3
- Version: 2.4.0
3
+ Version: 2.5.0
4
4
  Summary: A framework for creating trading bots
5
5
  Author: MDUYN
6
6
  Requires-Python: >=3.8.1,<4.0.0
@@ -36,7 +36,7 @@ Description-Content-Type: text/markdown
36
36
  ###### Sponsors
37
37
  <p align="left">
38
38
  <a href="https://finterion.com">
39
- <img alt="Finterion" src="https://logicfunds-web-app-images.s3.eu-central-1.amazonaws.com/finterion.png" width="200px" />
39
+ <img alt="Finterion" src="static/sponsors/finterion.png" width="200px" />
40
40
  </a>
41
41
  </p>
42
42
 
@@ -9,7 +9,7 @@
9
9
  ###### Sponsors
10
10
  <p align="left">
11
11
  <a href="https://finterion.com">
12
- <img alt="Finterion" src="https://logicfunds-web-app-images.s3.eu-central-1.amazonaws.com/finterion.png" width="200px" />
12
+ <img alt="Finterion" src="static/sponsors/finterion.png" width="200px" />
13
13
  </a>
14
14
  </p>
15
15
 
@@ -1,13 +1,14 @@
1
- import logging
2
1
  import decimal
2
+ import logging
3
3
  from typing import List
4
4
 
5
5
  from investing_algorithm_framework.domain import OrderStatus, OrderFee, \
6
6
  Position, Order, Portfolio, OrderType, OrderSide, ApiException, \
7
- BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME, Trade, PeekableQueue, \
8
- MarketService
7
+ BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME, MarketService
9
8
  from investing_algorithm_framework.services import MarketCredentialService, \
10
- MarketDataSourceService
9
+ MarketDataSourceService, PortfolioService, PositionService, TradeService, \
10
+ OrderService, ConfigurationService, StrategyOrchestratorService, \
11
+ PortfolioConfigurationService
11
12
 
12
13
  logger = logging.getLogger("investing_algorithm_framework")
13
14
 
@@ -24,21 +25,26 @@ class Algorithm:
24
25
  market_service,
25
26
  strategy_orchestrator_service,
26
27
  market_credential_service,
27
- market_data_source_service
28
+ market_data_source_service,
29
+ trade_service
28
30
  ):
29
- self.portfolio_service = portfolio_service
30
- self.position_service = position_service
31
- self.order_service = order_service
32
- self._market_service: MarketService = market_service
33
- self.configuration_service = configuration_service
34
- self.portfolio_configuration_service = portfolio_configuration_service
35
- self.strategy_orchestrator_service = strategy_orchestrator_service
31
+ self.portfolio_service: PortfolioService = portfolio_service
32
+ self.position_service: PositionService = position_service
33
+ self.order_service: OrderService = order_service
34
+ self.market_service: MarketService = market_service
35
+ self.configuration_service: ConfigurationService \
36
+ = configuration_service
37
+ self.portfolio_configuration_service: PortfolioConfigurationService \
38
+ = portfolio_configuration_service
39
+ self.strategy_orchestrator_service: StrategyOrchestratorService \
40
+ = strategy_orchestrator_service
36
41
  self._market_data_sources = {}
37
42
  self._strategies = []
38
43
  self._market_credential_service: MarketCredentialService \
39
44
  = market_credential_service
40
45
  self._market_data_source_service: MarketDataSourceService \
41
46
  = market_data_source_service
47
+ self.trade_service: TradeService = trade_service
42
48
 
43
49
  def start(self, number_of_iterations=None, stateless=False):
44
50
 
@@ -158,14 +164,14 @@ class Algorithm:
158
164
  )
159
165
 
160
166
  def create_market_order(
161
- self,
162
- target_symbol,
163
- order_side,
164
- amount,
165
- market=None,
166
- execute=False,
167
- validate=False,
168
- sync=True
167
+ self,
168
+ target_symbol,
169
+ order_side,
170
+ amount,
171
+ market=None,
172
+ execute=False,
173
+ validate=False,
174
+ sync=True
169
175
  ):
170
176
 
171
177
  if market is None:
@@ -221,13 +227,13 @@ class Algorithm:
221
227
  self._running_workers = []
222
228
 
223
229
  def get_order(
224
- self,
225
- reference_id=None,
226
- market=None,
227
- target_symbol=None,
228
- trading_symbol=None,
229
- order_side=None,
230
- order_type=None
230
+ self,
231
+ reference_id=None,
232
+ market=None,
233
+ target_symbol=None,
234
+ trading_symbol=None,
235
+ order_side=None,
236
+ order_type=None
231
237
  ) -> Order:
232
238
  query_params = {}
233
239
 
@@ -256,12 +262,12 @@ class Algorithm:
256
262
  return self.order_service.find(query_params)
257
263
 
258
264
  def get_orders(
259
- self,
260
- target_symbol=None,
261
- status=None,
262
- order_type=None,
263
- order_side=None,
264
- market=None
265
+ self,
266
+ target_symbol=None,
267
+ status=None,
268
+ order_type=None,
269
+ order_side=None,
270
+ market=None
265
271
  ) -> List[Order]:
266
272
 
267
273
  if market is None:
@@ -284,13 +290,13 @@ class Algorithm:
284
290
  return self.order_service.get_order_fee(order_id)
285
291
 
286
292
  def get_positions(
287
- self,
288
- market=None,
289
- identifier=None,
290
- amount_gt=None,
291
- amount_gte=None,
292
- amount_lt=None,
293
- amount_lte=None
293
+ self,
294
+ market=None,
295
+ identifier=None,
296
+ amount_gt=None,
297
+ amount_gte=None,
298
+ amount_lt=None,
299
+ amount_lte=None
294
300
  ) -> List[Position]:
295
301
  query_params = {}
296
302
 
@@ -346,14 +352,14 @@ class Algorithm:
346
352
  return None
347
353
 
348
354
  def has_position(
349
- self,
350
- symbol,
351
- market=None,
352
- identifier=None,
353
- amount_gt=0,
354
- amount_gte=None,
355
- amount_lt=None,
356
- amount_lte=None
355
+ self,
356
+ symbol,
357
+ market=None,
358
+ identifier=None,
359
+ amount_gt=0,
360
+ amount_gte=None,
361
+ amount_lt=None,
362
+ amount_lte=None
357
363
  ):
358
364
  return self.position_exists(
359
365
  symbol,
@@ -675,55 +681,10 @@ class Algorithm:
675
681
  self.order_service.check_pending_orders()
676
682
 
677
683
  def get_trades(self, market=None):
678
- portfolios = self.portfolio_service.get_all()
679
- trades = []
680
-
681
- for portfolio in portfolios:
682
- buy_orders = self.order_service.get_all({
683
- "status": OrderStatus.CLOSED.value,
684
- "order_side": OrderSide.BUY.value,
685
- "portfolio_id": portfolio.id
686
- })
687
-
688
- for buy_order in buy_orders:
689
- symbol = buy_order.get_symbol()
690
- ticker = self._market_data_source_service.get_ticker(
691
- symbol=symbol, market=market
692
- )
693
- trades.append(
694
- Trade(
695
- buy_order_id=buy_order.id,
696
- target_symbol=buy_order.get_target_symbol(),
697
- trading_symbol=buy_order.get_trading_symbol(),
698
- amount=buy_order.get_amount(),
699
- open_price=buy_order.get_price(),
700
- closed_price=buy_order.get_trade_closed_price(),
701
- closed_at=buy_order.get_trade_closed_at(),
702
- opened_at=buy_order.get_created_at(),
703
- current_price=ticker["bid"]
704
- )
705
- )
706
-
707
- return trades
684
+ return self.trade_service.get_trades(market)
708
685
 
709
686
  def get_closed_trades(self):
710
- buy_orders = self.order_service.get_all({
711
- "status": OrderStatus.CLOSED.value,
712
- "order_side": OrderSide.BUY.value
713
- })
714
- return [
715
- Trade(
716
- buy_order_id=order.id,
717
- target_symbol=order.get_target_symbol(),
718
- trading_symbol=order.get_trading_symbol(),
719
- amount=order.get_amount(),
720
- open_price=order.get_price(),
721
- closed_price=order.get_trade_closed_price(),
722
- closed_at=order.get_trade_closed_at(),
723
- opened_at=order.get_created_at()
724
- ) for order in buy_orders
725
- if order.get_trade_closed_at() is not None
726
- ]
687
+ return self.trade_service.get_closed_trades()
727
688
 
728
689
  def round_down(self, value, amount_of_decimals):
729
690
 
@@ -743,140 +704,10 @@ class Algorithm:
743
704
  return 0
744
705
 
745
706
  def get_open_trades(self, target_symbol=None, market=None):
746
- portfolios = self.portfolio_service.get_all()
747
- trades = []
748
-
749
- for portfolio in portfolios:
750
-
751
- if target_symbol is not None:
752
- buy_orders = self.order_service.get_all({
753
- "status": OrderStatus.CLOSED.value,
754
- "order_side": OrderSide.BUY.value,
755
- "portfolio_id": portfolio.id,
756
- "target_symbol": target_symbol
757
- })
758
- sell_orders = self.order_service.get_all({
759
- "status": OrderStatus.OPEN.value,
760
- "order_side": OrderSide.SELL.value,
761
- "portfolio_id": portfolio.id,
762
- "target_symbol": target_symbol
763
- })
764
- else:
765
- buy_orders = self.order_service.get_all({
766
- "status": OrderStatus.CLOSED.value,
767
- "order_side": OrderSide.BUY.value,
768
- "portfolio_id": portfolio.id
769
- })
770
- sell_orders = self.order_service.get_all({
771
- "status": OrderStatus.OPEN.value,
772
- "order_side": OrderSide.SELL.value,
773
- "portfolio_id": portfolio.id
774
- })
775
-
776
- buy_orders = [
777
- buy_order for buy_order in buy_orders
778
- if buy_order.get_trade_closed_at() is None
779
- ]
780
- sell_amount = sum([order.amount for order in sell_orders])
781
-
782
- # Subtract the amount of the open sell orders
783
- # from the amount of the buy orders
784
- buy_orders_queue = PeekableQueue()
785
-
786
- for buy_order in buy_orders:
787
- buy_orders_queue.enqueue(buy_order)
788
-
789
- while sell_amount > 0 and not buy_orders_queue.is_empty():
790
- first_buy_order = buy_orders_queue.peek()
791
- available = first_buy_order.get_filled() \
792
- - first_buy_order.get_trade_closed_amount()
793
-
794
- if available > sell_amount:
795
- remaining = available - sell_amount
796
- sell_amount = 0
797
- first_buy_order.set_filled(remaining)
798
- else:
799
- sell_amount = sell_amount - available
800
- buy_orders_queue.dequeue()
801
-
802
- for buy_order in buy_orders_queue:
803
- symbol = buy_order.get_symbol()
804
-
805
- try:
806
- ticker = self._market_data_source_service.get_ticker(
807
- symbol=symbol, market=market
808
- )
809
- except Exception as e:
810
- logger.error(e)
811
- raise ApiException(
812
- f"Error getting ticker data for "
813
- f"trade {buy_order.get_target_symbol()}"
814
- f"-{buy_order.get_trading_symbol()}. Make sure you "
815
- f"have registered a ticker market data source for "
816
- f"{buy_order.get_target_symbol()}"
817
- f"-{buy_order.get_trading_symbol()} "
818
- f"for market {portfolio.market}"
819
- )
820
-
821
- amount = buy_order.get_filled()
822
- closed_amount = buy_order.get_trade_closed_amount()
823
-
824
- if closed_amount is not None:
825
- amount = amount - closed_amount
826
-
827
- trades.append(
828
- Trade(
829
- buy_order_id=buy_order.id,
830
- target_symbol=buy_order.get_target_symbol(),
831
- trading_symbol=buy_order.get_trading_symbol(),
832
- amount=amount,
833
- open_price=buy_order.get_price(),
834
- opened_at=buy_order.get_created_at(),
835
- current_price=ticker["bid"]
836
- )
837
- )
838
-
839
- return trades
707
+ return self.trade_service.get_open_trades(target_symbol, market)
840
708
 
841
709
  def close_trade(self, trade, market=None):
842
-
843
- if trade.closed_at is not None:
844
- raise ApiException("Trade already closed.")
845
-
846
- order = self.order_service.get(trade.buy_order_id)
847
-
848
- if order.get_filled() <= 0:
849
- raise ApiException(
850
- "Buy order belonging to the trade has no amount."
851
- )
852
-
853
- portfolio = self.portfolio_service\
854
- .find({"position": order.position_id})
855
- position = self.position_service.find(
856
- {"portfolio": portfolio.id, "symbol": order.get_target_symbol()}
857
- )
858
- amount = order.get_amount()
859
-
860
- if position.get_amount() < amount:
861
- logger.warning(
862
- f"Order amount {amount} is larger then amount "
863
- f"of available {position.symbol} "
864
- f"position: {position.get_amount()}, "
865
- f"changing order amount to size of position"
866
- )
867
- amount = position.get_amount()
868
-
869
- symbol = f"{order.get_target_symbol().upper()}" \
870
- f"/{order.get_trading_symbol().upper()}"
871
- ticker = self._market_data_source_service.get_ticker(
872
- symbol=symbol, market=market
873
- )
874
- self.create_limit_order(
875
- target_symbol=order.target_symbol,
876
- amount=amount,
877
- order_side=OrderSide.SELL.value,
878
- price=ticker["bid"],
879
- )
710
+ self.trade_service.close_trade(trade, market)
880
711
 
881
712
  def get_number_of_positions(self):
882
713
  """
@@ -17,7 +17,7 @@ from investing_algorithm_framework.app.web import create_flask_app
17
17
  from investing_algorithm_framework.domain import DATABASE_NAME, TimeUnit, \
18
18
  DATABASE_DIRECTORY_PATH, RESOURCE_DIRECTORY, ENVIRONMENT, Environment, \
19
19
  SQLALCHEMY_DATABASE_URI, OperationalException, BACKTESTING_FLAG, \
20
- BACKTESTING_START_DATE, MarketService, BACKTESTING_END_DATE, \
20
+ BACKTESTING_START_DATE, BACKTESTING_END_DATE, \
21
21
  BACKTESTING_PENDING_ORDER_CHECK_INTERVAL
22
22
  from investing_algorithm_framework.infrastructure import setup_sqlalchemy, \
23
23
  create_all_tables
@@ -40,7 +40,6 @@ class App:
40
40
  self._strategies = []
41
41
  self._tasks = []
42
42
  self._configuration_service = None
43
- self._market_service: MarketService = None
44
43
  self._market_data_source_service: MarketDataSourceService = None
45
44
  self._market_credential_service: MarketCredentialService = None
46
45
 
@@ -50,7 +49,6 @@ class App:
50
49
 
51
50
  def initialize_services(self):
52
51
  self._configuration_service = self.container.configuration_service()
53
- self._market_service = self.container.market_service()
54
52
  self._market_data_source_service = \
55
53
  self.container.market_data_source_service()
56
54
  self._market_credential_service = \
@@ -559,7 +557,11 @@ class App:
559
557
  return self.algorithm.get_portfolio_configurations()
560
558
 
561
559
  def backtest(
562
- self, start_date, end_date, pending_order_check_interval='1h'
560
+ self,
561
+ start_date,
562
+ end_date,
563
+ pending_order_check_interval='1h',
564
+ output_directory=None
563
565
  ):
564
566
  logger.info("Initializing backtest")
565
567
 
@@ -578,6 +580,19 @@ class App:
578
580
  report = backtest_service.backtest(
579
581
  self.algorithm, start_date, end_date
580
582
  )
583
+ backtest_report_writer_service = self.container\
584
+ .backtest_report_writer_service()
585
+
586
+ if output_directory is None:
587
+ output_directory = os.path.join(
588
+ self.config.get(RESOURCE_DIRECTORY),
589
+ "backtest_reports"
590
+ )
591
+
592
+ backtest_report_writer_service.write_report_to_csv(
593
+ report=report, output_directory=output_directory
594
+ )
595
+
581
596
  return report
582
597
 
583
598
  def add_market_data_source(self, market_data_source):
@@ -7,11 +7,13 @@ class TradingStrategy:
7
7
  time_unit: str = None
8
8
  interval: int = None
9
9
  worker_id: str = None
10
+ strategy_id: str = None
10
11
  decorated = None
11
12
  market_data_sources = None
12
13
 
13
14
  def __init__(
14
15
  self,
16
+ strategy_id=None,
15
17
  time_unit=None,
16
18
  interval=None,
17
19
  market_data_sources=None,
@@ -41,6 +43,9 @@ class TradingStrategy:
41
43
  else:
42
44
  self.worker_id = self.__class__.__name__
43
45
 
46
+ if strategy_id is not None:
47
+ self.strategy_id = strategy_id
48
+
44
49
  def run_strategy(self, algorithm, market_data):
45
50
  self.apply_strategy(algorithm=algorithm, market_data=market_data)
46
51
 
@@ -105,3 +110,11 @@ class TradingStrategy:
105
110
 
106
111
  def on_trade_take_profit_created(self, algorithm: Algorithm, trade: Trade):
107
112
  pass
113
+
114
+ @property
115
+ def strategy_identifier(self):
116
+
117
+ if self.strategy_id is not None:
118
+ return self.strategy_id
119
+
120
+ return self.worker_id
@@ -7,9 +7,9 @@ from investing_algorithm_framework.infrastructure import SQLOrderRepository, \
7
7
  SQLPositionSnapshotRepository, PerformanceService, CCXTMarketService
8
8
  from investing_algorithm_framework.services import OrderService, \
9
9
  PositionService, PortfolioService, StrategyOrchestratorService, \
10
- PortfolioConfigurationService, MarketDataSourceService, BackTestService, \
10
+ PortfolioConfigurationService, MarketDataSourceService, BacktestService, \
11
11
  ConfigurationService, PortfolioSnapshotService, PositionSnapshotService, \
12
- MarketCredentialService
12
+ MarketCredentialService, TradeService, BacktestReportWriterService
13
13
 
14
14
 
15
15
  def setup_dependency_container(app, modules=None, packages=None):
@@ -88,6 +88,13 @@ class DependencyContainer(containers.DeclarativeContainer):
88
88
  portfolio_configuration_service=portfolio_configuration_service,
89
89
  portfolio_snapshot_service=portfolio_snapshot_service,
90
90
  )
91
+ trade_service = providers.Factory(
92
+ TradeService,
93
+ portfolio_service=portfolio_service,
94
+ order_service=order_service,
95
+ market_data_source_service=market_data_source_service,
96
+ position_service=position_service,
97
+ )
91
98
  strategy_orchestrator_service = providers.Factory(
92
99
  StrategyOrchestratorService,
93
100
  market_data_source_service=market_data_source_service
@@ -99,13 +106,16 @@ class DependencyContainer(containers.DeclarativeContainer):
99
106
  portfolio_repository=portfolio_repository
100
107
  )
101
108
  backtest_service = providers.Factory(
102
- BackTestService,
109
+ BacktestService,
103
110
  order_service=order_service,
104
111
  portfolio_repository=portfolio_repository,
105
112
  performance_service=performance_service,
106
113
  position_repository=position_repository,
107
114
  market_data_source_service=market_data_source_service,
108
115
  )
116
+ backtest_report_writer_service = providers.Factory(
117
+ BacktestReportWriterService,
118
+ )
109
119
  algorithm = providers.Factory(
110
120
  Algorithm,
111
121
  configuration_service=configuration_service,
@@ -117,4 +127,5 @@ class DependencyContainer(containers.DeclarativeContainer):
117
127
  market_credential_service=market_credential_service,
118
128
  market_data_source_service=market_data_source_service,
119
129
  market_service=market_service,
130
+ trade_service=trade_service,
120
131
  )
@@ -2,7 +2,7 @@ from .config import Config, Environment
2
2
  from .models import OrderStatus, OrderSide, OrderType, TimeInterval, \
3
3
  TimeUnit, TimeFrame, TradingTimeFrame, TradingDataType, \
4
4
  PortfolioConfiguration, Portfolio, Position, Order, \
5
- OrderFee, BacktestProfile, PortfolioSnapshot, StrategyProfile, \
5
+ OrderFee, BacktestReport, PortfolioSnapshot, StrategyProfile, \
6
6
  BacktestPosition, Trade, MarketCredential, PositionSnapshot
7
7
  from .exceptions import OperationalException, ApiException, \
8
8
  PermissionDeniedApiException, ImproperlyConfigured
@@ -70,7 +70,7 @@ __all__ = [
70
70
  "OrderFee",
71
71
  "parse_decimal_to_string",
72
72
  "parse_string_to_decimal",
73
- "BacktestProfile",
73
+ "BacktestReport",
74
74
  "pretty_print_backtest",
75
75
  "DATETIME_FORMAT_BACKTESTING",
76
76
  "BACKTESTING_FLAG",
@@ -7,7 +7,7 @@ from .trading_data_types import TradingDataType
7
7
  from .trading_time_frame import TradingTimeFrame
8
8
  from .portfolio import PortfolioConfiguration, Portfolio, PortfolioSnapshot
9
9
  from .position import Position, PositionSnapshot
10
- from .backtest_profile import BacktestProfile, BacktestPosition
10
+ from .backtesting import BacktestReport, BacktestPosition
11
11
  from .strategy_profile import StrategyProfile
12
12
  from .trade import Trade
13
13
 
@@ -25,7 +25,7 @@ __all__ = [
25
25
  "Position",
26
26
  "Portfolio",
27
27
  "OrderFee",
28
- "BacktestProfile",
28
+ "BacktestReport",
29
29
  "PositionSnapshot",
30
30
  "PortfolioSnapshot",
31
31
  "StrategyProfile",
@@ -0,0 +1,6 @@
1
+ from .backtest_report import BacktestReport, BacktestPosition
2
+
3
+ __all__ = [
4
+ "BacktestReport",
5
+ "BacktestPosition"
6
+ ]
@@ -1,5 +1,6 @@
1
- from .base_model import BaseModel
2
- from .time_unit import TimeUnit
1
+ from datetime import datetime
2
+ from investing_algorithm_framework.domain.models.base_model import BaseModel
3
+ from investing_algorithm_framework.domain.models.time_unit import TimeUnit
3
4
 
4
5
 
5
6
  class BacktestPosition(BaseModel):
@@ -97,10 +98,11 @@ class BacktestPosition(BaseModel):
97
98
  return self.value / self._total_value_portfolio * 100
98
99
 
99
100
 
100
- class BacktestProfile(BaseModel):
101
+ class BacktestReport(BaseModel):
101
102
 
102
103
  def __init__(
103
104
  self,
105
+ identifier=None,
104
106
  portfolio_id=None,
105
107
  initial_unallocated=0.0,
106
108
  interval=None,
@@ -132,8 +134,10 @@ class BacktestProfile(BaseModel):
132
134
  positions=None,
133
135
  average_trade_duration=0,
134
136
  average_trade_size=0.0,
135
- trades=None
137
+ trades=None,
138
+ created_at: datetime = None
136
139
  ):
140
+ self._identifier = identifier
137
141
  self._portfolio_id = portfolio_id
138
142
  self._interval = interval
139
143
  self._time_unit = time_unit
@@ -169,6 +173,15 @@ class BacktestProfile(BaseModel):
169
173
  self._average_trade_duration = average_trade_duration
170
174
  self._average_trade_size = average_trade_size
171
175
  self._trades = trades
176
+ self._created_at: datetime = created_at
177
+
178
+ @property
179
+ def identifier(self):
180
+ return self._identifier
181
+
182
+ @property
183
+ def created_at(self):
184
+ return self._created_at
172
185
 
173
186
  @property
174
187
  def portfolio_id(self):
@@ -454,3 +467,39 @@ class BacktestProfile(BaseModel):
454
467
  time_unit=self.time_unit,
455
468
  interval=self.interval
456
469
  )
470
+
471
+ def to_dict(self):
472
+ return {
473
+ "portfolio_id": self.portfolio_id,
474
+ "interval": self.interval,
475
+ "time_unit": self.time_unit,
476
+ "backtest_start_date_data": self.backtest_start_date_data,
477
+ "backtest_start_date": self.backtest_start_date,
478
+ "backtest_end_date": self.backtest_end_date,
479
+ "backtest_index_date": self.backtest_index_date,
480
+ "number_of_runs": self.number_of_runs,
481
+ "trading_time_frame": self.trading_time_frame,
482
+ "trading_time_frame_start_date":
483
+ self.trading_time_frame_start_date,
484
+ "symbols": self.symbols,
485
+ "market": self.market,
486
+ "number_of_days": self.number_of_days,
487
+ "number_of_orders": self.number_of_orders,
488
+ "number_of_positions": self.number_of_positions,
489
+ "market_data_file": self.market_data_file,
490
+ "percentage_positive_trades": self.percentage_positive_trades,
491
+ "percentage_negative_trades": self.percentage_negative_trades,
492
+ "number_of_trades_closed": self.number_of_trades_closed,
493
+ "number_of_trades_open": self.number_of_trades_open,
494
+ "total_cost": self.total_cost,
495
+ "growth_rate": self.growth_rate,
496
+ "growth": self.growth,
497
+ "initial_unallocated": self.initial_unallocated,
498
+ "trading_symbol": self.trading_symbol,
499
+ "total_net_gain_percentage": self.total_net_gain_percentage,
500
+ "total_net_gain": self.total_net_gain,
501
+ "backtest_data_index_date": self.backtest_data_index_date,
502
+ "total_value": self.total_value,
503
+ "average_trade_duration": self.average_trade_duration,
504
+ "average_trade_size": self.average_trade_size,
505
+ }