A Estratégia X Bug é um sistema cruzado de média móvel convertido do consultor especialista MQL4 com o mesmo nome. Ele compara duas médias móveis simples calculadas sobre o preço médio da vela. Quando a média rápida cruza acima ou abaixo da média lenta, a estratégia abre uma posição na direção do cruzamento. A implementação reproduz os recursos originais do Expert Advisor, incluindo reversão de sinal opcional, fechamento automático de posição em sinais opostos e ordens de proteção baseadas em pip.
Lógica de negociação
Assine o tipo de vela configurado (velas de um minuto por padrão) e calcule duas médias móveis simples: uma linha rápida e uma linha lenta. As médias utilizam o preço mediano e respeitam as mudanças do indicador configuradas.
Detecte um cruzamento de alta quando o valor rápido atual estiver acima do valor lento, enquanto o valor rápido duas barras anteriores estiver abaixo do valor lento. Detecte um cruzamento de baixa usando a condição oposta.
Opcionalmente, inverta o sinal de cruzamento quando ReverseSignals estiver habilitado para negociar na direção oposta.
Quando CloseOnSignal estiver habilitado, feche imediatamente qualquer posição oposta antes de inserir uma nova no novo sinal.
Insira posições longas em sinais de alta e posições curtas em sinais de baixa. A estratégia evita empilhar posições na mesma direção; ele só negocia quando a posição atual é plana ou alinhada com o sinal.
Gestão de risco
StopLossPips – define um stop de proteção absoluto em pips. O stop é expresso em pips inteiros; o preço fracionário (cotações de 5 ou 3 dígitos) é tratado automaticamente pela conversão do valor do pip usando a etapa de preço do título.
TakeProfitPips – configura a distância alvo de lucro em pips.
TrailingStopPips – quando UseTrailingStop está habilitado, ativa um trailing stop que começa na distância do pip configurada assim que a posição se move para lucro. A etapa final corresponde à distância final, replicando a lógica MetaTrader original.
Todas as ordens de proteção são gerenciadas por meio de StartProtection com saídas de mercado para manter a paridade com o especialista MQL4.
Parâmetros
Parâmetro
Descrição
Padrão
OrderVolume
Volume base de negociação usado para entradas no mercado.
0.1
StopLossPips
Distância de stop-loss medida em pips; defina como 0 para desativar.
70
TakeProfitPips
Distância de take-profit medida em pips; defina como 0 para desativar.
5000
UseTrailingStop
Ativa ou desativa o gerenciamento de trailing stop.
true
TrailingStopPips
Distância final em pips.
90
FastPeriod
Período da média móvel rápida.
1
FastShift
Barras para mudar a média móvel rápida antes de avaliar os sinais.
0
SlowPeriod
Período da média móvel lenta.
14
SlowShift
Barras para mudar a média móvel lenta antes de avaliar os sinais.
10
CloseOnSignal
Feche uma posição oposta imediatamente quando um novo sinal aparecer.
true
ReverseSignals
Inverta a direção do sinal para negociar contra o cruzamento.
false
AppliedPrice
Fonte de preços de velas fornecida às médias móveis.
Median
CandleType
Tipo de dados Candle para geração de sinal.
1 minute período de tempo
Notas
A conversão do pip multiplica o passo do preço por 10 para símbolos cotados com 5 ou 3 casas decimais, correspondendo ao comportamento original do Expert Advisor.
Nenhuma porta Python é fornecida; apenas a estratégia C# está incluída neste diretório.
Paradas finais, paradas e alvos são opcionais. Defina os valores pip correspondentes como zero para desativá-los.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Moving average crossover strategy converted from the MQL4 expert "X bug".
/// Uses fast and slow SMA crossover for signal generation.
/// </summary>
public class XBugStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<bool> _reverseSignals;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _slowMa;
private decimal? _prevFast;
private decimal? _prevSlow;
private int _cooldown;
private int _candleCount;
public XBugStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast MA period", "Length of the fast moving average.", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Slow MA period", "Length of the slow moving average.", "Indicators");
_reverseSignals = Param(nameof(ReverseSignals), false)
.SetDisplay("Reverse signals", "Invert buy and sell directions.", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle type", "Primary timeframe used for signals.", "General");
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public bool ReverseSignals
{
get => _reverseSignals.Value;
set => _reverseSignals.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_slowMa = default;
_prevFast = null;
_prevSlow = null;
_cooldown = 0;
_candleCount = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = 0.001m;
_prevFast = null;
_prevSlow = null;
_cooldown = 0;
_candleCount = 0;
_slowMa = new SimpleMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_slowMa, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_slowMa.IsFormed)
return;
_candleCount++;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Use close price as the "fast" value (period=1 effectively)
var fastValue = candle.ClosePrice;
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var signal = 0;
if (fastValue > slowValue && _prevFast.Value <= _prevSlow.Value)
signal = 1;
else if (fastValue < slowValue && _prevFast.Value >= _prevSlow.Value)
signal = -1;
_prevFast = fastValue;
_prevSlow = slowValue;
if (signal == 0)
return;
if (ReverseSignals)
signal = -signal;
if (signal > 0 && Position <= 0)
{
BuyMarket();
_cooldown = 100;
}
else if (signal < 0 && Position >= 0)
{
SellMarket();
_cooldown = 100;
}
}
}
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 SimpleMovingAverage
class x_bug_strategy(Strategy):
def __init__(self):
super(x_bug_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle type", "Primary timeframe used for signals.", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast MA period", "Length of the fast moving average.", "Indicators")
self._slow_period = self.Param("SlowPeriod", 14) \
.SetDisplay("Slow MA period", "Length of the slow moving average.", "Indicators")
self._reverse_signals = self.Param("ReverseSignals", False) \
.SetDisplay("Reverse signals", "Invert buy and sell directions.", "Trading")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
@property
def ReverseSignals(self):
return self._reverse_signals.Value
def OnStarted2(self, time):
super(x_bug_strategy, self).OnStarted2(time)
from System import Decimal
self.Volume = Decimal(0.001)
self._prev_fast = None
self._prev_slow = None
self._slow_ma = SimpleMovingAverage()
self._slow_ma.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._slow_ma, self.ProcessCandle).Start()
def ProcessCandle(self, candle, slow_val):
if candle.State != CandleStates.Finished:
return
if not self._slow_ma.IsFormed:
return
from System import Decimal
sv = Decimal(float(slow_val))
fast_value = candle.ClosePrice
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast_value
self._prev_slow = sv
return
signal = 0
if fast_value > sv and self._prev_fast <= self._prev_slow:
signal = 1
elif fast_value < sv and self._prev_fast >= self._prev_slow:
signal = -1
self._prev_fast = fast_value
self._prev_slow = sv
if signal == 0:
return
if self.ReverseSignals:
signal = -signal
if signal > 0 and self.Position <= 0:
self.BuyMarket()
elif signal < 0 and self.Position >= 0:
self.SellMarket()
def OnReseted(self):
super(x_bug_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def CreateClone(self):
return x_bug_strategy()