Add prep functions to exchange
This commit is contained in:
parent
b3ca2d0c57
commit
120cad88af
@ -1,6 +1,6 @@
|
|||||||
""" Binance exchange subclass """
|
""" Binance exchange subclass """
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict
|
from typing import Dict, Optional
|
||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
|
|
||||||
@ -89,3 +89,104 @@ class Binance(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 transfer(self, asset: str, amount: float, frm: str, to: str, pair: Optional[str]):
|
||||||
|
res = self._api.sapi_post_margin_isolated_transfer({
|
||||||
|
"asset": asset,
|
||||||
|
"amount": amount,
|
||||||
|
"transFrom": frm,
|
||||||
|
"transTo": to,
|
||||||
|
"symbol": pair
|
||||||
|
})
|
||||||
|
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):
|
||||||
|
return stake_amount / leverage
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
""" Bittrex exchange subclass """
|
""" Bittrex exchange subclass """
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from freqtrade.exchange import Exchange
|
from freqtrade.exchange import Exchange
|
||||||
|
from freqtrade.exceptions import OperationalException
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -23,3 +24,23 @@ 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")
|
||||||
|
@ -184,6 +184,7 @@ class Exchange:
|
|||||||
'secret': exchange_config.get('secret'),
|
'secret': exchange_config.get('secret'),
|
||||||
'password': exchange_config.get('password'),
|
'password': exchange_config.get('password'),
|
||||||
'uid': exchange_config.get('uid', ''),
|
'uid': exchange_config.get('uid', ''),
|
||||||
|
'options': exchange_config.get('options', {})
|
||||||
}
|
}
|
||||||
if ccxt_kwargs:
|
if ccxt_kwargs:
|
||||||
logger.info('Applying additional ccxt config: %s', ccxt_kwargs)
|
logger.info('Applying additional ccxt config: %s', ccxt_kwargs)
|
||||||
@ -524,8 +525,9 @@ class Exchange:
|
|||||||
else:
|
else:
|
||||||
return 1 / pow(10, precision)
|
return 1 / pow(10, precision)
|
||||||
|
|
||||||
def get_min_pair_stake_amount(self, pair: str, price: float,
|
def get_min_pair_stake_amount(self, pair: str, price: float, stoploss: float,
|
||||||
stoploss: float) -> Optional[float]:
|
leverage: Optional[float] = 1.0) -> Optional[float]:
|
||||||
|
# TODO-mg: Using leverage makes the min stake amount lower (on binance at least)
|
||||||
try:
|
try:
|
||||||
market = self.markets[pair]
|
market = self.markets[pair]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -559,7 +561,20 @@ class Exchange:
|
|||||||
# The value returned should satisfy both limits: for amount (base currency) and
|
# The value returned should satisfy both limits: for amount (base currency) and
|
||||||
# for cost (quote, stake currency), so max() is used here.
|
# for cost (quote, stake currency), so max() is used here.
|
||||||
# See also #2575 at github.
|
# See also #2575 at github.
|
||||||
return max(min_stake_amounts) * amount_reserve_percent
|
return self.apply_leverage_to_stake_amount(
|
||||||
|
max(min_stake_amounts) * amount_reserve_percent,
|
||||||
|
leverage or 1.0
|
||||||
|
)
|
||||||
|
|
||||||
|
def apply_leverage_to_stake_amount(self, stake_amount: float, leverage: float):
|
||||||
|
"""
|
||||||
|
#* Should be implemented by child classes if leverage affects the stake_amount
|
||||||
|
Takes the minimum stake amount for a pair with no leverage and returns the minimum
|
||||||
|
stake amount when leverage is considered
|
||||||
|
:param stake_amount: The stake amount for a pair before leverage is considered
|
||||||
|
:param leverage: The amount of leverage being used on the current trade
|
||||||
|
"""
|
||||||
|
return stake_amount
|
||||||
|
|
||||||
# Dry-run methods
|
# Dry-run methods
|
||||||
|
|
||||||
@ -686,6 +701,15 @@ class Exchange:
|
|||||||
raise InvalidOrderException(
|
raise InvalidOrderException(
|
||||||
f'Tried to get an invalid dry-run-order (id: {order_id}). Message: {e}') from e
|
f'Tried to get an invalid dry-run-order (id: {order_id}). Message: {e}') from e
|
||||||
|
|
||||||
|
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
|
||||||
|
but higher than the config min_leverage
|
||||||
|
"""
|
||||||
|
|
||||||
|
raise OperationalException(f"Leverage is not available on {self.name} using freqtrade")
|
||||||
|
return 1.0
|
||||||
|
|
||||||
# Order handling
|
# Order handling
|
||||||
|
|
||||||
def create_order(self, pair: str, ordertype: str, side: str, amount: float,
|
def create_order(self, pair: str, ordertype: str, side: str, amount: float,
|
||||||
@ -709,6 +733,7 @@ class Exchange:
|
|||||||
order = self._api.create_order(pair, ordertype, side,
|
order = self._api.create_order(pair, ordertype, side,
|
||||||
amount, rate_for_order, params)
|
amount, rate_for_order, params)
|
||||||
self._log_exchange_response('create_order', order)
|
self._log_exchange_response('create_order', order)
|
||||||
|
|
||||||
return order
|
return order
|
||||||
|
|
||||||
except ccxt.InsufficientFunds as e:
|
except ccxt.InsufficientFunds as e:
|
||||||
@ -729,6 +754,26 @@ 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) -> bool:
|
def stoploss_adjust(self, stop_loss: float, order: Dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Verify stop_loss against stoploss-order value (limit or price)
|
Verify stop_loss against stoploss-order value (limit or price)
|
||||||
@ -1492,6 +1537,9 @@ 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 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)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
""" Kraken exchange subclass """
|
""" Kraken exchange subclass """
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
import ccxt
|
import ccxt
|
||||||
|
|
||||||
@ -124,3 +124,23 @@ 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
|
||||||
|
Loading…
Reference in New Issue
Block a user