investing-algorithm-framework 8.0.0__tar.gz → 8.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/PKG-INFO +1 -1
  2. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/context.py +5 -1
  3. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/backtest_report.py +45 -2
  4. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/templates/dashboard.js +300 -120
  5. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/templates/dashboard_template.html.j2 +2 -0
  6. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/strategy.py +10 -5
  7. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/mcp_server.py +825 -22
  8. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +16 -0
  9. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +16 -0
  10. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/combine_backtests.py +120 -0
  11. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/order/order.py +27 -3
  12. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +10 -2
  13. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_service/trade_service.py +2 -0
  14. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/pyproject.toml +1 -1
  15. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/LICENSE +0 -0
  16. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/README.md +0 -0
  17. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/__init__.py +0 -0
  18. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/analysis/__init__.py +0 -0
  19. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/analysis/backtest_data_ranges.py +0 -0
  20. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/analysis/markdown.py +0 -0
  21. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/analysis/ranking.py +0 -0
  22. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/__init__.py +0 -0
  23. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/algorithm/__init__.py +0 -0
  24. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/algorithm/algorithm.py +0 -0
  25. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/algorithm/algorithm_factory.py +0 -0
  26. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/app.py +0 -0
  27. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/app_hook.py +0 -0
  28. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/eventloop.py +0 -0
  29. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/__init__.py +0 -0
  30. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/ascii.py +0 -0
  31. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/backtest_report_old.py +0 -0
  32. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/__init__.py +0 -0
  33. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +0 -0
  34. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/equity_curve.py +0 -0
  35. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +0 -0
  36. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/line_chart.py +0 -0
  37. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +0 -0
  38. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +0 -0
  39. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +0 -0
  40. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +0 -0
  41. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/generate.py +0 -0
  42. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/__init__.py +0 -0
  43. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +0 -0
  44. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
  45. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +0 -0
  46. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +0 -0
  47. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/trades_table.py +0 -0
  48. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/tables/utils.py +0 -0
  49. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/templates/dashboard.css +0 -0
  50. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +0 -0
  51. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
  52. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
  53. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
  54. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
  55. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
  56. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
  57. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/task.py +0 -0
  58. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/__init__.py +0 -0
  59. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
  60. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
  61. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
  62. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
  63. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/create_app.py +0 -0
  64. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/error_handler.py +0 -0
  65. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/responses.py +0 -0
  66. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
  67. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
  68. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
  69. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
  70. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
  71. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
  72. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/__init__.py +0 -0
  73. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/cli.py +0 -0
  74. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/deploy_to_aws_lambda.py +0 -0
  75. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/deploy_to_azure_function.py +0 -0
  76. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/initialize_app.py +0 -0
  77. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/.gitignore.template +0 -0
  78. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/app.py.template +0 -0
  79. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +0 -0
  80. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/app_azure_function.py.template +0 -0
  81. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/app_web.py.template +0 -0
  82. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +0 -0
  83. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +0 -0
  84. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +0 -0
  85. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +0 -0
  86. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +0 -0
  87. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/azure_function_host.json.template +0 -0
  88. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +0 -0
  89. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +0 -0
  90. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/data_providers.py.template +0 -0
  91. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/env.example.template +0 -0
  92. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/env_azure_function.example.template +0 -0
  93. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/market_data_providers.py.template +0 -0
  94. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/readme.md.template +0 -0
  95. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/requirements.txt.template +0 -0
  96. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/run_backtest.py.template +0 -0
  97. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/templates/strategy.py.template +0 -0
  98. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/cli/validate_backtest_checkpoints.py +0 -0
  99. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/create_app.py +0 -0
  100. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/dependency_container.py +0 -0
  101. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/__init__.py +0 -0
  102. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/algorithm_id.py +0 -0
  103. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/__init__.py +0 -0
  104. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest.py +0 -0
  105. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_date_range.py +0 -0
  106. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_metrics.py +0 -0
  107. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +0 -0
  108. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_run.py +0 -0
  109. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/backtest_utils.py +0 -0
  110. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/templates/backtest.html +0 -0
  111. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/templates/finterion-dark.png +0 -0
  112. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/backtesting/templates/finterion-light.png +0 -0
  113. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/config.py +0 -0
  114. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/constants.py +0 -0
  115. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/data_provider.py +0 -0
  116. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/data_structures.py +0 -0
  117. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
  118. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/exceptions.py +0 -0
  119. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/__init__.py +0 -0
  120. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/app_mode.py +0 -0
  121. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/base_model.py +0 -0
  122. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/data/__init__.py +0 -0
  123. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/data/data_source.py +0 -0
  124. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/data/data_type.py +0 -0
  125. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/event.py +0 -0
  126. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
  127. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
  128. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
  129. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/order/order.py +0 -0
  130. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
  131. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
  132. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
  133. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
  134. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
  135. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +0 -0
  136. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
  137. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
  138. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/position/position.py +0 -0
  139. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/position/position_size.py +0 -0
  140. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
  141. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/risk_rules/__init__.py +0 -0
  142. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/risk_rules/scaling_rule.py +0 -0
  143. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +0 -0
  144. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +0 -0
  145. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/risk_rules/trading_cost.py +0 -0
  146. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/snapshot_interval.py +0 -0
  147. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
  148. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
  149. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
  150. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
  151. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
  152. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/tracing/trace.py +0 -0
  153. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/trade/__init__.py +0 -0
  154. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/trade/trade.py +0 -0
  155. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/trade/trade_status.py +0 -0
  156. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +0 -0
  157. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/models/trade/trade_take_profit.py +0 -0
  158. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/order_executor.py +0 -0
  159. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/portfolio_provider.py +0 -0
  160. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/services/__init__.py +0 -0
  161. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/services/market_credential_service.py +0 -0
  162. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/services/portfolios/__init__.py +0 -0
  163. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -0
  164. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/services/rounding_service.py +0 -0
  165. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/services/state_handler.py +0 -0
  166. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
  167. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/strategy.py +0 -0
  168. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
  169. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/csv.py +0 -0
  170. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/custom_tqdm.py +0 -0
  171. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/dates.py +0 -0
  172. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +0 -0
  173. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/polars.py +0 -0
  174. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/random.py +0 -0
  175. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
  176. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
  177. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
  178. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/download_data.py +0 -0
  179. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
  180. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/data_providers/__init__.py +0 -0
  181. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/data_providers/ccxt.py +0 -0
  182. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/data_providers/csv.py +0 -0
  183. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/data_providers/pandas.py +0 -0
  184. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
  185. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
  186. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
  187. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
  188. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
  189. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
  190. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/order/trade_allocation.py +0 -0
  191. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/order_trade_association.py +0 -0
  192. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
  193. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
  194. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +0 -0
  195. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
  196. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
  197. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
  198. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/trades/__init__.py +0 -0
  199. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/trades/trade.py +0 -0
  200. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +0 -0
  201. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +0 -0
  202. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/order_executors/__init__.py +0 -0
  203. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +0 -0
  204. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +0 -0
  205. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +0 -0
  206. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +0 -0
  207. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
  208. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
  209. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +0 -0
  210. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
  211. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
  212. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
  213. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
  214. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/trade_allocation_repository.py +0 -0
  215. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/trade_repository.py +0 -0
  216. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +0 -0
  217. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +0 -0
  218. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
  219. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/aws/__init__.py +0 -0
  220. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/aws/state_handler.py +0 -0
  221. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/azure/__init__.py +0 -0
  222. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/azure/state_handler.py +0 -0
  223. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +0 -0
  224. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +0 -0
  225. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +0 -0
  226. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/__init__.py +0 -0
  227. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/configuration_service.py +0 -0
  228. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/data_providers/__init__.py +0 -0
  229. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/data_providers/data.py +0 -0
  230. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/data_providers/data_provider_service.py +0 -0
  231. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/market_credential_service.py +0 -0
  232. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/__init__.py +0 -0
  233. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/alpha.py +0 -0
  234. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/beta.py +0 -0
  235. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/cagr.py +0 -0
  236. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/calmar_ratio.py +0 -0
  237. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/drawdown.py +0 -0
  238. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/equity_curve.py +0 -0
  239. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/exposure.py +0 -0
  240. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/generate.py +0 -0
  241. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/mean_daily_return.py +0 -0
  242. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/price_efficiency.py +0 -0
  243. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/profit_factor.py +0 -0
  244. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/recovery.py +0 -0
  245. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/returns.py +0 -0
  246. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/risk_free_rate.py +0 -0
  247. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/sharpe_ratio.py +0 -0
  248. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/sortino_ratio.py +0 -0
  249. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/standard_deviation.py +0 -0
  250. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/trades.py +0 -0
  251. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  252. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  253. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  254. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/volatility.py +0 -0
  255. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/metrics/win_rate.py +0 -0
  256. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
  257. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/order_service/order_backtest_service.py +0 -0
  258. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/order_service/order_executor_lookup.py +0 -0
  259. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/order_service/order_service.py +0 -0
  260. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/__init__.py +0 -0
  261. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +0 -0
  262. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +0 -0
  263. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -0
  264. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/portfolio_service.py +0 -0
  265. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +0 -0
  266. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -0
  267. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/positions/__init__.py +0 -0
  268. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/positions/position_service.py +0 -0
  269. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/positions/position_snapshot_service.py +0 -0
  270. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/repository_service.py +0 -0
  271. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_order_evaluator/__init__.py +0 -0
  272. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +0 -0
  273. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +0 -0
  274. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +0 -0
  275. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_service/__init__.py +0 -0
  276. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +0 -0
  277. {investing_algorithm_framework-8.0.0 → investing_algorithm_framework-8.1.0}/investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: investing-algorithm-framework
