Estrategia MACD + Bollinger Bands + RSI
Esta configuración compuesta busca retrocesos contra el momentum MACD prevaleciente que se extienden más allá de las Bandas de Bollinger. Cuando el MACD es positivo pero el precio cierra por debajo de la banda inferior con un RSI sobrevendido, la estrategia compra anticipando una continuación de la tendencia. Lo opuesto aplica para posiciones cortas.
Detalles
- Criterios de entrada:
- Largo:
MACD > 0yClose < LowerBandyRSI < 30 - Corto:
MACD < 0yClose > UpperBandyRSI > 70
- Largo:
- Largo/Corto: Ambos
- Criterios de salida: Señal opuesta
- Stops: Ninguno
- Valores predeterminados:
MacdFastLength= 12MacdSlowLength= 26MacdSignalLength= 9BBLength= 20BBMultiplier= 2.0RSILength= 14
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: MACD, Bollinger Bands, RSI
- Stops: No
- Complejidad: Intermedio
- Marco temporal: Corto plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: Sí
- Nivel de riesgo: Medio
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// MACD + Bollinger Bands + RSI Strategy.
/// Uses MACD for momentum, BB for volatility levels, RSI for confirmation.
/// Buys when MACD bullish + price near lower BB + RSI oversold.
/// Sells when MACD bearish + price near upper BB + RSI overbought.
/// </summary>
public class MacdBbRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleTypeParam;
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbWidth;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _cooldownBars;
private MovingAverageConvergenceDivergence _macd;
private BollingerBands _bollinger;
private RelativeStrengthIndex _rsi;
private decimal _prevMacd;
private int _cooldownRemaining;
public MacdBbRsiStrategy()
{
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General");
_bbLength = Param(nameof(BBLength), 20)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger Bands period", "Bollinger Bands");
_bbWidth = Param(nameof(BBWidth), 1.5m)
.SetDisplay("BB Width", "BB standard deviation multiplier", "Bollinger Bands");
_rsiLength = Param(nameof(RSILength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI");
_cooldownBars = Param(nameof(CooldownBars), 50)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
public int BBLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
public decimal BBWidth
{
get => _bbWidth.Value;
set => _bbWidth.Value = value;
}
public int RSILength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_macd = null;
_bollinger = null;
_rsi = null;
_prevMacd = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_macd = new MovingAverageConvergenceDivergence();
_bollinger = new BollingerBands { Length = BBLength, Width = BBWidth };
_rsi = new RelativeStrengthIndex { Length = RSILength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, OnProcess)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _bollinger);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
// Process MACD and BB manually
var macdResult = _macd.Process(candle);
var bbResult = _bollinger.Process(candle);
if (!_macd.IsFormed || !_bollinger.IsFormed)
return;
var macdVal = macdResult.ToDecimal();
var bb = (BollingerBandsValue)bbResult;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevMacd = macdVal;
return;
}
var close = candle.ClosePrice;
// Buy: price below lower BB + RSI oversold + MACD positive
if (close <= lower && rsi < 30 && Position == 0)
{
BuyMarket();
_cooldownRemaining = CooldownBars;
}
// Sell: price above upper BB + RSI overbought + MACD negative
else if (close >= upper && rsi > 70 && Position == 0)
{
SellMarket();
_cooldownRemaining = CooldownBars;
}
_prevMacd = macdVal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import MovingAverageConvergenceDivergence, BollingerBands, RelativeStrengthIndex, IndicatorHelper, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class macd_bb_rsi_strategy(Strategy):
"""MACD + Bollinger Bands + RSI Strategy."""
def __init__(self):
super(macd_bb_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle type", "Candle type for strategy calculation.", "General")
self._bb_length = self.Param("BBLength", 20) \
.SetDisplay("BB Length", "Bollinger Bands period", "Bollinger Bands")
self._bb_width = self.Param("BBWidth", 1.5) \
.SetDisplay("BB Width", "BB standard deviation multiplier", "Bollinger Bands")
self._rsi_length = self.Param("RSILength", 14) \
.SetDisplay("RSI Length", "RSI period", "RSI")
self._cooldown_bars = self.Param("CooldownBars", 50) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._macd = None
self._bollinger = None
self._rsi = None
self._prev_macd = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_bb_rsi_strategy, self).OnReseted()
self._macd = None
self._bollinger = None
self._rsi = None
self._prev_macd = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(macd_bb_rsi_strategy, self).OnStarted2(time)
self._macd = MovingAverageConvergenceDivergence()
self._bollinger = BollingerBands()
self._bollinger.Length = int(self._bb_length.Value)
self._bollinger.Width = float(self._bb_width.Value)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = int(self._rsi_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._rsi, self._on_process).Start()
self.StartProtection(
Unit(2, UnitTypes.Percent),
Unit(1, UnitTypes.Percent)
)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._bollinger)
self.DrawOwnTrades(area)
def _on_process(self, candle, rsi_val):
if candle.State != CandleStates.Finished:
return
# Process MACD and BB manually (need CandleIndicatorValue wrapper for Python)
civ_macd = CandleIndicatorValue(self._macd, candle)
civ_macd.IsFinal = True
macd_result = self._macd.Process(civ_macd)
civ_bb = CandleIndicatorValue(self._bollinger, candle)
civ_bb.IsFinal = True
bb_result = self._bollinger.Process(civ_bb)
if not self._macd.IsFormed or not self._bollinger.IsFormed:
return
macd_val = float(IndicatorHelper.ToDecimal(macd_result))
if bb_result.UpBand is None or bb_result.LowBand is None or bb_result.MovingAverage is None:
return
upper = float(bb_result.UpBand)
lower = float(bb_result.LowBand)
middle = float(bb_result.MovingAverage)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_macd = macd_val
return
close = float(candle.ClosePrice)
rsi = float(rsi_val)
cooldown = int(self._cooldown_bars.Value)
# Buy: price below lower BB + RSI oversold
if close <= lower and rsi < 30 and self.Position == 0:
self.BuyMarket()
self._cooldown_remaining = cooldown
# Sell: price above upper BB + RSI overbought
elif close >= upper and rsi > 70 and self.Position == 0:
self.SellMarket()
self._cooldown_remaining = cooldown
self._prev_macd = macd_val
def CreateClone(self):
return macd_bb_rsi_strategy()