Cyberia Trader Strategy
This strategy is a simplified StockSharp port of the original CyberiaTrader.mq5 system. It combines several classic technical indicators to evaluate market direction and open trades when most filters agree.
Indicators
- MACD – Detects momentum shifts using fast/slow EMAs and a signal line.
- Simple Moving Average – Determines the prevailing trend.
- Commodity Channel Index – Screens overbought/oversold conditions.
- Average Directional Index – Confirms directional strength via +DI and -DI components.
Parameters
| Name | Description |
|---|---|
MacdFast |
Fast EMA period for MACD. |
MacdSlow |
Slow EMA period for MACD. |
MacdSignal |
Signal line period for MACD. |
MaPeriod |
Length of the moving average trend filter. |
CciPeriod |
Period of Commodity Channel Index. |
AdxPeriod |
Period of Average Directional Index. |
EnableMacd |
Enable/disable the MACD filter. |
EnableMa |
Enable/disable the moving average filter. |
EnableCci |
Enable/disable the CCI filter. |
EnableAdx |
Enable/disable the ADX filter. |
CandleType |
Timeframe of input candles. |
Trading Logic
- Values for all enabled indicators are calculated on each finished candle.
- Filters can block buying or selling based on their respective rules:
- MACD above its signal blocks short entries; below blocks long entries.
- Price above the moving average blocks shorts; below blocks longs.
- CCI above +100 blocks longs; below -100 blocks shorts.
- +DI greater than -DI blocks shorts; -DI greater than +DI blocks longs.
- A trade is opened only if one side is allowed and the opposite side is blocked.
- Basic position protection uses 2% take-profit and 1% stop-loss.
Notes
This translation focuses on the core directional filters of the original algorithm. The extensive probability analysis and auxiliary modules from the MQL5 version are intentionally omitted for clarity.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
using StockSharp.Algo;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified conversion of the CyberiaTrader MQL5 strategy.
/// Combines MACD, MA, CCI, and ADX filters to determine market direction.
/// </summary>
public class CyberiaTraderStrategy : Strategy
{
private readonly StrategyParam<int> _macdFast;
private readonly StrategyParam<int> _macdSlow;
private readonly StrategyParam<int> _macdSignal;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<bool> _enableMacd;
private readonly StrategyParam<bool> _enableMa;
private readonly StrategyParam<bool> _enableCci;
private readonly StrategyParam<bool> _enableAdx;
private readonly StrategyParam<DataType> _candleType;
private MovingAverageConvergenceDivergenceSignal _macd;
private SimpleMovingAverage _ma;
private CommodityChannelIndex _cci;
private AverageDirectionalIndex _adx;
private int _lastDirection;
/// <summary>
/// MACD fast EMA period.
/// </summary>
public int MacdFast { get => _macdFast.Value; set => _macdFast.Value = value; }
/// <summary>
/// MACD slow EMA period.
/// </summary>
public int MacdSlow { get => _macdSlow.Value; set => _macdSlow.Value = value; }
/// <summary>
/// MACD signal line period.
/// </summary>
public int MacdSignal { get => _macdSignal.Value; set => _macdSignal.Value = value; }
/// <summary>
/// Moving average length.
/// </summary>
public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
/// <summary>
/// Commodity Channel Index length.
/// </summary>
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
/// <summary>
/// ADX calculation length.
/// </summary>
public int AdxPeriod { get => _adxPeriod.Value; set => _adxPeriod.Value = value; }
/// <summary>
/// Enable MACD filter.
/// </summary>
public bool EnableMacd { get => _enableMacd.Value; set => _enableMacd.Value = value; }
/// <summary>
/// Enable moving average filter.
/// </summary>
public bool EnableMa { get => _enableMa.Value; set => _enableMa.Value = value; }
/// <summary>
/// Enable CCI filter.
/// </summary>
public bool EnableCci { get => _enableCci.Value; set => _enableCci.Value = value; }
/// <summary>
/// Enable ADX filter.
/// </summary>
public bool EnableAdx { get => _enableAdx.Value; set => _enableAdx.Value = value; }
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initializes a new instance of <see cref="CyberiaTraderStrategy"/>.
/// </summary>
public CyberiaTraderStrategy()
{
_macdFast = Param(nameof(MacdFast), 12)
.SetGreaterThanZero()
.SetDisplay("MACD Fast Period", "Fast EMA period for MACD", "Indicators");
_macdSlow = Param(nameof(MacdSlow), 26)
.SetGreaterThanZero()
.SetDisplay("MACD Slow Period", "Slow EMA period for MACD", "Indicators");
_macdSignal = Param(nameof(MacdSignal), 9)
.SetGreaterThanZero()
.SetDisplay("MACD Signal Period", "Signal MA period for MACD", "Indicators");
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Length of moving average", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Length of CCI", "Indicators");
_adxPeriod = Param(nameof(AdxPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Length of ADX", "Indicators");
_enableMacd = Param(nameof(EnableMacd), true)
.SetDisplay("Enable MACD", "Use MACD direction filter", "Logic");
_enableMa = Param(nameof(EnableMa), true)
.SetDisplay("Enable MA", "Use moving average trend filter", "Logic");
_enableCci = Param(nameof(EnableCci), true)
.SetDisplay("Enable CCI", "Use CCI overbought/oversold filter", "Logic");
_enableAdx = Param(nameof(EnableAdx), true)
.SetDisplay("Enable ADX", "Use ADX directional filter", "Logic");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
Volume = 1;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastDirection = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_lastDirection = 0;
_macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFast },
LongMa = { Length = MacdSlow },
},
SignalMa = { Length = MacdSignal }
};
_ma = new SMA { Length = MaPeriod };
_cci = new CommodityChannelIndex { Length = CciPeriod };
_adx = new AverageDirectionalIndex { Length = AdxPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_macd, _ma, _cci, _adx, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ma);
DrawOwnTrades(area);
var indicatorArea = CreateChartArea();
if (indicatorArea != null)
{
DrawIndicator(indicatorArea, _macd);
DrawIndicator(indicatorArea, _cci);
DrawIndicator(indicatorArea, _adx);
}
}
StartProtection(new Unit(2m, UnitTypes.Percent), new Unit(1m, UnitTypes.Percent));
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdVal, IIndicatorValue maVal, IIndicatorValue cciVal, IIndicatorValue adxVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var macdTyped = (MovingAverageConvergenceDivergenceSignalValue)macdVal;
var adxTyped = (AverageDirectionalIndexValue)adxVal;
var disableBuy = false;
var disableSell = false;
if (EnableMacd)
{
var macd = macdTyped.Macd ?? 0m;
var signal = macdTyped.Signal ?? 0m;
if (macd > signal)
disableSell = true;
else if (macd < signal)
disableBuy = true;
}
if (EnableMa)
{
var ma = maVal.ToDecimal();
if (candle.ClosePrice > ma)
disableSell = true;
else if (candle.ClosePrice < ma)
disableBuy = true;
}
if (EnableCci)
{
var cci = cciVal.ToDecimal();
if (cci > 100m)
disableBuy = true;
else if (cci < -100m)
disableSell = true;
}
if (EnableAdx)
{
var plus = adxTyped.Dx.Plus ?? 0m;
var minus = adxTyped.Dx.Minus ?? 0m;
if (plus > minus)
disableSell = true;
else if (minus > plus)
disableBuy = true;
}
var direction = !disableBuy && disableSell ? 1 : !disableSell && disableBuy ? -1 : 0;
if (direction == 1 && _lastDirection != 1 && Position <= 0)
{
BuyMarket();
}
else if (direction == -1 && _lastDirection != -1 && Position >= 0)
{
SellMarket();
}
_lastDirection = direction;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import (
MovingAverageConvergenceDivergenceSignal,
SimpleMovingAverage as SMA,
CommodityChannelIndex,
AverageDirectionalIndex,
)
from StockSharp.Algo.Strategies import Strategy
class cyberia_trader_strategy(Strategy):
def __init__(self):
super(cyberia_trader_strategy, self).__init__()
self._macd_fast = self.Param("MacdFast", 12)
self._macd_slow = self.Param("MacdSlow", 26)
self._macd_signal = self.Param("MacdSignal", 9)
self._ma_period = self.Param("MaPeriod", 20)
self._cci_period = self.Param("CciPeriod", 14)
self._adx_period = self.Param("AdxPeriod", 14)
self._enable_macd = self.Param("EnableMacd", True)
self._enable_ma = self.Param("EnableMa", True)
self._enable_cci = self.Param("EnableCci", True)
self._enable_adx = self.Param("EnableAdx", True)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._last_direction = 0
self.Volume = 1
@property
def MacdFast(self):
return self._macd_fast.Value
@MacdFast.setter
def MacdFast(self, value):
self._macd_fast.Value = value
@property
def MacdSlow(self):
return self._macd_slow.Value
@MacdSlow.setter
def MacdSlow(self, value):
self._macd_slow.Value = value
@property
def MacdSignal(self):
return self._macd_signal.Value
@MacdSignal.setter
def MacdSignal(self, value):
self._macd_signal.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
@property
def CciPeriod(self):
return self._cci_period.Value
@CciPeriod.setter
def CciPeriod(self, value):
self._cci_period.Value = value
@property
def AdxPeriod(self):
return self._adx_period.Value
@AdxPeriod.setter
def AdxPeriod(self, value):
self._adx_period.Value = value
@property
def EnableMacd(self):
return self._enable_macd.Value
@EnableMacd.setter
def EnableMacd(self, value):
self._enable_macd.Value = value
@property
def EnableMa(self):
return self._enable_ma.Value
@EnableMa.setter
def EnableMa(self, value):
self._enable_ma.Value = value
@property
def EnableCci(self):
return self._enable_cci.Value
@EnableCci.setter
def EnableCci(self, value):
self._enable_cci.Value = value
@property
def EnableAdx(self):
return self._enable_adx.Value
@EnableAdx.setter
def EnableAdx(self, value):
self._enable_adx.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(cyberia_trader_strategy, self).OnStarted2(time)
self._last_direction = 0
self._macd = MovingAverageConvergenceDivergenceSignal()
self._macd.Macd.ShortMa.Length = self.MacdFast
self._macd.Macd.LongMa.Length = self.MacdSlow
self._macd.SignalMa.Length = self.MacdSignal
self._ma = SMA()
self._ma.Length = self.MaPeriod
self._cci = CommodityChannelIndex()
self._cci.Length = self.CciPeriod
self._adx = AverageDirectionalIndex()
self._adx.Length = self.AdxPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(self._macd, self._ma, self._cci, self._adx, self.ProcessCandle).Start()
self.StartProtection(Unit(2, UnitTypes.Percent), Unit(1, UnitTypes.Percent))
def ProcessCandle(self, candle, macd_val, ma_val, cci_val, adx_val):
if candle.State != CandleStates.Finished:
return
macd_typed = macd_val
adx_typed = adx_val
disable_buy = False
disable_sell = False
if self.EnableMacd:
macd = float(macd_typed.Macd) if macd_typed.Macd is not None else 0.0
signal = float(macd_typed.Signal) if macd_typed.Signal is not None else 0.0
if macd > signal:
disable_sell = True
elif macd < signal:
disable_buy = True
if self.EnableMa:
ma = float(ma_val)
if float(candle.ClosePrice) > ma:
disable_sell = True
elif float(candle.ClosePrice) < ma:
disable_buy = True
if self.EnableCci:
cci = float(cci_val)
if cci > 100.0:
disable_buy = True
elif cci < -100.0:
disable_sell = True
if self.EnableAdx:
plus_val = float(adx_typed.Dx.Plus) if adx_typed.Dx.Plus is not None else 0.0
minus_val = float(adx_typed.Dx.Minus) if adx_typed.Dx.Minus is not None else 0.0
if plus_val > minus_val:
disable_sell = True
elif minus_val > plus_val:
disable_buy = True
if not disable_buy and disable_sell:
direction = 1
elif not disable_sell and disable_buy:
direction = -1
else:
direction = 0
if direction == 1 and self._last_direction != 1 and self.Position <= 0:
self.BuyMarket()
elif direction == -1 and self._last_direction != -1 and self.Position >= 0:
self.SellMarket()
self._last_direction = direction
def OnReseted(self):
super(cyberia_trader_strategy, self).OnReseted()
self._last_direction = 0
def CreateClone(self):
return cyberia_trader_strategy()