def fetch_ohlcv_dataframe(self, symbol, timeframe='1m', since=None, limit=None, params={}): # Exchanges in the real world have different behaviour, when there is # no since parameter provided. (some use data from the beginning, # some from the end) # We return data from the beginning, because this is most likely not # what the user wants, so this will force the user to provide the # parameters, which will work with every exchange. This is a bug # prevention mechanism. ohlcv = self._ohlcvs.get(symbol) if ohlcv is None: raise BadSymbol('ExchangeBackend: no prices for {}'.format(symbol)) pd_current_date = self._timeframe.date().floor('1T') if limit is None: limit = 5 timeframe_sec = Exchange.parse_timeframe(timeframe) pd_timeframe = pandas.Timedelta(timeframe_sec, unit='s') ohlcv_start_date = ohlcv.index[0] if since is None: pd_since = ohlcv_start_date else: pd_since = pandas.Timestamp(since, unit='ms', tz='UTC') pd_since = pd_since.ceil(pd_timeframe) if pd_since < ohlcv_start_date: raise BadRequest('ExchangeBackend: fetch_ohlcv: no date availabe ' 'at since') pd_until = pd_since + limit * pd_timeframe - pandas.Timedelta('1m') if pd_until >= pd_current_date + pd_timeframe: raise BadRequest('ExchangeBackend: fetch_ohlcv:' ' since.ceil(timeframe) + limit * timeframe' ' needs to be in the past') pd_until = min(pd_until, pd_current_date) data = ohlcv[pd_since:pd_until] return data.resample(pd_timeframe).agg({ 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last', 'volume': 'sum' })
def parse_params_and_execute_algorithm(AlgorithmClass): parser = argparse.ArgumentParser( epilog=HELP_EPILOG, formatter_class=argparse.RawTextHelpFormatter) parser.add_argument('--start-date', default='', help='Date to start backtesting, ignored in live mode') parser.add_argument('--end-date', default='2009-01-01', help='Date to end backtesting') parser.add_argument('--interval', default='1m', help='Timedelta between each iteration') parser.add_argument('--exchanges', default='', help='Exchange ids comma separated to load ohlcv') parser.add_argument('--symbols', default='', help='Symbols (comma separated) to load ohlcv ' 'per exchange') parser.add_argument('--data-directory', default=USER_DATA_DIR, help='directory where data is stored' ' (e.g. ohlcv data') parser.add_argument('--config-directory', default=USER_CONFIG_DIR, help='directory where config is stored' ' (e.g. exchange parameters') parser.add_argument('--auth-aliases', default='{}', help='Auth aliases for different exchange' ' config files') parser.add_argument('--live', action='store_true', help='Trade live on exchanges') parser.add_argument('--start-balances', default='{}', help='Balance at start (json): ' '{"exchange": {"BTC": 3}}') AlgorithmClass.configure_argparser(parser) args = parser.parse_args() logger = logging.getLogger(__package__) def split_parameters(p): if p == '': return [] return p.split(',') exchange_names = split_parameters(args.exchanges) symbols = split_parameters(args.symbols) if not args.live: if len(exchange_names) == 0: logger.warning('No exchanges specified, do not load ohlcv') if len(symbols) == 0: logger.warning('No symbols specified, load all ohlcvs per each ' 'exchange. This can lead to long start times') try: pd_interval = pandas.Timedelta( Exchange.parse_timeframe(args.interval), unit='s') except (NotSupported, ValueError): raise ValueError('Interval is not valid') auth_aliases = {} if args.live: if args.start_date != '': raise ValueError('Start date cannot be set in live mode') if args.start_balances != '{}': raise ValueError('Start balance cannot be set in live mode') pd_start_date = pandas.Timestamp.now(tz='UTC').floor(pd_interval) start_balances = None auth_aliases = json.loads(args.auth_aliases) else: pd_start_date = pandas.to_datetime(args.start_date, utc=True) start_balances = json.loads(args.start_balances) pd_end_date = pandas.to_datetime(args.end_date, utc=True) if pandas.isnull(pd_start_date): raise ValueError('Start date is not valid') if pandas.isnull(pd_end_date): raise ValueError('End date is not valid') return execute_algorithm(exchange_names=exchange_names, symbols=symbols, pd_start_date=pd_start_date, pd_end_date=pd_end_date, pd_interval=pd_interval, conf_dir=args.config_directory, data_dir=args.data_directory, AlgorithmClass=AlgorithmClass, args=args, auth_aliases=auth_aliases, live=args.live, start_balances=start_balances)