From 7a34578b4da58c0f80523f0a9db10836e67a532f Mon Sep 17 00:00:00 2001 From: xmatthias Date: Tue, 5 Jun 2018 23:34:26 +0200 Subject: [PATCH] refactor timerange to named tuple --- freqtrade/arguments.py | 21 ++++++++----- freqtrade/optimize/__init__.py | 51 ++++++++++++++++--------------- freqtrade/optimize/backtesting.py | 2 +- freqtrade/optimize/hyperopt.py | 2 +- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/freqtrade/arguments.py b/freqtrade/arguments.py index d79a52af2..bf5abb8ee 100644 --- a/freqtrade/arguments.py +++ b/freqtrade/arguments.py @@ -7,11 +7,19 @@ import argparse import logging import re import arrow -from typing import List, Tuple, Optional +from typing import List, Optional, NamedTuple from freqtrade import __version__, constants +class TimeRange(NamedTuple): + + starttype: Optional[str] = None + stoptype: Optional[str] = None + startts: int = 0 + stopts: int = 0 + + class Arguments(object): """ Arguments Class. Manage the arguments received by the cli @@ -222,15 +230,14 @@ class Arguments(object): self.hyperopt_options(hyperopt_cmd) @staticmethod - def parse_timerange(text: Optional[str]) -> \ - Optional[Tuple[Tuple, Optional[int], Optional[int]]]: + def parse_timerange(text: Optional[str]) -> TimeRange: """ Parse the value of the argument --timerange to determine what is the range desired :param text: value from --timerange :return: Start and End range period """ if text is None: - return None + return TimeRange() syntax = [(r'^-(\d{8})$', (None, 'date')), (r'^(\d{8})-$', ('date', None)), (r'^(\d{8})-(\d{8})$', ('date', 'date')), @@ -246,8 +253,8 @@ class Arguments(object): if match: # Regex has matched rvals = match.groups() index = 0 - start: Optional[int] = None - stop: Optional[int] = None + start: int = 0 + stop: int = 0 if stype[0]: starts = rvals[index] if stype[0] == 'date': @@ -263,7 +270,7 @@ class Arguments(object): else arrow.get(stops, 'YYYYMMDD').timestamp else: stop = int(stops) - return stype, start, stop + return TimeRange(stype[0], stype[1], start, stop) raise Exception('Incorrect syntax for timerange "%s"' % text) def scripts_options(self) -> None: diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py index 711adfd28..dc48a64ec 100644 --- a/freqtrade/optimize/__init__.py +++ b/freqtrade/optimize/__init__.py @@ -9,39 +9,40 @@ import arrow from freqtrade import misc, constants from freqtrade.exchange import get_ticker_history +from freqtrade.arguments import TimeRange from user_data.hyperopt_conf import hyperopt_optimize_conf logger = logging.getLogger(__name__) -def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) -> List[Dict]: +def trim_tickerlist(tickerlist: List[Dict], timerange: TimeRange) -> List[Dict]: if not tickerlist: return tickerlist - stype, start, stop = timerange - start_index = 0 stop_index = len(tickerlist) - if stype[0] == 'line': - stop_index = start - if stype[0] == 'index': - start_index = start - elif stype[0] == 'date': - while start_index < len(tickerlist) and tickerlist[start_index][0] < start * 1000: + if timerange.starttype == 'line': + stop_index = timerange.startts + if timerange.starttype == 'index': + start_index = timerange.startts + elif timerange.starttype == 'date': + while (start_index < len(tickerlist) and + tickerlist[start_index][0] < timerange.startts * 1000): start_index += 1 - if stype[1] == 'line': - start_index = len(tickerlist) + stop - if stype[1] == 'index': - stop_index = stop - elif stype[1] == 'date': - while stop_index > 0 and tickerlist[stop_index-1][0] > stop * 1000: + if timerange.stoptype == 'line': + start_index = len(tickerlist) + timerange.stopts + if timerange.stoptype == 'index': + stop_index = timerange.stopts + elif timerange.stoptype == 'date': + while (stop_index > 0 and + tickerlist[stop_index-1][0] > timerange.stopts * 1000): stop_index -= 1 if start_index > stop_index: - raise ValueError(f'The timerange [{start},{stop}] is incorrect') + raise ValueError(f'The timerange [{timerange.startts},{timerange.stopts}] is incorrect') return tickerlist[start_index:stop_index] @@ -49,7 +50,7 @@ def trim_tickerlist(tickerlist: List[Dict], timerange: Tuple[Tuple, int, int]) - def load_tickerdata_file( datadir: str, pair: str, ticker_interval: str, - timerange: Optional[Tuple[Tuple, int, int]] = None) -> Optional[List[Dict]]: + timerange: TimeRange) -> Optional[List[Dict]]: """ Load a pair from file, :return dict OR empty if unsuccesful @@ -84,7 +85,7 @@ def load_data(datadir: str, ticker_interval: str, pairs: Optional[List[str]] = None, refresh_pairs: Optional[bool] = False, - timerange: Optional[Tuple[Tuple, int, int]] = None) -> Dict[str, List]: + timerange: TimeRange = TimeRange()) -> Dict[str, List]: """ Loads ticker history data for the given parameters :return: dict @@ -124,7 +125,7 @@ def make_testdata_path(datadir: str) -> str: def download_pairs(datadir, pairs: List[str], ticker_interval: str, - timerange: Optional[Tuple[Tuple, int, int]] = None) -> bool: + timerange: TimeRange = TimeRange()) -> bool: """For each pairs passed in parameters, download the ticker intervals""" for pair in pairs: try: @@ -144,7 +145,7 @@ def download_pairs(datadir, pairs: List[str], def load_cached_data_for_updating(filename: str, tick_interval: str, - timerange: Optional[Tuple[Tuple, int, int]]) -> Tuple[ + timerange: Optional[TimeRange]) -> Tuple[ List[Any], Optional[int]]: """ @@ -155,10 +156,10 @@ def load_cached_data_for_updating(filename: str, # user sets timerange, so find the start time if timerange: - if timerange[0][0] == 'date': - since_ms = timerange[1] * 1000 - elif timerange[0][1] == 'line': - num_minutes = timerange[2] * constants.TICKER_INTERVAL_MINUTES[tick_interval] + if timerange.starttype == 'date': + since_ms = timerange.startts * 1000 + elif timerange.stoptype == 'line': + num_minutes = timerange.stopts * constants.TICKER_INTERVAL_MINUTES[tick_interval] since_ms = arrow.utcnow().shift(minutes=num_minutes).timestamp * 1000 # read the cached file @@ -188,7 +189,7 @@ def load_cached_data_for_updating(filename: str, def download_backtesting_testdata(datadir: str, pair: str, tick_interval: str = '5m', - timerange: Optional[Tuple[Tuple, int, int]] = None) -> None: + timerange: Optional[TimeRange] = None) -> None: """ Download the latest ticker intervals from the exchange for the pairs passed in parameters diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index d7ed45955..3dd643561 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -221,7 +221,7 @@ class Backtesting(object): timerange = Arguments.parse_timerange(None if self.config.get( 'timerange') is None else str(self.config.get('timerange'))) - data = optimize.load_data( # type: ignore # timerange will be refactored + data = optimize.load_data( self.config['datadir'], pairs=pairs, ticker_interval=self.ticker_interval, diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 74b39b445..878acc2dc 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -497,7 +497,7 @@ class Hyperopt(Backtesting): def start(self) -> None: timerange = Arguments.parse_timerange(None if self.config.get( 'timerange') is None else str(self.config.get('timerange'))) - data = load_data( # type: ignore # timerange will be refactored + data = load_data( datadir=str(self.config.get('datadir')), pairs=self.config['exchange']['pair_whitelist'], ticker_interval=self.ticker_interval,