Стратегия CCI Histogram
Эта стратегия использует индикатор Commodity Channel Index (CCI) для поиска разворотов при выходе из экстремальных зон. Длинная позиция открывается, когда CCI после нахождения выше верхнего уровня возвращается ниже него. Короткая позиция открывается, когда CCI, находясь ниже нижнего уровня, поднимается выше него. Открытые позиции могут защищаться фиксированным стоп-лоссом и тейк-профитом в пунктах.
Детали
- Критерии входа:
- Лонг: Предыдущий CCI >
UpperLevelи текущий CCI ≤UpperLevel. - Шорт: Предыдущий CCI <
LowerLevelи текущий CCI ≥LowerLevel.
- Лонг: Предыдущий CCI >
- Лонг/Шорт: Оба направления.
- Критерии выхода: Противоположный сигнал закрывает текущую позицию и открывает новую.
- Стопы: Опциональный фиксированный стоп-лосс и тейк-профит в пунктах.
- Значения по умолчанию:
CCI Period= 14Upper Level= 100Lower Level= -100Stop Loss= 100 пунктовTake Profit= 200 пунктов
- Фильтры:
- Категория: Развороты
- Направление: Оба
- Индикаторы: CCI
- Стопы: Опционально
- Сложность: Простая
- Таймфрейм: Любой (по умолчанию 4H)
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// CCI Histogram reversal strategy.
/// Buys when CCI leaves the upper extreme and sells when it leaves the lower extreme.
/// Optional stop loss and take profit protection in points.
/// </summary>
public class CciHistogramStrategy : Strategy
{
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _upperLevel;
private readonly StrategyParam<decimal> _lowerLevel;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<bool> _useStopLoss;
private readonly StrategyParam<bool> _useTakeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevCci;
/// <summary>
/// CCI period length.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// Upper CCI level that defines overbought zone.
/// </summary>
public decimal UpperLevel
{
get => _upperLevel.Value;
set => _upperLevel.Value = value;
}
/// <summary>
/// Lower CCI level that defines oversold zone.
/// </summary>
public decimal LowerLevel
{
get => _lowerLevel.Value;
set => _lowerLevel.Value = value;
}
/// <summary>
/// Stop loss in absolute points.
/// </summary>
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take profit in absolute points.
/// </summary>
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Use stop loss protection.
/// </summary>
public bool UseStopLoss
{
get => _useStopLoss.Value;
set => _useStopLoss.Value = value;
}
/// <summary>
/// Use take profit protection.
/// </summary>
public bool UseTakeProfit
{
get => _useTakeProfit.Value;
set => _useTakeProfit.Value = value;
}
/// <summary>
/// Candle type to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="CciHistogramStrategy"/> class.
/// </summary>
public CciHistogramStrategy()
{
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Period length for the CCI indicator", "General")
.SetOptimize(7, 28, 7);
_upperLevel = Param(nameof(UpperLevel), 100m)
.SetDisplay("Upper Level", "Upper CCI level", "General")
.SetOptimize(80m, 120m, 10m);
_lowerLevel = Param(nameof(LowerLevel), -100m)
.SetDisplay("Lower Level", "Lower CCI level", "General")
.SetOptimize(-120m, -80m, 10m);
_stopLossPoints = Param(nameof(StopLossPoints), 100m)
.SetDisplay("Stop Loss", "Stop loss in points", "Risk Management")
.SetOptimize(50m, 200m, 25m);
_takeProfitPoints = Param(nameof(TakeProfitPoints), 200m)
.SetDisplay("Take Profit", "Take profit in points", "Risk Management")
.SetOptimize(50m, 300m, 25m);
_useStopLoss = Param(nameof(UseStopLoss), false)
.SetDisplay("Enable Stop Loss", "Use stop loss protection", "Risk Management");
_useTakeProfit = Param(nameof(UseTakeProfit), false)
.SetDisplay("Enable Take Profit", "Use take profit protection", "Risk Management");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
var isInitialized = false;
subscription
.Bind(cci,
(candle, cciValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevCci = cciValue;
isInitialized = true;
return;
}
if (!isInitialized)
{
_prevCci = cciValue;
isInitialized = true;
return;
}
if (_prevCci > UpperLevel && cciValue <= UpperLevel && Position <= 0)
{
BuyMarket();
}
else if (_prevCci < LowerLevel && cciValue >= LowerLevel && Position >= 0)
{
SellMarket();
}
_prevCci = cciValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, cci);
DrawOwnTrades(area);
}
}
}
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_histogram_strategy(Strategy):
def __init__(self):
super(cci_histogram_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "Period length for the CCI indicator", "General")
self._upper_level = self.Param("UpperLevel", 100.0) \
.SetDisplay("Upper Level", "Upper CCI level", "General")
self._lower_level = self.Param("LowerLevel", -100.0) \
.SetDisplay("Lower Level", "Lower CCI level", "General")
self._stop_loss_points = self.Param("StopLossPoints", 100.0) \
.SetDisplay("Stop Loss", "Stop loss in points", "Risk Management")
self._take_profit_points = self.Param("TakeProfitPoints", 200.0) \
.SetDisplay("Take Profit", "Take profit in points", "Risk Management")
self._use_stop_loss = self.Param("UseStopLoss", False) \
.SetDisplay("Enable Stop Loss", "Use stop loss protection", "Risk Management")
self._use_take_profit = self.Param("UseTakeProfit", False) \
.SetDisplay("Enable Take Profit", "Use take profit protection", "Risk Management")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_cci = 0.0
self._initialized = False
@property
def cci_period(self):
return self._cci_period.Value
@property
def upper_level(self):
return self._upper_level.Value
@property
def lower_level(self):
return self._lower_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(cci_histogram_strategy, self).OnReseted()
self._prev_cci = 0.0
self._initialized = False
def OnStarted2(self, time):
super(cci_histogram_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_val):
if candle.State != CandleStates.Finished:
return
cci_val = float(cci_val)
if not self._initialized:
self._prev_cci = cci_val
self._initialized = True
return
upper = float(self.upper_level)
lower = float(self.lower_level)
if self._prev_cci > upper and cci_val <= upper and self.Position <= 0:
self.BuyMarket()
elif self._prev_cci < lower and cci_val >= lower and self.Position >= 0:
self.SellMarket()
self._prev_cci = cci_val
def CreateClone(self):
return cci_histogram_strategy()