Auf GitHub ansehen

This strategy trades on the crossover of two Commodity Channel Index (CCI) indicators. A fast CCI reacts quickly to price changes while a slow CCI smooths market noise. Signals are generated when the fast line crosses the slow one.

Details

  • Entry Criteria:
    • Long: fast CCI crosses above slow CCI.
    • Short: fast CCI crosses below slow CCI.
  • Long/Short: Both.
  • Exit Criteria:
    • Long positions closed when fast CCI crosses below slow CCI.
    • Short positions closed when fast CCI crosses above slow CCI.
  • Stops: No.
  • Default Values:
    • CandleType = 6-hour candles
    • FastLength = 14
    • SlowLength = 6
    • BuyOpen = true
    • SellOpen = true
    • BuyClose = true
    • SellClose = true
  • Filters:
    • Category: Trend-following
    • Direction: Both
    • Indicators: CCI
    • Stops: No
    • Complexity: Low
    • Timeframe: Any
    • 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 crossover of fast and slow CCI indicators.
/// </summary>
public class DigitalCciWoodiesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<bool> _buyOpen;
	private readonly StrategyParam<bool> _sellOpen;
	private readonly StrategyParam<bool> _buyClose;
	private readonly StrategyParam<bool> _sellClose;
	
	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _isFirst = true;
	
	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	
	/// <summary>
	/// Fast CCI length.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}
	
	/// <summary>
	/// Slow CCI length.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}
	
	/// <summary>
	/// Allow long entries.
	/// </summary>
	public bool BuyOpen
	{
		get => _buyOpen.Value;
		set => _buyOpen.Value = value;
	}
	
	/// <summary>
	/// Allow short entries.
	/// </summary>
	public bool SellOpen
	{
		get => _sellOpen.Value;
		set => _sellOpen.Value = value;
	}
	
	/// <summary>
	/// Allow closing long positions.
	/// </summary>
	public bool BuyClose
	{
		get => _buyClose.Value;
		set => _buyClose.Value = value;
	}
	
	/// <summary>
	/// Allow closing short positions.
	/// </summary>
	public bool SellClose
	{
		get => _sellClose.Value;
		set => _sellClose.Value = value;
	}
	
	/// <summary>
	/// Initializes the strategy parameters.
	/// </summary>
	public DigitalCciWoodiesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Timeframe for candles", "General");
		
		_fastLength = Param(nameof(FastLength), 14)
		.SetGreaterThanZero()
		.SetDisplay("Fast CCI Length", "Length of the fast CCI", "Indicators")
		
		.SetOptimize(5, 30, 1);
		
		_slowLength = Param(nameof(SlowLength), 6)
		.SetGreaterThanZero()
		.SetDisplay("Slow CCI Length", "Length of the slow CCI", "Indicators")
		
		.SetOptimize(3, 20, 1);
		
		_buyOpen = Param(nameof(BuyOpen), true)
		.SetDisplay("Buy Open", "Allow long entries", "Trading");
		
		_sellOpen = Param(nameof(SellOpen), true)
		.SetDisplay("Sell Open", "Allow short entries", "Trading");
		
		_buyClose = Param(nameof(BuyClose), true)
		.SetDisplay("Buy Close", "Allow closing longs", "Trading");
		
		_sellClose = Param(nameof(SellClose), true)
		.SetDisplay("Sell Close", "Allow closing shorts", "Trading");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = default;
		_prevSlow = default;
		_isFirst = true;
	}
	
	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		var fastCci = new CommodityChannelIndex { Length = FastLength };
		var slowCci = new CommodityChannelIndex { Length = SlowLength };
		
		var subscription = SubscribeCandles(CandleType);
		subscription
		.Bind(fastCci, slowCci, ProcessCandle)
		.Start();
		
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
		
		var indicatorArea = CreateChartArea();
		if (indicatorArea != null)
		{
			DrawIndicator(indicatorArea, fastCci);
			DrawIndicator(indicatorArea, slowCci);
		}
		
	}
	
	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		// Skip unfinished candles
		if (candle.State != CandleStates.Finished)
		return;
		
		// Ensure trading is allowed
		if (!IsFormedAndOnlineAndAllowTrading())
		return;
		
		if (_isFirst)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_isFirst = false;
			return;
		}
		
		var crossUp = _prevFast <= _prevSlow && fast > slow;
		var crossDown = _prevFast >= _prevSlow && fast < slow;
		
		if (crossUp)
		{
			if (Position < 0 && SellClose)
				BuyMarket();
			if (BuyOpen && Position <= 0)
				BuyMarket();
		}
		else if (crossDown)
		{
			if (Position > 0 && BuyClose)
				SellMarket();
			if (SellOpen && Position >= 0)
				SellMarket();
		}
		else
		{
			if (fast > slow && SellClose && Position < 0)
				BuyMarket();
			if (fast < slow && BuyClose && Position > 0)
				SellMarket();
		}
		
		_prevFast = fast;
		_prevSlow = slow;
	}
}