investing-algorithm-framework 3.7.0__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 (256) hide show
  1. investing_algorithm_framework/__init__.py +168 -45
  2. investing_algorithm_framework/app/__init__.py +32 -1
  3. investing_algorithm_framework/app/algorithm/__init__.py +7 -0
  4. investing_algorithm_framework/app/algorithm/algorithm.py +239 -0
  5. investing_algorithm_framework/app/algorithm/algorithm_factory.py +114 -0
  6. investing_algorithm_framework/app/analysis/__init__.py +15 -0
  7. investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
  8. investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
  9. investing_algorithm_framework/app/analysis/permutation.py +116 -0
  10. investing_algorithm_framework/app/analysis/ranking.py +297 -0
  11. investing_algorithm_framework/app/app.py +1933 -589
  12. investing_algorithm_framework/app/app_hook.py +28 -0
  13. investing_algorithm_framework/app/context.py +1725 -0
  14. investing_algorithm_framework/app/eventloop.py +590 -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 +4 -2
  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 +1 -1
  39. investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
  40. investing_algorithm_framework/app/strategy.py +664 -84
  41. investing_algorithm_framework/app/task.py +5 -3
  42. investing_algorithm_framework/app/web/__init__.py +2 -1
  43. investing_algorithm_framework/app/web/create_app.py +4 -2
  44. investing_algorithm_framework/cli/__init__.py +0 -0
  45. investing_algorithm_framework/cli/cli.py +226 -0
  46. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
  47. investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
  48. investing_algorithm_framework/cli/initialize_app.py +603 -0
  49. investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
  50. investing_algorithm_framework/cli/templates/app.py.template +18 -0
  51. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
  52. investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
  53. investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
  54. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  55. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  56. investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
  57. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
  58. investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
  59. investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
  60. investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
  61. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
  62. investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
  63. investing_algorithm_framework/cli/templates/env.example.template +2 -0
  64. investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
  65. investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
  66. investing_algorithm_framework/cli/templates/readme.md.template +135 -0
  67. investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
  68. investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
  69. investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
  70. investing_algorithm_framework/create_app.py +40 -6
  71. investing_algorithm_framework/dependency_container.py +72 -56
  72. investing_algorithm_framework/domain/__init__.py +71 -47
  73. investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
  74. investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
  75. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
  76. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
  77. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
  78. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  79. investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
  80. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  81. investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
  82. investing_algorithm_framework/domain/config.py +59 -91
  83. investing_algorithm_framework/domain/constants.py +13 -38
  84. investing_algorithm_framework/domain/data_provider.py +334 -0
  85. investing_algorithm_framework/domain/data_structures.py +3 -2
  86. investing_algorithm_framework/domain/exceptions.py +51 -1
  87. investing_algorithm_framework/domain/models/__init__.py +17 -12
  88. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  89. investing_algorithm_framework/domain/models/data/data_source.py +214 -0
  90. investing_algorithm_framework/domain/models/data/data_type.py +46 -0
  91. investing_algorithm_framework/domain/models/event.py +35 -0
  92. investing_algorithm_framework/domain/models/market/market_credential.py +55 -1
  93. investing_algorithm_framework/domain/models/order/order.py +77 -83
  94. investing_algorithm_framework/domain/models/order/order_status.py +2 -2
  95. investing_algorithm_framework/domain/models/order/order_type.py +1 -3
  96. investing_algorithm_framework/domain/models/portfolio/portfolio.py +81 -3
  97. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +26 -3
  98. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
  99. investing_algorithm_framework/domain/models/position/__init__.py +2 -1
  100. investing_algorithm_framework/domain/models/position/position.py +12 -0
  101. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  102. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  103. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  104. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  105. investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
  106. investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
  107. investing_algorithm_framework/domain/models/time_frame.py +37 -0
  108. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  109. investing_algorithm_framework/domain/models/time_unit.py +66 -2
  110. investing_algorithm_framework/domain/models/trade/__init__.py +8 -1
  111. investing_algorithm_framework/domain/models/trade/trade.py +295 -171
  112. investing_algorithm_framework/domain/models/trade/trade_status.py +9 -2
  113. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
  114. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
  115. investing_algorithm_framework/domain/order_executor.py +112 -0
  116. investing_algorithm_framework/domain/portfolio_provider.py +118 -0
  117. investing_algorithm_framework/domain/services/__init__.py +2 -9
  118. investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -6
  119. investing_algorithm_framework/domain/services/state_handler.py +38 -0
  120. investing_algorithm_framework/domain/strategy.py +1 -29
  121. investing_algorithm_framework/domain/utils/__init__.py +12 -7
  122. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  123. investing_algorithm_framework/domain/utils/dates.py +57 -0
  124. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  125. investing_algorithm_framework/domain/utils/polars.py +53 -0
  126. investing_algorithm_framework/domain/utils/random.py +29 -0
  127. investing_algorithm_framework/download_data.py +108 -0
  128. investing_algorithm_framework/infrastructure/__init__.py +31 -18
  129. investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
  130. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1143 -0
  131. investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
  132. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  133. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  134. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
  135. investing_algorithm_framework/infrastructure/models/__init__.py +6 -11
  136. investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -1
  137. investing_algorithm_framework/infrastructure/models/order/order.py +35 -49
  138. investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
  139. investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
  140. investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
  141. investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -0
  142. investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -5
  143. investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
  144. investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
  145. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
  146. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
  147. investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
  148. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  149. investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
  150. investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
  151. investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
  152. investing_algorithm_framework/infrastructure/repositories/__init__.py +8 -0
  153. investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
  154. investing_algorithm_framework/infrastructure/repositories/order_repository.py +5 -0
  155. investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +1 -1
  156. investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
  157. investing_algorithm_framework/infrastructure/repositories/repository.py +81 -27
  158. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
  159. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
  160. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
  161. investing_algorithm_framework/infrastructure/services/__init__.py +4 -4
  162. investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
  163. investing_algorithm_framework/infrastructure/services/aws/state_handler.py +113 -0
  164. investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
  165. investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
  166. investing_algorithm_framework/services/__init__.py +113 -16
  167. investing_algorithm_framework/services/backtesting/__init__.py +0 -7
  168. investing_algorithm_framework/services/backtesting/backtest_service.py +566 -359
  169. investing_algorithm_framework/services/configuration_service.py +77 -11
  170. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  171. investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
  172. investing_algorithm_framework/services/market_credential_service.py +16 -1
  173. investing_algorithm_framework/services/metrics/__init__.py +114 -0
  174. investing_algorithm_framework/services/metrics/alpha.py +0 -0
  175. investing_algorithm_framework/services/metrics/beta.py +0 -0
  176. investing_algorithm_framework/services/metrics/cagr.py +60 -0
  177. investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
  178. investing_algorithm_framework/services/metrics/drawdown.py +181 -0
  179. investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
  180. investing_algorithm_framework/services/metrics/exposure.py +210 -0
  181. investing_algorithm_framework/services/metrics/generate.py +358 -0
  182. investing_algorithm_framework/services/metrics/mean_daily_return.py +83 -0
  183. investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
  184. investing_algorithm_framework/services/metrics/recovery.py +113 -0
  185. investing_algorithm_framework/services/metrics/returns.py +452 -0
  186. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  187. investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
  188. investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
  189. investing_algorithm_framework/services/metrics/standard_deviation.py +157 -0
  190. investing_algorithm_framework/services/metrics/trades.py +500 -0
  191. investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  192. investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  193. investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  194. investing_algorithm_framework/services/metrics/volatility.py +97 -0
  195. investing_algorithm_framework/services/metrics/win_rate.py +177 -0
  196. investing_algorithm_framework/services/order_service/__init__.py +3 -1
  197. investing_algorithm_framework/services/order_service/order_backtest_service.py +76 -89
  198. investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
  199. investing_algorithm_framework/services/order_service/order_service.py +407 -326
  200. investing_algorithm_framework/services/portfolios/__init__.py +3 -1
  201. investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +37 -3
  202. investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +22 -8
  203. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
  204. investing_algorithm_framework/services/portfolios/portfolio_service.py +96 -28
  205. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +97 -28
  206. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +116 -313
  207. investing_algorithm_framework/services/positions/__init__.py +7 -0
  208. investing_algorithm_framework/services/positions/position_service.py +210 -0
  209. investing_algorithm_framework/services/repository_service.py +8 -2
  210. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  211. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
  212. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  213. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  214. investing_algorithm_framework/services/trade_service/__init__.py +7 -1
  215. investing_algorithm_framework/services/trade_service/trade_service.py +1013 -315
  216. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  217. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  218. investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
  219. investing_algorithm_framework-7.19.15.dist-info/RECORD +263 -0
  220. investing_algorithm_framework-7.19.15.dist-info/entry_points.txt +3 -0
  221. investing_algorithm_framework/app/algorithm.py +0 -1105
  222. investing_algorithm_framework/domain/graphs.py +0 -382
  223. investing_algorithm_framework/domain/metrics/__init__.py +0 -6
  224. investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -11
  225. investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -43
  226. investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
  227. investing_algorithm_framework/domain/models/backtesting/backtest_report.py +0 -580
  228. investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -243
  229. investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
  230. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
  231. investing_algorithm_framework/domain/services/market_data_sources.py +0 -344
  232. investing_algorithm_framework/domain/services/market_service.py +0 -153
  233. investing_algorithm_framework/domain/singleton.py +0 -9
  234. investing_algorithm_framework/domain/utils/backtesting.py +0 -472
  235. investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -12
  236. investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -559
  237. investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -254
  238. investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py +0 -47
  239. investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
  240. investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -455
  241. investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
  242. investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
  243. investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -350
  244. investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +0 -53
  245. investing_algorithm_framework/services/backtesting/graphs.py +0 -61
  246. investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -8
  247. investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -150
  248. investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -189
  249. investing_algorithm_framework/services/position_service.py +0 -31
  250. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -264
  251. investing_algorithm_framework-3.7.0.dist-info/METADATA +0 -339
  252. investing_algorithm_framework-3.7.0.dist-info/RECORD +0 -147
  253. /investing_algorithm_framework/{domain → services}/metrics/price_efficiency.py +0 -0
  254. /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
  255. {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
  256. {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
@@ -0,0 +1,147 @@
1
+ import pandas as pd
2
+
3
+ from investing_algorithm_framework.domain import DEFAULT_DATETIME_FORMAT
4
+ from .utils import safe_format, safe_format_date, safe_format_percentage
5
+
6
+
7
+ def highlight_win_rate(row):
8
+ """
9
+ | **Winning Percentage** | **Interpretation** |
10
+ |-------------------------|----------------------------------------------------------------------|
11
+ | **< 40%** | 🟥 Poor — Strategy may not be viable |
12
+ | **40% to 50%** | 🟧 Weak — Needs improvement, often breakeven or slightly negative |
13
+ | **50% to 60%** | 🟨 Average — Acceptable for many strategies, especially with high PF |
14
+ | **60% to 70%** | 🟩 Good — Solid performance, often with good risk/reward |
15
+ | **> 70%** | 🟩 Excellent — High win rate, typically indicates a strong edge |
16
+ """
17
+ metric = row['Metric']
18
+ try:
19
+ value = float(row['Value'].strip('%'))
20
+ except Exception:
21
+ value = None
22
+ styles = pd.Series('', index=row.index)
23
+ if metric == 'Win Rate' and value is not None:
24
+ if value < 40:
25
+ styles['Value'] = 'color: #B22222; font-weight: bold;' # red
26
+ elif 40 <= value < 50:
27
+ styles['Value'] = 'color: #FFA500; font-weight: bold;' # orange
28
+ elif 50 <= value < 60:
29
+ styles['Value'] = 'color: #FFD700; font-weight: bold;' # gold
30
+ elif 60 <= value < 70:
31
+ styles['Value'] = 'color: #32CD32; font-weight: bold;' # lime green
32
+ elif value >= 70:
33
+ styles['Value'] = 'color: #228B22; font-weight: bold;' # dark green
34
+ return styles
35
+
36
+
37
+ def highlight_win_loss_ratio(row):
38
+ """
39
+ | **Win/Loss Ratio** | **Interpretation** |
40
+ |---------------------|----------------------------------------------------------------------|
41
+ | **< 0.5** | 🟥 Poor — Strategy may not be viable |
42
+ | **0.5 to 1.0** | 🟧 Weak — Needs improvement, often breakeven or slightly negative |
43
+ | **1.0 to 1.5** | 🟨 Average — Acceptable for many strategies, especially with high PF |
44
+ | **1.5 to 2.0** | 🟩 Good — Solid performance, often with good risk/reward |
45
+ | **> 2.0** | 🟩 Excellent — High win/loss ratio, typically indicates a strong edge |
46
+ """
47
+ metric = row['Metric']
48
+ try:
49
+ value = float(row['Value'])
50
+ except Exception:
51
+ value = None
52
+ styles = pd.Series('', index=row.index)
53
+ if metric == 'Win/Loss Ratio' and value is not None:
54
+ if value < 0.5:
55
+ styles['Value'] = 'color: #B22222; font-weight: bold;' # red
56
+ elif 0.5 <= value < 1.0:
57
+ styles['Value'] = 'color: #FFA500; font-weight: bold;' # orange
58
+ elif 1.0 <= value < 1.5:
59
+ styles['Value'] = 'color: #FFD700; font-weight: bold;' # gold
60
+ elif 1.5 <= value < 2.0:
61
+ styles['Value'] = 'color: #32CD32; font-weight: bold;' # lime green
62
+ elif value >= 2.0:
63
+ styles['Value'] = 'color: #228B22; font-weight: bold;' # dark green
64
+ return styles
65
+
66
+
67
+ def create_html_trade_metrics_table(results, report):
68
+ copy_results = results.to_dict().copy()
69
+ string_format = "{:.2f}"
70
+ copy_results['Trades per Year'] = safe_format(copy_results['trades_per_year'], string_format)
71
+ copy_results['Trades per Day'] = safe_format(copy_results['trade_per_day'], string_format)
72
+ copy_results['Exposure Ratio'] = safe_format(copy_results['exposure_ratio'],string_format)
73
+ copy_results["Cumulative Exposure"] = safe_format(copy_results['cumulative_exposure'],string_format)
74
+ best_trade = copy_results['best_trade']
75
+
76
+ if best_trade is None:
77
+ copy_results["Best Trade"] = "N/A"
78
+ copy_results['Best Trade Date'] = "N/A"
79
+ else:
80
+ copy_results['Best Trade'] = f"{best_trade['net_gain']:.2f} {report.trading_symbol}"
81
+ copy_results['Best Trade Date'] = safe_format_date(best_trade["opened_at"], format_str=DEFAULT_DATETIME_FORMAT)
82
+ worst_trade = copy_results['worst_trade']
83
+
84
+ if worst_trade is None:
85
+ copy_results["Worst Trade"] = "N/A"
86
+ copy_results['Worst Trade Date'] = "N/A"
87
+ else:
88
+ copy_results['Worst Trade'] = f"{worst_trade['net_gain']:.2f} {report.trading_symbol}"
89
+ copy_results['Worst Trade Date'] = safe_format_date(worst_trade['opened_at'], format_str=DEFAULT_DATETIME_FORMAT)
90
+
91
+ copy_results['Trades Average Gain'] = f"{safe_format(copy_results['average_trade_gain'], string_format)} {report.trading_symbol} {copy_results['trades_average_gain_percentage']:.2f}%"
92
+ copy_results['Trades Average Loss'] = f"{safe_format(copy_results['average_trade_loss'], string_format)} {report.trading_symbol} {copy_results['trades_average_loss_percentage']:.2f}%"
93
+ copy_results['Average Trade Duration'] = f"{copy_results['average_trade_duration']:.2f} hours"
94
+ copy_results['Number of Trades'] = f"{copy_results['number_of_trades']}"
95
+ copy_results['Win Rate'] = f"{copy_results['win_rate']:.2f}%"
96
+ copy_results['Win/Loss Ratio'] = f"{copy_results['win_loss_ratio']:.2f}"
97
+
98
+ stats = {
99
+ "Metric": [
100
+ "Trades per Year",
101
+ "Trade per Day",
102
+ "Exposure Ratio",
103
+ "Cumulative Exposure",
104
+ "Trades Average Gain",
105
+ "Trades Average Loss",
106
+ "Best Trade",
107
+ "Best Trade Date",
108
+ "Worst Trade",
109
+ "Worst Trade Date",
110
+ "Average Trade Duration",
111
+ "Number of Trades",
112
+ "Win Rate",
113
+ "Win/Loss Ratio"
114
+ ],
115
+ "Value": [
116
+ copy_results['Trades per Year'],
117
+ copy_results['Trades per Day'],
118
+ copy_results['Exposure Ratio'],
119
+ copy_results['Cumulative Exposure'],
120
+ copy_results['Trades Average Gain'],
121
+ copy_results['Trades Average Loss'],
122
+ copy_results['Best Trade'],
123
+ copy_results['Best Trade Date'],
124
+ copy_results['Worst Trade'],
125
+ copy_results['Worst Trade Date'],
126
+ copy_results['Average Trade Duration'],
127
+ copy_results['Number of Trades'],
128
+ copy_results['Win Rate'],
129
+ copy_results['Win/Loss Ratio']
130
+ ]
131
+ }
132
+
133
+ df_stats = pd.DataFrame(stats)
134
+
135
+ table_html = (
136
+ df_stats.style
137
+ .apply(highlight_win_rate, axis=1)
138
+ .apply(highlight_win_loss_ratio, axis=1)
139
+ .set_table_styles([
140
+ {'selector': 'th', 'props': [('background-color', '#f2f2f2'), ('font-weight', 'bold')]},
141
+ {'selector': 'td', 'props': [('font-size', '14px')]},
142
+ {'selector': 'tr:nth-child(even)', 'props': [('background-color', '#fafafa')]}
143
+ ])
144
+ .hide(axis='index')
145
+ .to_html()
146
+ )
147
+ return table_html
@@ -0,0 +1,75 @@
1
+ import pandas as pd
2
+
3
+
4
+ def highlight_net_gain(row):
5
+ """
6
+ Apply conditional formatting to the 'Net Gain' column based on numeric value.
7
+ """
8
+ try:
9
+ # Extract numeric value before the first space (assumes format like "123.45 USDT (10.23%)")
10
+ value_str = row['Net Gain'].split()[2]
11
+ value_str = value_str.split('(')[1]
12
+ value_str = value_str.replace(')', '').strip()
13
+ if '%' in value_str:
14
+ value_str = value_str.replace('%', '')
15
+ value = float(value_str)
16
+
17
+ except Exception:
18
+ value = None
19
+
20
+ styles = pd.Series('', index=row.index)
21
+
22
+ if value is not None:
23
+ if value < -5:
24
+ styles['Net Gain'] = 'color: #B22222; font-weight: bold;' # red
25
+ elif -5 <= value < -2:
26
+ styles['Net Gain'] = 'color: #FFA500; font-weight: bold;' # orange
27
+ elif -2 <= value < 0:
28
+ styles['Net Gain'] = 'color: #FFD700; font-weight: bold;' # gold
29
+ elif 0 <= value < 5:
30
+ styles['Net Gain'] = 'color: #32CD32; font-weight: bold;' # lime green
31
+ elif value >= 5:
32
+ styles['Net Gain'] = 'color: #228B22; font-weight: bold;' # dark green
33
+
34
+ return styles
35
+
36
+ def get_exit(trade):
37
+ """
38
+ Returns the exit price of a trade if it is closed, otherwise returns "open".
39
+ This is used to display the exit price in the trades table.
40
+
41
+ A trade can have multiple exits and close prices.
42
+ """
43
+
44
+ if trade.closed_at:
45
+ return f"{trade.closed_at.strftime('%Y-%m-%d %H:%M:%S')}"
46
+ else:
47
+ return "open"
48
+
49
+
50
+ def create_html_trades_table(report):
51
+ trades = report.get_trades()
52
+
53
+ # Create a DataFrame from the trades, with the attributes id, net_gain, net_gain_percentage, entry_time, exit_time, duration, and symbol
54
+ selection = {
55
+ 'Trade': [f"{trade.id} {trade.target_symbol}/{trade.trading_symbol}" for trade in trades],
56
+ 'Net Gain': [f"{trade.change:.2f} {report.trading_symbol} ({trade.percentage_change:.2f}%)" for trade in trades],
57
+ 'Entry (Price, Date)': [f"{trade.open_price} {trade.opened_at.strftime('%Y-%m-%d %H:%M:%S')}" for trade in trades],
58
+ 'Exit (Price, Date)': [get_exit(trade) for trade in trades],
59
+ 'Duration': [f"{trade.duration:.2f} hours" for trade in trades],
60
+ }
61
+ trades_df = pd.DataFrame(selection)
62
+
63
+ table_html = (
64
+ trades_df.style
65
+ .apply(highlight_net_gain, axis=1)
66
+ # .apply(highlight_win_loss_ratio, axis=1)
67
+ .set_table_styles([
68
+ {'selector': 'th', 'props': [('background-color', '#f2f2f2'), ('font-weight', 'bold')]},
69
+ {'selector': 'td', 'props': [('font-size', '14px')]},
70
+ {'selector': 'tr:nth-child(even)', 'props': [('background-color', '#fafafa')]}
71
+ ])
72
+ .hide(axis='index')
73
+ .to_html(classes='display', index=False, table_id='tradesTable')
74
+ )
75
+ return table_html
@@ -0,0 +1,29 @@
1
+ import pandas as pd
2
+
3
+
4
+ def safe_format(value, format_str, default_value='N/A'):
5
+ if value is None:
6
+ return default_value
7
+
8
+ if isinstance(value, (int, float)):
9
+ return format_str.format(value)
10
+ return value
11
+
12
+
13
+ def safe_format_percentage(value, format_str, default_value='N/A'):
14
+ if value is None:
15
+ return default_value
16
+
17
+ if isinstance(value, (int, float)):
18
+ return format_str.format(value * 100)
19
+
20
+ return value
21
+
22
+
23
+ def safe_format_date(value, format_str, default_value='N/A'):
24
+ if value is None:
25
+ return default_value
26
+
27
+ if isinstance(value, pd.Timestamp):
28
+ return value.strftime(format_str)
29
+ return value
@@ -0,0 +1,154 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Aluminium Smelting Strategy Report</title>
5
+ <style>
6
+ body {{ '{' }}
7
+ font-family: Arial, sans-serif;
8
+ margin: 40px;
9
+ {{ '}' }}
10
+ h1 {{ '{' }}
11
+ color: #333;
12
+ text-align: center;
13
+ {{ '}' }}
14
+ .tab {{ '{' }}
15
+ overflow: hidden;
16
+ border-bottom: 1px solid #ccc;
17
+ margin-bottom: 20px;
18
+ {{ '}' }}
19
+ .tab button {{ '{' }}
20
+ background-color: #f1f1f1;
21
+ float: left;
22
+ border: none;
23
+ outline: none;
24
+ cursor: pointer;
25
+ padding: 10px 20px;
26
+ transition: 0.3s;
27
+ font-size: 17px;
28
+ {{ '}' }}
29
+ .tab button:hover {{ '{' }}
30
+ background-color: #ddd;
31
+ {{ '}' }}
32
+ .tab button.active {{ '{' }}
33
+ background-color: #ccc;
34
+ {{ '}' }}
35
+ .tabcontent {{ '{' }}
36
+ display: none;
37
+ {{ '}' }}
38
+ .tabcontent.active {{ '{' }}
39
+ display: block;
40
+ {{ '}' }}
41
+ .stats-table, .metrics-table {{ '{' }}
42
+ border-collapse: collapse;
43
+ width: 50%;
44
+ margin-top: 20px;
45
+ {{ '}' }}
46
+ .stats-table th, .stats-table td {{ '{' }}
47
+ border: 1px solid #ddd;
48
+ padding: 8px;
49
+ text-align: left;
50
+ {{ '}' }}
51
+ .stats-table th {{ '{' }}
52
+ background-color: #f2f2f2;
53
+ {{ '}' }}
54
+ .grid-container {{ '{' }}
55
+ display: flex;
56
+ gap: 10px;
57
+ align-items: flex-start;
58
+ margin-top: 20px;
59
+ {{ '}' }}
60
+ .heatmap-cell {{ '{' }}
61
+ padding: 5px;
62
+ width: 60%;
63
+ {{ '}' }}
64
+ .yearly-returns-cell {{ '{' }}
65
+ padding: 5px;
66
+ width: 30%;
67
+ {{ '}' }}
68
+ .metrics-table {{ '{' }}
69
+ padding: 5px;
70
+ {{ '}' }}
71
+ </style>
72
+ <script>
73
+ function openTab(evt, tabName) {{ '{' }}
74
+ var i, tabcontent, tablinks;
75
+ tabcontent = document.getElementsByClassName("tabcontent");
76
+ for (i = 0; i < tabcontent.length; i++) {{ '{' }}
77
+ tabcontent[i].classList.remove("active");
78
+ {{ '}' }}
79
+ tablinks = document.getElementsByClassName("tablink");
80
+ for (i = 0; i < tablinks.length; i++) {{ '{' }}
81
+ tablinks[i].classList.remove("active");
82
+ {{ '}' }}
83
+ document.getElementById(tabName).classList.add("active");
84
+ evt.currentTarget.classList.add("active");
85
+ {{ '}' }}
86
+ </script>
87
+
88
+ <!-- DataTables CSS -->
89
+ <link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css">
90
+ <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css"/>
91
+ <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
92
+ <script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
93
+ </head>
94
+ <body>
95
+ <h1>Backtest report: {{ report.name }}</h1>
96
+
97
+ <div class="tab">
98
+ <button class="tablink active" onclick="openTab(event, 'Overview')">Overview</button>
99
+ <button class="tablink" onclick="openTab(event, 'Trades')">Trades</button>
100
+ <button class="tablink" onclick="openTab(event, 'Positions and orders')">Positions and Orders</button>
101
+ <button class="tablink" onclick="openTab(event, 'DataAnalysis')">Data Analysis</button>
102
+
103
+ </div>
104
+
105
+ <div id="Overview" class="tabcontent active">
106
+ <div>
107
+ {{ equity_with_drawdown_plot_html | safe }}
108
+ </div>
109
+ <div>
110
+ {{ rolling_sharpe_ratio_plot_html | safe }}
111
+ </div>
112
+ <div class="grid-container">
113
+ <div class="heatmap-cell">
114
+ {{ monthly_returns_heatmap_html | safe }}
115
+ </div>
116
+ <div class="yearly-returns-cell">
117
+ {{ yearly_returns_histogram_html | safe }}
118
+ </div>
119
+ </div>
120
+ <div class="grid-container">
121
+ <div class="metrics-table">
122
+ <h2>Time Metrics</h2>
123
+ {{ time_metrics_table_html | safe }}
124
+ </div>
125
+ <div class="metrics-table">
126
+ <h2>Performance Metrics</h2>
127
+ {{ key_metrics_table_html | safe }}
128
+ </div>
129
+ <div class="metrics-table">
130
+ <h2>Trade Metrics</h2>
131
+ {{ trades_metrics_table_html | safe }}
132
+ </div>
133
+ </div>
134
+ </div>
135
+ <div id="Trades" class="tabcontent">
136
+ {{ trades_table_html | safe }}
137
+ {% raw %}
138
+ <script>
139
+ $(document).ready(function() {
140
+ $('.stats-table').DataTable({
141
+ paging: true,
142
+ pageLength: 10,
143
+ searching: true
144
+ });
145
+ });
146
+ </script>
147
+ {% endraw %}
148
+ </div>
149
+ <div id="DataAnalysis" class="tabcontent">
150
+ <h2>OHLCV Data Completeness Charts</h2>
151
+ {{ data_completeness_charts_html | safe }}
152
+ </div>
153
+ </body>
154
+ </html>
@@ -54,8 +54,10 @@ class ActionHandler:
54
54
  action_handler.set_strategy(payload)
55
55
  return action_handler
56
56
 
57
- def handle(self, payload, algorithm):
58
- return self.strategy.handle_event(payload=payload, algorithm=algorithm)
57
+ def handle(self, payload, context, strategy_orchestrator_service):
58
+ return self.strategy.handle_event(
59
+ payload, context, strategy_orchestrator_service
60
+ )
59
61
 
60
62
  def set_strategy(self, payload):
61
63
  action = ActionHandler.get_action_type(payload)
@@ -4,5 +4,5 @@ from abc import ABC, abstractmethod
4
4
  class ActionHandlerStrategy(ABC):
5
5
 
6
6
  @abstractmethod
7
- def handle_event(self, payload, algorithm):
7
+ def handle_event(self, payload, context, strategy_orchestrator_service):
8
8
  pass
@@ -7,7 +7,7 @@ from investing_algorithm_framework.app.stateless.action_handlers \
7
7
  class CheckOnlineHandler(ActionHandlerStrategy):
8
8
  MESSAGE = {"message": "online"}
9
9
 
10
- def handle_event(self, payload, algorithm):
10
+ def handle_event(self, payload, context, strategy_orchestrator_service):
11
11
  return {
12
12
  "statusCode": 200,
13
13
  "headers": {"Content-Type": "application/json"},
@@ -5,24 +5,31 @@ from investing_algorithm_framework.app.stateless.action_handlers \
5
5
 
6
6
 
7
7
  class RunStrategyHandler(ActionHandlerStrategy):
8
+ """
9
+ RunStrategyHandler is an action handler that runs a strategy and its tasks
10
+ synchronously.
11
+
12
+ If the run was successful, it returns a 200 OK response with a message
13
+ "OK".
14
+ """
8
15
  MESSAGE = {"message": "Ok"}
9
16
 
10
- def handle_event(self, payload, algorithm):
11
- strategies = algorithm.strategy_orchestrator_service\
17
+ def handle_event(self, payload, context, strategy_orchestrator_service):
18
+ strategies = strategy_orchestrator_service\
12
19
  .get_strategies(payload.get("strategies", None))
13
- tasks = algorithm.strategy_orchestrator_service.get_tasks()
20
+ tasks = strategy_orchestrator_service.get_tasks()
14
21
 
15
22
  for strategy in strategies:
16
- algorithm.strategy_orchestrator_service.run_strategy(
23
+ strategy_orchestrator_service.run_strategy(
17
24
  strategy=strategy,
18
- algorithm=algorithm,
25
+ context=context,
19
26
  sync=True
20
27
  )
21
28
 
22
29
  for task in tasks:
23
- algorithm.strategy_orchestrator_service.run_task(
30
+ strategy_orchestrator_service.run_task(
24
31
  task=task,
25
- algorithm=algorithm,
32
+ context=context,
26
33
  sync=True
27
34
  )
28
35