Auf GitHub ansehen

CCI Automatisiert

CCI Automatisiert ist eine Umkehrstrategie, die auf Schwellenwert-Kreuzungen des Commodity Channel Index (CCI) reagiert. Sie geht Long, wenn der CCI über −80 steigt, nachdem er unter −90 gefallen war, und Short, wenn der CCI unter 80 fällt, nachdem er 90 überschritten hatte. Das System verdoppelt Trades bis zu einem benutzerdefinierten Limit, verwaltet das Risiko mit festen Take-Profit- und Stop-Loss-Niveaus und verfolgt Gewinne mit einem konfigurierbaren Trailing-Stop.

Der Ansatz zielt darauf ab, frühe Momentum-Verschiebungen nach überkauften oder überverkauften Zuständen zu erfassen. Durch das Aufstocken mehrerer Positionen und das Verschieben des Stops, wenn der Kurs voranschreitet, versucht er von anhaltenden Umkehrungen zu profitieren und gleichzeitig das Verlustrisiko zu begrenzen.

Details

  • Einstiegskriterien: CCI kreuzt über -80, nachdem er unter -90 war, für Longs; kreuzt unter 80, nachdem er über 90 war, für Shorts.
  • Long/Short: Beide Richtungen.
  • Ausstiegskriterien: Stop-Loss, Take-Profit oder Trailing-Stop.
  • Stops: Ja.
  • Standardwerte:
    • CciPeriod = 9
    • TradesDuplicator = 3
    • Volume = 0.03
    • StopLoss = 50
    • TakeProfit = 200
    • TrailingStop = 50
    • CandleType = TimeSpan.FromMinutes(5)
  • Filter:
    • Kategorie: Mean Reversion
    • Richtung: Beide
    • Indikatoren: CCI
    • Stops: Ja
    • Komplexität: Grundlegend
    • Zeitrahmen: Intraday (5m)
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
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 that trades based on CCI crossing specific thresholds.
/// </summary>
public class CciAutomatedStrategy : Strategy
{
	private readonly StrategyParam<int> _cciPeriod;
	private readonly StrategyParam<int> _tradesDuplicator;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _trailingStop;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevCci;
	private decimal? _trailPrice;

	/// <summary>
	/// CCI calculation period.
	/// </summary>
	public int CciPeriod
	{
		get => _cciPeriod.Value;
		set => _cciPeriod.Value = value;
	}

	/// <summary>
	/// Maximum number of duplicated trades.
	/// </summary>
	public int TradesDuplicator
	{
		get => _tradesDuplicator.Value;
		set => _tradesDuplicator.Value = value;
	}


	/// <summary>
	/// Stop loss distance in price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit distance in price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Trailing stop distance in price units.
	/// </summary>
	public decimal TrailingStop
	{
		get => _trailingStop.Value;
		set => _trailingStop.Value = value;
	}

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="CciAutomatedStrategy" /> class.
	/// </summary>
	public CciAutomatedStrategy()
	{
		_cciPeriod = Param(nameof(CciPeriod), 9)
			.SetRange(5, 50)
			.SetDisplay("CCI Period", "CCI indicator length", "Indicators")
			;

		_tradesDuplicator = Param(nameof(TradesDuplicator), 3)
			.SetRange(1, 10)
			.SetDisplay("Trades Duplicator", "Maximum number of concurrent trades", "General")
			;


		_stopLoss = Param(nameof(StopLoss), 50m)
			.SetRange(10m, 200m)
			.SetDisplay("Stop Loss", "Stop loss in price units", "Risk")
			;

		_takeProfit = Param(nameof(TakeProfit), 200m)
			.SetRange(10m, 500m)
			.SetDisplay("Take Profit", "Take profit in price units", "Risk")
			;

		_trailingStop = Param(nameof(TrailingStop), 50m)
			.SetRange(10m, 200m)
			.SetDisplay("Trailing Stop", "Trailing stop in price units", "Risk")
			;

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCci = null;
		_trailPrice = null;
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var cci = new CommodityChannelIndex { Length = CciPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(cci, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, cci);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal cciValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var maxVolume = TradesDuplicator * Volume;

		if (_prevCci is decimal prev)
		{
			if (prev < -90m && cciValue > -80m && Position + Volume <= maxVolume)
			{
				BuyMarket();
				_trailPrice = candle.ClosePrice - TrailingStop;
			}
			else if (prev > 90m && cciValue < 80m && Position - Volume >= -maxVolume)
			{
				SellMarket();
				_trailPrice = candle.ClosePrice + TrailingStop;
			}
		}

		if (Position > 0)
		{
			var candidate = candle.ClosePrice - TrailingStop;
			if (_trailPrice is null || candidate > _trailPrice)
				_trailPrice = candidate;
			if (_trailPrice is decimal tp && candle.ClosePrice <= tp)
			{
				SellMarket();
				_trailPrice = null;
			}
		}
		else if (Position < 0)
		{
			var candidate = candle.ClosePrice + TrailingStop;
			if (_trailPrice is null || candidate < _trailPrice)
				_trailPrice = candidate;
			if (_trailPrice is decimal tp && candle.ClosePrice >= tp)
			{
				BuyMarket();
				_trailPrice = null;
			}
		}

		_prevCci = cciValue;
	}

	/// <inheritdoc />
	protected override void OnPositionReceived(Position position)
	{
		base.OnPositionReceived(position);

		if (Position == 0)
			_trailPrice = null;
	}
}