From 179b10e6e72f7ad2ad8a8e20f20d6c2123ba55b4 Mon Sep 17 00:00:00 2001 From: Gert Wohlgemuth Date: Thu, 14 Jun 2018 20:27:41 -0700 Subject: [PATCH] working on refacturing of the strategy class --- freqtrade/analyze.py | 27 ++++++++------- freqtrade/strategy/interface.py | 57 +++++++++++++++++++++++++++++-- freqtrade/strategy/resolver.py | 3 +- freqtrade/tests/test_dataframe.py | 2 +- 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/freqtrade/analyze.py b/freqtrade/analyze.py index f18ae291c..dcf66b0a2 100644 --- a/freqtrade/analyze.py +++ b/freqtrade/analyze.py @@ -14,7 +14,6 @@ from freqtrade.exchange import get_ticker_history from freqtrade.persistence import Trade from freqtrade.strategy.resolver import StrategyResolver, IStrategy - logger = logging.getLogger(__name__) @@ -31,6 +30,7 @@ class Analyze(object): Analyze class contains everything the bot need to determine if the situation is good for buying or selling. """ + def __init__(self, config: dict) -> None: """ Init Analyze @@ -62,10 +62,10 @@ class Analyze(object): 'close': 'last', 'volume': 'max', }) - frame.drop(frame.tail(1).index, inplace=True) # eliminate partial candle + frame.drop(frame.tail(1).index, inplace=True) # eliminate partial candle return frame - def populate_indicators(self, dataframe: DataFrame) -> DataFrame: + def populate_indicators(self, dataframe: DataFrame, pair: str = None) -> DataFrame: """ Adds several different TA indicators to the given DataFrame @@ -73,23 +73,23 @@ class Analyze(object): you are using. Let uncomment only the indicator you are using in your strategies or your hyperopt configuration, otherwise you will waste your memory and CPU usage. """ - return self.strategy.populate_indicators(dataframe=dataframe) + return self.strategy.advise_indicators(dataframe=dataframe, pair=pair) - def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: + def populate_buy_trend(self, dataframe: DataFrame, pair: str = None) -> DataFrame: """ Based on TA indicators, populates the buy signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ - return self.strategy.populate_buy_trend(dataframe=dataframe) + return self.strategy.advise_buy(dataframe=dataframe, pair=pair) - def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame: + def populate_sell_trend(self, dataframe: DataFrame, pair: str = None) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ - return self.strategy.populate_sell_trend(dataframe=dataframe) + return self.strategy.advise_sell(dataframe=dataframe, pair=pair) def get_ticker_interval(self) -> str: """ @@ -98,16 +98,17 @@ class Analyze(object): """ return self.strategy.ticker_interval - def analyze_ticker(self, ticker_history: List[Dict]) -> DataFrame: + def analyze_ticker(self, ticker_history: List[Dict], pair: str) -> 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 = self.parse_ticker_dataframe(ticker_history) - dataframe = self.populate_indicators(dataframe) - dataframe = self.populate_buy_trend(dataframe) - dataframe = self.populate_sell_trend(dataframe) + dataframe = self.populate_indicators(dataframe, pair) + dataframe = self.populate_buy_trend(dataframe, pair) + dataframe = self.populate_sell_trend(dataframe, pair) return dataframe def get_signal(self, pair: str, interval: str) -> Tuple[bool, bool]: @@ -123,7 +124,7 @@ class Analyze(object): return False, False try: - dataframe = self.analyze_ticker(ticker_hist) + dataframe = self.analyze_ticker(ticker_hist, pair) except ValueError as error: logger.warning( 'Unable to analyze ticker for pair %s: %s', diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 4ae358c6f..6ffd7b981 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -6,6 +6,7 @@ from typing import Dict from abc import ABC, abstractmethod from pandas import DataFrame +import warnings class IStrategy(ABC): @@ -19,30 +20,80 @@ class IStrategy(ABC): ticker_interval -> str: value of the ticker interval to use for the strategy """ + # associated minimal roi minimal_roi: Dict + + # associated stoploss stoploss: float + + # associated ticker interval ticker_interval: str - @abstractmethod + # configuration used, just in case the strategy want's to use it for something + config: dict = {} + def populate_indicators(self, dataframe: DataFrame) -> DataFrame: """ Populate indicators that will be used in the Buy and Sell strategy :param dataframe: Raw data from the exchange and parsed by parse_ticker_dataframe() :return: a Dataframe with all mandatory indicators for the strategies """ + warnings.warn("deprecated - please replace this method with advise_indicators!", DeprecationWarning) + return dataframe - @abstractmethod def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame: """ Based on TA indicators, populates the buy signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ + warnings.warn("deprecated - please replace this method with advise_buy!", DeprecationWarning) + dataframe.loc[ + ( + ), + 'buy'] = 0 + return dataframe - @abstractmethod def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with sell column """ + warnings.warn("deprecated - please replace this method with advise_sell!", DeprecationWarning) + dataframe.loc[ + ( + ), + 'sell'] = 0 + return dataframe + + def advise_indicators(self, dataframe: DataFrame, pair: str) -> DataFrame: + """ + + This wraps around the internal method + + Populate indicators that will be used in the Buy and Sell strategy + :param dataframe: Raw data from the exchange and parsed by parse_ticker_dataframe() + :param pair: The currently traded pair + :return: a Dataframe with all mandatory indicators for the strategies + """ + return self.populate_indicators(dataframe) + + def advise_buy(self, dataframe: DataFrame, pair: str) -> DataFrame: + """ + Based on TA indicators, populates the buy signal for the given dataframe + :param dataframe: DataFrame + :param pair: The currently traded pair + :return: DataFrame with buy column + """ + + return self.populate_buy_trend(dataframe) + + def advise_sell(self, dataframe: DataFrame, pair: str) -> DataFrame: + """ + Based on TA indicators, populates the sell signal for the given dataframe + :param dataframe: DataFrame + :param pair: The currently traded pair + :return: DataFrame with sell column + """ + return self.populate_sell_trend(dataframe) diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 3fd39bca3..abdfc2223 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -13,7 +13,6 @@ from typing import Optional, Dict, Type from freqtrade import constants from freqtrade.strategy.interface import IStrategy - logger = logging.getLogger(__name__) @@ -36,6 +35,8 @@ class StrategyResolver(object): self.strategy: IStrategy = self._load_strategy(strategy_name, extra_dir=config.get('strategy_path')) + self.strategy.config = config + # Set attributes # Check if we need to override configuration if 'minimal_roi' in config: diff --git a/freqtrade/tests/test_dataframe.py b/freqtrade/tests/test_dataframe.py index fd461a503..43003cb83 100644 --- a/freqtrade/tests/test_dataframe.py +++ b/freqtrade/tests/test_dataframe.py @@ -16,7 +16,7 @@ def load_dataframe_pair(pairs): dataframe = ld[pairs[0]] analyze = Analyze({'strategy': 'DefaultStrategy'}) - dataframe = analyze.analyze_ticker(dataframe) + dataframe = analyze.analyze_ticker(dataframe, pairs[0]) return dataframe