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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. investing_algorithm_framework/__init__.py +192 -16
  2. investing_algorithm_framework/analysis/__init__.py +16 -0
  3. investing_algorithm_framework/analysis/backtest_data_ranges.py +202 -0
  4. investing_algorithm_framework/analysis/data.py +170 -0
  5. investing_algorithm_framework/analysis/markdown.py +91 -0
  6. investing_algorithm_framework/analysis/ranking.py +298 -0
  7. investing_algorithm_framework/app/__init__.py +29 -4
  8. investing_algorithm_framework/app/algorithm/__init__.py +7 -0
  9. investing_algorithm_framework/app/algorithm/algorithm.py +193 -0
  10. investing_algorithm_framework/app/algorithm/algorithm_factory.py +118 -0
  11. investing_algorithm_framework/app/app.py +2220 -379
  12. investing_algorithm_framework/app/app_hook.py +28 -0
  13. investing_algorithm_framework/app/context.py +1724 -0
  14. investing_algorithm_framework/app/eventloop.py +620 -0
  15. investing_algorithm_framework/app/reporting/__init__.py +27 -0
  16. investing_algorithm_framework/app/reporting/ascii.py +921 -0
  17. investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
  18. investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
  19. investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
  20. investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
  21. investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
  22. investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
  23. investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
  24. investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
  25. investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
  26. investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
  27. investing_algorithm_framework/app/reporting/generate.py +185 -0
  28. investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
  29. investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
  30. investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
  31. investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
  32. investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
  33. investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
  34. investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
  35. investing_algorithm_framework/app/stateless/action_handlers/__init__.py +6 -3
  36. investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
  37. investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +2 -1
  38. investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
  39. investing_algorithm_framework/app/strategy.py +867 -60
  40. investing_algorithm_framework/app/task.py +5 -3
  41. investing_algorithm_framework/app/web/__init__.py +2 -1
  42. investing_algorithm_framework/app/web/controllers/__init__.py +2 -2
  43. investing_algorithm_framework/app/web/controllers/orders.py +3 -2
  44. investing_algorithm_framework/app/web/controllers/positions.py +2 -2
  45. investing_algorithm_framework/app/web/create_app.py +4 -2
  46. investing_algorithm_framework/app/web/schemas/position.py +1 -0
  47. investing_algorithm_framework/cli/__init__.py +0 -0
  48. investing_algorithm_framework/cli/cli.py +231 -0
  49. investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
  50. investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
  51. investing_algorithm_framework/cli/initialize_app.py +603 -0
  52. investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
  53. investing_algorithm_framework/cli/templates/app.py.template +18 -0
  54. investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
  55. investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
  56. investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
  57. investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
  58. investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
  59. investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
  60. investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
  61. investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
  62. investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
  63. investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
  64. investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
  65. investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
  66. investing_algorithm_framework/cli/templates/env.example.template +2 -0
  67. investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
  68. investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
  69. investing_algorithm_framework/cli/templates/readme.md.template +135 -0
  70. investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
  71. investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
  72. investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
  73. investing_algorithm_framework/cli/validate_backtest_checkpoints.py +197 -0
  74. investing_algorithm_framework/create_app.py +40 -7
  75. investing_algorithm_framework/dependency_container.py +100 -47
  76. investing_algorithm_framework/domain/__init__.py +97 -30
  77. investing_algorithm_framework/domain/algorithm_id.py +69 -0
  78. investing_algorithm_framework/domain/backtesting/__init__.py +25 -0
  79. investing_algorithm_framework/domain/backtesting/backtest.py +548 -0
  80. investing_algorithm_framework/domain/backtesting/backtest_date_range.py +113 -0
  81. investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +241 -0
  82. investing_algorithm_framework/domain/backtesting/backtest_metrics.py +470 -0
  83. investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
  84. investing_algorithm_framework/domain/backtesting/backtest_run.py +663 -0
  85. investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
  86. investing_algorithm_framework/domain/backtesting/backtest_utils.py +198 -0
  87. investing_algorithm_framework/domain/backtesting/combine_backtests.py +392 -0
  88. investing_algorithm_framework/domain/config.py +59 -136
  89. investing_algorithm_framework/domain/constants.py +18 -37
  90. investing_algorithm_framework/domain/data_provider.py +334 -0
  91. investing_algorithm_framework/domain/data_structures.py +42 -0
  92. investing_algorithm_framework/domain/exceptions.py +51 -1
  93. investing_algorithm_framework/domain/models/__init__.py +26 -19
  94. investing_algorithm_framework/domain/models/app_mode.py +34 -0
  95. investing_algorithm_framework/domain/models/data/__init__.py +7 -0
  96. investing_algorithm_framework/domain/models/data/data_source.py +222 -0
  97. investing_algorithm_framework/domain/models/data/data_type.py +46 -0
  98. investing_algorithm_framework/domain/models/event.py +35 -0
  99. investing_algorithm_framework/domain/models/market/__init__.py +5 -0
  100. investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
  101. investing_algorithm_framework/domain/models/order/__init__.py +3 -4
  102. investing_algorithm_framework/domain/models/order/order.py +198 -65
  103. investing_algorithm_framework/domain/models/order/order_status.py +2 -2
  104. investing_algorithm_framework/domain/models/order/order_type.py +1 -3
  105. investing_algorithm_framework/domain/models/portfolio/__init__.py +6 -2
  106. investing_algorithm_framework/domain/models/portfolio/portfolio.py +98 -3
  107. investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -43
  108. investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
  109. investing_algorithm_framework/domain/models/position/__init__.py +2 -1
  110. investing_algorithm_framework/domain/models/position/position.py +20 -0
  111. investing_algorithm_framework/domain/models/position/position_size.py +41 -0
  112. investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -2
  113. investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
  114. investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
  115. investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
  116. investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
  117. investing_algorithm_framework/domain/models/strategy_profile.py +19 -141
  118. investing_algorithm_framework/domain/models/time_frame.py +94 -98
  119. investing_algorithm_framework/domain/models/time_interval.py +33 -0
  120. investing_algorithm_framework/domain/models/time_unit.py +66 -2
  121. investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
  122. investing_algorithm_framework/domain/models/tracing/trace.py +23 -0
  123. investing_algorithm_framework/domain/models/trade/__init__.py +11 -0
  124. investing_algorithm_framework/domain/models/trade/trade.py +389 -0
  125. investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
  126. investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
  127. investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
  128. investing_algorithm_framework/domain/order_executor.py +112 -0
  129. investing_algorithm_framework/domain/portfolio_provider.py +118 -0
  130. investing_algorithm_framework/domain/services/__init__.py +11 -0
  131. investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
  132. investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
  133. investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
  134. investing_algorithm_framework/domain/services/rounding_service.py +27 -0
  135. investing_algorithm_framework/domain/services/state_handler.py +38 -0
  136. investing_algorithm_framework/domain/strategy.py +1 -29
  137. investing_algorithm_framework/domain/utils/__init__.py +15 -5
  138. investing_algorithm_framework/domain/utils/csv.py +22 -0
  139. investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
  140. investing_algorithm_framework/domain/utils/dates.py +57 -0
  141. investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
  142. investing_algorithm_framework/domain/utils/polars.py +53 -0
  143. investing_algorithm_framework/domain/utils/random.py +29 -0
  144. investing_algorithm_framework/download_data.py +244 -0
  145. investing_algorithm_framework/infrastructure/__init__.py +37 -11
  146. investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
  147. investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1152 -0
  148. investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
  149. investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
  150. investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
  151. investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
  152. investing_algorithm_framework/infrastructure/models/__init__.py +7 -3
  153. investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
  154. investing_algorithm_framework/infrastructure/models/order/order.py +53 -53
  155. investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
  156. investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
  157. investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
  158. investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -2
  159. investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -6
  160. investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +3 -1
  161. investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
  162. investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
  163. investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
  164. investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
  165. investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
  166. investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
  167. investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
  168. investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
  169. investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
  170. investing_algorithm_framework/infrastructure/repositories/__init__.py +10 -4
  171. investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
  172. investing_algorithm_framework/infrastructure/repositories/order_repository.py +16 -5
  173. investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
  174. investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
  175. investing_algorithm_framework/infrastructure/repositories/repository.py +84 -30
  176. investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
  177. investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
  178. investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
  179. investing_algorithm_framework/infrastructure/services/__init__.py +9 -4
  180. investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
  181. investing_algorithm_framework/infrastructure/services/aws/state_handler.py +193 -0
  182. investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
  183. investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
  184. investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +9 -0
  185. investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +2596 -0
  186. investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +285 -0
  187. investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +468 -0
  188. investing_algorithm_framework/services/__init__.py +123 -15
  189. investing_algorithm_framework/services/configuration_service.py +77 -11
  190. investing_algorithm_framework/services/data_providers/__init__.py +5 -0
  191. investing_algorithm_framework/services/data_providers/data_provider_service.py +1058 -0
  192. investing_algorithm_framework/services/market_credential_service.py +40 -0
  193. investing_algorithm_framework/services/metrics/__init__.py +119 -0
  194. investing_algorithm_framework/services/metrics/alpha.py +0 -0
  195. investing_algorithm_framework/services/metrics/beta.py +0 -0
  196. investing_algorithm_framework/services/metrics/cagr.py +60 -0
  197. investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
  198. investing_algorithm_framework/services/metrics/drawdown.py +218 -0
  199. investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
  200. investing_algorithm_framework/services/metrics/exposure.py +210 -0
  201. investing_algorithm_framework/services/metrics/generate.py +358 -0
  202. investing_algorithm_framework/services/metrics/mean_daily_return.py +84 -0
  203. investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
  204. investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
  205. investing_algorithm_framework/services/metrics/recovery.py +113 -0
  206. investing_algorithm_framework/services/metrics/returns.py +452 -0
  207. investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
  208. investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
  209. investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
  210. investing_algorithm_framework/services/metrics/standard_deviation.py +156 -0
  211. investing_algorithm_framework/services/metrics/trades.py +473 -0
  212. investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
  213. investing_algorithm_framework/services/metrics/ulcer.py +0 -0
  214. investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
  215. investing_algorithm_framework/services/metrics/volatility.py +118 -0
  216. investing_algorithm_framework/services/metrics/win_rate.py +177 -0
  217. investing_algorithm_framework/services/order_service/__init__.py +9 -0
  218. investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
  219. investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
  220. investing_algorithm_framework/services/order_service/order_service.py +826 -0
  221. investing_algorithm_framework/services/portfolios/__init__.py +16 -0
  222. investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
  223. investing_algorithm_framework/services/{portfolio_configuration_service.py → portfolios/portfolio_configuration_service.py} +27 -12
  224. investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
  225. investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
  226. investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
  227. investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
  228. investing_algorithm_framework/services/positions/__init__.py +7 -0
  229. investing_algorithm_framework/services/positions/position_service.py +210 -0
  230. investing_algorithm_framework/services/repository_service.py +8 -2
  231. investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
  232. investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +117 -0
  233. investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
  234. investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
  235. investing_algorithm_framework/services/trade_service/__init__.py +9 -0
  236. investing_algorithm_framework/services/trade_service/trade_service.py +1099 -0
  237. investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
  238. investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
  239. investing_algorithm_framework-7.25.6.dist-info/METADATA +535 -0
  240. investing_algorithm_framework-7.25.6.dist-info/RECORD +268 -0
  241. {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/WHEEL +1 -2
  242. investing_algorithm_framework-7.25.6.dist-info/entry_points.txt +3 -0
  243. investing_algorithm_framework/app/algorithm.py +0 -630
  244. investing_algorithm_framework/domain/models/backtest_profile.py +0 -414
  245. investing_algorithm_framework/domain/models/market_data/__init__.py +0 -11
  246. investing_algorithm_framework/domain/models/market_data/asset_price.py +0 -50
  247. investing_algorithm_framework/domain/models/market_data/ohlcv.py +0 -105
  248. investing_algorithm_framework/domain/models/market_data/order_book.py +0 -63
  249. investing_algorithm_framework/domain/models/market_data/ticker.py +0 -92
  250. investing_algorithm_framework/domain/models/order/order_fee.py +0 -45
  251. investing_algorithm_framework/domain/models/trade.py +0 -78
  252. investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
  253. investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
  254. investing_algorithm_framework/domain/singleton.py +0 -9
  255. investing_algorithm_framework/domain/utils/backtesting.py +0 -82
  256. investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
  257. investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
  258. investing_algorithm_framework/infrastructure/services/market_backtest_service.py +0 -360
  259. investing_algorithm_framework/infrastructure/services/market_service.py +0 -410
  260. investing_algorithm_framework/infrastructure/services/performance_service.py +0 -192
  261. investing_algorithm_framework/services/backtest_service.py +0 -268
  262. investing_algorithm_framework/services/market_data_service.py +0 -77
  263. investing_algorithm_framework/services/order_backtest_service.py +0 -122
  264. investing_algorithm_framework/services/order_service.py +0 -752
  265. investing_algorithm_framework/services/portfolio_service.py +0 -164
  266. investing_algorithm_framework/services/portfolio_snapshot_service.py +0 -68
  267. investing_algorithm_framework/services/position_cost_service.py +0 -5
  268. investing_algorithm_framework/services/position_service.py +0 -63
  269. investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -225
  270. investing_algorithm_framework-1.5.dist-info/AUTHORS.md +0 -8
  271. investing_algorithm_framework-1.5.dist-info/METADATA +0 -230
  272. investing_algorithm_framework-1.5.dist-info/RECORD +0 -119
  273. investing_algorithm_framework-1.5.dist-info/top_level.txt +0 -1
  274. /investing_algorithm_framework/{infrastructure/services/performance_backtest_service.py → app/reporting/tables/stop_loss_table.py} +0 -0
  275. /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
  276. {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
@@ -1,29 +1,72 @@
1
- from investing_algorithm_framework.app import App, Algorithm
1
+ from .analysis import generate_rolling_backtest_windows, \
2
+ select_backtest_date_ranges, rank_results, create_weights, \
3
+ get_missing_timeseries_data_entries, fill_missing_timeseries_data, \
4
+ create_markdown_table
5
+ from .app import App, Algorithm, \
6
+ TradingStrategy, StatelessAction, Task, AppHook, Context, \
7
+ add_html_report, BacktestReport, \
8
+ pretty_print_trades, pretty_print_positions, \
9
+ pretty_print_orders, pretty_print_backtest, \
10
+ get_equity_curve_with_drawdown_chart, \
11
+ get_rolling_sharpe_ratio_chart, get_monthly_returns_heatmap_chart, \
12
+ get_yearly_returns_bar_chart, get_entry_and_exit_signals, \
13
+ get_ohlcv_data_completeness_chart, get_equity_curve_chart
14
+ from .domain import ApiException, combine_backtests, PositionSize, \
15
+ OrderType, OperationalException, OrderStatus, OrderSide, tqdm, \
16
+ TimeUnit, TimeInterval, Order, Portfolio, Backtest, DataError, \
17
+ Position, TimeFrame, INDEX_DATETIME, MarketCredential, TakeProfitRule, \
18
+ PortfolioConfiguration, RESOURCE_DIRECTORY, AWS_LAMBDA_LOGGING_CONFIG, \
19
+ Trade, APP_MODE, AppMode, DATETIME_FORMAT, load_backtests_from_directory, \
20
+ BacktestDateRange, convert_polars_to_pandas, BacktestRun, \
21
+ DEFAULT_LOGGING_CONFIG, DataType, DataProvider, StopLossRule, \
22
+ TradeStatus, generate_backtest_summary_metrics, generate_algorithm_id, \
23
+ APPLICATION_DIRECTORY, DataSource, OrderExecutor, PortfolioProvider, \
24
+ SnapshotInterval, AWS_S3_STATE_BUCKET_NAME, BacktestEvaluationFocus, \
25
+ save_backtests_to_directory, BacktestMetrics
26
+ from .infrastructure import AzureBlobStorageStateHandler, \
27
+ CSVOHLCVDataProvider, CCXTOHLCVDataProvider, PandasOHLCVDataProvider, \
28
+ AWSS3StorageStateHandler
2
29
  from .create_app import create_app
3
- from investing_algorithm_framework.domain import ApiException, \
4
- TradingDataType, OrderBook, Ticker, TradingTimeFrame, OHLCV, OrderType,\
5
- OrderStatus, OrderSide, Config, TimeUnit, TimeInterval, Order, Portfolio, \
6
- Position, TimeFrame, BACKTESTING_INDEX_DATETIME
7
- from investing_algorithm_framework.domain import PortfolioConfiguration, \
8
- RESOURCE_DIRECTORY, pretty_print_backtest
9
- from investing_algorithm_framework.app import TradingStrategy, \
10
- StatelessAction, Task
30
+ from .download_data import download, download_v2, DownloadResult, \
31
+ create_data_storage_path
32
+ from .services import get_annual_volatility, get_sortino_ratio, \
33
+ get_drawdown_series, get_max_drawdown, get_equity_curve, \
34
+ get_price_efficiency_ratio, get_sharpe_ratio, \
35
+ get_profit_factor, get_cumulative_profit_factor_series, \
36
+ get_rolling_profit_factor_series, get_cagr, \
37
+ get_standard_deviation_returns, get_standard_deviation_downside_returns, \
38
+ get_max_drawdown_absolute, get_total_return, get_exposure_ratio, \
39
+ get_average_trade_duration, get_win_rate, get_win_loss_ratio, \
40
+ get_calmar_ratio, get_trade_frequency, get_yearly_returns, \
41
+ get_monthly_returns, get_best_year, get_best_month, get_worst_year, \
42
+ get_worst_month, get_best_trade, get_worst_trade, \
43
+ get_average_yearly_return, get_average_trade_gain, \
44
+ get_average_trade_loss, get_average_monthly_return, \
45
+ get_percentage_winning_months, get_max_drawdown_duration, \
46
+ get_max_daily_drawdown, get_trades_per_day, \
47
+ get_trades_per_year, get_average_monthly_return_losing_months, \
48
+ get_average_monthly_return_winning_months, get_percentage_winning_years, \
49
+ get_rolling_sharpe_ratio, create_backtest_metrics, get_total_growth, \
50
+ get_total_loss, get_cumulative_exposure, get_median_trade_return, \
51
+ get_average_trade_return, get_risk_free_rate_us, get_cumulative_return, \
52
+ get_cumulative_return_series, get_current_average_trade_return, \
53
+ get_current_average_trade_gain, get_current_average_trade_duration, \
54
+ get_current_average_trade_loss, get_negative_trades, \
55
+ get_positive_trades, get_number_of_trades, get_current_win_rate, \
56
+ get_current_win_loss_ratio, create_backtest_metrics_for_backtest, \
57
+ TradeTakeProfitService, TradeStopLossService
58
+
11
59
 
12
60
  __all__ = [
13
61
  "Algorithm",
14
62
  "RESOURCE_DIRECTORY",
15
63
  "App",
64
+ "AppHook",
16
65
  "create_app",
17
66
  "ApiException",
18
- "TradingDataType",
19
- "OrderBook",
20
- "Ticker",
21
- "TradingTimeFrame",
22
- "OHLCV",
23
67
  "OrderType",
24
68
  "OrderStatus",
25
69
  "OrderSide",
26
- "Config",
27
70
  "PortfolioConfiguration",
28
71
  "TimeUnit",
29
72
  "TimeInterval",
@@ -34,5 +77,138 @@ __all__ = [
34
77
  "StatelessAction",
35
78
  "Task",
36
79
  "pretty_print_backtest",
37
- "BACKTESTING_INDEX_DATETIME"
80
+ "INDEX_DATETIME",
81
+ "Trade",
82
+ "TimeFrame",
83
+ "MarketCredential",
84
+ "OperationalException",
85
+ "APP_MODE",
86
+ "AppMode",
87
+ "DATETIME_FORMAT",
88
+ "Backtest",
89
+ "BacktestDateRange",
90
+ "convert_polars_to_pandas",
91
+ "AzureBlobStorageStateHandler",
92
+ "DEFAULT_LOGGING_CONFIG",
93
+ "BacktestReport",
94
+ "TradeStatus",
95
+ "Context",
96
+ "APPLICATION_DIRECTORY",
97
+ "download",
98
+ "pretty_print_orders",
99
+ "pretty_print_trades",
100
+ "pretty_print_positions",
101
+ "DataSource",
102
+ "OrderExecutor",
103
+ "PortfolioProvider",
104
+ "SnapshotInterval",
105
+ "add_html_report",
106
+ "AWSS3StorageStateHandler",
107
+ "AWS_S3_STATE_BUCKET_NAME",
108
+ "AWS_LAMBDA_LOGGING_CONFIG",
109
+ 'select_backtest_date_ranges',
110
+ 'DataType',
111
+ 'CSVOHLCVDataProvider',
112
+ "CCXTOHLCVDataProvider",
113
+ "DataProvider",
114
+ "get_annual_volatility",
115
+ "get_sortino_ratio",
116
+ "get_drawdown_series",
117
+ "get_max_drawdown",
118
+ "get_equity_curve",
119
+ "get_price_efficiency_ratio",
120
+ "get_sharpe_ratio",
121
+ "get_profit_factor",
122
+ "get_cumulative_profit_factor_series",
123
+ "get_rolling_profit_factor_series",
124
+ "get_sharpe_ratio",
125
+ "get_cagr",
126
+ "get_standard_deviation_returns",
127
+ "get_standard_deviation_downside_returns",
128
+ "get_max_drawdown_absolute",
129
+ "get_total_return",
130
+ "get_exposure_ratio",
131
+ "get_cumulative_exposure",
132
+ "get_average_trade_duration",
133
+ "get_win_rate",
134
+ "get_win_loss_ratio",
135
+ "get_calmar_ratio",
136
+ "get_trade_frequency",
137
+ "get_yearly_returns",
138
+ "get_monthly_returns",
139
+ "get_best_year",
140
+ "get_best_month",
141
+ "get_worst_year",
142
+ "get_worst_month",
143
+ "get_best_trade",
144
+ "get_worst_trade",
145
+ "get_average_yearly_return",
146
+ "get_average_trade_gain",
147
+ "get_average_trade_loss",
148
+ "get_average_monthly_return",
149
+ "get_percentage_winning_months",
150
+ "get_average_trade_duration",
151
+ "get_trade_frequency",
152
+ "get_win_rate",
153
+ "get_win_loss_ratio",
154
+ "get_calmar_ratio",
155
+ "get_max_drawdown_absolute",
156
+ "get_max_drawdown_duration",
157
+ "get_max_daily_drawdown",
158
+ "get_trades_per_day",
159
+ "get_trades_per_year",
160
+ "get_average_monthly_return_losing_months",
161
+ "get_average_monthly_return_winning_months",
162
+ "get_percentage_winning_years",
163
+ "get_rolling_sharpe_ratio",
164
+ "create_backtest_metrics",
165
+ "PandasOHLCVDataProvider",
166
+ "get_equity_curve_with_drawdown_chart",
167
+ "get_rolling_sharpe_ratio_chart",
168
+ "get_monthly_returns_heatmap_chart",
169
+ "get_yearly_returns_bar_chart",
170
+ "get_ohlcv_data_completeness_chart",
171
+ "rank_results",
172
+ "create_weights",
173
+ "get_entry_and_exit_signals",
174
+ "BacktestEvaluationFocus",
175
+ "combine_backtests",
176
+ "PositionSize",
177
+ "get_median_trade_return",
178
+ "get_average_trade_return",
179
+ "get_risk_free_rate_us",
180
+ "get_cumulative_return",
181
+ "get_cumulative_return_series",
182
+ "get_total_loss",
183
+ "get_total_growth",
184
+ "generate_backtest_summary_metrics",
185
+ "get_equity_curve_chart",
186
+ "get_current_win_rate",
187
+ "get_current_win_loss_ratio",
188
+ "get_current_average_trade_loss",
189
+ "get_current_average_trade_duration",
190
+ "get_current_average_trade_gain",
191
+ "get_current_average_trade_return",
192
+ "get_negative_trades",
193
+ "get_positive_trades",
194
+ "get_number_of_trades",
195
+ "BacktestRun",
196
+ "load_backtests_from_directory",
197
+ "save_backtests_to_directory",
198
+ "DataError",
199
+ "create_backtest_metrics_for_backtest",
200
+ "TakeProfitRule",
201
+ "StopLossRule",
202
+ "TradeStopLossService",
203
+ "TradeTakeProfitService",
204
+ "generate_algorithm_id",
205
+ "BacktestMetrics",
206
+ "generate_rolling_backtest_windows",
207
+ "tqdm",
208
+ "get_missing_timeseries_data_entries",
209
+ "fill_missing_timeseries_data",
210
+ "create_markdown_table",
211
+ "download_v2",
212
+ "DownloadResult",
213
+ "create_data_storage_path"
38
214
  ]
@@ -0,0 +1,16 @@
1
+ from .markdown import create_markdown_table
2
+ from .backtest_data_ranges import select_backtest_date_ranges, \
3
+ generate_rolling_backtest_windows
4
+ from .ranking import create_weights, rank_results
5
+ from .data import fill_missing_timeseries_data, \
6
+ get_missing_timeseries_data_entries
7
+
8
+ __all__ = [
9
+ "create_markdown_table",
10
+ "select_backtest_date_ranges",
11
+ "generate_rolling_backtest_windows",
12
+ "create_weights",
13
+ "rank_results",
14
+ "fill_missing_timeseries_data",
15
+ "get_missing_timeseries_data_entries",
16
+ ]
@@ -0,0 +1,202 @@
1
+ import pandas as pd
2
+ from logging import getLogger
3
+ from datetime import datetime
4
+ from typing import List, Dict, Union
5
+ from datetime import timezone
6
+
7
+ from investing_algorithm_framework.domain import BacktestDateRange, \
8
+ OperationalException
9
+
10
+ logger = getLogger(__name__)
11
+
12
+
13
+ def select_backtest_date_ranges(
14
+ df: pd.DataFrame, window: Union[str, int] = '365D'
15
+ ) -> List[BacktestDateRange]:
16
+ """
17
+ Identifies the best upturn, worst downturn, and sideways periods
18
+ for the given window duration. This allows you to quickly select
19
+ interesting periods for backtesting.
20
+
21
+ Args:
22
+ df (pd.DataFrame): DataFrame with a DateTime index
23
+ and 'Close' column.
24
+ window (Union[str, int]): Duration of the window
25
+ to analyze. Can be a string like '365D' or an
26
+ integer representing days.
27
+
28
+ Returns:
29
+ List[BacktestDateRange]: List of BacktestDateRange
30
+ objects representing the best upturn, worst
31
+ downturn, and most sideways periods.
32
+ """
33
+ df = df.copy()
34
+ df = df.sort_index()
35
+
36
+ if isinstance(window, int):
37
+ window = pd.Timedelta(days=window)
38
+ elif isinstance(window, str):
39
+ window = pd.to_timedelta(window)
40
+ else:
41
+ raise OperationalException("window must be a string or integer")
42
+
43
+ # Check if the window is larger than the DataFrame
44
+ if len(df) == 0:
45
+ raise OperationalException("DataFrame is empty")
46
+
47
+ if df.index[-1] - df.index[0] < window:
48
+ raise OperationalException(
49
+ "Window duration is larger than the data duration"
50
+ )
51
+
52
+ if len(df) < 2 or df.index[-1] - df.index[0] < window:
53
+ raise OperationalException(
54
+ "DataFrame must contain at least two rows and span "
55
+ "the full window duration"
56
+ )
57
+
58
+ best_upturn = {
59
+ "name": "UpTurn", "return": float('-inf'), "start": None, "end": None
60
+ }
61
+ worst_downturn = {
62
+ "name": "DownTurn", "return": float('inf'), "start": None, "end": None
63
+ }
64
+ most_sideways = {
65
+ "name": "SideWays",
66
+ "volatility": float('inf'),
67
+ "return": None,
68
+ "start": None,
69
+ "end": None
70
+ }
71
+
72
+ for i in range(len(df)):
73
+ start_time = df.index[i]
74
+ end_time = start_time + window
75
+ window_df = df[(df.index >= start_time) & (df.index <= end_time)]
76
+
77
+ if len(window_df) < 2 or (window_df.index[-1] - start_time) < window:
78
+ continue
79
+
80
+ start_price = window_df['Close'].iloc[0]
81
+ end_price = window_df['Close'].iloc[-1]
82
+ ret = (end_price / start_price) - 1 # relative return
83
+ volatility = window_df['Close'].std()
84
+
85
+ # Ensure datetime for BacktestDateRange and with timezone utc
86
+ start_time = pd.Timestamp(start_time).to_pydatetime()
87
+ start_time = start_time.replace(tzinfo=timezone.utc)
88
+ end_time = pd.Timestamp(window_df.index[-1]).to_pydatetime()
89
+ end_time = end_time.replace(tzinfo=timezone.utc)
90
+
91
+ if ret > best_upturn["return"]:
92
+ best_upturn.update(
93
+ {"return": ret, "start": start_time, "end": end_time}
94
+ )
95
+
96
+ if ret < worst_downturn["return"]:
97
+ worst_downturn.update(
98
+ {"return": ret, "start": start_time, "end": end_time}
99
+ )
100
+
101
+ if volatility < most_sideways["volatility"]:
102
+ most_sideways.update({
103
+ "return": ret,
104
+ "volatility": volatility,
105
+ "start": start_time,
106
+ "end": end_time
107
+ })
108
+
109
+ return [
110
+ BacktestDateRange(
111
+ start_date=best_upturn['start'],
112
+ end_date=best_upturn['end'],
113
+ name=best_upturn['name']
114
+ ),
115
+ BacktestDateRange(
116
+ start_date=worst_downturn['start'],
117
+ end_date=worst_downturn['end'],
118
+ name=worst_downturn['name']
119
+ ),
120
+ BacktestDateRange(
121
+ start_date=most_sideways['start'],
122
+ end_date=most_sideways['end'],
123
+ name=most_sideways['name']
124
+ )
125
+ ]
126
+
127
+
128
+ def generate_rolling_backtest_windows(
129
+ start_date: datetime,
130
+ end_date: datetime,
131
+ train_days: int = 365,
132
+ test_days: int = 90,
133
+ step_days: int = 90,
134
+ gap_days: int = 0,
135
+ ) -> List[Dict[str, BacktestDateRange]]:
136
+ """
137
+ Generate rolling windows for walk-forward backtesting.
138
+
139
+ This function creates training and testing date ranges for
140
+ time-series backtesting, avoiding look-ahead bias and providing
141
+ realistic out-of-sample performance estimates.
142
+
143
+ Args:
144
+ start_date (datetime): The starting date for the first
145
+ training window.
146
+ end_date (datetime): The ending date for the last
147
+ testing window.
148
+ train_days (int): Number of days in the training window.
149
+ test_days (int): Number of days in the testing window.
150
+ step_days (int): Number of days to step forward for the next window.
151
+ gap_days (int): Number of days to skip between train and test windows.
152
+ Useful to avoid look-ahead bias in indicators
153
+ with lag (e.g., 26 for MACD). Default is 0 (no gap).
154
+
155
+ Returns:
156
+ List[Dict[str, BacktestDateRange]]: A list of dictionaries containing:
157
+ - "train_range": BacktestDateRange for training period
158
+ - "test_range": BacktestDateRange for testing period
159
+
160
+ Example:
161
+ >>> windows = generate_rolling_backtest_windows(
162
+ ... start_date=datetime(2021, 1, 1, tzinfo=timezone.utc),
163
+ ... end_date=datetime(2024, 12, 31, tzinfo=timezone.utc),
164
+ ... train_days=365,
165
+ ... test_days=90,
166
+ ... step_days=90,
167
+ ... gap_days=30
168
+ ... )
169
+ """
170
+ windows = []
171
+ current_start = start_date
172
+ max_iterations = 10000 # Safety limit to prevent infinite loops
173
+ iteration = 0
174
+
175
+ while iteration < max_iterations:
176
+ iteration += 1
177
+ train_start = current_start
178
+ train_end = train_start + pd.Timedelta(days=train_days)
179
+ test_start = train_end + pd.Timedelta(days=gap_days)
180
+ test_end = test_start + pd.Timedelta(days=test_days)
181
+
182
+ if test_end > end_date:
183
+ break
184
+
185
+ train_backtest_date_range = BacktestDateRange(
186
+ name=f"train_window_{iteration}",
187
+ start_date=train_start,
188
+ end_date=train_end
189
+ )
190
+ test_backtest_date_range = BacktestDateRange(
191
+ name=f"test_window_{iteration}",
192
+ start_date=test_start,
193
+ end_date=test_end
194
+ )
195
+ windows.append({
196
+ "train_range": train_backtest_date_range,
197
+ "test_range": test_backtest_date_range,
198
+ })
199
+
200
+ current_start += pd.Timedelta(days=step_days)
201
+
202
+ return windows
@@ -0,0 +1,170 @@
1
+ import pandas as pd
2
+ import polars as pl
3
+ from typing import Union
4
+
5
+
6
+ def fill_missing_timeseries_data(
7
+ data: Union[pd.DataFrame, pl.DataFrame, str],
8
+ missing_dates: list = None,
9
+ start_date=None,
10
+ end_date=None,
11
+ save_to_file: bool = False,
12
+ file_path: str = None
13
+ ) -> Union[pd.DataFrame, pl.DataFrame]:
14
+ """
15
+ Fill missing dates in time-series data using a hybrid approach:
16
+ forward-fill by default, backward-fill only when missing dates
17
+ are at the start of the data.
18
+
19
+ This function handles missing rows (dates) in time-series data,
20
+ not just missing values within existing rows. All columns are
21
+ duplicated from the adjacent row.
22
+
23
+ Args:
24
+ data (pd.DataFrame | pl.DataFrame | str): Time-series data as a
25
+ DataFrame or path to a CSV file. Index should be datetime.
26
+ missing_dates (list, optional): List of datetime objects representing
27
+ specific missing dates to fill. If None and start_date/end_date
28
+ are provided, missing dates will be auto-detected.
29
+ start_date (datetime, optional): Start date to check for missing dates.
30
+ end_date (datetime, optional): End date to check for missing dates.
31
+ save_to_file (bool): If True, save the result back to the CSV file.
32
+ file_path (str, optional): Path to save/load the CSV file.
33
+
34
+ Returns:
35
+ pd.DataFrame | pl.DataFrame: DataFrame with missing dates filled.
36
+ """
37
+ is_polars = False
38
+
39
+ # Load data if file path is provided
40
+ if isinstance(data, str):
41
+ file_path = data
42
+ df = pd.read_csv(file_path, index_col=0, parse_dates=True)
43
+ elif isinstance(data, pl.DataFrame):
44
+ is_polars = True
45
+ # Convert polars to pandas for processing
46
+ df = data.to_pandas()
47
+ if 'Datetime' in df.columns:
48
+ df = df.set_index('Datetime')
49
+ df.index = pd.to_datetime(df.index)
50
+ else:
51
+ df = data.copy()
52
+
53
+ # Store the index name
54
+ index_name = df.index.name if df.index.name else 'Datetime'
55
+
56
+ rows_to_add = []
57
+
58
+ # Determine which dates need to be filled
59
+ if missing_dates is not None and len(missing_dates) > 0:
60
+ # Convert index to set of timestamps for proper comparison
61
+ existing_timestamps = set(pd.to_datetime(df.index))
62
+ # Deduplicate missing_dates and filter out existing dates
63
+ seen = set()
64
+ dates_to_fill = []
65
+ for d in missing_dates:
66
+ dt = pd.to_datetime(d)
67
+ if dt not in existing_timestamps and dt not in seen:
68
+ dates_to_fill.append(d)
69
+ seen.add(dt)
70
+ elif start_date is not None and end_date is not None:
71
+ dates_to_fill = get_missing_timeseries_data_entries(
72
+ df, start=start_date, end=end_date, freq='D'
73
+ )
74
+ else:
75
+ dates_to_fill = []
76
+
77
+ # Fill missing dates
78
+ for missing_timestamp in dates_to_fill:
79
+ # Find the index position where this timestamp should be inserted
80
+ position = df[df.index < missing_timestamp].shape[0]
81
+
82
+ # Edge case: missing timestamp is BEFORE all existing data
83
+ if position == 0:
84
+ # Use the FIRST row (backward fill)
85
+ if len(df) > 0:
86
+ next_row = df.iloc[0]
87
+ new_row = next_row.to_dict()
88
+ else:
89
+ continue # No data to fill from
90
+ else:
91
+ # Normal case: use previous row (forward fill)
92
+ prev_row = df.iloc[position - 1]
93
+ new_row = prev_row.to_dict()
94
+
95
+ rows_to_add.append({index_name: missing_timestamp, **new_row})
96
+
97
+ # Add new rows if any
98
+ if rows_to_add:
99
+ new_df = pd.DataFrame(rows_to_add).set_index(index_name)
100
+ df = pd.concat([df, new_df]).sort_index()
101
+
102
+ # Save to file if requested
103
+ if save_to_file and file_path:
104
+ df.to_csv(file_path)
105
+
106
+ # Convert back to polars if input was polars
107
+ if is_polars:
108
+ df = df.reset_index()
109
+ return pl.from_pandas(df)
110
+
111
+ return df
112
+
113
+
114
+ def get_missing_timeseries_data_entries(
115
+ data: Union[pd.DataFrame, pl.DataFrame, str],
116
+ start=None,
117
+ end=None,
118
+ freq: str = None
119
+ ):
120
+ """
121
+ Identify missing timestamps in a time series.
122
+
123
+ Args:
124
+ data (pd.DataFrame | pl.DataFrame | str): Time-series data as a
125
+ DataFrame or path to a CSV file. Index should be datetime.
126
+ start (datetime, optional): The start datetime for the expected range.
127
+ If None, uses the first timestamp in the data.
128
+ end (datetime, optional): The end datetime for the expected range.
129
+ If None, uses the last timestamp in the data.
130
+ freq (str, optional): Frequency string (e.g., 'D' for daily, 'H' for
131
+ hourly). If None, will be inferred from the data.
132
+
133
+ Returns:
134
+ list: A list of missing timestamps within the specified range.
135
+ """
136
+ # Load data if file path is provided
137
+ if isinstance(data, str):
138
+ df = pd.read_csv(data, index_col=0, parse_dates=True)
139
+ elif isinstance(data, pl.DataFrame):
140
+ df = data.to_pandas()
141
+ if 'Datetime' in df.columns:
142
+ df = df.set_index('Datetime')
143
+ df.index = pd.to_datetime(df.index)
144
+ else:
145
+ df = data
146
+
147
+ # Get existing timestamps from the index
148
+ existing_timestamps = pd.to_datetime(df.index)
149
+
150
+ # Use data bounds if start/end not provided
151
+ if start is None:
152
+ start = existing_timestamps.min()
153
+ if end is None:
154
+ end = existing_timestamps.max()
155
+
156
+ # Infer frequency if not provided
157
+ if freq is None:
158
+ freq = df.index.inferred_freq
159
+ if freq is None and len(df) >= 2:
160
+ diff = df.index[1] - df.index[0]
161
+ freq = diff
162
+ elif freq is None:
163
+ freq = 'D' # Default to daily
164
+
165
+ expected_timestamps = pd.date_range(start=start, end=end, freq=freq)
166
+
167
+ # Find missing by checking which expected timestamps are not in existing
168
+ missing_mask = ~expected_timestamps.isin(existing_timestamps)
169
+ missing_timestamps = expected_timestamps[missing_mask].tolist()
170
+ return missing_timestamps