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)
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

View File

@ -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

View File

@ -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__)

View File

@ -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:
"""

View File

@ -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(),