Ver no GitHub

Estratégia Exp ColorMETRO MMRec Duplex

Visão Geral

Esta estratégia porta o consultor especialista MetaTrader 5 Exp_ColorMETRO_MMRec_Duplex para o StockSharp. O robô original executa dois módulos independentes do indicador ColorMETRO (um longo, um curto) e aplica uma sobreposição MMRec (recálculo de gestão de dinheiro) que reduz o tamanho da posição após perdas repetidas. A versão em C# replica esse comportamento usando a API de alto nível do StockSharp para assinaturas de velas e roteamento de ordens.

Lógica de Negociação

  • Dois indicadores ColorMETRO distintos operam em tipos de velas configuráveis. O módulo longo gerencia apenas exposição comprada, enquanto o módulo curto controla a exposição vendida.
  • Cada indicador produz um envelope RSI escalonado rápido e lento. A estratégia imita as chamadas CopyBuffer do MQL5 armazenando valores históricos e inspecionando a barra definida por SignalBar.
  • Uma entrada longa é gerada quando a banda rápida cruza abaixo da banda lenta na barra inspecionada, enquanto a barra anterior ainda tinha a banda rápida acima da banda lenta. Qualquer posição vendida aberta é achatada antes de abrir o novo comprado.
  • Saídas longas ocorrem quando a banda lenta na barra anterior inspecionada fica acima da banda rápida, sinalizando um regime baixista no EA original.
  • Entradas e saídas curtas replicam a lógica longa (cruzamento acima para entradas, linha rápida acima da lenta na barra anterior para saídas).
  • Apenas velas terminadas são processadas e a negociação é bloqueada até que o indicador reporte ambas as bandas como prontas, reproduzindo o período de aquecimento do MetaTrader.

Gestão de Dinheiro (MMRec)

  • Strategy.Volume define o tamanho do lote de referência. Os módulos longo e curto multiplicam-no por seus respectivos coeficientes LongMm/ShortMm ao dimensionar novas ordens.
  • Após cada operação concluída, a estratégia registra se o resultado foi uma perda (baseado em preços de fechamento de velas, assim como o EA que inspeciona negociações históricas).
  • Se as TotalTrigger operações mais recentes de um módulo contiverem pelo menos LossTrigger perdedoras, o módulo muda para o multiplicador reduzido (SmallMm). Uma vez que a contagem de perdas cai abaixo do limiar, o multiplicador padrão é restaurado automaticamente.
  • Reversões de posição primeiro finalizam o resultado da operação existente (atualizando os contadores MMRec) antes de dimensionar e abrir a direção oposta.

Notas sobre o Indicador

  • ColorMetroMmrecIndicator é um port fiel do indicador personalizado ColorMETRO. Ele alimenta os mesmos envelopes rápidos/lentos impulsionados por um núcleo RSI com rastreamento de passos e memória de tendência.
  • O indicador expõe o RSI interno e uma flag de prontidão para que a estratégia possa ignorar valores incompletos exatamente como a implementação MQL faz.

Parâmetros

Grupo Nome Descrição
Comprado LongCandleType Tipo de vela usado para o módulo ColorMETRO comprado.
Comprado LongTotalTrigger Número de operações longas concluídas inspecionadas ao avaliar MMRec.
Comprado LongLossTrigger Contagem de perdas que ativa o multiplicador longo reduzido.
Comprado LongSmallMm Multiplicador reduzido aplicado a operações longas após uma sequência de perdas.
Comprado LongMm Multiplicador padrão para operações longas.
Comprado LongEnableOpen Habilita a abertura de posições longas.
Comprado LongEnableClose Habilita o fechamento de posições longas.
Comprado LongPeriodRsi Comprimento RSI usado dentro do indicador ColorMETRO longo.
Comprado LongStepSizeFast Tamanho do passo do envelope rápido para o módulo longo.
Comprado LongStepSizeSlow Tamanho do passo do envelope lento para o módulo longo.
Comprado LongSignalBar Deslocamento histórico (em barras fechadas) usado ao ler valores do indicador.
Comprado LongMagic Número mágico MT5 original, mantido como referência.
Comprado LongStopLossTicks Marcador de distância de stop-loss do EA (não aplicado).
Comprado LongTakeProfitTicks Marcador de distância de take-profit do EA (não aplicado).
Comprado LongDeviationTicks Marcador de slippage permitido do EA (não aplicado).
Comprado LongMarginMode Flag de modo MM mantido para compatibilidade (lógica usa multiplicadores brutos).
Vendido ShortCandleType Tipo de vela usado para o módulo ColorMETRO vendido.
Vendido ShortTotalTrigger Número de operações curtas concluídas inspecionadas ao avaliar MMRec.
Vendido ShortLossTrigger Contagem de perdas que ativa o multiplicador curto reduzido.
Vendido ShortSmallMm Multiplicador reduzido aplicado a operações curtas após uma sequência de perdas.
Vendido ShortMm Multiplicador padrão para operações curtas.
Vendido ShortEnableOpen Habilita a abertura de posições curtas.
Vendido ShortEnableClose Habilita o fechamento de posições curtas.
Vendido ShortPeriodRsi Comprimento RSI usado dentro do indicador ColorMETRO curto.
Vendido ShortStepSizeFast Tamanho do passo do envelope rápido para o módulo curto.
Vendido ShortStepSizeSlow Tamanho do passo do envelope lento para o módulo curto.
Vendido ShortSignalBar Deslocamento histórico (em barras fechadas) usado ao ler valores do indicador.
Vendido ShortMagic Número mágico MT5 original, mantido como referência.
Vendido ShortStopLossTicks Marcador de distância de stop-loss do EA (não aplicado).
Vendido ShortTakeProfitTicks Marcador de distância de take-profit do EA (não aplicado).
Vendido ShortDeviationTicks Marcador de slippage permitido do EA (não aplicado).
Vendido ShortMarginMode Flag de modo MM mantido para compatibilidade (lógica usa multiplicadores brutos).

Notas de Implementação

  • A estratégia depende de SubscribeCandles(...).BindEx(...) e evita acesso direto a buffers, alinhando-se com as diretrizes de conversão.
  • Stops protetores do EA são deixados apenas como parâmetros; os usuários podem anexar StartProtection ou módulos de risco personalizados se necessário.
  • Ambos os módulos compartilham a mesma instância de instrumento, mas mantêm suas próprias assinaturas de velas e contadores MMRec, correspondendo ao layout duplex do MetaTrader.
  • Todos os comentários no código são fornecidos em inglês e a lógica evita usar chamadas de API proibidas como GetTrades.

Aviso

Este port reproduz a estrutura lógica do EA original, mas a qualidade de execução depende do broker conectado, feed de dados e configuração do StockSharp. Sempre valide o comportamento em dados históricos e de demonstração antes de negociar com capital real.

using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// ColorMETRO MMRec Duplex strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class ExpColorMetroMmrecDuplexStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ExpColorMetroMmrecDuplexStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}