This strategy is a C# conversion of the MQL5 expert Exp_ColorSchaffJCCXTrendCycle.
It employs the Schaff Trend Cycle (STC) oscillator built on top of the JCCX algorithm.
Trading Logic
Calculate the Schaff Trend Cycle on each finished candle.
When the oscillator drops below the High Level after being above it, a long position is opened and short positions are closed.
When the oscillator rises above the Low Level after being below it, a short position is opened and long positions are closed.
Parameters
Name
Description
Fast JCCX
Fast JCCX period used in the indicator.
Slow JCCX
Slow JCCX period used in the indicator.
Smoothing
JJMA smoothing factor for JCCX.
Phase
JJMA phase value.
Cycle
Length of the cycle for Schaff Trend calculation.
High Level
Upper trigger level of the oscillator.
Low Level
Lower trigger level of the oscillator.
Open Long
Allow opening long positions.
Open Short
Allow opening short positions.
Close Long
Allow closing existing long positions.
Close Short
Allow closing existing short positions.
Notes
The strategy uses StockSharp's high level API and subscribes to candle data. It reacts only to finished candles. Money management and risk control are kept simple for demonstration purposes.
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 the Schaff Trend Cycle indicator level crossovers.
/// </summary>
public class ColorSchaffJccxTrendCycleStrategy : Strategy
{
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prev;
public decimal HighLevel { get => _highLevel.Value; set => _highLevel.Value = value; }
public decimal LowLevel { get => _lowLevel.Value; set => _lowLevel.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ColorSchaffJccxTrendCycleStrategy()
{
_highLevel = Param(nameof(HighLevel), 75m)
.SetDisplay("High Level", "Upper trigger level", "Signal");
_lowLevel = Param(nameof(LowLevel), 25m)
.SetDisplay("Low Level", "Lower trigger level", "Signal");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prev = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stc = new SchaffTrendCycle();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(stc, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, stc);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal stc)
{
if (candle.State != CandleStates.Finished)
return;
if (_prev is null)
{
_prev = stc;
return;
}
if (_prev > HighLevel && stc <= HighLevel && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (_prev < LowLevel && stc >= LowLevel && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prev = stc;
}
}
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 SchaffTrendCycle
from StockSharp.Algo.Strategies import Strategy
class color_schaff_jccx_trend_cycle_strategy(Strategy):
def __init__(self):
super(color_schaff_jccx_trend_cycle_strategy, self).__init__()
self._high_level = self.Param("HighLevel", 75.0) \
.SetDisplay("High Level", "Upper trigger level", "Signal")
self._low_level = self.Param("LowLevel", 25.0) \
.SetDisplay("Low Level", "Lower trigger level", "Signal")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev = None
@property
def high_level(self):
return self._high_level.Value
@property
def low_level(self):
return self._low_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_schaff_jccx_trend_cycle_strategy, self).OnReseted()
self._prev = None
def OnStarted2(self, time):
super(color_schaff_jccx_trend_cycle_strategy, self).OnStarted2(time)
stc = SchaffTrendCycle()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(stc, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, stc)
self.DrawOwnTrades(area)
def process_candle(self, candle, stc_val):
if candle.State != CandleStates.Finished:
return
stc_val = float(stc_val)
if self._prev is None:
self._prev = stc_val
return
if self._prev > float(self.high_level) and stc_val <= float(self.high_level) and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev < float(self.low_level) and stc_val >= float(self.low_level) and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev = stc_val
def CreateClone(self):
return color_schaff_jccx_trend_cycle_strategy()