Add Support for kraken stoploss-limit

This commit is contained in:
Matthias 2020-11-25 16:27:27 +01:00
parent 8180393bbc
commit c14c0f60a1
4 changed files with 36 additions and 21 deletions

View File

@ -23,7 +23,8 @@ Binance has been split into 3, and users must use the correct ccxt exchange ID f
## Kraken ## Kraken
!!! Tip "Stoploss on Exchange" !!! Tip "Stoploss on Exchange"
Kraken supports `stoploss_on_exchange`. It provides great advantages, so we recommend to benefit from it. Kraken supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use.
### Historic Kraken data ### Historic Kraken data
@ -75,8 +76,7 @@ print(res)
!!! Tip "Stoploss on Exchange" !!! Tip "Stoploss on Exchange"
FTX supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it. FTX supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type of stoploss shall be used.
### Using subaccounts ### Using subaccounts
@ -99,10 +99,10 @@ To use subaccounts with FTX, you need to edit the configuration and add the foll
Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys. Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys.
## Random notes for other exchanges ## Random notes for other exchanges
* The Ocean (exchange id: `theocean`) exchange uses Web3 functionality and requires `web3` python package to be installed: * The Ocean (exchange id: `theocean`) exchange uses Web3 functionality and requires `web3` python package to be installed:
```shell ```shell
$ pip3 install web3 $ pip3 install web3
``` ```

View File

@ -23,11 +23,12 @@ These modes can be configured with these values:
``` ```
!!! Note !!! Note
Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market) and FTX (stop limit and stop-market) as of now. Stoploss on exchange is only supported for Binance (stop-loss-limit), Kraken (stop-loss-market, stop-loss-limit) and FTX (stop limit and stop-market) as of now.
<ins>Do not set too low stoploss value if using stop loss on exchange!</ins> <ins>Do not set too low/tight stoploss value if using stop loss on exchange!</ins>
If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work.
### stoploss_on_exchange and stoploss_on_exchange_limit_ratio ### stoploss_on_exchange and stoploss_on_exchange_limit_ratio
Enable or Disable stop loss on exchange. Enable or Disable stop loss on exchange.
If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled. If the stoploss is *on exchange* it means a stoploss limit order is placed on the exchange immediately after buy order happens successfully. This will protect you against sudden crashes in market as the order will be in the queue immediately and if market goes down then the order has more chance of being fulfilled.
@ -40,13 +41,18 @@ Stop-price is 95$, then limit would be `95 * 0.99 = 94.05$` - so the limit order
For example, assuming the stoploss is on exchange, and trailing stoploss is enabled, and the market is going up, then the bot automatically cancels the previous stoploss order and puts a new one with a stop value higher than the previous stoploss order. For example, assuming the stoploss is on exchange, and trailing stoploss is enabled, and the market is going up, then the bot automatically cancels the previous stoploss order and puts a new one with a stop value higher than the previous stoploss order.
!!! Note
If `stoploss_on_exchange` is enabled and the stoploss is cancelled manually on the exchange, then the bot will create a new stoploss order.
### stoploss_on_exchange_interval ### stoploss_on_exchange_interval
In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary. In case of stoploss on exchange there is another parameter called `stoploss_on_exchange_interval`. This configures the interval in seconds at which the bot will check the stoploss and update it if necessary.
The bot cannot do these every 5 seconds (at each iteration), otherwise it would get banned by the exchange. The bot cannot do these every 5 seconds (at each iteration), otherwise it would get banned by the exchange.
So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute). So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute).
This same logic will reapply a stoploss order on the exchange should you cancel it accidentally. This same logic will reapply a stoploss order on the exchange should you cancel it accidentally.
### emergencysell ### emergencysell
`emergencysell` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails. `emergencysell` is an optional value, which defaults to `market` and is used when creating stop loss on exchange orders fails.
The below is the default which is used if not changed in strategy or configuration file. The below is the default which is used if not changed in strategy or configuration file.

View File

