Call leverage before custom_stake_amount to properly determine min-stake-amount

This commit is contained in:
Matthias 2022-03-19 15:27:06 +01:00
parent 35607ae03b
commit b292f28b35
3 changed files with 44 additions and 37 deletions

View File

@ -42,8 +42,8 @@ By default, loop runs every few seconds (`internals.process_throttle_secs`) and
* Check if trade-slots are still available (if `max_open_trades` is reached). * Check if trade-slots are still available (if `max_open_trades` is reached).
* Verifies buy signal trying to enter new positions. * Verifies buy signal trying to enter new positions.
* Determine buy-price based on `bid_strategy` configuration setting, or by using the `custom_entry_price()` callback. * Determine buy-price based on `bid_strategy` configuration setting, or by using the `custom_entry_price()` callback.
* Determine stake size by calling the `custom_stake_amount()` callback.
* In Margin and Futures mode, `leverage()` strategy callback is called to determine the desired leverage. * In Margin and Futures mode, `leverage()` strategy callback is called to determine the desired leverage.
* Determine stake size by calling the `custom_stake_amount()` callback.
* Before a buy order is placed, `confirm_trade_entry()` strategy callback is called. * Before a buy order is placed, `confirm_trade_entry()` strategy callback is called.
This loop will be repeated again and again until the bot is stopped. This loop will be repeated again and again until the bot is stopped.
@ -59,8 +59,8 @@ This loop will be repeated again and again until the bot is stopped.
* Loops per candle simulating entry and exit points. * Loops per candle simulating entry and exit points.
* Confirm trade buy / sell (calls `confirm_trade_entry()` and `confirm_trade_exit()` if implemented in the strategy). * Confirm trade buy / sell (calls `confirm_trade_entry()` and `confirm_trade_exit()` if implemented in the strategy).
* Call `custom_entry_price()` (if implemented in the strategy) to determine entry price (Prices are moved to be within the opening candle). * Call `custom_entry_price()` (if implemented in the strategy) to determine entry price (Prices are moved to be within the opening candle).
* Determine stake size by calling the `custom_stake_amount()` callback.
* In Margin and Futures mode, `leverage()` strategy callback is called to determine the desired leverage. * In Margin and Futures mode, `leverage()` strategy callback is called to determine the desired leverage.
* Determine stake size by calling the `custom_stake_amount()` callback.
* Check position adjustments for open trades if enabled and call `adjust_trade_position()` to determine if an additional order is requested. * Check position adjustments for open trades if enabled and call `adjust_trade_position()` to determine if an additional order is requested.
* Call `custom_stoploss()` and `custom_sell()` to find custom exit points. * Call `custom_stoploss()` and `custom_sell()` to find custom exit points.
* For sells based on sell-signal and custom-sell: Call `custom_exit_price()` to determine exit price (Prices are moved to be within the closing candle). * For sells based on sell-signal and custom-sell: Call `custom_exit_price()` to determine exit price (Prices are moved to be within the closing candle).

View File

