Merge branch 'feat/short' into max-amount

This commit is contained in:
Sam Germain
2022-02-04 04:42:38 -06:00
10 changed files with 187 additions and 40 deletions

View File

@@ -1227,7 +1227,8 @@ def test_buy_dry_run(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf)
order = exchange.create_order(pair='ETH/BTC', ordertype='limit', side="buy",
amount=1, rate=200, time_in_force='gtc')
amount=1, rate=200, leverage=1.0,
time_in_force='gtc')
assert 'id' in order
assert 'dry_run_buy_' in order['id']
@@ -1252,7 +1253,8 @@ def test_buy_prod(default_conf, mocker, exchange_name):
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1271,7 +1273,9 @@ def test_buy_prod(default_conf, mocker, exchange_name):
side="buy",
amount=1,
rate=200,
time_in_force=time_in_force)
leverage=1.0,
time_in_force=time_in_force
)
assert api_mock.create_order.call_args[0][0] == 'ETH/BTC'
assert api_mock.create_order.call_args[0][1] == order_type
assert api_mock.create_order.call_args[0][2] == 'buy'
@@ -1283,31 +1287,36 @@ def test_buy_prod(default_conf, mocker, exchange_name):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("Not enough funds"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype='limit', side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype='market', side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
with pytest.raises(TemporaryError):
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("Network disconnect"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
with pytest.raises(OperationalException):
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("Unknown error"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
@pytest.mark.parametrize("exchange_name", EXCHANGES)
@@ -1331,7 +1340,8 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
time_in_force = 'ioc'
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1348,7 +1358,8 @@ def test_buy_considers_time_in_force(default_conf, mocker, exchange_name):
time_in_force = 'ioc'
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1367,7 +1378,7 @@ def test_sell_dry_run(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf)
order = exchange.create_order(pair='ETH/BTC', ordertype='limit',
side="sell", amount=1, rate=200)
side="sell", amount=1, rate=200, leverage=1.0)
assert 'id' in order
assert 'dry_run_sell_' in order['id']
@@ -1392,7 +1403,7 @@ def test_sell_prod(default_conf, mocker, exchange_name):
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
side="sell", amount=1, rate=200)
side="sell", amount=1, rate=200, leverage=1.0)
assert 'id' in order
assert 'info' in order
@@ -1406,7 +1417,8 @@ def test_sell_prod(default_conf, mocker, exchange_name):
api_mock.create_order.reset_mock()
order_type = 'limit'
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
side="sell", amount=1, rate=200)
side="sell", amount=1, rate=200,
leverage=1.0)
assert api_mock.create_order.call_args[0][0] == 'ETH/BTC'
assert api_mock.create_order.call_args[0][1] == order_type
assert api_mock.create_order.call_args[0][2] == 'sell'
@@ -1417,28 +1429,33 @@ def test_sell_prod(default_conf, mocker, exchange_name):
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InsufficientFunds("0 balance"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200,
leverage=1.0)
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype='limit', side="sell", amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype='limit', side="sell", amount=1, rate=200,
leverage=1.0)
# Market orders don't require price, so the behaviour is slightly different
with pytest.raises(DependencyException):
api_mock.create_order = MagicMock(side_effect=ccxt.InvalidOrder("Order not found"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype='market', side="sell", amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype='market', side="sell", amount=1, rate=200,
leverage=1.0)
with pytest.raises(TemporaryError):
api_mock.create_order = MagicMock(side_effect=ccxt.NetworkError("No Connection"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200,
leverage=1.0)
with pytest.raises(OperationalException):
api_mock.create_order = MagicMock(side_effect=ccxt.BaseError("DeadBeef"))
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200)
exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell", amount=1, rate=200,
leverage=1.0)
@pytest.mark.parametrize("exchange_name", EXCHANGES)
@@ -1462,7 +1479,8 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
time_in_force = 'ioc'
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -1478,7 +1496,8 @@ def test_sell_considers_time_in_force(default_conf, mocker, exchange_name):
order_type = 'market'
time_in_force = 'ioc'
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="sell",
amount=1, rate=200, time_in_force=time_in_force)
amount=1, rate=200, leverage=1.0,
time_in_force=time_in_force)
assert 'id' in order
assert 'info' in order
@@ -3792,9 +3811,10 @@ def test__fetch_and_calculate_funding_fees_datetime_called(
d1 = datetime.strptime("2021-09-01 00:00:00 +0000", '%Y-%m-%d %H:%M:%S %z')
time_machine.move_to("2021-09-01 08:00:00 +00:00")
# TODO-lev: test this for longs
funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, True, d1)
assert funding_fees == expected_fees
funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, False, d1)
assert funding_fees == 0 - expected_fees
@pytest.mark.parametrize('pair,expected_size,trading_mode', [

View File

@@ -32,8 +32,15 @@ def test_buy_kraken_trading_agreement(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.price_to_precision', lambda s, x, y: y)
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type, side="buy",
amount=1, rate=200, time_in_force=time_in_force)
order = exchange.create_order(
pair='ETH/BTC',
ordertype=order_type,
side="buy",
amount=1,
rate=200,
leverage=1.0,
time_in_force=time_in_force
)
assert 'id' in order
assert 'info' in order
@@ -66,7 +73,7 @@ def test_sell_kraken_trading_agreement(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="kraken")
order = exchange.create_order(pair='ETH/BTC', ordertype=order_type,
side="sell", amount=1, rate=200)
side="sell", amount=1, rate=200, leverage=1.0)
assert 'id' in order
assert 'info' in order

View File

@@ -169,7 +169,6 @@ class StrategyTestV3(IStrategy):
),
'exit_short'] = 1
# TODO-lev: Add short logic
return dataframe
def leverage(self, pair: str, current_time: datetime, current_rate: float,

View File

@@ -4799,9 +4799,125 @@ def test_get_valid_price(mocker, default_conf_usdt) -> None:
assert valid_price_at_min_alwd < proposed_price
def test_leverage_prep():
# TODO-lev
return
@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', 'okex', '', 5.0, 10.0, 1.0, None),
(True, 'spot', 'okex', '', 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/okex, 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/okex, 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', 'okex', 'isolated', 11.87413417771621),
# (False, 'futures', 'okex', '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,
):
"""
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/Okex, 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/Okex, 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['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:
isclose(expected_liq, liq)
@pytest.mark.parametrize('trading_mode,calls,t1,t2', [