Liquidation price is in freqtradebot

This commit is contained in:
Sam Germain 2021-08-02 06:14:30 -06:00
parent 1af6d8abca
commit 970ca71848
6 changed files with 50 additions and 203 deletions

View File

@ -110,98 +110,5 @@ class Binance(Exchange):
}) })
logger.info(f"Transfer response: {res}") logger.info(f"Transfer response: {res}")
def borrow(self, asset: str, amount: float, pair: str):
res = self._api.sapi_post_margin_loan({
"asset": asset,
"isIsolated": True,
"symbol": pair,
"amount": amount
}) # borrow from binance
logger.info(f"Borrow response: {res}")
def repay(self, asset: str, amount: float, pair: str):
res = self._api.sapi_post_margin_repay({
"asset": asset,
"isIsolated": True,
"symbol": pair,
"amount": amount
}) # borrow from binance
logger.info(f"Borrow response: {res}")
def setup_leveraged_enter(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
if not quote_currency or not is_short:
raise OperationalException(
"quote_currency and is_short are required arguments to setup_leveraged_enter"
" when trading with leverage on binance"
)
open_rate = 2 # TODO-mg: get the real open_rate, or real stake_amount
stake_amount = amount * open_rate
if is_short:
borrowed = stake_amount * ((leverage-1)/leverage)
else:
borrowed = amount
self.transfer( # Transfer to isolated margin
asset=quote_currency,
amount=stake_amount,
frm='SPOT',
to='ISOLATED_MARGIN',
pair=pair
)
self.borrow(
asset=quote_currency,
amount=borrowed,
pair=pair
) # borrow from binance
def complete_leveraged_exit(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
if not quote_currency or not is_short:
raise OperationalException(
"quote_currency and is_short are required arguments to setup_leveraged_enter"
" when trading with leverage on binance"
)
open_rate = 2 # TODO-mg: get the real open_rate, or real stake_amount
stake_amount = amount * open_rate
if is_short:
borrowed = stake_amount * ((leverage-1)/leverage)
else:
borrowed = amount
self.repay(
asset=quote_currency,
amount=borrowed,
pair=pair
) # repay binance
self.transfer( # Transfer to isolated margin
asset=quote_currency,
amount=stake_amount,
frm='ISOLATED_MARGIN',
to='SPOT',
pair=pair
)
def apply_leverage_to_stake_amount(self, stake_amount: float, leverage: float): def apply_leverage_to_stake_amount(self, stake_amount: float, leverage: float):
return stake_amount / leverage return stake_amount / leverage
def get_isolated_liq(self, pair: str, open_rate: float,
amount: float, leverage: float, is_short: bool) -> float:
# TODO-mg: implement
return 0.0

View File

@ -1,8 +1,7 @@
""" Bittrex exchange subclass """ """ Bittrex exchange subclass """
import logging import logging
from typing import Dict, Optional from typing import Dict
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
@ -24,28 +23,3 @@ class Bittrex(Exchange):
}, },
"l2_limit_range": [1, 25, 500], "l2_limit_range": [1, 25, 500],
} }
def setup_leveraged_enter(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
raise OperationalException("Bittrex does not support leveraged trading")
def complete_leveraged_exit(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
raise OperationalException("Bittrex does not support leveraged trading")
def get_isolated_liq(self, pair: str, open_rate: float,
amount: float, leverage: float, is_short: bool) -> float:
# TODO-mg: implement
raise OperationalException("Bittrex does not support margin trading")

View File

@ -707,8 +707,7 @@ class Exchange:
def get_max_leverage(self, pair: str, stake_amount: float, price: float) -> float: def get_max_leverage(self, pair: str, stake_amount: float, price: float) -> float:
""" """
Gets the maximum leverage available on this pair that is below the config leverage Gets the maximum leverage available on this pair
but higher than the config min_leverage
""" """
raise OperationalException(f"Leverage is not available on {self.name} using freqtrade") raise OperationalException(f"Leverage is not available on {self.name} using freqtrade")
@ -758,26 +757,6 @@ class Exchange:
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) from e raise OperationalException(e) from e
def setup_leveraged_enter(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
raise OperationalException(f"Leverage is not available on {self.name} using freqtrade")
def complete_leveraged_exit(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
raise OperationalException(f"Leverage is not available on {self.name} using freqtrade")
def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool: def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool:
""" """
Verify stop_loss against stoploss-order value (limit or price) Verify stop_loss against stoploss-order value (limit or price)
@ -1542,19 +1521,13 @@ class Exchange:
self._async_get_trade_history(pair=pair, since=since, self._async_get_trade_history(pair=pair, since=since,
until=until, from_id=from_id)) until=until, from_id=from_id))
def transfer(self, asset: str, amount: float, frm: str, to: str, pair: Optional[str]):
self._api.transfer(asset, amount, frm, to)
def get_isolated_liq(self, pair: str, open_rate: float,
amount: float, leverage: float, is_short: bool) -> float:
raise OperationalException(
f"Isolated margin is not available on {self.name} using freqtrade"
)
def get_interest_rate(self, pair: str, open_rate: float, is_short: bool) -> float: def get_interest_rate(self, pair: str, open_rate: float, is_short: bool) -> float:
# TODO-mg: implement # TODO-mg: implement
return 0.0005 return 0.0005
def set_leverage(self, pair, leverage):
self._api.set_leverage(symbol=pair, leverage=leverage)
def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = None) -> bool: def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = None) -> bool:
return exchange_name in ccxt_exchanges(ccxt_module) return exchange_name in ccxt_exchanges(ccxt_module)