@ -600,26 +600,12 @@ class FreqtradeBot(LoggingMixin):
trade_side = 'short' if is_short else 'long' trade_side = 'short' if is_short else 'long'
pos_adjust = trade is not None pos_adjust = trade is not None
enter_limit_requested, stake_amount = self.get_valid_enter_price_and_stake( enter_limit_requested, stake_amount, leverage = self.get_valid_enter_price_and_stake(
pair, price, stake_amount, side, trade_side, enter_tag, trade) pair, price, stake_amount, side, trade_side, enter_tag, trade)
if not stake_amount: if not stake_amount:
return False return False
if not pos_adjust:
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
leverage = strategy_safe_wrapper(self.strategy.leverage, default_retval=1.0)(
pair=pair,
current_time=datetime.now(timezone.utc),
current_rate=enter_limit_requested,
proposed_leverage=1.0,
max_leverage=max_leverage,
side=trade_side,
) if self.trading_mode != TradingMode.SPOT else 1.0
# Cap leverage between 1.0 and max_leverage.
leverage = min(max(leverage, 1.0), max_leverage)
else:
# Changing leverage currently not possible
leverage = trade.leverage if trade else 1.0
if pos_adjust: if pos_adjust:
logger.info(f"Position adjust: about to create a new order for {pair} with stake: " logger.info(f"Position adjust: about to create a new order for {pair} with stake: "
f"{stake_amount} for {trade}") f"{stake_amount} for {trade}")
@ -775,7 +761,7 @@ class FreqtradeBot(LoggingMixin):
side: str, trade_side: str, side: str, trade_side: str,
entry_tag: Optional[str], entry_tag: Optional[str],
trade: Optional[Trade] trade: Optional[Trade]
) -> Tuple[float, float]: ) -> Tuple[float, float, float]:
if price: if price:
enter_limit_requested = price enter_limit_requested = price
@ -792,13 +778,30 @@ class FreqtradeBot(LoggingMixin):
if not enter_limit_requested: if not enter_limit_requested:
raise PricingError(f'Could not determine {side} price.') raise PricingError(f'Could not determine {side} price.')
if trade is None:
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
leverage = strategy_safe_wrapper(self.strategy.leverage, default_retval=1.0)(
pair=pair,
current_time=datetime.now(timezone.utc),
current_rate=enter_limit_requested,
proposed_leverage=1.0,
max_leverage=max_leverage,
side=trade_side,
) if self.trading_mode != TradingMode.SPOT else 1.0
# Cap leverage between 1.0 and max_leverage.
leverage = min(max(leverage, 1.0), max_leverage)
else:
# Changing leverage currently not possible
leverage = trade.leverage if trade else 1.0
# Min-stake-amount should actually include Leverage - this way our "minimal" # Min-stake-amount should actually include Leverage - this way our "minimal"
# stake- amount might be higher than necessary. # stake- amount might be higher than necessary.
# We do however also need min-stake to determine leverage, therefore this is ignored as # We do however also need min-stake to determine leverage, therefore this is ignored as
# edge-case for now. # edge-case for now.
min_stake_amount = self.exchange.get_min_pair_stake_amount( min_stake_amount = self.exchange.get_min_pair_stake_amount(
pair, enter_limit_requested, self.strategy.stoploss) pair, enter_limit_requested, self.strategy.stoploss, leverage)
max_stake_amount = self.exchange.get_max_pair_stake_amount(pair, enter_limit_requested) max_stake_amount = self.exchange.get_max_pair_stake_amount(
pair, enter_limit_requested, leverage)
if not self.edge and trade is None: if not self.edge and trade is None:
stake_available = self.wallets.get_available_stake_amount() stake_available = self.wallets.get_available_stake_amount()
@ -817,7 +820,7 @@ class FreqtradeBot(LoggingMixin):
max_stake_amount=max_stake_amount, max_stake_amount=max_stake_amount,
) )
return enter_limit_requested, stake_amount return enter_limit_requested, stake_amount, leverage
def _notify_enter(self, trade: Trade, order: Dict, order_type: Optional[str] = None, def _notify_enter(self, trade: Trade, order: Dict, order_type: Optional[str] = None,
fill: bool = False) -> None: fill: bool = False) -> None:

View File

@ -656,11 +656,27 @@ class Backtesting:
else: else:
propose_rate = min(propose_rate, row[HIGH_IDX]) propose_rate = min(propose_rate, row[HIGH_IDX])
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, propose_rate, -0.05) or 0 pos_adjust = trade is not None
max_stake_amount = self.exchange.get_max_pair_stake_amount(pair, propose_rate)
if not pos_adjust:
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
leverage = strategy_safe_wrapper(self.strategy.leverage, default_retval=1.0)(
pair=pair,
current_time=current_time,
current_rate=row[OPEN_IDX],
proposed_leverage=1.0,
max_leverage=max_leverage,
side=direction,
) if self._can_short else 1.0
# Cap leverage between 1.0 and max_leverage.
leverage = min(max(leverage, 1.0), max_leverage)
min_stake_amount = self.exchange.get_min_pair_stake_amount(
pair, propose_rate, -0.05, leverage=leverage) or 0
max_stake_amount = self.exchange.get_max_pair_stake_amount(
pair, propose_rate, leverage=leverage)
stake_available = self.wallets.get_available_stake_amount() stake_available = self.wallets.get_available_stake_amount()
pos_adjust = trade is not None
if not pos_adjust: if not pos_adjust:
try: try:
stake_amount = self.wallets.get_trade_stake_amount(pair, None, update=False) stake_amount = self.wallets.get_trade_stake_amount(pair, None, update=False)
@ -689,18 +705,6 @@ class Backtesting:
time_in_force = self.strategy.order_time_in_force['entry'] time_in_force = self.strategy.order_time_in_force['entry']
if not pos_adjust: if not pos_adjust:
max_leverage = self.exchange.get_max_leverage(pair, stake_amount)
leverage = strategy_safe_wrapper(self.strategy.leverage, default_retval=1.0)(
pair=pair,
current_time=current_time,
current_rate=row[OPEN_IDX],
proposed_leverage=1.0,
max_leverage=max_leverage,
side=direction,
) if self._can_short else 1.0
# Cap leverage between 1.0 and max_leverage.
leverage = min(max(leverage, 1.0), max_leverage)
# Confirm trade entry: # Confirm trade entry:
if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)( if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)(
pair=pair, order_type=order_type, amount=stake_amount, rate=propose_rate, pair=pair, order_type=order_type, amount=stake_amount, rate=propose_rate,