La estrategia MA Bollinger RSI transfiere el experto MetaTrader BolRSIMAs al API de alto nivel de StockSharp. El sistema combina un
Bollinger Ruptura de banda, un filtro RSI y un promedio móvil exponencial de período de tiempo más alto (EMA) para identificar operaciones de retroceso en
la dirección de la tendencia dominante. Se conserva el tamaño del lote automático: cuando está habilitada, la estrategia convierte el riesgo configurado
fracción del capital de la cartera en volumen utilizando el precio actual, la distancia de parada Bollinger y el tamaño del contrato del instrumento.
Lógica comercial
Suscríbase a la serie de velas principal (predeterminada: 1 hora) y calcule Bollinger Bandas y RSI en el mismo período de tiempo.
Suscríbase a velas diarias e introduzca sus precios de cierre en un EMA de 200 períodos para reproducir el filtro de marco temporal más alto utilizado.
en el original EA.
Genere una configuración larga cuando la última vela cierre por debajo de la banda inferior, el valor RSI esté por debajo del umbral de sobreventa
y el cierre se mantiene por encima del EMA diario. Una configuración corta se desencadena por un cierre por encima de la banda superior, RSI por encima de la
umbral de sobrecompra y precio por debajo del EMA diario.
Abra posiciones solo cuando no haya ninguna exposición activa. Cada nueva operación almacena niveles de stop-loss y take-profit derivados de la
valores anteriores de Bollinger: los largos usan lowerBand - StopLossOffset y apuntan a la banda media; uso de pantalones cortos
upperBand + StopLossOffset y apuntar también a la banda media.
En cada vela terminada, la estrategia compara los extremos de la vela con los niveles de protección. Si el bajo/alto toca el
stop o target, la posición se cierra inmediatamente, emulando las órdenes de protección colocadas por la versión MetaTrader.
Parámetros
Nombre
Predeterminado
Descripción
CandleType
velas de 1 hora
Periodo de tiempo principal procesado por Bollinger Bandas y RSI.
DailyCandleType
velas de 1 dia
Periodo de tiempo más alto que alimenta el filtro de tendencias EMA.
BollingerPeriod
20
Número de velas utilizadas para construir Bollinger Bandas.
BollingerDeviation
2
Multiplicador de ancho de banda.
RsiPeriod
13
RSI longitud de suavizado.
RsiUpperLevel
70
Umbral de sobrecompra requerido para operaciones cortas.
RsiLowerLevel
30
Umbral de sobreventa requerido para operaciones largas.
MaPeriod
200
Duración del plazo superior EMA.
StopLossOffset
0.0238
Se agregó un buffer adicional fuera de la banda antes de colocar el stop-loss.
UseAutoLot
true
Permite dimensionar las posiciones en función del riesgo.
RiskPerTrade
0.05
Fracción del capital asignado a cada operación cuando el lote automático está activo.
FixedVolume
0.1
Tamaño del pedido cuando el tamaño de lote automático está deshabilitado.
gestión del dinero
Cuando UseAutoLot es true, el volumen es igual a (equity * RiskPerTrade) / (StopLossOffset * price * contractSize) redondeado al
límites de cambio. Esto refleja la rutina de autolot MetaTrader, que divide el monto del riesgo por la distancia de parada en efectivo y
el tamaño del contrato.
Si la información sobre el capital o el precio no están disponibles, la estrategia vuelve a FixedVolume respetando al mismo tiempo el
Restricciones de volumen del instrumento.
Diferencias con el experto MetaTrader
Las órdenes de stop-loss y take-profit se simulan a través de máximos y mínimos de velas en lugar de órdenes del lado del servidor, coincidiendo con el
resultado del EA original sin depender del envío sincrónico del pedido.
El filtro EMA utiliza las suscripciones de velas de StockSharp; no hay dependencia de llamadas de datos diarias específicas de MetaTrader.
El tamaño del riesgo respeta los límites de seguridad StockSharp (MinVolume, MaxVolume, VolumeStep) para evitar pedidos rechazados en los intercambios.
Consejos de uso
Ajuste StopLossOffset al intercambiar símbolos con diferentes escalas de precios para que la distancia refleje los EA originales
Amortiguador del 2,38 % más allá de la banda Bollinger.
Si el instrumento utiliza un período de tiempo diario diferente (por ejemplo, intercambios de cifrado), cambie DailyCandleType en consecuencia para que EMA
refleja el filtro de tendencia previsto.
Combine la estrategia con trailingstops externos si prefiere salidas dinámicas una vez que se alcance el objetivo de la banda media.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Bollinger + RSI + MA strategy.
/// Buys when price at lower BB and RSI oversold, sells at upper BB and RSI overbought.
/// </summary>
public class BollingerRsiMaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bandPercent;
private readonly StrategyParam<int> _signalCooldownCandles;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
public decimal BandPercent { get => _bandPercent.Value; set => _bandPercent.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public BollingerRsiMaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bandPercent = Param(nameof(BandPercent), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Band Percent", "MA percentage band width", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candlesSinceTrade = SignalCooldownCandles;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var ma = new SimpleMovingAverage { Length = BbPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal maValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
var close = candle.ClosePrice;
var upper = maValue * (1 + BandPercent);
var lower = maValue * (1 - BandPercent);
// Mean reversion: buy at lower band, sell at upper band
if (close < lower && rsiValue < 35 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (close > upper && rsiValue > 65 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bollinger_rsi_ma_strategy(Strategy):
def __init__(self):
super(bollinger_rsi_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._bb_period = self.Param("BbPeriod", 20)
self._band_percent = self.Param("BandPercent", 0.01)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def BbPeriod(self):
return self._bb_period.Value
@BbPeriod.setter
def BbPeriod(self, value):
self._bb_period.Value = value
@property
def BandPercent(self):
return self._band_percent.Value
@BandPercent.setter
def BandPercent(self, value):
self._band_percent.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(bollinger_rsi_ma_strategy, self).OnReseted()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(bollinger_rsi_ma_strategy, self).OnStarted2(time)
self._candles_since_trade = self.SignalCooldownCandles
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
ma = SimpleMovingAverage()
ma.Length = self.BbPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, ma, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, ma_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
ma_val = float(ma_value)
upper = ma_val * (1.0 + self.BandPercent)
lower = ma_val * (1.0 - self.BandPercent)
if close < lower and rsi_val < 35 and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif close > upper and rsi_val > 65 and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return bollinger_rsi_ma_strategy()