Ver no GitHub

Estratégia MACD Stochastic 2

Esta estratégia reproduz a lógica especialista MetaTrader "MACD Stochastic 2" com a API de alto nível do StockSharp. Combina um filtro de swing MACD de três barras com um oscilador estocástico para buscar reversões de momentum próximas a regiões de sobrevenda e sobrecompra. O risco é controlado por stops e take-profits específicos por direção, e um trailing stop opcional que opera em unidades de pips.

Visão geral

  • Funciona em qualquer instrumento e período fornecido pelo parâmetro CandleType.
  • Usa a linha principal do MACD para confirmar mínimos/máximos locais, enquanto o histograma e a linha de sinal do MACD permanecem disponíveis para visualização.
  • Confirma entradas com leitura de %K do estocástico abaixo de 20 para compras e acima de 80 para vendas.
  • Adapta o tratamento de pips do MetaTrader derivando o tamanho do pip do step de preço do instrumento, multiplicando por 10 quando o símbolo tem 3 ou 5 casas decimais.

Lógica de negociação

Entrada comprada

  1. Os valores da linha principal do MACD da vela atual e das duas anteriores completadas estão todos abaixo de zero.
  2. O valor atual do MACD é maior que o anterior, enquanto o anterior é menor que o valor de duas barras atrás (mínimo local).
  3. %K do estocástico está abaixo de 20 (sobrevendido).
  4. Não há posição comprada existente aberta (Position <= 0). Qualquer posição vendida é zerada antes de entrar na nova compra.

Entrada vendida

  1. Os valores da linha principal do MACD da vela atual e das duas anteriores completadas estão todos acima de zero.
  2. O valor atual do MACD é menor que o anterior, enquanto o anterior é maior que o valor de duas barras atrás (máximo local).
  3. %K do estocástico está acima de 80 (sobrecomprado).
  4. Não há posição vendida existente aberta (Position >= 0). Qualquer posição comprada é fechada antes de entrar na nova venda.

Gerenciamento de risco e saídas

  • Stop Fixo / Take Profit: Cada direção tem distâncias independentes de stop-loss e take-profit baseadas em pips. Os pips são convertidos em offsets de preço absolutos usando o tamanho de pip calculado.
  • Trailing Stop: Quando habilitado, o trailing stop se ativa após o preço avançar além da distância de trailing. O stop é elevado/rebaixado apenas quando o movimento supera o passo de trailing configurado para evitar excessiva rotação de ordens.
  • Sinais opostos: Ao entrar em um sinal oposto, primeiro zera a posição existente e então abre a nova com o volume de negociação configurado.

Parâmetros

Parâmetro Padrão Descrição
TradeVolume 1 Volume de ordem enviado com cada nova negociação.
StopLossBuyPips 50 Distância em pips do stop-loss para compras. Defina como 0 para desativar.
StopLossSellPips 50 Distância em pips do stop-loss para vendas. Defina como 0 para desativar.
TakeProfitBuyPips 50 Distância em pips do take-profit para compras. Defina como 0 para desativar.
TakeProfitSellPips 50 Distância em pips do take-profit para vendas. Defina como 0 para desativar.
TrailingStopPips 0 Distância do trailing stop em pips. 0 desativa o trailing.
TrailingStepPips 5 Ganho mínimo em pips antes de atualizar o trailing stop. Deve permanecer positivo quando o trailing estiver ativo.
MacdFastPeriod 12 Comprimento da EMA rápida para MACD.
MacdSlowPeriod 26 Comprimento da EMA lenta para MACD.
MacdSignalPeriod 9 Comprimento do suavizamento do sinal para MACD.
StochasticKPeriod 5 Período de lookback para %K estocástico.
StochasticDPeriod 3 Período de suavizamento para %D estocástico.
StochasticSlowing 3 Suavizamento adicional aplicado ao %K estocástico.
CandleType período de 1h Tipo de vela (período) usado para cálculos de indicadores.

Notas

  • O cálculo do tamanho do pip espelha o especialista MetaTrader original: pip = PriceStep e é multiplicado por 10 quando o instrumento é cotado com 3 ou 5 decimais.
  • Os limites do estocástico (20/80) permanecem como constantes como no script original. Ajuste-os diretamente no código se níveis personalizados forem necessários.
  • A estratégia opera apenas em velas completamente fechadas, garantindo consistência com a execução no fechamento de barra do MetaTrader.

