Move leverage_prep calculations to exchange class
This commit is contained in:
parent
1121965c6e
commit
8e2d3445a7
@ -2055,6 +2055,42 @@ class Exchange:
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
|
def leverage_prep(
|
||||||
|
self,
|
||||||
|
pair: str,
|
||||||
|
open_rate: float,
|
||||||
|
amount: float, # quote currency, includes leverage
|
||||||
|
leverage: float,
|
||||||
|
is_short: bool
|
||||||
|
) -> Tuple[float, Optional[float]]:
|
||||||
|
|
||||||
|
# if TradingMode == TradingMode.MARGIN:
|
||||||
|
# interest_rate = self.get_interest_rate(
|
||||||
|
# pair=pair,
|
||||||
|
# open_rate=open_rate,
|
||||||
|
# is_short=is_short
|
||||||
|
# )
|
||||||
|
if self.trading_mode == TradingMode.SPOT:
|
||||||
|
return (0.0, None)
|
||||||
|
elif (
|
||||||
|
self.margin_mode == MarginMode.ISOLATED and
|
||||||
|
self.trading_mode == TradingMode.FUTURES
|
||||||
|
):
|
||||||
|
wallet_balance = (amount * open_rate) / leverage
|
||||||
|
isolated_liq = self.get_liquidation_price(
|
||||||
|
pair=pair,
|
||||||
|
open_rate=open_rate,
|
||||||
|
is_short=is_short,
|
||||||
|
position=amount,
|
||||||
|
wallet_balance=wallet_balance,
|
||||||
|
mm_ex_1=0.0,
|
||||||
|
upnl_ex_1=0.0,
|
||||||
|
)
|
||||||
|
return (0.0, isolated_liq)
|
||||||
|
else:
|
||||||
|
raise OperationalException(
|
||||||
|
"Freqtrade only supports isolated futures for leverage trading")
|
||||||
|
|
||||||
def funding_fee_cutoff(self, open_date: datetime):
|
def funding_fee_cutoff(self, open_date: datetime):
|
||||||
"""
|
"""
|
||||||
:param open_date: The open date for a trade
|
:param open_date: The open date for a trade
|
||||||
|
@ -578,42 +578,6 @@ 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, # quote currency, includes leverage
|
|
||||||
leverage: float,
|
|
||||||
is_short: bool
|
|
||||||
) -> Tuple[float, Optional[float]]:
|
|
||||||
|
|
||||||
# if TradingMode == TradingMode.MARGIN:
|
|
||||||
# interest_rate = self.exchange.get_interest_rate(
|
|
||||||
# pair=pair,
|
|
||||||
# open_rate=open_rate,
|
|
||||||
# is_short=is_short
|
|
||||||
# )
|
|
||||||
if self.trading_mode == TradingMode.SPOT:
|
|
||||||
return (0.0, None)
|
|
||||||
elif (
|
|
||||||
self.margin_mode == MarginMode.ISOLATED and
|
|
||||||
self.trading_mode == TradingMode.FUTURES
|
|
||||||
):
|
|
||||||
wallet_balance = (amount * open_rate)/leverage
|
|
||||||
isolated_liq = self.exchange.get_liquidation_price(
|
|
||||||
pair=pair,
|
|
||||||
open_rate=open_rate,
|
|
||||||
is_short=is_short,
|
|
||||||
position=amount,
|
|
||||||
wallet_balance=wallet_balance,
|
|
||||||
mm_ex_1=0.0,
|
|
||||||
upnl_ex_1=0.0,
|
|
||||||
)
|
|
||||||
return (0.0, isolated_liq)
|
|
||||||
else:
|
|
||||||
raise OperationalException(
|
|
||||||
"Freqtrade only supports isolated futures for leverage trading")
|
|
||||||
|
|
||||||
def execute_entry(
|
def execute_entry(
|
||||||
self,
|
self,
|
||||||
pair: str,
|
pair: str,
|
||||||
@ -724,7 +688,7 @@ 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, isolated_liq = self.leverage_prep(
|
interest_rate, isolated_liq = self.exchange.leverage_prep(
|
||||||
leverage=leverage,
|
leverage=leverage,
|
||||||
pair=pair,
|
pair=pair,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
|
@ -592,42 +592,6 @@ class Backtesting:
|
|||||||
else:
|
else:
|
||||||
return self._get_sell_trade_entry_for_candle(trade, sell_row)
|
return self._get_sell_trade_entry_for_candle(trade, sell_row)
|
||||||
|
|
||||||
def _leverage_prep(
|
|
||||||
self,
|
|
||||||
pair: str,
|
|
||||||
open_rate: float,
|
|
||||||
amount: float, # quote currency, includes leverage
|
|
||||||
leverage: float,
|
|
||||||
is_short: bool
|
|
||||||
) -> Tuple[float, Optional[float]]:
|
|
||||||
|
|
||||||
# if TradingMode == TradingMode.MARGIN:
|
|
||||||
# interest_rate = self.exchange.get_interest_rate(
|
|
||||||
# pair=pair,
|
|
||||||
# open_rate=open_rate,
|
|
||||||
# is_short=is_short
|
|
||||||
# )
|
|
||||||
if self.trading_mode == TradingMode.SPOT:
|
|
||||||
return (0.0, None)
|
|
||||||
elif (
|
|
||||||
self.margin_mode == MarginMode.ISOLATED and
|
|
||||||
self.trading_mode == TradingMode.FUTURES
|
|
||||||
):
|
|
||||||
wallet_balance = (amount * open_rate)/leverage
|
|
||||||
isolated_liq = self.exchange.get_liquidation_price(
|
|
||||||
pair=pair,
|
|
||||||
open_rate=open_rate,
|
|
||||||
is_short=is_short,
|
|
||||||
position=amount,
|
|
||||||
wallet_balance=wallet_balance,
|
|
||||||
mm_ex_1=0.0,
|
|
||||||
upnl_ex_1=0.0,
|
|
||||||
)
|
|
||||||
return (0.0, isolated_liq)
|
|
||||||
else:
|
|
||||||
raise OperationalException(
|
|
||||||
"Freqtrade only supports isolated futures for leverage trading")
|
|
||||||
|
|
||||||
def _enter_trade(self, pair: str, row: Tuple, direction: str,
|
def _enter_trade(self, pair: str, row: Tuple, direction: str,
|
||||||
stake_amount: Optional[float] = None,
|
stake_amount: Optional[float] = None,
|
||||||
trade: Optional[LocalTrade] = None) -> Optional[LocalTrade]:
|
trade: Optional[LocalTrade] = None) -> Optional[LocalTrade]:
|
||||||
@ -702,7 +666,7 @@ class Backtesting:
|
|||||||
self.order_id_counter += 1
|
self.order_id_counter += 1
|
||||||
amount = round((stake_amount / propose_rate) * leverage, 8)
|
amount = round((stake_amount / propose_rate) * leverage, 8)
|
||||||
is_short = (direction == 'short')
|
is_short = (direction == 'short')
|
||||||
(interest_rate, isolated_liq) = self._leverage_prep(
|
(interest_rate, isolated_liq) = self.exchange.leverage_prep(
|
||||||
pair=pair,
|
pair=pair,
|
||||||
open_rate=propose_rate,
|
open_rate=propose_rate,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
|
@ -4527,3 +4527,127 @@ def test__get_params(mocker, default_conf, exchange_name):
|
|||||||
time_in_force='ioc',
|
time_in_force='ioc',
|
||||||
leverage=3.0,
|
leverage=3.0,
|
||||||
) == params2
|
) == params2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('liquidation_buffer', [0.0, 0.05])
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"is_short,trading_mode,exchange_name,margin_mode,leverage,open_rate,amount,expected_liq", [
|
||||||
|
(False, 'spot', 'binance', '', 5.0, 10.0, 1.0, None),
|
||||||
|
(True, 'spot', 'binance', '', 5.0, 10.0, 1.0, None),
|
||||||
|
(False, 'spot', 'gateio', '', 5.0, 10.0, 1.0, None),
|
||||||
|
(True, 'spot', 'gateio', '', 5.0, 10.0, 1.0, None),
|
||||||
|
(False, 'spot', 'okx', '', 5.0, 10.0, 1.0, None),
|
||||||
|
(True, 'spot', 'okx', '', 5.0, 10.0, 1.0, None),
|
||||||
|
# Binance, short
|
||||||
|
(True, 'futures', 'binance', 'isolated', 5.0, 10.0, 1.0, 11.89108910891089),
|
||||||
|
(True, 'futures', 'binance', 'isolated', 3.0, 10.0, 1.0, 13.211221122079207),
|
||||||
|
(True, 'futures', 'binance', 'isolated', 5.0, 8.0, 1.0, 9.514851485148514),
|
||||||
|
(True, 'futures', 'binance', 'isolated', 5.0, 10.0, 0.6, 12.557755775577558),
|
||||||
|
# Binance, long
|
||||||
|
(False, 'futures', 'binance', 'isolated', 5, 10, 1.0, 8.070707070707071),
|
||||||
|
(False, 'futures', 'binance', 'isolated', 5, 8, 1.0, 6.454545454545454),
|
||||||
|
(False, 'futures', 'binance', 'isolated', 3, 10, 1.0, 6.717171717171718),
|
||||||
|
(False, 'futures', 'binance', 'isolated', 5, 10, 0.6, 7.39057239057239),
|
||||||
|
# Gateio/okx, short
|
||||||
|
(True, 'futures', 'gateio', 'isolated', 5, 10, 1.0, 11.87413417771621),
|
||||||
|
(True, 'futures', 'gateio', 'isolated', 5, 10, 2.0, 11.87413417771621),
|
||||||
|
(True, 'futures', 'gateio', 'isolated', 3, 10, 1.0, 13.476180850346978),
|
||||||
|
(True, 'futures', 'gateio', 'isolated', 5, 8, 1.0, 9.499307342172967),
|
||||||
|
# Gateio/okx, long
|
||||||
|
(False, 'futures', 'gateio', 'isolated', 5.0, 10.0, 1.0, 8.085708510208207),
|
||||||
|
(False, 'futures', 'gateio', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506),
|
||||||
|
# (True, 'futures', 'okx', 'isolated', 11.87413417771621),
|
||||||
|
# (False, 'futures', 'okx', 'isolated', 8.085708510208207),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_leverage_prep(
|
||||||
|
mocker,
|
||||||
|
default_conf_usdt,
|
||||||
|
is_short,
|
||||||
|
trading_mode,
|
||||||
|
exchange_name,
|
||||||
|
margin_mode,
|
||||||
|
leverage,
|
||||||
|
open_rate,
|
||||||
|
amount,
|
||||||
|
expected_liq,
|
||||||
|
liquidation_buffer,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
position = 0.2 * 5
|
||||||
|
wb: wallet balance (stake_amount if isolated)
|
||||||
|
cum_b: maintenance amount
|
||||||
|
side_1: -1 if is_short else 1
|
||||||
|
ep1: entry price
|
||||||
|
mmr_b: maintenance margin ratio
|
||||||
|
|
||||||
|
Binance, Short
|
||||||
|
leverage = 5, open_rate = 10, amount = 1.0
|
||||||
|
((wb + cum_b) - (side_1 * position * ep1)) / ((position * mmr_b) - (side_1 * position))
|
||||||
|
((2 + 0.01) - ((-1) * 1 * 10)) / ((1 * 0.01) - ((-1) * 1)) = 11.89108910891089
|
||||||
|
leverage = 3, open_rate = 10, amount = 1.0
|
||||||
|
((3.3333333333 + 0.01) - ((-1) * 1.0 * 10)) / ((1.0 * 0.01) - ((-1) * 1.0)) = 13.2112211220
|
||||||
|
leverage = 5, open_rate = 8, amount = 1.0
|
||||||
|
((1.6 + 0.01) - ((-1) * 1 * 8)) / ((1 * 0.01) - ((-1) * 1)) = 9.514851485148514
|
||||||
|
leverage = 5, open_rate = 10, amount = 0.6
|
||||||
|
((1.6 + 0.01) - ((-1) * 0.6 * 10)) / ((0.6 * 0.01) - ((-1) * 0.6)) = 12.557755775577558
|
||||||
|
|
||||||
|
Binance, Long
|
||||||
|
leverage = 5, open_rate = 10, amount = 1.0
|
||||||
|
((wb + cum_b) - (side_1 * position * ep1)) / ((position * mmr_b) - (side_1 * position))
|
||||||
|
((2 + 0.01) - (1 * 1 * 10)) / ((1 * 0.01) - (1 * 1)) = 8.070707070707071
|
||||||
|
leverage = 5, open_rate = 8, amount = 1.0
|
||||||
|
((1.6 + 0.01) - (1 * 1 * 8)) / ((1 * 0.01) - (1 * 1)) = 6.454545454545454
|
||||||
|
leverage = 3, open_rate = 10, amount = 1.0
|
||||||
|
((2 + 0.01) - (1 * 0.6 * 10)) / ((0.6 * 0.01) - (1 * 0.6)) = 6.717171717171718
|
||||||
|
leverage = 5, open_rate = 10, amount = 0.6
|
||||||
|
((1.6 + 0.01) - (1 * 0.6 * 10)) / ((0.6 * 0.01) - (1 * 0.6)) = 7.39057239057239
|
||||||
|
|
||||||
|
Gateio/Okx, Short
|
||||||
|
leverage = 5, open_rate = 10, amount = 1.0
|
||||||
|
(open_rate + (wallet_balance / position)) / (1 + (mm_ratio + taker_fee_rate))
|
||||||
|
(10 + (2 / 1.0)) / (1 + (0.01 + 0.0006)) = 11.87413417771621
|
||||||
|
leverage = 5, open_rate = 10, amount = 2.0
|
||||||
|
(10 + (4 / 2.0)) / (1 + (0.01 + 0.0006)) = 11.87413417771621
|
||||||
|
leverage = 3, open_rate = 10, amount = 1.0
|
||||||
|
(10 + (3.3333333333333 / 1.0)) / (1 - (0.01 + 0.0006)) = 13.476180850346978
|
||||||
|
leverage = 5, open_rate = 8, amount = 1.0
|
||||||
|
(8 + (1.6 / 1.0)) / (1 + (0.01 + 0.0006)) = 9.499307342172967
|
||||||
|
|
||||||
|
Gateio/Okx, Long
|
||||||
|
leverage = 5, open_rate = 10, amount = 1.0
|
||||||
|
(open_rate - (wallet_balance / position)) / (1 - (mm_ratio + taker_fee_rate))
|
||||||
|
(10 - (2 / 1)) / (1 - (0.01 + 0.0006)) = 8.085708510208207
|
||||||
|
leverage = 5, open_rate = 10, amount = 2.0
|
||||||
|
(10 - (4 / 2.0)) / (1 + (0.01 + 0.0006)) = 7.916089451810806
|
||||||
|
leverage = 3, open_rate = 10, amount = 1.0
|
||||||
|
(10 - (3.333333333333333333 / 1.0)) / (1 - (0.01 + 0.0006)) = 6.738090425173506
|
||||||
|
leverage = 5, open_rate = 8, amount = 1.0
|
||||||
|
(8 - (1.6 / 1.0)) / (1 + (0.01 + 0.0006)) = 6.332871561448645
|
||||||
|
"""
|
||||||
|
default_conf_usdt['liquidation_buffer'] = liquidation_buffer
|
||||||
|
default_conf_usdt['trading_mode'] = trading_mode
|
||||||
|
default_conf_usdt['exchange']['name'] = exchange_name
|
||||||
|
default_conf_usdt['margin_mode'] = margin_mode
|
||||||
|
mocker.patch('freqtrade.exchange.Gateio.validate_ordertypes')
|
||||||
|
exchange = get_patched_exchange(mocker, default_conf_usdt)
|
||||||
|
|
||||||
|
exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(0.01, 0.01))
|
||||||
|
exchange.name = exchange_name
|
||||||
|
# default_conf_usdt.update({
|
||||||
|
# "dry_run": False,
|
||||||
|
# })
|
||||||
|
(interest, liq) = exchange.leverage_prep(
|
||||||
|
pair='ETH/USDT:USDT',
|
||||||
|
open_rate=open_rate,
|
||||||
|
amount=amount,
|
||||||
|
leverage=leverage,
|
||||||
|
is_short=is_short,
|
||||||
|
)
|
||||||
|
assert interest == 0.0
|
||||||
|
if expected_liq is None:
|
||||||
|
assert liq is None
|
||||||
|
else:
|
||||||
|
buffer_amount = liquidation_buffer * abs(open_rate - expected_liq)
|
||||||
|
expected_liq = expected_liq - buffer_amount if is_short else expected_liq + buffer_amount
|
||||||
|
isclose(expected_liq, liq)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import random
|
import random
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
from math import isclose
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import MagicMock, PropertyMock
|
from unittest.mock import MagicMock, PropertyMock
|
||||||
|
|
||||||
@ -10,7 +11,6 @@ import numpy as np
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import pytest
|
import pytest
|
||||||
from arrow import Arrow
|
from arrow import Arrow
|
||||||
from math import isclose
|
|
||||||
|
|
||||||
from freqtrade import constants
|
from freqtrade import constants
|
||||||
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_backtesting
|
from freqtrade.commands.optimize_commands import setup_optimize_configuration, start_backtesting
|
||||||
|
@ -4839,132 +4839,6 @@ def test_get_valid_price(mocker, default_conf_usdt) -> None:
|
|||||||
assert valid_price_at_min_alwd < proposed_price
|
assert valid_price_at_min_alwd < proposed_price
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('liquidation_buffer', [0.0, 0.05])
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"is_short,trading_mode,exchange_name,margin_mode,leverage,open_rate,amount,expected_liq", [
|
|
||||||
(False, 'spot', 'binance', '', 5.0, 10.0, 1.0, None),
|
|
||||||
(True, 'spot', 'binance', '', 5.0, 10.0, 1.0, None),
|
|
||||||
(False, 'spot', 'gateio', '', 5.0, 10.0, 1.0, None),
|
|
||||||
(True, 'spot', 'gateio', '', 5.0, 10.0, 1.0, None),
|
|
||||||
(False, 'spot', 'okx', '', 5.0, 10.0, 1.0, None),
|
|
||||||
(True, 'spot', 'okx', '', 5.0, 10.0, 1.0, None),
|
|
||||||
# Binance, short
|
|
||||||
(True, 'futures', 'binance', 'isolated', 5.0, 10.0, 1.0, 11.89108910891089),
|
|
||||||
(True, 'futures', 'binance', 'isolated', 3.0, 10.0, 1.0, 13.211221122079207),
|
|
||||||
(True, 'futures', 'binance', 'isolated', 5.0, 8.0, 1.0, 9.514851485148514),
|
|
||||||
(True, 'futures', 'binance', 'isolated', 5.0, 10.0, 0.6, 12.557755775577558),
|
|
||||||
# Binance, long
|
|
||||||
(False, 'futures', 'binance', 'isolated', 5, 10, 1.0, 8.070707070707071),
|
|
||||||
(False, 'futures', 'binance', 'isolated', 5, 8, 1.0, 6.454545454545454),
|
|
||||||
(False, 'futures', 'binance', 'isolated', 3, 10, 1.0, 6.717171717171718),
|
|
||||||
(False, 'futures', 'binance', 'isolated', 5, 10, 0.6, 7.39057239057239),
|
|
||||||
# Gateio/okx, short
|
|
||||||
(True, 'futures', 'gateio', 'isolated', 5, 10, 1.0, 11.87413417771621),
|
|
||||||
(True, 'futures', 'gateio', 'isolated', 5, 10, 2.0, 11.87413417771621),
|
|
||||||
(True, 'futures', 'gateio', 'isolated', 3, 10, 1.0, 13.476180850346978),
|
|
||||||
(True, 'futures', 'gateio', 'isolated', 5, 8, 1.0, 9.499307342172967),
|
|
||||||
# Gateio/okx, long
|
|
||||||
(False, 'futures', 'gateio', 'isolated', 5.0, 10.0, 1.0, 8.085708510208207),
|
|
||||||
(False, 'futures', 'gateio', 'isolated', 3.0, 10.0, 1.0, 6.738090425173506),
|
|
||||||
# (True, 'futures', 'okx', 'isolated', 11.87413417771621),
|
|
||||||
# (False, 'futures', 'okx', 'isolated', 8.085708510208207),
|
|
||||||
]
|
|
||||||
)
|
|
||||||
def test_leverage_prep(
|
|
||||||
mocker,
|
|
||||||
default_conf_usdt,
|
|
||||||
is_short,
|
|
||||||
trading_mode,
|
|
||||||
exchange_name,
|
|
||||||
margin_mode,
|
|
||||||
leverage,
|
|
||||||
open_rate,
|
|
||||||
amount,
|
|
||||||
expected_liq,
|
|
||||||
liquidation_buffer,
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
position = 0.2 * 5
|
|
||||||
wb: wallet balance (stake_amount if isolated)
|
|
||||||
cum_b: maintenance amount
|
|
||||||
side_1: -1 if is_short else 1
|
|
||||||
ep1: entry price
|
|
||||||
mmr_b: maintenance margin ratio
|
|
||||||
|
|
||||||
Binance, Short
|
|
||||||
leverage = 5, open_rate = 10, amount = 1.0
|
|
||||||
((wb + cum_b) - (side_1 * position * ep1)) / ((position * mmr_b) - (side_1 * position))
|
|
||||||
((2 + 0.01) - ((-1) * 1 * 10)) / ((1 * 0.01) - ((-1) * 1)) = 11.89108910891089
|
|
||||||
leverage = 3, open_rate = 10, amount = 1.0
|
|
||||||
((3.3333333333 + 0.01) - ((-1) * 1.0 * 10)) / ((1.0 * 0.01) - ((-1) * 1.0)) = 13.2112211220
|
|
||||||
leverage = 5, open_rate = 8, amount = 1.0
|
|
||||||
((1.6 + 0.01) - ((-1) * 1 * 8)) / ((1 * 0.01) - ((-1) * 1)) = 9.514851485148514
|
|
||||||
leverage = 5, open_rate = 10, amount = 0.6
|
|
||||||
((1.6 + 0.01) - ((-1) * 0.6 * 10)) / ((0.6 * 0.01) - ((-1) * 0.6)) = 12.557755775577558
|
|
||||||
|
|
||||||
Binance, Long
|
|
||||||
leverage = 5, open_rate = 10, amount = 1.0
|
|
||||||
((wb + cum_b) - (side_1 * position * ep1)) / ((position * mmr_b) - (side_1 * position))
|
|
||||||
((2 + 0.01) - (1 * 1 * 10)) / ((1 * 0.01) - (1 * 1)) = 8.070707070707071
|
|
||||||
leverage = 5, open_rate = 8, amount = 1.0
|
|
||||||
((1.6 + 0.01) - (1 * 1 * 8)) / ((1 * 0.01) - (1 * 1)) = 6.454545454545454
|
|
||||||
leverage = 3, open_rate = 10, amount = 1.0
|
|
||||||
((2 + 0.01) - (1 * 0.6 * 10)) / ((0.6 * 0.01) - (1 * 0.6)) = 6.717171717171718
|
|
||||||
leverage = 5, open_rate = 10, amount = 0.6
|
|
||||||
((1.6 + 0.01) - (1 * 0.6 * 10)) / ((0.6 * 0.01) - (1 * 0.6)) = 7.39057239057239
|
|
||||||
|
|
||||||
Gateio/Okx, Short
|
|
||||||
leverage = 5, open_rate = 10, amount = 1.0
|
|
||||||
(open_rate + (wallet_balance / position)) / (1 + (mm_ratio + taker_fee_rate))
|
|
||||||
(10 + (2 / 1.0)) / (1 + (0.01 + 0.0006)) = 11.87413417771621
|
|
||||||
leverage = 5, open_rate = 10, amount = 2.0
|
|
||||||
(10 + (4 / 2.0)) / (1 + (0.01 + 0.0006)) = 11.87413417771621
|
|
||||||
leverage = 3, open_rate = 10, amount = 1.0
|
|
||||||
(10 + (3.3333333333333 / 1.0)) / (1 - (0.01 + 0.0006)) = 13.476180850346978
|
|
||||||
leverage = 5, open_rate = 8, amount = 1.0
|
|
||||||
(8 + (1.6 / 1.0)) / (1 + (0.01 + 0.0006)) = 9.499307342172967
|
|
||||||
|
|
||||||
Gateio/Okx, Long
|
|
||||||
leverage = 5, open_rate = 10, amount = 1.0
|
|
||||||
(open_rate - (wallet_balance / position)) / (1 - (mm_ratio + taker_fee_rate))
|
|
||||||
(10 - (2 / 1)) / (1 - (0.01 + 0.0006)) = 8.085708510208207
|
|
||||||
leverage = 5, open_rate = 10, amount = 2.0
|
|
||||||
(10 - (4 / 2.0)) / (1 + (0.01 + 0.0006)) = 7.916089451810806
|
|
||||||
leverage = 3, open_rate = 10, amount = 1.0
|
|
||||||
(10 - (3.333333333333333333 / 1.0)) / (1 - (0.01 + 0.0006)) = 6.738090425173506
|
|
||||||
leverage = 5, open_rate = 8, amount = 1.0
|
|
||||||
(8 - (1.6 / 1.0)) / (1 + (0.01 + 0.0006)) = 6.332871561448645
|
|
||||||
"""
|
|
||||||
default_conf_usdt['liquidation_buffer'] = liquidation_buffer
|
|
||||||
default_conf_usdt['trading_mode'] = trading_mode
|
|
||||||
default_conf_usdt['exchange']['name'] = exchange_name
|
|
||||||
default_conf_usdt['margin_mode'] = margin_mode
|
|
||||||
mocker.patch('freqtrade.exchange.Gateio.validate_ordertypes')
|
|
||||||
patch_RPCManager(mocker)
|
|
||||||
patch_exchange(mocker, id=exchange_name)
|
|
||||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
|
||||||
|
|
||||||
freqtrade.exchange.get_maintenance_ratio_and_amt = MagicMock(return_value=(0.01, 0.01))
|
|
||||||
freqtrade.exchange.name = exchange_name
|
|
||||||
# default_conf_usdt.update({
|
|
||||||
# "dry_run": False,
|
|
||||||
# })
|
|
||||||
(interest, liq) = freqtrade.leverage_prep(
|
|
||||||
pair='ETH/USDT:USDT',
|
|
||||||
open_rate=open_rate,
|
|
||||||
amount=amount,
|
|
||||||
leverage=leverage,
|
|
||||||
is_short=is_short,
|
|
||||||
)
|
|
||||||
assert interest == 0.0
|
|
||||||
if expected_liq is None:
|
|
||||||
assert liq is None
|
|
||||||
else:
|
|
||||||
buffer_amount = liquidation_buffer * abs(open_rate - expected_liq)
|
|
||||||
expected_liq = expected_liq - buffer_amount if is_short else expected_liq + buffer_amount
|
|
||||||
isclose(expected_liq, liq)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('trading_mode,calls,t1,t2', [
|
@pytest.mark.parametrize('trading_mode,calls,t1,t2', [
|
||||||
('spot', 0, "2021-09-01 00:00:00", "2021-09-01 08:00:00"),
|
('spot', 0, "2021-09-01 00:00:00", "2021-09-01 08:00:00"),
|
||||||
('margin', 0, "2021-09-01 00:00:00", "2021-09-01 08:00:00"),
|
('margin', 0, "2021-09-01 00:00:00", "2021-09-01 08:00:00"),
|
||||||
|
Loading…
Reference in New Issue
Block a user