One-Minute Bollinger Band Pullback Entry Strategy
Summary
This Freqtrade strategy looks for a long entry when price moves below the previous candle’s lower Bollinger Band. It calculates bands over a 40-period window with two standard deviations, then checks the band width, the size of the close-to-close move, the candle’s lower tail, and whether the current close is no higher than the previous close. These conditions seek a sufficiently sharp downward move with a limited lower wick, which may identify a pullback or short-term reversal setup.
The strategy uses a one-minute timeframe, sets a stated minimal return target and stop loss, and exposes entry thresholds as optimization parameters. It defines no technical exit signal, so exits depend on the framework’s other configured mechanisms. The document provides implementation details but no backtest results, market, execution assumptions, or evidence that the entry rules are profitable. Its sample parameter defaults also exceed the declared parameter ranges, so the configuration should be checked before use.
Key ideas
- The entry rule requires the close to fall below the prior lower Bollinger Band.
- Band width and price-change thresholds filter for larger short-term moves.
- A lower-tail condition limits the candle shape accepted for entry.
- The strategy has no explicit exit signal and supplies no performance evidence.
Tags
Full text
# BinHV45.py
```py
# --- Do not remove these libs ---
from freqtrade.strategy import IStrategy
from freqtrade.strategy import IntParameter
from pandas import DataFrame
import numpy as np
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
def bollinger_bands(stock_price, window_size, num_of_std):
rolling_mean = stock_price.rolling(window=window_size).mean()
rolling_std = stock_price.rolling(window=window_size).std()
lower_band = rolling_mean - (rolling_std * num_of_std)
return rolling_mean, lower_band
class BinHV45(IStrategy):
INTERFACE_VERSION: int = 3
minimal_roi = {
"0": 0.0125
}
stoploss = -0.05
timeframe = '1m'
buy_bbdelta = IntParameter(low=1, high=15, default=30, space='buy', optimize=True)
buy_closedelta = IntParameter(low=15, high=20, default=30, space='buy', optimize=True)
buy_tail = IntParameter(low=20, high=30, default=30, space='buy', optimize=True)
# Hyperopt parameters
buy_params = {
"buy_bbdelta": 7,
"buy_closedelta": 17,
"buy_tail": 25,
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=40, stds=2)
dataframe['upper'] = bollinger['upper']
dataframe['mid'] = bollinger['mid']
dataframe['lower'] = bollinger['lower']
dataframe['bbdelta'] = (dataframe['mid'] - dataframe['lower']).abs()
dataframe['pricedelta'] = (dataframe['open'] - dataframe['close']).abs()
dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs()
dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs()
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
dataframe['lower'].shift().gt(0) &
dataframe['bbdelta'].gt(dataframe['close'] * self.buy_bbdelta.value / 1000) &
dataframe['closedelta'].gt(dataframe['close'] * self.buy_closedelta.value / 1000) &
dataframe['tail'].lt(dataframe['bbdelta'] * self.buy_tail.value / 1000) &
dataframe['close'].lt(dataframe['lower'].shift()) &
dataframe['close'].le(dataframe['close'].shift())
),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
no sell signal
"""
dataframe.loc[:, 'exit_long'] = 0
return dataframe
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.