investing-algorithm-framework 3.7.0__py3-none-any.whl → 7.19.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of investing-algorithm-framework might be problematic. Click here for more details.
- investing_algorithm_framework/__init__.py +168 -45
- investing_algorithm_framework/app/__init__.py +32 -1
- investing_algorithm_framework/app/algorithm/__init__.py +7 -0
- investing_algorithm_framework/app/algorithm/algorithm.py +239 -0
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +114 -0
- investing_algorithm_framework/app/analysis/__init__.py +15 -0
- investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
- investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
- investing_algorithm_framework/app/analysis/permutation.py +116 -0
- investing_algorithm_framework/app/analysis/ranking.py +297 -0
- investing_algorithm_framework/app/app.py +1933 -589
- investing_algorithm_framework/app/app_hook.py +28 -0
- investing_algorithm_framework/app/context.py +1725 -0
- investing_algorithm_framework/app/eventloop.py +590 -0
- investing_algorithm_framework/app/reporting/__init__.py +27 -0
- investing_algorithm_framework/app/reporting/ascii.py +921 -0
- investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
- investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
- investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
- investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
- investing_algorithm_framework/app/reporting/generate.py +185 -0
- investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
- investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
- investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
- investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
- investing_algorithm_framework/app/stateless/action_handlers/__init__.py +4 -2
- investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
- investing_algorithm_framework/app/strategy.py +664 -84
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/app/web/__init__.py +2 -1
- investing_algorithm_framework/app/web/create_app.py +4 -2
- investing_algorithm_framework/cli/__init__.py +0 -0
- investing_algorithm_framework/cli/cli.py +226 -0
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
- investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
- investing_algorithm_framework/cli/initialize_app.py +603 -0
- investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
- investing_algorithm_framework/cli/templates/app.py.template +18 -0
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
- investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
- investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
- investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
- investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
- investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
- investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
- investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
- investing_algorithm_framework/cli/templates/env.example.template +2 -0
- investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
- investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
- investing_algorithm_framework/cli/templates/readme.md.template +135 -0
- investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
- investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
- investing_algorithm_framework/create_app.py +40 -6
- investing_algorithm_framework/dependency_container.py +72 -56
- investing_algorithm_framework/domain/__init__.py +71 -47
- investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
- investing_algorithm_framework/domain/config.py +59 -91
- investing_algorithm_framework/domain/constants.py +13 -38
- investing_algorithm_framework/domain/data_provider.py +334 -0
- investing_algorithm_framework/domain/data_structures.py +3 -2
- investing_algorithm_framework/domain/exceptions.py +51 -1
- investing_algorithm_framework/domain/models/__init__.py +17 -12
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +214 -0
- investing_algorithm_framework/domain/models/data/data_type.py +46 -0
- investing_algorithm_framework/domain/models/event.py +35 -0
- investing_algorithm_framework/domain/models/market/market_credential.py +55 -1
- investing_algorithm_framework/domain/models/order/order.py +77 -83
- investing_algorithm_framework/domain/models/order/order_status.py +2 -2
- investing_algorithm_framework/domain/models/order/order_type.py +1 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +81 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +26 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +12 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
- investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
- investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
- investing_algorithm_framework/domain/models/time_frame.py +37 -0
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +66 -2
- investing_algorithm_framework/domain/models/trade/__init__.py +8 -1
- investing_algorithm_framework/domain/models/trade/trade.py +295 -171
- investing_algorithm_framework/domain/models/trade/trade_status.py +9 -2
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
- investing_algorithm_framework/domain/order_executor.py +112 -0
- investing_algorithm_framework/domain/portfolio_provider.py +118 -0
- investing_algorithm_framework/domain/services/__init__.py +2 -9
- investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -6
- investing_algorithm_framework/domain/services/state_handler.py +38 -0
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +12 -7
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/dates.py +57 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +53 -0
- investing_algorithm_framework/domain/utils/random.py +29 -0
- investing_algorithm_framework/download_data.py +108 -0
- investing_algorithm_framework/infrastructure/__init__.py +31 -18
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1143 -0
- investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
- investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
- investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
- investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
- investing_algorithm_framework/infrastructure/models/__init__.py +6 -11
- investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -1
- investing_algorithm_framework/infrastructure/models/order/order.py +35 -49
- investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
- investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
- investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -0
- investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -5
- investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
- investing_algorithm_framework/infrastructure/repositories/__init__.py +8 -0
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +5 -0
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +1 -1
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +81 -27
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +4 -4
- investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
- investing_algorithm_framework/infrastructure/services/aws/state_handler.py +113 -0
- investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
- investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
- investing_algorithm_framework/services/__init__.py +113 -16
- investing_algorithm_framework/services/backtesting/__init__.py +0 -7
- investing_algorithm_framework/services/backtesting/backtest_service.py +566 -359
- investing_algorithm_framework/services/configuration_service.py +77 -11
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
- investing_algorithm_framework/services/market_credential_service.py +16 -1
- investing_algorithm_framework/services/metrics/__init__.py +114 -0
- investing_algorithm_framework/services/metrics/alpha.py +0 -0
- investing_algorithm_framework/services/metrics/beta.py +0 -0
- investing_algorithm_framework/services/metrics/cagr.py +60 -0
- investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
- investing_algorithm_framework/services/metrics/drawdown.py +181 -0
- investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
- investing_algorithm_framework/services/metrics/exposure.py +210 -0
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/services/metrics/mean_daily_return.py +83 -0
- investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
- investing_algorithm_framework/services/metrics/recovery.py +113 -0
- investing_algorithm_framework/services/metrics/returns.py +452 -0
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
- investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
- investing_algorithm_framework/services/metrics/standard_deviation.py +157 -0
- investing_algorithm_framework/services/metrics/trades.py +500 -0
- investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- investing_algorithm_framework/services/metrics/volatility.py +97 -0
- investing_algorithm_framework/services/metrics/win_rate.py +177 -0
- investing_algorithm_framework/services/order_service/__init__.py +3 -1
- investing_algorithm_framework/services/order_service/order_backtest_service.py +76 -89
- investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
- investing_algorithm_framework/services/order_service/order_service.py +407 -326
- investing_algorithm_framework/services/portfolios/__init__.py +3 -1
- investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +37 -3
- investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +22 -8
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
- investing_algorithm_framework/services/portfolios/portfolio_service.py +96 -28
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +97 -28
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +116 -313
- investing_algorithm_framework/services/positions/__init__.py +7 -0
- investing_algorithm_framework/services/positions/position_service.py +210 -0
- investing_algorithm_framework/services/repository_service.py +8 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
- investing_algorithm_framework/services/trade_service/__init__.py +7 -1
- investing_algorithm_framework/services/trade_service/trade_service.py +1013 -315
- investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
- investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
- investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
- investing_algorithm_framework-7.19.15.dist-info/RECORD +263 -0
- investing_algorithm_framework-7.19.15.dist-info/entry_points.txt +3 -0
- investing_algorithm_framework/app/algorithm.py +0 -1105
- investing_algorithm_framework/domain/graphs.py +0 -382
- investing_algorithm_framework/domain/metrics/__init__.py +0 -6
- investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -11
- investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -43
- investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
- investing_algorithm_framework/domain/models/backtesting/backtest_report.py +0 -580
- investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -243
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/services/market_data_sources.py +0 -344
- investing_algorithm_framework/domain/services/market_service.py +0 -153
- investing_algorithm_framework/domain/singleton.py +0 -9
- investing_algorithm_framework/domain/utils/backtesting.py +0 -472
- investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -12
- investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -559
- investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -254
- investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py +0 -47
- investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
- investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -455
- investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
- investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
- investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -350
- investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +0 -53
- investing_algorithm_framework/services/backtesting/graphs.py +0 -61
- investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -8
- investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -150
- investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -189
- investing_algorithm_framework/services/position_service.py +0 -31
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -264
- investing_algorithm_framework-3.7.0.dist-info/METADATA +0 -339
- investing_algorithm_framework-3.7.0.dist-info/RECORD +0 -147
- /investing_algorithm_framework/{domain → services}/metrics/price_efficiency.py +0 -0
- /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
- {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
- {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
from typing import List, Dict
|
|
2
|
-
|
|
3
|
-
from investing_algorithm_framework.domain.exceptions import \
|
|
4
|
-
OperationalException
|
|
5
|
-
from investing_algorithm_framework.domain.models.backtesting\
|
|
6
|
-
.backtest_date_range import BacktestDateRange
|
|
7
|
-
from .backtest_report import BacktestReport
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class BacktestReportsEvaluation:
|
|
11
|
-
"""
|
|
12
|
-
A class to evaluate backtest reports.
|
|
13
|
-
|
|
14
|
-
This class is used to evaluate backtest reports and order them based on
|
|
15
|
-
different metrics. It also groups the reports by backtest date range.
|
|
16
|
-
|
|
17
|
-
The class has methods to get the best algorithm based on profit and growth.
|
|
18
|
-
"""
|
|
19
|
-
report_groupings: Dict[BacktestDateRange, List[BacktestReport]]
|
|
20
|
-
|
|
21
|
-
def __init__(self, backtest_reports: List[BacktestReport]):
|
|
22
|
-
|
|
23
|
-
if backtest_reports is None:
|
|
24
|
-
raise OperationalException("No backtest reports to evaluate")
|
|
25
|
-
|
|
26
|
-
self.backtest_reports = backtest_reports
|
|
27
|
-
self.group_reports(self.backtest_reports)
|
|
28
|
-
self.profit_order = {}
|
|
29
|
-
self.profit_order_grouped_by_date = {}
|
|
30
|
-
self.growth_order = {}
|
|
31
|
-
self.growth_order_grouped_by_date = {}
|
|
32
|
-
self.percentage_positive_trades_order = {}
|
|
33
|
-
self.percentage_positive_trades_order_grouped_by_date = {}
|
|
34
|
-
|
|
35
|
-
# Calculate all metrics and group reports
|
|
36
|
-
for key in self.report_groupings:
|
|
37
|
-
self.profit_order_grouped_by_date[key] = self.order_on_profit(
|
|
38
|
-
self.report_groupings[key].copy()
|
|
39
|
-
)
|
|
40
|
-
self.growth_order_grouped_by_date[key] = self.order_on_growth(
|
|
41
|
-
self.report_groupings[key].copy()
|
|
42
|
-
)
|
|
43
|
-
self.percentage_positive_trades_order_grouped_by_date[key] = \
|
|
44
|
-
self.order_on_positive_trades(
|
|
45
|
-
self.report_groupings[key].copy()
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
# Overall ordered reports
|
|
49
|
-
self.percentage_positive_trades_order = \
|
|
50
|
-
self.order_on_positive_trades(self.backtest_reports)
|
|
51
|
-
self.growth_order = self.order_on_growth(self.backtest_reports)
|
|
52
|
-
self.profit_order = self.order_on_profit(self.backtest_reports)
|
|
53
|
-
|
|
54
|
-
def order_on_profit(self, reports: List[BacktestReport]):
|
|
55
|
-
return sorted(reports, key=lambda x: x.total_net_gain, reverse=True)
|
|
56
|
-
|
|
57
|
-
def order_on_growth(self, reports: List[BacktestReport]):
|
|
58
|
-
return sorted(reports, key=lambda x: x.growth_rate, reverse=True)
|
|
59
|
-
|
|
60
|
-
def order_on_positive_trades(self, reports: List[BacktestReport]):
|
|
61
|
-
return sorted(
|
|
62
|
-
reports, key=lambda x: x.percentage_positive_trades, reverse=True
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
def group_reports(self, reports: List[BacktestReport]):
|
|
66
|
-
"""
|
|
67
|
-
Group reports by backtest start and end date.
|
|
68
|
-
"""
|
|
69
|
-
self.report_groupings = {}
|
|
70
|
-
|
|
71
|
-
for report in reports:
|
|
72
|
-
key = report.backtest_date_range
|
|
73
|
-
if key not in self.report_groupings:
|
|
74
|
-
self.report_groupings[key] = []
|
|
75
|
-
self.report_groupings[key].append(report)
|
|
76
|
-
|
|
77
|
-
def get_date_ranges(self):
|
|
78
|
-
"""
|
|
79
|
-
Get the date ranges of the backtest reports.
|
|
80
|
-
"""
|
|
81
|
-
return list(self.report_groupings.keys())
|
|
82
|
-
|
|
83
|
-
def get_profit_order(
|
|
84
|
-
self, backtest_date_range: BacktestDateRange = None
|
|
85
|
-
) -> List[BacktestReport]:
|
|
86
|
-
"""
|
|
87
|
-
Function to get profit order of all the backtest reports
|
|
88
|
-
in an ordered list.
|
|
89
|
-
|
|
90
|
-
:param backtest_date_range: Tuple with two datetime objects
|
|
91
|
-
:return: List of backtest reports
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
if backtest_date_range is None:
|
|
95
|
-
return self.profit_order
|
|
96
|
-
else:
|
|
97
|
-
|
|
98
|
-
if backtest_date_range in self.profit_order_grouped_by_date:
|
|
99
|
-
return self.profit_order_grouped_by_date[backtest_date_range]
|
|
100
|
-
|
|
101
|
-
raise OperationalException("No matches for given date range")
|
|
102
|
-
|
|
103
|
-
def get_growth_order(
|
|
104
|
-
self, backtest_date_range: BacktestDateRange = None
|
|
105
|
-
) -> List[BacktestReport]:
|
|
106
|
-
"""
|
|
107
|
-
Function to get growth order of all the backtest reports
|
|
108
|
-
in an ordered list.
|
|
109
|
-
|
|
110
|
-
:param backtest_date_range: Tuple with two datetime objects
|
|
111
|
-
:return: List of backtest reports
|
|
112
|
-
"""
|
|
113
|
-
|
|
114
|
-
if backtest_date_range is None:
|
|
115
|
-
return self.growth_order
|
|
116
|
-
else:
|
|
117
|
-
|
|
118
|
-
if backtest_date_range in self.growth_order_grouped_by_date:
|
|
119
|
-
return self.growth_order_grouped_by_date[backtest_date_range]
|
|
120
|
-
|
|
121
|
-
raise OperationalException("No matches for given date range")
|
|
122
|
-
|
|
123
|
-
def get_percentage_positive_trades_order(
|
|
124
|
-
self, backtest_date_range: BacktestDateRange = None
|
|
125
|
-
) -> List[BacktestReport]:
|
|
126
|
-
"""
|
|
127
|
-
Function to get growth order of all the backtest reports
|
|
128
|
-
in an ordered list.
|
|
129
|
-
|
|
130
|
-
:param backtest_date_range: Tuple with two datetime objects
|
|
131
|
-
:return: List of backtest reports
|
|
132
|
-
"""
|
|
133
|
-
|
|
134
|
-
if backtest_date_range is None:
|
|
135
|
-
return self.percentage_positive_trades_order
|
|
136
|
-
else:
|
|
137
|
-
|
|
138
|
-
if backtest_date_range in \
|
|
139
|
-
self.percentage_positive_trades_order_grouped_by_date:
|
|
140
|
-
return self.percentage_positive_trades_order_grouped_by_date[
|
|
141
|
-
backtest_date_range
|
|
142
|
-
]
|
|
143
|
-
|
|
144
|
-
raise OperationalException("No matches for given date range")
|
|
145
|
-
|
|
146
|
-
def rank(
|
|
147
|
-
self,
|
|
148
|
-
weight_profit=0.7,
|
|
149
|
-
weight_growth=0.3,
|
|
150
|
-
backtest_date_range: BacktestDateRange = None
|
|
151
|
-
) -> str:
|
|
152
|
-
"""
|
|
153
|
-
Function to get the best overall algorithm based on the
|
|
154
|
-
weighted sum of profit and growth.
|
|
155
|
-
|
|
156
|
-
:param weight_profit: Weight for profit
|
|
157
|
-
:param weight_growth: Weight for growth
|
|
158
|
-
:return: Name of the best algorithm
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
# Create a dictionary with the algorithm name as key and group
|
|
162
|
-
# the reports by name
|
|
163
|
-
ordered_reports = {}
|
|
164
|
-
|
|
165
|
-
if backtest_date_range is not None:
|
|
166
|
-
reports = self.report_groupings[backtest_date_range]
|
|
167
|
-
else:
|
|
168
|
-
reports = self.backtest_reports
|
|
169
|
-
|
|
170
|
-
for report in reports:
|
|
171
|
-
if report.name not in ordered_reports:
|
|
172
|
-
ordered_reports[report.name] = []
|
|
173
|
-
ordered_reports[report.name].append(report)
|
|
174
|
-
|
|
175
|
-
best_algorithm = None
|
|
176
|
-
best_score = 0
|
|
177
|
-
profit_score = 0
|
|
178
|
-
growth_score = 0
|
|
179
|
-
|
|
180
|
-
for algorithm in ordered_reports:
|
|
181
|
-
profit_score += sum(
|
|
182
|
-
[report.total_net_gain for
|
|
183
|
-
report in ordered_reports[algorithm]]
|
|
184
|
-
)
|
|
185
|
-
growth_score += sum(
|
|
186
|
-
[report.growth for report in
|
|
187
|
-
ordered_reports[algorithm]]
|
|
188
|
-
)
|
|
189
|
-
score = weight_profit * profit_score + weight_growth * growth_score
|
|
190
|
-
|
|
191
|
-
if score > best_score:
|
|
192
|
-
best_score = score
|
|
193
|
-
best_algorithm = algorithm
|
|
194
|
-
|
|
195
|
-
profit_score = 0
|
|
196
|
-
growth_score = 0
|
|
197
|
-
|
|
198
|
-
return best_algorithm
|
|
199
|
-
|
|
200
|
-
def get_reports(
|
|
201
|
-
self, name: str = None, backtest_date_range: BacktestDateRange = None
|
|
202
|
-
) -> List[BacktestReport]:
|
|
203
|
-
"""
|
|
204
|
-
Function to get all the reports for a given algorithm name.
|
|
205
|
-
|
|
206
|
-
:param name: Name of the algorithm
|
|
207
|
-
:param backtest_date_range: Tuple with two datetime objects
|
|
208
|
-
:return: List of backtest reports
|
|
209
|
-
"""
|
|
210
|
-
|
|
211
|
-
if name is not None and backtest_date_range is not None:
|
|
212
|
-
return [
|
|
213
|
-
report for report in self.report_groupings[backtest_date_range]
|
|
214
|
-
if report.name == name
|
|
215
|
-
]
|
|
216
|
-
|
|
217
|
-
if name is not None:
|
|
218
|
-
return [
|
|
219
|
-
report for report in self.backtest_reports
|
|
220
|
-
if report.name == name
|
|
221
|
-
]
|
|
222
|
-
|
|
223
|
-
if backtest_date_range is not None:
|
|
224
|
-
return self.report_groupings[backtest_date_range]
|
|
225
|
-
|
|
226
|
-
def get_report(
|
|
227
|
-
self, name: str, backtest_date_range: BacktestDateRange = None
|
|
228
|
-
):
|
|
229
|
-
"""
|
|
230
|
-
Function to get the report for a given algorithm name and date range.
|
|
231
|
-
|
|
232
|
-
:param name: Name of the algorithm
|
|
233
|
-
:param backtest_date_range: Tuple with two datetime objects
|
|
234
|
-
:return: Backtest report
|
|
235
|
-
"""
|
|
236
|
-
reports = self.get_reports(name, backtest_date_range)
|
|
237
|
-
|
|
238
|
-
if len(reports) == 0:
|
|
239
|
-
raise OperationalException(
|
|
240
|
-
"No matches for given name and date range"
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
return reports[0]
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
from enum import Enum
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class TradingDataType(Enum):
|
|
5
|
-
TICKER = 'TICKER'
|
|
6
|
-
ORDER_BOOK = 'ORDER_BOOK'
|
|
7
|
-
OHLCV = "OHLCV"
|
|
8
|
-
|
|
9
|
-
@staticmethod
|
|
10
|
-
def from_value(value):
|
|
11
|
-
|
|
12
|
-
if isinstance(value, TradingDataType):
|
|
13
|
-
for trading_data_type in TradingDataType:
|
|
14
|
-
|
|
15
|
-
if value == trading_data_type:
|
|
16
|
-
return trading_data_type
|
|
17
|
-
|
|
18
|
-
elif isinstance(value, str):
|
|
19
|
-
return TradingDataType.from_string(value)
|
|
20
|
-
|
|
21
|
-
raise ValueError(
|
|
22
|
-
"Could not convert value to trading data type"
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
@staticmethod
|
|
26
|
-
def from_string(value: str):
|
|
27
|
-
|
|
28
|
-
if isinstance(value, str):
|
|
29
|
-
for order_type in TradingDataType:
|
|
30
|
-
|
|
31
|
-
if value.upper() == order_type.value:
|
|
32
|
-
return order_type
|
|
33
|
-
|
|
34
|
-
raise ValueError(
|
|
35
|
-
"Could not convert value to trading data type"
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
def equals(self, other):
|
|
39
|
-
|
|
40
|
-
if other is None:
|
|
41
|
-
return False
|
|
42
|
-
|
|
43
|
-
if isinstance(other, Enum):
|
|
44
|
-
return self.value == other.value
|
|
45
|
-
|
|
46
|
-
else:
|
|
47
|
-
return TradingDataType.from_string(other) == self
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
from datetime import timedelta, datetime
|
|
2
|
-
from enum import Enum
|
|
3
|
-
|
|
4
|
-
from investing_algorithm_framework.domain.exceptions import \
|
|
5
|
-
OperationalException
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TradingTimeFrame(Enum):
|
|
9
|
-
ONE_MINUTE = "ONE_MINUTE"
|
|
10
|
-
FIFTEEN_MINUTE = "FIFTEEN_MINUTE"
|
|
11
|
-
ONE_HOUR = "ONE_HOUR"
|
|
12
|
-
TWO_HOUR = "TWO_HOUR"
|
|
13
|
-
ONE_DAY = 'ONE_DAY'
|
|
14
|
-
ONE_MONTH = "ONE_MONTH"
|
|
15
|
-
ONE_YEAR = "ONE_YEAR"
|
|
16
|
-
|
|
17
|
-
def create_time_frame_from_limit(self, limit: int = 50):
|
|
18
|
-
|
|
19
|
-
if TradingTimeFrame.ONE_MINUTE.equals(self):
|
|
20
|
-
hold = 1
|
|
21
|
-
start_date = datetime.now() - timedelta(minutes=limit)
|
|
22
|
-
elif TradingTimeFrame.FIFTEEN_MINUTE.equals(self):
|
|
23
|
-
hold = 15
|
|
24
|
-
start_date = datetime.now() - timedelta(minutes=(limit * 15))
|
|
25
|
-
elif TradingTimeFrame.ONE_HOUR.equals(self):
|
|
26
|
-
hold = 60
|
|
27
|
-
start_date = datetime.now() - timedelta(hours=limit)
|
|
28
|
-
elif TradingTimeFrame.TWO_HOUR.equals(self):
|
|
29
|
-
hold = 60 * 2
|
|
30
|
-
start_date = datetime.now() - timedelta(hours=limit)
|
|
31
|
-
elif TradingTimeFrame.ONE_DAY.equals(self):
|
|
32
|
-
hold = 60 * 24
|
|
33
|
-
start_date = datetime.now() - timedelta(days=limit)
|
|
34
|
-
elif TradingTimeFrame.ONE_MONTH.equals(self):
|
|
35
|
-
hold = 60 * 24 * 30
|
|
36
|
-
start_date = datetime.now() - timedelta(weeks=(4 * limit))
|
|
37
|
-
else:
|
|
38
|
-
hold = 60 * 24 * 365
|
|
39
|
-
start_date = datetime.now() - timedelta(days=(limit * 365))
|
|
40
|
-
|
|
41
|
-
iteration = 1
|
|
42
|
-
dates = []
|
|
43
|
-
while iteration < limit or \
|
|
44
|
-
start_date + timedelta(minutes=hold) < datetime.now():
|
|
45
|
-
dates.append(start_date + timedelta(minutes=hold))
|
|
46
|
-
start_date += timedelta(minutes=hold)
|
|
47
|
-
iteration += 1
|
|
48
|
-
|
|
49
|
-
dates.append(datetime.now())
|
|
50
|
-
return dates
|
|
51
|
-
|
|
52
|
-
def create_time_frame_from_start_date(self, start_date: datetime):
|
|
53
|
-
|
|
54
|
-
if start_date > datetime.now():
|
|
55
|
-
raise OperationalException("Start date cannot be in the future")
|
|
56
|
-
|
|
57
|
-
if TradingTimeFrame.ONE_MINUTE.equals(self):
|
|
58
|
-
hold = 1
|
|
59
|
-
elif TradingTimeFrame.FIFTEEN_MINUTE.equals(self):
|
|
60
|
-
hold = 15
|
|
61
|
-
elif TradingTimeFrame.ONE_HOUR.equals(self):
|
|
62
|
-
hold = 60
|
|
63
|
-
elif TradingTimeFrame.TWO_HOUR.equals(self):
|
|
64
|
-
hold = 60 * 2
|
|
65
|
-
elif TradingTimeFrame.ONE_DAY.equals(self):
|
|
66
|
-
hold = 60 * 24
|
|
67
|
-
elif TradingTimeFrame.ONE_MONTH.equals(self):
|
|
68
|
-
hold = 60 * 24 * 30
|
|
69
|
-
else:
|
|
70
|
-
hold = 60 * 24 * 365
|
|
71
|
-
|
|
72
|
-
iteration = 1
|
|
73
|
-
dates = []
|
|
74
|
-
|
|
75
|
-
while start_date < datetime.now():
|
|
76
|
-
dates.append(start_date + timedelta(minutes=hold))
|
|
77
|
-
start_date += timedelta(minutes=hold)
|
|
78
|
-
iteration += 1
|
|
79
|
-
|
|
80
|
-
dates.append(datetime.now())
|
|
81
|
-
return dates
|
|
82
|
-
|
|
83
|
-
def to_ccxt_string(self):
|
|
84
|
-
|
|
85
|
-
if TradingTimeFrame.ONE_MINUTE.equals(self):
|
|
86
|
-
return "1m"
|
|
87
|
-
|
|
88
|
-
if TradingTimeFrame.FIFTEEN_MINUTE.equals(self):
|
|
89
|
-
return "15m"
|
|
90
|
-
|
|
91
|
-
if TradingTimeFrame.ONE_HOUR.equals(self):
|
|
92
|
-
return "1h"
|
|
93
|
-
|
|
94
|
-
if TradingTimeFrame.TWO_HOUR.equals(self):
|
|
95
|
-
return "2h"
|
|
96
|
-
|
|
97
|
-
if TradingTimeFrame.ONE_DAY.equals(self):
|
|
98
|
-
return "1d"
|
|
99
|
-
|
|
100
|
-
if TradingTimeFrame.ONE_MONTH.equals(self):
|
|
101
|
-
return "1m"
|
|
102
|
-
|
|
103
|
-
if TradingTimeFrame.ONE_YEAR.equals(self):
|
|
104
|
-
return "1y"
|
|
105
|
-
|
|
106
|
-
raise OperationalException("Data time unit value is not supported")
|
|
107
|
-
|
|
108
|
-
@staticmethod
|
|
109
|
-
def from_value(value):
|
|
110
|
-
|
|
111
|
-
if isinstance(value, TradingTimeFrame):
|
|
112
|
-
for data_time_unit in TradingTimeFrame:
|
|
113
|
-
|
|
114
|
-
if value == data_time_unit:
|
|
115
|
-
return data_time_unit
|
|
116
|
-
|
|
117
|
-
elif isinstance(value, str):
|
|
118
|
-
return TradingTimeFrame.from_string(value)
|
|
119
|
-
|
|
120
|
-
raise ValueError(
|
|
121
|
-
"Could not convert value to data time unit"
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
@staticmethod
|
|
125
|
-
def from_string(value: str):
|
|
126
|
-
|
|
127
|
-
if isinstance(value, str):
|
|
128
|
-
for data_time_unit in TradingTimeFrame:
|
|
129
|
-
|
|
130
|
-
if value.upper() == data_time_unit.value:
|
|
131
|
-
return data_time_unit
|
|
132
|
-
|
|
133
|
-
raise ValueError(
|
|
134
|
-
"Could not convert value to data time unit"
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
def equals(self, other):
|
|
138
|
-
|
|
139
|
-
if other is None:
|
|
140
|
-
return False
|
|
141
|
-
|
|
142
|
-
if isinstance(other, Enum):
|
|
143
|
-
return self.value == other.value
|
|
144
|
-
|
|
145
|
-
else:
|
|
146
|
-
return TradingTimeFrame.from_string(other) == self
|
|
147
|
-
|
|
148
|
-
def create_start_date(self, limit=50):
|
|
149
|
-
|
|
150
|
-
if TradingTimeFrame.ONE_MINUTE.equals(self):
|
|
151
|
-
return datetime.now() - timedelta(minutes=limit)
|
|
152
|
-
|
|
153
|
-
if TradingTimeFrame.FIFTEEN_MINUTE.equals(self):
|
|
154
|
-
return datetime.now() - timedelta(minutes=(limit * 15))
|
|
155
|
-
|
|
156
|
-
if TradingTimeFrame.ONE_HOUR.equals(self):
|
|
157
|
-
return datetime.now() - timedelta(hours=limit)
|
|
158
|
-
|
|
159
|
-
if TradingTimeFrame.TWO_HOUR.equals(self):
|
|
160
|
-
return datetime.now() - timedelta(hours=limit * 2)
|
|
161
|
-
|
|
162
|
-
if TradingTimeFrame.ONE_DAY.equals(self):
|
|
163
|
-
return datetime.now() - timedelta(days=limit)
|
|
164
|
-
|
|
165
|
-
if TradingTimeFrame.ONE_MONTH.equals(self):
|
|
166
|
-
return datetime.now() - timedelta(weeks=(4 * limit))
|
|
167
|
-
|
|
168
|
-
if TradingTimeFrame.ONE_YEAR.equals(self):
|
|
169
|
-
return datetime.now() - timedelta(days=(limit * 365))
|
|
170
|
-
|
|
171
|
-
raise OperationalException("Data time unit value is not supported")
|
|
172
|
-
|
|
173
|
-
@property
|
|
174
|
-
def minutes(self):
|
|
175
|
-
|
|
176
|
-
if TradingTimeFrame.ONE_MINUTE.equals(self):
|
|
177
|
-
return 1
|
|
178
|
-
|
|
179
|
-
if TradingTimeFrame.FIFTEEN_MINUTE.equals(self):
|
|
180
|
-
return 15
|
|
181
|
-
|
|
182
|
-
if TradingTimeFrame.ONE_HOUR.equals(self):
|
|
183
|
-
return 60
|
|
184
|
-
|
|
185
|
-
if TradingTimeFrame.TWO_HOUR.equals(self):
|
|
186
|
-
return 120
|
|
187
|
-
|
|
188
|
-
if TradingTimeFrame.ONE_DAY.equals(self):
|
|
189
|
-
return 60 * 24
|
|
190
|
-
|
|
191
|
-
if TradingTimeFrame.ONE_MONTH.equals(self):
|
|
192
|
-
return 60 * 24 * 30
|
|
193
|
-
|
|
194
|
-
if TradingTimeFrame.ONE_YEAR.equals(self):
|
|
195
|
-
return 60 * 24 * 365
|
|
196
|
-
|
|
197
|
-
raise OperationalException("Data time frame value is not supported")
|
|
198
|
-
|
|
199
|
-
@property
|
|
200
|
-
def milliseconds(self):
|
|
201
|
-
|
|
202
|
-
if TradingTimeFrame.ONE_MINUTE.equals(self):
|
|
203
|
-
return 60 * 1000
|
|
204
|
-
|
|
205
|
-
if TradingTimeFrame.FIFTEEN_MINUTE.equals(self):
|
|
206
|
-
return 15 * 60 * 1000
|
|
207
|
-
|
|
208
|
-
if TradingTimeFrame.ONE_HOUR.equals(self):
|
|
209
|
-
return 60 * 60 * 1000
|
|
210
|
-
|
|
211
|
-
if TradingTimeFrame.TWO_HOUR.equals(self):
|
|
212
|
-
return 2 * 60 * 60 * 1000
|
|
213
|
-
|
|
214
|
-
if TradingTimeFrame.ONE_DAY.equals(self):
|
|
215
|
-
return 60 * 60 * 24 * 1000
|
|
216
|
-
|
|
217
|
-
if TradingTimeFrame.ONE_MONTH.equals(self):
|
|
218
|
-
return 60 * 60 * 24 * 30 * 1000
|
|
219
|
-
|
|
220
|
-
if TradingTimeFrame.ONE_YEAR.equals(self):
|
|
221
|
-
return 60 * 60 * 24 * 365 * 1000
|
|
222
|
-
|
|
223
|
-
raise OperationalException("Data time frame value is not supported")
|