Additional Entries Based of Dataframe Value

A slight improvement from the simple code, what if you want to include check based of dataframe value, for example, additional entries only when an enter signal is active?

def adjust_trade_position(self, trade: Trade, current_time: datetime,
                          current_rate: float, current_profit: float, min_stake: float,
                          max_stake: float, **kwargs) -> Optional[float]:
    
    dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
    current_candle = dataframe.iloc[-1].squeeze()
    current_profit = trade.calc_profit_ratio(current_candle['close'])
    
    if current_profit > self.initial_safety_order_trigger:
        return None

    filled_entries = trade.select_filled_orders(trade.entry_side)
    count_of_entries = len(filled_entries)

    if 1 <= count_of_entries <= self.max_entry_position_adjustment:
        # Make sure last entry order isn't on current candle, otherwise wait until next candle
        if (current_time - timedelta(minutes=timeframe_to_minutes(self.timeframe))) >= filled_entries[(count_of_entries - 1)].order_filled_date.replace(tzinfo=timezone.utc):
            # Check for entry  and exit signal
            enter_signal = False
            exit_signal = False

            if trade.is_short:
                enter_signal = (current_candle['enter_short'] == 1)
                exit_signal = (current_candle['exit_short'] == 1)
            else:
                enter_signal = (current_candle['enter_long'] == 1)
                exit_signal = (current_candle['exit_long'] == 1)

            if enter_signal and (exit_signal == False):
                safety_order_trigger = (abs(self.initial_safety_order_trigger) * count_of_entries)
                if (self.safety_order_step_scale > 1):
                    safety_order_trigger = abs(self.initial_safety_order_trigger) + (abs(self.initial_safety_order_trigger) * self.safety_order_step_scale * (math.pow(self.safety_order_step_scale,(count_of_entries - 1)) - 1) / (self.safety_order_step_scale - 1))
                elif (self.safety_order_step_scale < 1):
                    safety_order_trigger = abs(self.initial_safety_order_trigger) + (abs(self.initial_safety_order_trigger) * self.safety_order_step_scale * (1 - math.pow(self.safety_order_step_scale,(count_of_entries - 1))) / (1 - self.safety_order_step_scale))

                if current_profit <= (-1 * abs(safety_order_trigger)):
                    try:
                        # This returns first order stake size
                        stake_amount = filled_entries[0].stake_amount
                        # This then calculates current safety order size
                        stake_amount = stake_amount * math.pow(self.safety_order_volume_scale,(count_of_entries - 1))
                        amount = stake_amount / current_rate
                        logger.info(f"Initiating additional entry #{count_of_entries} for {trade.pair} with stake amount of {stake_amount} {trade.stake_currency} which equals {amount} {trade.base_currency}")
                        return stake_amount
                    except Exception as exception:
                        logger.info(f'Error occured while trying to get stake amount for {trade.pair}: {str(exception)}') 
                        return None

    return None

Same restriction from the simple code are still exist in this code, to make this backtestable. current_profit is tied to last closed candle’s close value, and only 1 entry order per candle (including original entry order).

You can modify the code above to add indicator check as well. Be creative with it.

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *