From 01ad65de68f30d9516ae5ce4da9417a4bcaae49c Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 13 Nov 2021 19:22:43 -0600 Subject: [PATCH 1/6] test_rpc_apiserver.py --- .../plugins/protections/stoploss_guard.py | 2 +- tests/rpc/test_rpc_apiserver.py | 22 +++++++++---------- tests/rpc/test_rpc_telegram.py | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index 888dc0316..79b311f2b 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -32,7 +32,7 @@ class StoplossGuard(IProtection): def _reason(self) -> str: """ LockReason to use - #TODO-lev: check if min is the right word for shorts + # TODO-lev: check if min is the right word for shorts """ return (f'{self._trade_limit} stoplosses in {self._lookback_period} min, ' f'locking for {self._stop_duration} min.') diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index a3788872f..e0e73f6f1 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -586,10 +586,10 @@ def test_api_trades(botclient, mocker, fee, markets, is_short): assert rc.json()['total_trades'] == 2 -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) -def test_api_trade_single(botclient, mocker, fee, ticker, markets): +@pytest.mark.parametrize('is_short', [True, False]) +def test_api_trade_single(botclient, mocker, fee, ticker, markets, is_short): ftbot, client = botclient - patch_get_signal(ftbot) + patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short) mocker.patch.multiple( 'freqtrade.exchange.Exchange', markets=PropertyMock(return_value=markets), @@ -599,7 +599,7 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets): assert_response(rc, 404) assert rc.json()['detail'] == 'Trade not found.' - create_mock_trades(fee, False) + create_mock_trades(fee, is_short=is_short) Trade.query.session.flush() rc = client_get(client, f"{BASE_URI}/trade/3") @@ -607,10 +607,10 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets): assert rc.json()['trade_id'] == 3 -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) -def test_api_delete_trade(botclient, mocker, fee, markets): +@pytest.mark.parametrize('is_short', [True, False]) +def test_api_delete_trade(botclient, mocker, fee, markets, is_short): ftbot, client = botclient - patch_get_signal(ftbot) + patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short) stoploss_mock = MagicMock() cancel_mock = MagicMock() mocker.patch.multiple( @@ -749,10 +749,10 @@ def test_api_profit(botclient, mocker, ticker, fee, markets): } -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) -def test_api_stats(botclient, mocker, ticker, fee, markets,): +@pytest.mark.parametrize('is_short', [True, False]) +def test_api_stats(botclient, mocker, ticker, fee, markets, is_short): ftbot, client = botclient - patch_get_signal(ftbot) + patch_get_signal(ftbot, enter_long=not is_short, enter_short=is_short) mocker.patch.multiple( 'freqtrade.exchange.Exchange', get_balances=MagicMock(return_value=ticker), @@ -766,7 +766,7 @@ def test_api_stats(botclient, mocker, ticker, fee, markets,): assert 'durations' in rc.json() assert 'sell_reasons' in rc.json() - create_mock_trades(fee, False) + create_mock_trades(fee, is_short=is_short) rc = client_get(client, f"{BASE_URI}/stats") assert_response(rc, 200) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index d88c7b24e..522883a36 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1261,8 +1261,8 @@ def test_edge_enabled(edge_conf, update, mocker) -> None: assert 'Winrate' not in msg_mock.call_args_list[0][0][0] -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) -def test_telegram_trades(mocker, update, default_conf, fee): +@pytest.mark.parametrize('is_short', [True, False]) +def test_telegram_trades(mocker, update, default_conf, fee, is_short): telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) From ca9805112db78cfa7b2d87e7dd1bca8b8cb95314 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 13 Nov 2021 19:26:30 -0600 Subject: [PATCH 2/6] test_get_trades_proxy and test_select_order for shorts passes --- tests/test_persistence.py | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 9dd5b175b..2d4a7406f 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -1907,12 +1907,12 @@ def test_get_total_closed_profit(fee, use_db): @pytest.mark.usefixtures("init_persistence") -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) +@pytest.mark.parametrize('is_short', [True, False]) @pytest.mark.parametrize('use_db', [True, False]) -def test_get_trades_proxy(fee, use_db): +def test_get_trades_proxy(fee, use_db, is_short): Trade.use_db = use_db Trade.reset_trades() - create_mock_trades(fee, False, use_db) + create_mock_trades(fee, is_short, use_db) trades = Trade.get_trades_proxy() assert len(trades) == 6 @@ -2042,48 +2042,48 @@ def test_update_order_from_ccxt(caplog): @pytest.mark.usefixtures("init_persistence") -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) -def test_select_order(fee): - create_mock_trades(fee, False) +@pytest.mark.parametrize('is_short', [True, False]) +def test_select_order(fee, is_short): + create_mock_trades(fee, is_short) trades = Trade.get_trades().all() # Open buy order, no sell order - order = trades[0].select_order('buy', True) + order = trades[0].select_order(trades[0].enter_side, True) assert order is None - order = trades[0].select_order('buy', False) + order = trades[0].select_order(trades[0].enter_side, False) assert order is not None - order = trades[0].select_order('sell', None) + order = trades[0].select_order(trades[0].exit_side, None) assert order is None # closed buy order, and open sell order - order = trades[1].select_order('buy', True) + order = trades[1].select_order(trades[1].enter_side, True) assert order is None - order = trades[1].select_order('buy', False) + order = trades[1].select_order(trades[1].enter_side, False) assert order is not None - order = trades[1].select_order('buy', None) + order = trades[1].select_order(trades[1].enter_side, None) assert order is not None - order = trades[1].select_order('sell', True) + order = trades[1].select_order(trades[1].exit_side, True) assert order is None - order = trades[1].select_order('sell', False) + order = trades[1].select_order(trades[1].exit_side, False) assert order is not None # Has open buy order - order = trades[3].select_order('buy', True) + order = trades[3].select_order(trades[3].enter_side, True) assert order is not None - order = trades[3].select_order('buy', False) + order = trades[3].select_order(trades[3].enter_side, False) assert order is None # Open sell order - order = trades[4].select_order('buy', True) + order = trades[4].select_order(trades[4].enter_side, True) assert order is None - order = trades[4].select_order('buy', False) + order = trades[4].select_order(trades[4].enter_side, False) assert order is not None - order = trades[4].select_order('sell', True) + order = trades[4].select_order(trades[4].exit_side, True) assert order is not None assert order.ft_order_side == 'stoploss' - order = trades[4].select_order('sell', False) + order = trades[4].select_order(trades[4].exit_side, False) assert order is None From 77f8f8658cd6e820bd0551757e2fd8a7d66ac2df Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 13 Nov 2021 19:36:49 -0600 Subject: [PATCH 3/6] test_rpc_telegram short test --- tests/rpc/test_rpc_telegram.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/rpc/test_rpc_telegram.py b/tests/rpc/test_rpc_telegram.py index 522883a36..323eddd4d 100644 --- a/tests/rpc/test_rpc_telegram.py +++ b/tests/rpc/test_rpc_telegram.py @@ -1261,8 +1261,8 @@ def test_edge_enabled(edge_conf, update, mocker) -> None: assert 'Winrate' not in msg_mock.call_args_list[0][0][0] -@pytest.mark.parametrize('is_short', [True, False]) -def test_telegram_trades(mocker, update, default_conf, fee, is_short): +# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) +def test_telegram_trades(mocker, update, default_conf, fee): telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) @@ -1294,8 +1294,8 @@ def test_telegram_trades(mocker, update, default_conf, fee, is_short): msg_mock.call_args_list[0][0][0])) -# TODO-lev: @pytest.mark.parametrize('is_short', [True, False]) -def test_telegram_delete_trade(mocker, update, default_conf, fee): +@pytest.mark.parametrize('is_short', [True, False]) +def test_telegram_delete_trade(mocker, update, default_conf, fee, is_short): telegram, _, msg_mock = get_telegram_testobject(mocker, default_conf) context = MagicMock() @@ -1305,7 +1305,7 @@ def test_telegram_delete_trade(mocker, update, default_conf, fee): assert "Trade-id not set." in msg_mock.call_args_list[0][0][0] msg_mock.reset_mock() - create_mock_trades(fee, False) + create_mock_trades(fee, is_short) context = MagicMock() context.args = [1] From 430aa0903f6e698e39739c7de1b318ea78d55c4d Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 13 Nov 2021 19:45:41 -0600 Subject: [PATCH 4/6] Removed redundent TODO-levs --- freqtrade/exchange/binance.py | 7 ++++--- freqtrade/exchange/bybit.py | 5 +++-- freqtrade/exchange/ftx.py | 5 +++-- freqtrade/exchange/gateio.py | 7 ++++--- freqtrade/exchange/kraken.py | 5 +++-- freqtrade/exchange/okex.py | 7 ++++--- freqtrade/freqtradebot.py | 5 ++--- freqtrade/persistence/models.py | 4 ++-- tests/conftest_trades.py | 2 +- 9 files changed, 26 insertions(+), 21 deletions(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index c16566fde..ba3528949 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -33,9 +33,10 @@ class Binance(Exchange): _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list - # (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported + # TODO-lev: Uncomment once supported + # (TradingMode.MARGIN, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.ISOLATED) ] @property diff --git a/freqtrade/exchange/bybit.py b/freqtrade/exchange/bybit.py index df19a671b..31152d6c1 100644 --- a/freqtrade/exchange/bybit.py +++ b/freqtrade/exchange/bybit.py @@ -27,6 +27,7 @@ class Bybit(Exchange): _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list - # (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported + # TODO-lev: Uncomment once supported + # (TradingMode.FUTURES, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.ISOLATED) ] diff --git a/freqtrade/exchange/ftx.py b/freqtrade/exchange/ftx.py index 2acf32ba3..d8df8bc97 100644 --- a/freqtrade/exchange/ftx.py +++ b/freqtrade/exchange/ftx.py @@ -25,8 +25,9 @@ class Ftx(Exchange): _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list - # (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.CROSS) # TODO-lev: Uncomment once supported + # TODO-lev: Uncomment once supported + # (TradingMode.MARGIN, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.CROSS) ] def market_is_tradable(self, market: Dict[str, Any]) -> bool: diff --git a/freqtrade/exchange/gateio.py b/freqtrade/exchange/gateio.py index 83abd1266..eb5d244aa 100644 --- a/freqtrade/exchange/gateio.py +++ b/freqtrade/exchange/gateio.py @@ -30,9 +30,10 @@ class Gateio(Exchange): _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list - # (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported + # TODO-lev: Uncomment once supported + # (TradingMode.MARGIN, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.ISOLATED) ] @property diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 8bd5d2fb3..6d0294e1c 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -27,8 +27,9 @@ class Kraken(Exchange): _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list - # (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.CROSS) # TODO-lev: No CCXT support + # TODO-lev: Uncomment once supported + # (TradingMode.MARGIN, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.CROSS) ] def market_is_tradable(self, market: Dict[str, Any]) -> bool: diff --git a/freqtrade/exchange/okex.py b/freqtrade/exchange/okex.py index 100bf3adf..cade318a5 100644 --- a/freqtrade/exchange/okex.py +++ b/freqtrade/exchange/okex.py @@ -21,9 +21,10 @@ class Okex(Exchange): _supported_trading_mode_collateral_pairs: List[Tuple[TradingMode, Collateral]] = [ # TradingMode.SPOT always supported and not required in this list - # (TradingMode.MARGIN, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.CROSS), # TODO-lev: Uncomment once supported - # (TradingMode.FUTURES, Collateral.ISOLATED) # TODO-lev: Uncomment once supported + # TODO-lev: Uncomment once supported + # (TradingMode.MARGIN, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.CROSS), + # (TradingMode.FUTURES, Collateral.ISOLATED) ] @property diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 8369a8579..092d658c2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -922,8 +922,7 @@ class FreqtradeBot(LoggingMixin): Check if trade is fulfilled in which case the stoploss on exchange should be added immediately if stoploss on exchange is enabled. - # TODO-lev: liquidation price will always be on exchange, even though - # TODO-lev: stoploss_on_exchange might not be enabled + # TODO-lev: liquidation price always on exchange, even without stoploss_on_exchange """ logger.debug('Handling stoploss on exchange %s ...', trade) @@ -1517,7 +1516,7 @@ class FreqtradeBot(LoggingMixin): self.wallets.update() if fee_abs != 0 and self.wallets.get_free(trade_base_currency) >= amount: # Eat into dust if we own more than base currency - # TODO-lev: won't be in base currency for shorts + # TODO-lev: settle currency for futures logger.info(f"Fee amount for {trade} was in base currency - " f"Eating Fee {fee_abs} into dust.") elif fee_abs != 0: diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 4835a1772..9ba88057c 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -916,8 +916,8 @@ class Trade(_DECL_BASE, LocalTrade): max_rate = Column(Float, nullable=True, default=0.0) # Lowest price reached min_rate = Column(Float, nullable=True) - sell_reason = Column(String(100), nullable=True) # TODO-lev: Change to close_reason - sell_order_status = Column(String(100), nullable=True) # TODO-lev: Change to close_order_status + sell_reason = Column(String(100), nullable=True) + sell_order_status = Column(String(100), nullable=True) strategy = Column(String(100), nullable=True) buy_tag = Column(String(100), nullable=True) timeframe = Column(Integer, nullable=True) diff --git a/tests/conftest_trades.py b/tests/conftest_trades.py index c13b482dc..dcd5e70df 100644 --- a/tests/conftest_trades.py +++ b/tests/conftest_trades.py @@ -488,7 +488,7 @@ def leverage_trade(fee): open_order_id='dry_run_leverage_buy_12368', strategy='DefaultStrategy', timeframe=5, - sell_reason='sell_signal', # TODO-lev: Update to exit/close reason + sell_reason='sell_signal', open_date=datetime.now(tz=timezone.utc) - timedelta(minutes=300), close_date=datetime.now(tz=timezone.utc), interest_rate=0.0005 From 86e5b480a84ed9ac50a36c5b9b03cf420d3493cc Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Sat, 13 Nov 2021 19:50:53 -0600 Subject: [PATCH 5/6] test_strategy_test_v2 for shorts --- tests/strategy/test_default_strategy.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/strategy/test_default_strategy.py b/tests/strategy/test_default_strategy.py index a995491f2..19f645d90 100644 --- a/tests/strategy/test_default_strategy.py +++ b/tests/strategy/test_default_strategy.py @@ -1,5 +1,6 @@ from datetime import datetime +import pytest from pandas import DataFrame from freqtrade.persistence.models import Trade @@ -16,7 +17,11 @@ def test_strategy_test_v2_structure(): assert hasattr(StrategyTestV3, 'populate_sell_trend') -def test_strategy_test_v2(result, fee): +@pytest.mark.parametrize('is_short,side', [ + (True, 'short'), + (False, 'long'), +]) +def test_strategy_test_v2(result, fee, is_short, side): strategy = StrategyTestV3({}) metadata = {'pair': 'ETH/BTC'} @@ -32,16 +37,18 @@ def test_strategy_test_v2(result, fee): open_rate=19_000, amount=0.1, pair='ETH/BTC', - fee_open=fee.return_value + fee_open=fee.return_value, + is_short=is_short ) assert strategy.confirm_trade_entry(pair='ETH/BTC', order_type='limit', amount=0.1, rate=20000, time_in_force='gtc', - current_time=datetime.utcnow(), side='long') is True + current_time=datetime.utcnow(), + side=side) is True assert strategy.confirm_trade_exit(pair='ETH/BTC', trade=trade, order_type='limit', amount=0.1, rate=20000, time_in_force='gtc', sell_reason='roi', - current_time=datetime.utcnow()) is True + current_time=datetime.utcnow(), + side=side) is True - # TODO-lev: Test for shorts? assert strategy.custom_stoploss(pair='ETH/BTC', trade=trade, current_time=datetime.now(), current_rate=20_000, current_profit=0.05) == strategy.stoploss From 38362e0ec52c0e8f28adf25610dc0e4d9f160125 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 14 Nov 2021 09:02:25 +0100 Subject: [PATCH 6/6] Update test names --- tests/strategy/test_default_strategy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/strategy/test_default_strategy.py b/tests/strategy/test_default_strategy.py index 19f645d90..ff2ce10a7 100644 --- a/tests/strategy/test_default_strategy.py +++ b/tests/strategy/test_default_strategy.py @@ -8,7 +8,7 @@ from freqtrade.persistence.models import Trade from .strats.strategy_test_v3 import StrategyTestV3 -def test_strategy_test_v2_structure(): +def test_strategy_test_v3_structure(): assert hasattr(StrategyTestV3, 'minimal_roi') assert hasattr(StrategyTestV3, 'stoploss') assert hasattr(StrategyTestV3, 'timeframe') @@ -21,7 +21,7 @@ def test_strategy_test_v2_structure(): (True, 'short'), (False, 'long'), ]) -def test_strategy_test_v2(result, fee, is_short, side): +def test_strategy_test_v3(result, fee, is_short, side): strategy = StrategyTestV3({}) metadata = {'pair': 'ETH/BTC'}