Added is_short to conf tests

This commit is contained in:
Sam Germain 2021-09-14 21:08:15 -06:00
parent d3ab2f887f
commit d604757056
4 changed files with 179 additions and 127 deletions

View File

@ -727,7 +727,6 @@ class Exchange:
if not self.exchange_has('fetchL2OrderBook'): if not self.exchange_has('fetchL2OrderBook'):
return True return True
ob = self.fetch_l2_order_book(pair, 1) ob = self.fetch_l2_order_book(pair, 1)
breakpoint()
if side == 'buy': if side == 'buy':
price = ob['asks'][0][0] price = ob['asks'][0][0]
logger.debug(f"{pair} checking dry buy-order: price={price}, limit={limit}") logger.debug(f"{pair} checking dry buy-order: price={price}, limit={limit}")

View File

@ -29,6 +29,14 @@ from tests.conftest_trades import (leverage_trade, mock_trade_1, mock_trade_2, m
mock_trade_4, mock_trade_5, mock_trade_6, short_trade) mock_trade_4, mock_trade_5, mock_trade_6, short_trade)
def enter_side(is_short: bool):
return "sell" if is_short else "buy"
def exit_side(is_short: bool):
return "buy" if is_short else "sell"
logging.getLogger('').setLevel(logging.INFO) logging.getLogger('').setLevel(logging.INFO)
@ -216,7 +224,7 @@ def patch_get_signal(freqtrade: FreqtradeBot, enter_long=True, exit_long=False,
freqtrade.exchange.refresh_latest_ohlcv = lambda p: None freqtrade.exchange.refresh_latest_ohlcv = lambda p: None
def create_mock_trades(fee, use_db: bool = True): def create_mock_trades(fee, is_short: bool, use_db: bool = True):
""" """
Create some fake trades ... Create some fake trades ...
""" """
@ -227,22 +235,22 @@ def create_mock_trades(fee, use_db: bool = True):
LocalTrade.add_bt_trade(trade) LocalTrade.add_bt_trade(trade)
# Simulate dry_run entries # Simulate dry_run entries
trade = mock_trade_1(fee) trade = mock_trade_1(fee, is_short)
add_trade(trade) add_trade(trade)
trade = mock_trade_2(fee) trade = mock_trade_2(fee, is_short)
add_trade(trade) add_trade(trade)
trade = mock_trade_3(fee) trade = mock_trade_3(fee, is_short)
add_trade(trade) add_trade(trade)
trade = mock_trade_4(fee) trade = mock_trade_4(fee, is_short)
add_trade(trade) add_trade(trade)
trade = mock_trade_5(fee) trade = mock_trade_5(fee, is_short)
add_trade(trade) add_trade(trade)
trade = mock_trade_6(fee) trade = mock_trade_6(fee, is_short)
add_trade(trade) add_trade(trade)
if use_db: if use_db:

View File

@ -6,12 +6,24 @@ from freqtrade.persistence.models import Order, Trade
MOCK_TRADE_COUNT = 6 MOCK_TRADE_COUNT = 6
def mock_order_1(): def enter_side(is_short: bool):
return "sell" if is_short else "buy"
def exit_side(is_short: bool):
return "buy" if is_short else "sell"
def direc(is_short: bool):
return "short" if is_short else "long"
def mock_order_1(is_short: bool):
return { return {
'id': '1234', 'id': f'1234_{direc(is_short)}',
'symbol': 'ETH/BTC', 'symbol': 'ETH/BTC',
'status': 'closed', 'status': 'closed',
'side': 'buy', 'side': enter_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.123, 'price': 0.123,
'amount': 123.0, 'amount': 123.0,
@ -20,7 +32,7 @@ def mock_order_1():
} }
def mock_trade_1(fee): def mock_trade_1(fee, is_short: bool):
trade = Trade( trade = Trade(
pair='ETH/BTC', pair='ETH/BTC',
stake_amount=0.001, stake_amount=0.001,
@ -32,21 +44,22 @@ def mock_trade_1(fee):
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=17),
open_rate=0.123, open_rate=0.123,
exchange='binance', exchange='binance',
open_order_id='dry_run_buy_12345', open_order_id=f'dry_run_buy_{direc(is_short)}_12345',
strategy='StrategyTestV2', strategy='StrategyTestV2',
timeframe=5, timeframe=5,
is_short=is_short
) )
o = Order.parse_from_ccxt_object(mock_order_1(), 'ETH/BTC', 'buy') o = Order.parse_from_ccxt_object(mock_order_1(is_short), 'ETH/BTC', enter_side(is_short))
trade.orders.append(o) trade.orders.append(o)
return trade return trade
def mock_order_2(): def mock_order_2(is_short: bool):
return { return {
'id': '1235', 'id': f'1235_{direc(is_short)}',
'symbol': 'ETC/BTC', 'symbol': 'ETC/BTC',
'status': 'closed', 'status': 'closed',
'side': 'buy', 'side': enter_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.123, 'price': 0.123,
'amount': 123.0, 'amount': 123.0,
@ -55,12 +68,12 @@ def mock_order_2():
} }
def mock_order_2_sell(): def mock_order_2_sell(is_short: bool):
return { return {
'id': '12366', 'id': f'12366_{direc(is_short)}',
'symbol': 'ETC/BTC', 'symbol': 'ETC/BTC',
'status': 'closed', 'status': 'closed',
'side': 'sell', 'side': exit_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.128, 'price': 0.128,
'amount': 123.0, 'amount': 123.0,
@ -69,7 +82,7 @@ def mock_order_2_sell():
} }
def mock_trade_2(fee): def mock_trade_2(fee, is_short: bool):
""" """
Closed trade... Closed trade...
""" """
@ -82,30 +95,31 @@ def mock_trade_2(fee):
fee_close=fee.return_value, fee_close=fee.return_value,
open_rate=0.123, open_rate=0.123,
close_rate=0.128, close_rate=0.128,
close_profit=0.005, close_profit=-0.005 if is_short else 0.005,
close_profit_abs=0.000584127, close_profit_abs=-0.005584127 if is_short else 0.000584127,
exchange='binance', exchange='binance',
is_open=False, is_open=False,
open_order_id='dry_run_sell_12345', open_order_id=f'dry_run_sell_{direc(is_short)}_12345',
strategy='StrategyTestV2', strategy='StrategyTestV2',
timeframe=5, timeframe=5,
sell_reason='sell_signal', sell_reason='sell_signal',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2), close_date=datetime.now(tz=timezone.utc) - timedelta(minutes=2),
is_short=is_short
) )
o = Order.parse_from_ccxt_object(mock_order_2(), 'ETC/BTC', 'buy') o = Order.parse_from_ccxt_object(mock_order_2(is_short), 'ETC/BTC', enter_side(is_short))
trade.orders.append(o) trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_2_sell(), 'ETC/BTC', 'sell') o = Order.parse_from_ccxt_object(mock_order_2_sell(is_short), 'ETC/BTC', exit_side(is_short))
trade.orders.append(o) trade.orders.append(o)
return trade return trade
def mock_order_3(): def mock_order_3(is_short: bool):
return { return {
'id': '41231a12a', 'id': f'41231a12a_{direc(is_short)}',
'symbol': 'XRP/BTC', 'symbol': 'XRP/BTC',
'status': 'closed', 'status': 'closed',
'side': 'buy', 'side': enter_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.05, 'price': 0.05,
'amount': 123.0, 'amount': 123.0,
@ -114,12 +128,12 @@ def mock_order_3():
} }
def mock_order_3_sell(): def mock_order_3_sell(is_short: bool):
return { return {
'id': '41231a666a', 'id': f'41231a666a_{direc(is_short)}',
'symbol': 'XRP/BTC', 'symbol': 'XRP/BTC',
'status': 'closed', 'status': 'closed',
'side': 'sell', 'side': exit_side(is_short),
'type': 'stop_loss_limit', 'type': 'stop_loss_limit',
'price': 0.06, 'price': 0.06,
'average': 0.06, 'average': 0.06,
@ -129,7 +143,7 @@ def mock_order_3_sell():
} }
def mock_trade_3(fee): def mock_trade_3(fee, is_short: bool):
""" """
Closed trade Closed trade
""" """
@ -142,8 +156,8 @@ def mock_trade_3(fee):
fee_close=fee.return_value, fee_close=fee.return_value,
open_rate=0.05, open_rate=0.05,
close_rate=0.06, close_rate=0.06,
close_profit=0.01, close_profit=-0.01 if is_short else 0.01,
close_profit_abs=0.000155, close_profit_abs=-0.001155 if is_short else 0.000155,
exchange='binance', exchange='binance',
is_open=False, is_open=False,
strategy='StrategyTestV2', strategy='StrategyTestV2',
@ -151,20 +165,21 @@ def mock_trade_3(fee):
sell_reason='roi', sell_reason='roi',
open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20), open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=20),
close_date=datetime.now(tz=timezone.utc), close_date=datetime.now(tz=timezone.utc),
is_short=is_short
) )
o = Order.parse_from_ccxt_object(mock_order_3(), 'XRP/BTC', 'buy') o = Order.parse_from_ccxt_object(mock_order_3(is_short), 'XRP/BTC', enter_side(is_short))
trade.orders.append(o) trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_3_sell(), 'XRP/BTC', 'sell') o = Order.parse_from_ccxt_object(mock_order_3_sell(is_short), 'XRP/BTC', exit_side(is_short))
trade.orders.append(o) trade.orders.append(o)
return trade return trade
def mock_order_4(): def mock_order_4(is_short: bool):
return { return {
'id': 'prod_buy_12345', 'id': f'prod_buy_{direc(is_short)}_12345',
'symbol': 'ETC/BTC', 'symbol': 'ETC/BTC',
'status': 'open', 'status': 'open',
'side': 'buy', 'side': enter_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.123, 'price': 0.123,
'amount': 123.0, 'amount': 123.0,
@ -173,7 +188,7 @@ def mock_order_4():
} }
def mock_trade_4(fee): def mock_trade_4(fee, is_short: bool):
""" """
Simulate prod entry Simulate prod entry
""" """
@ -188,21 +203,22 @@ def mock_trade_4(fee):
is_open=True, is_open=True,
open_rate=0.123, open_rate=0.123,
exchange='binance', exchange='binance',
open_order_id='prod_buy_12345', open_order_id=f'prod_buy_{direc(is_short)}_12345',
strategy='StrategyTestV2', strategy='StrategyTestV2',
timeframe=5, timeframe=5,
is_short=is_short
) )
o = Order.parse_from_ccxt_object(mock_order_4(), 'ETC/BTC', 'buy') o = Order.parse_from_ccxt_object(mock_order_4(is_short), 'ETC/BTC', enter_side(is_short))
trade.orders.append(o) trade.orders.append(o)
return trade return trade
def mock_order_5(): def mock_order_5(is_short: bool):
return { return {
'id': 'prod_buy_3455', 'id': f'prod_buy_{direc(is_short)}_3455',
'symbol': 'XRP/BTC', 'symbol': 'XRP/BTC',
'status': 'closed', 'status': 'closed',
'side': 'buy', 'side': enter_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.123, 'price': 0.123,
'amount': 123.0, 'amount': 123.0,
@ -211,12 +227,12 @@ def mock_order_5():
} }
def mock_order_5_stoploss(): def mock_order_5_stoploss(is_short: bool):
return { return {
'id': 'prod_stoploss_3455', 'id': f'prod_stoploss_{direc(is_short)}_3455',
'symbol': 'XRP/BTC', 'symbol': 'XRP/BTC',
'status': 'open', 'status': 'open',
'side': 'sell', 'side': exit_side(is_short),
'type': 'stop_loss_limit', 'type': 'stop_loss_limit',
'price': 0.123, 'price': 0.123,
'amount': 123.0, 'amount': 123.0,
@ -225,7 +241,7 @@ def mock_order_5_stoploss():
} }
def mock_trade_5(fee): def mock_trade_5(fee, is_short: bool):
""" """
Simulate prod entry with stoploss Simulate prod entry with stoploss
""" """
@ -241,22 +257,23 @@ def mock_trade_5(fee):
open_rate=0.123, open_rate=0.123,
exchange='binance', exchange='binance',
strategy='SampleStrategy', strategy='SampleStrategy',
stoploss_order_id='prod_stoploss_3455', stoploss_order_id=f'prod_stoploss_{direc(is_short)}_3455',
timeframe=5, timeframe=5,
is_short=is_short
) )
o = Order.parse_from_ccxt_object(mock_order_5(), 'XRP/BTC', 'buy') o = Order.parse_from_ccxt_object(mock_order_5(is_short), 'XRP/BTC', enter_side(is_short))
trade.orders.append(o) trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_5_stoploss(), 'XRP/BTC', 'stoploss') o = Order.parse_from_ccxt_object(mock_order_5_stoploss(is_short), 'XRP/BTC', 'stoploss')
trade.orders.append(o) trade.orders.append(o)
return trade return trade
def mock_order_6(): def mock_order_6(is_short: bool):
return { return {
'id': 'prod_buy_6', 'id': f'prod_buy_{direc(is_short)}_6',
'symbol': 'LTC/BTC', 'symbol': 'LTC/BTC',
'status': 'closed', 'status': 'closed',
'side': 'buy', 'side': enter_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.15, 'price': 0.15,
'amount': 2.0, 'amount': 2.0,
@ -265,23 +282,23 @@ def mock_order_6():
} }
def mock_order_6_sell(): def mock_order_6_sell(is_short: bool):
return { return {
'id': 'prod_sell_6', 'id': f'prod_sell_{direc(is_short)}_6',
'symbol': 'LTC/BTC', 'symbol': 'LTC/BTC',
'status': 'open', 'status': 'open',
'side': 'sell', 'side': exit_side(is_short),
'type': 'limit', 'type': 'limit',
'price': 0.20, 'price': 0.15 if is_short else 0.20,
'amount': 2.0, 'amount': 2.0,
'filled': 0.0, 'filled': 0.0,
'remaining': 2.0, 'remaining': 2.0,
} }
def mock_trade_6(fee): def mock_trade_6(fee, is_short: bool):
""" """
Simulate prod entry with open sell order Simulate prod entry with open exit order
""" """
trade = Trade( trade = Trade(
pair='LTC/BTC', pair='LTC/BTC',
@ -295,12 +312,12 @@ def mock_trade_6(fee):
open_rate=0.15, open_rate=0.15,
exchange='binance', exchange='binance',
strategy='SampleStrategy', strategy='SampleStrategy',
open_order_id="prod_sell_6", open_order_id=f"prod_sell_{direc(is_short)}_6",
timeframe=5, timeframe=5,
) )
o = Order.parse_from_ccxt_object(mock_order_6(), 'LTC/BTC', 'buy') o = Order.parse_from_ccxt_object(mock_order_6(is_short), 'LTC/BTC', enter_side(is_short))
trade.orders.append(o) trade.orders.append(o)
o = Order.parse_from_ccxt_object(mock_order_6_sell(), 'LTC/BTC', 'sell') o = Order.parse_from_ccxt_object(mock_order_6_sell(is_short), 'LTC/BTC', exit_side(is_short))
trade.orders.append(o) trade.orders.append(o)
return trade return trade

