handle stop loss on exchange added

This commit is contained in:
misagh 2018-11-23 15:17:36 +01:00
parent 1dde56790c
commit fea77824d0
4 changed files with 102 additions and 3 deletions

View File

@ -572,6 +572,17 @@ class FreqtradeBot(object):
trade.update(order)
# Check if stoploss on exchnage is hit first
if self.strategy.stoploss_on_exchange and trade.stoploss_order_id:
# Check if stoploss is hit
result = self.handle_stoploss_on_exchage(trade)
# Updating wallets if stoploss is hit
if result:
self.wallets.update()
return result
if trade.is_open and trade.open_order_id is None:
# Check if we can sell our current pair
result = self.handle_trade(trade)
@ -676,6 +687,19 @@ class FreqtradeBot(object):
logger.info('Found no sell signals for whitelisted currencies. Trying again..')
return False
def handle_stoploss_on_exchage(self, trade: Trade) -> bool:
if not trade.is_open:
raise ValueError(f'attempt to handle stoploss on exchnage for a closed trade: {trade}')
logger.debug('Handling stoploss on exchange %s ...', trade)
order = self.exchange.get_order(trade.stoploss_order_id, trade.pair)
if order['status'] == 'closed':
trade.sell_reason = SellType.STOPLOSS_ON_EXCHNAGE.value
trade.update(order)
return True
else:
return False
def check_sell(self, trade: Trade, sell_rate: float, buy: bool, sell: bool) -> bool:
if self.edge:
stoploss = self.edge.stoploss(trade.pair)

View File

@ -178,7 +178,7 @@ class Trade(_DECL_BASE):
# absolute value of the initial stop loss
initial_stop_loss = Column(Float, nullable=True, default=0.0)
# absolute value of the highest reached price
stoploss_order_id = Column(Integer, nullable=True, index=True)
stoploss_order_id = Column(String, nullable=True, index=True)
max_rate = Column(Float, nullable=True, default=0.0)
sell_reason = Column(String, nullable=True)
strategy = Column(String, nullable=True)
@ -250,6 +250,9 @@ class Trade(_DECL_BASE):
self.open_order_id = None
elif order_type == 'limit' and order['side'] == 'sell':
self.close(order['price'])
elif order_type == 'stop_loss_limit':
self.stoploss_order_id = None
self.close(order['price'])
else:
raise ValueError(f'Unknown order type: {order_type}')
cleanup()

View File

@ -33,6 +33,7 @@ class SellType(Enum):
"""
ROI = "roi"
STOP_LOSS = "stop_loss"
STOPLOSS_ON_EXCHNAGE = "stoploss_on_exchange"
TRAILING_STOP_LOSS = "trailing_stop_loss"
SELL_SIGNAL = "sell_signal"
FORCE_SELL = "force_sell"

View File

@ -931,7 +931,7 @@ def test_execute_buy_with_stoploss_on_exchange(mocker, default_conf,
trade = Trade.query.first()
assert trade.is_open is True
assert trade.stoploss_order_id == 13434334
assert trade.stoploss_order_id == '13434334'
def test_process_maybe_execute_buy(mocker, default_conf) -> None:
@ -1572,7 +1572,8 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
get_ticker=ticker_sell_up
)
freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid'], sell_reason=SellType.ROI)
freqtrade.execute_sell(trade=trade, limit=ticker_sell_up()['bid'],
sell_reason=SellType.SELL_SIGNAL)
trade = Trade.query.first()
assert trade
@ -1580,6 +1581,76 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
assert rpc_mock.call_count == 2
def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
ticker, fee,
limit_buy_order,
markets, mocker) -> None:
default_conf['exchange']['name'] = 'binance'
rpc_mock = patch_RPCManager(mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
_load_markets=MagicMock(return_value={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
)
stoploss_limit = MagicMock(return_value={
'id': 123,
'info': {
'foo': 'bar'
}
})
mocker.patch('freqtrade.exchange.Exchange.symbol_amount_prec', lambda s, x, y: y)
mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, x, y: y)
mocker.patch('freqtrade.exchange.Exchange.stoploss_limit', stoploss_limit)
freqtrade = FreqtradeBot(default_conf)
freqtrade.strategy.stoploss_on_exchange = True
patch_get_signal(freqtrade)
# Create some test data
freqtrade.create_trade()
trade = Trade.query.first()
assert trade
assert trade.stoploss_order_id == '123'
assert trade.open_order_id is not None
trade.update(limit_buy_order)
# Assuming stoploss on exchnage is hit
# stoploss_order_id should become None
# and trade should be sold at the price of stoploss
stoploss_limit_executed = MagicMock(return_value={
"id": "123",
"timestamp": 1542707426845,
"datetime": "2018-11-20T09:50:26.845Z",
"lastTradeTimestamp": None,
"symbol": "BTC/USDT",
"type": "stop_loss_limit",
"side": "sell",
"price": 1.08801,
"amount": 90.99181074,
"cost": 99.0000000032274,
"average": 1.08801,
"filled": 90.99181074,
"remaining": 0.0,
"status": "closed",
"fee": None,
"trades": None
})
mocker.patch('freqtrade.exchange.Exchange.get_order', stoploss_limit_executed)
freqtrade.process_maybe_execute_sell(trade)
assert trade.stoploss_order_id is None
assert trade.is_open is False
print(trade.sell_reason)
assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHNAGE.value
assert rpc_mock.call_count == 1
def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
ticker_sell_up, markets, mocker) -> None:
rpc_mock = patch_RPCManager(mocker)