diff --git a/freqtrade/commands/hyperopt_commands.py b/freqtrade/commands/hyperopt_commands.py index 089529d15..d2d30f399 100755 --- a/freqtrade/commands/hyperopt_commands.py +++ b/freqtrade/commands/hyperopt_commands.py @@ -102,3 +102,4 @@ 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/commands/list_commands.py b/freqtrade/commands/list_commands.py index 410b9b72b..2b857cba6 100644 --- a/freqtrade/commands/list_commands.py +++ b/freqtrade/commands/list_commands.py @@ -148,6 +148,7 @@ def start_list_markets(args: Dict[str, Any], pairs_only: bool = False) -> None: quote_currencies = args.get('quote_currencies', []) try: + # TODO-lev: Add leverage amount to get markets that support a certain leverage pairs = exchange.get_markets(base_currencies=base_currencies, quote_currencies=quote_currencies, pairs_only=pairs_only, diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f94ba599b..4c2e908f2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -371,7 +371,7 @@ class FreqtradeBot(LoggingMixin): def enter_positions(self) -> int: """ - Tries to execute long buy/short sell orders for new trades (positions) + Tries to execute entry orders for new trades (positions) """ trades_created = 0 @@ -534,10 +534,6 @@ class FreqtradeBot(LoggingMixin): # is_short=is_short # ) - if self.trading_mode == TradingMode.FUTURES: - self.exchange.set_leverage(pair, leverage) - self.exchange.set_margin_mode(pair, self.collateral_type) - return interest_rate, isolated_liq def execute_entry( @@ -708,7 +704,7 @@ class FreqtradeBot(LoggingMixin): def _notify_enter(self, trade: Trade, order_type: str) -> None: """ - Sends rpc notification when a buy/short occurred. + Sends rpc notification when a entry order occurred. """ msg = { 'trade_id': trade.id, @@ -731,7 +727,7 @@ class FreqtradeBot(LoggingMixin): def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str) -> None: """ - Sends rpc notification when a buy/short cancel occurred. + Sends rpc notification when a entry order cancel occurred. """ current_rate = self.exchange.get_rate(trade.pair, refresh=False, side=trade.enter_side) msg_type = RPCMessageType.SHORT_CANCEL if trade.is_short else RPCMessageType.BUY_CANCEL @@ -778,7 +774,7 @@ class FreqtradeBot(LoggingMixin): def exit_positions(self, trades: List[Any]) -> int: """ - Tries to execute sell/exit_short orders for open trades (positions) + Tries to execute exit orders for open trades (positions) """ trades_closed = 0 for trade in trades: @@ -1149,7 +1145,7 @@ class FreqtradeBot(LoggingMixin): def handle_cancel_exit(self, trade: Trade, order: Dict, reason: str) -> str: """ - Sell/exit_short cancel - cancel order and update trade + exit order cancel - cancel order and update trade :return: Reason for cancel """ # if trade is not partially completed, just cancel the order @@ -1275,7 +1271,7 @@ class FreqtradeBot(LoggingMixin): if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( pair=trade.pair, trade=trade, order_type=order_type, amount=amount, rate=limit, time_in_force=time_in_force, sell_reason=sell_reason.sell_reason, - current_time=datetime.now(timezone.utc)): + current_time=datetime.now(timezone.utc)): # TODO-lev: Update to exit logger.info(f"User requested abortion of exiting {trade.pair}") return False @@ -1284,10 +1280,10 @@ class FreqtradeBot(LoggingMixin): order = self.exchange.create_order( pair=trade.pair, ordertype=order_type, + side="sell", amount=amount, rate=limit, - time_in_force=time_in_force, - side=trade.exit_side + time_in_force=time_in_force ) except InsufficientFundsError as e: logger.warning(f"Unable to place order {e}.") diff --git a/freqtrade/plugins/pairlist/PrecisionFilter.py b/freqtrade/plugins/pairlist/PrecisionFilter.py index a3c262e8c..2c02ccdb3 100644 --- a/freqtrade/plugins/pairlist/PrecisionFilter.py +++ b/freqtrade/plugins/pairlist/PrecisionFilter.py @@ -18,6 +18,7 @@ class PrecisionFilter(IPairList): pairlist_pos: int) -> None: super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) + # TODO-lev: Liquidation price? if 'stoploss' not in self._config: raise OperationalException( 'PrecisionFilter can only work with stoploss defined. Please add the ' diff --git a/freqtrade/plugins/protections/max_drawdown_protection.py b/freqtrade/plugins/protections/max_drawdown_protection.py index 67e204039..89b723c60 100644 --- a/freqtrade/plugins/protections/max_drawdown_protection.py +++ b/freqtrade/plugins/protections/max_drawdown_protection.py @@ -36,6 +36,7 @@ class MaxDrawdown(IProtection): """ LockReason to use """ + # TODO-lev: < for shorts? return (f'{drawdown} > {self._max_allowed_drawdown} in {self.lookback_period_str}, ' f'locking for {self.stop_duration_str}.') diff --git a/freqtrade/plugins/protections/stoploss_guard.py b/freqtrade/plugins/protections/stoploss_guard.py index 40edf1204..888dc0316 100644 --- a/freqtrade/plugins/protections/stoploss_guard.py +++ b/freqtrade/plugins/protections/stoploss_guard.py @@ -32,6 +32,7 @@ class StoplossGuard(IProtection): 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.') @@ -51,6 +52,7 @@ class StoplossGuard(IProtection): # if pair: # filters.append(Trade.pair == pair) # trades = Trade.get_trades(filters).all() + # TODO-lev: Liquidation price? trades1 = Trade.get_trades_proxy(pair=pair, is_open=False, close_date=look_back_until) trades = [trade for trade in trades1 if (str(trade.sell_reason) in ( diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index e89811bd0..2b227c849 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -168,7 +168,7 @@ class IStrategy(ABC, HyperStrategyMixin): """ Check buy timeout function callback. This method can be used to override the enter-timeout. - It is called whenever a limit buy/short order has been created, + It is called whenever a limit entry order has been created, and is not yet fully filled. Configuration options in `unfilledtimeout` will be verified before this, so ensure to set these timeouts high enough. @@ -178,7 +178,7 @@ class IStrategy(ABC, HyperStrategyMixin): :param trade: trade object. :param order: Order dictionary as returned from CCXT. :param **kwargs: Ensure to keep this here so updates to this won't break your strategy. - :return bool: When True is returned, then the buy/short-order is cancelled. + :return bool: When True is returned, then the entry order is cancelled. """ return False @@ -213,7 +213,7 @@ class IStrategy(ABC, HyperStrategyMixin): def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, current_time: datetime, **kwargs) -> bool: """ - Called right before placing a buy/short order. + Called right before placing a entry order. Timing for this function is critical, so avoid doing heavy computations or network requests in this method. @@ -237,7 +237,7 @@ class IStrategy(ABC, HyperStrategyMixin): rate: float, time_in_force: str, sell_reason: str, current_time: datetime, **kwargs) -> bool: """ - Called right before placing a regular sell/exit_short order. + Called right before placing a regular exit order. Timing for this function is critical, so avoid doing heavy computations or network requests in this method. @@ -412,7 +412,7 @@ class IStrategy(ABC, HyperStrategyMixin): Checks if a pair is currently locked The 2nd, optional parameter ensures that locks are applied until the new candle arrives, and not stop at 14:00:00 - while the next candle arrives at 14:00:02 leaving a gap - of 2 seconds for a buy/short to happen on an old signal. + of 2 seconds for an entry order to happen on an old signal. :param pair: "Pair to check" :param candle_date: Date of the last candle. Optional, defaults to current date :returns: locking state of the pair in question. @@ -428,7 +428,7 @@ class IStrategy(ABC, HyperStrategyMixin): def analyze_ticker(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Parses the given candle (OHLCV) data and returns a populated DataFrame - add several TA indicators and buy/short signal to it + add several TA indicators and entry order signal to it :param dataframe: Dataframe containing data from exchange :param metadata: Metadata dictionary with additional data (e.g. 'pair') :return: DataFrame of candle (OHLCV) data with indicator data and signals added @@ -547,7 +547,9 @@ class IStrategy(ABC, HyperStrategyMixin): dataframe: DataFrame, ) -> Tuple[Optional[DataFrame], Optional[arrow.Arrow]]: """ - Get the latest candle. Used only during real mode + Calculates current signal based based on the entry order or exit order + columns of the dataframe. + Used by Bot to get the signal to buy, sell, short, or exit_short :param pair: pair in format ANT/BTC :param timeframe: timeframe to use :param dataframe: Analyzed dataframe to get signal from. @@ -672,7 +674,7 @@ class IStrategy(ABC, HyperStrategyMixin): low: float = None, high: float = None, force_stoploss: float = 0) -> SellCheckTuple: """ - This function evaluates if one of the conditions required to trigger a sell/exit_short + This function evaluates if one of the conditions required to trigger an exit order has been reached, which can either be a stop-loss, ROI or exit-signal. :param low: Only used during backtesting to simulate (long)stoploss/(short)ROI :param high: Only used during backtesting, to simulate (short)stoploss/(long)ROI @@ -884,7 +886,7 @@ class IStrategy(ABC, HyperStrategyMixin): def advise_buy(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the buy/short signal for the given dataframe + Based on TA indicators, populates the entry order signal for the given dataframe This method should not be overridden. :param dataframe: DataFrame :param metadata: Additional information dictionary, with details like the @@ -907,7 +909,7 @@ class IStrategy(ABC, HyperStrategyMixin): def advise_sell(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ - Based on TA indicators, populates the sell/exit_short signal for the given dataframe + Based on TA indicators, populates the exit order signal for the given dataframe This method should not be overridden. :param dataframe: DataFrame :param metadata: Additional information dictionary, with details like the diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 51e55dfe0..fa4f51077 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3379,7 +3379,7 @@ def test__safe_exit_amount_error(default_conf, fee, caplog, mocker): ) freqtrade = FreqtradeBot(default_conf) patch_get_signal(freqtrade) - with pytest.raises(DependencyException, match=r"Not enough amount to exit trade."): + with pytest.raises(DependencyException, match=r"Not enough amount to exit."): assert freqtrade._safe_exit_amount(trade.pair, trade.amount) diff --git a/tests/test_persistence.py b/tests/test_persistence.py index 911d7d6c2..1250e7b92 100644 --- a/tests/test_persistence.py +++ b/tests/test_persistence.py @@ -90,7 +90,7 @@ def test_enter_exit_side(fee): @pytest.mark.usefixtures("init_persistence") -def test__set_stop_loss_isolated_liq(fee): +def test_set_stop_loss_isolated_liq(fee): trade = Trade( id=2, pair='ADA/USDT',