investing-algorithm-framework 1.3.1__py3-none-any.whl → 7.25.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. investing_algorithm_framework/__init__.py +195 -16
  2. investing_algorithm_framework/analysis/__init__.py +16 -0
  3. investing_algorithm_framework/analysis/backtest_data_ranges.py +202 -0
  4. investing_algorithm_framework/analysis/data.py +170 -0
  5. investing_algorithm_framework/analysis/markdown.py +91 -0
  6. investing_algorithm_framework/analysis/ranking.py +298 -0
  7. investing_algorithm_framework/app/__init__.py +31 -4
  8. investing_algorithm_framework/app/algorithm/__init__.py +7 -0
  9. investing_algorithm_framework/app/algorithm/algorithm.py +193 -0
  10. investing_algorithm_framework/app/algorithm/algorithm_factory.py +118 -0
  11. investing_algorithm_framework/app/app.py +2233 -264
  12. investing_algorithm_framework/app/app_hook.py +28 -0
  13. investing_algorithm_framework/app/context.py +1724 -0
  14. investing_algorithm_framework/app/eventloop.py +620 -0
  15. investing_algorithm_framework/app/reporting/__init__.py +27 -0
  16. investing_algorithm_framework/app/reporting/ascii.py +921 -0
  17. investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
  18. investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
  19. investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
  20. investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
  21. investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
  22. investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
  23. investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
  24. investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
  25. investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
  26. investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
  27. investing_algorithm_framework/app/reporting/generate.py +185 -0
  28. investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
  29. investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
  30. investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
  31. investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
  32. investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
  33. investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
  34. investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
  35. investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
  36. investing_algorithm_framework/app/stateless/action_handlers/__init__.py +6 -3
  37. investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
  38. investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +2 -1
  39. investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
  40. investing_algorithm_framework/app/stateless/exception_handler.py +1 -1
  41. investing_algorithm_framework/app/strategy.py +873 -52
  42. investing_algorithm_framework/app/task.py +5 -3
  43. investing_algorithm_framework/app/web/__init__.py +2 -1
  44. investing_algorithm_framework/app/web/controllers/__init__.py +2 -2
  45. investing_algorithm_framework/app/web/controllers/orders.py +4 -3
  46. investing_algorithm_framework/app/web/controllers/portfolio.py +1 -1
  47. investing_algorithm_framework/app/web/controllers/positions.py +3 -3
  48. investing_algorithm_framework/app/web/create_app.py +4 -2
  49. investing_algorithm_framework/app/web/error_handler.py +1 -1
  50. investing_algorithm_framework/app/web/schemas/order.py +2 -2
  51. investing_algorithm_framework/app/web/schemas/position.py +1 -0
  52. investing_algorithm_framework/cli/__init__.py +0 -0
  53. investing_algorithm_framework/cli/cli.py +231 -0
  54. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
  55. investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
  56. investing_algorithm_framework/cli/initialize_app.py +603 -0
  57. investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
  58. investing_algorithm_framework/cli/templates/app.py.template +18 -0
  59. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
  60. investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
  61. investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
  62. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  63. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  64. investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
  65. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
  66. investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
  67. investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
  68. investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
  69. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
  70. investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
  71. investing_algorithm_framework/cli/templates/env.example.template +2 -0
  72. investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
  73. investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
  74. investing_algorithm_framework/cli/templates/readme.md.template +135 -0
  75. investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
  76. investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
  77. investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
  78. investing_algorithm_framework/cli/validate_backtest_checkpoints.py +197 -0
  79. investing_algorithm_framework/create_app.py +43 -9
  80. investing_algorithm_framework/dependency_container.py +121 -33
  81. investing_algorithm_framework/domain/__init__.py +109 -22
  82. investing_algorithm_framework/domain/algorithm_id.py +69 -0
  83. investing_algorithm_framework/domain/backtesting/__init__.py +25 -0
  84. investing_algorithm_framework/domain/backtesting/backtest.py +548 -0
  85. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +113 -0
  86. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +241 -0
  87. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +470 -0
  88. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  89. investing_algorithm_framework/domain/backtesting/backtest_run.py +663 -0
  90. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  91. investing_algorithm_framework/domain/backtesting/backtest_utils.py +198 -0
  92. investing_algorithm_framework/domain/backtesting/combine_backtests.py +392 -0
  93. investing_algorithm_framework/domain/config.py +60 -138
  94. investing_algorithm_framework/domain/constants.py +23 -34
  95. investing_algorithm_framework/domain/data_provider.py +334 -0
  96. investing_algorithm_framework/domain/data_structures.py +42 -0
  97. investing_algorithm_framework/domain/decimal_parsing.py +40 -0
  98. investing_algorithm_framework/domain/exceptions.py +51 -1
  99. investing_algorithm_framework/domain/models/__init__.py +29 -14
  100. investing_algorithm_framework/domain/models/app_mode.py +34 -0
  101. investing_algorithm_framework/domain/models/base_model.py +3 -1
  102. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  103. investing_algorithm_framework/domain/models/data/data_source.py +222 -0
  104. investing_algorithm_framework/domain/models/data/data_type.py +46 -0
  105. investing_algorithm_framework/domain/models/event.py +35 -0
  106. investing_algorithm_framework/domain/models/market/__init__.py +5 -0
  107. investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
  108. investing_algorithm_framework/domain/models/order/__init__.py +3 -4
  109. investing_algorithm_framework/domain/models/order/order.py +243 -86
  110. investing_algorithm_framework/domain/models/order/order_status.py +2 -2
  111. investing_algorithm_framework/domain/models/order/order_type.py +1 -3
  112. investing_algorithm_framework/domain/models/portfolio/__init__.py +7 -2
  113. investing_algorithm_framework/domain/models/portfolio/portfolio.py +134 -1
  114. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -37
  115. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +208 -0
  116. investing_algorithm_framework/domain/models/position/__init__.py +3 -2
  117. investing_algorithm_framework/domain/models/position/position.py +29 -0
  118. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  119. investing_algorithm_framework/domain/models/position/{position_cost.py → position_snapshot.py} +16 -8
  120. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  121. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  122. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  123. investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
  124. investing_algorithm_framework/domain/models/strategy_profile.py +33 -0
  125. investing_algorithm_framework/domain/models/time_frame.py +94 -98
  126. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  127. investing_algorithm_framework/domain/models/time_unit.py +111 -2
  128. investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
  129. investing_algorithm_framework/domain/models/tracing/trace.py +23 -0
  130. investing_algorithm_framework/domain/models/trade/__init__.py +11 -0
  131. investing_algorithm_framework/domain/models/trade/trade.py +389 -0
  132. investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
  133. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
  134. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
  135. investing_algorithm_framework/domain/order_executor.py +112 -0
  136. investing_algorithm_framework/domain/portfolio_provider.py +118 -0
  137. investing_algorithm_framework/domain/services/__init__.py +11 -0
  138. investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
  139. investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
  140. investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
  141. investing_algorithm_framework/domain/services/rounding_service.py +27 -0
  142. investing_algorithm_framework/domain/services/state_handler.py +38 -0
  143. investing_algorithm_framework/domain/strategy.py +1 -29
  144. investing_algorithm_framework/domain/utils/__init__.py +16 -4
  145. investing_algorithm_framework/domain/utils/csv.py +22 -0
  146. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  147. investing_algorithm_framework/domain/utils/dates.py +57 -0
  148. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  149. investing_algorithm_framework/domain/utils/polars.py +53 -0
  150. investing_algorithm_framework/domain/utils/random.py +29 -0
  151. investing_algorithm_framework/download_data.py +244 -0
  152. investing_algorithm_framework/infrastructure/__init__.py +39 -11
  153. investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
  154. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1152 -0
  155. investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
  156. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  157. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  158. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +87 -13
  159. investing_algorithm_framework/infrastructure/models/__init__.py +13 -4
  160. investing_algorithm_framework/infrastructure/models/decimal_parser.py +14 -0
  161. investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
  162. investing_algorithm_framework/infrastructure/models/order/order.py +73 -73
  163. investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
  164. investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
  165. investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +3 -2
  166. investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +37 -0
  167. investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +57 -3
  168. investing_algorithm_framework/infrastructure/models/position/__init__.py +2 -2
  169. investing_algorithm_framework/infrastructure/models/position/position.py +16 -11
  170. investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +23 -0
  171. investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
  172. investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
  173. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
  174. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
  175. investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
  176. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  177. investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
  178. investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
  179. investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
  180. investing_algorithm_framework/infrastructure/repositories/__init__.py +13 -5
  181. investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
  182. investing_algorithm_framework/infrastructure/repositories/order_repository.py +32 -19
  183. investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
  184. investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +56 -0
  185. investing_algorithm_framework/infrastructure/repositories/position_repository.py +47 -4
  186. investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +21 -0
  187. investing_algorithm_framework/infrastructure/repositories/repository.py +85 -31
  188. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
  189. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
  190. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
  191. investing_algorithm_framework/infrastructure/services/__init__.py +9 -2
  192. investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
  193. investing_algorithm_framework/infrastructure/services/aws/state_handler.py +193 -0
  194. investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
  195. investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
  196. investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +9 -0
  197. investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +2596 -0
  198. investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +285 -0
  199. investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +468 -0
  200. investing_algorithm_framework/services/__init__.py +127 -10
  201. investing_algorithm_framework/services/configuration_service.py +95 -0
  202. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  203. investing_algorithm_framework/services/data_providers/data_provider_service.py +1058 -0
  204. investing_algorithm_framework/services/market_credential_service.py +40 -0
  205. investing_algorithm_framework/services/metrics/__init__.py +119 -0
  206. investing_algorithm_framework/services/metrics/alpha.py +0 -0
  207. investing_algorithm_framework/services/metrics/beta.py +0 -0
  208. investing_algorithm_framework/services/metrics/cagr.py +60 -0
  209. investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
  210. investing_algorithm_framework/services/metrics/drawdown.py +218 -0
  211. investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
  212. investing_algorithm_framework/services/metrics/exposure.py +210 -0
  213. investing_algorithm_framework/services/metrics/generate.py +358 -0
  214. investing_algorithm_framework/services/metrics/mean_daily_return.py +84 -0
  215. investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
  216. investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
  217. investing_algorithm_framework/services/metrics/recovery.py +113 -0
  218. investing_algorithm_framework/services/metrics/returns.py +452 -0
  219. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  220. investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
  221. investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
  222. investing_algorithm_framework/services/metrics/standard_deviation.py +156 -0
  223. investing_algorithm_framework/services/metrics/trades.py +473 -0
  224. investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  225. investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  226. investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  227. investing_algorithm_framework/services/metrics/volatility.py +118 -0
  228. investing_algorithm_framework/services/metrics/win_rate.py +177 -0
  229. investing_algorithm_framework/services/order_service/__init__.py +9 -0
  230. investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
  231. investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
  232. investing_algorithm_framework/services/order_service/order_service.py +826 -0
  233. investing_algorithm_framework/services/portfolios/__init__.py +16 -0
  234. investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
  235. investing_algorithm_framework/services/{portfolio_configuration_service.py → portfolios/portfolio_configuration_service.py} +27 -12
  236. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
  237. investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
  238. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
  239. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
  240. investing_algorithm_framework/services/positions/__init__.py +7 -0
  241. investing_algorithm_framework/services/positions/position_service.py +210 -0
  242. investing_algorithm_framework/services/positions/position_snapshot_service.py +18 -0
  243. investing_algorithm_framework/services/repository_service.py +8 -2
  244. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  245. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +117 -0
  246. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  247. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  248. investing_algorithm_framework/services/trade_service/__init__.py +9 -0
  249. investing_algorithm_framework/services/trade_service/trade_service.py +1099 -0
  250. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  251. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  252. investing_algorithm_framework-7.25.6.dist-info/METADATA +535 -0
  253. investing_algorithm_framework-7.25.6.dist-info/RECORD +268 -0
  254. {investing_algorithm_framework-1.3.1.dist-info → investing_algorithm_framework-7.25.6.dist-info}/WHEEL +1 -2
  255. investing_algorithm_framework-7.25.6.dist-info/entry_points.txt +3 -0
  256. investing_algorithm_framework/app/algorithm.py +0 -410
  257. investing_algorithm_framework/domain/models/market_data/__init__.py +0 -11
  258. investing_algorithm_framework/domain/models/market_data/asset_price.py +0 -50
  259. investing_algorithm_framework/domain/models/market_data/ohlcv.py +0 -76
  260. investing_algorithm_framework/domain/models/market_data/order_book.py +0 -63
  261. investing_algorithm_framework/domain/models/market_data/ticker.py +0 -92
  262. investing_algorithm_framework/domain/models/order/order_fee.py +0 -45
  263. investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
  264. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -205
  265. investing_algorithm_framework/domain/singleton.py +0 -9
  266. investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
  267. investing_algorithm_framework/infrastructure/models/position/position_cost.py +0 -32
  268. investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
  269. investing_algorithm_framework/infrastructure/repositories/position_cost_repository.py +0 -16
  270. investing_algorithm_framework/infrastructure/services/market_service.py +0 -422
  271. investing_algorithm_framework/services/market_data_service.py +0 -75
  272. investing_algorithm_framework/services/order_service.py +0 -464
  273. investing_algorithm_framework/services/portfolio_service.py +0 -105
  274. investing_algorithm_framework/services/position_cost_service.py +0 -5
  275. investing_algorithm_framework/services/position_service.py +0 -50
  276. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -219
  277. investing_algorithm_framework/setup_logging.py +0 -40
  278. investing_algorithm_framework-1.3.1.dist-info/AUTHORS.md +0 -8
  279. investing_algorithm_framework-1.3.1.dist-info/METADATA +0 -172
  280. investing_algorithm_framework-1.3.1.dist-info/RECORD +0 -103
  281. investing_algorithm_framework-1.3.1.dist-info/top_level.txt +0 -1
  282. {investing_algorithm_framework-1.3.1.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
@@ -0,0 +1,40 @@
1
+ from typing import Union, List
2
+
3
+ from investing_algorithm_framework.domain import MarketCredential
4
+
5
+
6
+ class MarketCredentialService:
7
+ """
8
+ Service to manage market credentials.
9
+
10
+ This service is responsible for adding, retrieving, and
11
+ initializing market credentials.
12
+ """
13
+ def __init__(self):
14
+ self._market_credentials = {}
15
+
16
+ def add(self, market_data_credential: MarketCredential):
17
+ self._market_credentials[market_data_credential.market.upper()] \
18
+ = market_data_credential
19
+
20
+ def add_all(self, market_data_credentials: List[MarketCredential]):
21
+ for market_data_credential in market_data_credentials:
22
+ self.add(market_data_credential)
23
+
24
+ def get(self, market) -> Union[MarketCredential, None]:
25
+
26
+ if market.upper() not in self._market_credentials:
27
+ return None
28
+
29
+ return self._market_credentials[market.upper()]
30
+
31
+ def get_all(self) -> List[MarketCredential]:
32
+ return list(self._market_credentials.values())
33
+
34
+ def initialize(self):
35
+ """
36
+ Initialize all market credentials.
37
+ """
38
+
39
+ for market_credential in self.get_all():
40
+ market_credential.initialize()
@@ -0,0 +1,119 @@
1
+ from .volatility import get_annual_volatility
2
+ from .sortino_ratio import get_sortino_ratio
3
+ from .drawdown import get_drawdown_series, get_max_drawdown
4
+ from .equity_curve import get_equity_curve
5
+ from .price_efficiency import get_price_efficiency_ratio
6
+ from .profit_factor import get_profit_factor, \
7
+ get_cumulative_profit_factor_series, get_rolling_profit_factor_series
8
+ from .sharpe_ratio import get_sharpe_ratio, get_rolling_sharpe_ratio
9
+ from .price_efficiency import get_price_efficiency_ratio
10
+ from .equity_curve import get_equity_curve
11
+ from .drawdown import get_drawdown_series, get_max_drawdown, \
12
+ get_max_drawdown_absolute, get_max_drawdown_duration, \
13
+ get_max_daily_drawdown
14
+ from .cagr import get_cagr
15
+ from .standard_deviation import get_standard_deviation_downside_returns, \
16
+ get_standard_deviation_returns
17
+ from .returns import get_yearly_returns, get_monthly_returns, \
18
+ get_best_year, get_best_month, get_worst_month, get_total_return, \
19
+ get_average_yearly_return, get_average_monthly_return, \
20
+ get_percentage_winning_months, get_average_monthly_return_losing_months, \
21
+ get_average_monthly_return_winning_months, get_total_growth, \
22
+ get_percentage_winning_years, get_worst_year, get_cumulative_return, \
23
+ get_total_loss, get_cumulative_return_series
24
+ from .exposure import get_average_trade_duration, \
25
+ get_trade_frequency, get_trades_per_day, get_trades_per_year, \
26
+ get_cumulative_exposure, get_exposure_ratio
27
+ from .win_rate import get_win_rate, get_win_loss_ratio, get_current_win_rate, \
28
+ get_current_win_loss_ratio
29
+ from .calmar_ratio import get_calmar_ratio
30
+ from .generate import create_backtest_metrics, \
31
+ create_backtest_metrics_for_backtest
32
+ from .risk_free_rate import get_risk_free_rate_us
33
+ from .trades import get_negative_trades, get_positive_trades, \
34
+ get_number_of_trades, get_number_of_closed_trades, \
35
+ get_average_trade_size, get_average_trade_return, get_best_trade, \
36
+ get_worst_trade, get_average_trade_gain, get_median_trade_return, \
37
+ get_average_trade_loss, get_current_average_trade_loss, \
38
+ get_current_average_trade_duration, get_current_average_trade_gain, \
39
+ get_current_average_trade_return, get_number_of_open_trades, \
40
+ get_average_trade_duration
41
+ from .mean_daily_return import get_mean_daily_return, get_mean_yearly_return
42
+ from .standard_deviation import get_daily_returns_std
43
+
44
+ __all__ = [
45
+ "get_mean_daily_return",
46
+ "get_daily_returns_std",
47
+ "get_annual_volatility",
48
+ "get_sortino_ratio",
49
+ "get_drawdown_series",
50
+ "get_max_drawdown",
51
+ "get_equity_curve",
52
+ "get_price_efficiency_ratio",
53
+ "get_sharpe_ratio",
54
+ "get_profit_factor",
55
+ "get_cumulative_profit_factor_series",
56
+ "get_rolling_profit_factor_series",
57
+ "get_sharpe_ratio",
58
+ "get_cagr",
59
+ "get_standard_deviation_returns",
60
+ "get_standard_deviation_downside_returns",
61
+ "get_max_drawdown_absolute",
62
+ "get_total_return",
63
+ "get_total_loss",
64
+ "get_total_growth",
65
+ "get_cumulative_exposure",
66
+ "get_exposure_ratio",
67
+ "get_win_rate",
68
+ "get_win_loss_ratio",
69
+ "get_calmar_ratio",
70
+ "get_trade_frequency",
71
+ "get_yearly_returns",
72
+ "get_monthly_returns",
73
+ "get_best_year",
74
+ "get_best_month",
75
+ "get_worst_year",
76
+ "get_worst_month",
77
+ "get_best_trade",
78
+ "get_worst_trade",
79
+ "get_average_yearly_return",
80
+ "get_average_monthly_return",
81
+ "get_percentage_winning_months",
82
+ "get_average_trade_duration",
83
+ "get_trade_frequency",
84
+ "get_win_rate",
85
+ "get_win_loss_ratio",
86
+ "get_calmar_ratio",
87
+ "get_max_drawdown_absolute",
88
+ "get_max_drawdown_duration",
89
+ "get_max_daily_drawdown",
90
+ "get_trades_per_day",
91
+ "get_trades_per_year",
92
+ "get_average_monthly_return_losing_months",
93
+ "get_average_monthly_return_winning_months",
94
+ "get_percentage_winning_years",
95
+ "get_rolling_sharpe_ratio",
96
+ "create_backtest_metrics",
97
+ "get_risk_free_rate_us",
98
+ "get_median_trade_return",
99
+ "get_average_trade_gain",
100
+ "get_average_trade_loss",
101
+ "get_average_trade_size",
102
+ "get_average_trade_return",
103
+ "get_number_of_trades",
104
+ "get_number_of_closed_trades",
105
+ "get_negative_trades",
106
+ "get_positive_trades",
107
+ "get_cumulative_return",
108
+ "get_cumulative_return_series",
109
+ "get_current_win_rate",
110
+ "get_current_win_loss_ratio",
111
+ "get_current_average_trade_loss",
112
+ "get_current_average_trade_duration",
113
+ "get_current_average_trade_gain",
114
+ "get_current_average_trade_return",
115
+ "get_number_of_open_trades",
116
+ "get_average_trade_duration",
117
+ "create_backtest_metrics_for_backtest",
118
+ "get_mean_yearly_return"
119
+ ]
File without changes
@@ -0,0 +1,60 @@
1
+ """
2
+ The Compound Annual Growth Rate (CAGR) normalizes returns over a one-year
3
+ period, allowing you to compare performance across different timeframes.
4
+ It assumes the investment grows at a steady rate and compounds over time.
5
+
6
+ This formula is suitable whether your data spans:
7
+
8
+ * Less than a year (e.g. 30 days)
9
+ * Exactly a year (365 days)
10
+ * More than a year (e.g. 500 days)
11
+ """
12
+
13
+ import pandas as pd
14
+ from typing import List
15
+ from investing_algorithm_framework.domain import PortfolioSnapshot
16
+
17
+
18
+ def get_cagr(snapshots: List[PortfolioSnapshot]) -> float:
19
+ """
20
+ Calculate the Compound Annual Growth Rate (CAGR) of a backtest report.
21
+ CAGR is a useful metric to evaluate the performance of an investment
22
+ over a period of time, normalizing the return to a one-year basis.
23
+
24
+ The formula for CAGR is:
25
+ CAGR = (End Value / Start Value) ^ (1 / Number of Years) - 1
26
+
27
+ Where:
28
+ - End Value is the final value of the investment
29
+ - Start Value is the initial value of the investment
30
+ - Number of Years is the total time period in years
31
+ This function assumes that the snapshots in the report are ordered by
32
+ creation date and that the net size represents the value of the investment.
33
+
34
+ Args:
35
+ snapshots (list[Snapshot]): A list of snapshots
36
+
37
+ Returns:
38
+ Float: The CAGR as a decimal. Returns 0.0 if not enough
39
+ data is available.
40
+ """
41
+
42
+ if len(snapshots) < 2:
43
+ return 0.0 # Not enough data
44
+
45
+ # Convert snapshots to DataFrame
46
+ data = [(s.total_value, s.created_at) for s in snapshots]
47
+ df = pd.DataFrame(data, columns=["total_value", "created_at"])
48
+ df['created_at'] = pd.to_datetime(df['created_at'])
49
+ df = df.sort_values('created_at')
50
+ start_value = df.iloc[0]['total_value']
51
+ end_value = df.iloc[-1]['total_value']
52
+ start_date = df.iloc[0]['created_at']
53
+ end_date = df.iloc[-1]['created_at']
54
+ num_days = (end_date - start_date).days
55
+
56
+ if num_days == 0 or start_value == 0:
57
+ return 0.0
58
+
59
+ # Apply CAGR formula
60
+ return (end_value / start_value) ** (365 / num_days) - 1
@@ -0,0 +1,40 @@
1
+ """
2
+ | **Calmar Ratio** | **Interpretation** |
3
+ | ---------------- | ----------------------------------------------------------- |
4
+ | **> 3.0** | **Excellent** – strong return vs. drawdown |
5
+ | **2.0 – 3.0** | **Very Good** – solid risk-adjusted performance |
6
+ | **1.0 – 2.0** | **Acceptable** – decent, especially for volatile strategies |
7
+ | **< 1.0** | **Poor** – high drawdowns relative to return |
8
+ """
9
+
10
+ from typing import List
11
+ from investing_algorithm_framework.domain import PortfolioSnapshot
12
+ from .cagr import get_cagr
13
+ from .drawdown import get_max_drawdown
14
+
15
+
16
+ def get_calmar_ratio(snapshots: List[PortfolioSnapshot]):
17
+ """
18
+ Calculate the Calmar Ratio, which is the ratio of the annualized
19
+ return to the maximum drawdown.
20
+
21
+ Formula:
22
+ Calmar Ratio = CAGR / |Maximum Drawdown|
23
+
24
+ The Calmar Ratio is a measure of risk-adjusted return,
25
+ where a higher ratio indicates a more favorable risk-return profile.
26
+
27
+ Args:
28
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots
29
+ from the backtest report.
30
+
31
+ Returns:
32
+ float: The Calmar Ratio.
33
+ """
34
+ cagr = get_cagr(snapshots)
35
+ max_drawdown = get_max_drawdown(snapshots)
36
+
37
+ if max_drawdown == 0 or max_drawdown is None:
38
+ return 0.0
39
+
40
+ return cagr / max_drawdown
@@ -0,0 +1,218 @@
1
+ """"
2
+ Max Drawdown (MDD) — a key risk metric that shows the worst
3
+ peak-to-trough decline of a portfolio:
4
+
5
+ | **Max Drawdown (%)** | **Interpretation** |
6
+ |-----------------------|----------------------------------------------------------------------|
7
+ | **0% to -5%** | 🟢 Excellent — Very low risk, typical for conservative strategies |
8
+ | **-5% to -10%** | ✅ Good — Moderate volatility, acceptable for balanced portfolios |
9
+ | **-10% to -20%** | ⚠️ Elevated Risk — Common in growth or actively managed strategies |
10
+ | **-20% to -40%** | 🔻 High Risk — Significant drawdown, typical of aggressive strategies |
11
+ | **> -40%** | 🚨 Very High Risk — Risk of capital loss or strategy failure |
12
+ """
13
+ from typing import List, Tuple
14
+ import pandas as pd
15
+ from datetime import datetime
16
+ from investing_algorithm_framework.domain import PortfolioSnapshot, Trade
17
+ from .equity_curve import get_equity_curve
18
+
19
+
20
+ def get_drawdown_series(snapshots: List[PortfolioSnapshot]) -> List[Tuple[float, datetime]]:
21
+ """
22
+ Calculate the drawdown series of a backtest report.
23
+
24
+ The drawdown is calculated as the percentage difference
25
+ between the current equity value and the maximum equity value
26
+ observed up to that point in time.
27
+
28
+ Args:
29
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots
30
+
31
+ Returns:
32
+ List[Tuple[datetime, float]]: A list of tuples with datetime
33
+ and drawdown percentage. The drawdown is expressed as a
34
+ negative percentage, where 0% means no drawdown and -100%
35
+ means the portfolio has lost all its value.
36
+ """
37
+ equity_curve = get_equity_curve(snapshots)
38
+
39
+ drawdown_series = []
40
+ max_value = None
41
+
42
+ for value, timestamp in equity_curve:
43
+ # Skip zero or negative values to avoid division by zero
44
+ if value <= 0:
45
+ drawdown_series.append((0.0, timestamp))
46
+ continue
47
+
48
+ if max_value is None or max_value <= 0:
49
+ max_value = value
50
+ max_value = max(max_value, value)
51
+ drawdown = (value - max_value) / max_value # This will be <= 0
52
+ drawdown_series.append((drawdown, timestamp))
53
+
54
+ return drawdown_series
55
+
56
+
57
+ def get_max_drawdown(snapshots: List[PortfolioSnapshot]) -> float:
58
+ """
59
+ Calculate the maximum drawdown of the portfolio as a percentage from the peak.
60
+
61
+ Max Drawdown is the maximum observed loss from a peak to a
62
+ trough before a new peak is achieved.
63
+
64
+ It is expressed here as a negative percentage.
65
+
66
+ Args:
67
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots
68
+
69
+ Returns:
70
+ float: The maximum drawdown as a negative percentage (e.g., -12.5 for a 12.5% drawdown).
71
+ """
72
+ equity_curve = get_equity_curve(snapshots)
73
+
74
+ if not equity_curve:
75
+ return 0.0
76
+
77
+ peak = equity_curve[0][0]
78
+
79
+ # Handle zero or negative starting value
80
+ if peak <= 0:
81
+ # Find first positive value as the peak
82
+ for equity, _ in equity_curve:
83
+ if equity > 0:
84
+ peak = equity
85
+ break
86
+ else:
87
+ # No positive values found
88
+ return 0.0
89
+
90
+ max_drawdown_pct = 0.0
91
+
92
+ for equity, _ in equity_curve:
93
+ # Skip non-positive values
94
+ if equity <= 0:
95
+ continue
96
+
97
+ if equity > peak:
98
+ peak = equity
99
+
100
+ # Avoid division by zero (shouldn't happen now but extra safety)
101
+ if peak <= 0:
102
+ continue
103
+
104
+ drawdown_pct = (equity - peak) / peak # Will be 0 or negative
105
+ max_drawdown_pct = min(max_drawdown_pct, drawdown_pct)
106
+
107
+ return abs(max_drawdown_pct)
108
+
109
+
110
+ def get_max_daily_drawdown(snapshots: List[PortfolioSnapshot]) -> float:
111
+ """
112
+ Calculate the maximum daily drawdown of the portfolio as a percentage from the peak.
113
+
114
+ This is the largest drop in equity (in percentage) from a peak to a trough
115
+ during the backtest period, calculated on a daily basis.
116
+
117
+ Args:
118
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots
119
+
120
+ Returns:
121
+ float: The maximum daily drawdown as a negative percentage (e.g., -5.0 for a 5% drawdown).
122
+ """
123
+ # Create DataFrame from snapshots
124
+ data = [(s.created_at, s.total_value) for s in snapshots]
125
+ df = pd.DataFrame(data, columns=["created_at", "total_value"])
126
+ df['created_at'] = pd.to_datetime(df['created_at'])
127
+ df = df.sort_values('created_at').drop_duplicates('created_at')\
128
+ .set_index('created_at')
129
+
130
+ # Resample to daily frequency using last value of the day
131
+ daily_df = df.resample('1D').last().dropna()
132
+
133
+ if daily_df.empty:
134
+ return 0.0
135
+
136
+ # Filter out non-positive values
137
+ positive_values = daily_df[daily_df['total_value'] > 0]['total_value']
138
+
139
+ if positive_values.empty:
140
+ return 0.0
141
+
142
+ peak = positive_values.iloc[0]
143
+ max_daily_drawdown_pct = 0.0
144
+
145
+ for equity in positive_values:
146
+ if equity > peak:
147
+ peak = equity
148
+
149
+ # Avoid division by zero (shouldn't happen but extra safety)
150
+ if peak <= 0:
151
+ continue
152
+
153
+ drawdown_pct = (equity - peak) / peak
154
+ max_daily_drawdown_pct = min(max_daily_drawdown_pct, drawdown_pct)
155
+
156
+ return abs(max_daily_drawdown_pct) # Return as positive percentage
157
+
158
+ def get_max_drawdown_duration(snapshots: List[PortfolioSnapshot]) -> int:
159
+ """
160
+ Calculate the maximum duration of drawdown in days.
161
+
162
+ This is the longest period where the portfolio equity was below its peak.
163
+
164
+ Args:
165
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots
166
+
167
+ Returns:
168
+ int: The maximum drawdown duration in days.
169
+ """
170
+ equity_curve = get_equity_curve(snapshots)
171
+ if not equity_curve:
172
+ return 0
173
+
174
+ peak = equity_curve[0][0]
175
+ max_duration = 0
176
+ current_duration = 0
177
+
178
+ for equity, _ in equity_curve:
179
+ if equity < peak:
180
+ current_duration += 1
181
+ else:
182
+ max_duration = max(max_duration, current_duration)
183
+ current_duration = 0
184
+ peak = equity # Reset peak to current equity
185
+
186
+ max_duration = max(max_duration, current_duration) # Final check
187
+
188
+ return max_duration
189
+
190
+
191
+ def get_max_drawdown_absolute(snapshots: List[PortfolioSnapshot]) -> float:
192
+ """
193
+ Calculate the maximum absolute drawdown of the portfolio.
194
+
195
+ This is the largest drop in equity (in currency units) from a peak to a trough
196
+ during the backtest period.
197
+
198
+ Args:
199
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots
200
+
201
+ Returns:
202
+ float: The maximum absolute drawdown as a positive number (e.g., €10,000).
203
+ """
204
+ equity_curve = get_equity_curve(snapshots)
205
+ if not equity_curve:
206
+ return 0.0
207
+
208
+ peak = equity_curve[0][0]
209
+ max_drawdown = 0.0
210
+
211
+ for equity, _ in equity_curve:
212
+ if equity > peak:
213
+ peak = equity
214
+
215
+ drawdown = peak - equity # Drop from peak
216
+ max_drawdown = max(max_drawdown, drawdown)
217
+
218
+ return abs(max_drawdown) # Return as positive number (e.g., €10,000)
@@ -0,0 +1,24 @@
1
+ from datetime import datetime
2
+ from typing import List
3
+ from investing_algorithm_framework.domain import PortfolioSnapshot
4
+
5
+
6
+ def get_equity_curve(
7
+ snapshots: List[PortfolioSnapshot]
8
+ ) -> list[tuple[float, datetime]]:
9
+ """
10
+ Calculate the total size of the portfolio at each snapshot timestamp.
11
+
12
+ Args:
13
+ snapshots (List[PortfolioSnapshot]): List of portfolio snapshots.
14
+ Returns:
15
+ list[tuple[datetime, float]]: A list of tuples with
16
+ timestamps and total sizes.
17
+ """
18
+ series = []
19
+ for snapshot in snapshots:
20
+ timestamp = snapshot.created_at
21
+ total_size = snapshot.total_value
22
+ series.append((total_size, timestamp))
23
+
24
+ return series