View File

@ -28,6 +28,14 @@ from tests.conftest_trades import (MOCK_TRADE_COUNT, mock_order_1, mock_order_2,
mock_order_5_stoploss, mock_order_6_sell) mock_order_5_stoploss, mock_order_6_sell)
def enter_side(is_short: bool):
return "sell" if is_short else "buy"
def exit_side(is_short: bool):
return "buy" if is_short else "sell"
def patch_RPCManager(mocker) -> MagicMock: def patch_RPCManager(mocker) -> MagicMock:
""" """
This function mock RPC manager to avoid repeating this code in almost every tests This function mock RPC manager to avoid repeating this code in almost every tests
@ -2394,8 +2402,8 @@ def test_check_handle_cancelled_buy(default_conf, ticker, limit_buy_order_old, o
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old, open_trade, is_short, def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_order_old, open_trade,
fee, mocker) -> None: is_short, fee, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()
patch_exchange(mocker) patch_exchange(mocker)
@ -2421,8 +2429,8 @@ def test_check_handle_timedout_buy_exception(default_conf, ticker, limit_buy_ord
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_check_handle_timedout_sell_usercustom(default_conf, ticker, limit_sell_order_old, mocker, is_short, def test_check_handle_timedout_sell_usercustom(default_conf, ticker, limit_sell_order_old, mocker,
open_trade) -> None: is_short, open_trade) -> None:
default_conf["unfilledtimeout"] = {"buy": 1440, "sell": 1440} default_conf["unfilledtimeout"] = {"buy": 1440, "sell": 1440}
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()
@ -2502,8 +2510,8 @@ def test_check_handle_timedout_sell(default_conf, ticker, limit_sell_order_old,
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old, open_trade, is_short, def test_check_handle_cancelled_sell(default_conf, ticker, limit_sell_order_old, open_trade,
mocker, caplog) -> None: is_short, mocker, caplog) -> None:
""" Handle sell order cancelled on exchange""" """ Handle sell order cancelled on exchange"""
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()
@ -2602,9 +2610,10 @@ def test_check_handle_timedout_partial_fee(default_conf, ticker, open_trade, cap
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade, caplog, fee, is_short, def test_check_handle_timedout_partial_except(
limit_buy_order_old_partial, trades_for_order, default_conf, ticker, open_trade, caplog, fee, is_short, limit_buy_order_old_partial,
limit_buy_order_old_partial_canceled, mocker) -> None: trades_for_order, limit_buy_order_old_partial_canceled, mocker
) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock(return_value=limit_buy_order_old_partial_canceled) cancel_order_mock = MagicMock(return_value=limit_buy_order_old_partial_canceled)
patch_exchange(mocker) patch_exchange(mocker)
@ -2642,7 +2651,8 @@ def test_check_handle_timedout_partial_except(default_conf, ticker, open_trade,
assert trades[0].fee_open == fee() assert trades[0].fee_open == fee()
def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocker, caplog, is_short) -> None: def test_check_handle_timedout_exception(default_conf, ticker, open_trade,
mocker, caplog) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()
@ -2664,7 +2674,7 @@ def test_check_handle_timedout_exception(default_conf, ticker, open_trade, mocke
freqtrade.check_handle_timedout() freqtrade.check_handle_timedout()
assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, " assert log_has_re(r"Cannot query order for Trade\(id=1, pair=ETH/BTC, amount=90.99181073, "
r"is_short=False, leverage=1.0, " f"is_short=False, leverage=1.0, "
r"open_rate=0.00001099, open_since=" r"open_rate=0.00001099, open_since="
f"{open_trade.open_date.strftime('%Y-%m-%d %H:%M:%S')}" f"{open_trade.open_date.strftime('%Y-%m-%d %H:%M:%S')}"
r"\) due to Traceback \(most recent call last\):\n*", r"\) due to Traceback \(most recent call last\):\n*",
@ -2905,7 +2915,8 @@ def test_execute_trade_exit_up(default_conf, ticker, fee, ticker_sell_up, mocker
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_execute_trade_exit_down(default_conf, ticker, fee, ticker_sell_down, mocker, is_short) -> None: def test_execute_trade_exit_down(default_conf, ticker, fee, ticker_sell_down,
mocker, is_short) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3120,8 +3131,8 @@ def test_execute_trade_exit_sloe_cancel_exception(
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up, is_short, def test_execute_trade_exit_with_stoploss_on_exchange(default_conf, ticker, fee, ticker_sell_up,
mocker) -> None: is_short, mocker) -> None:
default_conf['exchange']['name'] = 'binance' default_conf['exchange']['name'] = 'binance'
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
@ -3343,8 +3354,8 @@ def test_execute_trade_exit_insufficient_funds_error(default_conf, ticker, fee,
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy_order_open, is_short, def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy_order_open,
fee, mocker) -> None: is_short, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3384,8 +3395,8 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, limit_buy
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, limit_buy_order_open, is_short, def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, limit_buy_order_open,
fee, mocker) -> None: is_short, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3419,8 +3430,8 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, limit_bu
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, limit_buy_order_open, is_short, def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, limit_buy_order_open,
fee, mocker) -> None: is_short, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3453,8 +3464,8 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, limit_buy_o
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, limit_buy_order_open, is_short, def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, limit_buy_order_open,
fee, mocker) -> None: is_short, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3577,7 +3588,8 @@ def test__safe_exit_amount_error(default_conf, fee, caplog, mocker):
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_locked_pairs(default_conf, ticker, fee, ticker_sell_down, mocker, caplog, is_short) -> None: def test_locked_pairs(default_conf, ticker, fee,
ticker_sell_down, mocker, caplog, is_short) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -3707,8 +3719,8 @@ def test_trailing_stop_loss(default_conf, limit_buy_order_open, limit_buy_order,
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_order_open, fee, is_short, def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_order_open, fee,
caplog, mocker) -> None: is_short, caplog, mocker) -> None:
buy_price = limit_buy_order['price'] buy_price = limit_buy_order['price']
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -3769,8 +3781,8 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, limit_buy_or
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_order_open, fee, is_short, def test_trailing_stop_loss_offset(default_conf, limit_buy_order, limit_buy_order_open, fee,
caplog, mocker) -> None: is_short, caplog, mocker) -> None:
buy_price = limit_buy_order['price'] buy_price = limit_buy_order['price']
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
@ -3897,8 +3909,8 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, limit_buy_order_
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open, is_short, def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, limit_buy_order_open,
fee, mocker) -> None: is_short, fee, mocker) -> None:
patch_RPCManager(mocker) patch_RPCManager(mocker)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
@ -4311,8 +4323,8 @@ def test_apply_fee_conditional(default_conf, fee, caplog, mocker,
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, limit_buy_order, is_short, def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order_open, limit_buy_order,
fee, mocker, order_book_l2): is_short, fee, mocker, order_book_l2):
default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True default_conf['bid_strategy']['check_depth_of_market']['enabled'] = True
default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1 default_conf['bid_strategy']['check_depth_of_market']['bids_to_ask_delta'] = 0.1
patch_RPCManager(mocker) patch_RPCManager(mocker)
@ -4516,7 +4528,8 @@ def test_startup_trade_reinit(default_conf, edge_conf, mocker):
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_open, caplog, is_short): def test_sync_wallet_dry_run(
mocker, default_conf, ticker, fee, limit_buy_order_open, caplog, is_short):
default_conf['dry_run'] = True default_conf['dry_run'] = True
# Initialize to 2 times stake amount # Initialize to 2 times stake amount
default_conf['dry_run_wallet'] = 0.002 default_conf['dry_run_wallet'] = 0.002
@ -4549,7 +4562,8 @@ def test_sync_wallet_dry_run(mocker, default_conf, ticker, fee, limit_buy_order_
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("is_short", [False, True]) @pytest.mark.parametrize("is_short", [False, True])
def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limit_sell_order, is_short): def test_cancel_all_open_orders(
mocker, default_conf, fee, limit_buy_order, limit_sell_order, is_short):
default_conf['cancel_open_orders_on_exit'] = True default_conf['cancel_open_orders_on_exit'] = True
mocker.patch('freqtrade.exchange.Exchange.fetch_order', mocker.patch('freqtrade.exchange.Exchange.fetch_order',
side_effect=[ side_effect=[
@ -4558,7 +4572,7 @@ def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limi
sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit') sell_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.handle_cancel_exit')
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
create_mock_trades(fee) create_mock_trades(fee, is_short=is_short)
trades = Trade.query.all() trades = Trade.query.all()
assert len(trades) == MOCK_TRADE_COUNT assert len(trades) == MOCK_TRADE_COUNT
freqtrade.cancel_all_open_orders() freqtrade.cancel_all_open_orders()
@ -4567,13 +4581,14 @@ def test_cancel_all_open_orders(mocker, default_conf, fee, limit_buy_order, limi
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
def test_check_for_open_trades(mocker, default_conf, fee): @pytest.mark.parametrize("is_short", [False, True])
def test_check_for_open_trades(mocker, default_conf, fee, is_short):
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
freqtrade.check_for_open_trades() freqtrade.check_for_open_trades()
assert freqtrade.rpc.send_msg.call_count == 0 assert freqtrade.rpc.send_msg.call_count == 0
create_mock_trades(fee) create_mock_trades(fee, is_short)
trade = Trade.query.first() trade = Trade.query.first()
trade.is_open = True trade.is_open = True
@ -4582,10 +4597,11 @@ def test_check_for_open_trades(mocker, default_conf, fee):
assert 'Handle these trades manually' in freqtrade.rpc.send_msg.call_args[0][0]['status'] assert 'Handle these trades manually' in freqtrade.rpc.send_msg.call_args[0][0]['status']
@pytest.mark.parametrize("is_short", [False, True])
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
def test_update_open_orders(mocker, default_conf, fee, caplog): def test_update_open_orders(mocker, default_conf, fee, caplog, is_short):
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
create_mock_trades(fee) create_mock_trades(fee, is_short=is_short)
freqtrade.update_open_orders() freqtrade.update_open_orders()
assert not log_has_re(r"Error updating Order .*", caplog) assert not log_has_re(r"Error updating Order .*", caplog)
@ -4598,7 +4614,7 @@ def test_update_open_orders(mocker, default_conf, fee, caplog):
caplog.clear() caplog.clear()
assert len(Order.get_open_orders()) == 3 assert len(Order.get_open_orders()) == 3
matching_buy_order = mock_order_4() matching_buy_order = mock_order_4(is_short=is_short)
matching_buy_order.update({ matching_buy_order.update({
'status': 'closed', 'status': 'closed',
}) })
@ -4620,19 +4636,20 @@ def test_update_closed_trades_without_assigned_fees(mocker, default_conf, fee, i
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
side_effect=[ side_effect=[
patch_with_fee(mock_order_2_sell()), patch_with_fee(mock_order_2_sell(is_short=is_short)),
patch_with_fee(mock_order_3_sell()), patch_with_fee(mock_order_3_sell(is_short=is_short)),
patch_with_fee(mock_order_1()), patch_with_fee(mock_order_1(is_short=is_short)),
patch_with_fee(mock_order_2()), patch_with_fee(mock_order_2(is_short=is_short)),
patch_with_fee(mock_order_3()), patch_with_fee(mock_order_3(is_short=is_short)),
patch_with_fee(mock_order_4()), patch_with_fee(mock_order_4(is_short=is_short)),
] ]
) )
create_mock_trades(fee) create_mock_trades(fee, is_short=is_short)
trades = Trade.get_trades().all() trades = Trade.get_trades().all()
assert len(trades) == MOCK_TRADE_COUNT assert len(trades) == MOCK_TRADE_COUNT
for trade in trades: for trade in trades:
trade.is_short = is_short
assert trade.fee_open_cost is None assert trade.fee_open_cost is None
assert trade.fee_open_currency is None assert trade.fee_open_currency is None
assert trade.fee_close_cost is None assert trade.fee_close_cost is None
@ -4659,7 +4676,7 @@ def test_update_closed_trades_without_assigned_fees(mocker, default_conf, fee, i
for trade in trades: for trade in trades:
if trade.is_open: if trade.is_open:
# Exclude Trade 4 - as the order is still open. # Exclude Trade 4 - as the order is still open.
if trade.select_order('buy', False): if trade.select_order(enter_side(is_short), False):
assert trade.fee_open_cost is not None assert trade.fee_open_cost is not None
assert trade.fee_open_currency is not None assert trade.fee_open_currency is not None
else: else:
@ -4677,15 +4694,23 @@ def test_reupdate_enter_order_fees(mocker, default_conf, fee, caplog, is_short):
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state') mock_uts = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.update_trade_state')
create_mock_trades(fee) create_mock_trades(fee, is_short=is_short)
trades = Trade.get_trades().all() trades = Trade.get_trades().all()
freqtrade.reupdate_enter_order_fees(trades[0]) freqtrade.reupdate_enter_order_fees(trades[0])
assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) assert log_has_re(
f"Trying to reupdate {enter_side(is_short)} "
r"fees for .*",
caplog
)
assert mock_uts.call_count == 1 assert mock_uts.call_count == 1
assert mock_uts.call_args_list[0][0][0] == trades[0] assert mock_uts.call_args_list[0][0][0] == trades[0]
assert mock_uts.call_args_list[0][0][1] == mock_order_1()['id'] assert mock_uts.call_args_list[0][0][1] == mock_order_1(is_short=is_short)['id']
assert log_has_re(r"Updating buy-fee on trade .* for order .*\.", caplog) assert log_has_re(
f"Updating {enter_side(is_short)}-fee on trade "
r".* for order .*\.",
caplog
)
mock_uts.reset_mock() mock_uts.reset_mock()
caplog.clear() caplog.clear()
@ -4700,22 +4725,24 @@ def test_reupdate_enter_order_fees(mocker, default_conf, fee, caplog, is_short):
amount=20, amount=20,
open_rate=0.01, open_rate=0.01,
exchange='binance', exchange='binance',
is_short=is_short
) )
Trade.query.session.add(trade) Trade.query.session.add(trade)
freqtrade.reupdate_enter_order_fees(trade) freqtrade.reupdate_enter_order_fees(trade)
assert log_has_re(r"Trying to reupdate buy fees for .*", caplog) assert log_has_re(f"Trying to reupdate {enter_side(is_short)} fees for "
r".*", caplog)
assert mock_uts.call_count == 0 assert mock_uts.call_count == 0
assert not log_has_re(r"Updating buy-fee on trade .* for order .*\.", caplog) assert not log_has_re(f"Updating {enter_side(is_short)}-fee on trade "
r".* for order .*\.", caplog)
@pytest.mark.usefixtures("init_persistence") @pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("is_short", [False, True]) def test_handle_insufficient_funds(mocker, default_conf, fee):
def test_handle_insufficient_funds(mocker, default_conf, fee, is_short):
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
mock_rlo = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.refind_lost_order') mock_rlo = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.refind_lost_order')
mock_bof = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.reupdate_enter_order_fees') mock_bof = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.reupdate_enter_order_fees')
create_mock_trades(fee) create_mock_trades(fee, is_short=False)
trades = Trade.get_trades().all() trades = Trade.get_trades().all()
# Trade 0 has only a open buy order, no closed order # Trade 0 has only a open buy order, no closed order
@ -4761,8 +4788,9 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog, is_short):
def reset_open_orders(trade): def reset_open_orders(trade):
trade.open_order_id = None trade.open_order_id = None
trade.stoploss_order_id = None trade.stoploss_order_id = None
trade.is_short = is_short
create_mock_trades(fee) create_mock_trades(fee, is_short=is_short)
trades = Trade.get_trades().all() trades = Trade.get_trades().all()
caplog.clear() caplog.clear()
@ -4774,7 +4802,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog, is_short):
assert trade.stoploss_order_id is None assert trade.stoploss_order_id is None
freqtrade.refind_lost_order(trade) freqtrade.refind_lost_order(trade)
order = mock_order_1() order = mock_order_1(is_short=is_short)
assert log_has_re(r"Order Order(.*order_id=" + order['id'] + ".*) is no longer open.", caplog) assert log_has_re(r"Order Order(.*order_id=" + order['id'] + ".*) is no longer open.", caplog)
assert mock_fo.call_count == 0 assert mock_fo.call_count == 0
assert mock_uts.call_count == 0 assert mock_uts.call_count == 0
@ -4792,7 +4820,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog, is_short):
assert trade.stoploss_order_id is None assert trade.stoploss_order_id is None
freqtrade.refind_lost_order(trade) freqtrade.refind_lost_order(trade)
order = mock_order_4() order = mock_order_4(is_short=is_short)
assert log_has_re(r"Trying to refind Order\(.*", caplog) assert log_has_re(r"Trying to refind Order\(.*", caplog)
assert mock_fo.call_count == 0 assert mock_fo.call_count == 0
assert mock_uts.call_count == 0 assert mock_uts.call_count == 0
@ -4810,7 +4838,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog, is_short):
assert trade.stoploss_order_id is None assert trade.stoploss_order_id is None
freqtrade.refind_lost_order(trade) freqtrade.refind_lost_order(trade)
order = mock_order_5_stoploss() order = mock_order_5_stoploss(is_short=is_short)
assert log_has_re(r"Trying to refind Order\(.*", caplog) assert log_has_re(r"Trying to refind Order\(.*", caplog)
assert mock_fo.call_count == 1 assert mock_fo.call_count == 1
assert mock_uts.call_count == 1 assert mock_uts.call_count == 1
@ -4829,7 +4857,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog, is_short):
assert trade.stoploss_order_id is None assert trade.stoploss_order_id is None
freqtrade.refind_lost_order(trade) freqtrade.refind_lost_order(trade)
order = mock_order_6_sell() order = mock_order_6_sell(is_short=is_short)
assert log_has_re(r"Trying to refind Order\(.*", caplog) assert log_has_re(r"Trying to refind Order\(.*", caplog)
assert mock_fo.call_count == 1 assert mock_fo.call_count == 1
assert mock_uts.call_count == 1 assert mock_uts.call_count == 1
@ -4842,7 +4870,7 @@ def test_refind_lost_order(mocker, default_conf, fee, caplog, is_short):
# Test error case # Test error case
mock_fo = mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', mock_fo = mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
side_effect=ExchangeError()) side_effect=ExchangeError())
order = mock_order_5_stoploss() order = mock_order_5_stoploss(is_short=is_short)
freqtrade.refind_lost_order(trades[4]) freqtrade.refind_lost_order(trades[4])
assert log_has(f"Error updating {order['id']}.", caplog) assert log_has(f"Error updating {order['id']}.", caplog)