diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index beea3e507..bac20c054 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -14,6 +14,7 @@ from freqtrade.configuration.directory_operations import create_datadir, create_ from freqtrade.configuration.environment_vars import enironment_vars_to_dict from freqtrade.configuration.load_config import load_config_file, load_file from freqtrade.enums import NON_UTIL_MODES, TRADING_MODES, RunMode +from freqtrade.enums.candletype import CandleType from freqtrade.exceptions import OperationalException from freqtrade.loggers import setup_logging from freqtrade.misc import deep_merge_dicts, parse_db_uri_for_logging @@ -433,6 +434,7 @@ class Configuration: logstring='Detected --new-pairs-days: {}') self._args_to_config(config, argname='trading_mode', logstring='Detected --trading-mode: {}') + config['candle_type_def'] = CandleType.get_default(config.get('trading_mode', 'spot')) self._args_to_config(config, argname='candle_types', logstring='Detected --candle-types: {}') diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index 793c8b839..4e9ac9dcf 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -260,7 +260,7 @@ def refresh_backtest_ohlcv_data(exchange: Exchange, pairs: List[str], timeframes """ pairs_not_available = [] data_handler = get_datahandler(datadir, data_format) - candle_type = CandleType.FUTURES if trading_mode == 'futures' else CandleType.SPOT_ + candle_type = CandleType.get_default(trading_mode) for idx, pair in enumerate(pairs, start=1): if pair not in exchange.markets: pairs_not_available.append(pair) diff --git a/freqtrade/plugins/pairlist/AgeFilter.py b/freqtrade/plugins/pairlist/AgeFilter.py index 7c490d920..f5507d0a6 100644 --- a/freqtrade/plugins/pairlist/AgeFilter.py +++ b/freqtrade/plugins/pairlist/AgeFilter.py @@ -10,7 +10,6 @@ from pandas import DataFrame from freqtrade.configuration import PeriodicCache from freqtrade.constants import ListPairsWithTimeframes -from freqtrade.enums import CandleType from freqtrade.exceptions import OperationalException from freqtrade.misc import plural from freqtrade.plugins.pairlist.IPairList import IPairList @@ -74,7 +73,7 @@ class AgeFilter(IPairList): :return: new allowlist """ needed_pairs: ListPairsWithTimeframes = [ - (p, '1d', CandleType.SPOT_) for p in pairlist + (p, '1d', self._config['candle_type_def']) for p in pairlist if p not in self._symbolsChecked and p not in self._symbolsCheckFailed] if not needed_pairs: # Remove pairs that have been removed before @@ -90,8 +89,8 @@ class AgeFilter(IPairList): candles = self._exchange.refresh_latest_ohlcv(needed_pairs, since_ms=since_ms, cache=False) if self._enabled: for p in deepcopy(pairlist): - daily_candles = candles[(p, '1d', CandleType.SPOT_)] if ( - p, '1d', CandleType.SPOT_) in candles else None + daily_candles = candles[(p, '1d', self._config['candle_type_def'])] if ( + p, '1d', self._config['candle_type_def']) in candles else None if not self._validate_pair_loc(p, daily_candles): pairlist.remove(p) self.log_once(f"Validated {len(pairlist)} pairs.", logger.info) diff --git a/freqtrade/plugins/pairlist/VolatilityFilter.py b/freqtrade/plugins/pairlist/VolatilityFilter.py index bdb7a043a..c2dedcdeb 100644 --- a/freqtrade/plugins/pairlist/VolatilityFilter.py +++ b/freqtrade/plugins/pairlist/VolatilityFilter.py @@ -12,7 +12,6 @@ from cachetools.ttl import TTLCache from pandas import DataFrame from freqtrade.constants import ListPairsWithTimeframes -from freqtrade.enums import CandleType from freqtrade.exceptions import OperationalException from freqtrade.misc import plural from freqtrade.plugins.pairlist.IPairList import IPairList @@ -70,7 +69,7 @@ class VolatilityFilter(IPairList): :return: new allowlist """ needed_pairs: ListPairsWithTimeframes = [ - (p, '1d', CandleType.SPOT_) for p in pairlist if p not in self._pair_cache] + (p, '1d', self._config['candle_type_def']) for p in pairlist if p not in self._pair_cache] since_ms = (arrow.utcnow() .floor('day') @@ -84,8 +83,8 @@ class VolatilityFilter(IPairList): if self._enabled: for p in deepcopy(pairlist): - daily_candles = candles[(p, '1d', CandleType.SPOT_)] if ( - p, '1d', CandleType.SPOT_) in candles else None + daily_candles = candles[(p, '1d', self._config['candle_type_def'])] if ( + p, '1d', self._config['candle_type_def']) in candles else None if not self._validate_pair_loc(p, daily_candles): pairlist.remove(p) return pairlist diff --git a/freqtrade/plugins/pairlist/VolumePairList.py b/freqtrade/plugins/pairlist/VolumePairList.py index b81a5db5c..ca9771516 100644 --- a/freqtrade/plugins/pairlist/VolumePairList.py +++ b/freqtrade/plugins/pairlist/VolumePairList.py @@ -11,7 +11,6 @@ import arrow from cachetools.ttl import TTLCache from freqtrade.constants import ListPairsWithTimeframes -from freqtrade.enums import CandleType from freqtrade.exceptions import OperationalException from freqtrade.exchange import timeframe_to_minutes from freqtrade.misc import format_ms_time @@ -45,6 +44,7 @@ class VolumePairList(IPairList): self._lookback_days = self._pairlistconfig.get('lookback_days', 0) self._lookback_timeframe = self._pairlistconfig.get('lookback_timeframe', '1d') self._lookback_period = self._pairlistconfig.get('lookback_period', 0) + self._def_candletype = self._config['candle_type_def'] if (self._lookback_days > 0) & (self._lookback_period > 0): raise OperationalException( @@ -162,7 +162,7 @@ class VolumePairList(IPairList): f"{self._lookback_timeframe}, starting from {format_ms_time(since_ms)} " f"till {format_ms_time(to_ms)}", logger.info) needed_pairs: ListPairsWithTimeframes = [ - (p, self._lookback_timeframe, CandleType.SPOT_) for p in + (p, self._lookback_timeframe, self._def_candletype) for p in [s['symbol'] for s in filtered_tickers] if p not in self._pair_cache ] @@ -175,8 +175,10 @@ class VolumePairList(IPairList): ) for i, p in enumerate(filtered_tickers): pair_candles = candles[ - (p['symbol'], self._lookback_timeframe, CandleType.SPOT_) - ] if (p['symbol'], self._lookback_timeframe, CandleType.SPOT_) in candles else None + (p['symbol'], self._lookback_timeframe, self._def_candletype) + ] if ( + p['symbol'], self._lookback_timeframe, self._def_candletype + ) in candles else None # in case of candle data calculate typical price and quoteVolume for candle if pair_candles is not None and not pair_candles.empty: pair_candles['typical_price'] = (pair_candles['high'] + pair_candles['low'] diff --git a/freqtrade/plugins/pairlist/rangestabilityfilter.py b/freqtrade/plugins/pairlist/rangestabilityfilter.py index 3e90400a6..7a4aa772a 100644 --- a/freqtrade/plugins/pairlist/rangestabilityfilter.py +++ b/freqtrade/plugins/pairlist/rangestabilityfilter.py @@ -10,7 +10,6 @@ from cachetools.ttl import TTLCache from pandas import DataFrame from freqtrade.constants import ListPairsWithTimeframes -from freqtrade.enums import CandleType from freqtrade.exceptions import OperationalException from freqtrade.misc import plural from freqtrade.plugins.pairlist.IPairList import IPairList @@ -68,7 +67,7 @@ class RangeStabilityFilter(IPairList): :return: new allowlist """ needed_pairs: ListPairsWithTimeframes = [ - (p, '1d', CandleType.SPOT_) for p in pairlist if p not in self._pair_cache] + (p, '1d', self._config['candle_type_def']) for p in pairlist if p not in self._pair_cache] since_ms = (arrow.utcnow() .floor('day') @@ -82,8 +81,8 @@ class RangeStabilityFilter(IPairList): if self._enabled: for p in deepcopy(pairlist): - daily_candles = candles[(p, '1d', CandleType.SPOT_)] if ( - p, '1d', CandleType.SPOT_) in candles else None + daily_candles = candles[(p, '1d', self._config['candle_type_def'])] if ( + p, '1d', self._config['candle_type_def']) in candles else None if not self._validate_pair_loc(p, daily_candles): pairlist.remove(p) return pairlist diff --git a/freqtrade/strategy/informative_decorator.py b/freqtrade/strategy/informative_decorator.py index 2085630cb..40e9a7b47 100644 --- a/freqtrade/strategy/informative_decorator.py +++ b/freqtrade/strategy/informative_decorator.py @@ -15,7 +15,7 @@ class InformativeData(NamedTuple): timeframe: str fmt: Union[str, Callable[[Any], str], None] ffill: bool - candle_type: CandleType = CandleType.SPOT_ + candle_type: CandleType def informative(timeframe: str, asset: str = '', @@ -58,7 +58,8 @@ def informative(timeframe: str, asset: str = '', def decorator(fn: PopulateIndicators): informative_pairs = getattr(fn, '_ft_informative', []) # TODO-lev: Add candle_type to InformativeData - informative_pairs.append(InformativeData(_asset, _timeframe, _fmt, _ffill)) + informative_pairs.append(InformativeData(_asset, _timeframe, _fmt, _ffill, + CandleType.SPOT_)) setattr(fn, '_ft_informative', informative_pairs) return fn return decorator diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 7c3fd60f1..62acc3ac6 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -424,7 +424,8 @@ class IStrategy(ABC, HyperStrategyMixin): informative_pairs = self.informative_pairs() # Compatibility code for 2 tuple informative pairs informative_pairs = [ - (p[0], p[1], CandleType.from_string(p[2]) if len(p) > 2 else CandleType.SPOT_) + (p[0], p[1], CandleType.from_string(p[2]) if len( + p) > 2 else self.config['candle_type_def']) for p in informative_pairs] for inf_data, _ in self._ft_informative: if inf_data.asset: @@ -530,8 +531,9 @@ class IStrategy(ABC, HyperStrategyMixin): dataframe = self.analyze_ticker(dataframe, metadata) self._last_candle_seen_per_pair[pair] = dataframe.iloc[-1]['date'] if self.dp: - self.dp._set_cached_df(pair, self.timeframe, dataframe, CandleType.SPOT_) - # TODO-lev: CandleType should be set conditionally + self.dp._set_cached_df( + pair, self.timeframe, dataframe, + candle_type=self.config['candle_type_def']) else: logger.debug("Skipping TA Analysis for already analyzed candle") dataframe[SignalType.ENTER_LONG.value] = 0 diff --git a/tests/conftest.py b/tests/conftest.py index 38ef35abb..e60c441b7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,6 +19,7 @@ from freqtrade.commands import Arguments from freqtrade.data.converter import ohlcv_to_dataframe from freqtrade.edge import PairInfo from freqtrade.enums import Collateral, RunMode, TradingMode +from freqtrade.enums.candletype import CandleType from freqtrade.enums.signaltype import SignalDirection from freqtrade.exchange import Exchange from freqtrade.freqtradebot import FreqtradeBot @@ -459,6 +460,7 @@ def get_default_conf(testdatadir): "disableparamexport": True, "internals": {}, "export": "none", + "candle_type_def": CandleType.SPOT, } return configuration