View File

@ -160,9 +160,3 @@ class Ftx(Exchange):
if order['type'] == 'stop': if order['type'] == 'stop':
return safe_value_fallback2(order, order, 'id_stop', 'id') return safe_value_fallback2(order, order, 'id_stop', 'id')
return order['id'] return order['id']
def get_isolated_liq(self, pair: str, open_rate: float,
amount: float, leverage: float, is_short: bool) -> float:
# TODO-mg: implement
raise OperationalException(
"Isolated margin trading not yet implemented on FTX, would you like to implement it?")

View File

@ -1,6 +1,6 @@
""" Kraken exchange subclass """ """ Kraken exchange subclass """
import logging import logging
from typing import Any, Dict, Optional from typing import Any, Dict
import ccxt import ccxt
@ -132,28 +132,3 @@ class Kraken(Exchange):
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e f'Could not place sell 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
def setup_leveraged_enter(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
return
def complete_leveraged_exit(
self,
pair: str,
leverage: float,
amount: float,
quote_currency: Optional[str],
is_short: Optional[bool]
):
return
def get_isolated_liq(self, pair: str, open_rate: float,
amount: float, leverage: float, is_short: bool) -> float:
# TODO-mg: implement
raise OperationalException("Kraken only supports cross margin trading")

View File

@ -532,6 +532,42 @@ class FreqtradeBot(LoggingMixin):
logger.info(f"Bids to asks delta for {pair} does not satisfy condition.") logger.info(f"Bids to asks delta for {pair} does not satisfy condition.")
return False return False
def leverage_prep(
self,
pair: str,
open_rate: float,
amount: float,
leverage: float,
is_short: bool
): # -> (float, Optional[float]):
interest_rate = 0.0
isolated_liq = None
if leverage > 1.0:
interest_rate = self.exchange.get_interest_rate(
pair=pair,
open_rate=open_rate,
is_short=is_short
)
if self.trading_mode == TradingMode.ISOLATED_MARGIN or \
self.trading_mode == TradingMode.ISOLATED_FUTURES:
isolated_liq = self.exchange.liq_formula(
trading_mode=self.trading_mode,
open_rate=open_rate,
amount=amount,
leverage=leverage,
is_short=is_short
)
if self.trading_mode == TradingMode.CROSS_FUTURES or \
self.trading_mode == TradingMode.ISOLATED_FUTURES:
self.exchange.set_leverage(pair=pair, leverage=leverage)
return interest_rate, isolated_liq
def execute_enter( def execute_enter(
self, self,
pair: str, pair: str,
@ -598,6 +634,7 @@ class FreqtradeBot(LoggingMixin):
logger.info(f"User requested abortion of {name.lower()}ing {pair}") logger.info(f"User requested abortion of {name.lower()}ing {pair}")
return False return False
amount = self.exchange.amount_to_precision(pair, amount) amount = self.exchange.amount_to_precision(pair, amount)
order = self.exchange.create_order(pair=pair, ordertype=order_type, side=side, order = self.exchange.create_order(pair=pair, ordertype=order_type, side=side,
amount=amount, rate=enter_limit_requested, amount=amount, rate=enter_limit_requested,
time_in_force=time_in_force) time_in_force=time_in_force)
@ -638,26 +675,13 @@ class FreqtradeBot(LoggingMixin):
amount = safe_value_fallback(order, 'filled', 'amount') amount = safe_value_fallback(order, 'filled', 'amount')
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price') enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
interest_rate = 0.0 interest_rate, isolated_liq = self.leverage_prep(
isolated_liq = None leverage=leverage,
pair=pair,
if leverage > 1.0: amount=amount,
interest_rate = self.exchange.get_interest_rate( open_rate=enter_limit_filled_price,
pair=pair, is_short=is_short
open_rate=enter_limit_filled_price, )
is_short=is_short
)
if self.trading_mode == TradingMode.ISOLATED_MARGIN or \
self.trading_mode == TradingMode.ISOLATED_FUTURES:
isolated_liq = self.exchange.liq_formula(
trading_mode=self.trading_mode,
open_rate=enter_limit_filled_price,
amount=amount,
leverage=leverage,
is_short=is_short
)
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')