La Estrategia BandOsMa convierte el asesor experto MetaTrader 5 "BandOsMA" en una estrategia StockSharp. Evalúa el histograma MACD (OsMA) utilizando Bollinger bandas construidas directamente sobre los valores del histograma. Las rupturas por encima o por debajo de las bandas crean señales de entrada, mientras que una media móvil adicional del histograma gestiona las salidas de señales.
La estrategia opera con un solo símbolo y período de tiempo seleccionado por el usuario. Los valores del indicador se calculan sobre velas terminadas utilizando las suscripciones de velas de alto nivel de StockSharp.
Lógica de trading
Indicadores
MovingAverageConvergenceDivergenceSignal proporciona el histograma MACD (OsMA).
BollingerBands se aplica a la secuencia OsMA para detectar desviaciones extremas.
Una media móvil configurable suaviza el histograma y actúa como filtro de salida.
Entrada
Aparece una señal larga cuando el OsMA actual cierra por debajo de la banda inferior mientras que la barra anterior permaneció por encima de ella.
Aparece una señal corta cuando el OsMA actual cierra por encima de la banda superior mientras que la barra anterior permaneció por debajo de ella.
Salir
Las señales se borran cuando el histograma cruza la media móvil en la dirección opuesta.
Cuando una posición abierta ya no coincide con la señal activa, la posición se cierra inmediatamente.
Se adjunta un stop-loss basado en pips a cada posición. La parada también actúa como una parada de seguimiento con la misma distancia y un paso de seguimiento igual a StopLossPoints / 50 (reflejando la clase auxiliar MetaTrader.
Gestión de Puestos
Stop Loss & Trailing: La distancia del stop se expresa en MetaTrader puntos y se convierte en unidades de precio utilizando el PriceStep del instrumento. La misma distancia se utiliza para el trailing stop, que avanza una vez que el precio de cierre mejora al menos el paso de seguimiento.
Una posición a la vez: Solo se mantiene una posición neta. Las señales opuestas cierran la posición actual antes de considerar una nueva entrada.
Parámetros
grupo
Nombre
Descripción
Predeterminado
generales
CandleType
Plazo para la suscripción de velas y cálculo del indicador.
H1
Riesgo
LotSize
Volumen comercial en lotes.
0.01
Riesgo
StopLossPoints
Distancia de stop-loss expresada en MetaTrader puntos (también utilizada para seguimiento).
1000
Indicadores
MacdFastPeriod
Longitud rápida de EMA en MACD.
12
Indicadores
MacdSlowPeriod
Longitud lenta de EMA en MACD.
26
Indicadores
MacdSignalPeriod
Longitud de la señal EMA en MACD.
9
Indicadores
PriceType
Precio aplicado para la entrada MACD (Close, Open, High, Low, Median, Typical, Weighted).
Typical
Indicadores
BollingerPeriod
Período de Bollinger Bandas sobre la secuencia OsMA.
26
Indicadores
BollingerShift
Cambio aplicado a Bollinger buffers (no negativo).
0
Indicadores
BollingerDeviation
Multiplicador de desviación estándar para Bollinger bandas.
2
Indicadores
MovingAveragePeriod
Longitud de la media móvil aplicada a OsMA.
10
Indicadores
MovingAverageShift
Cambio aplicado al buffer de media móvil (no negativo).
0
Indicadores
MovingAverageMethod
Tipo de media móvil (Simple, Exponential, Smoothed, LinearWeighted).
Simple
Notas de implementación
El procesamiento de velas utiliza WhenCandlesFinished para garantizar que solo las barras finales impulsen la lógica.
Los valores del indicador se almacenan en búferes históricos para emular cambios de búfer estilo MetaTrader. No se admiten cambios negativos; utilice valores cero o positivos como en los valores predeterminados originales del experto.
Las paradas dinámicas se basan en cierres de velas en lugar de actualizaciones paso a paso. Ajuste la distancia del pip si se requiere un seguimiento preciso del nivel de tick.
Uso
Seleccione el símbolo y el período de tiempo deseados en StockSharp.
Configure los parámetros, especialmente CandleType, LotSize y períodos del indicador.
Iniciar la estrategia; se suscribirá a velas, calculará los indicadores y ejecutará operaciones de acuerdo con la lógica descrita.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy combining the MACD histogram (OsMA) with Bollinger Bands to trade reversals.
/// When OsMA crosses below lower Bollinger band, buy signal is generated.
/// When OsMA crosses above upper Bollinger band, sell signal is generated.
/// </summary>
public class BandOsMaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _macdFastPeriod;
private readonly StrategyParam<int> _macdSlowPeriod;
private readonly StrategyParam<int> _macdSignalPeriod;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private decimal _prevOsma;
private decimal _prevUpper;
private decimal _prevLower;
private bool _hasPrev;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MacdFastPeriod
{
get => _macdFastPeriod.Value;
set => _macdFastPeriod.Value = value;
}
public int MacdSlowPeriod
{
get => _macdSlowPeriod.Value;
set => _macdSlowPeriod.Value = value;
}
public int MacdSignalPeriod
{
get => _macdSignalPeriod.Value;
set => _macdSignalPeriod.Value = value;
}
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
public BandOsMaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe", "General");
_macdFastPeriod = Param(nameof(MacdFastPeriod), 20)
.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");
_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 50)
.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");
_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 12)
.SetDisplay("MACD Signal", "Signal EMA length", "Indicators");
_bollingerPeriod = Param(nameof(BollingerPeriod), 14)
.SetDisplay("Bollinger Period", "OsMA Bollinger Bands period", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
.SetDisplay("Bollinger Deviation", "Bollinger Bands deviation", "Indicators");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastPeriod },
LongMa = { Length = MacdSlowPeriod }
},
SignalMa = { Length = MacdSignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, macd);
DrawOwnTrades(area);
}
}
private BollingerBands _bollinger;
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
var val = (IMovingAverageConvergenceDivergenceSignalValue)macdValue;
if (val.Macd is not decimal macdLine || val.Signal is not decimal signalLine)
return;
var osma = macdLine - signalLine;
_bollinger ??= new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var bbResult = (BollingerBandsValue)_bollinger.Process(new DecimalIndicatorValue(_bollinger, osma, candle.CloseTime));
if (bbResult.UpBand is not decimal upper || bbResult.LowBand is not decimal lower)
{
return;
}
if (_hasPrev)
{
// Buy: OsMA crosses below lower band (reversal up expected)
if (_prevOsma > _prevLower && osma <= lower && Position <= 0)
{
BuyMarket(Position < 0 ? Math.Abs(Position) + 1 : 1);
}
// Sell: OsMA crosses above upper band (reversal down expected)
else if (_prevOsma < _prevUpper && osma >= upper && Position >= 0)
{
SellMarket(Position > 0 ? Math.Abs(Position) + 1 : 1);
}
}
_prevOsma = osma;
_prevUpper = upper;
_prevLower = lower;
_hasPrev = true;
}
/// <inheritdoc />
protected override void OnReseted()
{
_prevOsma = 0;
_prevUpper = 0;
_prevLower = 0;
_hasPrev = false;
_bollinger = null;
base.OnReseted();
}
}
import clr
import math
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 MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class band_os_ma_strategy(Strategy):
def __init__(self):
super(band_os_ma_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._macd_fast_period = self.Param("MacdFastPeriod", 20)
self._macd_slow_period = self.Param("MacdSlowPeriod", 50)
self._macd_signal_period = self.Param("MacdSignalPeriod", 12)
self._bollinger_period = self.Param("BollingerPeriod", 14)
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0)
self._macd_history = []
self._osma_history = []
self._prev_osma = None
self._prev_upper = None
self._prev_lower = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MacdFastPeriod(self):
return self._macd_fast_period.Value
@MacdFastPeriod.setter
def MacdFastPeriod(self, value):
self._macd_fast_period.Value = value
@property
def MacdSlowPeriod(self):
return self._macd_slow_period.Value
@MacdSlowPeriod.setter
def MacdSlowPeriod(self, value):
self._macd_slow_period.Value = value
@property
def MacdSignalPeriod(self):
return self._macd_signal_period.Value
@MacdSignalPeriod.setter
def MacdSignalPeriod(self, value):
self._macd_signal_period.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerDeviation(self):
return self._bollinger_deviation.Value
@BollingerDeviation.setter
def BollingerDeviation(self, value):
self._bollinger_deviation.Value = value
def OnReseted(self):
super(band_os_ma_strategy, self).OnReseted()
self._macd_history = []
self._osma_history = []
self._prev_osma = None
self._prev_upper = None
self._prev_lower = None
def OnStarted2(self, time):
super(band_os_ma_strategy, self).OnStarted2(time)
self._macd_history = []
self._osma_history = []
self._prev_osma = None
self._prev_upper = None
self._prev_lower = None
macd = MovingAverageConvergenceDivergence()
macd.ShortMa.Length = self.MacdFastPeriod
macd.LongMa.Length = self.MacdSlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
macd_val = float(macd_value)
signal_period = self.MacdSignalPeriod
bb_period = self.BollingerPeriod
bb_dev = float(self.BollingerDeviation)
# Compute signal line manually
self._macd_history.append(macd_val)
while len(self._macd_history) > signal_period:
self._macd_history.pop(0)
if len(self._macd_history) < signal_period:
return
signal = sum(self._macd_history) / signal_period
osma = macd_val - signal
# Compute Bollinger Bands on OsMA
self._osma_history.append(osma)
while len(self._osma_history) > bb_period:
self._osma_history.pop(0)
if len(self._osma_history) < bb_period:
return
mean = sum(self._osma_history) / len(self._osma_history)
variance = sum((x - mean) ** 2 for x in self._osma_history) / len(self._osma_history)
std_dev = math.sqrt(variance)
upper = mean + bb_dev * std_dev
lower = mean - bb_dev * std_dev
if self._prev_osma is not None and self._prev_upper is not None and self._prev_lower is not None:
# Buy: OsMA crosses below lower band
if self._prev_osma > self._prev_lower and osma <= lower and self.Position <= 0:
self.BuyMarket()
# Sell: OsMA crosses above upper band
elif self._prev_osma < self._prev_upper and osma >= upper and self.Position >= 0:
self.SellMarket()
self._prev_osma = osma
self._prev_upper = upper
self._prev_lower = lower
def CreateClone(self):
return band_os_ma_strategy()