Color Zerolag JJRSX Strategy
This strategy replicates the logic of the ColorZerolagJJRSX MetaTrader expert. It uses two smoothed RSI oscillators to approximate the original ColorZerolagJJRSX indicator. The fast and slow lines cross to generate trading signals.
How It Works
- When the fast oscillator crosses below the slow oscillator, the strategy closes any short position and optionally opens a new long position.
- When the fast oscillator crosses above the slow oscillator, the strategy closes any long position and optionally opens a new short position.
- Protective stop-loss and take-profit levels are applied using the built-in
StartProtectionmechanism.
Parameters
| Name | Description |
|---|---|
FastPeriod |
Period of the fast JJRSX line. |
SlowPeriod |
Period of the slow JJRSX line. |
BuyOpen |
Allow opening long positions. |
SellOpen |
Allow opening short positions. |
BuyClose |
Close existing long positions on opposite signal. |
SellClose |
Close existing short positions on opposite signal. |
StopLoss |
Stop-loss level in price units. |
TakeProfit |
Take-profit level in price units. |
CandleType |
Time frame used for calculations. |
Notes
- The implementation uses built-in indicators and high-level
BindAPI. - Volume is taken from the strategy's
Volumeproperty. - Implementations are available in both C# and Python.
References
Original MQL source located in MQL/13854 within this repository.
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>
/// Strategy based on crossing of two RSI lines (fast and slow).
/// </summary>
public class ColorZerolagJjrsxStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
private readonly StrategyParam<bool> _buyOpen, _sellOpen, _buyClose, _sellClose;
private Order _pending;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public bool BuyOpen { get => _buyOpen.Value; set => _buyOpen.Value = value; }
public bool SellOpen { get => _sellOpen.Value; set => _sellOpen.Value = value; }
public bool BuyClose { get => _buyClose.Value; set => _buyClose.Value = value; }
public bool SellClose { get => _sellClose.Value; set => _sellClose.Value = value; }
public ColorZerolagJjrsxStrategy()
{
_buyOpen = Param(nameof(BuyOpen), true);
_sellOpen = Param(nameof(SellOpen), true);
_buyClose = Param(nameof(BuyClose), true);
_sellClose = Param(nameof(SellClose), true);
_fastPeriod = Param(nameof(FastPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast RSI period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow RSI period", "Indicator");
_stopLoss = Param(nameof(StopLoss), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfit = Param(nameof(TakeProfit), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Time frame for indicator", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
_pending = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_pending = null;
var fastRsi = new RelativeStrengthIndex { Length = FastPeriod };
var slowRsi = new RelativeStrengthIndex { Length = SlowPeriod };
StartProtection(
takeProfit: new Unit(TakeProfit, UnitTypes.Absolute),
stopLoss: new Unit(StopLoss, UnitTypes.Absolute),
useMarketOrders: true);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastRsi, slowRsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastRsi);
DrawIndicator(area, slowRsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast is null || _prevSlow is null)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var crossDown = _prevFast > _prevSlow && fast < slow;
var crossUp = _prevFast < _prevSlow && fast > slow;
if (IsFormedAndOnlineAndAllowTrading() && (_pending is null || _pending.State is OrderStates.Done or OrderStates.Failed))
{
if (crossDown)
{
if (Position < 0m && SellClose) _pending = BuyMarket(-Position + (BuyOpen ? Volume : 0m));
else if (Position == 0m && BuyOpen) _pending = BuyMarket(Volume);
}
else if (crossUp)
{
if (Position > 0m && BuyClose) _pending = SellMarket(Position + (SellOpen ? Volume : 0m));
else if (Position == 0m && SellOpen) _pending = SellMarket(Volume);
}
}
_prevFast = fast;
_prevSlow = slow;
}
}
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, OrderStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class color_zerolag_jjrsx_strategy(Strategy):
def __init__(self):
super(color_zerolag_jjrsx_strategy, self).__init__()
self._buy_open = self.Param("BuyOpen", True)
self._sell_open = self.Param("SellOpen", True)
self._buy_close = self.Param("BuyClose", True)
self._sell_close = self.Param("SellClose", True)
self._pending = None
self._fast_period = self.Param("FastPeriod", 8) \
.SetDisplay("Fast Period", "Fast RSI period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 21) \
.SetDisplay("Slow Period", "Slow RSI period", "Indicator")
self._stop_loss = self.Param("StopLoss", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit = self.Param("TakeProfit", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame for indicator", "General")
self._prev_fast = None
self._prev_slow = None
self._pending = None
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_pct(self):
return self._stop_loss.Value
@property
def take_profit_pct(self):
return self._take_profit.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_zerolag_jjrsx_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(color_zerolag_jjrsx_strategy, self).OnStarted2(time)
self._pending = None
fast_rsi = RelativeStrengthIndex()
fast_rsi.Length = self.fast_period
slow_rsi = RelativeStrengthIndex()
slow_rsi.Length = self.slow_period
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Absolute),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Absolute),
useMarketOrders=True)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_rsi, slow_rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_rsi)
self.DrawIndicator(area, slow_rsi)
self.DrawOwnTrades(area)
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast = float(fast)
slow = float(slow)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fast
self._prev_slow = slow
return
cross_down = self._prev_fast > self._prev_slow and fast < slow
cross_up = self._prev_fast < self._prev_slow and fast > slow
if self.IsFormedAndOnlineAndAllowTrading() and (self._pending is None or self._pending.State in (OrderStates.Done, OrderStates.Failed)):
if cross_down:
if self.Position < 0 and self._sell_close.Value:
self._pending = self.BuyMarket(-self.Position + (self.Volume if self._buy_open.Value else 0))
elif self.Position == 0 and self._buy_open.Value:
self._pending = self.BuyMarket(self.Volume)
elif cross_up:
if self.Position > 0 and self._buy_close.Value:
self._pending = self.SellMarket(self.Position + (self.Volume if self._sell_open.Value else 0))
elif self.Position == 0 and self._sell_open.Value:
self._pending = self.SellMarket(self.Volume)
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return color_zerolag_jjrsx_strategy()