A estratégia Macd Secrets é um sistema multitemporal de seguimento de momentum inspirado no expert advisor original "Macd Secrets I" para MetaTrader. A versão StockSharp usa a API de alto nível e foca em alinhar a direção MACD em três períodos, filtrando operações com uma linha de base de média móvel ponderada linear (LWMA) e uma verificação de desvio de momentum. A estratégia mantém apenas uma posição líquida por vez, oferecendo um perfil de risco simplificado e transparente em comparação com o EA de origem, que podia piramidar múltiplas ordens.
Geração de sinais
Configuração comprada
A LWMA rápida está abaixo da LWMA lenta no período de execução, sinalizando que o preço negocia perto do lado inferior do canal de tendência (o EA original aplica o mesmo filtro).
A linha MACD está acima da sua linha de sinal em todos os períodos acompanhados: execução, confirmação de tendência e confirmação mensal. Isso espelha o alinhamento triplo de MACD na versão MQL.
Pelo menos uma das três últimas leituras de momentum no período de tendência se desvia de 100 pelo mínimo configurado (padrão 0.3). O cálculo de desvio reproduz a lógica MathAbs(100 - Momentum) do EA.
Nenhuma posição está aberta.
Quando as condições são atendidas, uma ordem de compra a mercado é colocada com o volume configurado.
Configuração vendida
A linha MACD está abaixo da sua linha de sinal nos períodos de execução, tendência e mensal.
Pelo menos uma das três últimas divergências de momentum no período de tendência excede o limite vendido configurado.
Nenhuma posição está aberta (a versão evita hedge e escalonamento).
Se todas as regras se mantêm, uma ordem de venda a mercado é enviada.
Gestão da operação
A estratégia opcionalmente inicia ordens de proteção usando distâncias baseadas em pontos para stop-loss e take-profit. Essas distâncias são multiplicadas pelo passo de preço do ativo para converter pontos em incrementos de preço.
Nenhuma lógica de trailing-stop, breakeven ou proteção baseada em equity do EA original está incluída; a proteção do StockSharp é aplicada uma vez na inicialização.
Sinais são avaliados apenas em candles finalizados para evitar ruído intrabar.
Dados multitemporais
Período primário: frequência de execução (padrão 15 minutos). MACD e o par de LWMAs são calculados aqui.
Período de tendência: confirmação de período superior (padrão 1 hora). Tanto MACD quanto momentum rodam nessa assinatura. Desvios de momentum são coletados dos três últimos candles fechados.
Período mensal: confirmação MACD de longo prazo (padrão 30 dias para aproximar um mês calendário).
A estratégia sobrescreve GetWorkingSecurities para que todas as três assinaturas sejam solicitadas ao conector desde o início.
Parâmetros
Nome
Descrição
Padrão
OrderVolume
Volume de negociação em lotes. Deve ser positivo.
0.1
TakeProfitPoints
Distância de take-profit medida em pontos. Defina como zero para desabilitar.
50
StopLossPoints
Distância de stop-loss em pontos. Defina como zero para desabilitar.
20
FastMaPeriod
Comprimento da LWMA rápida no período primário.
6
SlowMaPeriod
Comprimento da LWMA lenta no período primário.
85
MacdFastPeriod
Período da EMA rápida usado por cada instância MACD.
12
MacdSlowPeriod
Período da EMA lenta usado por cada instância MACD.
26
MacdSignalPeriod
Período da EMA de sinal para MACD.
9
MomentumPeriod
Retrospectiva de momentum no período de tendência.
14
MomentumBuyThreshold
Desvio absoluto mínimo a partir de 100 exigido para operações compradas.
0.3
MomentumSellThreshold
Desvio absoluto mínimo a partir de 100 exigido para operações vendidas.
0.3
PrimaryCandleType
Tipo de candle para execução. Padrão de período de 15 minutos.
15m
TrendCandleType
Tipo de candle para confirmação. Padrão de período de 1 hora.
1h
MonthlyCandleType
Tipo de candle para confirmação de longo prazo. Padrão de barra de 30 dias.
30d
Notas de uso
O filtro LWMA é intencionalmente assimétrico: apenas operações compradas exigem que a LWMA rápida esteja abaixo da LWMA lenta, correspondendo ao comportamento observado no script MQL.
Como a versão negocia uma única posição líquida, ela ignora o dimensionamento de posição estilo martingale presente no código-fonte (LotsOptimized). Se empilhamento for necessário, ele pode ser reintroduzido acompanhando o volume executado e comparando com OrderVolume.
Garanta que a corretora ou fonte de dados conectada possa fornecer todos os três períodos de candles; caso contrário, a estratégia permanecerá inativa aguardando formação dos indicadores.
Considere ajustar o período mensal para mercados em que candles de 30 dias não estejam disponíveis, fornecendo um parâmetro DataType personalizado.
A estratégia opera inteiramente em candles fechados e não lê buffers históricos de indicadores diretamente, cumprindo as diretrizes de uso de indicadores do StockSharp.
Diferenças em relação ao EA original
Trailing-stop, breakeven, saídas baseadas em dinheiro e proteção de equity em nível de conta não são portados. Em vez disso, usa-se proteção StockSharp com distâncias estáticas.
Piramidagem de ordens e lógica martingale são omitidas por clareza. O dimensionamento de posição permanece constante.
Notificações (alertas, e-mails, mensagens push) não são implementadas.
Aviso
Negociação algorítmica envolve risco financeiro significativo. Teste a estratégia em dados históricos e em ambiente simulado antes de usá-la 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;
public class MacdSecretsStrategy : 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 MacdSecretsStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).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;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class macd_secrets_strategy(Strategy):
"""
MACD Secrets: EMA crossover with manual SL/TP via price steps.
"""
def __init__(self):
super(macd_secrets_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200).SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400).SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_secrets_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(macd_secrets_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._fast_ind.IsFormed or not self._slow_ind.IsFormed:
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast
self._prev_slow = slow
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return macd_secrets_strategy()