Merge remote-tracking branch 'origin/StopLossSupport' into wohlgemuth

This commit is contained in:
Gert Wohlgemuth 2018-05-11 14:30:13 -07:00
commit b9dcb100d3
2 changed files with 68 additions and 2 deletions

View File

@ -14,7 +14,6 @@ from freqtrade.exchange import get_ticker_history
from freqtrade.persistence import Trade from freqtrade.persistence import Trade
from freqtrade.strategy.resolver import StrategyResolver from freqtrade.strategy.resolver import StrategyResolver
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -31,6 +30,7 @@ class Analyze(object):
Analyze class contains everything the bot need to determine if the situation is good for Analyze class contains everything the bot need to determine if the situation is good for
buying or selling. buying or selling.
""" """
def __init__(self, config: dict) -> None: def __init__(self, config: dict) -> None:
""" """
Init Analyze Init Analyze
@ -195,10 +195,29 @@ class Analyze(object):
:return True if bot should sell at current rate :return True if bot should sell at current rate
""" """
current_profit = trade.calc_profit_percent(current_rate) current_profit = trade.calc_profit_percent(current_rate)
if self.strategy.stoploss is not None and current_profit < self.strategy.stoploss:
if trade.stop_loss is None:
# initially adjust the stop loss to the base value
trade.adjust_stop_loss(trade.open_rate, self.strategy.stoploss)
# evaluate if the stoploss was hit
if self.strategy.stoploss is not None and trade.stop_loss >= current_rate:
# just for debugging
if 'trailing_stop' in self.config and self.config['trailing_stop']:
print(
"HIT STOP: current price at {:.6f}, stop loss is {:.6f}, "
"initial stop loss was at {:.6f}, trade opened at {:.6f}".format(
current_rate, trade.stop_loss, trade.initial_stop_loss, trade.open_rate))
print("trailing stop saved us: {:.6f}".format(trade.stop_loss - trade.initial_stop_loss))
logger.debug('Stop loss hit.') logger.debug('Stop loss hit.')
return True return True
# update the stop loss afterwards, after all by definition it's supposed to be hanging
if 'trailing_stop' in self.config and self.config['trailing_stop']:
trade.adjust_stop_loss(current_rate, self.strategy.stoploss)
# Check if time matches and current rate is above threshold # Check if time matches and current rate is above threshold
time_diff = (current_time.timestamp() - trade.open_date.timestamp()) / 60 time_diff = (current_time.timestamp() - trade.open_date.timestamp()) / 60
for duration, threshold in self.strategy.minimal_roi.items(): for duration, threshold in self.strategy.minimal_roi.items():

View File

@ -95,6 +95,9 @@ class Trade(_DECL_BASE):
open_date = Column(DateTime, nullable=False, default=datetime.utcnow) open_date = Column(DateTime, nullable=False, default=datetime.utcnow)
close_date = Column(DateTime) close_date = Column(DateTime)
open_order_id = Column(String) open_order_id = Column(String)
stop_loss = Column(Float, nullable=False, default=0.0) # absolute value of the stop loss
initial_stop_loss = Column(Float, nullable=False, default=0.0) # absolute value of the initial stop loss
max_rate = Column(Float, nullable=False, default=0.0) # absolute value of the highest reached price
def __repr__(self): def __repr__(self):
return 'Trade(id={}, pair={}, amount={:.8f}, open_rate={:.8f}, open_since={})'.format( return 'Trade(id={}, pair={}, amount={:.8f}, open_rate={:.8f}, open_since={})'.format(
@ -105,6 +108,50 @@ class Trade(_DECL_BASE):
arrow.get(self.open_date).humanize() if self.is_open else 'closed' arrow.get(self.open_date).humanize() if self.is_open else 'closed'
) )
def adjust_stop_loss(self, current_price, stoploss):
"""
this adjusts the stop loss to it's most recently observed
setting
:param current_price:
:param stoploss:
:return:
"""
new_loss = Decimal(current_price * (1 - abs(stoploss)))
# keeping track of the highest observed rate for this trade
if self.max_rate is None:
self.max_rate = current_price
else:
if current_price > self.max_rate:
self.max_rate = current_price
# no stop loss assigned yet
if self.stop_loss is None:
logger.debug("assigning new stop loss")
self.stop_loss = new_loss
self.initial_stop_loss = new_loss
# evaluate if the stop loss needs to be updated
else:
if new_loss > self.stop_loss: # stop losses only walk up, never down!
self.stop_loss = new_loss
logger.debug("adjusted stop loss")
else:
logger.debug("keeping current stop loss")
print(
"{} - current price {:.6f}, bought at {:.6f} and calculated "
"stop loss is at: {:.6f} initial stop at {:.6f}. trailing stop loss saved us: {:.6f} "
"and max observed rate was {:.6f}".format(
self.pair, current_price, self.open_rate,
self.initial_stop_loss,
self.stop_loss, self.stop_loss - self.initial_stop_loss,
self.max_rate
))
def update(self, order: Dict) -> None: def update(self, order: Dict) -> None:
""" """
Updates this entity with amount and actual open/close rates. Updates this entity with amount and actual open/close rates.