Added short functionality to exchange stoplss methods

This commit is contained in:
Sam Germain 2021-08-21 21:10:03 -06:00
parent 4ac2237937
commit 6ac0ab0233
4 changed files with 35 additions and 32 deletions

View File

@ -30,8 +30,11 @@ class Binance(Exchange):
Returns True if adjustment is necessary. Returns True if adjustment is necessary.
:param side: "buy" or "sell" :param side: "buy" or "sell"
""" """
# TODO-lev: Short support
return order['type'] == 'stop_loss_limit' and stop_loss > float(order['info']['stopPrice']) return order['type'] == 'stop_loss_limit' and (
side == "sell" and stop_loss > float(order['info']['stopPrice']) or
side == "buy" and stop_loss < float(order['info']['stopPrice'])
)
@retrier(retries=0) @retrier(retries=0)
def stoploss(self, pair: str, amount: float, def stoploss(self, pair: str, amount: float,
@ -42,7 +45,6 @@ class Binance(Exchange):
It may work with a limited number of other exchanges, but this has not been tested yet. It may work with a limited number of other exchanges, but this has not been tested yet.
:param side: "buy" or "sell" :param side: "buy" or "sell"
""" """
# TODO-lev: Short support
# Limit price threshold: As limit price should always be below stop-price # Limit price threshold: As limit price should always be below stop-price
limit_price_pct = order_types.get('stoploss_on_exchange_limit_ratio', 0.99) limit_price_pct = order_types.get('stoploss_on_exchange_limit_ratio', 0.99)
rate = stop_price * limit_price_pct rate = stop_price * limit_price_pct
@ -51,14 +53,16 @@ class Binance(Exchange):
stop_price = self.price_to_precision(pair, stop_price) stop_price = self.price_to_precision(pair, stop_price)
bad_stop_price = (stop_price <= rate) if side == "sell" else (stop_price >= rate)
# Ensure rate is less than stop price # Ensure rate is less than stop price
if stop_price <= rate: if bad_stop_price:
raise OperationalException( raise OperationalException(
'In stoploss limit order, stop price should be more than limit price') 'In stoploss limit order, stop price should be better than limit price')
if self._config['dry_run']: if self._config['dry_run']:
dry_order = self.create_dry_run_order( dry_order = self.create_dry_run_order(
pair, ordertype, "sell", amount, stop_price) pair, ordertype, side, amount, stop_price)
return dry_order return dry_order
try: try:
@ -69,7 +73,7 @@ class Binance(Exchange):
rate = self.price_to_precision(pair, rate) rate = self.price_to_precision(pair, rate)
order = self._api.create_order(symbol=pair, type=ordertype, side='sell', order = self._api.create_order(symbol=pair, type=ordertype, side=side,
amount=amount, price=rate, params=params) amount=amount, price=rate, params=params)
logger.info('stoploss limit order added for %s. ' logger.info('stoploss limit order added for %s. '
'stop price: %s. limit: %s', pair, stop_price, rate) 'stop price: %s. limit: %s', pair, stop_price, rate)
@ -77,21 +81,21 @@ class Binance(Exchange):
return order return order
except ccxt.InsufficientFunds as e: except ccxt.InsufficientFunds as e:
raise InsufficientFundsError( raise InsufficientFundsError(
f'Insufficient funds to create {ordertype} sell order on market {pair}. ' f'Insufficient funds to create {ordertype} {side} order on market {pair}. '
f'Tried to sell amount {amount} at rate {rate}. ' f'Tried to {side} amount {amount} at rate {rate}. '
f'Message: {e}') from e f'Message: {e}') from e
except ccxt.InvalidOrder as e: except ccxt.InvalidOrder as e:
# Errors: # Errors:
# `binance Order would trigger immediately.` # `binance Order would trigger immediately.`
raise InvalidOrderException( raise InvalidOrderException(
f'Could not create {ordertype} sell order on market {pair}. ' f'Could not create {ordertype} {side} order on market {pair}. '
f'Tried to sell amount {amount} at rate {rate}. ' f'Tried to {side} amount {amount} at rate {rate}. '
f'Message: {e}') from e f'Message: {e}') from e
except ccxt.DDoSProtection as e: except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e: except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError( raise TemporaryError(
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e f'Could not place {side} order due to {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) from e raise OperationalException(e) from e

View File

@ -36,8 +36,10 @@ class Ftx(Exchange):
Verify stop_loss against stoploss-order value (limit or price) Verify stop_loss against stoploss-order value (limit or price)
Returns True if adjustment is necessary. Returns True if adjustment is necessary.
""" """
# TODO-lev: Short support return order['type'] == 'stop' and (
return order['type'] == 'stop' and stop_loss > float(order['price']) side == "sell" and stop_loss > float(order['price']) or
side == "buy" and stop_loss < float(order['price'])
)
@retrier(retries=0) @retrier(retries=0)
def stoploss(self, pair: str, amount: float, def stoploss(self, pair: str, amount: float,
@ -48,7 +50,6 @@ class Ftx(Exchange):
Limit orders are defined by having orderPrice set, otherwise a market order is used. Limit orders are defined by having orderPrice set, otherwise a market order is used.
""" """
# TODO-lev: Short support
limit_price_pct = order_types.get('stoploss_on_exchange_limit_ratio', 0.99) limit_price_pct = order_types.get('stoploss_on_exchange_limit_ratio', 0.99)
limit_rate = stop_price * limit_price_pct limit_rate = stop_price * limit_price_pct
@ -59,7 +60,7 @@ class Ftx(Exchange):
if self._config['dry_run']: if self._config['dry_run']:
dry_order = self.create_dry_run_order( dry_order = self.create_dry_run_order(
pair, ordertype, "sell", amount, stop_price) pair, ordertype, side, amount, stop_price)
return dry_order return dry_order
try: try:
@ -71,7 +72,7 @@ class Ftx(Exchange):
params['stopPrice'] = stop_price params['stopPrice'] = stop_price
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=side,
amount=amount, params=params) amount=amount, params=params)
self._log_exchange_response('create_stoploss_order', order) self._log_exchange_response('create_stoploss_order', order)
logger.info('stoploss order added for %s. ' logger.info('stoploss order added for %s. '
@ -79,19 +80,19 @@ class Ftx(Exchange):
return order return order
except ccxt.InsufficientFunds as e: except ccxt.InsufficientFunds as e:
raise InsufficientFundsError( raise InsufficientFundsError(
f'Insufficient funds to create {ordertype} sell order on market {pair}. ' f'Insufficient funds to create {ordertype} {side} order on market {pair}. '
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. ' f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
f'Message: {e}') from e f'Message: {e}') from e
except ccxt.InvalidOrder as e: except ccxt.InvalidOrder as e:
raise InvalidOrderException( raise InvalidOrderException(
f'Could not create {ordertype} sell order on market {pair}. ' f'Could not create {ordertype} {side} order on market {pair}. '
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. ' f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
f'Message: {e}') from e f'Message: {e}') from e
except ccxt.DDoSProtection as e: except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e: except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError( raise TemporaryError(
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e f'Could not place {side} order due to {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) from e raise OperationalException(e) from e

View File

@ -72,18 +72,18 @@ class Kraken(Exchange):
Verify stop_loss against stoploss-order value (limit or price) Verify stop_loss against stoploss-order value (limit or price)
Returns True if adjustment is necessary. Returns True if adjustment is necessary.
""" """
# TODO-lev: Short support return (order['type'] in ('stop-loss', 'stop-loss-limit') and (
return (order['type'] in ('stop-loss', 'stop-loss-limit') (side == "sell" and stop_loss > float(order['price'])) or
and stop_loss > float(order['price'])) (side == "buy" and stop_loss < float(order['price']))
))
@retrier(retries=0) @ retrier(retries=0)
def stoploss(self, pair: str, amount: float, def stoploss(self, pair: str, amount: float,
stop_price: float, order_types: Dict, side: str) -> Dict: stop_price: float, order_types: Dict, side: str) -> Dict:
""" """
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.
""" """
# TODO-lev: Short support
params = self._params.copy() params = self._params.copy()
if order_types.get('stoploss', 'market') == 'limit': if order_types.get('stoploss', 'market') == 'limit':
@ -98,13 +98,13 @@ class Kraken(Exchange):
if self._config['dry_run']: if self._config['dry_run']:
dry_order = self.create_dry_run_order( dry_order = self.create_dry_run_order(
pair, ordertype, "sell", amount, stop_price) pair, ordertype, side, amount, stop_price)
return dry_order return dry_order
try: try:
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=side,
amount=amount, price=stop_price, params=params) amount=amount, price=stop_price, params=params)
self._log_exchange_response('create_stoploss_order', order) self._log_exchange_response('create_stoploss_order', order)
logger.info('stoploss order added for %s. ' logger.info('stoploss order added for %s. '
@ -112,19 +112,19 @@ class Kraken(Exchange):
return order return order
except ccxt.InsufficientFunds as e: except ccxt.InsufficientFunds as e:
raise InsufficientFundsError( raise InsufficientFundsError(
f'Insufficient funds to create {ordertype} sell order on market {pair}. ' f'Insufficient funds to create {ordertype} {side} order on market {pair}. '
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. ' f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
f'Message: {e}') from e f'Message: {e}') from e
except ccxt.InvalidOrder as e: except ccxt.InvalidOrder as e:
raise InvalidOrderException( raise InvalidOrderException(
f'Could not create {ordertype} sell order on market {pair}. ' f'Could not create {ordertype} {side} order on market {pair}. '
f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. ' f'Tried to create stoploss with amount {amount} at stoploss {stop_price}. '
f'Message: {e}') from e f'Message: {e}') from e
except ccxt.DDoSProtection as e: except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e: except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError( raise TemporaryError(
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e f'Could not place {side} order due to {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) from e raise OperationalException(e) from e
@ -133,7 +133,6 @@ class Kraken(Exchange):
Assigns property _leverage_brackets to a dictionary of information about the leverage Assigns property _leverage_brackets to a dictionary of information about the leverage
allowed on each pair allowed on each pair
""" """
# TODO-lev: Not sure if this works correctly for futures
leverages = {} leverages = {}
try: try:
for pair, market in self._api.load_markets().items(): for pair, market in self._api.load_markets().items():

View File

@ -499,7 +499,6 @@ class LocalTrade():
lower_stop = new_loss < self.stop_loss lower_stop = new_loss < self.stop_loss
# stop losses only walk up, never down!, # stop losses only walk up, never down!,
# TODO-lev
# ? But adding more to a leveraged trade would create a lower liquidation price, # ? But adding more to a leveraged trade would create a lower liquidation price,
# ? decreasing the minimum stoploss # ? decreasing the minimum stoploss
if (higher_stop and not self.is_short) or (lower_stop and self.is_short): if (higher_stop and not self.is_short) or (lower_stop and self.is_short):