From 250edae193db7af5f01f8b6fa3a831e8223512ef Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 31 Dec 2021 06:00:56 -0600 Subject: [PATCH 1/6] test__async_get_historic_ohlcv parametrized candle_type --- tests/exchange/test_exchange.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index 7fe666565a3..4158bf73375 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1667,8 +1667,8 @@ async def mock_candle_hist(pair, timeframe, candle_type, since_ms): @pytest.mark.asyncio @pytest.mark.parametrize("exchange_name", EXCHANGES) -# TODO-lev @pytest.mark.parametrize('candle_type', ['mark', '']) -async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name): +@pytest.mark.parametrize('candle_type', [CandleType.MARK, CandleType.SPOT]) +async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_type): ohlcv = [ [ int((datetime.now(timezone.utc).timestamp() - 1000) * 1000), @@ -1685,7 +1685,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_ pair = 'ETH/USDT' respair, restf, _, res = await exchange._async_get_historic_ohlcv( - pair, "5m", 1500000000000, candle_type=CandleType.SPOT, is_new_pair=False) + pair, "5m", 1500000000000, candle_type=candle_type, is_new_pair=False) assert respair == pair assert restf == '5m' # Call with very old timestamp - causes tons of requests From 867483170a56c84b5fe72bc0e625cf08bed2c0fc Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 31 Dec 2021 06:11:43 -0600 Subject: [PATCH 2/6] binance.funding_fee_cutoff removed TODO-lev --- freqtrade/exchange/binance.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 10fc7ab650c..6fcead08c73 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -224,7 +224,6 @@ async def _async_get_historic_ohlcv(self, pair: str, timeframe: str, def funding_fee_cutoff(self, open_date: datetime): """ - # TODO-lev: Double check that gateio, ftx, and kraken don't also have this :param open_date: The open date for a trade :return: The cutoff open time for when a funding fee is charged """ From 46072be01152c6cd1497bd4c2ebd3ce7fa41d134 Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 31 Dec 2021 06:20:00 -0600 Subject: [PATCH 3/6] models.__init__ exception for no interest_rates on Margin trading --- freqtrade/persistence/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/freqtrade/persistence/models.py b/freqtrade/persistence/models.py index 3314f8204b9..609a8c18c30 100644 --- a/freqtrade/persistence/models.py +++ b/freqtrade/persistence/models.py @@ -335,7 +335,9 @@ def __init__(self, **kwargs): if self.isolated_liq: self.set_isolated_liq(self.isolated_liq) self.recalc_open_trade_value() - # TODO-lev: Throw exception if on margin and interest_rate is none + if self.trading_mode == TradingMode.MARGIN and self.interest_rate is None: + raise OperationalException( + f"{self.trading_mode.value} trading requires param interest_rate on trades") def _set_stop_loss(self, stop_loss: float, percent: float): """ From 08b738a5d91963a9edac80aedf174548625445ba Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 31 Dec 2021 06:26:13 -0600 Subject: [PATCH 4/6] removed outdated todo in kraken --- tests/exchange/test_kraken.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/exchange/test_kraken.py b/tests/exchange/test_kraken.py index 0e7233cb406..2db3955ba60 100644 --- a/tests/exchange/test_kraken.py +++ b/tests/exchange/test_kraken.py @@ -164,8 +164,6 @@ def test_get_balances_prod(default_conf, mocker): ccxt_exceptionhandlers(mocker, default_conf, api_mock, "kraken", "get_balances", "fetch_balance") -# TODO-lev: All these stoploss tests with shorts - @pytest.mark.parametrize('ordertype', ['market', 'limit']) @pytest.mark.parametrize('side,adjustedprice', [ From 9a220f6cfee97f40ac81052d0457b4b1267977be Mon Sep 17 00:00:00 2001 From: Sam Germain Date: Fri, 31 Dec 2021 06:49:21 -0600 Subject: [PATCH 5/6] removed a few todos --- docs/leverage.md | 2 -- .../plugins/protections/max_drawdown_protection.py | 3 +-- tests/test_freqtradebot.py | 11 +++++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/leverage.md b/docs/leverage.md index 3f4312e6851..7813c38369f 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -28,8 +28,6 @@ Regular trading mode (low risk) ### Leverage trading modes -# TODO-lev: include a resource to help calculate stoplosses that are above the liquidation price - With leverage, a trader borrows capital from the exchange. The capital must be repayed fully to the exchange(potentially with interest), and the trader keeps any profits, or pays any losses, from any trades made using the borrowed capital. Because the capital must always be repayed, exchanges will **liquidate** a trade (forcefully sell the traders assets) made using borrowed capital when the total value of assets in a leverage account drops to a certain point(a point where the total value of losses is less than the value of the collateral that the trader actually owns in the leverage account), in order to ensure that the trader has enough capital to pay back the borrowed assets to the exchange. The exchange will also charge a **liquidation fee**, adding to the traders losses. For this reason, **DO NOT TRADE WITH LEVERAGE IF YOU DON'T KNOW EXACTLY WHAT YOUR DOING. LEVERAGE TRADING IS HIGH RISK, AND CAN RESULT IN THE VALUE OF YOUR ASSETS DROPPING TO 0 VERY QUICKLY, WITH NO CHANCE OF INCREASING IN VALUE AGAIN** diff --git a/freqtrade/plugins/protections/max_drawdown_protection.py b/freqtrade/plugins/protections/max_drawdown_protection.py index 89b723c60b3..0f670c0b723 100644 --- a/freqtrade/plugins/protections/max_drawdown_protection.py +++ b/freqtrade/plugins/protections/max_drawdown_protection.py @@ -36,8 +36,7 @@ def _reason(self, drawdown: float) -> str: """ LockReason to use """ - # TODO-lev: < for shorts? - return (f'{drawdown} > {self._max_allowed_drawdown} in {self.lookback_period_str}, ' + return (f'{drawdown} passed {self._max_allowed_drawdown} in {self.lookback_period_str}, ' f'locking for {self.stop_duration_str}.') def _max_drawdown(self, date_now: datetime) -> ProtectionReturn: diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a99ccc33e6e..83ddaaf88ca 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -685,7 +685,7 @@ def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker) inf_pairs = MagicMock(return_value=[ ("BTC/ETH", '1m', CandleType.SPOT), ("ETH/USDT", "1h", CandleType.SPOT) - ]) + ]) mocker.patch.multiple( 'freqtrade.strategy.interface.IStrategy', get_exit_signal=MagicMock(return_value=(False, False)), @@ -710,8 +710,8 @@ def test_process_informative_pairs_added(default_conf_usdt, ticker_usdt, mocker) 'spot', # TODO-lev: Enable other modes # 'margin', 'futures' - ] - ) +] +) @pytest.mark.parametrize("is_short", [False, True]) def test_execute_entry(mocker, default_conf_usdt, fee, limit_order, limit_order_open, is_short, trading_mode) -> None: @@ -2090,9 +2090,8 @@ def test_handle_trade_roi(default_conf_usdt, ticker_usdt, limit_order_open, fee, # we might just want to check if we are in a sell condition without # executing # if ROI is reached we must sell - # TODO-lev: Change the next line for shorts caplog.clear() - patch_get_signal(freqtrade, enter_long=False, exit_long=True) + patch_get_signal(freqtrade, enter_long=False, exit_long=not is_short, exit_short=is_short) assert freqtrade.handle_trade(trade) assert log_has("ETH/USDT - Required profit reached. sell_type=SellType.ROI", caplog) @@ -4928,4 +4927,4 @@ def refresh_latest_ohlcv_mock(pairlist, **kwargs): assert trade.funding_fees == pytest.approx(sum( trade.amount * mark_prices[trade.pair].iloc[0:2]['open'] * funding_rates[trade.pair].iloc[0:2]['open'] - )) + )) From c06496e66fa104f6c2052eddc448f90b4aae26e9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 31 Dec 2021 16:49:47 +0100 Subject: [PATCH 6/6] Update some more TODO-lev's --- freqtrade/commands/hyperopt_commands.py | 1 - freqtrade/freqtradebot.py | 1 - freqtrade/plugins/pairlistmanager.py | 1 - freqtrade/plugins/protections/stoploss_guard.py | 1 - freqtrade/rpc/rpc.py | 1 - freqtrade/rpc/telegram.py | 1 - 6 files changed, 6 deletions(-) diff --git a/freqtrade/commands/hyperopt_commands.py b/freqtrade/commands/hyperopt_commands.py index 4ed7d76987c..3448282820e 100755 --- a/freqtrade/commands/hyperopt_commands.py +++ b/freqtrade/commands/hyperopt_commands.py @@ -102,4 +102,3 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None: HyperoptTools.show_epoch_details(val, total_epochs, print_json, no_header, header_str="Epoch details") -# TODO-lev: Hyperopt optimal leverage diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 8f335737327..e631ad070eb 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -80,7 +80,6 @@ def __init__(self, config: Dict[str, Any]) -> None: # so anything in the Freqtradebot instance should be ready (initialized), including # the initial state of the bot. # Keep this at the end of this initialization method. - # TODO-lev: Do I need to consider the rpc, pairlists or dataprovider? self.rpc: RPCManager = RPCManager(self) self.pairlists = PairListManager(self.exchange, self.config) diff --git a/freqtrade/plugins/pairlistmanager.py b/freqtrade/plugins/pairlistmanager.py index 6a67e7dd5fb..eecd1087b9b 100644 --- a/freqtrade/plugins/pairlistmanager.py +++ b/freqtrade/plugins/pairlistmanager.py @@ -128,7 +128,6 @@ def verify_whitelist(self, pairlist: List[str], logmethod, :return: pairlist - whitelisted pairs """ try: - # TODO-lev: filter for pairlists that are able to trade at the desired leverage whitelist = expand_pairlist(pairlist, self._exchange.get_markets().keys(), keep_invalid) except ValueError as err: logger.error(f"Pair whitelist contains an invalid Wildcard: {err}") diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index 79b311f2bea..025ba5f1f02 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -32,7 +32,6 @@ def short_desc(self) -> str: def _reason(self) -> str: """ LockReason to use - # 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/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 129248416ec..f7a4f717f93 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -39,7 +39,6 @@ class RPCException(Exception): raise RPCException('*Status:* `no active trade`') """ - # TODO-lev: Add new configuration options introduced with leveraged/short trading def __init__(self, message: str) -> None: super().__init__(self) diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index a47206d36e0..94177a813e9 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -1294,7 +1294,6 @@ def _help(self, update: Update, context: CallbackContext) -> None: " *table :* `will display trades in a table`\n" " `pending buy orders are marked with an asterisk (*)`\n" " `pending sell orders are marked with a double asterisk (**)`\n" - # TODO-lev: Update commands and help (?) "*/buys :* `Shows the enter_tag performance`\n" "*/sells :* `Shows the sell reason performance`\n" "*/mix_tags :* `Shows combined buy tag + sell reason performance`\n"