Ver no GitHub

BandOsMaEstratégia Personalizada

Visão geral

Esta estratégia é uma porta direta do consultor especialista MetaTrader 5 localizado em MQL/45596/mql5/Experts/MQL5Book/p7/BandOsMACustom.mq5. O robô original combina o histograma MACD (também conhecido como OsMA) com bandas Bollinger e um média móvel aplicada aos valores do histograma em vez dos preços brutos. Sempre que o histograma ultrapassa a banda inferior, o especialista abre uma negociação longa, enquanto toques na banda superior acionam entradas curtas. O histograma cruzando um a média móvel separada fecha a posição. Uma parada protetora e um passo de trailing-stop (igual a um quinquagésimo do stop) mantém o risco sob controle.

A implementação StockSharp preserva esse comportamento usando o API de alto nível, portanto, a lógica de negociação permanece legível e depurável dentro da estrutura.

Destaques de conversão

  • O histograma MACD é implementado por meio MovingAverageConvergenceDivergenceHistogram, alimentado com o preço da vela que corresponde ao modo MetaTrader PRICE_* selecionado pelo AppliedPrice parâmetro.
  • Bollinger As bandas e a média móvel de saída processam a saída OsMA em vez do que dados de preços. Um buffer de histórico compacto reproduz o MetaTrader shift argumentos para ambos os indicadores.
  • A estratégia mantém a sinalização longa/curta original: cruzamentos abaixo do banda inferior iniciam posições compradas, cruzamentos acima da faixa superior iniciam posições vendidas e OsMA cruzando sua média móvel fecha a negociação.
  • StartProtection espelha o bloco MetaTrader de stop-loss mais trailing-stop. A etapa final é calculada como StopLossPoints / 50, assim como MQL classe TrailingStop fez.

Indicadores

Indicador Objetivo
MovingAverageConvergenceDivergenceHistogram Recria a saída iOsMA de iOsMA.
BollingerBands Calcula os limites superior e inferior no histograma.
Média móvel (SMA/EMA/SMMA/LWMA) Os filtros saem quando o histograma o cruza.

Parâmetros

Nome Padrão Descrição
CandleType Período de 1 hora Prazo principal usado para todos os cálculos dos indicadores.
FastOsmaPeriod 12 Comprimento EMA rápido do cálculo OsMA.
SlowOsmaPeriod 26 Comprimento EMA lento do cálculo OsMA.
SignalPeriod 9 Comprimento do sinal SMA do cálculo OsMA.
AppliedPrice Típico Preço aplicado no estilo MetaTrader que alimenta o histograma.
BandsPeriod 26 Comprimento das bandas Bollinger desenhadas nos valores do histograma.
BandsShift 0 Deslocamento para a direita (em barras) aplicado aos valores Bollinger.
BandsDeviation 2,0 Multiplicador de desvio padrão para as bandas.
MaPeriod 10 Comprimento da média móvel de saída calculada no histograma.
MaShift 0 Deslocamento para a direita (em barras) aplicado à média móvel de saída.
MaMethod Simples Método de média móvel (SMA, EMA, SMMA, LWMA).
StopLossPoints 1000 Distância de parada protetora expressa em etapas de preço.
OrderVolume 0,01 Volume de negociação, idêntico à entrada MetaTrader “Lotes”.

Regras de negociação

  1. Assine a série de velas selecionada e alimente o preço aplicado escolhido no histograma MACD.
  2. Passe cada valor do histograma para as bandas Bollinger e a média móvel de saída.
  3. Detecte sinais usando os buffers deslocados:
    • Se o histograma cair na banda inferior, defina um sinal de alta.
    • Se o histograma ultrapassar a banda superior, defina um sinal de baixa.
    • Quando o histograma cruzar a média móvel de saída, limpe o ativo sinal, que permite que a posição seja fechada.
  4. Gerenciar posições:
    • Feche as posições compradas existentes sempre que o sinal de alta desaparecer; shorts próximos quando o sinal de baixa desaparecer.
    • Abra uma posição comprada quando o sinal de alta estiver ativo e não houver abertura posição; abrir uma posição curta quando o sinal de baixa estiver ativo e a posição for plano.
  5. Aplique StartProtection com a distância de stop-loss configurada e um trailing passo igual a StopLossPoints / 50 passos de preço.

Notas

  • Todos os comentários no código-fonte estão em inglês para estar em conformidade com o repositório diretrizes.
  • Os buffers de histórico garantem que a versão StockSharp respeite MetaTrader Parâmetros BandsShift e MaShift sem solicitar valores de indicador por índice.
  • A estratégia está alinhada com as convenções de alto nível API: SubscribeCandles impulsiona atualizações de indicadores e direciona chamadas para imitar BuyMarket/SellMarket a colocação do pedido do especialista original.
using System;

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.
/// Similar to BandOsMa but with customizable moving average filter for exit signals.
/// </summary>
public class BandOsMaCustomStrategy : 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 readonly StrategyParam<int> _maPeriod;

	private BollingerBands _bollinger;
	private SMA _osmaMA;

	private decimal _prevOsma;
	private decimal _prevUpper;
	private decimal _prevLower;
	private decimal _prevMa;
	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 int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public BandOsMaCustomStrategy()
	{
		_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");

		_maPeriod = Param(nameof(MaPeriod), 10)
			.SetDisplay("MA Period", "OsMA moving average period for exit filter", "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 }
		};

		_bollinger = new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};

		_osmaMA = new SMA { Length = MaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, macd);
			DrawOwnTrades(area);
		}
	}

	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;

		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;

		var maResult = _osmaMA.Process(new DecimalIndicatorValue(_osmaMA, osma, candle.CloseTime));
		if (maResult.IsEmpty)
			return;

		var ma = maResult.GetValue<decimal>();

		if (_hasPrev)
		{
			var buySignal = _prevOsma > _prevLower && osma <= lower && osma < ma;
			var sellSignal = _prevOsma < _prevUpper && osma >= upper && osma > ma;

			if (buySignal && Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + 1 : 1);
			else if (sellSignal && Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + 1 : 1);
		}

		_prevOsma = osma;
		_prevUpper = upper;
		_prevLower = lower;
		_prevMa = ma;
		_hasPrev = true;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_bollinger = null;
		_osmaMA = null;
		_prevOsma = 0;
		_prevUpper = 0;
		_prevLower = 0;
		_prevMa = 0;
		_hasPrev = false;

		base.OnReseted();
	}
}