mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
Use namedtuple for sell_return
This commit is contained in:
parent
ad98c62329
commit
a452864b41
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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__)
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user