A Wajdyss MA Expert Strategy é uma versão C# do MetaTrader 4 consultor especialista "wajdyss MA expert v3". Ele compara duas médias móveis configuradas com períodos independentes, modos de cálculo, mudanças e preços aplicados. Um cruzamento de alta da média rápida acima da média lenta abre uma exposição longa, enquanto um cruzamento de baixa abre uma exposição curta. A conversão reproduz as regras originais de gestão de dinheiro, fechamento automático opcional de negociações opostas e filtros de liquidação de final de dia/fim de semana.
Lógica de negociação
Assine o CandleType selecionado (velas de 15 minutos por padrão) e calcule as médias móveis rápidas e lentas usando as configurações MovingAverageMethod e PriceSource escolhidas para cada perna.
Armazene os valores dos indicadores para velas finalizadas. Avalie um sinal de alta quando a média rápida (com sua mudança configurada) estiver acima da média lenta na última barra fechada, enquanto estava abaixo de duas barras atrás. Avalie um sinal de baixa com a condição inversa.
Imponha um resfriamento entre novas entradas na mesma direção. A estratégia deve esperar pelo menos uma vela completa do período subscrito após a última negociação desse lado, espelhando o guarda de tempo variável global da versão MT4.
Quando AutoCloseOpposite estiver ativado, cancele ordens de trabalho e reverta a exposição em uma única ordem de mercado: o novo volume de ordem inclui qualquer posição pendente na direção oposta para que a conta mude imediatamente.
Aplique filtros de fechamento diário e de sexta-feira. Após o DailyCloseHour/DailyCloseMinute ou FridayCloseHour/FridayCloseMinute configurado, todas as posições são achatadas e novas negociações são bloqueadas até a próxima sessão.
Gestão de Risco e Dinheiro
TakeProfitPips, StopLossPips e TrailingStopPips são interpretados em pips inteiros. A implementação os converte em etapas de preço usando os metadados de segurança e aciona o mecanismo StartProtection de StockSharp com saídas de mercado para paridade com a lógica final original.
UseMoneyManagement emula o cálculo do lote MT4: volume = (account_balance / BalanceReference) * InitialVolume. Os limites de câmbio são respeitados por meio de verificações de etapas de volume, mínimo e máximo.
Se o gerenciamento de dinheiro estiver desativado, os pedidos usarão InitialVolume diretamente.
Parâmetros
Parâmetro
Tipo
Padrão
Descrição
FastPeriod
int
10
Período da média móvel rápida.
FastShift
int
0
Barras para alterar a média rápida antes de comparar os valores de cruzamento.
FastMethod
MovingAverageMethod
Ema
Modo de média móvel para a linha rápida (Sma, Ema, Smma, Lwma).
FastPriceType
PriceSource
Close
Preço da vela inserido na média móvel rápida (Close, Open, High, Low, Median, Typical, Weighted).
SlowPeriod
int
20
Período da média móvel lenta.
SlowShift
int
0
Barras para mudar a média lenta antes da comparação.
SlowMethod
MovingAverageMethod
Ema
Modo de média móvel para a linha lenta.
SlowPriceType
PriceSource
Close
O preço da vela alimentou a média lenta.
TakeProfitPips
decimal
100
Distância até a meta de lucro em pips (definida como 0 para desativar).
StopLossPips
decimal
50
Distância até a parada de proteção em pips (definida como 0 para desativar).
TrailingStopPips
decimal
0
Distância do trailing stop em pips (definida como 0 para desativar).
AutoCloseOpposite
bool
true
Feche a exposição oposta antes de abrir uma nova negociação na outra direção.
InitialVolume
decimal
0.1
Baseie o volume de negociação antes de aplicar a gestão de dinheiro.
UseMoneyManagement
bool
true
Ative o dimensionamento de posição baseado em equilíbrio.
BalanceReference
decimal
1000
Divisor usado ao dimensionar o volume com o saldo da conta.
DailyCloseHour
int
23
Hora (0-23) após a qual as posições diárias são fechadas.
DailyCloseMinute
int
45
Componente minuto do filtro de fechamento diário.
FridayCloseHour
int
22
Hora (0-23) após a qual a negociação de sexta-feira termina.
FridayCloseMinute
int
45
Componente minuto do filtro de fechamento de sexta-feira.
CandleType
DataType
15m período de tempo
Série de velas usada para cálculos e tempo de resfriamento.
Notas
A estratégia depende exclusivamente do StockSharp API de alto nível: velas são processadas por meio de SubscribeCandles, ligações de indicadores alimentam médias móveis e StartProtection gerencia ordens de stop/take-profit/trailing.
O achatamento de posição usa ordens de mercado para espelhar os fechamentos imediatos de tickets opostos do especialista MT4.
Nenhuma tradução do Python está incluída nesta pasta; apenas a implementação C# é fornecida.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Wajdyss MA Expert: Fast/slow EMA crossover with ATR stops.
/// </summary>
public class WajdyssMaExpertStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public WajdyssMaExpertStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastLength = Param(nameof(FastLength), 10)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowLength = Param(nameof(SlowLength), 20)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period for stops.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
var fast = new ExponentialMovingAverage { Length = FastLength };
var slow = new ExponentialMovingAverage { Length = SlowLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
// Exit
if (Position > 0)
{
if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 3m || fastVal < slowVal)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (close >= _entryPrice + atrVal * 2m || close <= _entryPrice - atrVal * 3m || fastVal > slowVal)
{
BuyMarket();
_entryPrice = 0;
}
}
// Entry: EMA crossover
if (Position == 0)
{
if (_prevFast <= _prevSlow && fastVal > slowVal)
{
_entryPrice = close;
BuyMarket();
}
else if (_prevFast >= _prevSlow && fastVal < slowVal)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
class wajdyss_ma_expert_strategy(Strategy):
def __init__(self):
super(wajdyss_ma_expert_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._fast_length = self.Param("FastLength", 10) \
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators")
self._slow_length = self.Param("SlowLength", 20) \
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period for stops.", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastLength(self):
return self._fast_length.Value
@property
def SlowLength(self):
return self._slow_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(wajdyss_ma_expert_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._fast = ExponentialMovingAverage()
self._fast.Length = self.FastLength
self._slow = ExponentialMovingAverage()
self._slow.Length = self.SlowLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._fast, self._slow, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
fv = float(fast_val)
sv = float(slow_val)
av = float(atr_val)
if self._prev_fast == 0 or self._prev_slow == 0 or av <= 0:
self._prev_fast = fv
self._prev_slow = sv
return
close = float(candle.ClosePrice)
# Exit
if self.Position > 0:
if close <= self._entry_price - av * 2.0 or close >= self._entry_price + av * 3.0 or fv < sv:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close >= self._entry_price + av * 2.0 or close <= self._entry_price - av * 3.0 or fv > sv:
self.BuyMarket()
self._entry_price = 0.0
# Entry: EMA crossover
if self.Position == 0:
if self._prev_fast <= self._prev_slow and fv > sv:
self._entry_price = close
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv:
self._entry_price = close
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def OnReseted(self):
super(wajdyss_ma_expert_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
def CreateClone(self):
return wajdyss_ma_expert_strategy()