From 627ab9f583fad5fd9ef5ece90d1fd956d2ff2355 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 11 Dec 2018 19:47:48 +0100 Subject: [PATCH] pass around dataframe instead of list --- freqtrade/exchange/__init__.py | 18 +++++++++++++----- freqtrade/exchange/exchange_helpers.py | 1 + freqtrade/freqtradebot.py | 5 ++--- freqtrade/strategy/interface.py | 13 ++++++------- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index c0fb6629f..02104062d 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -7,12 +7,14 @@ from typing import List, Dict, Tuple, Any, Optional from datetime import datetime from math import floor, ceil +import arrow import asyncio import ccxt import ccxt.async_support as ccxt_async -import arrow +from pandas import DataFrame from freqtrade import constants, OperationalException, DependencyException, TemporaryError +from freqtrade.exchange.exchange_helpers import parse_ticker_dataframe logger = logging.getLogger(__name__) @@ -81,7 +83,7 @@ class Exchange(object): self._pairs_last_refresh_time: Dict[str, int] = {} # Holds candles - self.klines: Dict[str, Any] = {} + self._klines: Dict[str, DataFrame] = {} # Holds all open sell orders for dry_run self._dry_run_open_orders: Dict[str, Any] = {} @@ -155,6 +157,12 @@ class Exchange(object): """exchange ccxt id""" return self._api.id + def klines(self, pair: str) -> DataFrame: + if pair in self._klines: + return self._klines.get(pair).copy() + else: + return None + def set_sandbox(self, api, exchange_config: dict, name: str): if exchange_config.get('sandbox'): if api.urls.get('test'): @@ -499,7 +507,7 @@ class Exchange(object): def refresh_tickers(self, pair_list: List[str], ticker_interval: str) -> None: """ - Refresh tickers asyncronously and set `klines` of this object with the result + Refresh tickers asyncronously and set `_klines` of this object with the result """ logger.debug("Refreshing klines for %d pairs", len(pair_list)) asyncio.get_event_loop().run_until_complete( @@ -515,7 +523,7 @@ class Exchange(object): # Gather corotines to run for pair in pairs: if not (self._pairs_last_refresh_time.get(pair, 0) + interval_in_sec >= - arrow.utcnow().timestamp and pair in self.klines): + arrow.utcnow().timestamp and pair in self._klines): input_coroutines.append(self._async_get_candle_history(pair, tick_interval)) else: logger.debug("Using cached klines data for %s ...", pair) @@ -528,7 +536,7 @@ class Exchange(object): if ticks: self._pairs_last_refresh_time[pair] = ticks[-1][0] // 1000 # keeping parsed dataframe in cache - self.klines[pair] = ticks + self._klines[pair] = parse_ticker_dataframe(ticks) return tickers @retrier_async diff --git a/freqtrade/exchange/exchange_helpers.py b/freqtrade/exchange/exchange_helpers.py index 84e68d4bb..729a4a987 100644 --- a/freqtrade/exchange/exchange_helpers.py +++ b/freqtrade/exchange/exchange_helpers.py @@ -14,6 +14,7 @@ def parse_ticker_dataframe(ticker: list) -> DataFrame: :param ticker: ticker list, as returned by exchange.async_get_candle_history :return: DataFrame """ + logger.debug("Parsing tickerlist to dataframe") cols = ['date', 'open', 'high', 'low', 'close', 'volume'] frame = DataFrame(ticker, columns=cols) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 1297a1c2c..e4f6311d5 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -317,7 +317,7 @@ class FreqtradeBot(object): # running get_signal on historical data fetched for _pair in whitelist: - (buy, sell) = self.strategy.get_signal(_pair, interval, self.exchange.klines.get(_pair)) + (buy, sell) = self.strategy.get_signal(_pair, interval, self.exchange.klines(_pair)) if buy and not sell: stake_amount = self._get_trade_stake_amount(_pair) if not stake_amount: @@ -540,9 +540,8 @@ class FreqtradeBot(object): (buy, sell) = (False, False) experimental = self.config.get('experimental', {}) if experimental.get('use_sell_signal') or experimental.get('ignore_roi_if_buy_signal'): - ticker = self.exchange.klines.get(trade.pair) (buy, sell) = self.strategy.get_signal(trade.pair, self.strategy.ticker_interval, - ticker) + self.exchange.klines(trade.pair)) config_ask_strategy = self.config.get('ask_strategy', {}) if config_ask_strategy.get('use_order_book', False): diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 141dd996c..d8f379d53 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -6,7 +6,7 @@ import logging from abc import ABC, abstractmethod from datetime import datetime from enum import Enum -from typing import Dict, List, NamedTuple, Optional, Tuple +from typing import Dict, List, NamedTuple, Tuple import warnings import arrow @@ -122,15 +122,13 @@ class IStrategy(ABC): """ return self.__class__.__name__ - def analyze_ticker(self, ticker_history: List[Dict], metadata: dict) -> DataFrame: + def analyze_ticker(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Parses the given ticker history and returns a populated DataFrame add several TA indicators and buy signal to it :return DataFrame with ticker data and indicator data """ - dataframe = parse_ticker_dataframe(ticker_history) - pair = str(metadata.get('pair')) # Test if seen this pair and last candle before. @@ -155,19 +153,20 @@ class IStrategy(ABC): return dataframe def get_signal(self, pair: str, interval: str, - ticker_hist: Optional[List[Dict]]) -> Tuple[bool, bool]: + dataframe: DataFrame) -> Tuple[bool, bool]: """ Calculates current signal based several technical analysis indicators :param pair: pair in format ANT/BTC :param interval: Interval to use (in min) + :param dataframe: Dataframe to analyze :return: (Buy, Sell) A bool-tuple indicating buy/sell signal """ - if not ticker_hist: + if isinstance(dataframe, DataFrame) and dataframe.empty: logger.warning('Empty ticker history for pair %s', pair) return False, False try: - dataframe = self.analyze_ticker(ticker_hist, {'pair': pair}) + dataframe = self.analyze_ticker(dataframe, {'pair': pair}) except ValueError as error: logger.warning( 'Unable to analyze ticker for pair %s: %s',