Cronex CCI
Strategy based on Cronex Commodity Channel Index crossover. The indicator smooths the CCI through two exponential moving averages to create a fast and a slow line.
The strategy opens a long position when the fast line crosses below the slow line and closes any short position. A short position is opened when the fast line crosses above the slow line and closes any long position.
This contrarian approach attempts to capture reversals after momentum shifts. It works on higher timeframes such as 4 hour candles.
Details
- Entry Criteria: Crossovers of fast and slow smoothed CCI lines.
- Long/Short: Both directions.
- Exit Criteria: Opposite crossover.
- Stops: No.
- Default Values:
CciPeriod= 25FastPeriod= 14SlowPeriod= 25CandleType= TimeSpan.FromHours(4)EnableLongEntry= trueEnableShortEntry= trueEnableLongExit= trueEnableShortExit= true
- Filters:
- Category: Mean Reversion
- Direction: Both
- Indicators: CCI, EMA
- Stops: No
- Complexity: Basic
- Timeframe: Swing (4h)
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
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;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Cronex CCI indicator.
/// </summary>
public class CronexCciStrategy : Strategy
{
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _enableLongEntry;
private readonly StrategyParam<bool> _enableShortEntry;
private readonly StrategyParam<bool> _enableLongExit;
private readonly StrategyParam<bool> _enableShortExit;
private decimal? _prevFast;
private decimal? _prevSlow;
/// <summary>
/// CCI period.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// Fast smoothing period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow smoothing period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Enable opening long positions.
/// </summary>
public bool EnableLongEntry
{
get => _enableLongEntry.Value;
set => _enableLongEntry.Value = value;
}
/// <summary>
/// Enable opening short positions.
/// </summary>
public bool EnableShortEntry
{
get => _enableShortEntry.Value;
set => _enableShortEntry.Value = value;
}
/// <summary>
/// Enable closing long positions.
/// </summary>
public bool EnableLongExit
{
get => _enableLongExit.Value;
set => _enableLongExit.Value = value;
}
/// <summary>
/// Enable closing short positions.
/// </summary>
public bool EnableShortExit
{
get => _enableShortExit.Value;
set => _enableShortExit.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="CronexCciStrategy"/>.
/// </summary>
public CronexCciStrategy()
{
_cciPeriod = Param(nameof(CciPeriod), 25)
.SetRange(5, 100)
.SetDisplay("CCI Period", "CCI calculation length", "Indicators")
;
_fastPeriod = Param(nameof(FastPeriod), 14)
.SetRange(2, 50)
.SetDisplay("Fast Period", "Fast smoothing period", "Indicators")
;
_slowPeriod = Param(nameof(SlowPeriod), 25)
.SetRange(2, 100)
.SetDisplay("Slow Period", "Slow smoothing period", "Indicators")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_enableLongEntry = Param(nameof(EnableLongEntry), true)
.SetDisplay("Enable Long Entry", "Allow opening long positions", "Trading");
_enableShortEntry = Param(nameof(EnableShortEntry), true)
.SetDisplay("Enable Short Entry", "Allow opening short positions", "Trading");
_enableLongExit = Param(nameof(EnableLongExit), true)
.SetDisplay("Enable Long Exit", "Allow closing long positions", "Trading");
_enableShortExit = Param(nameof(EnableShortExit), true)
.SetDisplay("Enable Short Exit", "Allow closing short positions", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Initialize indicators
var cci = new CommodityChannelIndex { Length = CciPeriod };
var fastMa = new EMA { Length = FastPeriod };
var slowMa = new EMA { Length = SlowPeriod };
// Subscribe to candles and bind indicators
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, fastMa, slowMa, ProcessCandle)
.Start();
// Setup chart visualization
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue, decimal fastValue, decimal slowValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
var prevFast = _prevFast;
var prevSlow = _prevSlow;
if (prevFast.HasValue && prevSlow.HasValue)
{
if (prevFast > prevSlow)
{
if (EnableShortExit && Position < 0)
BuyMarket();
if (EnableLongEntry && fastValue <= slowValue && Position <= 0)
BuyMarket();
}
else if (prevFast < prevSlow)
{
if (EnableLongExit && Position > 0)
SellMarket();
if (EnableShortEntry && fastValue >= slowValue && Position >= 0)
SellMarket();
}
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
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 CommodityChannelIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class cronex_cci_strategy(Strategy):
def __init__(self):
super(cronex_cci_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 25) \
.SetDisplay("CCI Period", "CCI calculation length", "Indicators")
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast smoothing period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 25) \
.SetDisplay("Slow Period", "Slow smoothing period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._enable_long_entry = self.Param("EnableLongEntry", True) \
.SetDisplay("Enable Long Entry", "Allow opening long positions", "Trading")
self._enable_short_entry = self.Param("EnableShortEntry", True) \
.SetDisplay("Enable Short Entry", "Allow opening short positions", "Trading")
self._enable_long_exit = self.Param("EnableLongExit", True) \
.SetDisplay("Enable Long Exit", "Allow closing long positions", "Trading")
self._enable_short_exit = self.Param("EnableShortExit", True) \
.SetDisplay("Enable Short Exit", "Allow closing short positions", "Trading")
self._prev_fast = None
self._prev_slow = None
@property
def CciPeriod(self):
return self._cci_period.Value
@CciPeriod.setter
def CciPeriod(self, value):
self._cci_period.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EnableLongEntry(self):
return self._enable_long_entry.Value
@EnableLongEntry.setter
def EnableLongEntry(self, value):
self._enable_long_entry.Value = value
@property
def EnableShortEntry(self):
return self._enable_short_entry.Value
@EnableShortEntry.setter
def EnableShortEntry(self, value):
self._enable_short_entry.Value = value
@property
def EnableLongExit(self):
return self._enable_long_exit.Value
@EnableLongExit.setter
def EnableLongExit(self, value):
self._enable_long_exit.Value = value
@property
def EnableShortExit(self):
return self._enable_short_exit.Value
@EnableShortExit.setter
def EnableShortExit(self, value):
self._enable_short_exit.Value = value
def OnStarted2(self, time):
super(cronex_cci_strategy, self).OnStarted2(time)
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.FastPeriod
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.SlowPeriod
self.SubscribeCandles(self.CandleType) \
.Bind(cci, fast_ma, slow_ma, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, cci_value, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
prev_fast = self._prev_fast
prev_slow = self._prev_slow
if prev_fast is not None and prev_slow is not None:
if prev_fast > prev_slow:
if self.EnableShortExit and self.Position < 0:
self.BuyMarket()
if self.EnableLongEntry and fast_val <= slow_val and self.Position <= 0:
self.BuyMarket()
elif prev_fast < prev_slow:
if self.EnableLongExit and self.Position > 0:
self.SellMarket()
if self.EnableShortEntry and fast_val >= slow_val and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def OnReseted(self):
super(cronex_cci_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def CreateClone(self):
return cronex_cci_strategy()