Bollinger Bands Bounce strategy. Buy: Price closes below lower band and RSI confirms oversold. Sell: Price closes above upper band or RSI confirms overbought.
Timeframe
1h
Direction
Long Only
Stoploss
-6.0%
Trailing Stop
Yes
ROI
0m: 5.0%, 60m: 3.0%, 120m: 1.5%, 240m: 0.0%
Interface Version
3
Startup Candles
N/A
Indicators
2
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
"""
Bollinger Bands Bounce Strategy
Buy when price touches/crosses below lower Bollinger Band then bounces back.
Sell when price touches/crosses above upper Bollinger Band.
Uses RSI as confirmation to avoid catching falling knives.
Timeframe: 1h
Pairs: BTC/USDT, ETH/USDT, SOL/USDT, BNB/USDT
"""
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Optional, Union
from freqtrade.strategy import (
IStrategy,
Trade,
Order,
PairLocks,
BooleanParameter,
CategoricalParameter,
DecimalParameter,
IntParameter,
RealParameter,
)
import talib.abstract as ta
from technical import qtpylib
class BollingerBounceStrategy(IStrategy):
"""
Bollinger Bands Bounce strategy.
Buy: Price closes below lower band and RSI confirms oversold.
Sell: Price closes above upper band or RSI confirms overbought.
"""
INTERFACE_VERSION = 3
can_short: bool = False
minimal_roi = {
"0": 0.05,
"60": 0.03,
"120": 0.015,
"240": 0.0,
}
stoploss = -0.06 # 6% stop loss
# Trailing stop
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.025
trailing_only_offset_is_reached = True
timeframe = "1h"
process_only_new_candles = True
use_exit_signal = True
exit_profit_only = False
ignore_roi_if_entry_signal = False
# Hyperoptable parameters
buy_bb_window = IntParameter(15, 30, default=20, space="buy", optimize=True)
buy_bb_stds = DecimalParameter(1.5, 3.0, default=2.0, decimals=1, space="buy", optimize=True)
buy_rsi_limit = IntParameter(20, 45, default=35, space="buy", optimize=True)
sell_rsi_limit = IntParameter(60, 85, default=75, space="sell", optimize=True)
startup_candle_count: int = 50
order_types = {
"entry": "limit",
"exit": "limit",
"stoploss": "market",
"stoploss_on_exchange": False,
}
order_time_in_force = {"entry": "GTC", "exit": "GTC"}
plot_config = {
"main_plot": {
"bb_lowerband": {"color": "green"},
"bb_middleband": {"color": "orange"},
"bb_upperband": {"color": "red"},
},
"subplots": {
"RSI": {
"rsi": {"color": "blue"},
},
},
}
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Calculate Bollinger Bands and RSI."""
# Bollinger Bands with multiple windows for hyperopt
for window in range(15, 31):
for std in [1.5, 2.0, 2.5, 3.0]:
suffix = f"_{window}_{str(std).replace('.', '')}"
bollinger = qtpylib.bollinger_bands(
qtpylib.typical_price(dataframe), window=window, stds=std
)
dataframe[f"bb_lowerband{suffix}"] = bollinger["lower"]
dataframe[f"bb_middleband{suffix}"] = bollinger["mid"]
dataframe[f"bb_upperband{suffix}"] = bollinger["upper"]
# RSI for confirmation
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Buy when price is below lower Bollinger Band and RSI confirms oversold."""
std_str = str(self.buy_bb_stds.value).replace(".", "")
suffix = f"_{self.buy_bb_window.value}_{std_str}"
dataframe.loc[
(
(dataframe["close"] < dataframe[f"bb_lowerband{suffix}"])
& (dataframe["rsi"] < self.buy_rsi_limit.value)
& (dataframe["volume"] > 0)
),
"enter_long",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Sell when price is above upper Bollinger Band or RSI overbought."""
std_str = str(self.buy_bb_stds.value).replace(".", "")
suffix = f"_{self.buy_bb_window.value}_{std_str}"
dataframe.loc[
(
(
(dataframe["close"] > dataframe[f"bb_upperband{suffix}"])
| (dataframe["rsi"] > self.sell_rsi_limit.value)
)
& (dataframe["volume"] > 0)
),
"exit_long",
] = 1
return dataframe