@ -77,8 +77,15 @@ class Kraken(Exchange):
Creates a stoploss market order. Creates a stoploss market order.
Stoploss market orders is the only stoploss type supported by kraken. Stoploss market orders is the only stoploss type supported by kraken.
""" """
params = self._params.copy()
ordertype = "stop-loss" if order_types.get('stoploss', 'market') == 'limit':
ordertype = "stop-loss-limit"
limit_price_pct = order_types.get('stoploss_on_exchange_limit_ratio', 0.99)
limit_rate = stop_price * limit_price_pct
params['price2'] = self.price_to_precision(pair, limit_rate)
else:
ordertype = "stop-loss"
stop_price = self.price_to_precision(pair, stop_price) stop_price = self.price_to_precision(pair, stop_price)
@ -88,8 +95,6 @@ class Kraken(Exchange):
return dry_order return dry_order
try: try:
params = self._params.copy()
amount = self.amount_to_precision(pair, amount) amount = self.amount_to_precision(pair, amount)
order = self._api.create_order(symbol=pair, type=ordertype, side='sell', order = self._api.create_order(symbol=pair, type=ordertype, side='sell',

View File

@ -10,6 +10,7 @@ from tests.exchange.test_exchange import ccxt_exceptionhandlers
STOPLOSS_ORDERTYPE = 'stop-loss' STOPLOSS_ORDERTYPE = 'stop-loss'
STOPLOSS_LIMIT_ORDERTYPE = 'stop-loss-limit'
def test_buy_kraken_trading_agreement(default_conf, mocker): def test_buy_kraken_trading_agreement(default_conf, mocker):
@ -156,7 +157,8 @@ def test_get_balances_prod(default_conf, mocker):
"get_balances", "fetch_balance") "get_balances", "fetch_balance")
def test_stoploss_order_kraken(default_conf, mocker): @pytest.mark.parametrize('ordertype', ['market', 'limit'])
def test_stoploss_order_kraken(default_conf, mocker, ordertype):
api_mock = MagicMock() api_mock = MagicMock()
order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6)) order_id = 'test_prod_buy_{}'.format(randint(0, 10 ** 6))
@ -173,24 +175,26 @@ def test_stoploss_order_kraken(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken') exchange = get_patched_exchange(mocker, default_conf, api_mock, 'kraken')
# stoploss_on_exchange_limit_ratio is irrelevant for kraken market orders order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220,
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=190, order_types={'stoploss': ordertype,
order_types={'stoploss_on_exchange_limit_ratio': 1.05}) 'stoploss_on_exchange_limit_ratio': 0.99
assert api_mock.create_order.call_count == 1 })
api_mock.create_order.reset_mock()
order = exchange.stoploss(pair='ETH/BTC', amount=1, stop_price=220, order_types={})
assert 'id' in order assert 'id' in order
assert 'info' in order assert 'info' in order
assert order['id'] == order_id assert order['id'] == order_id
assert api_mock.create_order.call_args_list[0][1]['symbol'] == 'ETH/BTC' assert api_mock.create_order.call_args_list[0][1]['symbol'] == 'ETH/BTC'
assert api_mock.create_order.call_args_list[0][1]['type'] == STOPLOSS_ORDERTYPE if ordertype == 'limit':
assert api_mock.create_order.call_args_list[0][1]['type'] == STOPLOSS_LIMIT_ORDERTYPE
assert api_mock.create_order.call_args_list[0][1]['params'] == {
'trading_agreement': 'agree', 'price2': 217.8}
else:
assert api_mock.create_order.call_args_list[0][1]['type'] == STOPLOSS_ORDERTYPE
assert api_mock.create_order.call_args_list[0][1]['params'] == {
'trading_agreement': 'agree'}
assert api_mock.create_order.call_args_list[0][1]['side'] == 'sell' assert api_mock.create_order.call_args_list[0][1]['side'] == 'sell'
assert api_mock.create_order.call_args_list[0][1]['amount'] == 1 assert api_mock.create_order.call_args_list[0][1]['amount'] == 1
assert api_mock.create_order.call_args_list[0][1]['price'] == 220 assert api_mock.create_order.call_args_list[0][1]['price'] == 220
assert api_mock.create_order.call_args_list[0][1]['params'] == {'trading_agreement': 'agree'}
# test exception handling # test exception handling
with pytest.raises(DependencyException): with pytest.raises(DependencyException):