Esta estratégia é um port do StockSharp do utilitário Advanced EA Panel do MQL5. O assessor especialista original fornecia um painel de trading manual com análises de múltiplos períodos, gestão de pivôs e botões de negociação rápida. A implementação em C# recria essas capacidades analíticas dentro de uma estratégia automatizada para que permaneçam disponíveis sem um painel de controle no gráfico.
Principais funcionalidades
Agrega nove períodos (M1 … MN1) e rastreia votos de EMA(3/6/9), SMA(50/200), CCI(14) e RSI(21) para cada horizonte.
Calcula níveis de pivô floor-trader, Woodie ou Camarilla em uma série de velas configurável.
Monitora a volatilidade com um feed ATR e registra cada mudança significativa.
Mantém um painel de risco interno calculando a distância do stop, distância de recompensa e relação risco/recompensa ao vivo para a posição ativa.
Suporta execução automática de ordens quando o voto multi-período excede um limiar configurável. Negociações opostas são achatadas antes de reverter, exatamente como ao pressionar os botões do painel.
Aproveita StartProtection para que os guardas de stop-loss e take-profit sobrevivam a reinicializações, refletindo a lógica de proteção do painel original.
Lógica de negociação
Cada assinatura de período produz valores de indicadores para EMA(3/6/9), SMA(50/200), CCI(14) e RSI(21). Um voto altista é adicionado quando o fechamento está acima das médias móveis, CCI está acima de +100 e RSI está acima de 60. Votos baixistas são produzidos para as condições opostas. Leituras neutras não contribuem para a pontuação.
A pontuação total nos períodos prontos é comparada com DirectionalThreshold. Pontuações ≥ limiar geram um sinal de Compra; pontuações ≤ –limiar geram um sinal de Venda.
Quando o trading automático está habilitado, a estratégia:
Fecha a posição oposta com ClosePosition() antes de enviar a ordem de reversão.
Envia uma ordem de mercado dimensionada de acordo com Volume, arredondada para o Security.VolumeStep mais próximo.
Depende de StartProtection para anexar brackets de stop-loss/take-profit expressos em pips.
O ATR da série de velas primária é registrado. Qualquer mudança além da precisão de arredondamento imprime um novo relatório de volatilidade.
Os níveis de pivô são recalculados sempre que o período de pivô produz uma vela finalizada. O log mostra PP, R1–R4 e S1–S4 para que possam ser usados como níveis discricionários ou exportados para dashboards.
Parâmetros
Nome
Descrição
Grupo
Padrão
Volume
Volume de trading em lotes. Arredondado para VolumeStep antes de enviar ordens.
Negociação
1.0
StopLossPips
Distância da entrada ao stop-loss expressa em steps de preço. 0 desabilita o stop.
Risco
50
TakeProfitPips
Distância da entrada ao take-profit em steps de preço. 0 desabilita o take.
Risco
100
VolatilityPeriod
Comprimento de lookback ATR usado para registro de volatilidade.
Volatilidade
14
PrimaryCandleType
Tipo de vela que impulsiona cálculos ATR e desenho no gráfico.
Geral
Velas de 15 minutos
PivotCandleType
Tipo de vela usado para recálculo de níveis de pivô.
Geral
Velas de 1 hora
DirectionalThreshold
Pontuação absoluta necessária para acionar um sinal de Compra/Venda.
Sinais
3
AutoTradingEnabled
Habilita a execução automática de sinais detectados.
Sinais
true
PivotFormula
Preset de pivô (Classic, Woodie, Camarilla).
Geral
Classic
Gestão de risco
StartProtection anexa brackets baseados em preço calculados de StopLossPips e TakeProfitPips (convertidos para preço absoluto usando PriceStep).
_entryPrice, _stopPrice e _takePrice são atualizados em preenchimentos para que a estratégia possa registrar risco, recompensa e relação risco/recompensa em pips.
Se o trading automático estiver desabilitado, o monitor de risco ainda funciona para entradas manuais executadas fora da estratégia.
Diferenças em relação ao painel MQL5
O EA original exibia botões e linhas arrastáveis no gráfico; a versão StockSharp expõe a mesma análise através de logs e parâmetros de estratégia. Todos os comentários dentro do código explicam como estender ou conectar os resultados a uma UI se necessário.
O gerenciamento de posição está automatizado. Clicar em Comprar, Vender, Reverter ou Fechar é substituído por RequestExecution, SendOrder e ClosePosition() em reação à pontuação multi-período.
Points of interest, edições manuais de abas e manipulação de objetos do gráfico não estão portados. Em vez disso, os pivôs são recalculados programaticamente e registrados. Os traders podem consumir o log ou estender a estratégia para desenhar objetos se desejado.
Volatilidade, métricas de risco e pivôs persistem entre reinicializações porque são recalculados a partir de dados ao vivo em vez de depender de objetos do gráfico.
Notas de uso
Anexe a estratégia a um símbolo e certifique-se de que o conector fornece todos os tipos de velas listados em PanelTimeFrames. Dados ausentes atrasarão a geração de sinais até que pelo menos uma vela por período seja finalizada.
Ajuste DirectionalThreshold para controlar a sensibilidade. Limiares mais altos exigem mais concordância entre períodos antes de negociar.
Configure AutoTradingEnabled = false para usar o módulo como dashboard informativo enquanto coloca ordens manualmente de outra ferramenta.
A classe adiciona renderização de gráfico padrão para velas primárias, ATR e negociações próprias. Remova ou estenda essas chamadas se uma visualização personalizada for necessária.
Resumo de conversão
Ações de UI → Métodos de estratégia. Manipuladores de botões do painel (EAPanelClickHandler, T0ClickHandler, etc.) são mapeados para helpers de execução de ordens que preservam o fluxo de compra/venda/reversão/fechamento.
Fórmulas de pivô. Os seletores de MQL5 permitiam fórmulas independentes por nível; este port mantém as combinações preset (Classic, Woodie, Camarilla) que o painel oferecia via seus botões de seleção rápida.
Rastreamento de indicadores. Handles de indicadores nativos do MQL5 são substituídos por ExponentialMovingAverage, SimpleMovingAverage, CommodityChannelIndex e RelativeStrengthIndex do StockSharp com callbacks Bind.
Painel de risco. Todos os cálculos de risco/recompensa que anteriormente eram renderizados em caixas de edição agora são registrados e podem ser consumidos por qualquer componente de monitoramento.
A estratégia, portanto, preserva a intenção do Advanced EA Panel—consciência situacional centralizada com lógica de reação rápida—enquanto se apresenta como uma estratégia StockSharp totalmente automatizada pronta para otimização ou monitoramento discricionário.
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>
/// Advanced EA Panel strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class AdvancedEaPanelStrategy : 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 AdvancedEaPanelStrategy()
{
_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;
}
}
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 advanced_ea_panel_strategy(Strategy):
def __init__(self):
super(advanced_ea_panel_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA 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._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(advanced_ea_panel_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(advanced_ea_panel_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
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 > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val 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_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return advanced_ea_panel_strategy()