investing-algorithm-framework 6.9.1__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 +147 -44
- investing_algorithm_framework/app/__init__.py +23 -6
- investing_algorithm_framework/app/algorithm/algorithm.py +5 -41
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +17 -10
- 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 +1322 -707
- investing_algorithm_framework/app/context.py +196 -88
- investing_algorithm_framework/app/eventloop.py +590 -0
- investing_algorithm_framework/app/reporting/__init__.py +16 -5
- investing_algorithm_framework/app/reporting/ascii.py +57 -202
- investing_algorithm_framework/app/reporting/backtest_report.py +284 -170
- investing_algorithm_framework/app/reporting/charts/__init__.py +10 -2
- 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 +11 -26
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +1 -1
- investing_algorithm_framework/app/reporting/generate.py +100 -114
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +40 -32
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +34 -27
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +23 -19
- investing_algorithm_framework/app/reporting/tables/trades_table.py +1 -1
- investing_algorithm_framework/app/reporting/tables/utils.py +1 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +10 -16
- investing_algorithm_framework/app/strategy.py +315 -175
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/cli/cli.py +30 -12
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +131 -34
- investing_algorithm_framework/cli/initialize_app.py +20 -1
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +18 -6
- 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_requirements.txt.template +2 -2
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +1 -1
- investing_algorithm_framework/create_app.py +3 -5
- investing_algorithm_framework/dependency_container.py +25 -39
- investing_algorithm_framework/domain/__init__.py +45 -38
- 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 +27 -0
- investing_algorithm_framework/domain/constants.py +6 -34
- investing_algorithm_framework/domain/data_provider.py +200 -56
- investing_algorithm_framework/domain/exceptions.py +34 -1
- investing_algorithm_framework/domain/models/__init__.py +10 -19
- investing_algorithm_framework/domain/models/base_model.py +0 -6
- 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/{market_data_type.py → data/data_type.py} +7 -7
- investing_algorithm_framework/domain/models/market/market_credential.py +6 -0
- investing_algorithm_framework/domain/models/order/order.py +34 -13
- investing_algorithm_framework/domain/models/order/order_status.py +1 -1
- investing_algorithm_framework/domain/models/order/order_type.py +1 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +14 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +5 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +51 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +9 -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 +0 -1
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
- investing_algorithm_framework/domain/models/time_frame.py +7 -0
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +63 -1
- investing_algorithm_framework/domain/models/trade/__init__.py +0 -2
- investing_algorithm_framework/domain/models/trade/trade.py +56 -32
- investing_algorithm_framework/domain/models/trade/trade_status.py +8 -2
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +106 -41
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +161 -99
- investing_algorithm_framework/domain/order_executor.py +19 -0
- investing_algorithm_framework/domain/portfolio_provider.py +20 -1
- investing_algorithm_framework/domain/services/__init__.py +0 -13
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +5 -1
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +17 -14
- investing_algorithm_framework/download_data.py +40 -10
- investing_algorithm_framework/infrastructure/__init__.py +13 -25
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +7 -4
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +811 -546
- investing_algorithm_framework/infrastructure/data_providers/csv.py +433 -122
- 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 +81 -0
- investing_algorithm_framework/infrastructure/models/__init__.py +0 -13
- investing_algorithm_framework/infrastructure/models/order/order.py +9 -3
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +27 -8
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +21 -7
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +2 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +16 -2
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +6 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +6 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +0 -4
- investing_algorithm_framework/services/__init__.py +105 -8
- investing_algorithm_framework/services/backtesting/backtest_service.py +536 -476
- investing_algorithm_framework/services/configuration_service.py +14 -4
- 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/{app/reporting → services}/metrics/__init__.py +48 -17
- investing_algorithm_framework/{app/reporting → services}/metrics/drawdown.py +10 -10
- investing_algorithm_framework/{app/reporting → services}/metrics/equity_curve.py +2 -2
- investing_algorithm_framework/{app/reporting → services}/metrics/exposure.py +60 -2
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/profit_factor.py +36 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/recovery.py +2 -2
- investing_algorithm_framework/{app/reporting → services}/metrics/returns.py +146 -147
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/{app/reporting/metrics/sharp_ratio.py → services/metrics/sharpe_ratio.py} +6 -10
- investing_algorithm_framework/{app/reporting → services}/metrics/sortino_ratio.py +3 -7
- investing_algorithm_framework/services/metrics/trades.py +500 -0
- investing_algorithm_framework/services/metrics/volatility.py +97 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/win_rate.py +70 -3
- investing_algorithm_framework/services/order_service/order_backtest_service.py +21 -31
- investing_algorithm_framework/services/order_service/order_service.py +9 -71
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -2
- investing_algorithm_framework/services/portfolios/portfolio_service.py +3 -13
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +62 -96
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -3
- investing_algorithm_framework/services/repository_service.py +5 -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 +51 -29
- 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-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/RECORD +159 -148
- investing_algorithm_framework/app/reporting/evaluation.py +0 -243
- investing_algorithm_framework/app/reporting/metrics/risk_free_rate.py +0 -8
- investing_algorithm_framework/app/reporting/metrics/volatility.py +0 -69
- investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -3
- investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -9
- investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -47
- investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
- investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
- investing_algorithm_framework/domain/models/backtesting/backtest_results.py +0 -440
- investing_algorithm_framework/domain/models/data_source.py +0 -21
- investing_algorithm_framework/domain/models/date_range.py +0 -64
- investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -34
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -48
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/services/market_data_sources.py +0 -543
- investing_algorithm_framework/domain/services/market_service.py +0 -153
- investing_algorithm_framework/domain/services/observable.py +0 -51
- investing_algorithm_framework/domain/services/observer.py +0 -19
- investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -16
- investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -746
- investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -270
- investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -312
- investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
- investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -471
- 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 -322
- investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -10
- investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -269
- investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -350
- investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -377
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -296
- investing_algorithm_framework-6.9.1.dist-info/METADATA +0 -440
- /investing_algorithm_framework/{app/reporting → services}/metrics/alpha.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/beta.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/cagr.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/calmar_ratio.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/mean_daily_return.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/price_efficiency.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/standard_deviation.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/treynor_ratio.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/ulcer.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/value_at_risk.py +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/entry_points.txt +0 -0
|
@@ -1,746 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import os
|
|
3
|
-
from datetime import timedelta, datetime, timezone
|
|
4
|
-
|
|
5
|
-
import polars
|
|
6
|
-
from dateutil import parser
|
|
7
|
-
|
|
8
|
-
from investing_algorithm_framework.domain import RESOURCE_DIRECTORY, \
|
|
9
|
-
BACKTEST_DATA_DIRECTORY_NAME, DATETIME_FORMAT_BACKTESTING, \
|
|
10
|
-
OperationalException, DATETIME_FORMAT, OHLCVMarketDataSource, \
|
|
11
|
-
BacktestMarketDataSource, OrderBookMarketDataSource, \
|
|
12
|
-
TickerMarketDataSource, TimeFrame, sync_timezones
|
|
13
|
-
from investing_algorithm_framework.infrastructure.services import \
|
|
14
|
-
CCXTMarketService
|
|
15
|
-
|
|
16
|
-
logger = logging.getLogger("investing_algorithm_framework")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class CCXTOHLCVBacktestMarketDataSource(
|
|
20
|
-
OHLCVMarketDataSource, BacktestMarketDataSource
|
|
21
|
-
):
|
|
22
|
-
"""
|
|
23
|
-
CCXTOHLCVBacktestMarketDataSource implementation using ccxt to download
|
|
24
|
-
all data sources.
|
|
25
|
-
|
|
26
|
-
This class will determine the start and end date of the data range by
|
|
27
|
-
taking the backtest start date (e.g. 01-01-2024) and the backtest
|
|
28
|
-
end date (e.g. 31-12-2024) in combination with the difference between
|
|
29
|
-
start and end date. The reason for this is that the data source needs
|
|
30
|
-
to have data on the first run (e.g. an algorithm starting on
|
|
31
|
-
01-01-2024 that requires 2h data for the last 17 days will
|
|
32
|
-
need to have pulled data from 15-12-2023)
|
|
33
|
-
|
|
34
|
-
To achieve this, a backtest_data_start_date attribute is used. This
|
|
35
|
-
attribute is indexed on this calculated date.
|
|
36
|
-
"""
|
|
37
|
-
backtest_data_directory = None
|
|
38
|
-
backtest_data_end_date = None
|
|
39
|
-
total_minutes_time_frame = None
|
|
40
|
-
column_names = ["Datetime", "Open", "High", "Low", "Close", "Volume"]
|
|
41
|
-
|
|
42
|
-
def __init__(
|
|
43
|
-
self,
|
|
44
|
-
identifier,
|
|
45
|
-
market,
|
|
46
|
-
symbol,
|
|
47
|
-
time_frame,
|
|
48
|
-
window_size=None,
|
|
49
|
-
):
|
|
50
|
-
super().__init__(
|
|
51
|
-
identifier=identifier,
|
|
52
|
-
market=market,
|
|
53
|
-
symbol=symbol,
|
|
54
|
-
time_frame=time_frame,
|
|
55
|
-
window_size=window_size,
|
|
56
|
-
)
|
|
57
|
-
self.data = None
|
|
58
|
-
self._start_date_data_source = None
|
|
59
|
-
self._end_date_data_source = None
|
|
60
|
-
self.backtest_end_index = self.window_size
|
|
61
|
-
self.backtest_start_index = 0
|
|
62
|
-
self.window_cache = {}
|
|
63
|
-
|
|
64
|
-
def prepare_data(
|
|
65
|
-
self,
|
|
66
|
-
config,
|
|
67
|
-
backtest_start_date,
|
|
68
|
-
backtest_end_date,
|
|
69
|
-
):
|
|
70
|
-
"""
|
|
71
|
-
Prepare data implementation of ccxt based ohlcv backtest market
|
|
72
|
-
data source
|
|
73
|
-
|
|
74
|
-
This implementation will check if the data source already exists before
|
|
75
|
-
pulling all the data. This optimization will prevent downloading
|
|
76
|
-
of unnecessary resources.
|
|
77
|
-
|
|
78
|
-
When downloading the data it will use the ccxt library.
|
|
79
|
-
|
|
80
|
-
Args:
|
|
81
|
-
config (dict): the configuration of the data source
|
|
82
|
-
backtest_start_date (datetime): the start date of the backtest
|
|
83
|
-
backtest_end_date (datetime): the end date of the backtest
|
|
84
|
-
time_frame (string): the time frame of the data
|
|
85
|
-
window_size (int): the total amount of candle sticks that need to
|
|
86
|
-
be returned
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
None
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
if config is None:
|
|
93
|
-
config = self.config
|
|
94
|
-
|
|
95
|
-
# Calculating the backtest data start date
|
|
96
|
-
backtest_data_start_date = \
|
|
97
|
-
backtest_start_date - timedelta(
|
|
98
|
-
minutes=(
|
|
99
|
-
(self.window_size + 1) *
|
|
100
|
-
TimeFrame.from_value(self.time_frame).amount_of_minutes
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
self.backtest_data_start_date = backtest_data_start_date\
|
|
105
|
-
.replace(microsecond=0)
|
|
106
|
-
self.backtest_data_end_date = backtest_end_date.replace(microsecond=0)
|
|
107
|
-
|
|
108
|
-
# Creating the backtest data directory and file
|
|
109
|
-
self.backtest_data_directory = os.path.join(
|
|
110
|
-
config[RESOURCE_DIRECTORY], config[BACKTEST_DATA_DIRECTORY_NAME]
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
if not os.path.isdir(self.backtest_data_directory):
|
|
114
|
-
os.mkdir(self.backtest_data_directory)
|
|
115
|
-
|
|
116
|
-
file_path = self._create_file_path()
|
|
117
|
-
|
|
118
|
-
if not self._data_source_exists(file_path):
|
|
119
|
-
if not os.path.isfile(file_path):
|
|
120
|
-
try:
|
|
121
|
-
with open(file_path, 'w') as _:
|
|
122
|
-
pass
|
|
123
|
-
except Exception as e:
|
|
124
|
-
logger.error(e)
|
|
125
|
-
raise OperationalException(
|
|
126
|
-
f"Could not create backtest data file {file_path}"
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
# Get the OHLCV data from the ccxt market service
|
|
130
|
-
market_service = CCXTMarketService(
|
|
131
|
-
market_credential_service=self.market_credential_service,
|
|
132
|
-
)
|
|
133
|
-
market_service.config = config
|
|
134
|
-
ohlcv = market_service.get_ohlcv(
|
|
135
|
-
symbol=self.symbol,
|
|
136
|
-
time_frame=self.time_frame,
|
|
137
|
-
from_timestamp=backtest_data_start_date,
|
|
138
|
-
to_timestamp=backtest_end_date,
|
|
139
|
-
market=self.market
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
if len(ohlcv) == 0:
|
|
143
|
-
raise OperationalException(
|
|
144
|
-
f"No data found for {self.symbol} " +
|
|
145
|
-
f"for date range: {backtest_data_start_date} " +
|
|
146
|
-
f"to {backtest_end_date}. Please make sure that " +
|
|
147
|
-
"the market has data for this date range."
|
|
148
|
-
)
|
|
149
|
-
self.write_data_to_file_path(file_path, ohlcv)
|
|
150
|
-
|
|
151
|
-
self.load_data()
|
|
152
|
-
self._precompute_sliding_windows() # Precompute sliding windows!
|
|
153
|
-
|
|
154
|
-
def _precompute_sliding_windows(self):
|
|
155
|
-
"""
|
|
156
|
-
Precompute all sliding windows for fast retrieval.
|
|
157
|
-
|
|
158
|
-
A sliding window is calculated as a subset of the data. It will
|
|
159
|
-
take for each timestamp in the data a window of size `window_size`
|
|
160
|
-
and stores it in a cache with the last timestamp of the window.
|
|
161
|
-
"""
|
|
162
|
-
self.window_cache = {}
|
|
163
|
-
timestamps = self.data["Datetime"].to_list()
|
|
164
|
-
|
|
165
|
-
for i in range(len(timestamps) - self.window_size + 1):
|
|
166
|
-
# Use last timestamp as key
|
|
167
|
-
end_time = timestamps[i + self.window_size - 1]
|
|
168
|
-
|
|
169
|
-
# Convert end_time datetime object to UTC
|
|
170
|
-
if isinstance(end_time, str):
|
|
171
|
-
end_time = parser.parse(end_time)
|
|
172
|
-
elif isinstance(end_time, datetime):
|
|
173
|
-
end_time = end_time
|
|
174
|
-
|
|
175
|
-
# end_time = end_time.replace(tzinfo=timezone.utc)
|
|
176
|
-
self.window_cache[end_time] = self.data.slice(i, self.window_size)
|
|
177
|
-
|
|
178
|
-
def load_data(self):
|
|
179
|
-
file_path = self._create_file_path()
|
|
180
|
-
self.data = polars.read_csv(
|
|
181
|
-
file_path,
|
|
182
|
-
schema_overrides={"Datetime": polars.Datetime},
|
|
183
|
-
low_memory=True
|
|
184
|
-
) # Faster parsing
|
|
185
|
-
first_row = self.data.head(1)
|
|
186
|
-
last_row = self.data.tail(1)
|
|
187
|
-
|
|
188
|
-
self._start_date_data_source = first_row["Datetime"][0]
|
|
189
|
-
self._end_date_data_source = last_row["Datetime"][0]
|
|
190
|
-
|
|
191
|
-
def _create_file_path(self):
|
|
192
|
-
"""
|
|
193
|
-
Function to create a filename in the following format:
|
|
194
|
-
OHLCV_{symbol}_{market}_{time_frame}_{start_date}_{end_date}.csv
|
|
195
|
-
"""
|
|
196
|
-
symbol_string = self.symbol.replace("/", "-")
|
|
197
|
-
time_frame_string = self.time_frame.replace("_", "")
|
|
198
|
-
backtest_data_start_date = \
|
|
199
|
-
self.backtest_data_start_date.strftime(DATETIME_FORMAT_BACKTESTING)
|
|
200
|
-
backtest_data_end_date = \
|
|
201
|
-
self.backtest_data_end_date.strftime(DATETIME_FORMAT_BACKTESTING)
|
|
202
|
-
return os.path.join(
|
|
203
|
-
self.backtest_data_directory,
|
|
204
|
-
os.path.join(
|
|
205
|
-
f"OHLCV_"
|
|
206
|
-
f"{symbol_string}_"
|
|
207
|
-
f"{self.market}_"
|
|
208
|
-
f"{time_frame_string}_"
|
|
209
|
-
f"{backtest_data_start_date}_"
|
|
210
|
-
f"{backtest_data_end_date}.csv"
|
|
211
|
-
)
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
def get_data(
|
|
215
|
-
self,
|
|
216
|
-
date,
|
|
217
|
-
config=None,
|
|
218
|
-
):
|
|
219
|
-
"""
|
|
220
|
-
Get data implementation of ccxt based ohlcv backtest market data
|
|
221
|
-
source. This implementation will use polars to load and filter the
|
|
222
|
-
data.
|
|
223
|
-
"""
|
|
224
|
-
|
|
225
|
-
data = self.window_cache.get(date)
|
|
226
|
-
if data is not None:
|
|
227
|
-
return data
|
|
228
|
-
|
|
229
|
-
# Find closest previous timestamp
|
|
230
|
-
sorted_timestamps = sorted(self.window_cache.keys())
|
|
231
|
-
|
|
232
|
-
closest_date = None
|
|
233
|
-
for ts in reversed(sorted_timestamps):
|
|
234
|
-
date = sync_timezones(ts, date)
|
|
235
|
-
|
|
236
|
-
if ts <= date:
|
|
237
|
-
closest_date = ts
|
|
238
|
-
break
|
|
239
|
-
|
|
240
|
-
return self.window_cache.get(closest_date) if closest_date else None
|
|
241
|
-
|
|
242
|
-
def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
|
|
243
|
-
# Ignore this method for now
|
|
244
|
-
pass
|
|
245
|
-
|
|
246
|
-
def empty(self):
|
|
247
|
-
return False
|
|
248
|
-
|
|
249
|
-
@property
|
|
250
|
-
def file_name(self):
|
|
251
|
-
return self._create_file_path().split("/")[-1]
|
|
252
|
-
|
|
253
|
-
def write_data_to_file_path(self, data_file, data: polars.DataFrame):
|
|
254
|
-
data.write_csv(data_file)
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
class CCXTTickerBacktestMarketDataSource(
|
|
258
|
-
TickerMarketDataSource, BacktestMarketDataSource
|
|
259
|
-
):
|
|
260
|
-
"""
|
|
261
|
-
CCXTTickerBacktestMarketDataSource implementation using ccxt to download
|
|
262
|
-
all data sources.
|
|
263
|
-
|
|
264
|
-
This class will determine the start and end date of the data range by
|
|
265
|
-
taking the start date of the backtest minus 1 day and the end date of the
|
|
266
|
-
backtest. The reason for this is that the data source needs
|
|
267
|
-
to have data on the first run (e.g. an algorithm starting on
|
|
268
|
-
01-01-2024 that requires ticker data will need to have pulled data from
|
|
269
|
-
01-01-2024 - amount of minutes of the provided time_frame)
|
|
270
|
-
|
|
271
|
-
To achieve this, a backtest_data_start_date attribute is used. This
|
|
272
|
-
attribute is indexed on this calculated date.
|
|
273
|
-
"""
|
|
274
|
-
backtest_data_directory = None
|
|
275
|
-
backtest_data_start_date = None
|
|
276
|
-
backtest_data_end_date = None
|
|
277
|
-
time_frame = None
|
|
278
|
-
column_names = ["Datetime", "Open", "High", "Low", "Close", "Volume"]
|
|
279
|
-
|
|
280
|
-
def __init__(
|
|
281
|
-
self,
|
|
282
|
-
identifier,
|
|
283
|
-
market,
|
|
284
|
-
symbol=None,
|
|
285
|
-
time_frame=None,
|
|
286
|
-
):
|
|
287
|
-
super().__init__(
|
|
288
|
-
identifier=identifier,
|
|
289
|
-
market=market,
|
|
290
|
-
symbol=symbol,
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
if time_frame is not None:
|
|
294
|
-
self.time_frame = time_frame
|
|
295
|
-
|
|
296
|
-
if self.time_frame is None:
|
|
297
|
-
raise OperationalException(
|
|
298
|
-
"time_frame should be set for "
|
|
299
|
-
"CCXTTickerBacktestMarketDataSource"
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
def prepare_data(
|
|
303
|
-
self,
|
|
304
|
-
config,
|
|
305
|
-
backtest_start_date,
|
|
306
|
-
backtest_end_date,
|
|
307
|
-
):
|
|
308
|
-
"""
|
|
309
|
-
Prepare data implementation of ccxt based ticker backtest market
|
|
310
|
-
data source
|
|
311
|
-
|
|
312
|
-
This implementation will check if the data source already exists before
|
|
313
|
-
pulling all the data. This optimization will prevent downloading
|
|
314
|
-
of unnecessary resources.
|
|
315
|
-
|
|
316
|
-
When downloading the data it will use the ccxt library.
|
|
317
|
-
"""
|
|
318
|
-
|
|
319
|
-
if config is None:
|
|
320
|
-
config = self.config
|
|
321
|
-
|
|
322
|
-
total_minutes = TimeFrame.from_string(self.time_frame)\
|
|
323
|
-
.amount_of_minutes
|
|
324
|
-
self.backtest_data_start_date = \
|
|
325
|
-
backtest_start_date - timedelta(minutes=total_minutes)
|
|
326
|
-
self.backtest_data_end_date = backtest_end_date
|
|
327
|
-
|
|
328
|
-
# Creating the backtest data directory and file
|
|
329
|
-
self.backtest_data_directory = os.path.join(
|
|
330
|
-
config[RESOURCE_DIRECTORY], config[BACKTEST_DATA_DIRECTORY_NAME]
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
if not os.path.isdir(self.backtest_data_directory):
|
|
334
|
-
os.mkdir(self.backtest_data_directory)
|
|
335
|
-
|
|
336
|
-
file_path = self._create_file_path()
|
|
337
|
-
|
|
338
|
-
if not os.path.isfile(file_path):
|
|
339
|
-
try:
|
|
340
|
-
with open(file_path, 'w') as _:
|
|
341
|
-
pass
|
|
342
|
-
except Exception as e:
|
|
343
|
-
logger.error(e)
|
|
344
|
-
raise OperationalException(
|
|
345
|
-
f"Could not create backtest data file {file_path}"
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
# Check if the data source already exists, if not download the data
|
|
349
|
-
if not self._data_source_exists(file_path):
|
|
350
|
-
if not os.path.isfile(file_path):
|
|
351
|
-
try:
|
|
352
|
-
with open(file_path, 'w') as _:
|
|
353
|
-
pass
|
|
354
|
-
except Exception as e:
|
|
355
|
-
logger.error(e)
|
|
356
|
-
raise OperationalException(
|
|
357
|
-
f"Could not create backtest data file {file_path}"
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
# Get the OHLCV data from the ccxt market service
|
|
361
|
-
market_service = CCXTMarketService(
|
|
362
|
-
market_credential_service=self.market_credential_service
|
|
363
|
-
)
|
|
364
|
-
market_service.config = config
|
|
365
|
-
ohlcv = market_service.get_ohlcv(
|
|
366
|
-
symbol=self.symbol,
|
|
367
|
-
time_frame=self.time_frame,
|
|
368
|
-
from_timestamp=self.backtest_data_start_date,
|
|
369
|
-
to_timestamp=backtest_end_date,
|
|
370
|
-
market=self.market
|
|
371
|
-
)
|
|
372
|
-
self.write_data_to_file_path(file_path, ohlcv)
|
|
373
|
-
|
|
374
|
-
def _create_file_path(self):
|
|
375
|
-
|
|
376
|
-
if self.symbol is None or self.market is None:
|
|
377
|
-
return None
|
|
378
|
-
|
|
379
|
-
symbol_string = self.symbol.replace("/", "-")
|
|
380
|
-
market_string = self.market.replace("/", "-")
|
|
381
|
-
backtest_data_start_date = \
|
|
382
|
-
self.backtest_data_start_date.strftime(DATETIME_FORMAT_BACKTESTING)
|
|
383
|
-
backtest_data_end_date = \
|
|
384
|
-
self.backtest_data_end_date.strftime(DATETIME_FORMAT_BACKTESTING)
|
|
385
|
-
return os.path.join(
|
|
386
|
-
self.backtest_data_directory,
|
|
387
|
-
os.path.join(
|
|
388
|
-
f"TICKER_"
|
|
389
|
-
f"{symbol_string}_"
|
|
390
|
-
f"{market_string}_"
|
|
391
|
-
f"{backtest_data_start_date}_"
|
|
392
|
-
f"{backtest_data_end_date}.csv"
|
|
393
|
-
)
|
|
394
|
-
)
|
|
395
|
-
|
|
396
|
-
def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
|
|
397
|
-
# Ignore this method for now
|
|
398
|
-
pass
|
|
399
|
-
|
|
400
|
-
def empty(self):
|
|
401
|
-
return False
|
|
402
|
-
|
|
403
|
-
def get_data(
|
|
404
|
-
self,
|
|
405
|
-
date,
|
|
406
|
-
config,
|
|
407
|
-
):
|
|
408
|
-
"""
|
|
409
|
-
Get data implementation of ccxt based ticker backtest market data
|
|
410
|
-
source
|
|
411
|
-
"""
|
|
412
|
-
file_path = self._create_file_path()
|
|
413
|
-
|
|
414
|
-
# Filter the data based on the backtest index date and the end date
|
|
415
|
-
df = polars.read_csv(file_path)
|
|
416
|
-
filtered_df = df.filter(
|
|
417
|
-
(df['Datetime'] >= date.strftime(DATETIME_FORMAT))
|
|
418
|
-
)
|
|
419
|
-
|
|
420
|
-
# If nothing is found, get all dates before the index date
|
|
421
|
-
if len(filtered_df) == 0:
|
|
422
|
-
filtered_df = df.filter(
|
|
423
|
-
(df['Datetime'] <= date.strftime(
|
|
424
|
-
DATETIME_FORMAT))
|
|
425
|
-
)
|
|
426
|
-
first_row = filtered_df.tail(1)[0]
|
|
427
|
-
else:
|
|
428
|
-
first_row = filtered_df.head(1)[0]
|
|
429
|
-
|
|
430
|
-
first_row_datetime = parser.parse(first_row["Datetime"][0])
|
|
431
|
-
|
|
432
|
-
return {
|
|
433
|
-
"symbol": self.symbol,
|
|
434
|
-
"bid": float(first_row["Close"][0]),
|
|
435
|
-
"ask": float(first_row["Close"][0]),
|
|
436
|
-
"datetime": first_row_datetime,
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
def write_data_to_file_path(self, data_file, data: polars.DataFrame):
|
|
440
|
-
data.write_csv(data_file)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
class CCXTOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
444
|
-
"""
|
|
445
|
-
CCXTOHLCVMarketDataSource implementation of OHLCVMarketDataSource using
|
|
446
|
-
ccxt to download all ohlcv data sources.
|
|
447
|
-
"""
|
|
448
|
-
|
|
449
|
-
def get_data(
|
|
450
|
-
self,
|
|
451
|
-
start_date: datetime = None,
|
|
452
|
-
end_date: datetime = None,
|
|
453
|
-
config=None,
|
|
454
|
-
):
|
|
455
|
-
"""
|
|
456
|
-
Implementation of get_data for CCXTOHLCVMarketDataSource.
|
|
457
|
-
This implementation uses the CCXTMarketService to get the OHLCV data.
|
|
458
|
-
|
|
459
|
-
Args:
|
|
460
|
-
start_date: datetime (optional) - the start date of the data. The
|
|
461
|
-
first candle stick should close to this date.
|
|
462
|
-
end_date: datetime (optional) - the end date of the data. The last
|
|
463
|
-
candle stick should close to this date.
|
|
464
|
-
storage_path: string (optional) - the storage path specifies the
|
|
465
|
-
directory where the data is written to or read from.
|
|
466
|
-
If set the data provider will write all its downloaded data
|
|
467
|
-
to this location. Also, it will check if the
|
|
468
|
-
data already exists at the storage location. If this is the
|
|
469
|
-
case it will return this.
|
|
470
|
-
|
|
471
|
-
Returns
|
|
472
|
-
polars.DataFrame with the OHLCV data
|
|
473
|
-
"""
|
|
474
|
-
market_service = CCXTMarketService(
|
|
475
|
-
market_credential_service=self.market_credential_service,
|
|
476
|
-
)
|
|
477
|
-
|
|
478
|
-
# Add config if present
|
|
479
|
-
if self.config is not None:
|
|
480
|
-
market_service.config = self.config
|
|
481
|
-
|
|
482
|
-
# Calculate the start and end dates
|
|
483
|
-
if start_date is None or end_date is None:
|
|
484
|
-
|
|
485
|
-
if start_date is None:
|
|
486
|
-
|
|
487
|
-
if end_date is None:
|
|
488
|
-
end_date = datetime.now(tz=timezone.utc)
|
|
489
|
-
|
|
490
|
-
if self.window_size is None:
|
|
491
|
-
raise OperationalException(
|
|
492
|
-
"Window_size should be defined before the " +
|
|
493
|
-
"get_data method can be called. Make sure to set " +
|
|
494
|
-
"the window_size attribute on your " +
|
|
495
|
-
"CCXTOHLCVMarketDataSource or provide a start_date " +
|
|
496
|
-
"and end_date to the get_data method."
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
start_date = self.create_start_date(
|
|
500
|
-
end_date=end_date,
|
|
501
|
-
time_frame=self.time_frame,
|
|
502
|
-
window_size=self.window_size
|
|
503
|
-
)
|
|
504
|
-
else:
|
|
505
|
-
end_date = self.create_end_date(
|
|
506
|
-
start_date=start_date,
|
|
507
|
-
time_frame=self.time_frame,
|
|
508
|
-
window_size=self.window_size
|
|
509
|
-
)
|
|
510
|
-
|
|
511
|
-
storage_path = self.get_storage_path()
|
|
512
|
-
|
|
513
|
-
logger.info(
|
|
514
|
-
f"Getting OHLCV data for {self.symbol} " +
|
|
515
|
-
f"from {start_date} to {end_date}"
|
|
516
|
-
)
|
|
517
|
-
data = None
|
|
518
|
-
|
|
519
|
-
if storage_path is not None:
|
|
520
|
-
# Check if data is already in storage
|
|
521
|
-
data = self._get_data_from_storage(
|
|
522
|
-
storage_path=storage_path,
|
|
523
|
-
symbol=self.symbol,
|
|
524
|
-
time_frame=self.time_frame,
|
|
525
|
-
from_timestamp=start_date,
|
|
526
|
-
to_timestamp=end_date,
|
|
527
|
-
market=self.market,
|
|
528
|
-
)
|
|
529
|
-
|
|
530
|
-
if data is None:
|
|
531
|
-
# Get the OHLCV data from the ccxt market service
|
|
532
|
-
data = market_service.get_ohlcv(
|
|
533
|
-
symbol=self.symbol,
|
|
534
|
-
time_frame=self.time_frame,
|
|
535
|
-
from_timestamp=start_date,
|
|
536
|
-
to_timestamp=end_date,
|
|
537
|
-
market=self.market
|
|
538
|
-
)
|
|
539
|
-
|
|
540
|
-
# if storage path is set, write the data to the storage path
|
|
541
|
-
if storage_path is not None:
|
|
542
|
-
self.write_data_to_storage(
|
|
543
|
-
data=data,
|
|
544
|
-
storage_path=storage_path,
|
|
545
|
-
symbol=self.symbol,
|
|
546
|
-
time_frame=self.time_frame,
|
|
547
|
-
from_timestamp=start_date,
|
|
548
|
-
to_timestamp=end_date,
|
|
549
|
-
market=self.market,
|
|
550
|
-
data_type="OHLCV"
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
return data
|
|
554
|
-
|
|
555
|
-
def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
|
|
556
|
-
|
|
557
|
-
if self.window_size is None:
|
|
558
|
-
raise OperationalException(
|
|
559
|
-
"Window_size should be defined before the " +
|
|
560
|
-
"CCXTOHLCVMarketDataSource can be converted to " +
|
|
561
|
-
"a backtest market data source. Make sure to set " +
|
|
562
|
-
"the window_size attribute on your CCXTOHLCVMarketDataSource"
|
|
563
|
-
)
|
|
564
|
-
|
|
565
|
-
return CCXTOHLCVBacktestMarketDataSource(
|
|
566
|
-
identifier=self.identifier,
|
|
567
|
-
market=self.market,
|
|
568
|
-
symbol=self.symbol,
|
|
569
|
-
time_frame=self.time_frame,
|
|
570
|
-
window_size=self.window_size
|
|
571
|
-
)
|
|
572
|
-
|
|
573
|
-
def _get_data_from_storage(
|
|
574
|
-
self,
|
|
575
|
-
storage_path,
|
|
576
|
-
symbol,
|
|
577
|
-
time_frame,
|
|
578
|
-
from_timestamp,
|
|
579
|
-
to_timestamp,
|
|
580
|
-
market
|
|
581
|
-
):
|
|
582
|
-
"""
|
|
583
|
-
Function to get data from the storage path:
|
|
584
|
-
|
|
585
|
-
Parameters:
|
|
586
|
-
storage_path: string - the storage path where the
|
|
587
|
-
data should be in.
|
|
588
|
-
|
|
589
|
-
Return:
|
|
590
|
-
Polars dataframe.
|
|
591
|
-
"""
|
|
592
|
-
|
|
593
|
-
if not os.path.isdir(storage_path):
|
|
594
|
-
return None
|
|
595
|
-
|
|
596
|
-
if not os.path.isdir(storage_path):
|
|
597
|
-
return None
|
|
598
|
-
|
|
599
|
-
for filename in os.listdir(storage_path):
|
|
600
|
-
path = os.path.join(storage_path, filename)
|
|
601
|
-
|
|
602
|
-
if os.path.isfile(path) or path.split('.')[-1] != ".csv":
|
|
603
|
-
continue
|
|
604
|
-
|
|
605
|
-
file_name_symbol = self.get_file_name_symbol(path)
|
|
606
|
-
file_name_market = self.get_file_name_market(path)
|
|
607
|
-
file_name_time_frame = self.get_file_name_time_frame(path)
|
|
608
|
-
file_name_start_date = self.get_file_name_start_date(path)
|
|
609
|
-
file_name_end_date = self.get_file_name_end_date(path)
|
|
610
|
-
|
|
611
|
-
if file_name_symbol == symbol \
|
|
612
|
-
and file_name_market == market \
|
|
613
|
-
and file_name_time_frame == time_frame \
|
|
614
|
-
and file_name_start_date >= from_timestamp \
|
|
615
|
-
and file_name_end_date <= to_timestamp:
|
|
616
|
-
return polars.read_csv(path)
|
|
617
|
-
|
|
618
|
-
return None
|
|
619
|
-
|
|
620
|
-
def write_data_to_storage(
|
|
621
|
-
self,
|
|
622
|
-
data: polars.DataFrame,
|
|
623
|
-
storage_path,
|
|
624
|
-
symbol,
|
|
625
|
-
time_frame,
|
|
626
|
-
from_timestamp,
|
|
627
|
-
to_timestamp,
|
|
628
|
-
market,
|
|
629
|
-
data_type="OHLCV"
|
|
630
|
-
):
|
|
631
|
-
"""
|
|
632
|
-
Function to write data to the storage path:
|
|
633
|
-
|
|
634
|
-
Parameters:
|
|
635
|
-
data: polars.DataFrame - the data that should be written to the
|
|
636
|
-
storage path.
|
|
637
|
-
storage_path: string - the storage path where the data should
|
|
638
|
-
be written to.
|
|
639
|
-
symbol: string - the symbol of the data.
|
|
640
|
-
time_frame: string - the time_frame of the data.
|
|
641
|
-
from_timestamp: datetime - the start date of the data.
|
|
642
|
-
to_timestamp: datetime - the end date of the data.
|
|
643
|
-
market: string - the market of the data.
|
|
644
|
-
|
|
645
|
-
Return:
|
|
646
|
-
None
|
|
647
|
-
"""
|
|
648
|
-
|
|
649
|
-
if not os.path.isdir(storage_path):
|
|
650
|
-
os.mkdir(storage_path)
|
|
651
|
-
|
|
652
|
-
file_path = self.create_storage_file_path(
|
|
653
|
-
storage_path=storage_path,
|
|
654
|
-
symbol=symbol,
|
|
655
|
-
time_frame=time_frame,
|
|
656
|
-
start_datetime=from_timestamp,
|
|
657
|
-
end_datetime=to_timestamp,
|
|
658
|
-
market=market,
|
|
659
|
-
data_type=data_type
|
|
660
|
-
)
|
|
661
|
-
|
|
662
|
-
if os.path.isfile(file_path):
|
|
663
|
-
return
|
|
664
|
-
|
|
665
|
-
else:
|
|
666
|
-
try:
|
|
667
|
-
with open(file_path, 'w') as _:
|
|
668
|
-
pass
|
|
669
|
-
except Exception as e:
|
|
670
|
-
logger.error(e)
|
|
671
|
-
raise OperationalException(
|
|
672
|
-
f"Could not create data file {file_path}"
|
|
673
|
-
)
|
|
674
|
-
|
|
675
|
-
data.write_csv(file_path)
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
class CCXTOrderBookMarketDataSource(OrderBookMarketDataSource):
|
|
679
|
-
|
|
680
|
-
def get_data(
|
|
681
|
-
self,
|
|
682
|
-
start_date: datetime = None,
|
|
683
|
-
end_date: datetime = None,
|
|
684
|
-
config=None,
|
|
685
|
-
):
|
|
686
|
-
market_service = CCXTMarketService(
|
|
687
|
-
market_credential_service=self.market_credential_service
|
|
688
|
-
)
|
|
689
|
-
market_service.config = self.config
|
|
690
|
-
return market_service.get_order_book(
|
|
691
|
-
symbol=self.symbol, market=self.market
|
|
692
|
-
)
|
|
693
|
-
|
|
694
|
-
def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
|
|
695
|
-
pass
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
class CCXTTickerMarketDataSource(TickerMarketDataSource):
|
|
699
|
-
|
|
700
|
-
def __init__(
|
|
701
|
-
self,
|
|
702
|
-
market,
|
|
703
|
-
identifier=None,
|
|
704
|
-
symbol=None,
|
|
705
|
-
backtest_time_frame=None,
|
|
706
|
-
):
|
|
707
|
-
super().__init__(
|
|
708
|
-
identifier=identifier,
|
|
709
|
-
market=market,
|
|
710
|
-
symbol=symbol,
|
|
711
|
-
)
|
|
712
|
-
self._backtest_time_frame = backtest_time_frame
|
|
713
|
-
|
|
714
|
-
def get_data(
|
|
715
|
-
self,
|
|
716
|
-
start_date: datetime = None,
|
|
717
|
-
end_date: datetime = None,
|
|
718
|
-
config=None,
|
|
719
|
-
):
|
|
720
|
-
market_service = CCXTMarketService(
|
|
721
|
-
market_credential_service=self.market_credential_service
|
|
722
|
-
)
|
|
723
|
-
market_service.config = self.config
|
|
724
|
-
market = self.market
|
|
725
|
-
|
|
726
|
-
market_service.market = market
|
|
727
|
-
symbol = self.symbol
|
|
728
|
-
return market_service.get_ticker(symbol=symbol, market=market)
|
|
729
|
-
|
|
730
|
-
def to_backtest_market_data_source(self) -> BacktestMarketDataSource:
|
|
731
|
-
|
|
732
|
-
if self._backtest_time_frame is None:
|
|
733
|
-
raise OperationalException(
|
|
734
|
-
"Backtest time frame should be defined before the " +
|
|
735
|
-
"CCXTTickerMarketDataSource can be converted to " +
|
|
736
|
-
"a backtest market data source. Make sure to set " +
|
|
737
|
-
"the backtest_time_frame attribute on your " +
|
|
738
|
-
"CCXTTickerMarketDataSource"
|
|
739
|
-
)
|
|
740
|
-
|
|
741
|
-
return CCXTTickerBacktestMarketDataSource(
|
|
742
|
-
identifier=self.identifier,
|
|
743
|
-
market=self.market,
|
|
744
|
-
symbol=self.symbol,
|
|
745
|
-
time_frame=self._backtest_time_frame,
|
|
746
|
-
)
|