Add Emergencyselling after X timeouts have been reached
This commit is contained in:
parent
d99eaccb5a
commit
7a907a7636
@ -28,6 +28,7 @@
|
|||||||
"unfilledtimeout": {
|
"unfilledtimeout": {
|
||||||
"buy": 10,
|
"buy": 10,
|
||||||
"sell": 30,
|
"sell": 30,
|
||||||
|
"exit_timeout_count": 0,
|
||||||
"unit": "minutes"
|
"unit": "minutes"
|
||||||
},
|
},
|
||||||
"bid_strategy": {
|
"bid_strategy": {
|
||||||
|
@ -101,6 +101,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
|
|||||||
| `fee` | Fee used during backtesting / dry-runs. Should normally not be configured, which has freqtrade fall back to the exchange default fee. Set as ratio (e.g. 0.001 = 0.1%). Fee is applied twice for each trade, once when buying, once when selling. <br> **Datatype:** Float (as ratio)
|
| `fee` | Fee used during backtesting / dry-runs. Should normally not be configured, which has freqtrade fall back to the exchange default fee. Set as ratio (e.g. 0.001 = 0.1%). Fee is applied twice for each trade, once when buying, once when selling. <br> **Datatype:** Float (as ratio)
|
||||||
| `unfilledtimeout.buy` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer
|
| `unfilledtimeout.buy` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer
|
||||||
| `unfilledtimeout.sell` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer
|
| `unfilledtimeout.sell` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer
|
||||||
|
| `unfilledtimeout.exit_timeout_count` | How many times can exit orders time out. 0 to disable and allow unlimited cancels. [Strategy Override](#parameters-in-the-strategy).<br>*Defaults to `0`.* <br> **Datatype:** Integer
|
||||||
| `unfilledtimeout.unit` | Unit to use in unfilledtimeout setting. Note: If you set unfilledtimeout.unit to "seconds", "internals.process_throttle_secs" must be inferior or equal to timeout [Strategy Override](#parameters-in-the-strategy). <br> *Defaults to `minutes`.* <br> **Datatype:** String
|
| `unfilledtimeout.unit` | Unit to use in unfilledtimeout setting. Note: If you set unfilledtimeout.unit to "seconds", "internals.process_throttle_secs" must be inferior or equal to timeout [Strategy Override](#parameters-in-the-strategy). <br> *Defaults to `minutes`.* <br> **Datatype:** String
|
||||||
| `bid_strategy.price_side` | Select the side of the spread the bot should look at to get the buy rate. [More information below](#buy-price-side).<br> *Defaults to `bid`.* <br> **Datatype:** String (either `ask` or `bid`).
|
| `bid_strategy.price_side` | Select the side of the spread the bot should look at to get the buy rate. [More information below](#buy-price-side).<br> *Defaults to `bid`.* <br> **Datatype:** String (either `ask` or `bid`).
|
||||||
| `bid_strategy.ask_last_balance` | **Required.** Interpolate the bidding price. More information [below](#buy-price-without-orderbook-enabled).
|
| `bid_strategy.ask_last_balance` | **Required.** Interpolate the bidding price. More information [below](#buy-price-without-orderbook-enabled).
|
||||||
|
@ -156,6 +156,7 @@ CONF_SCHEMA = {
|
|||||||
'properties': {
|
'properties': {
|
||||||
'buy': {'type': 'number', 'minimum': 1},
|
'buy': {'type': 'number', 'minimum': 1},
|
||||||
'sell': {'type': 'number', 'minimum': 1},
|
'sell': {'type': 'number', 'minimum': 1},
|
||||||
|
'exit_timeout_count': {'type': 'number', 'minimum': 0, 'default': 0},
|
||||||
'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'}
|
'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -920,6 +920,13 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
trade=trade,
|
trade=trade,
|
||||||
order=order))):
|
order=order))):
|
||||||
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
|
self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
|
||||||
|
canceled_count = trade.get_exit_order_count()
|
||||||
|
max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0)
|
||||||
|
if max_timeouts > 0 and canceled_count >= max_timeouts:
|
||||||
|
logger.warning(f'Emergencyselling trade {trade}, as the sell order '
|
||||||
|
f'timed out {max_timeouts} times.')
|
||||||
|
self.execute_trade_exit(trade, order.get('price'), sell_reason=SellCheckTuple(
|
||||||
|
sell_type=SellType.EMERGENCY_SELL))
|
||||||
|
|
||||||
def cancel_all_open_orders(self) -> None:
|
def cancel_all_open_orders(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -1283,7 +1290,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
if self.exchange.check_order_canceled_empty(order):
|
if self.exchange.check_order_canceled_empty(order):
|
||||||
# Trade has been cancelled on exchange
|
# Trade has been cancelled on exchange
|
||||||
# Handling of this will happen in check_handle_timeout.
|
# Handling of this will happen in check_handle_timedout.
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Try update amount (binance-fix)
|
# Try update amount (binance-fix)
|
||||||
|
@ -491,6 +491,14 @@ class LocalTrade():
|
|||||||
def update_order(self, order: Dict) -> None:
|
def update_order(self, order: Dict) -> None:
|
||||||
Order.update_orders(self.orders, order)
|
Order.update_orders(self.orders, order)
|
||||||
|
|
||||||
|
def get_exit_order_count(self) -> int:
|
||||||
|
"""
|
||||||
|
Get amount of failed exiting orders
|
||||||
|
assumes full exits.
|
||||||
|
"""
|
||||||
|
orders = [o for o in self.orders if o.ft_order_side == 'sell']
|
||||||
|
return len(orders)
|
||||||
|
|
||||||
def _calc_open_trade_value(self) -> float:
|
def _calc_open_trade_value(self) -> float:
|
||||||
"""
|
"""
|
||||||
Calculate the open_rate including open_fee.
|
Calculate the open_rate including open_fee.
|
||||||
@ -775,7 +783,7 @@ class Trade(_DECL_BASE, LocalTrade):
|
|||||||
return Trade.query
|
return Trade.query
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_open_order_trades():
|
def get_open_order_trades() -> List['Trade']:
|
||||||
"""
|
"""
|
||||||
Returns all open trades
|
Returns all open trades
|
||||||
NOTE: Not supported in Backtesting.
|
NOTE: Not supported in Backtesting.
|
||||||
|
Loading…
Reference in New Issue
Block a user