diff --git a/freqtrade/data/converter.py b/freqtrade/data/converter.py index dfd4a9f68..680b95ab2 100644 --- a/freqtrade/data/converter.py +++ b/freqtrade/data/converter.py @@ -11,6 +11,7 @@ import pandas as pd from pandas import DataFrame, to_datetime from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS, TradeList +from freqtrade.enums.candletype import CandleType logger = logging.getLogger(__name__) @@ -266,7 +267,7 @@ def convert_ohlcv_format( convert_from: str, convert_to: str, erase: bool, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT_ ): """ Convert OHLCV from one format to another diff --git a/freqtrade/data/history/hdf5datahandler.py b/freqtrade/data/history/hdf5datahandler.py index 906a7ea6c..35e01f279 100644 --- a/freqtrade/data/history/hdf5datahandler.py +++ b/freqtrade/data/history/hdf5datahandler.py @@ -51,7 +51,7 @@ class HDF5DataHandler(IDataHandler): for the specified timeframe :param datadir: Directory to search for ohlcv files :param timeframe: Timeframe to search pairs for - :param candle_type: Any of the enum CandleType (must match your trading mode!) + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: List of Pairs """ candle = "" @@ -69,14 +69,14 @@ class HDF5DataHandler(IDataHandler): pair: str, timeframe: str, data: pd.DataFrame, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT_ ) -> None: """ Store data in hdf5 file. :param pair: Pair - used to generate filename :param timeframe: Timeframe - used to generate filename :param data: Dataframe containing OHLCV data - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: None """ key = self._pair_ohlcv_key(pair, timeframe) @@ -90,7 +90,9 @@ class HDF5DataHandler(IDataHandler): ) def _ohlcv_load(self, pair: str, timeframe: str, - timerange: Optional[TimeRange] = None, candle_type: str = '') -> pd.DataFrame: + timerange: Optional[TimeRange] = None, + candle_type: CandleType = CandleType.SPOT_ + ) -> pd.DataFrame: """ Internal method used to load data for one pair from disk. Implements the loading and conversion to a Pandas dataframe. @@ -100,7 +102,7 @@ class HDF5DataHandler(IDataHandler): :param timerange: Limit data to be loaded to this timerange. Optionally implemented by subclasses to avoid loading all data where possible. - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: DataFrame with ohlcv data, or empty DataFrame """ key = self._pair_ohlcv_key(pair, timeframe) @@ -133,14 +135,14 @@ class HDF5DataHandler(IDataHandler): pair: str, timeframe: str, data: pd.DataFrame, - candle_type: str = '' + candle_type: CandleType ) -> None: """ Append data to existing data structures :param pair: Pair :param timeframe: Timeframe this ohlcv data is for :param data: Data to append. - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) """ raise NotImplementedError() diff --git a/freqtrade/data/history/history_utils.py b/freqtrade/data/history/history_utils.py index 7b0c727c8..3fdb36e58 100644 --- a/freqtrade/data/history/history_utils.py +++ b/freqtrade/data/history/history_utils.py @@ -12,6 +12,7 @@ from freqtrade.constants import DEFAULT_DATAFRAME_COLUMNS from freqtrade.data.converter import (clean_ohlcv_dataframe, ohlcv_to_dataframe, trades_remove_duplicates, trades_to_ohlcv) from freqtrade.data.history.idatahandler import IDataHandler, get_datahandler +from freqtrade.enums.candletype import CandleType from freqtrade.exceptions import OperationalException from freqtrade.exchange import Exchange from freqtrade.misc import format_ms_time @@ -29,7 +30,7 @@ def load_pair_history(pair: str, startup_candles: int = 0, data_format: str = None, data_handler: IDataHandler = None, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT ) -> DataFrame: """ Load cached ohlcv history for the given pair. @@ -44,7 +45,7 @@ def load_pair_history(pair: str, :param startup_candles: Additional candles to load at the start of the period :param data_handler: Initialized data-handler to use. Will be initialized from data_format if not set - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: DataFrame with ohlcv data, or empty DataFrame """ data_handler = get_datahandler(datadir, data_format, data_handler) @@ -67,7 +68,7 @@ def load_data(datadir: Path, startup_candles: int = 0, fail_without_data: bool = False, data_format: str = 'json', - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT ) -> Dict[str, DataFrame]: """ Load ohlcv history data for a list of pairs. @@ -80,7 +81,7 @@ def load_data(datadir: Path, :param startup_candles: Additional candles to load at the start of the period :param fail_without_data: Raise OperationalException if no data is found. :param data_format: Data format which should be used. Defaults to json - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: dict(:) """ result: Dict[str, DataFrame] = {} @@ -111,7 +112,7 @@ def refresh_data(datadir: Path, exchange: Exchange, data_format: str = None, timerange: Optional[TimeRange] = None, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT ) -> None: """ Refresh ohlcv history data for a list of pairs. @@ -122,7 +123,7 @@ def refresh_data(datadir: Path, :param exchange: Exchange object :param data_format: dataformat to use :param timerange: Limit data to be loaded to this timerange - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) """ data_handler = get_datahandler(datadir, data_format) for idx, pair in enumerate(pairs): @@ -138,7 +139,7 @@ def _load_cached_data_for_updating( timeframe: str, timerange: Optional[TimeRange], data_handler: IDataHandler, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT ) -> Tuple[DataFrame, Optional[int]]: """ Load cached data to download more data. @@ -177,7 +178,8 @@ def _download_pair_history(pair: str, *, new_pairs_days: int = 30, data_handler: IDataHandler = None, timerange: Optional[TimeRange] = None, - candle_type: str = '') -> bool: + candle_type: CandleType = CandleType.SPOT + ) -> bool: """ Download latest candles from the exchange for the pair and timeframe passed in parameters The data is downloaded starting from the last correct data that @@ -189,7 +191,7 @@ def _download_pair_history(pair: str, *, :param pair: pair to download :param timeframe: Timeframe (e.g "5m") :param timerange: range of time to download - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: bool with success state """ data_handler = get_datahandler(datadir, data_handler=data_handler) @@ -249,7 +251,8 @@ def refresh_backtest_ohlcv_data(exchange: Exchange, pairs: List[str], timeframes datadir: Path, timerange: Optional[TimeRange] = None, new_pairs_days: int = 30, erase: bool = False, data_format: str = None, - candle_type: str = '') -> List[str]: + candle_type: CandleType = CandleType.SPOT + ) -> List[str]: """ Refresh stored ohlcv data for backtesting and hyperopt operations. Used by freqtrade download-data subcommand. @@ -382,7 +385,7 @@ def convert_trades_to_ohlcv( erase: bool = False, data_format_ohlcv: str = 'json', data_format_trades: str = 'jsongz', - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT ) -> None: """ Convert stored trades data to ohlcv data diff --git a/freqtrade/data/history/idatahandler.py b/freqtrade/data/history/idatahandler.py index dbf93e787..72758a325 100644 --- a/freqtrade/data/history/idatahandler.py +++ b/freqtrade/data/history/idatahandler.py @@ -59,7 +59,7 @@ class IDataHandler(ABC): for the specified timeframe :param datadir: Directory to search for ohlcv files :param timeframe: Timeframe to search pairs for - :param candle_type: Any of the enum CandleType (must match your trading mode!) + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: List of Pairs """ @@ -69,21 +69,20 @@ class IDataHandler(ABC): pair: str, timeframe: str, data: DataFrame, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT_ ) -> None: """ Store ohlcv data. :param pair: Pair - used to generate filename :param timeframe: Timeframe - used to generate filename :param data: Dataframe containing OHLCV data - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: None """ @abstractmethod - def _ohlcv_load(self, pair: str, timeframe: str, - timerange: Optional[TimeRange] = None, - candle_type: str = '' + def _ohlcv_load(self, pair: str, timeframe: str, timerange: Optional[TimeRange] = None, + candle_type: CandleType = CandleType.SPOT_ ) -> DataFrame: """ Internal method used to load data for one pair from disk. @@ -94,16 +93,17 @@ class IDataHandler(ABC): :param timerange: Limit data to be loaded to this timerange. Optionally implemented by subclasses to avoid loading all data where possible. - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: DataFrame with ohlcv data, or empty DataFrame """ - def ohlcv_purge(self, pair: str, timeframe: str, candle_type: str = '') -> bool: + def ohlcv_purge( + self, pair: str, timeframe: str, candle_type: CandleType = CandleType.SPOT_) -> bool: """ Remove data for this pair :param pair: Delete data for this pair. :param timeframe: Timeframe (e.g. "5m") - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: True when deleted, false if file did not exist. """ filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) @@ -118,14 +118,14 @@ class IDataHandler(ABC): pair: str, timeframe: str, data: DataFrame, - candle_type: str = '' + candle_type: CandleType ) -> None: """ Append data to existing data structures :param pair: Pair :param timeframe: Timeframe this ohlcv data is for :param data: Data to append. - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) """ @abstractclassmethod @@ -200,14 +200,15 @@ class IDataHandler(ABC): datadir: Path, pair: str, timeframe: str, - candle_type: str = '' + candle_type: CandleType ) -> Path: pair_s = misc.pair_to_filename(pair) - if candle_type: + candle = "" + if candle_type not in (CandleType.SPOT, CandleType.SPOT_): datadir = datadir.joinpath('futures') - candle_type = f"-{candle_type}" + candle = f"-{candle_type}" filename = datadir.joinpath( - f'{pair_s}-{timeframe}{candle_type}.{cls._get_file_extension()}') + f'{pair_s}-{timeframe}{candle}.{cls._get_file_extension()}') return filename @classmethod @@ -232,7 +233,7 @@ class IDataHandler(ABC): drop_incomplete: bool = True, startup_candles: int = 0, warn_no_data: bool = True, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT_ ) -> DataFrame: """ Load cached candle (OHLCV) data for the given pair. @@ -244,7 +245,7 @@ class IDataHandler(ABC): :param drop_incomplete: Drop last candle assuming it may be incomplete. :param startup_candles: Additional candles to load at the start of the period :param warn_no_data: Log a warning message when no data is found - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: DataFrame with ohlcv data, or empty DataFrame """ # Fix startup period diff --git a/freqtrade/data/history/jsondatahandler.py b/freqtrade/data/history/jsondatahandler.py index 2a8b1093c..1f5439c27 100644 --- a/freqtrade/data/history/jsondatahandler.py +++ b/freqtrade/data/history/jsondatahandler.py @@ -52,7 +52,7 @@ class JsonDataHandler(IDataHandler): for the specified timeframe :param datadir: Directory to search for ohlcv files :param timeframe: Timeframe to search pairs for - :param candle_type: Any of the enum CandleType (must match your trading mode!) + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: List of Pairs """ candle = "" @@ -70,7 +70,7 @@ class JsonDataHandler(IDataHandler): pair: str, timeframe: str, data: DataFrame, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT_ ) -> None: """ Store data in json format "values". @@ -79,7 +79,7 @@ class JsonDataHandler(IDataHandler): :param pair: Pair - used to generate filename :param timeframe: Timeframe - used to generate filename :param data: Dataframe containing OHLCV data - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: None """ filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type) @@ -95,7 +95,7 @@ class JsonDataHandler(IDataHandler): def _ohlcv_load(self, pair: str, timeframe: str, timerange: Optional[TimeRange] = None, - candle_type: str = '' + candle_type: CandleType = CandleType.SPOT_ ) -> DataFrame: """ Internal method used to load data for one pair from disk. @@ -106,7 +106,7 @@ class JsonDataHandler(IDataHandler): :param timerange: Limit data to be loaded to this timerange. Optionally implemented by subclasses to avoid loading all data where possible. - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) :return: DataFrame with ohlcv data, or empty DataFrame """ filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type=candle_type) @@ -126,33 +126,19 @@ class JsonDataHandler(IDataHandler): infer_datetime_format=True) return pairdata - def ohlcv_purge(self, pair: str, timeframe: str, candle_type: str = '') -> bool: - """ - Remove data for this pair - :param pair: Delete data for this pair. - :param timeframe: Timeframe (e.g. "5m") - :param candle_type: '', mark, index, premiumIndex, or funding_rate - :return: True when deleted, false if file did not exist. - """ - filename = self._pair_data_filename(self._datadir, pair, timeframe, candle_type=candle_type) - if filename.exists(): - filename.unlink() - return True - return False - def ohlcv_append( self, pair: str, timeframe: str, data: DataFrame, - candle_type: str = '' + candle_type: CandleType ) -> None: """ Append data to existing data structures :param pair: Pair :param timeframe: Timeframe this ohlcv data is for :param data: Data to append. - :param candle_type: '', mark, index, premiumIndex, or funding_rate + :param candle_type: Any of the enum CandleType (must match trading mode!) """ raise NotImplementedError() diff --git a/tests/data/test_history.py b/tests/data/test_history.py index a36f933c9..7944593c1 100644 --- a/tests/data/test_history.py +++ b/tests/data/test_history.py @@ -24,6 +24,7 @@ from freqtrade.data.history.history_utils import (_download_pair_history, _downl validate_backtest_data) from freqtrade.data.history.idatahandler import IDataHandler, get_datahandler, get_datahandlerclass from freqtrade.data.history.jsondatahandler import JsonDataHandler, JsonGzDataHandler +from freqtrade.enums.candletype import CandleType from freqtrade.exchange import timeframe_to_minutes from freqtrade.misc import file_dump_json from freqtrade.resolvers import StrategyResolver @@ -809,9 +810,9 @@ def test_jsondatahandler_trades_purge(mocker, testdatadir): def test_datahandler_ohlcv_append(datahandler, testdatadir, ): dh = get_datahandler(testdatadir, datahandler) with pytest.raises(NotImplementedError): - dh.ohlcv_append('UNITTEST/ETH', '5m', DataFrame()) + dh.ohlcv_append('UNITTEST/ETH', '5m', DataFrame(), CandleType.SPOT) with pytest.raises(NotImplementedError): - dh.ohlcv_append('UNITTEST/ETH', '5m', DataFrame(), candle_type='mark') + dh.ohlcv_append('UNITTEST/ETH', '5m', DataFrame(), CandleType.MARK) @pytest.mark.parametrize('datahandler', AVAILABLE_DATAHANDLERS)