Uso

  1. Configure o instrumento desejado, CandleType e volume antes de iniciar a estratégia.
  2. Ajuste os parâmetros de stop, take-profit e trailing para corresponder à volatilidade do instrumento.
  3. Opcionalmente otimize os comprimentos do MACD e estocástico usando o otimizador do StockSharp graças aos parâmetros expostos.
  4. Monitore os objetos do gráfico (velas, MACD, estocástico, negociações próprias) adicionados automaticamente quando uma área de gráfico está disponível.
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>
/// MACD and stochastic based swing strategy.
/// Buys when MACD turns up in negative zone + stochastic is oversold.
/// Sells when MACD turns down in positive zone + stochastic is overbought.
/// </summary>
public class MacdStochastic2Strategy : Strategy
{
	private readonly StrategyParam<decimal> _oversoldThreshold;
	private readonly StrategyParam<decimal> _overboughtThreshold;
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _stochasticKPeriod;
	private readonly StrategyParam<int> _stochasticDPeriod;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _macdPrev1;
	private decimal _macdPrev2;
	private int _macdCount;

	public decimal OversoldThreshold { get => _oversoldThreshold.Value; set => _oversoldThreshold.Value = value; }
	public decimal OverboughtThreshold { get => _overboughtThreshold.Value; set => _overboughtThreshold.Value = value; }
	public int MacdFastPeriod { get => _macdFastPeriod.Value; set => _macdFastPeriod.Value = value; }
	public int MacdSlowPeriod { get => _macdSlowPeriod.Value; set => _macdSlowPeriod.Value = value; }
	public int StochasticKPeriod { get => _stochasticKPeriod.Value; set => _stochasticKPeriod.Value = value; }
	public int StochasticDPeriod { get => _stochasticDPeriod.Value; set => _stochasticDPeriod.Value = value; }
	public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
	public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MacdStochastic2Strategy()
	{
		_oversoldThreshold = Param(nameof(OversoldThreshold), 20m)
			.SetDisplay("Oversold", "Stochastic oversold threshold", "Stochastic");

		_overboughtThreshold = Param(nameof(OverboughtThreshold), 80m)
			.SetDisplay("Overbought", "Stochastic overbought threshold", "Stochastic");

		_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("MACD Fast", "Fast EMA length for MACD", "MACD");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("MACD Slow", "Slow EMA length for MACD", "MACD");

		_stochasticKPeriod = Param(nameof(StochasticKPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Stochastic K", "Lookback for %K", "Stochastic");

		_stochasticDPeriod = Param(nameof(StochasticDPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("Stochastic D", "Smoothing for %D", "Stochastic");

		_stopLoss = Param(nameof(StopLoss), 1000m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");

		_takeProfit = Param(nameof(TakeProfit), 2000m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit", "Take profit in price units", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for calculations", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_macdPrev1 = 0m;
		_macdPrev2 = 0m;
		_macdCount = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var macd = new MovingAverageConvergenceDivergence(
			new ExponentialMovingAverage { Length = MacdSlowPeriod },
			new ExponentialMovingAverage { Length = MacdFastPeriod });

		var rsi = new RelativeStrengthIndex { Length = StochasticKPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, (candle, rsiValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				// Process MACD manually
				var macdResult = macd.Process(candle.ClosePrice, candle.CloseTime, true);
				if (!macd.IsFormed)
					return;

				var macdValue = macdResult.ToDecimal();

				_macdCount++;
				if (_macdCount < 3)
				{
					_macdPrev2 = _macdPrev1;
					_macdPrev1 = macdValue;
					return;
				}

				var macd0 = macdValue;
				var macd1 = _macdPrev1;
				var macd2 = _macdPrev2;

				// Buy: MACD in negative zone turning up + stochastic oversold
				var longSignal = macd0 < 0m && macd1 < 0m && macd2 < 0m &&
					macd0 > macd1 && macd1 < macd2 &&
					rsiValue < OversoldThreshold;

				// Sell: MACD in positive zone turning down + stochastic overbought
				var shortSignal = macd0 > 0m && macd1 > 0m && macd2 > 0m &&
					macd0 < macd1 && macd1 > macd2 &&
					rsiValue > OverboughtThreshold;

				if (longSignal && Position <= 0)
					BuyMarket();
				else if (shortSignal && Position >= 0)
					SellMarket();

				_macdPrev2 = _macdPrev1;
				_macdPrev1 = macdValue;
			})
			.Start();

		StartProtection(
			new Unit(TakeProfit, UnitTypes.Absolute),
			new Unit(StopLoss, UnitTypes.Absolute));

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