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,6 +1,7 @@
1
1
  import logging
2
2
 
3
3
  from sqlalchemy import create_engine, StaticPool
4
+ from sqlalchemy import inspect
4
5
  from sqlalchemy.orm import DeclarativeBase, sessionmaker
5
6
 
6
7
  from investing_algorithm_framework.domain import SQLALCHEMY_DATABASE_URI, \
@@ -38,9 +39,89 @@ def setup_sqlalchemy(app, throw_exception_if_not_set=True):
38
39
  return app
39
40
 
40
41
 
42
+
41
43
  class SQLBaseModel(DeclarativeBase):
42
44
  pass
43
45
 
44
46
 
45
47
  def create_all_tables():
46
48
  SQLBaseModel.metadata.create_all(bind=Session().bind)
49
+
50
+
51
+ from sqlalchemy import event
52
+ from sqlalchemy.orm import mapper
53
+ from datetime import timezone
54
+
55
+ def clear_db(db_uri):
56
+ """
57
+ Clear the database by dropping all tables.
58
+ This is useful for testing purposes.
59
+
60
+ Args:
61
+ db_uri (str): The database URI to connect to.
62
+
63
+ Returns:
64
+ None
65
+ """
66
+ # Drop all tables before deleting file
67
+ try:
68
+ engine = create_engine(db_uri)
69
+ inspector = inspect(engine)
70
+ if inspector.get_table_names():
71
+ logger.info("Dropping all tables in backtest database")
72
+ SQLBaseModel.metadata.drop_all(bind=engine)
73
+ except Exception as e:
74
+ logger.error(f"Error dropping tables: {e}")
75
+
76
+ # # Clear mappers (if using classical mappings)
77
+ # try:
78
+ # clear_mappers()
79
+ # except Exception:
80
+ # pass # ignore if not needed
81
+
82
+
83
+ @event.listens_for(mapper, "load")
84
+ def attach_utc_timezone_on_load(target, context):
85
+ """
86
+ For each model instance loaded from the database,
87
+ this function will check if one of the following attributes are
88
+ present: created_at, updated_at, closed_at, opened_at, triggered_at.
89
+ If so, it will check if these datetime
90
+ attributes are timezone-naive and, if so, will set them to UTC.
91
+
92
+ Its documented in the contributing guide (https://coding-kitties.github
93
+ .io/investing-algorithm-framework/Contributing%20Guide/contributing)
94
+ that each datetime attribute should be utc timezone-aware.
95
+
96
+ Args:
97
+ target: The model instance being loaded from the database.
98
+ context: The context in which the event is being handled.
99
+
100
+ Returns:
101
+ None
102
+ """
103
+ # This will apply to every model instance loaded from the DB
104
+ if hasattr(target, "created_at"):
105
+ dt = getattr(target, "created_at")
106
+ if dt and dt.tzinfo is None:
107
+ target.created_at = dt.replace(tzinfo=timezone.utc)
108
+
109
+ if hasattr(target, "updated_at"):
110
+ dt = getattr(target, "updated_at")
111
+ if dt and dt.tzinfo is None:
112
+ target.updated_at = dt.replace(tzinfo=timezone.utc)
113
+
114
+ if hasattr(target, "closed_at"):
115
+ dt = getattr(target, "closed_at")
116
+ if dt and dt.tzinfo is None:
117
+ target.closed_at = dt.replace(tzinfo=timezone.utc)
118
+
119
+ if hasattr(target, "opened_at"):
120
+ dt = getattr(target, "opened_at")
121
+ if dt and dt.tzinfo is None:
122
+ target.opened_at = dt.replace(tzinfo=timezone.utc)
123
+
124
+ if hasattr(target, "triggered_at"):
125
+ dt = getattr(target, "triggered_at")
126
+ if dt and dt.tzinfo is None:
127
+ target.triggered_at = dt.replace(tzinfo=timezone.utc)
@@ -1,8 +1,3 @@
1
- from .market_data_sources import CCXTOrderBookMarketDataSource, \
2
- CCXTTickerMarketDataSource, CCXTOHLCVMarketDataSource, \
3
- CCXTOHLCVBacktestMarketDataSource, CSVOHLCVMarketDataSource, \
4
- CSVTickerMarketDataSource, PandasOHLCVBacktestMarketDataSource, \
5
- PandasOHLCVMarketDataSource
6
1
  from .order import SQLOrder, SQLOrderMetadata
7
2
  from .portfolio import SQLPortfolio, SQLPortfolioSnapshot
