Use namedtuple for sell_return

This commit is contained in:
Matthias 2018-07-12 22:21:52 +02:00
parent ad98c62329
commit a452864b41
5 changed files with 29 additions and 19 deletions

View File

@ -508,8 +508,8 @@ class FreqtradeBot(object):
trade.pair, self.strategy.ticker_interval) trade.pair, self.strategy.ticker_interval)
should_sell = self.strategy.should_sell(trade, current_rate, datetime.utcnow(), buy, sell) should_sell = self.strategy.should_sell(trade, current_rate, datetime.utcnow(), buy, sell)
if should_sell[0]: if should_sell.sell_flag:
self.execute_sell(trade, current_rate, should_sell[1]) self.execute_sell(trade, current_rate, should_sell.sell_type)
return True return True
logger.info('Found no sell signals for whitelisted currencies. Trying again..') logger.info('Found no sell signals for whitelisted currencies. Trying again..')
return False return False

View File

@ -164,8 +164,8 @@ class Backtesting(object):
buy_signal = sell_row.buy buy_signal = sell_row.buy
sell = self.strategy.should_sell(trade, sell_row.open, sell_row.date, buy_signal, sell = self.strategy.should_sell(trade, sell_row.open, sell_row.date, buy_signal,
sell_row.sell) sell_row.sell)
if sell[0]: if sell.sell_flag:
return BacktestResult(pair=pair, return BacktestResult(pair=pair,
profit_percent=trade.calc_profit_percent(rate=sell_row.open), profit_percent=trade.calc_profit_percent(rate=sell_row.open),
@ -178,7 +178,7 @@ class Backtesting(object):
open_at_end=False, open_at_end=False,
open_rate=buy_row.open, open_rate=buy_row.open,
close_rate=sell_row.open, close_rate=sell_row.open,
sell_reason=sell[1] sell_reason=sell.sell_type
) )
if partial_ticker: if partial_ticker:
# no sell condition found - trade stil open at end of backtest period # no sell condition found - trade stil open at end of backtest period

View File

@ -13,10 +13,10 @@ import sqlalchemy as sql
from numpy import mean, nan_to_num from numpy import mean, nan_to_num
from pandas import DataFrame from pandas import DataFrame
from freqtrade.analyze import SellType
from freqtrade.misc import shorten_date from freqtrade.misc import shorten_date
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.state import State from freqtrade.state import State
from freqtrade.strategy.interface import SellType
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View File

@ -6,7 +6,7 @@ import logging
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from datetime import datetime from datetime import datetime
from enum import Enum from enum import Enum
from typing import Dict, List, Tuple from typing import Dict, List, NamedTuple, Tuple
import arrow import arrow
from pandas import DataFrame from pandas import DataFrame
@ -39,6 +39,14 @@ class SellType(Enum):
NONE = "" NONE = ""
class SellCheckTuple(NamedTuple):
"""
NamedTuple for Sell type + reason
"""
sell_flag: bool
sell_type: SellType
class IStrategy(ABC): class IStrategy(ABC):
""" """
Interface for freqtrade strategies Interface for freqtrade strategies
@ -157,7 +165,7 @@ class IStrategy(ABC):
return buy, sell return buy, sell
def should_sell(self, trade: Trade, rate: float, date: datetime, buy: bool, 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 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. if the threshold is reached and updates the trade record.
@ -166,32 +174,32 @@ class IStrategy(ABC):
current_profit = trade.calc_profit_percent(rate) current_profit = trade.calc_profit_percent(rate)
stoplossflag = self.stop_loss_reached(current_rate=rate, trade=trade, current_time=date, stoplossflag = self.stop_loss_reached(current_rate=rate, trade=trade, current_time=date,
current_profit=current_profit) current_profit=current_profit)
if stoplossflag[0]: if stoplossflag.sell_flag:
return (True, stoplossflag[1]) return stoplossflag
experimental = self.config.get('experimental', {}) experimental = self.config.get('experimental', {})
if buy and experimental.get('ignore_roi_if_buy_signal', False): if buy and experimental.get('ignore_roi_if_buy_signal', False):
logger.debug('Buy signal still active - not selling.') 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) # 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): if self.min_roi_reached(trade=trade, current_profit=current_profit, current_time=date):
logger.debug('Required profit reached. Selling..') 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): if experimental.get('sell_profit_only', False):
logger.debug('Checking if trade is profitable..') logger.debug('Checking if trade is profitable..')
if trade.calc_profit(rate=rate) <= 0: 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): if sell and not buy and experimental.get('use_sell_signal', False):
logger.debug('Sell signal received. Selling..') 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, 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, Based on current profit of the trade and configured (trailing) stoploss,
decides to sell or not 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(f"trailing stop saved {trade.stop_loss - trade.initial_stop_loss:.6f}")
logger.debug('Stop loss hit.') 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 # update the stop loss afterwards, after all by definition it's supposed to be hanging
if trailing_stop: if trailing_stop:
@ -231,7 +239,7 @@ class IStrategy(ABC):
trade.adjust_stop_loss(current_rate, stop_loss_value) 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: def min_roi_reached(self, trade: Trade, current_profit: float, current_time: datetime) -> bool:
""" """

View File

@ -16,7 +16,7 @@ import requests
from freqtrade import (DependencyException, OperationalException, from freqtrade import (DependencyException, OperationalException,
TemporaryError, constants) TemporaryError, constants)
from freqtrade.analyze import SellType from freqtrade.strategy.interface.IStrategy import SellType, SellCheckTuple
from freqtrade.freqtradebot import FreqtradeBot from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.rpc import RPCMessageType 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_RPCManager(mocker)
patch_coinmarketcap(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( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(), validate_pairs=MagicMock(),