''' new strat ''' # from freqtrade.strategy import IStrategy # from pandas import DataFrame # import numpy as np # class NewStrategy(IStrategy): # timeframe = '1h' # stoploss = -1 # minimal_roi = {"0": 0.05} # def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # dataframe['high_20'] = dataframe['high'].rolling(window=20).max() # dataframe['low_20'] = dataframe['low'].rolling(window=20).min() # dataframe['low_3'] = dataframe['low'].rolling(window=3).min() # return dataframe.dropna().copy() # def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # dataframe['buy'] = (dataframe['close'] > dataframe['high_20']).astype('bool') # return dataframe # def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # dataframe['exit_long'] = False # dataframe['exit_short'] = False # return dataframe # def custom_stoploss(self, pair: str, trade, current_time, current_rate, current_profit, **kwargs) -> float: # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) # idx = dataframe.index.searchsorted(trade.open_date_utc) # if idx >= len(dataframe) or idx < 0: # return 1.0 # Trigger exit if index is invalid # trailing_min = dataframe['low_3'].iloc[idx:].min() # if current_rate <= trailing_min: # stoploss_rel = (trailing_min - trade.open_rate) / trade.open_rate # return max(0.01, abs(stoploss_rel)) # Ensure within valid bounds # return 1.0 from freqtrade.strategy import IStrategy from pandas import DataFrame import numpy as np from freqtrade.strategy import IStrategy from pandas import DataFrame class NewStrategy(IStrategy): """ 20-bar breakout strategy with 3-bar trailing stoploss. Only one trade is allowed at a time (handled by Freqtrade via max_open_trades = 1). """ # === Configuration === timeframe = '30m' # Use '1h' for testing, '30m' for actual outputs stoploss = -1 # Disable default stoploss; custom stoploss is used minimal_roi = {"0": 0.5} # Placeholder ROI def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Calculate breakout and trailing indicators dataframe['high_20'] = dataframe['high'].rolling(window=20).max() dataframe['low_20'] = dataframe['low'].rolling(window=20).min() dataframe['low_3'] = dataframe['low'].rolling(window=3).min() dataframe.dropna(inplace=True) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Entry condition: Close breaks out above *previous* 20-bar high dataframe['buy'] = ( dataframe['close'] > dataframe['high_20'].shift(1) ).astype('bool') return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Exit logic is handled via custom stoploss dataframe['exit_long'] = False dataframe['exit_short'] = False return dataframe def custom_stoploss(self, pair: str, trade, current_time, current_rate, current_profit, **kwargs) -> float: # Use the 3-bar low since the trade was opened as a trailing stop dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) # Find index where trade was opened idx = dataframe.index.searchsorted(trade.open_date_utc) if idx >= len(dataframe) or idx < 0: return 1.0 # Exit immediately if data is invalid # Get trailing minimum 3-bar low after trade entry trailing_min = dataframe['low_3'].iloc[idx:].min() # If current price drops below that trailing min, exit the trade if current_rate <= trailing_min: stoploss_rel = (trailing_min - trade.open_rate) / trade.open_rate return max(0.01, abs(stoploss_rel)) # Return positive stop between 0 and 1 return 1.0 # Otherwise, keep trade open