8
3
  from .position import SQLPosition, SQLPositionSnapshot
@@ -14,16 +9,8 @@ __all__ = [
14
9
  "SQLPortfolio",
15
10
  "SQLPositionSnapshot",
16
11
  "SQLPortfolioSnapshot",
17
- "CCXTOHLCVBacktestMarketDataSource",
18
- "CCXTOrderBookMarketDataSource",
19
- "CCXTTickerMarketDataSource",
20
- "CCXTOHLCVMarketDataSource",
21
- "CSVTickerMarketDataSource",
22
- "CSVOHLCVMarketDataSource",
23
12
  "SQLTrade",
24
13
  "SQLTradeStopLoss",
25
14
  "SQLTradeTakeProfit",
26
15
  "SQLOrderMetadata",
27
- "PandasOHLCVBacktestMarketDataSource",
28
- "PandasOHLCVMarketDataSource"
29
16
  ]
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from datetime import datetime
2
+ from datetime import datetime, timezone
3
3
 
4
4
  from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Float
5
5
  from sqlalchemy.orm import relationship
@@ -15,6 +15,10 @@ from investing_algorithm_framework.infrastructure.models.\
15
15
  logger = logging.getLogger("investing_algorithm_framework")
16
16
 
17
17
 
18
+ def utcnow():
19
+ return datetime.now(tz=timezone.utc)
20
+
21
+
18
22
  class SQLOrder(Order, SQLBaseModel, SQLAlchemyModelExtension):
19
23
  """
20
24
  SQLOrder model based on the Order domain model.
@@ -37,8 +41,10 @@ class SQLOrder(Order, SQLBaseModel, SQLAlchemyModelExtension):
37
41
  status = Column(String, default=OrderStatus.CREATED.value)
38
42
  position_id = Column(Integer, ForeignKey('positions.id'))
39
43
  position = relationship("SQLPosition", back_populates="orders")
40
- created_at = Column(DateTime, default=datetime.utcnow)
41
- updated_at = Column(DateTime, default=datetime.utcnow)
44
+ created_at = Column(DateTime(timezone=True), default=utcnow)
45
+ updated_at = Column(
46
+ DateTime(timezone=True), default=utcnow, onupdate=utcnow
47
+ )
42
48
  order_fee = Column(Float, default=None)
43
49
  order_fee_currency = Column(String, default=None)
44
50
  order_fee_rate = Column(Float, default=None)
@@ -1,4 +1,5 @@
1
- from sqlalchemy import Column, Integer, String, Float, ForeignKey, Boolean
1
+ from sqlalchemy import Column, Integer, String, Float, ForeignKey, Boolean, \
2
+ DateTime
2
3
  from sqlalchemy.orm import relationship
3
4
 
4
5
  from investing_algorithm_framework.domain import TradeStopLoss
@@ -14,19 +15,33 @@ class SQLTradeStopLoss(TradeStopLoss, SQLBaseModel, SQLAlchemyModelExtension):
14
15
  A trade stop loss is a stop loss strategy for a trade.
15
16
 
16
17
  Attributes:
17
- * trade: Trade - the trade that the take profit is for
18
- * take_profit: float - the take profit percentage
19
- * trade_risk_type: TradeRiskType - the type of trade risk, either
20
- trailing or fixed
21
- * sell_percentage: float - the percentage of the trade to sell when the
22
-
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.
23
38
  """
24
39
 
25
40
  __tablename__ = "trade_stop_losses"
26
41
  id = Column(Integer, primary_key=True, unique=True)
27
42
  trade_id = Column(Integer, ForeignKey('trades.id'))
28
43
  trade = relationship('SQLTrade', back_populates='stop_losses')
29
- trade_risk_type = Column(String)
44
+ trailing = Column(Boolean)
30
45
  percentage = Column(Float)
31
46
  sell_percentage = Column(Float)
32
47
  open_price = Column(Float)
@@ -38,3 +53,7 @@ class SQLTradeStopLoss(TradeStopLoss, SQLBaseModel, SQLAlchemyModelExtension):
38
53
  sell_amount = Column(Float)
39
54
  sold_amount = Column(Float)
40
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)
@@ -1,4 +1,5 @@
1
- from sqlalchemy import Column, Integer, String, Float, ForeignKey, Boolean
1
+ from sqlalchemy import Column, Integer, String, Float, ForeignKey, Boolean, \
2
+ DateTime
2
3
  from sqlalchemy.orm import relationship
3
4
 
4
5
  from investing_algorithm_framework.domain import TradeTakeProfit
@@ -16,18 +17,27 @@ class SQLTradeTakeProfit(
16
17
  A trade take profit is a take profit strategy for a trade.
17
18
 
18
19
  Attributes:
19
- * trade: Trade - the trade that the take profit is for
20
- * take_profit: float - the take profit percentage
21
- * trade_risk_type: TradeRiskType - the type of trade risk, either
22
- trailing or fixed
23
- * sell_percentage: float - the percentage of the trade to sell when the
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.
24
34
  """
25
35
 
26
36
  __tablename__ = "trade_take_profits"
27
37
  id = Column(Integer, primary_key=True, unique=True)
28
38
  trade_id = Column(Integer, ForeignKey('trades.id'))
29
39
  trade = relationship('SQLTrade', back_populates='take_profits')
30
- trade_risk_type = Column(String)
40
+ trailing = Column(Boolean)
31
41
  percentage = Column(Float)
32
42
  sell_percentage = Column(Float)
33
43
  open_price = Column(Float)
@@ -39,3 +49,7 @@ class SQLTradeTakeProfit(
39
49
  sell_dates = Column(String)
40
50
  sold_amount = Column(Float)
41
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)
@@ -1,4 +1,5 @@
1
1
  from .ccxt_order_executor import CCXTOrderExecutor
2
+ from .backtest_oder_executor import BacktestOrderExecutor
2
3
 
3
4
 
4
5
  def get_default_order_executors():
@@ -15,5 +16,6 @@ def get_default_order_executors():
15
16
 
16
17
  __all__ = [
17
18
  'CCXTOrderExecutor',
19
+ 'BacktestOrderExecutor',
18
20
  'get_default_order_executors',
19
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
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  from abc import ABC, abstractmethod
3
3
  from typing import Callable
4
+ from dateutil.parser import parse
4
5
 
5
6
  from sqlalchemy.exc import SQLAlchemyError
6
7
  from werkzeug.datastructures import MultiDict
@@ -12,6 +13,16 @@ from investing_algorithm_framework.infrastructure.database import Session
12
13
  logger = logging.getLogger("investing_algorithm_framework")
13
14
 
14
15
 
16
+ def convert_datetime_fields(data, datetime_fields):
17
+ for field in datetime_fields:
18
+ if field in data and isinstance(data[field], str):
19
+ try:
20
+ data[field] = parse(data[field])
21
+ except Exception:
22
+ pass # Ignore if not a valid datetime string
23
+ return data
24
+
25
+
15
26
  class Repository(ABC):
16
27
  base_class: Callable
17
28
  DEFAULT_NOT_FOUND_MESSAGE = "The requested resource was not found"
@@ -20,7 +31,6 @@ class Repository(ABC):
20
31
 
21
32
  def create(self, data, save=True):
22
33
  created_object = self.base_class(**data)
23
-
24
34
  if save:
25
35
  with Session() as db:
26
36
  try:
@@ -35,7 +45,11 @@ class Repository(ABC):
35
45
  return created_object
36
46
 
37
47
  def update(self, object_id, data):
38
-
48
+ # List all datetime fields for your model
49
+ datetime_fields = [
50
+ "created_at", "updated_at", "closed_at", "opened_at"
51
+ ]
52
+ data = convert_datetime_fields(data, datetime_fields)
39
53
  with Session() as db:
40
54
  try:
41
55
  update_object = self.get(object_id)
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from sqlalchemy.exc import SQLAlchemyError
3
3
 
4
- from investing_algorithm_framework.domain import OrderStatus, ApiException
4
+ from investing_algorithm_framework.domain import TradeStatus, ApiException
5
5
  from investing_algorithm_framework.infrastructure.models import SQLPosition, \
6
6
  SQLPortfolio, SQLTrade, SQLOrder
7
7
  from investing_algorithm_framework.infrastructure.database import Session
@@ -43,7 +43,7 @@ class SQLTradeRepository(Repository):
43
43
  .filter(SQLPosition.portfolio_id == portfolio.id)
44
44
 
45
45
  if status_query_param:
46
- status = OrderStatus.from_value(status_query_param)
46
+ status = TradeStatus.from_value(status_query_param)
47
47
  # Explicitly filter on SQLTrade.status
48
48
  query = query.filter(SQLTrade.status == status.value)
49
49
 
@@ -14,10 +14,16 @@ class SQLTradeStopLossRepository(Repository):
14
14
 
15
15
  def _apply_query_params(self, db, query, query_params):
16
16
  trade_query_param = self.get_query_param("trade_id", query_params)
17
+ triggered_query_param = self.get_query_param(
18
+ "triggered", query_params
19
+ )
17
20
 
18
21
  if trade_query_param:
19
22
  query = query.filter(
20
23
  SQLTradeStopLoss.trade_id == trade_query_param
21
24
  )
22
25
 
26
+ if triggered_query_param is not None:
27
+ query = query.filter_by(triggered=triggered_query_param)
28
+
23
29
  return query
@@ -14,10 +14,16 @@ class SQLTradeTakeProfitRepository(Repository):
14
14
 
15
15
  def _apply_query_params(self, db, query, query_params):
16
16
  trade_query_param = self.get_query_param("trade_id", query_params)
17
+ triggered_query_param = self.get_query_param(
18
+ "triggered", query_params
19
+ )
17
20
 
18
21
  if trade_query_param:
19
22
  query = query.filter(
20
23
  SQLTradeTakeProfit.trade_id == trade_query_param
21
24
  )
22
25
 
26
+ if triggered_query_param is not None:
27
+ query = query.filter_by(triggered=triggered_query_param)
28
+
23
29
  return query
@@ -1,11 +1,7 @@
1
- from .market_service import CCXTMarketService
2
- from .performance_service import PerformanceService
3
1
  from .azure import AzureBlobStorageStateHandler
4
2
  from .aws import AWSS3StorageStateHandler
5
3
 
6
4
  __all__ = [
7
- "PerformanceService",
8
- "CCXTMarketService",
9
5
  "AzureBlobStorageStateHandler",
10
6
  "AWSS3StorageStateHandler"
11
7
  ]
@@ -1,8 +1,9 @@
1
1
  from .backtesting import BacktestService
2
+ from .trade_order_evaluator import BacktestTradeOrderEvaluator, \
3
+ TradeOrderEvaluator, DefaultTradeOrderEvaluator
2
4
  from .configuration_service import ConfigurationService
3
5
  from .market_credential_service import MarketCredentialService
4
- from .market_data_source_service import MarketDataSourceService, \
5
- BacktestMarketDataSourceService, DataProviderService
6
+ from .data_providers import DataProviderService
6
7
  from .order_service import OrderService, OrderBacktestService, \
7
8
  OrderExecutorLookup
8
9
  from .portfolios import PortfolioService, BacktestPortfolioService, \
@@ -10,17 +11,41 @@ from .portfolios import PortfolioService, BacktestPortfolioService, \
10
11
  PortfolioSnapshotService, PortfolioProviderLookup
11
12
  from .positions import PositionService, PositionSnapshotService
12
13
  from .repository_service import RepositoryService
13
- from .strategy_orchestrator_service import StrategyOrchestratorService
14
- from .trade_service import TradeService
14
+ from .trade_service import TradeService, TradeStopLossService, \
15
+ TradeTakeProfitService
16
+ from .metrics import get_annual_volatility, \
17
+ get_sortino_ratio, get_drawdown_series, get_max_drawdown, \
18
+ get_equity_curve, get_price_efficiency_ratio, get_sharpe_ratio, \
19
+ get_profit_factor, get_cumulative_profit_factor_series, \
20
+ get_rolling_profit_factor_series, \
21
+ get_cagr, get_standard_deviation_returns, \
22
+ get_standard_deviation_downside_returns, \
23
+ get_total_return, get_cumulative_exposure, get_exposure_ratio, \
24
+ get_yearly_returns, get_monthly_returns, get_best_year, \
25
+ get_best_month, get_worst_year, get_worst_month, get_best_trade, \
26
+ get_worst_trade, get_average_yearly_return, get_average_trade_gain, \
27
+ get_average_trade_loss, get_average_monthly_return, \
28
+ get_percentage_winning_months, get_average_trade_duration, \
29
+ get_trade_frequency, get_win_rate, get_win_loss_ratio, \
30
+ get_calmar_ratio, get_max_drawdown_absolute, get_current_win_loss_ratio, \
31
+ get_max_drawdown_duration, get_max_daily_drawdown, get_trades_per_day, \
32
+ get_trades_per_year, get_average_monthly_return_losing_months, \
33
+ get_average_monthly_return_winning_months, get_percentage_winning_years, \
34
+ get_rolling_sharpe_ratio, create_backtest_metrics, get_total_growth, \
35
+ get_total_loss, get_risk_free_rate_us, get_median_trade_return, \
36
+ get_average_trade_return, get_cumulative_return, \
37
+ get_cumulative_return_series, get_average_trade_size, \
38
+ get_positive_trades, get_negative_trades, get_number_of_trades, \
39
+ get_current_win_rate, get_current_average_trade_return, \
40
+ get_current_average_trade_loss, get_current_average_trade_duration, \
41
+ get_current_average_trade_gain, create_backtest_metrics_for_backtest
15
42
 
16
43
  __all__ = [
17
- "StrategyOrchestratorService",
18
44
  "OrderService",
19
45
  "RepositoryService",
20
46
  "PortfolioService",
21
47
  "PositionService",
22
48
  "PortfolioConfigurationService",
23
- "MarketDataSourceService",
24
49
  "BacktestService",
25
50
  "OrderBacktestService",
26
51
  "ConfigurationService",
@@ -28,11 +53,83 @@ __all__ = [
28
53
  "PortfolioSnapshotService",
29
54
  "PositionSnapshotService",
30
55
  "MarketCredentialService",
31
- "BacktestMarketDataSourceService",
32
56
  "BacktestPortfolioService",
33
57
  "TradeService",
34
58
  "DataProviderService",
35
59
  "OrderExecutorLookup",
36
- "PortfolioServiceV2",
60
+ "BacktestTradeOrderEvaluator",
37
61
  "PortfolioProviderLookup",
62
+ "TradeOrderEvaluator",
63
+ "DefaultTradeOrderEvaluator",
64
+ "get_risk_free_rate_us",
65
+ "get_annual_volatility",
66
+ "get_sortino_ratio",
67
+ "get_drawdown_series",
68
+ "get_max_drawdown",
69
+ "get_equity_curve",
70
+ "get_price_efficiency_ratio",
71
+ "get_sharpe_ratio",
72
+ "get_profit_factor",
73
+ "get_cumulative_profit_factor_series",
74
+ "get_rolling_profit_factor_series",
75
+ "get_sharpe_ratio",
76
+ "get_cagr",
77
+ "get_standard_deviation_returns",
78
+ "get_standard_deviation_downside_returns",
79
+ "get_max_drawdown_absolute",
80
+ "get_total_return",
81
+ "get_cumulative_exposure",
82
+ "get_exposure_ratio",
83
+ "get_average_trade_duration",
84
+ "get_win_rate",
85
+ "get_win_loss_ratio",
86
+ "get_calmar_ratio",
87
+ "get_trade_frequency",
88
+ "get_yearly_returns",
89
+ "get_monthly_returns",
90
+ "get_best_year",
91
+ "get_best_month",
92
+ "get_worst_year",
93
+ "get_worst_month",
94
+ "get_best_trade",
95
+ "get_worst_trade",
96
+ "get_average_yearly_return",
97
+ "get_average_trade_loss",
98
+ "get_average_monthly_return",
99
+ "get_percentage_winning_months",
100
+ "get_average_trade_duration",
101
+ "get_trade_frequency",
102
+ "get_win_rate",
103
+ "get_win_loss_ratio",
104
+ "get_calmar_ratio",
105
+ "get_max_drawdown_duration",
106
+ "get_max_daily_drawdown",
107
+ "get_trades_per_day",
108
+ "get_trades_per_year",
109
+ "get_average_monthly_return_losing_months",
110
+ "get_average_monthly_return_winning_months",
111
+ "get_percentage_winning_years",
112
+ "get_rolling_sharpe_ratio",
113
+ "get_total_growth",
114
+ "create_backtest_metrics",
115
+ "get_total_loss",
116
+ "get_median_trade_return",
117
+ "get_average_trade_gain",
118
+ "get_average_trade_size",
119
+ "get_average_trade_return",
120
+ "get_positive_trades",
121
+ "get_negative_trades",
122
+ "get_number_of_trades",
123
+ "get_cumulative_return",
124
+ "get_cumulative_return_series",
125
+ "get_current_win_loss_ratio",
126
+ "get_current_win_rate",
127
+ "get_current_win_loss_ratio",
128
+ "get_current_average_trade_loss",
129
+ "get_current_average_trade_duration",
130
+ "get_current_average_trade_gain",
131
+ "get_current_average_trade_return",
132
+ "create_backtest_metrics_for_backtest",
133
+ "TradeStopLossService",
134
+ "TradeTakeProfitService"
38
135
  ]