3
- Version: 8.0.0
3
+ Version: 8.1.0
4
4
  Summary: A framework for creating trading bots
5
5
  Author: MDUYN
6
6
  Requires-Python: >=3.10
@@ -161,7 +161,8 @@ class Context:
161
161
  market=None,
162
162
  execute=True,
163
163
  validate=True,
164
- sync=True
164
+ sync=True,
165
+ metadata=None
165
166
  ) -> Order:
166
167
  """
167
168
  Function to create a limit order. This function will create a limit
@@ -257,6 +258,9 @@ class Context:
257
258
  "trading_symbol": portfolio.trading_symbol,
258
259
  }
259
260
 
261
+ if metadata is not None:
262
+ order_data["metadata"] = metadata
263
+
260
264
  if BACKTESTING_FLAG in self.configuration_service.config \
261
265
  and self.configuration_service.config[BACKTESTING_FLAG]:
262
266
  order_data["created_at"] = \
@@ -125,14 +125,17 @@ class BacktestReport:
125
125
  with open(path, "w") as f:
126
126
  f.write(self.html_report)
127
127
 
128
+ if browser:
129
+ webbrowser.open(f"file://{path}")
130
+ return
131
+
128
132
  try:
129
133
  from IPython import get_ipython
130
134
  shell = get_ipython().__class__.__name__
131
135
  if shell == 'ZMQInteractiveShell':
132
136
  from IPython.display import display, HTML
133
137
  display(HTML(self.html_report))
134
- if not browser:
135
- return
138
+ return
136
139
  except (NameError, ImportError):
137
140
  pass
138
141
 
@@ -463,6 +466,29 @@ class BacktestReport:
463
466
  op_dt = t.opened_at
464
467
  cl_dt = t.closed_at
465
468
  total_fees = getattr(t, 'total_fees', 0) or 0
469
+ # Stop-loss / take-profit status
470
+ t_sls = getattr(t, 'stop_losses', None)
471
+ t_tps = getattr(t, 'take_profits', None)
472
+ sl_triggered = any(
473
+ getattr(sl, 'triggered', False)
474
+ for sl in (t_sls or [])
475
+ )
476
+ tp_triggered = any(
477
+ getattr(tp, 'triggered', False)
478
+ for tp in (t_tps or [])
479
+ )
480
+ has_sl = bool(t_sls and len(t_sls) > 0)
481
+ has_tp = bool(t_tps and len(t_tps) > 0)
482
+ # Collect unique order reasons
483
+ t_reasons = set()
484
+ for t_o in (getattr(t, 'orders', None)
485
+ or []):
486
+ t_o_meta = getattr(
487
+ t_o, 'metadata', None
488
+ ) or {}
489
+ r = t_o_meta.get('order_reason')
490
+ if r:
491
+ t_reasons.add(r)
466
492
  trades_list.append({
467
493
  'id': idx_t,
468
494
  'sym': sym,
@@ -476,6 +502,17 @@ class BacktestReport:
476
502
  'total_fees': round(total_fees, 4),
477
503
  'net_gain': round(ng, 2),
478
504
  'pct': round(pct, 2),
505
+ 'stop_loss': (
506
+ 'Triggered' if sl_triggered
507
+ else ('Set' if has_sl else '')
508
+ ),
509
+ 'take_profit': (
510
+ 'Triggered' if tp_triggered
511
+ else ('Set' if has_tp else '')
512
+ ),
513
+ 'reasons': ', '.join(
514
+ sorted(t_reasons)
515
+ ),
479
516
  })
480
517
  sym_stats.setdefault(sym, {'count': 0, 'gain': 0})
481
518
  sym_stats[sym]['count'] += 1
@@ -588,6 +625,11 @@ class BacktestReport:
588
625
  o_slippage = getattr(o, 'slippage', None)
589
626
  if o_slippage is None:
590
627
  o_slippage = 0
628
+ o_meta = getattr(o, 'metadata', None)
629
+ o_meta = o_meta if o_meta else {}
630
+ o_reason = o_meta.get(
631
+ 'order_reason', ''
632
+ )
591
633
  orders_list.append({
592
634
  'sym': getattr(o, 'target_symbol', '')
593
635
  or '',
@@ -617,6 +659,7 @@ class BacktestReport:
617
659
  'slippage': round(
618
660
  float(o_slippage), 4
619
661
  ),
662
+ 'reason': o_reason,
620
663
  'created': _fmt_date(o_dt)
621
664
  if o_dt else '',
622
665
  'updated': _fmt_date(u_dt)
@@ -24,6 +24,8 @@ const COMP_COLS = [
24
24
  ['Volatility','annual_volatility','pct_abs','min'],
25
25
  ['Recovery','recovery_factor','ratio','max'],
26
26
  ['Net Gain %','total_net_gain_percentage','pct','max'],
27
+ ['Consistency','consistency_score','pct_abs','max'],
28
+ ['Stability','stability_score','pct_abs','max'],
27
29
  ['VaR 95%','var_95','pct','min'],
28
30
  ['CVaR 95%','cvar_95','pct','min'],
29
31
  ];
@@ -1720,6 +1722,54 @@ function rebuildRankingTable() {
1720
1722
  if (bestIdx>=0) bestVals[key]=bestIdx;
1721
1723
  });
1722
1724
 
1725
+ // Absolute-threshold color coding: red/yellow/green based on
1726
+ // financially meaningful breakpoints, NOT relative ranking.
1727
+ // Returns a 0-1 score where 0=bad, 1=good.
1728
+ var _absThresholds = {
1729
+ // [bad_end, neutral, good_start] — linear interpolation between
1730
+ // 'max' metrics: higher value = better
1731
+ 'cagr': [-0.05, 0, 0.15],
1732
+ 'sharpe_ratio': [-0.5, 0.5, 1.5],
1733
+ 'sortino_ratio': [-0.5, 0.5, 2.0],
1734
+ 'calmar_ratio': [-0.5, 0.5, 2.0],
1735
+ 'recovery_factor': [-1, 0, 2.0],
1736
+ 'total_net_gain_percentage': [-0.05, 0, 0.20],
1737
+ 'consistency_score': [0.2, 0.5, 0.8],
1738
+ 'stability_score': [0.2, 0.5, 0.8],
1739
+ // 'min' metrics: lower absolute value = better (inverted internally)
1740
+ 'max_drawdown': [0.03, 0.10, 0.25], // abs values
1741
+ 'annual_volatility': [0.05, 0.15, 0.40],
1742
+ 'var_95': [0, -0.02, -0.05], // negative; closer to 0 = better
1743
+ 'cvar_95': [0, -0.03, -0.08],
1744
+ };
1745
+
1746
+ function _metricColor(key, v, direction) {
1747
+ if (v == null) return '';
1748
+ var th = _absThresholds[key];
1749
+ if (!th) return '';
1750
+ var t; // 0=bad … 1=good
1751
+ if (direction === 'min') {
1752
+ // For min-direction: value at th[0] = best (green), th[2] = worst (red)
1753
+ if (key === 'max_drawdown') v = Math.abs(v);
1754
+ if (th[2] !== th[0]) t = 1 - Math.max(0, Math.min(1, (v - th[0]) / (th[2] - th[0])));
1755
+ else t = 0.5;
1756
+ } else {
1757
+ // For max-direction: value at th[0] = worst (red), th[2] = best (green)
1758
+ if (th[2] !== th[0]) t = Math.max(0, Math.min(1, (v - th[0]) / (th[2] - th[0])));
1759
+ else t = 0.5;
1760
+ }
1761
+ var h, s, l;
1762
+ if (t <= 0.5) {
1763
+ h = Math.round(t * 2 * 45);
1764
+ s = 70; l = 44;
1765
+ } else {
1766
+ h = Math.round(45 + (t - 0.5) * 2 * 95);
1767
+ s = 65; l = 38 - Math.round((t - 0.5) * 2 * 4);
1768
+ }
1769
+ var alpha = 0.15 + t * 0.20;
1770
+ return 'color:hsl(' + h + ',' + (s + 10) + '%,' + (l - 10) + '%)';
1771
+ }
1772
+
1723
1773
  let html = '';
1724
1774
  pageIndices.forEach(i => {
1725
1775
  const s = STRATEGIES[i];
@@ -1730,11 +1780,18 @@ function rebuildRankingTable() {
1730
1780
  html += '<td class="sticky-col" onclick="showPage(\'strat-'+i+'\')"><span class="sb-dot" style="background:'+s.color+'"></span>'+s.name+(s.tag ? ' <span class="tag-badge">'+s.tag+'</span>' : '')+'</td>';
1731
1781
  COMP_COLS.forEach(([label,key,ftype,direction]) => {
1732
1782
  const v = key === 'cagr' ? s.summary.cagr : m[key];
1733
- const isBest = bestVals[key]===i;
1734
- const cls = (isBest && pageIndices.length>1) ? ' class="best-cell"' : '';
1735
- if (key==='max_drawdown' && v!=null) html += '<td'+cls+' onclick="showPage(\'strat-'+i+'\')">'+(Math.abs(v)*100).toFixed(1)+'%</td>';
1736
- else if (key==='average_trade_duration' && v!=null) html += '<td'+cls+' onclick="showPage(\'strat-'+i+'\')">'+v.toFixed(1)+'d</td>';
1737
- else html += '<td'+cls+' onclick="showPage(\'strat-'+i+'\')">' + fmtVal(v,ftype) + '</td>';
1783
+ const isBest = bestVals[key]===i && pageIndices.length > 1;
1784
+ var colorStyle = _metricColor(key, v, direction);
1785
+ var star = isBest ? ' ★' : '';
1786
+ var txt;
1787
+ if (key==='max_drawdown' && v!=null) txt = (Math.abs(v)*100).toFixed(1)+'%';
1788
+ else if (key==='average_trade_duration' && v!=null) txt = v.toFixed(1)+'d';
1789
+ else txt = fmtVal(v,ftype);
1790
+ if (colorStyle) {
1791
+ html += '<td onclick="showPage(\'strat-'+i+'\')"><span style="'+colorStyle+';font-weight:600">'+txt+star+'</span></td>';
1792
+ } else {
1793
+ html += '<td onclick="showPage(\'strat-'+i+'\')">'+txt+star+'</td>';
1794
+ }
1738
1795
  });
1739
1796
  html += '</tr>';
1740
1797
  });
@@ -1848,6 +1905,8 @@ function updateStratSummary(stratIdx) {
1848
1905
  + kpiCard('Windows', String(m.number_of_windows || 0))
1849
1906
  + kpiCard('Profitable', String(m.number_of_profitable_windows || 0), 'var(--green)')
1850
1907
  + kpiCard('Total Net Gain', fmtVal(m.total_net_gain_percentage,'pct'))
1908
+ + kpiCard('Consistency (CV)', m.consistency_score != null ? (m.consistency_score * 100).toFixed(1) + '%' : '—', m.consistency_score != null && m.consistency_score >= 0.6 ? 'var(--green)' : m.consistency_score != null && m.consistency_score < 0.4 ? 'var(--red)' : null)
1909
+ + kpiCard('Stability (σ)', m.stability_score != null ? (m.stability_score * 100).toFixed(1) + '%' : '—', m.stability_score != null && m.stability_score >= 0.6 ? 'var(--green)' : m.stability_score != null && m.stability_score < 0.4 ? 'var(--red)' : null)
1851
1910
  + kpiCard('Runs', String(strat.runIds.length))
1852
1911
  + '</div>';
1853
1912
  } else {
@@ -6061,6 +6120,9 @@ var tradesHeaders = [
6061
6120
  {key: 'total_fees', label: 'Fees', align: 'right'},
6062
6121
  {key: 'net_gain', label: 'Net Gain', align: 'right', colorFn: function(r) { return r.net_gain >= 0 ? 'var(--green)' : 'var(--red)'; }},
6063
6122
  {key: 'pct', label: 'Return %', align: 'right', colorFn: function(r) { return r.pct >= 0 ? 'var(--green)' : 'var(--red)'; }},
6123
+ {key: 'stop_loss', label: 'Stop Loss', colorFn: function(r) { return r.stop_loss === 'Triggered' ? '#E91E63' : (r.stop_loss === 'Set' ? 'var(--text-secondary)' : ''); }},
6124
+ {key: 'take_profit', label: 'Take Profit', colorFn: function(r) { return r.take_profit === 'Triggered' ? '#9C27B0' : (r.take_profit === 'Set' ? 'var(--text-secondary)' : ''); }},
6125
+ {key: 'reasons', label: 'Order Reasons'},
6064
6126
  ];
6065
6127
 
6066
6128
  var ordersHeaders = [
@@ -6068,6 +6130,10 @@ var ordersHeaders = [
6068
6130
  {key: 'side', label: 'Side', colorFn: function(r) { return r.side === 'BUY' ? 'var(--green)' : 'var(--red)'; }},
6069
6131
  {key: 'type', label: 'Type'},
6070
6132
  {key: 'status', label: 'Status'},
6133
+ {key: 'reason', label: 'Reason', colorFn: function(r) {
6134
+ var c = {'buy_signal':'var(--green)','sell_signal':'var(--red)','scale_in':'#2196F3','scale_out':'#FF9800','stop_loss':'#E91E63','take_profit':'#9C27B0'};
6135
+ return c[r.reason] || '';
6136
+ }},
6071
6137
  {key: 'price', label: 'Price', align: 'right'},
6072
6138
  {key: 'amount', label: 'Amount', align: 'right'},
6073
6139
  {key: 'filled', label: 'Filled', align: 'right'},
@@ -6124,8 +6190,7 @@ function buildPositionsTable(stratIdx) {
6124
6190
  pagTableRenderers[tableKey]();
6125
6191
  }
6126
6192
 
6127
- // Scatter chart for trade/order timeline
6128
- var timelineChartInstances = {};
6193
+ // Timeline scatter chart (custom canvas — no Chart.js dependency)
6129
6194
 
6130
6195
  function buildTimelineScatter(stratIdx) {
6131
6196
  var sid = 'strat-' + stratIdx;
@@ -6136,142 +6201,257 @@ function buildTimelineScatter(stratIdx) {
6136
6201
 
6137
6202
  var trades = rd.TRADES || [];
6138
6203
  var orders = rd.ORDERS || [];
6139
- if (trades.length === 0 && orders.length === 0) {
6140
- el.innerHTML = '';
6141
- return;
6142
- }
6204
+ if (trades.length === 0 && orders.length === 0) { el.innerHTML = ''; return; }
6143
6205
 
6144
- // Build scatter datasets
6145
- var buyPoints = [];
6146
- var sellPoints = [];
6206
+ // Collect all points with symbol info
6207
+ var allPoints = [];
6147
6208
  orders.forEach(function(o) {
6148
- if (!o.created) return;
6149
- var point = {x: o.created, y: o.price, label: o.sym + ' ' + o.side + ' ' + o.status};
6150
- if (o.side === 'BUY') buyPoints.push(point);
6151
- else sellPoints.push(point);
6209
+ if (!o.created || !o.price) return;
6210
+ allPoints.push({
6211
+ date: o.created, y: o.price, sym: o.sym,
6212
+ label: o.sym + ' ' + o.side + ' ' + o.status,
6213
+ series: o.side === 'BUY' ? 'buy' : 'sell'
6214
+ });
6152
6215
  });
6153
-
6154
- var tradeOpenPoints = [];
6155
- var tradeClosePoints = [];
6156
6216
  trades.forEach(function(t) {
6157
- if (t.opened) {
6158
- tradeOpenPoints.push({x: t.opened, y: t.open_price, label: t.sym + ' opened'});
6217
+ if (t.opened && t.open_price) {
6218
+ allPoints.push({date: t.opened, y: t.open_price, sym: t.sym, label: t.sym + ' opened', series: 'tradeOpen'});
6159
6219
  }
6160
6220
  if (t.closed && t.close_price) {
6161
- var c = t.net_gain >= 0 ? 'rgba(16,185,129,0.9)' : 'rgba(239,68,68,0.9)';
6162
- tradeClosePoints.push({x: t.closed, y: t.close_price, label: t.sym + ' closed (' + (t.net_gain >= 0 ? '+' : '') + t.pct + '%)', color: c, gain: t.net_gain});
6221
+ allPoints.push({
6222
+ date: t.closed, y: t.close_price, sym: t.sym,
6223
+ label: t.sym + ' closed (' + (t.net_gain >= 0 ? '+' : '') + t.pct + '%)',
6224
+ series: 'tradeClose', gain: t.net_gain
6225
+ });
6163
6226
  }
6164
6227
  });
6228
+ if (allPoints.length === 0) { el.innerHTML = ''; return; }
6165
6229
 
6166
- // Destroy old chart
6167
- if (timelineChartInstances[sid]) {
6168
- timelineChartInstances[sid].destroy();
6169
- timelineChartInstances[sid] = null;
6170
- }
6230
+ // Collect unique symbols sorted
6231
+ var symSet = {};
6232
+ allPoints.forEach(function(p) { if (p.sym) symSet[p.sym] = true; });
6233
+ var symbols = Object.keys(symSet).sort();
6234
+
6235
+ // Build dropdown HTML — default is empty prompt
6236
+ var optionsHtml = '<option value="" selected>Select asset\u2026</option>';
6237
+ symbols.forEach(function(s) { optionsHtml += '<option value="' + s + '">' + s + '</option>'; });
6171
6238
 
6172
6239
  el.innerHTML = '<div class="chart-card">'
6173
- + '<div class="chart-title">Trade &amp; Order Timeline</div>'
6240
+ + '<div class="chart-title" style="display:flex;align-items:center;gap:12px;">'
6241
+ + 'Trade &amp; Order Timeline'
6242
+ + '<select id="sel-' + sid + '-timeline-sym" style="'
6243
+ + 'font-size:12px;padding:3px 8px;border-radius:6px;'
6244
+ + 'border:1px solid var(--border,#23232a);background:var(--surface,#111113);'
6245
+ + 'color:var(--text,#eaeaf0);cursor:pointer;outline:none;">'
6246
+ + optionsHtml + '</select>'
6247
+ + '</div>'
6174
6248
  + '<div class="chart-wrap"><canvas id="c-' + sid + '-timeline"></canvas>'
6175
6249
  + '<div class="tooltip" id="tt-' + sid + '-timeline"></div></div></div>';
6176
6250
 
6177
- var canvas = document.getElementById('c-' + sid + '-timeline');
6178
- if (!canvas) return;
6251
+ // Store points on element for redraw
6252
+ el._allPoints = allPoints;
6253
+ el._stratIdx = stratIdx;
6254
+
6255
+ // Draw initial prompt message (no symbol selected)
6256
+ _drawTimelineCanvas(sid, allPoints, '');
6179
6257
 
6180
- var datasets = [];
6181
- if (buyPoints.length > 0) {
6182
- datasets.push({
6183
- label: 'Buy Orders',
6184
- data: buyPoints.map(function(p) { return {x: p.x, y: p.y}; }),
6185
- pointBackgroundColor: 'rgba(16,185,129,0.7)',
6186
- pointBorderColor: 'rgba(16,185,129,1)',
6187
- pointRadius: 5,
6188
- pointStyle: 'triangle',
6189
- showLine: false,
6190
- _labels: buyPoints.map(function(p) { return p.label; }),
6258
+ // Dropdown change handler
6259
+ var sel = document.getElementById('sel-' + sid + '-timeline-sym');
6260
+ if (sel) {
6261
+ sel.addEventListener('change', function() {
6262
+ _drawTimelineCanvas(sid, el._allPoints, sel.value);
6191
6263
  });
6192
6264
  }
6193
- if (sellPoints.length > 0) {
6194
- datasets.push({
6195
- label: 'Sell Orders',
6196
- data: sellPoints.map(function(p) { return {x: p.x, y: p.y}; }),
6197
- pointBackgroundColor: 'rgba(239,68,68,0.7)',
6198
- pointBorderColor: 'rgba(239,68,68,1)',
6199
- pointRadius: 5,
6200
- pointStyle: 'triangleDown' in Chart.defaults ? 'triangle' : 'rect',
6201
- pointRotation: 180,
6202
- showLine: false,
6203
- _labels: sellPoints.map(function(p) { return p.label; }),
6204
- });
6265
+ }
6266
+
6267
+ function _drawTimelineCanvas(sid, allPoints, filterSym) {
6268
+ // Filter points
6269
+ // Show prompt when no symbol selected
6270
+ if (!filterSym) {
6271
+ var canvas = document.getElementById('c-' + sid + '-timeline');
6272
+ if (canvas) {
6273
+ var r2 = resizeCanvas('c-' + sid + '-timeline');
6274
+ if (r2) {
6275
+ r2.ctx.font = '14px JetBrains Mono, monospace';
6276
+ r2.ctx.fillStyle = COL.dim; r2.ctx.textAlign = 'center';
6277
+ r2.ctx.fillText('Select an asset to view trades & orders', r2.w / 2, r2.h / 2);
6278
+ }
6279
+ }
6280
+ return;
6205
6281
  }
6206
- if (tradeOpenPoints.length > 0) {
6207
- datasets.push({
6208
- label: 'Trade Opened',
6209
- data: tradeOpenPoints.map(function(p) { return {x: p.x, y: p.y}; }),
6210
- pointBackgroundColor: 'rgba(34,211,238,0.8)',
6211
- pointBorderColor: 'rgba(34,211,238,1)',
6212
- pointRadius: 7,
6213
- pointStyle: 'circle',
6214
- showLine: false,
6215
- _labels: tradeOpenPoints.map(function(p) { return p.label; }),
6216
- });
6282
+
6283
+ // Filter points by symbol
6284
+ var points = allPoints.filter(function(p) { return p.sym === filterSym; });
6285
+ if (points.length === 0) {
6286
+ var canvas = document.getElementById('c-' + sid + '-timeline');
6287
+ if (canvas) {
6288
+ var r2 = resizeCanvas('c-' + sid + '-timeline');
6289
+ if (r2) {
6290
+ r2.ctx.font = '13px JetBrains Mono, monospace';
6291
+ r2.ctx.fillStyle = COL.dim; r2.ctx.textAlign = 'center';
6292
+ r2.ctx.fillText('No data for selected asset', r2.w / 2, r2.h / 2);
6293
+ }
6294
+ }
6295
+ return;
6217
6296
  }
6218
- if (tradeClosePoints.length > 0) {
6219
- datasets.push({
6220
- label: 'Trade Closed',
6221
- data: tradeClosePoints.map(function(p) { return {x: p.x, y: p.y}; }),
6222
- pointBackgroundColor: tradeClosePoints.map(function(p) { return p.color; }),
6223
- pointBorderColor: tradeClosePoints.map(function(p) { return p.color; }),
6224
- pointRadius: 7,
6225
- pointStyle: 'rectRounded',
6226
- showLine: false,
6227
- _labels: tradeClosePoints.map(function(p) { return p.label; }),
6228
- });
6297
+
6298
+ // Sort by date
6299
+ points.sort(function(a,b) { return a.date < b.date ? -1 : a.date > b.date ? 1 : 0; });
6300
+ var uniqueDates = [];
6301
+ var seen = {};
6302
+ points.forEach(function(p) { if (!seen[p.date]) { uniqueDates.push(p.date); seen[p.date] = true; } });
6303
+
6304
+ // Y range
6305
+ var ys = points.map(function(p) { return p.y; });
6306
+ var yMin = Math.min.apply(null, ys);
6307
+ var yMax = Math.max.apply(null, ys);
6308
+ if (yMin === yMax) { yMin -= 1; yMax += 1; }
6309
+ var yPad = (yMax - yMin) * 0.08;
6310
+ yMin -= yPad; yMax += yPad;
6311
+ var yRange = yMax - yMin;
6312
+
6313
+ var r = resizeCanvas('c-' + sid + '-timeline');
6314
+ if (!r) return;
6315
+ var ctx = r.ctx, w = r.w, h = r.h;
6316
+ var pad = { t: 25, r: 70, b: 35, l: 10 };
6317
+ var cw = w - pad.l - pad.r;
6318
+ var ch = h - pad.t - pad.b;
6319
+
6320
+ // Grid lines & Y labels
6321
+ ctx.strokeStyle = COL.border; ctx.lineWidth = 1;
6322
+ ctx.font = '10px JetBrains Mono, monospace'; ctx.fillStyle = COL.dim; ctx.textAlign = 'right';
6323
+ for (var i = 0; i <= 5; i++) {
6324
+ var gy = pad.t + ch - (i / 5) * ch;
6325
+ var val = yMin + (i / 5) * yRange;
6326
+ ctx.beginPath(); ctx.moveTo(pad.l, gy); ctx.lineTo(w - pad.r, gy); ctx.stroke();
6327
+ ctx.fillText(val.toFixed(val >= 100 ? 0 : 2), w - pad.r + 55, gy + 3.5);
6229
6328
  }
6230
6329
 
6231
- if (datasets.length === 0) { el.innerHTML = ''; return; }
6232
-
6233
- var isDark = document.documentElement.getAttribute('data-theme') !== 'light';
6234
- var gridColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)';
6235
- var textColor = isDark ? '#9898a6' : '#5a5a72';
6236
-
6237
- timelineChartInstances[sid] = new Chart(canvas, {
6238
- type: 'scatter',
6239
- data: {datasets: datasets},
6240
- options: {
6241
- responsive: true,
6242
- maintainAspectRatio: false,
6243
- interaction: {mode: 'nearest', intersect: true},
6244
- plugins: {
6245
- legend: {
6246
- display: true,
6247
- position: 'top',
6248
- labels: {color: textColor, font: {size: 11}, usePointStyle: true, pointStyleWidth: 12}
6249
- },
6250
- tooltip: {
6251
- callbacks: {
6252
- label: function(ctx) {
6253
- var ds = ctx.dataset;
6254
- var labels = ds._labels || [];
6255
- var lbl = labels[ctx.dataIndex] || '';
6256
- return lbl + ' @ ' + ctx.parsed.y;
6257
- }
6258
- }
6259
- }
6260
- },
6261
- scales: {
6262
- x: {
6263
- type: 'category',
6264
- grid: {color: gridColor},
6265
- ticks: {color: textColor, font: {size: 10}, maxRotation: 45, autoSkip: true, maxTicksLimit: 20}
6266
- },
6267
- y: {
6268
- grid: {color: gridColor},
6269
- ticks: {color: textColor, font: {size: 10}},
6270
- title: {display: true, text: 'Price', color: textColor}
6271
- }
6272
- }
6330
+ // X labels
6331
+ ctx.textAlign = 'center';
6332
+ var maxLabels = Math.min(uniqueDates.length, 8);
6333
+ var step = Math.max(1, Math.floor(uniqueDates.length / maxLabels));
6334
+ for (var i = 0; i < uniqueDates.length; i += step) {
6335
+ var xFrac = uniqueDates.length > 1 ? i / (uniqueDates.length - 1) : 0.5;
6336
+ var lx = pad.l + xFrac * cw;
6337
+ ctx.fillText(uniqueDates[i], lx, h - 5);
6338
+ }
6339
+
6340
+ // Series colors
6341
+ var seriesColors = {
6342
+ buy: { fill: 'rgba(16,185,129,0.8)', stroke: 'rgba(16,185,129,1)' },
6343
+ sell: { fill: 'rgba(239,68,68,0.8)', stroke: 'rgba(239,68,68,1)' },
6344
+ tradeOpen: { fill: 'rgba(34,211,238,0.8)', stroke: 'rgba(34,211,238,1)' },
6345
+ tradeClose: { fill: null, stroke: null },
6346
+ };
6347
+
6348
+ // Draw legend
6349
+ var legendItems = [
6350
+ { label: 'Buy', color: seriesColors.buy.fill, shape: 'triangle' },
6351
+ { label: 'Sell', color: seriesColors.sell.fill, shape: 'triangleDown' },
6352
+ { label: 'Trade Open', color: seriesColors.tradeOpen.fill, shape: 'circle' },
6353
+ { label: 'Trade Close +', color: COL.green, shape: 'rect' },
6354
+ { label: 'Trade Close \u2212', color: COL.red, shape: 'rect' },
6355
+ ];
6356
+ ctx.font = '10px JetBrains Mono, monospace';
6357
+ var lx = pad.l + 5;
6358
+ legendItems.forEach(function(item) {
6359
+ ctx.fillStyle = item.color;
6360
+ if (item.shape === 'circle') {
6361
+ ctx.beginPath(); ctx.arc(lx + 4, pad.t - 12, 4, 0, Math.PI * 2); ctx.fill();
6362
+ } else if (item.shape === 'triangle') {
6363
+ ctx.beginPath(); ctx.moveTo(lx, pad.t - 8); ctx.lineTo(lx + 8, pad.t - 8); ctx.lineTo(lx + 4, pad.t - 16); ctx.closePath(); ctx.fill();
6364
+ } else if (item.shape === 'triangleDown') {
6365
+ ctx.beginPath(); ctx.moveTo(lx, pad.t - 16); ctx.lineTo(lx + 8, pad.t - 16); ctx.lineTo(lx + 4, pad.t - 8); ctx.closePath(); ctx.fill();
6366
+ } else {
6367
+ ctx.fillRect(lx, pad.t - 16, 8, 8);
6273
6368
  }
6369
+ ctx.fillStyle = COL.dim;
6370
+ ctx.textAlign = 'left';
6371
+ ctx.fillText(item.label, lx + 12, pad.t - 8);
6372
+ lx += ctx.measureText(item.label).width + 24;
6274
6373
  });
6374
+
6375
+ // Draw points
6376
+ var hitBoxes = [];
6377
+ points.forEach(function(p) {
6378
+ var di = uniqueDates.indexOf(p.date);
6379
+ var xFrac = uniqueDates.length > 1 ? di / (uniqueDates.length - 1) : 0.5;
6380
+ var px = pad.l + xFrac * cw;
6381
+ var py = pad.t + ch - ((p.y - yMin) / yRange) * ch;
6382
+ var radius = 5;
6383
+ var sc = seriesColors[p.series];
6384
+ var fillC, strokeC;
6385
+
6386
+ if (p.series === 'tradeClose') {
6387
+ fillC = p.gain >= 0 ? COL.green : COL.red;
6388
+ strokeC = fillC;
6389
+ } else {
6390
+ fillC = sc.fill; strokeC = sc.stroke;
6391
+ }
6392
+
6393
+ ctx.fillStyle = fillC; ctx.strokeStyle = strokeC; ctx.lineWidth = 1.5;
6394
+
6395
+ if (p.series === 'buy') {
6396
+ ctx.beginPath();
6397
+ ctx.moveTo(px, py - radius); ctx.lineTo(px - radius, py + radius); ctx.lineTo(px + radius, py + radius);
6398
+ ctx.closePath(); ctx.fill(); ctx.stroke();
6399
+ } else if (p.series === 'sell') {
6400
+ ctx.beginPath();
6401
+ ctx.moveTo(px, py + radius); ctx.lineTo(px - radius, py - radius); ctx.lineTo(px + radius, py - radius);
6402
+ ctx.closePath(); ctx.fill(); ctx.stroke();
6403
+ } else if (p.series === 'tradeOpen') {
6404
+ ctx.beginPath(); ctx.arc(px, py, radius, 0, Math.PI * 2); ctx.fill(); ctx.stroke();
6405
+ } else {
6406
+ var s = radius * 1.4;
6407
+ ctx.beginPath();
6408
+ ctx.moveTo(px - s + 2, py - s); ctx.lineTo(px + s - 2, py - s);
6409
+ ctx.quadraticCurveTo(px + s, py - s, px + s, py - s + 2);
6410
+ ctx.lineTo(px + s, py + s - 2);
6411
+ ctx.quadraticCurveTo(px + s, py + s, px + s - 2, py + s);
6412
+ ctx.lineTo(px - s + 2, py + s);
6413
+ ctx.quadraticCurveTo(px - s, py + s, px - s, py + s - 2);
6414
+ ctx.lineTo(px - s, py - s + 2);
6415
+ ctx.quadraticCurveTo(px - s, py - s, px - s + 2, py - s);
6416
+ ctx.closePath(); ctx.fill(); ctx.stroke();
6417
+ }
6418
+
6419
+ hitBoxes.push({ x: px, y: py, r: radius + 3, label: p.label, price: p.y, date: p.date });
6420
+ });
6421
+
6422
+ // Store hitbox data for tooltip
6423
+ var canvas = document.getElementById('c-' + sid + '-timeline');
6424
+ canvas._timelineHitBoxes = hitBoxes;
6425
+
6426
+ // Setup tooltip (remove old listeners by cloning)
6427
+ var tooltip = document.getElementById('tt-' + sid + '-timeline');
6428
+ if (canvas && tooltip) {
6429
+ var newCanvas = canvas.cloneNode(true);
6430
+ newCanvas._timelineHitBoxes = hitBoxes;
6431
+ newCanvas.getContext('2d').drawImage(canvas, 0, 0);
6432
+ canvas.parentNode.replaceChild(newCanvas, canvas);
6433
+ newCanvas.addEventListener('mousemove', function(e) {
6434
+ var rect = newCanvas.getBoundingClientRect();
6435
+ var mx = e.clientX - rect.left;
6436
+ var my = e.clientY - rect.top;
6437
+ var hit = null;
6438
+ var boxes = newCanvas._timelineHitBoxes || [];
6439
+ for (var i = 0; i < boxes.length; i++) {
6440
+ var b = boxes[i];
6441
+ var dx = mx - b.x, dy = my - b.y;
6442
+ if (dx * dx + dy * dy <= b.r * b.r) { hit = b; break; }
6443
+ }
6444
+ if (hit) {
6445
+ tooltip.textContent = hit.date + ': ' + hit.label + ' @ ' + hit.price.toFixed(2);
6446
+ tooltip.classList.add('visible');
6447
+ tooltip.style.left = (mx + 12) + 'px';
6448
+ tooltip.style.top = (my - 20) + 'px';
6449
+ } else {
6450
+ tooltip.classList.remove('visible');
6451
+ }
6452
+ });
6453
+ newCanvas.addEventListener('mouseleave', function() { tooltip.classList.remove('visible'); });
6454
+ }
6275
6455
  }
6276
6456
 
6277
6457
  function updateStratTables(stratIdx) {
@@ -148,6 +148,8 @@
148
148
  <th data-col="annual_volatility">Volatility <span class="sort-arrow">&#9650;</span></th>
149
149
  <th data-col="recovery_factor">Recovery <span class="sort-arrow">&#9650;</span></th>
150
150
  <th data-col="total_net_gain_percentage">Net Gain % <span class="sort-arrow">&#9650;</span></th>
151
+ <th data-col="consistency_score">Consistency <span class="sort-arrow">&#9650;</span></th>
152
+ <th data-col="stability_score">Stability <span class="sort-arrow">&#9650;</span></th>
151
153
  <th data-col="var_95">VaR 95% <span class="sort-arrow">&#9650;</span></th>
152
154
  <th data-col="cvar_95">CVaR 95% <span class="sort-arrow">&#9650;</span></th>
153
155
  </tr>