Estrategia ScalpWiz Bollinger
Descripción general
La Estrategia ScalpWiz Bollinger es un sistema contra-tendencia que utiliza las Bandas de Bollinger para detectar precios extendidos. Cuando el precio de cierre se aleja demasiado de la banda superior o inferior, la estrategia abre una posición en la dirección opuesta esperando una reversión.
Se verifican cuatro niveles de distancia. Cada nivel corresponde a una fuerza de señal diferente y multiplica el volumen de la operación. El tamaño de la posición también se escala por un porcentaje de riesgo del valor actual de la cartera.
Parámetros
BandsPeriod– número de velas utilizadas para calcular las Bandas de Bollinger.BandsDeviation– multiplicador de desviación estándar para las bandas.Level1Pips…Level4Pips– distancia desde la banda en pips que activa una señal de nivel 1–4.StrengthLevel1Multiplier…StrengthLevel4Multiplier– multiplicadores de volumen para cada nivel.RiskPercent– porcentaje del valor de la cartera arriesgado por señal.CandleType– marco temporal de velas utilizado para los cálculos.
Lógica de trading
- Suscribirse a velas del marco temporal seleccionado y calcular las Bandas de Bollinger.
- En cada vela finalizada:
- Si el cierre está por encima de la banda superior por una distancia de nivel configurada, abrir una posición corta.
- Si el cierre está por debajo de la banda inferior por una distancia de nivel configurada, abrir una posición larga.
- El volumen se calcula a partir del porcentaje de riesgo y el multiplicador de fuerza de señal.
La estrategia fue inspirada por el script MQL original mcb.scalpwiz.9001.mq4.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bollinger-based reverse scalping strategy.
/// Places counter-trend orders when price deviates from the bands.
/// Position size scales with signal strength and risk percentage.
/// </summary>
public class ScalpWizBollingerStrategy : Strategy
{
private readonly StrategyParam<int> _bandsPeriod;
private readonly StrategyParam<decimal> _bandsDeviation;
private readonly StrategyParam<decimal> _level1Pips;
private readonly StrategyParam<decimal> _level2Pips;
private readonly StrategyParam<decimal> _level3Pips;
private readonly StrategyParam<decimal> _level4Pips;
private readonly StrategyParam<int> _multiplier1;
private readonly StrategyParam<int> _multiplier2;
private readonly StrategyParam<int> _multiplier3;
private readonly StrategyParam<int> _multiplier4;
private readonly StrategyParam<int> _riskPercent;
private readonly StrategyParam<DataType> _candleType;
public int BandsPeriod { get => _bandsPeriod.Value; set => _bandsPeriod.Value = value; }
public decimal BandsDeviation { get => _bandsDeviation.Value; set => _bandsDeviation.Value = value; }
public decimal Level1Pips { get => _level1Pips.Value; set => _level1Pips.Value = value; }
public decimal Level2Pips { get => _level2Pips.Value; set => _level2Pips.Value = value; }
public decimal Level3Pips { get => _level3Pips.Value; set => _level3Pips.Value = value; }
public decimal Level4Pips { get => _level4Pips.Value; set => _level4Pips.Value = value; }
public int StrengthLevel1Multiplier { get => _multiplier1.Value; set => _multiplier1.Value = value; }
public int StrengthLevel2Multiplier { get => _multiplier2.Value; set => _multiplier2.Value = value; }
public int StrengthLevel3Multiplier { get => _multiplier3.Value; set => _multiplier3.Value = value; }
public int StrengthLevel4Multiplier { get => _multiplier4.Value; set => _multiplier4.Value = value; }
public int RiskPercent { get => _riskPercent.Value; set => _riskPercent.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Constructor.
/// </summary>
public ScalpWizBollingerStrategy()
{
_bandsPeriod = Param(nameof(BandsPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Bands Period", "Number of candles for Bollinger calculation", "Bollinger")
.SetOptimize(20, 40, 5);
_bandsDeviation = Param(nameof(BandsDeviation), 2m)
.SetGreaterThanZero()
.SetDisplay("Bands Deviation", "Standard deviation multiplier", "Bollinger")
.SetOptimize(1m, 3m, 0.5m);
_level1Pips = Param(nameof(Level1Pips), 1m)
.SetGreaterThanZero()
.SetDisplay("Level1 Pips", "Deviation from band for weakest signal", "Levels");
_level2Pips = Param(nameof(Level2Pips), 5m)
.SetGreaterThanZero()
.SetDisplay("Level2 Pips", "Deviation from band for level 2", "Levels");
_level3Pips = Param(nameof(Level3Pips), 10m)
.SetGreaterThanZero()
.SetDisplay("Level3 Pips", "Deviation from band for level 3", "Levels");
_level4Pips = Param(nameof(Level4Pips), 20m)
.SetGreaterThanZero()
.SetDisplay("Level4 Pips", "Deviation from band for strongest signal", "Levels");
_multiplier1 = Param(nameof(StrengthLevel1Multiplier), 1)
.SetGreaterThanZero()
.SetDisplay("Strength 1 Multiplier", "Volume multiplier for level 1", "Strength");
_multiplier2 = Param(nameof(StrengthLevel2Multiplier), 2)
.SetGreaterThanZero()
.SetDisplay("Strength 2 Multiplier", "Volume multiplier for level 2", "Strength");
_multiplier3 = Param(nameof(StrengthLevel3Multiplier), 3)
.SetGreaterThanZero()
.SetDisplay("Strength 3 Multiplier", "Volume multiplier for level 3", "Strength");
_multiplier4 = Param(nameof(StrengthLevel4Multiplier), 4)
.SetGreaterThanZero()
.SetDisplay("Strength 4 Multiplier", "Volume multiplier for level 4", "Strength");
_riskPercent = Param(nameof(RiskPercent), 2)
.SetGreaterThanZero()
.SetDisplay("Risk %", "Risk percentage per trade", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands
{
Length = BandsPeriod,
Width = BandsDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bb = (BollingerBandsValue)value;
if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower)
return;
var step = Security?.PriceStep ?? 0.0001m;
var close = candle.ClosePrice;
if (close - upper > Level4Pips * step)
{
SellByStrength(StrengthLevel4Multiplier, close);
}
else if (close - upper > Level3Pips * step)
{
SellByStrength(StrengthLevel3Multiplier, close);
}
else if (close - upper > Level2Pips * step)
{
SellByStrength(StrengthLevel2Multiplier, close);
}
else if (close - upper > Level1Pips * step)
{
SellByStrength(StrengthLevel1Multiplier, close);
}
else if (lower - close > Level4Pips * step)
{
BuyByStrength(StrengthLevel4Multiplier, close);
}
else if (lower - close > Level3Pips * step)
{
BuyByStrength(StrengthLevel3Multiplier, close);
}
else if (lower - close > Level2Pips * step)
{
BuyByStrength(StrengthLevel2Multiplier, close);
}
else if (lower - close > Level1Pips * step)
{
BuyByStrength(StrengthLevel1Multiplier, close);
}
}
private void BuyByStrength(int strength, decimal price)
{
BuyMarket();
}
private void SellByStrength(int strength, decimal price)
{
SellMarket();
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class scalp_wiz_bollinger_strategy(Strategy):
def __init__(self):
super(scalp_wiz_bollinger_strategy, self).__init__()
self._bands_period = self.Param("BandsPeriod", 30) \
.SetDisplay("Bands Period", "Number of candles for Bollinger calculation", "Bollinger")
self._bands_deviation = self.Param("BandsDeviation", 2.0) \
.SetDisplay("Bands Deviation", "Standard deviation multiplier", "Bollinger")
self._level1_pips = self.Param("Level1Pips", 1.0) \
.SetDisplay("Level1 Pips", "Deviation from band for weakest signal", "Levels")
self._level2_pips = self.Param("Level2Pips", 5.0) \
.SetDisplay("Level2 Pips", "Deviation from band for level 2", "Levels")
self._level3_pips = self.Param("Level3Pips", 10.0) \
.SetDisplay("Level3 Pips", "Deviation from band for level 3", "Levels")
self._level4_pips = self.Param("Level4Pips", 20.0) \
.SetDisplay("Level4 Pips", "Deviation from band for strongest signal", "Levels")
self._multiplier1 = self.Param("StrengthLevel1Multiplier", 1) \
.SetDisplay("Strength 1 Multiplier", "Volume multiplier for level 1", "Strength")
self._multiplier2 = self.Param("StrengthLevel2Multiplier", 2) \
.SetDisplay("Strength 2 Multiplier", "Volume multiplier for level 2", "Strength")
self._multiplier3 = self.Param("StrengthLevel3Multiplier", 3) \
.SetDisplay("Strength 3 Multiplier", "Volume multiplier for level 3", "Strength")
self._multiplier4 = self.Param("StrengthLevel4Multiplier", 4) \
.SetDisplay("Strength 4 Multiplier", "Volume multiplier for level 4", "Strength")
self._risk_percent = self.Param("RiskPercent", 2) \
.SetDisplay("Risk %", "Risk percentage per trade", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def bands_period(self):
return self._bands_period.Value
@property
def bands_deviation(self):
return self._bands_deviation.Value
@property
def level1_pips(self):
return self._level1_pips.Value
@property
def level2_pips(self):
return self._level2_pips.Value
@property
def level3_pips(self):
return self._level3_pips.Value
@property
def level4_pips(self):
return self._level4_pips.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(scalp_wiz_bollinger_strategy, self).OnReseted()
def OnStarted2(self, time):
super(scalp_wiz_bollinger_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self.bands_period
bollinger.Width = self.bands_deviation
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, self.process_candle).Start()
def process_candle(self, candle, value):
if candle.State != CandleStates.Finished:
return
upper = value.UpBand
lower = value.LowBand
if upper is None or lower is None:
return
upper = float(upper)
lower = float(lower)
step = 0.0001
if self.Security is not None and self.Security.PriceStep is not None:
step = float(self.Security.PriceStep)
close = float(candle.ClosePrice)
l1 = float(self.level1_pips) * step
l2 = float(self.level2_pips) * step
l3 = float(self.level3_pips) * step
l4 = float(self.level4_pips) * step
if close - upper > l4:
self.SellMarket()
elif close - upper > l3:
self.SellMarket()
elif close - upper > l2:
self.SellMarket()
elif close - upper > l1:
self.SellMarket()
elif lower - close > l4:
self.BuyMarket()
elif lower - close > l3:
self.BuyMarket()
elif lower - close > l2:
self.BuyMarket()
elif lower - close > l1:
self.BuyMarket()
def CreateClone(self):
return scalp_wiz_bollinger_strategy()