This strategy is a contrarian moving average crossover system converted from the original MQL4 expert X_trader_v2. It uses two moving averages to detect sudden reversals and executes trades opposite to the crossing direction.
How It Works
Two simple moving averages are calculated on the selected timeframe.
When the fast MA crosses above the slow MA, the strategy opens a short position.
When the fast MA crosses below the slow MA, the strategy opens a long position.
Only one position can be open at a time. A new trade is placed only after the previous one is closed and a fresh signal appears.
Built-in protection automatically places stop-loss and take-profit orders.
Parameters
Ma1Period – period of the fast moving average.
Ma2Period – period of the slow moving average.
TakeProfitTicks – take-profit distance in price ticks.
StopLossTicks – stop-loss distance in price ticks.
CandleType – candle type used for calculations.
Notes
The strategy subscribes to candle data via the high-level API.
Indicator values are processed through bindings without direct calls to GetValue.
The algorithm stores previous indicator values internally to avoid heavy history lookups.
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>
/// Contrarian moving average crossover strategy (X trader v2).
/// </summary>
public class XTraderV2Strategy : Strategy
{
private readonly StrategyParam<int> _ma1Period;
private readonly StrategyParam<int> _ma2Period;
private readonly StrategyParam<DataType> _candleType;
private decimal _ma1Prev;
private decimal _ma1Prev2;
private decimal _ma2Prev;
private decimal _ma2Prev2;
private bool _hasPrev2;
public int Ma1Period { get => _ma1Period.Value; set => _ma1Period.Value = value; }
public int Ma2Period { get => _ma2Period.Value; set => _ma2Period.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public XTraderV2Strategy()
{
_ma1Period = Param(nameof(Ma1Period), 16)
.SetGreaterThanZero()
.SetDisplay("MA1 Period", "Period for the first moving average", "Indicators");
_ma2Period = Param(nameof(Ma2Period), 10)
.SetGreaterThanZero()
.SetDisplay("MA2 Period", "Period for the second moving average", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_ma1Prev = 0;
_ma1Prev2 = 0;
_ma2Prev = 0;
_ma2Prev2 = 0;
_hasPrev2 = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma1 = new ExponentialMovingAverage { Length = Ma1Period };
var ma2 = new ExponentialMovingAverage { Length = Ma2Period };
SubscribeCandles(CandleType)
.Bind(ma1, ma2, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal ma1, decimal ma2)
{
if (candle.State != CandleStates.Finished) return;
if (_ma1Prev == 0)
{
_ma1Prev = ma1;
_ma2Prev = ma2;
return;
}
if (!_hasPrev2)
{
_ma1Prev2 = _ma1Prev;
_ma2Prev2 = _ma2Prev;
_ma1Prev = ma1;
_ma2Prev = ma2;
_hasPrev2 = true;
return;
}
// Contrarian: sell when MA1 crosses above MA2, buy when crosses below
var sellSignal = ma1 > ma2 && _ma1Prev > _ma2Prev && _ma1Prev2 < _ma2Prev2;
var buySignal = ma1 < ma2 && _ma1Prev < _ma2Prev && _ma1Prev2 > _ma2Prev2;
if (sellSignal && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
else if (buySignal && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
_ma1Prev2 = _ma1Prev;
_ma2Prev2 = _ma2Prev;
_ma1Prev = ma1;
_ma2Prev = ma2;
}
}
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 x_trader_v2_strategy(Strategy):
def __init__(self):
super(x_trader_v2_strategy, self).__init__()
self._ma1_period = self.Param("Ma1Period", 16) \
.SetDisplay("MA1 Period", "Period for the first moving average", "Indicators")
self._ma2_period = self.Param("Ma2Period", 10) \
.SetDisplay("MA2 Period", "Period for the second moving average", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._ma1_prev = 0.0
self._ma1_prev2 = 0.0
self._ma2_prev = 0.0
self._ma2_prev2 = 0.0
self._has_prev2 = False
@property
def ma1_period(self):
return self._ma1_period.Value
@property
def ma2_period(self):
return self._ma2_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(x_trader_v2_strategy, self).OnReseted()
self._ma1_prev = 0.0
self._ma1_prev2 = 0.0
self._ma2_prev = 0.0
self._ma2_prev2 = 0.0
self._has_prev2 = False
def OnStarted2(self, time):
super(x_trader_v2_strategy, self).OnStarted2(time)
ma1 = ExponentialMovingAverage()
ma1.Length = self.ma1_period
ma2 = ExponentialMovingAverage()
ma2.Length = self.ma2_period
self.SubscribeCandles(self.candle_type).Bind(ma1, ma2, self.process_candle).Start()
def process_candle(self, candle, ma1_val, ma2_val):
if candle.State != CandleStates.Finished:
return
m1 = float(ma1_val)
m2 = float(ma2_val)
if self._ma1_prev == 0.0:
self._ma1_prev = m1
self._ma2_prev = m2
return
if not self._has_prev2:
self._ma1_prev2 = self._ma1_prev
self._ma2_prev2 = self._ma2_prev
self._ma1_prev = m1
self._ma2_prev = m2
self._has_prev2 = True
return
sell_signal = m1 > m2 and self._ma1_prev > self._ma2_prev and self._ma1_prev2 < self._ma2_prev2
buy_signal = m1 < m2 and self._ma1_prev < self._ma2_prev and self._ma1_prev2 > self._ma2_prev2
if sell_signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
elif buy_signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._ma1_prev2 = self._ma1_prev
self._ma2_prev2 = self._ma2_prev
self._ma1_prev = m1
self._ma2_prev = m2
def CreateClone(self):
return x_trader_v2_strategy()