From a452864b419733292e321e0311989e01fc4e057b Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 12 Jul 2018 22:21:52 +0200 Subject: [PATCH] Use namedtuple for sell_return --- freqtrade/freqtradebot.py | 4 ++-- freqtrade/optimize/backtesting.py | 6 +++--- freqtrade/rpc/rpc.py | 2 +- freqtrade/strategy/interface.py | 32 +++++++++++++++++----------- freqtrade/tests/test_freqtradebot.py | 4 +++- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 8c71119ae..566b0670f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -508,8 +508,8 @@ class FreqtradeBot(object): trade.pair, self.strategy.ticker_interval) should_sell = self.strategy.should_sell(trade, current_rate, datetime.utcnow(), buy, sell) - if should_sell[0]: - self.execute_sell(trade, current_rate, should_sell[1]) + if should_sell.sell_flag: + self.execute_sell(trade, current_rate, should_sell.sell_type) return True logger.info('Found no sell signals for whitelisted currencies. Trying again..') return False diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 3f867df22..391e05b83 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -164,8 +164,8 @@ class Backtesting(object): buy_signal = sell_row.buy sell = self.strategy.should_sell(trade, sell_row.open, sell_row.date, buy_signal, - sell_row.sell) - if sell[0]: + sell_row.sell) + if sell.sell_flag: return BacktestResult(pair=pair, profit_percent=trade.calc_profit_percent(rate=sell_row.open), @@ -178,7 +178,7 @@ class Backtesting(object): open_at_end=False, open_rate=buy_row.open, close_rate=sell_row.open, - sell_reason=sell[1] + sell_reason=sell.sell_type ) if partial_ticker: # no sell condition found - trade stil open at end of backtest period diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 96556df78..27ec7ea7a 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -13,10 +13,10 @@ import sqlalchemy as sql from numpy import mean, nan_to_num from pandas import DataFrame -from freqtrade.analyze import SellType from freqtrade.misc import shorten_date from freqtrade.persistence import Trade from freqtrade.state import State +from freqtrade.strategy.interface import SellType logger = logging.getLogger(__name__) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 5d1cecdb3..7b8d91010 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, Tuple +from typing import Dict, List, NamedTuple, Tuple import arrow from pandas import DataFrame @@ -39,6 +39,14 @@ class SellType(Enum): NONE = "" +class SellCheckTuple(NamedTuple): + """ + NamedTuple for Sell type + reason + """ + sell_flag: bool + sell_type: SellType + + class IStrategy(ABC): """ Interface for freqtrade strategies @@ -157,7 +165,7 @@ class IStrategy(ABC): return buy, sell def should_sell(self, trade: Trade, rate: float, date: datetime, buy: bool, - sell: bool) -> Tuple[bool, SellType]: + sell: bool) -> SellCheckTuple: """ This function evaluate if on the condition required to trigger a sell has been reached if the threshold is reached and updates the trade record. @@ -166,32 +174,32 @@ class IStrategy(ABC): current_profit = trade.calc_profit_percent(rate) stoplossflag = self.stop_loss_reached(current_rate=rate, trade=trade, current_time=date, current_profit=current_profit) - if stoplossflag[0]: - return (True, stoplossflag[1]) + if stoplossflag.sell_flag: + return stoplossflag experimental = self.config.get('experimental', {}) if buy and experimental.get('ignore_roi_if_buy_signal', False): logger.debug('Buy signal still active - not selling.') - return (False, SellType.NONE) + return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) # Check if minimal roi has been reached and no longer in buy conditions (avoiding a fee) if self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date): logger.debug('Required profit reached. Selling..') - return (True, SellType.ROI) + return SellCheckTuple(sell_flag=True, sell_type=SellType.ROI) if experimental.get('sell_profit_only', False): logger.debug('Checking if trade is profitable..') if trade.calc_profit(rate=rate) <= 0: - return (False, SellType.NONE) + return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) if sell and not buy and experimental.get('use_sell_signal', False): logger.debug('Sell signal received. Selling..') - return (True, SellType.SELL_SIGNAL) + return SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL) - return (False, SellType.NONE) + return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) def stop_loss_reached(self, current_rate: float, trade: Trade, current_time: datetime, - current_profit: float) -> Tuple[bool, SellType]: + current_profit: float) -> SellCheckTuple: """ Based on current profit of the trade and configured (trailing) stoploss, decides to sell or not @@ -214,7 +222,7 @@ class IStrategy(ABC): logger.debug(f"trailing stop saved {trade.stop_loss - trade.initial_stop_loss:.6f}") logger.debug('Stop loss hit.') - return (True, selltype) + return SellCheckTuple(sell_flag=True, sell_type=selltype) # update the stop loss afterwards, after all by definition it's supposed to be hanging if trailing_stop: @@ -231,7 +239,7 @@ class IStrategy(ABC): trade.adjust_stop_loss(current_rate, stop_loss_value) - return (False, SellType.NONE) + return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) def min_roi_reached(self, trade: Trade, current_profit: float, current_time: datetime) -> bool: """ diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index 7ac421bbb..65cd99689 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -16,7 +16,7 @@ import requests from freqtrade import (DependencyException, OperationalException, TemporaryError, constants) -from freqtrade.analyze import SellType +from freqtrade.strategy.interface.IStrategy import SellType, SellCheckTuple from freqtrade.freqtradebot import FreqtradeBot from freqtrade.persistence import Trade from freqtrade.rpc import RPCMessageType @@ -1625,6 +1625,8 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, market """ patch_RPCManager(mocker) patch_coinmarketcap(mocker) + mocker.patch('freqtrade.freqtradebot.strategy.interface.stop_loss_reached', + return_value=SellCheckTuple(sell_flag=False, sell_type=SellType.NONE)) mocker.patch.multiple( 'freqtrade.exchange.Exchange', validate_pairs=MagicMock(),