Liquidation price is in freqtradebot
This commit is contained in:
parent
1af6d8abca
commit
970ca71848
@ -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
|
|
||||||
|
@ -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")
|
|
||||||
|
@ -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)
|
||||||
|
@ -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?")
|
|
||||||
|
@ -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")
|
|
||||||
|
@ -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')
|
||||||
|
Loading…
Reference in New Issue
Block a user