CCI Automated
CCI Automated — стратегия разворота, использующая пересечения уровней индикатора Commodity Channel Index (CCI). Покупка открывается, когда CCI поднимается выше −80 после значения ниже −90; продажа — когда CCI опускается ниже 80 после значения выше 90. Система допускает несколько одновременно открытых позиций, управляет рисками фиксированными стоп-лоссом и тейк-профитом и сопровождает прибыль трейлинг-стопом.
Метод стремится поймать ранние развороты после зон перепроданности или перекупленности. Путём накопления позиций и подтягивания стопа по мере движения цены стратегия старается извлечь выгоду из устойчивых разворотных импульсов, ограничивая при этом убытки.
Детали
- Критерии входа: CCI пересекает -80 снизу после значения ниже -90 для покупок; пересекает 80 сверху после значения выше 90 для продаж.
- Длинные/Короткие: Оба направления.
- Критерии выхода: Стоп-лосс, тейк-профит или трейлинг-стоп.
- Стопы: Да.
- Значения по умолчанию:
CciPeriod= 9TradesDuplicator= 3Volume= 0.03StopLoss= 50TakeProfit= 200TrailingStop= 50CandleType= TimeSpan.FromMinutes(5)
- Фильтры:
- Категория: Mean Reversion
- Направление: Оба
- Индикаторы: CCI
- Стопы: Да
- Сложность: Базовая
- Таймфрейм: Внутридневной (5m)
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class cci_automated_strategy(Strategy):
def __init__(self):
super(cci_automated_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 9) \
.SetDisplay("CCI Period", "CCI indicator length", "Indicators")
self._trades_duplicator = self.Param("TradesDuplicator", 3) \
.SetDisplay("Trades Duplicator", "Maximum number of concurrent trades", "General")
self._stop_loss = self.Param("StopLoss", 50.0) \
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk")
self._take_profit = self.Param("TakeProfit", 200.0) \
.SetDisplay("Take Profit", "Take profit in price units", "Risk")
self._trailing_stop = self.Param("TrailingStop", 50.0) \
.SetDisplay("Trailing Stop", "Trailing stop in price units", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_cci = None
self._trail_price = None
@property
def cci_period(self):
return self._cci_period.Value
@property
def trades_duplicator(self):
return self._trades_duplicator.Value
@property
def stop_loss(self):
return self._stop_loss.Value
@property
def take_profit(self):
return self._take_profit.Value
@property
def trailing_stop(self):
return self._trailing_stop.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(cci_automated_strategy, self).OnReseted()
self._prev_cci = None
self._trail_price = None
def OnStarted2(self, time):
super(cci_automated_strategy, self).OnStarted2(time)
cci = CommodityChannelIndex()
cci.Length = self.cci_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, cci)
self.DrawOwnTrades(area)
def process_candle(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
cci_value = float(cci_value)
close = float(candle.ClosePrice)
trail = float(self.trailing_stop)
max_vol = self.trades_duplicator * self.Volume
if self._prev_cci is not None:
if self._prev_cci < -90.0 and cci_value > -80.0 and self.Position + self.Volume <= max_vol:
self.BuyMarket()
self._trail_price = close - trail
elif self._prev_cci > 90.0 and cci_value < 80.0 and self.Position - self.Volume >= -max_vol:
self.SellMarket()
self._trail_price = close + trail
if self.Position > 0:
candidate = close - trail
if self._trail_price is None or candidate > self._trail_price:
self._trail_price = candidate
if self._trail_price is not None and close <= self._trail_price:
self.SellMarket()
self._trail_price = None
elif self.Position < 0:
candidate = close + trail
if self._trail_price is None or candidate < self._trail_price:
self._trail_price = candidate
if self._trail_price is not None and close >= self._trail_price:
self.BuyMarket()
self._trail_price = None
self._prev_cci = cci_value
def CreateClone(self):
return cci_automated_strategy()