diff --git a/docs/stoploss.md b/docs/stoploss.md index ff93fd1d8..110cfa0d1 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -40,7 +40,7 @@ due to demand, it is possible to have a default stop loss, when you are in the r the system will utilize a new stop loss, which can be a different value. For example your default stop loss is 5%, but once you are in the black, it will be changed to be only a 1% stop loss -this can be configured in the main confiuration file, the following way: +this can be configured in the main configuration file, the following way: ``` "trailing_stop": { diff --git a/freqtrade/analyze.py b/freqtrade/analyze.py index c7958552b..9fcb70a76 100644 --- a/freqtrade/analyze.py +++ b/freqtrade/analyze.py @@ -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/freqtradebot.py b/freqtrade/freqtradebot.py index bf29029af..ecd5cf952 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -156,7 +156,7 @@ class FreqtradeBot(object): state_changed |= self.process_maybe_execute_sell(trade) # Then looking for buy opportunities - if (self.config['disable_buy']): + if (self.config.get('disable_buy', False)): logger.info('Buy disabled...') else: if len(trades) < self.config['max_open_trades']: @@ -250,7 +250,7 @@ class FreqtradeBot(object): balance = self.config['bid_strategy']['ask_last_balance'] ticker_rate = ticker['ask'] + balance * (ticker['last'] - ticker['ask']) - if self.config['bid_strategy']['use_book_order']: + if self.config['bid_strategy'].get('use_book_order', False): logger.info('Getting price from Order Book') orderBook = exchange.get_order_book(pair) orderBook_rate = orderBook['bids'][self.config['bid_strategy']['book_order_top']][0] @@ -444,14 +444,14 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \ if self.config.get('experimental', {}).get('use_sell_signal'): (buy, sell) = self.analyze.get_signal(trade.pair, self.analyze.get_ticker_interval()) - if self.config['ask_strategy']['use_book_order']: + if 'ask_strategy' in self.config and self.config['ask_strategy'].get('use_book_order', False): logger.info('Using order book for selling...') orderBook = exchange.get_order_book(trade.pair) # logger.debug('Order book %s',orderBook) orderBook_min = self.config['ask_strategy']['book_order_min'] orderBook_max = self.config['ask_strategy']['book_order_max'] - for i in range(orderBook_min, orderBook_max+1): - orderBook_rate = orderBook['asks'][i-1][0] + for i in range(orderBook_min, orderBook_max + 1): + orderBook_rate = orderBook['asks'][i - 1][0] # if orderbook has higher rate (high profit), # use orderbook, otherwise just use sell rate if (sell_rate < orderBook_rate): @@ -502,7 +502,7 @@ with limit `{buy_limit:.8f} ({stake_amount:.6f} \ ordertime = arrow.get(order['datetime']).datetime # Check if trade is still actually open - if (int(order['filled']) == 0) and (order['status'] == 'open'): + if order['status'] == 'open': if order['side'] == 'buy' and ordertime < buy_timeoutthreashold: self.handle_timedout_limit_buy(trade, order) elif order['side'] == 'sell' and ordertime < sell_timeoutthreashold: diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 4ae358c6f..2cd0c80cd 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -2,12 +2,12 @@ IStrategy interface This module defines the interface to apply for strategies """ +import warnings from typing import Dict -from abc import ABC, abstractmethod +from abc import ABC from pandas import DataFrame - class IStrategy(ABC): """ Interface for freqtrade strategies @@ -19,30 +19,71 @@ 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 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 acb4258c1..845d20874 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -40,6 +40,7 @@ class StrategyResolver(object): self.strategy: IStrategy = self._load_strategy(strategy_name, extra_dir=config.get('strategy_path')) + # Set attributes # Check if we need to override configuration if 'minimal_roi' in config: @@ -125,7 +126,7 @@ class StrategyResolver(object): strategy_name = os.path.splitext(name)[0] - print("stored downloaded stat at: {}".format(temp)) + # print("stored downloaded stat at: {}".format(temp)) # register temp path with the bot abs_paths.insert(0, temp.absolute()) 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