investing-algorithm-framework 6.7.1__tar.gz → 6.8.1__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 (227) hide show
  1. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/PKG-INFO +1 -1
  2. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/__init__.py +6 -1
  3. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trade/trade.py +6 -0
  4. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +1 -0
  5. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/__init__.py +8 -1
  6. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/cagr.py +5 -8
  7. investing_algorithm_framework-6.8.1/investing_algorithm_framework/metrics/calmar_ratio.py +39 -0
  8. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/drawdown.py +2 -2
  9. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/exposure.py +33 -3
  10. investing_algorithm_framework-6.8.1/investing_algorithm_framework/metrics/mean_daily_return.py +84 -0
  11. investing_algorithm_framework-6.8.1/investing_algorithm_framework/metrics/sharp_ratio.py +87 -0
  12. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/sortino_ratio.py +23 -14
  13. investing_algorithm_framework-6.8.1/investing_algorithm_framework/metrics/standard_deviation.py +159 -0
  14. investing_algorithm_framework-6.8.1/investing_algorithm_framework/metrics/win_rate.py +97 -0
  15. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +1 -3
  16. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/pyproject.toml +1 -1
  17. investing_algorithm_framework-6.7.1/investing_algorithm_framework/metrics/sharp_ratio.py +0 -38
  18. investing_algorithm_framework-6.7.1/investing_algorithm_framework/metrics/standard_deviation.py +0 -92
  19. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/LICENSE +0 -0
  20. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/README.md +0 -0
  21. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/__init__.py +0 -0
  22. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/algorithm/__init__.py +0 -0
  23. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/algorithm/algorithm.py +0 -0
  24. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/algorithm/algorithm_factory.py +0 -0
  25. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/app.py +0 -0
  26. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/app_hook.py +0 -0
  27. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/context.py +0 -0
  28. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
  29. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
  30. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
  31. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
  32. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
  33. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
  34. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/strategy.py +0 -0
  35. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/task.py +0 -0
  36. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/__init__.py +0 -0
  37. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
  38. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
  39. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
  40. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
  41. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/create_app.py +0 -0
  42. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/error_handler.py +0 -0
  43. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/responses.py +0 -0
  44. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
  45. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
  46. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
  47. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
  48. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
  49. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
  50. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/__init__.py +0 -0
  51. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/cli.py +0 -0
  52. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/deploy_to_azure_function.py +0 -0
  53. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/initialize_app.py +0 -0
  54. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/.gitignore.template +0 -0
  55. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/app-web.py.template +0 -0
  56. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/app.py.template +0 -0
  57. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/app_azure_function.py.template +0 -0
  58. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/app_web.py.template +0 -0
  59. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +0 -0
  60. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/azure_function_host.json.template +0 -0
  61. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +0 -0
  62. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/data_providers.py.template +0 -0
  63. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/env.example.template +0 -0
  64. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/env_azure_function.example.template +0 -0
  65. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/market_data_providers.py.template +0 -0
  66. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/readme.md.template +0 -0
  67. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/requirements.txt.template +0 -0
  68. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -0
  69. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/run_backtest.py.template +0 -0
  70. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/cli/templates/strategy.py.template +0 -0
  71. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/create_app.py +0 -0
  72. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/dependency_container.py +0 -0
  73. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/__init__.py +0 -0
  74. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/config.py +0 -0
  75. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/constants.py +0 -0
  76. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/data_provider.py +0 -0
  77. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/data_structures.py +0 -0
  78. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
  79. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/exceptions.py +0 -0
  80. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/__init__.py +0 -0
  81. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/app_mode.py +0 -0
  82. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -0
  83. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -0
  84. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -0
  85. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +0 -0
  86. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
  87. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/base_model.py +0 -0
  88. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/data_source.py +0 -0
  89. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/date_range.py +0 -0
  90. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/event.py +0 -0
  91. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
  92. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
  93. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/market_data_type.py +0 -0
  94. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
  95. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/order/order.py +0 -0
  96. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
  97. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
  98. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
  99. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
  100. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
  101. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +0 -0
  102. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
  103. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
  104. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/position/position.py +0 -0
  105. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
  106. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/snapshot_interval.py +0 -0
  107. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
  108. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
  109. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
  110. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
  111. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
  112. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/tracing/trace.py +0 -0
  113. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trade/__init__.py +0 -0
  114. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -0
  115. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trade/trade_status.py +0 -0
  116. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +0 -0
  117. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trade/trade_take_profit.py +0 -0
  118. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trading_data_types.py +0 -0
  119. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/models/trading_time_frame.py +0 -0
  120. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/order_executor.py +0 -0
  121. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/portfolio_provider.py +0 -0
  122. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/__init__.py +0 -0
  123. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/market_credential_service.py +0 -0
  124. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/market_data_sources.py +0 -0
  125. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/market_service.py +0 -0
  126. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/observable.py +0 -0
  127. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/observer.py +0 -0
  128. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/portfolios/__init__.py +0 -0
  129. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -0
  130. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/rounding_service.py +0 -0
  131. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/services/state_handler.py +0 -0
  132. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
  133. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/strategy.py +0 -0
  134. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
  135. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/backtesting.py +0 -0
  136. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/csv.py +0 -0
  137. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/dates.py +0 -0
  138. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/polars.py +0 -0
  139. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/random.py +0 -0
  140. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
  141. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
  142. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
  143. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/download_data.py +0 -0
  144. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
  145. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/data_providers/__init__.py +0 -0
  146. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/data_providers/ccxt.py +0 -0
  147. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/data_providers/csv.py +0 -0
  148. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
  149. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
  150. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
  151. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
  152. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -0
  153. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -0
  154. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -0
  155. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -0
  156. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
  157. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
  158. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/order/order.py +0 -0
  159. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/order/order_metadata.py +0 -0
  160. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/order_trade_association.py +0 -0
  161. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
  162. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
  163. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +0 -0
  164. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
  165. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
  166. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
  167. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/trades/__init__.py +0 -0
  168. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/trades/trade.py +0 -0
  169. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +0 -0
  170. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +0 -0
  171. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/order_executors/__init__.py +0 -0
  172. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +0 -0
  173. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +0 -0
  174. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +0 -0
  175. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
  176. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +0 -0
  177. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +0 -0
  178. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
  179. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
  180. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
  181. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
  182. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/trade_repository.py +0 -0
  183. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +0 -0
  184. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +0 -0
  185. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
  186. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/azure/__init__.py +0 -0
  187. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/azure/state_handler.py +0 -0
  188. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -0
  189. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -0
  190. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -0
  191. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -0
  192. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -0
  193. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/equity_curve.py +0 -0
  194. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/net_profit.py +0 -0
  195. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/price_efficiency.py +0 -0
  196. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/profit_factor.py +0 -0
  197. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/recovery.py +0 -0
  198. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/risk_free_rate.py +0 -0
  199. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/metrics/volatility.py +0 -0
  200. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/overfitting/__init__.py +0 -0
  201. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/overfitting/permutations.py +0 -0
  202. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/__init__.py +0 -0
  203. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/backtesting/__init__.py +0 -0
  204. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/backtesting/backtest_service.py +0 -0
  205. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/configuration_service.py +0 -0
  206. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/market_credential_service.py +0 -0
  207. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -0
  208. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -0
  209. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -0
  210. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -0
  211. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
  212. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/order_service/order_backtest_service.py +0 -0
  213. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/order_service/order_executor_lookup.py +0 -0
  214. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/order_service/order_service.py +0 -0
  215. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/__init__.py +0 -0
  216. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +0 -0
  217. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +0 -0
  218. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -0
  219. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/portfolio_service.py +0 -0
  220. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -0
  221. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/positions/__init__.py +0 -0
  222. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/positions/position_service.py +0 -0
  223. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/positions/position_snapshot_service.py +0 -0
  224. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/repository_service.py +0 -0
  225. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -0
  226. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/trade_service/__init__.py +0 -0
  227. {investing_algorithm_framework-6.7.1 → investing_algorithm_framework-6.8.1}/investing_algorithm_framework/services/trade_service/trade_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: investing-algorithm-framework
3
- Version: 6.7.1
3
+ Version: 6.8.1
4
4
  Summary: A framework for creating trading bots
5
5
  Author: MDUYN
6
6
  Requires-Python: >=3.10
@@ -31,7 +31,8 @@ from .metrics import get_volatility, get_sortino_ratio, get_profit_factor, \
31
31
  get_drawdown_series, get_max_drawdown, get_cagr, \
32
32
  get_standard_deviation_returns, get_standard_deviation_downside_returns, \
33
33
  get_max_drawdown_absolute, get_exposure_time, get_average_trade_duration, \
34
- get_net_profit
34
+ get_net_profit, get_win_rate, get_win_loss_ratio, get_calmar_ratio, \
35
+ get_trade_frequency
35
36
 
36
37
  __all__ = [
37
38
  "Algorithm",
@@ -120,4 +121,8 @@ __all__ = [
120
121
  "get_exposure_time",
121
122
  "get_average_trade_duration",
122
123
  "get_net_profit",
124
+ "get_win_rate",
125
+ "get_win_loss_ratio",
126
+ "get_calmar_ratio",
127
+ "get_trade_frequency",
123
128
  ]
@@ -148,6 +148,12 @@ class Trade(BaseModel):
148
148
 
149
149
  @property
150
150
  def duration(self):
151
+ """
152
+ Calculate the duration of the trade in hours.
153
+
154
+ Returns:
155
+ float: The duration of the trade in hours.
156
+ """
151
157
  if TradeStatus.CLOSED.equals(self.status):
152
158
  # Get the total hours between the closed and opened datetime
153
159
  diff = self.closed_at - self.opened_at
@@ -53,6 +53,7 @@ class SQLOrderRepository(Repository):
53
53
  query = query.filter_by(id=None)
54
54
 
55
55
  if external_id_query_param:
56
+ print("Filtering by external_id:", external_id_query_param)
56
57
  query = query.filter_by(external_id=external_id_query_param)
57
58
 
58
59
  if side_query_param:
@@ -15,7 +15,10 @@ from .cagr import get_cagr
15
15
  from .standard_deviation import get_standard_deviation_downside_returns, \
16
16
  get_standard_deviation_returns
17
17
  from .net_profit import get_net_profit
18
- from .exposure import get_exposure_time, get_average_trade_duration
18
+ from .exposure import get_exposure_time, get_average_trade_duration, \
19
+ get_trade_frequency
20
+ from .win_rate import get_win_rate, get_win_loss_ratio
21
+ from .calmar_ratio import get_calmar_ratio
19
22
 
20
23
  __all__ = [
21
24
  "get_volatility",
@@ -36,4 +39,8 @@ __all__ = [
36
39
  "get_net_profit",
37
40
  "get_exposure_time",
38
41
  "get_average_trade_duration",
42
+ "get_win_rate",
43
+ "get_win_loss_ratio",
44
+ "get_calmar_ratio",
45
+ "get_trade_frequency",
39
46
  ]
@@ -45,12 +45,12 @@ def get_cagr(report: BacktestReport) -> float:
45
45
 
46
46
  # Convert snapshots to DataFrame
47
47
  data = [(s.total_value, s.created_at) for s in snapshots]
48
- df = pd.DataFrame(data, columns=["net_size", "created_at"])
48
+ df = pd.DataFrame(data, columns=["total_value", "created_at"])
49
49
  df['created_at'] = pd.to_datetime(df['created_at'])
50
50
  df = df.sort_values('created_at')
51
51
 
52
- start_value = df.iloc[0]['net_size']
53
- end_value = df.iloc[-1]['net_size']
52
+ start_value = df.iloc[0]['total_value']
53
+ end_value = df.iloc[-1]['total_value']
54
54
 
55
55
  start_date = df.iloc[0]['created_at']
56
56
  end_date = df.iloc[-1]['created_at']
@@ -60,8 +60,5 @@ def get_cagr(report: BacktestReport) -> float:
60
60
  if num_days == 0 or start_value == 0:
61
61
  return 0.0
62
62
 
63
- # CAGR formula
64
- cagr = (end_value / start_value) ** (365 / num_days) - 1
65
- # Return as percentage
66
- cagr = round(cagr * 100, 2) # Convert to percentage and 2 decimal places
67
- return cagr
63
+ # Apply CAGR formula
64
+ return (end_value / start_value) ** (365 / num_days) - 1
@@ -0,0 +1,39 @@
1
+ """
2
+ | **Calmar Ratio** | **Interpretation** |
3
+ | ---------------- | ----------------------------------------------------------- |
4
+ | **> 3.0** | **Excellent** – strong return vs. drawdown |
5
+ | **2.0 – 3.0** | **Very Good** – solid risk-adjusted performance |
6
+ | **1.0 – 2.0** | **Acceptable** – decent, especially for volatile strategies |
7
+ | **< 1.0** | **Poor** – high drawdowns relative to return |
8
+ """
9
+
10
+
11
+ from investing_algorithm_framework.domain import BacktestReport
12
+ from .cagr import get_cagr
13
+ from .drawdown import get_max_drawdown
14
+
15
+
16
+ def get_calmar_ratio(report: BacktestReport):
17
+ """
18
+ Calculate the Calmar Ratio, which is the ratio of the annualized
19
+ return to the maximum drawdown.
20
+
21
+ Formula:
22
+ Calmar Ratio = CAGR / |Maximum Drawdown|
23
+
24
+ The Calmar Ratio is a measure of risk-adjusted return,
25
+ where a higher ratio indicates a more favorable risk-return profile.
26
+
27
+ Args:
28
+ report: An object that provides methods to get trades and equity curve.
29
+
30
+ Returns:
31
+ float: The Calmar Ratio.
32
+ """
33
+ cagr = get_cagr(report)
34
+ max_drawdown = get_max_drawdown(report)
35
+
36
+ if max_drawdown == 0 or max_drawdown is None:
37
+ return 0.0
38
+
39
+ return cagr / max_drawdown
@@ -79,7 +79,7 @@ def get_max_drawdown(backtest_report: BacktestReport) -> float:
79
79
  drawdown_pct = (equity - peak) / peak # Will be 0 or negative
80
80
  max_drawdown_pct = min(max_drawdown_pct, drawdown_pct)
81
81
 
82
- return max_drawdown_pct * 100.0 # Return as percentage (e.g., -10.0)
82
+ return abs(max_drawdown_pct)
83
83
 
84
84
 
85
85
  def get_max_drawdown_absolute(backtest_report: BacktestReport) -> float:
@@ -110,4 +110,4 @@ def get_max_drawdown_absolute(backtest_report: BacktestReport) -> float:
110
110
  drawdown = peak - equity # Drop from peak
111
111
  max_drawdown = max(max_drawdown, drawdown)
112
112
 
113
- return max_drawdown
113
+ return abs(max_drawdown) # Return as positive number (e.g., €10,000)
@@ -1,3 +1,11 @@
1
+ """
2
+ High exposure (>1) means you’re deploying capital aggressively, possibly with many simultaneous positions.
3
+
4
+ Exposure around 1 means capital is nearly fully invested most of the time, but not overlapping.
5
+
6
+ Low exposure (<1) means capital is mostly idle or only partially invested.
7
+ """
8
+
1
9
  from datetime import timedelta
2
10
  from investing_algorithm_framework.domain import BacktestReport
3
11
 
@@ -18,13 +26,14 @@ def get_exposure_time(report: BacktestReport):
18
26
 
19
27
  total_trade_duration = timedelta(0)
20
28
  for trade in trades:
21
- entry = trade.created_at
29
+ entry = trade.opened_at
22
30
  exit = trade.closed_at or report.backtest_end_date # open trades counted up to end
23
31
 
24
32
  if exit > entry:
25
33
  total_trade_duration += exit - entry
26
34
 
27
35
  backtest_duration = report.backtest_end_date - report.backtest_start_date
36
+
28
37
  if backtest_duration.total_seconds() == 0:
29
38
  return 0.0
30
39
 
@@ -44,7 +53,8 @@ def get_average_trade_duration(report: BacktestReport):
44
53
  if not trades:
45
54
  return 0.0
46
55
 
47
- total_duration = timedelta(0)
56
+ total_duration = 0
57
+
48
58
  for trade in trades:
49
59
  trade_duration = trade.duration
50
60
 
@@ -52,4 +62,24 @@ def get_average_trade_duration(report: BacktestReport):
52
62
  total_duration += trade_duration
53
63
 
54
64
  average_trade_duration = total_duration / len(trades)
55
- return average_trade_duration.total_seconds() / 3600.0 # Convert to hours
65
+ return average_trade_duration
66
+
67
+
68
+ def get_trade_frequency(report: BacktestReport):
69
+ """
70
+ Calculates the trade frequency as the number of trades per day
71
+ during the backtest period.
72
+
73
+ Returns:
74
+ A float representing the average number of trades per day.
75
+ """
76
+ trades = report.get_trades()
77
+
78
+ if not trades:
79
+ return 0.0
80
+
81
+ total_days = (report.backtest_end_date - report.backtest_start_date).days + 1
82
+ if total_days <= 0:
83
+ return 0.0
84
+
85
+ return len(trades) / total_days
@@ -0,0 +1,84 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+
4
+ from .cagr import get_cagr
5
+
6
+
7
+ def get_mean_daily_return(report):
8
+ """
9
+ Calculate the mean daily return from the total value of the snapshots.
10
+
11
+ This function computes the mean daily return based on the list of
12
+ snapshots in the report. If the snapshots have a granularity of less
13
+ than a day, the function will resample to daily frequency and compute
14
+ average daily returns.
15
+
16
+ If there is less data then for a year, it will use cagr to
17
+ calculate the mean daily return.
18
+
19
+ Args:
20
+ report (BacktestReport): The report containing the equity curve.
21
+
22
+ Returns:
23
+ float: The mean daily return.
24
+ """
25
+ snapshots = report.get_snapshots()
26
+
27
+ if len(snapshots) < 2:
28
+ return 0.0 # Not enough data
29
+
30
+ # Create DataFrame from snapshots
31
+ data = [(s.created_at, s.total_value) for s in snapshots]
32
+ df = pd.DataFrame(data, columns=["created_at", "total_value"])
33
+ df['created_at'] = pd.to_datetime(df['created_at'])
34
+ df = df.sort_values('created_at').drop_duplicates('created_at')\
35
+ .set_index('created_at')
36
+
37
+ start_date = df.iloc[0].name
38
+ end_date = df.iloc[-1].name
39
+
40
+ # Check if the period is less than a year
41
+ if (end_date - start_date).days < 365:
42
+ # Use CAGR to calculate mean daily return
43
+ cagr = get_cagr(report)
44
+ if cagr == 0.0:
45
+ return 0.0
46
+ return (1 + cagr) ** (1 / 365) - 1
47
+
48
+ # Resample to daily frequency using last value of the day
49
+ daily_df = df.resample('1D').last().dropna()
50
+
51
+ # Calculate daily returns
52
+ daily_df['return'] = daily_df['total_value'].pct_change()
53
+ daily_df = daily_df.dropna()
54
+
55
+ if daily_df.empty:
56
+ return 0.0
57
+
58
+ mean_return = daily_df['return'].mean()
59
+
60
+ if np.isnan(mean_return):
61
+ return 0.0
62
+
63
+ return mean_return
64
+
65
+
66
+ def get_mean_yearly_return(report, periods_per_year=365):
67
+ """
68
+ Calculate the mean yearly return from a backtest report by
69
+ annualizing the mean daily return.
70
+
71
+ Args:
72
+ report (BacktestReport): The report containing the snapshots.
73
+ periods_per_year (int): Number of periods in a year (e.g., 365 for daily data).
74
+
75
+ Returns:
76
+ float: The mean yearly return (annualized).
77
+ """
78
+ mean_daily_return = get_mean_daily_return(report)
79
+
80
+ if mean_daily_return == 0.0:
81
+ return 0.0
82
+
83
+ return (1 + mean_daily_return) ** periods_per_year - 1
84
+
@@ -0,0 +1,87 @@
1
+ """
2
+ The Sharpe Ratio is a widely used risk-adjusted performance metric. It
3
+ measures the excess return per unit of risk (volatility), where risk is
4
+ represented by the standard deviation of returns.
5
+
6
+ | Sharpe Ratio | Interpretation |
7
+ | -------------- | ------------------------------------------- |
8
+ | **< 0** | Bad: Underperforms risk-free asset |
9
+ | **0.0 – 1.0** | Suboptimal: Returns do not justify risk |
10
+ | **1.0 – 1.99** | Acceptable: Reasonable risk-adjusted return |
11
+ | **2.0 – 2.99** | Good: Strong risk-adjusted performance |
12
+ | **3.0+** | Excellent: Exceptional risk-adjusted return |
13
+
14
+ Sharpe Ratio is highly sensitive to the volatility estimate: Inconsistent sampling frequency, short backtests, or low trade frequency can distort it.
15
+
16
+ Different strategies have different risk profiles:
17
+
18
+ High-frequency strategies may have high Sharpe Ratios (>3).
19
+
20
+ Trend-following strategies might have lower Sharpe (1–2) but strong CAGR and Calmar.
21
+
22
+ Use risk-free rate (~4–5% annual currently) if your backtest spans long periods.
23
+
24
+ ### 📌 Practical Notes about the implementation:
25
+
26
+ - Use **daily returns** for consistent Sharpe Ratio calculation and **annualize** the result using this formula:
27
+
28
+
29
+ Sharpe Ratio Formula:
30
+ Sharpe Ratio = (Mean Daily Return × Periods Per Year - Risk-Free Rate) /
31
+ (Standard Deviation of Daily Returns × sqrt(Periods Per Year))
32
+
33
+ - You can also calculate a **rolling Sharpe Ratio** (e.g., over a 90-day window) to detect changes in performance stability over time.
34
+
35
+ Mean daily return is either based on the real returns from the backtest or the CAGR, depending on the data duration.
36
+
37
+ When do we use actual returns vs CAGR?
38
+
39
+ | Data Duration | Use This Approach | Reason |
40
+ | ------------- | --------------------------------------------------------------- | ----------------------------------------------------------------- |
41
+ | **< 1 year** | Use **CAGR** directly and avoid Sharpe Ratio | Not enough data to estimate volatility robustly |
42
+ | **1–2 years** | Use **CAGR + conservative vol estimate** OR Sharpe with caution | Sharpe may be unstable, consider adding error bars or disclaimers |
43
+ | **> 2 years** | Use **Sharpe Ratio** based on periodic returns | Adequate data to reliably estimate risk-adjusted return |
44
+
45
+ """
46
+
47
+ from typing import Optional
48
+
49
+ import math
50
+
51
+ from investing_algorithm_framework.domain.models import BacktestReport
52
+ from .mean_daily_return import get_mean_daily_return
53
+ from .risk_free_rate import get_risk_free_rate_us
54
+ from .standard_deviation import get_daily_returns_std
55
+
56
+
57
+ def get_sharpe_ratio(
58
+ backtest_report: BacktestReport, risk_free_rate: Optional[float] = None,
59
+ ) -> float:
60
+ """
61
+ Calculate the Sharpe Ratio from a backtest report using daily or
62
+ weekly returns.
63
+
64
+ The Sharpe Ratio is calculated as:
65
+ (Annualized Return - Risk-Free Rate) / Annualized Std Dev of Returns
66
+
67
+ Args:
68
+ backtest_report: Object with get_trades(trade_status=...) and
69
+ `number_of_days` attributes.
70
+ risk_free_rate (float, optional): Annual risk-free rate as a
71
+ decimal (e.g., 0.047 for 4.7%).
72
+
73
+ Returns:
74
+ float: The Sharpe Ratio.
75
+ """
76
+ snapshots = backtest_report.get_snapshots()
77
+ snapshots = sorted(snapshots, key=lambda s: s.created_at)
78
+ mean_daily_return = get_mean_daily_return(backtest_report)
79
+ std_daily_return = get_daily_returns_std(snapshots)
80
+
81
+ if risk_free_rate is None:
82
+ risk_free_rate = get_risk_free_rate_us()
83
+
84
+ # Formula: Sharpe Ratio = (Mean Daily Return × Periods Per Year - Risk-Free Rate) /
85
+ # (Standard Deviation of Daily Returns × sqrt(Periods Per Year))
86
+ return (mean_daily_return * 365 - risk_free_rate) / \
87
+ (std_daily_return * math.sqrt(365))
@@ -11,14 +11,21 @@ symmetrically distributed.
11
11
  | **1 to 2** | ✅ Acceptable/Good — Reasonable performance for most portfolios |
12
12
  | **2 to 3** | 💪 Strong — Very good risk-adjusted returns |
13
13
  | **> 3** | 🌟 Excellent — Rare, may indicate exceptional strategy or overfitting |
14
+
15
+ Formula:
16
+ Sortino Ratio = (Mean Daily Return × Periods Per Year - Risk-Free Rate) /
17
+ (Downside Standard Deviation of Daily Returns × sqrt(Periods Per Year))
18
+
14
19
  """
15
20
 
16
21
  from typing import Optional
17
22
 
23
+ import math
24
+ import numpy as np
18
25
  from investing_algorithm_framework.domain import BacktestReport
19
- from .cagr import get_cagr
26
+ from .mean_daily_return import get_mean_daily_return
20
27
  from .risk_free_rate import get_risk_free_rate_us
21
- from .standard_deviation import get_standard_deviation_downside_returns
28
+ from .standard_deviation import get_downside_std_of_daily_returns
22
29
 
23
30
 
24
31
  def get_sortino_ratio(
@@ -44,22 +51,24 @@ def get_sortino_ratio(
44
51
  Returns:
45
52
  float: The Sortino Ratio.
46
53
  """
47
- annualized_return = get_cagr(report)
54
+ snapshots = report.get_snapshots()
55
+
56
+ if not snapshots:
57
+ return float('inf')
48
58
 
49
- # Convert annualized return to decimal
50
- annualized_return = annualized_return / 100.0
51
- standard_deviation_downside = \
52
- get_standard_deviation_downside_returns(report)
59
+ snapshots = sorted(snapshots, key=lambda s: s.created_at)
60
+ mean_daily_return = get_mean_daily_return(report)
61
+ std_downside_daily_return = get_downside_std_of_daily_returns(snapshots)
53
62
 
54
63
  if risk_free_rate is None:
55
64
  risk_free_rate = get_risk_free_rate_us()
56
65
 
57
- if standard_deviation_downside == 0.0:
58
- print("returning inf because standard deviation downside is 0")
59
- return float("inf")
66
+ # Formula: Sharpe Ratio = (Mean Daily Return × Periods Per Year - Risk-Free Rate) /
67
+ # (Standard Deviation of Daily Returns × sqrt(Periods Per Year))
68
+ ratio = (mean_daily_return * 365 - risk_free_rate) / \
69
+ (std_downside_daily_return * math.sqrt(365))
60
70
 
61
- if annualized_return == 0:
62
- return 0
71
+ if np.float64("inf") == ratio or np.float64("-inf") == ratio:
72
+ return float('inf')
63
73
 
64
- # Calculate sortino ratio
65
- return (annualized_return - risk_free_rate) / standard_deviation_downside
74
+ return ratio if not np.isnan(ratio) else 0.0
@@ -0,0 +1,159 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from investing_algorithm_framework.domain import BacktestReport
4
+
5
+ def get_standard_deviation_downside_returns(report: BacktestReport):
6
+ """
7
+ Calculate the standard deviation of downside returns from the net size
8
+ of the reports.
9
+
10
+ Args:
11
+ report (BacktestReport): The report containing the equity curve.
12
+
13
+ Returns:
14
+ float: The standard deviation of downside returns.
15
+ """
16
+ snapshots = report.get_snapshots()
17
+
18
+ if len(snapshots) < 2:
19
+ return 0.0 # Not enough data
20
+
21
+ # Create DataFrame of net_size over time
22
+ data = [(s.total_value, s.created_at) for s in snapshots]
23
+ df = pd.DataFrame(data, columns=["total_value", "created_at"])
24
+ df['created_at'] = pd.to_datetime(df['created_at'])
25
+ df = df.sort_values('created_at').drop_duplicates('created_at').copy()
26
+
27
+ # Compute percentage returns
28
+ df['return'] = df['total_value'].pct_change()
29
+ df = df.dropna()
30
+
31
+ if df.empty:
32
+ return 0.0
33
+
34
+ # Filter downside returns
35
+ downside_returns = df['return'][df['return'] < 0]
36
+
37
+ if downside_returns.empty:
38
+ return 0.0
39
+
40
+ # Compute standard deviation of downside returns
41
+ downside_std = downside_returns.std(ddof=1) # ddof=1 for sample std dev
42
+
43
+ # Handle edge cases
44
+ if np.isnan(downside_std):
45
+ return 0.0
46
+
47
+ return downside_std
48
+
49
+
50
+ def get_standard_deviation_returns(report: BacktestReport):
51
+ """
52
+ Calculate the standard deviation of returns from the net size
53
+ of the reports.
54
+
55
+ Args:
56
+ report (BacktestReport): The report containing the equity curve.
57
+
58
+ Returns:
59
+ float: The standard deviation of downside returns.
60
+ """
61
+ snapshots = report.get_snapshots()
62
+
63
+ if len(snapshots) < 2:
64
+ return 0.0 # Not enough data
65
+
66
+ # Create DataFrame of net_size over time
67
+ data = [(s.total_value, s.created_at) for s in snapshots]
68
+ df = pd.DataFrame(data, columns=["total_value", "created_at"])
69
+ df['created_at'] = pd.to_datetime(df['created_at'])
70
+ df = df.sort_values('created_at').drop_duplicates('created_at').copy()
71
+
72
+ # Compute percentage returns
73
+ df['return'] = df['total_value'].pct_change()
74
+ df = df.dropna()
75
+
76
+ if df.empty:
77
+ return 0.0
78
+
79
+ # Filter downside returns
80
+ df_returns = df['return']
81
+
82
+ if df_returns.empty:
83
+ return 0.0
84
+
85
+ std = df_returns.std(ddof=1) # ddof=1 for sample std dev
86
+
87
+ # Handle edge cases
88
+ if np.isnan(std):
89
+ return 0.0
90
+
91
+ return std
92
+
93
+ def get_daily_returns_std(snapshots):
94
+ """
95
+ Calculate the standard deviation of daily returns from a list of snapshots.
96
+ Resamples data to daily frequency using end-of-day values.
97
+
98
+ Args:
99
+ snapshots (List[PortfolioSnapshot]): Snapshots with total_value and created_at.
100
+
101
+ Returns:
102
+ float: Standard deviation of daily returns.
103
+ """
104
+ if len(snapshots) < 2:
105
+ return 0.0 # Not enough data
106
+
107
+ # Create DataFrame from snapshots
108
+ data = [(s.created_at, s.total_value) for s in snapshots]
109
+ df = pd.DataFrame(data, columns=["created_at", "total_value"])
110
+ df["created_at"] = pd.to_datetime(df["created_at"])
111
+ df = df.drop_duplicates("created_at").set_index("created_at")
112
+ df = df.sort_index()
113
+
114
+ # Resample to daily frequency (end of day)
115
+ daily_df = df.resample("D").last().dropna()
116
+
117
+ # Calculate daily returns
118
+ daily_df["return"] = daily_df["total_value"].pct_change().dropna()
119
+
120
+ if daily_df["return"].empty:
121
+ return 0.0
122
+
123
+ return daily_df["return"].std()
124
+
125
+
126
+ def get_downside_std_of_daily_returns(snapshots):
127
+ """
128
+ Calculate the downside standard deviation of daily returns from a list of snapshots.
129
+ Resamples data to daily frequency using end-of-day values.
130
+
131
+ Args:
132
+ snapshots (List[PortfolioSnapshot]): Snapshots with total_value and created_at.
133
+
134
+ Returns:
135
+ float: Downside standard deviation of daily returns.
136
+ """
137
+ if len(snapshots) < 2:
138
+ return 0.0 # Not enough data
139
+
140
+ # Create DataFrame from snapshots
141
+ data = [(s.created_at, s.total_value) for s in snapshots]
142
+ df = pd.DataFrame(data, columns=["created_at", "total_value"])
143
+ df["created_at"] = pd.to_datetime(df["created_at"])
144
+ df = df.drop_duplicates("created_at").set_index("created_at")
145
+ df = df.sort_index()
146
+
147
+ # Resample to daily frequency (end of day)
148
+ daily_df = df.resample("D").last().dropna()
149
+
150
+ # Calculate daily returns
151
+ daily_df["return"] = daily_df["total_value"].pct_change().dropna()
152
+
153
+ # Filter only negative returns for downside deviation
154
+ negative_returns = daily_df["return"][daily_df["return"] < 0]
155
+
156
+ if negative_returns.empty:
157
+ return 0.0
158
+
159
+ return negative_returns.std()