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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from investing_algorithm_framework.domain import Order
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OrderExecutor(ABC):
|
|
7
|
+
"""
|
|
8
|
+
Abstract base class for order executors. The OrderExecutor class is
|
|
9
|
+
responsible for executing orders in a trading algorithm.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
_priority (int): The priority of the order executor compared to
|
|
13
|
+
other order executors. The lower the number, the higher the
|
|
14
|
+
priority. The framework will use this priority when searching
|
|
15
|
+
for an order executor for a specific market.
|
|
16
|
+
_config (dict): Reference to the application configuration.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, priority=1):
|
|
20
|
+
self._priority = priority
|
|
21
|
+
self._config = None
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def priority(self):
|
|
25
|
+
"""
|
|
26
|
+
Returns the priority of the order executor.
|
|
27
|
+
"""
|
|
28
|
+
return self._priority
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def config(self):
|
|
32
|
+
"""
|
|
33
|
+
Returns the configuration of the order executor.
|
|
34
|
+
This can be used to store any configuration that is needed
|
|
35
|
+
for the order executor.
|
|
36
|
+
"""
|
|
37
|
+
return self._config
|
|
38
|
+
|
|
39
|
+
@config.setter
|
|
40
|
+
def config(self, config):
|
|
41
|
+
"""
|
|
42
|
+
Setter for the app config. This will be used to set a reference
|
|
43
|
+
to the config of the Application when the app is started.
|
|
44
|
+
"""
|
|
45
|
+
self._config = config
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def execute_order(self, portfolio, order, market_credential) -> Order:
|
|
49
|
+
"""
|
|
50
|
+
Executes an order for a given portfolio. The order executor should
|
|
51
|
+
create an order on the exchange or broker and return an order object
|
|
52
|
+
that reflects the order on the exchange or broker. This should be
|
|
53
|
+
done by setting the external_id of the order to the id of the order
|
|
54
|
+
on the exchange or broker.
|
|
55
|
+
|
|
56
|
+
!Important: This function should not throw an exception if the order
|
|
57
|
+
is not successfully executed. Instead, it should return an order
|
|
58
|
+
instance with the status set to OrderStatus.FAILED.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
order: The order to be executed
|
|
62
|
+
portfolio: The portfolio in which the order will be executed
|
|
63
|
+
market_credential: The market credential to use for the order
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Order: Instance of the executed order. The order instance
|
|
67
|
+
should copy the id of the order that has been provided as a
|
|
68
|
+
"""
|
|
69
|
+
raise NotImplementedError(
|
|
70
|
+
"Subclasses must implement this method."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
@abstractmethod
|
|
74
|
+
def cancel_order(self, portfolio, order, market_credential) -> Order:
|
|
75
|
+
"""
|
|
76
|
+
Cancels an order for a given portfolio. The order executor should
|
|
77
|
+
cancel the order on the exchange or broker and return an order
|
|
78
|
+
object that reflects the order on the exchange or broker.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
order: The order to be canceled
|
|
82
|
+
portfolio: The portfolio in which the order was executed
|
|
83
|
+
market_credential: The market credential to use for the order
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Order: Instance of the canceled order.
|
|
87
|
+
"""
|
|
88
|
+
raise NotImplementedError(
|
|
89
|
+
"Subclasses must implement this method."
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
@abstractmethod
|
|
93
|
+
def supports_market(self, market):
|
|
94
|
+
"""
|
|
95
|
+
Checks if the order executor supports the given market.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
market: The market to check
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
bool: True if the order executor supports the market, False
|
|
102
|
+
otherwise.
|
|
103
|
+
"""
|
|
104
|
+
raise NotImplementedError(
|
|
105
|
+
"Subclasses must implement this method."
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
def __repr__(self):
|
|
109
|
+
"""
|
|
110
|
+
Returns a string representation of the order executor.
|
|
111
|
+
"""
|
|
112
|
+
return f"{self.__class__.__name__}(priority={self._priority})"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
from investing_algorithm_framework.domain import Order, Position
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PortfolioProvider(ABC):
|
|
8
|
+
"""
|
|
9
|
+
Abstract base class for portfolio providers. The PortfolioProvider class
|
|
10
|
+
is responsible for managing and providing access to trading portfolios.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
_priority (int): The priority of the portfolio provider compared to
|
|
14
|
+
other portfolio providers. The lower the number, the higher the
|
|
15
|
+
priority. The framework will use this priority when searching
|
|
16
|
+
for a portfolio provider for a specific symbol or market.
|
|
17
|
+
_config (dict): Reference to the application configuration.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, priority=1):
|
|
21
|
+
self._priority = priority
|
|
22
|
+
self._config = None
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def priority(self):
|
|
26
|
+
"""
|
|
27
|
+
Returns the priority of the portfolio provider.
|
|
28
|
+
"""
|
|
29
|
+
return self._priority
|
|
30
|
+
|
|
31
|
+
@priority.setter
|
|
32
|
+
def priority(self, value: int):
|
|
33
|
+
"""
|
|
34
|
+
Sets the priority of the portfolio provider.
|
|
35
|
+
"""
|
|
36
|
+
self._priority = value
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def config(self):
|
|
40
|
+
"""
|
|
41
|
+
Returns the configuration of the order executor.
|
|
42
|
+
This can be used to store any configuration that is needed
|
|
43
|
+
for the order executor.
|
|
44
|
+
"""
|
|
45
|
+
return self._config
|
|
46
|
+
|
|
47
|
+
@config.setter
|
|
48
|
+
def config(self, config):
|
|
49
|
+
"""
|
|
50
|
+
Setter for the app config. This will be used to set a reference
|
|
51
|
+
to the config of the Application when the app is started.
|
|
52
|
+
"""
|
|
53
|
+
self._config = config
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def get_order(
|
|
57
|
+
self, portfolio, order, market_credential
|
|
58
|
+
) -> Union[Order, None]:
|
|
59
|
+
"""
|
|
60
|
+
Function to get an order from the exchange or broker. The returned
|
|
61
|
+
should be an order object that reflects the current state of the
|
|
62
|
+
order on the exchange or broker.
|
|
63
|
+
|
|
64
|
+
!IMPORTANT: This function should return None if the order is
|
|
65
|
+
not found or if the order is not available on the
|
|
66
|
+
exchange or broker. Please do not throw an exception if the
|
|
67
|
+
order is not found.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
portfolio: Portfolio object
|
|
71
|
+
order: Order object from the database
|
|
72
|
+
market_credential: Market credential object
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Order: Order object reflecting the order on the exchange or broker
|
|
76
|
+
"""
|
|
77
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
78
|
+
|
|
79
|
+
@abstractmethod
|
|
80
|
+
def get_position(
|
|
81
|
+
self, portfolio, symbol, market_credential
|
|
82
|
+
) -> Union[Position, None]:
|
|
83
|
+
"""
|
|
84
|
+
Function to get the position for a given symbol in the portfolio.
|
|
85
|
+
The returned position should be an object that reflects the current
|
|
86
|
+
state of the position on the exchange or broker.
|
|
87
|
+
|
|
88
|
+
!IMPORTANT: This function should return None if the position is
|
|
89
|
+
not found or if the position is not available on the
|
|
90
|
+
exchange or broker. Please do not throw an exception if the
|
|
91
|
+
position is not found.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
portfolio: Portfolio object
|
|
95
|
+
symbol: Symbol object
|
|
96
|
+
market_credential: MarketCredential object
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
float: Position for the given symbol in the portfolio
|
|
100
|
+
"""
|
|
101
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
102
|
+
|
|
103
|
+
@abstractmethod
|
|
104
|
+
def supports_market(self, market) -> bool:
|
|
105
|
+
"""
|
|
106
|
+
Function to check if the market is supported by the portfolio
|
|
107
|
+
provider.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
market: Market object
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
bool: True if the market is supported, False otherwise
|
|
114
|
+
"""
|
|
115
|
+
raise NotImplementedError("Subclasses must implement this method.")
|
|
116
|
+
|
|
117
|
+
def __repr__(self):
|
|
118
|
+
return f"{self.__class__.__name__}(priority={self.priority})"
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
from .market_credential_service import MarketCredentialService
|
|
2
|
-
from .market_data_sources import MarketDataSource, TickerMarketDataSource, \
|
|
3
|
-
OHLCVMarketDataSource, OrderBookMarketDataSource, BacktestMarketDataSource
|
|
4
|
-
from .market_service import MarketService
|
|
5
2
|
from .portfolios import AbstractPortfolioSyncService
|
|
6
3
|
from .rounding_service import RoundingService
|
|
4
|
+
from .state_handler import StateHandler
|
|
7
5
|
|
|
8
6
|
__all__ = [
|
|
9
|
-
"MarketDataSource",
|
|
10
|
-
"TickerMarketDataSource",
|
|
11
|
-
"OHLCVMarketDataSource",
|
|
12
|
-
"OrderBookMarketDataSource",
|
|
13
|
-
"BacktestMarketDataSource",
|
|
14
|
-
"MarketService",
|
|
15
7
|
"MarketCredentialService",
|
|
16
8
|
"AbstractPortfolioSyncService",
|
|
17
9
|
"RoundingService",
|
|
10
|
+
"StateHandler",
|
|
18
11
|
]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class StateHandler(ABC):
|
|
5
|
+
"""
|
|
6
|
+
Abstract base class for state handlers.
|
|
7
|
+
|
|
8
|
+
This class defines the
|
|
9
|
+
interface for state handlers, which are responsible for
|
|
10
|
+
saving and loading state information.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
def initialize(self):
|
|
15
|
+
"""
|
|
16
|
+
Initialize the state handler.
|
|
17
|
+
"""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def save(self, target_directory: str):
|
|
22
|
+
"""
|
|
23
|
+
Save the state to the specified directory.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
target_directory (str): Directory to save the state
|
|
27
|
+
"""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def load(self, target_directory: str):
|
|
32
|
+
"""
|
|
33
|
+
Load the state from the specified directory.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
target_directory (str): Directory to load the state
|
|
37
|
+
"""
|
|
38
|
+
pass
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .models import
|
|
1
|
+
from .models import TimeUnit
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Strategy:
|
|
@@ -11,9 +11,6 @@ class Strategy:
|
|
|
11
11
|
worker_id=None,
|
|
12
12
|
symbols=None,
|
|
13
13
|
limit=None,
|
|
14
|
-
trading_data_type=None,
|
|
15
|
-
trading_data_types=None,
|
|
16
|
-
trading_time_frame=None,
|
|
17
14
|
):
|
|
18
15
|
self._market = market
|
|
19
16
|
self._time_unit = TimeUnit.from_value(time_unit).value
|
|
@@ -22,19 +19,6 @@ class Strategy:
|
|
|
22
19
|
self._limit = limit
|
|
23
20
|
self._worker_id = worker_id
|
|
24
21
|
|
|
25
|
-
if trading_data_type is not None:
|
|
26
|
-
self._trading_data_type = TradingDataType \
|
|
27
|
-
.from_value(trading_data_type)
|
|
28
|
-
|
|
29
|
-
if trading_data_types is not None:
|
|
30
|
-
trading_data_types = [TradingDataType.from_value(trading_data_type)
|
|
31
|
-
for trading_data_type in trading_data_types]
|
|
32
|
-
self._trading_data_types = trading_data_types
|
|
33
|
-
|
|
34
|
-
if trading_time_frame is not None:
|
|
35
|
-
self._trading_time_frame = TradingTimeFrame \
|
|
36
|
-
.from_value(trading_time_frame)
|
|
37
|
-
|
|
38
22
|
@property
|
|
39
23
|
def market(self):
|
|
40
24
|
return self._market
|
|
@@ -55,18 +39,6 @@ class Strategy:
|
|
|
55
39
|
def limit(self):
|
|
56
40
|
return self._limit
|
|
57
41
|
|
|
58
|
-
@property
|
|
59
|
-
def trading_data_type(self):
|
|
60
|
-
return self._trading_data_type
|
|
61
|
-
|
|
62
|
-
@property
|
|
63
|
-
def trading_data_types(self):
|
|
64
|
-
return self._trading_data_types
|
|
65
|
-
|
|
66
|
-
@property
|
|
67
|
-
def trading_time_frame(self):
|
|
68
|
-
return self._trading_time_frame
|
|
69
|
-
|
|
70
42
|
@property
|
|
71
43
|
def worker_id(self):
|
|
72
44
|
return self._worker_id
|
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
from .backtesting import pretty_print_backtest, load_backtest_report, \
|
|
2
|
-
pretty_print_backtest_reports_evaluation, load_backtest_reports
|
|
3
1
|
from .csv import get_total_amount_of_rows, append_dict_as_row_to_csv, \
|
|
4
2
|
add_column_headers_to_csv, csv_to_list, load_csv_into_dict
|
|
5
|
-
from .random import random_string
|
|
3
|
+
from .random import random_string, random_number
|
|
6
4
|
from .stoppable_thread import StoppableThread
|
|
7
5
|
from .synchronized import synchronized
|
|
6
|
+
from .polars import convert_polars_to_pandas
|
|
7
|
+
from .dates import is_timezone_aware, sync_timezones, get_timezone
|
|
8
|
+
from .jupyter_notebook_detection import is_jupyter_notebook
|
|
9
|
+
from .custom_tqdm import tqdm
|
|
8
10
|
|
|
9
11
|
__all__ = [
|
|
10
12
|
'synchronized',
|
|
11
13
|
'StoppableThread',
|
|
12
14
|
'random_string',
|
|
15
|
+
'random_number',
|
|
13
16
|
'get_total_amount_of_rows',
|
|
14
17
|
'append_dict_as_row_to_csv',
|
|
15
18
|
'add_column_headers_to_csv',
|
|
16
19
|
'csv_to_list',
|
|
17
|
-
'pretty_print_backtest',
|
|
18
|
-
'pretty_print_backtest_reports_evaluation',
|
|
19
20
|
'load_csv_into_dict',
|
|
20
|
-
'
|
|
21
|
-
'
|
|
21
|
+
'convert_polars_to_pandas',
|
|
22
|
+
'is_timezone_aware',
|
|
23
|
+
'sync_timezones',
|
|
24
|
+
'get_timezone',
|
|
25
|
+
'is_jupyter_notebook',
|
|
26
|
+
'tqdm'
|
|
22
27
|
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from tqdm.notebook import tqdm as tqdm_notebook
|
|
2
|
+
from tqdm import tqdm as tqdm_terminal
|
|
3
|
+
|
|
4
|
+
from .jupyter_notebook_detection import is_jupyter_notebook
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def tqdm(*args, **kwargs):
|
|
8
|
+
"""
|
|
9
|
+
Returns a tqdm progress bar that adapts to the
|
|
10
|
+
environment (Jupyter Notebook or terminal).
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
*args: Positional arguments for tqdm.
|
|
14
|
+
**kwargs: Keyword arguments for tqdm.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
tqdm object: A tqdm progress bar.
|
|
18
|
+
"""
|
|
19
|
+
if is_jupyter_notebook():
|
|
20
|
+
return tqdm_notebook(*args, **kwargs)
|
|
21
|
+
else:
|
|
22
|
+
return tqdm_terminal(*args, **kwargs)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import pytz
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def is_timezone_aware(dt: datetime) -> bool:
|
|
7
|
+
"""
|
|
8
|
+
Check if a datetime object is timezone-aware.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
dt (datetime): The datetime object to check.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
bool: True if the datetime is timezone-aware, False otherwise.
|
|
15
|
+
"""
|
|
16
|
+
return dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_timezone(dt: datetime) -> Optional[pytz.tzinfo.BaseTzInfo]:
|
|
20
|
+
"""
|
|
21
|
+
Returns the timezone info from a datetime object.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
dt (datetime): The datetime object to check.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
pytz timezone info if available, otherwise None.
|
|
28
|
+
"""
|
|
29
|
+
if dt.tzinfo is not None and dt.tzinfo.utcoffset(dt) is not None:
|
|
30
|
+
return dt.tzinfo
|
|
31
|
+
return None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def sync_timezones(reference_dt: datetime, naive_dt: datetime) -> datetime:
|
|
35
|
+
"""
|
|
36
|
+
Synchronize a naive datetime with the timezone of a reference datetime.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
reference_dt (datetime): A timezone-aware datetime to
|
|
40
|
+
use as a reference.
|
|
41
|
+
naive_dt (datetime): A naive datetime to be synchronized.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Datetime: A timezone-aware datetime that matches the
|
|
45
|
+
timezone of the reference.
|
|
46
|
+
"""
|
|
47
|
+
tz = get_timezone(reference_dt)
|
|
48
|
+
|
|
49
|
+
if tz is None:
|
|
50
|
+
return naive_dt
|
|
51
|
+
|
|
52
|
+
# Check if tz has a localize method (pytz)
|
|
53
|
+
if hasattr(tz, 'localize'):
|
|
54
|
+
return tz.localize(naive_dt)
|
|
55
|
+
else:
|
|
56
|
+
# fallback (e.g., zoneinfo or other)
|
|
57
|
+
return naive_dt.replace(tzinfo=tz)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
def is_jupyter_notebook():
|
|
2
|
+
"""
|
|
3
|
+
Check if the code is running in a Jupyter Notebook environment.
|
|
4
|
+
|
|
5
|
+
Returns:
|
|
6
|
+
bool: True if running in a Jupyter Notebook, False otherwise.
|
|
7
|
+
"""
|
|
8
|
+
try:
|
|
9
|
+
# Check for the presence of the 'IPython' module
|
|
10
|
+
from IPython import get_ipython
|
|
11
|
+
return 'IPKernelApp' in get_ipython().config
|
|
12
|
+
except ImportError:
|
|
13
|
+
return False
|
|
14
|
+
except AttributeError:
|
|
15
|
+
# If get_ipython() does not have 'config', it is not a Jupyter Notebook
|
|
16
|
+
return False
|
|
17
|
+
except Exception:
|
|
18
|
+
# Catch any other exceptions and return False
|
|
19
|
+
return False
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from polars import DataFrame as PolarsDataFrame
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def convert_polars_to_pandas(
|
|
6
|
+
data: PolarsDataFrame,
|
|
7
|
+
remove_duplicates=True,
|
|
8
|
+
add_index=True,
|
|
9
|
+
add_datetime_column=True,
|
|
10
|
+
datetime_column_name="Datetime"
|
|
11
|
+
):
|
|
12
|
+
"""
|
|
13
|
+
Function to convert polars dataframe to pandas dataframe.
|
|
14
|
+
|
|
15
|
+
The function will set the index to the datetime column. The reason
|
|
16
|
+
for this is that You can filter with clean, readable code in a faster way
|
|
17
|
+
then with filtering on a column that is not the index.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
data:Polars Dataframe - The original polars dataframe
|
|
21
|
+
remove_duplicates: Boolean - If set to true, all duplicate
|
|
22
|
+
dates will be removed from the dataframe
|
|
23
|
+
add_index: Boolean - If set to true, an index will
|
|
24
|
+
be added to the dataframe
|
|
25
|
+
add_datetime_column: Boolean - If set to true, a datetime
|
|
26
|
+
column will be added to the dataframe
|
|
27
|
+
datetime_column_name: String - the column name that has the
|
|
28
|
+
datetime object. By default this is set to column name Datetime
|
|
29
|
+
This is only used if add_index is set to True
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
DataFrame: Pandas DataFrame that has been converted
|
|
33
|
+
from a Polars DataFrame
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
if not isinstance(data, PolarsDataFrame):
|
|
37
|
+
raise ValueError("Data must be a Polars DataFrame")
|
|
38
|
+
|
|
39
|
+
df = data.to_pandas().copy()
|
|
40
|
+
|
|
41
|
+
if add_datetime_column and datetime_column_name not in df.columns:
|
|
42
|
+
df[datetime_column_name] = pd.to_datetime(df.index)
|
|
43
|
+
|
|
44
|
+
# Ensure datetime column is datetime type
|
|
45
|
+
df[datetime_column_name] = pd.to_datetime(df[datetime_column_name])
|
|
46
|
+
|
|
47
|
+
if remove_duplicates:
|
|
48
|
+
df = df.drop_duplicates(subset=datetime_column_name, keep="first")
|
|
49
|
+
|
|
50
|
+
if add_index:
|
|
51
|
+
df.set_index(datetime_column_name, inplace=True)
|
|
52
|
+
|
|
53
|
+
return df
|
|
@@ -3,6 +3,16 @@ import string
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def random_string(n, spaces: bool = False):
|
|
6
|
+
"""
|
|
7
|
+
Function to generate a random string of n characters.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
n: number of characters
|
|
11
|
+
spaces: if True, include spaces in the string
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
str: Random string of n characters
|
|
15
|
+
"""
|
|
6
16
|
|
|
7
17
|
if spaces:
|
|
8
18
|
return ''.join(
|
|
@@ -10,3 +20,22 @@ def random_string(n, spaces: bool = False):
|
|
|
10
20
|
)
|
|
11
21
|
|
|
12
22
|
return ''.join(random.choice(string.ascii_lowercase) for _ in range(n))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def random_number(n, variable_size: bool = False):
|
|
26
|
+
"""
|
|
27
|
+
Function to generate a random number of n digits.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
n: number of digits
|
|
31
|
+
variable_size: if True, the number of digits will be variable
|
|
32
|
+
between 1 and n
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
int: Random number of n digits
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
if variable_size:
|
|
39
|
+
n = random.randint(1, n)
|
|
40
|
+
|
|
41
|
+
return int(''.join(random.choice(string.digits) for _ in range(n)))
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from dateutil import parser
|
|
3
|
+
from datetime import timezone, datetime
|
|
4
|
+
import pandas
|
|
5
|
+
import polars
|
|
6
|
+
from typing import Union
|
|
7
|
+
from investing_algorithm_framework.services import DataProviderService, \
|
|
8
|
+
ConfigurationService, MarketCredentialService
|
|
9
|
+
from investing_algorithm_framework.infrastructure import \
|
|
10
|
+
get_default_data_providers
|
|
11
|
+
from investing_algorithm_framework.domain import DataSource, \
|
|
12
|
+
OperationalException, DataType
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def download(
|
|
16
|
+
symbol: str,
|
|
17
|
+
market: str = None,
|
|
18
|
+
date: Union[datetime, str] = None,
|
|
19
|
+
time_frame: str = None,
|
|
20
|
+
data_type: Union[str, DataType] = DataType.OHLCV,
|
|
21
|
+
start_date: Union[datetime, str] = None,
|
|
22
|
+
end_date: Union[datetime, str] = None,
|
|
23
|
+
window_size: int = 200,
|
|
24
|
+
pandas: bool = True,
|
|
25
|
+
save: bool = True,
|
|
26
|
+
storage_path: Union[str, Path] = None,
|
|
27
|
+
) -> Union[pandas.DataFrame, polars.DataFrame]:
|
|
28
|
+
"""
|
|
29
|
+
Download market data from the specified source. This function
|
|
30
|
+
uses the MarketDataSourceService to get the data provider
|
|
31
|
+
for the given set of parameters.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
symbol (str): The symbol to download data for.
|
|
35
|
+
market (str): The market to download data from.
|
|
36
|
+
data_type (str): The type of data to
|
|
37
|
+
download (e.g., "ohlcv", "ticker").
|
|
38
|
+
start_date (str): The start date for the data download.
|
|
39
|
+
end_date (str): The end date for the data download.
|
|
40
|
+
window_size (int): The size of the data window.
|
|
41
|
+
pandas (bool): Whether to return the data as a pandas DataFrame.
|
|
42
|
+
save (bool): Whether to save the downloaded data.
|
|
43
|
+
storage_path (str): The directory to save the downloaded data.
|
|
44
|
+
time_frame (str): The time frame for the data download.
|
|
45
|
+
date (str): The date for the data download.
|
|
46
|
+
window_size (int): The size of the data window.
|
|
47
|
+
pandas (bool): Whether to return the data as a pandas DataFrame.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
None
|
|
51
|
+
"""
|
|
52
|
+
configuration_service = ConfigurationService()
|
|
53
|
+
market_credential_service = MarketCredentialService()
|
|
54
|
+
data_provider_service = DataProviderService(
|
|
55
|
+
default_data_providers=get_default_data_providers(),
|
|
56
|
+
configuration_service=configuration_service,
|
|
57
|
+
market_credential_service=market_credential_service,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if start_date is not None and isinstance(start_date, str):
|
|
61
|
+
start_date = parser.parse(start_date)
|
|
62
|
+
start_date = start_date.replace(tzinfo=timezone.utc)
|
|
63
|
+
|
|
64
|
+
if end_date is not None and isinstance(end_date, str):
|
|
65
|
+
end_date = parser.parse(end_date)
|
|
66
|
+
end_date = end_date.replace(tzinfo=timezone.utc)
|
|
67
|
+
|
|
68
|
+
if date is not None and isinstance(date, str):
|
|
69
|
+
date = parser.parse(date)
|
|
70
|
+
date = date.replace(tzinfo=timezone.utc)
|
|
71
|
+
|
|
72
|
+
# Check if all the datetime parameters are in UTC
|
|
73
|
+
if date is not None \
|
|
74
|
+
and (date.tzinfo is None or date.tzinfo != timezone.utc):
|
|
75
|
+
raise OperationalException("Date must be a UTC datetime object")
|
|
76
|
+
|
|
77
|
+
if start_date is not None \
|
|
78
|
+
and (
|
|
79
|
+
start_date.tzinfo is None or start_date.tzinfo != timezone.utc
|
|
80
|
+
):
|
|
81
|
+
raise OperationalException("Start date must be a UTC datetime object")
|
|
82
|
+
|
|
83
|
+
if end_date is not None \
|
|
84
|
+
and (end_date.tzinfo is None or end_date.tzinfo != timezone.utc):
|
|
85
|
+
raise OperationalException("End date must be a UTC datetime object")
|
|
86
|
+
|
|
87
|
+
data_source = DataSource(
|
|
88
|
+
symbol=symbol,
|
|
89
|
+
market=market,
|
|
90
|
+
data_type=data_type,
|
|
91
|
+
time_frame=time_frame,
|
|
92
|
+
date=date,
|
|
93
|
+
start_date=start_date,
|
|
94
|
+
end_date=end_date,
|
|
95
|
+
window_size=window_size,
|
|
96
|
+
pandas=pandas,
|
|
97
|
+
save=save,
|
|
98
|
+
storage_path=storage_path
|
|
99
|
+
)
|
|
100
|
+
data_provider_service.index_data_providers(
|
|
101
|
+
data_sources=[data_source]
|
|
102
|
+
)
|
|
103
|
+
return data_provider_service.get_data(
|
|
104
|
+
data_source=data_source,
|
|
105
|
+
date=date,
|
|
106
|
+
start_date=start_date,
|
|
107
|
+
end_date=end_date,
|
|
108
|
+
)
|