A estratégia MACD Power é um sistema de momentum multitemporal convertido do expert advisor MetaTrader original. A lógica combina um par de médias móveis linearmente ponderadas (LWMA) calculadas no período principal, duas variações de MACD, um filtro de momentum em um período superior e um viés MACD mensal. A estratégia tenta participar de movimentos impulsivos quando o momentum e as condições de tendência do período superior se alinham.
Lógica principal
Médias móveis primárias – Uma LWMA rápida e uma lenta do preço típico da vela (((High + Low + Close) / 3)). A estratégia exige que a média rápida esteja abaixo da lenta antes de considerar qualquer sinal, espelhando o código original que aguarda retrações dentro de uma inclinação bajista dominante antes de entrar na direção do viés mensal.
Confirmação dupla de MACD – Dois indicadores MACD com parâmetros (12, 26, 1) e (6, 13, 1) devem estar ambos acima de zero para operações compradas ou abaixo de zero para vendidas. Esses valores reproduzem as condições MacdMAIN1 e MacdMAIN2 do expert MQL que medem aceleração de curto prazo.
Filtro de momentum – O Momentum (comprimento 14) é calculado em um período superior derivado do tamanho da vela principal (ex.: base de 15 minutos → momentum de 1 hora). A distância absoluta de 100 é monitorada nas três últimas leituras de momentum; pelo menos uma delas deve exceder o limiar configurado para confirmar que o preço está se movendo decisivamente.
Viés MACD mensal – Um MACD mensal (12, 26, 9) (idêntico a MacdMAIN0/MacdSIGNAL0 no EA) deve ter sua linha principal acima da linha de sinal para operações compradas e abaixo para vendidas. Isso protege contra operar contra a tendência macro dominante.
Gestão de operações
Dimensionamento de entrada – O parâmetro OrderVolume define o tamanho base da ordem. Quando uma reversão de posição é necessária, o motor adiciona automaticamente a magnitude da posição oposta para que o volume líquido seja invertido em uma única ordem a mercado.
Take profit / stop loss – Distâncias absolutas são expressas em pontos do instrumento e convertidas em preço usando Security.PriceStep (com fallback seguro para 1).
Trailing stop – Uma vez que o preço se move a favor em TrailingActivationPoints, o stop rastreia o preço mais alto (comprado) ou mais baixo (vendido) com um offset definido por TrailingOffsetPoints.
Ponto de equilíbrio – Quando o preço atinge BreakEvenTriggerPoints, um stop de ponto de equilíbrio sintético é ativado em Entrada ± BreakEvenOffsetPoints. Se o preço recuar para esse nível, a posição é fechada.
Limite de operações – MaxTrades limita o número de iniciações de posição por execução; uma vez atingido o limiar, nenhuma nova entrada é emitida.
Parâmetros
Nome
Descrição
Padrão
CandleType
Período principal para geração de sinais.
Velas de 15 minutos
FastMaLength
Comprimento da LWMA rápida (preço típico).
6
SlowMaLength
Comprimento da LWMA lenta (preço típico).
85
MomentumLength
Lookback do Momentum no período superior.
14
MomentumBuyThreshold
Distância mínima absoluta de 100 necessária para momentum de alta.
0.3
MomentumSellThreshold
Distância mínima absoluta de 100 necessária para momentum de baixa.
0.3
TakeProfitPoints
Distância do take-profit em pontos do instrumento.
50
StopLossPoints
Distância do stop-loss em pontos do instrumento.
20
TrailingActivationPoints
Lucro (pontos) necessário antes de o trailing ativar.
40
TrailingOffsetPoints
Distância (pontos) entre o trailing stop e o preço extremo.
40
BreakEvenTriggerPoints
Lucro (pontos) que ativa a proteção de ponto de equilíbrio.
30
BreakEvenOffsetPoints
Offset (pontos) aplicado ao mover o stop para o ponto de equilíbrio.
30
MaxTrades
Número máximo de operações permitidas por sessão.
10
OrderVolume
Volume base da ordem.
1
Diferenças em relação ao expert MQL
A estratégia usa a API de alto nível do StockSharp (SubscribeCandles + Bind/BindEx) em vez de polling direto de ticks. Os valores dos indicadores são processados apenas após o fechamento das velas.
Blocos de trailing baseado em dinheiro e stop de capital do código original não são portados porque o gerenciamento de dinheiro no nível de conta normalmente é tratado pelo framework de risco do StockSharp. Em vez disso, trailing e ponto de equilíbrio baseados em pontos permanecem e podem ser configurados para emular o comportamento do EA.
Alertas, notificações e auxiliares de modificação manual de ordens do MQL são omitidos; o motor StockSharp gerencia ordens diretamente via chamadas a mercado.
Notas de uso
Escolha o período principal configurando CandleType. O momentum do período superior e o MACD mensal são derivados automaticamente conforme o mapeamento implementado em GetMomentumCandleType().
Alinhe TakeProfitPoints, StopLossPoints e os parâmetros de trailing/ponto de equilíbrio com o tamanho de tick do instrumento. Os padrões refletem as configurações Forex de 5 dígitos do EA, mas podem ser adaptados para outros mercados.
Monitore o contador MaxTrades ao executar backtests automatizados; defina-o como um número grande se o comportamento de empilhamento tipo martingale do EA original for desejado.
Para análise visual, ative gráficos na GUI – a implementação desenha velas e as duas curvas LWMA por padrão.
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 MacdPowerStrategy : 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 MacdPowerStrategy()
{
_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_power_strategy(Strategy):
"""
MACD Power: EMA crossover with manual SL/TP via price steps.
"""
def __init__(self):
super(macd_power_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_power_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_power_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_power_strategy()