Стратегия Cci Threshold
Простая стратегия на основе индикатора CCI. Покупает, когда CCI опускается ниже порога, и закрывает позицию, когда цена закрытия превышает предыдущую. Опциональные стоп-лосс и тейк-профит в пунктах.
Детали
- Условия входа:
- Long:
CCI < BuyThreshold
- Long:
- Длинные/Короткие: Только long
- Условия выхода:
ClosePrice > предыдущего ClosePrice
- Стопы: По желанию через
UseStopLossиUseTakeProfit - Значения по умолчанию:
LookbackPeriod= 12BuyThreshold= -90StopLossPoints= 100mTakeProfitPoints= 150mUseStopLoss= falseUseTakeProfit= falseCandleType= TimeSpan.FromMinutes(15).TimeFrame()
- Фильтры:
- Категория: Mean reversion
- Направление: Long
- Индикаторы: CCI
- Стопы: Опционально
- Сложность: Низкая
- Таймфрейм: Краткосрочный
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// CCI Threshold strategy.
/// Long only: buys when CCI(LookbackPeriod) is below BuyThreshold and closes the long when the close is above the previous close.
/// Optional stop loss and take profit are StopLossPoints and TakeProfitPoints price steps from the entry.
/// </summary>
public class CciThresholdStrategy : Strategy
{
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<decimal> _buyThreshold;
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? _prevClose;
/// <summary>
/// CCI period.
/// </summary>
public int LookbackPeriod
{
get => _lookbackPeriod.Value;
set => _lookbackPeriod.Value = value;
}
/// <summary>
/// CCI level below which the strategy buys.
/// </summary>
public decimal BuyThreshold
{
get => _buyThreshold.Value;
set => _buyThreshold.Value = value;
}
/// <summary>
/// Stop loss distance in price steps.
/// </summary>
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take profit distance in price steps.
/// </summary>
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Enable the stop loss.
/// </summary>
public bool UseStopLoss
{
get => _useStopLoss.Value;
set => _useStopLoss.Value = value;
}
/// <summary>
/// Enable the take profit.
/// </summary>
public bool UseTakeProfit
{
get => _useTakeProfit.Value;
set => _useTakeProfit.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public CciThresholdStrategy()
{
_lookbackPeriod = Param(nameof(LookbackPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("Lookback Period", "CCI period", "CCI");
_buyThreshold = Param(nameof(BuyThreshold), -90m)
.SetDisplay("Buy Threshold", "CCI level below which the strategy buys", "CCI");
_stopLossPoints = Param(nameof(StopLossPoints), 100m)
.SetNotNegative()
.SetDisplay("Stop Loss Points", "Stop loss distance in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 150m)
.SetNotNegative()
.SetDisplay("Take Profit Points", "Take profit distance in price steps", "Risk");
_useStopLoss = Param(nameof(UseStopLoss), false)
.SetDisplay("Use Stop Loss", "Enable the stop loss", "Risk");
_useTakeProfit = Param(nameof(UseTakeProfit), false)
.SetDisplay("Use Take Profit", "Enable the take profit", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
var cci = new CommodityChannelIndex { Length = LookbackPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(cci, ProcessCandle)
.Start();
var step = Security?.PriceStep ?? 1m;
var takeProfit = UseTakeProfit && TakeProfitPoints > 0 ? new Unit(TakeProfitPoints * step, UnitTypes.Absolute) : new Unit();
var stopLoss = UseStopLoss && StopLossPoints > 0 ? new Unit(StopLossPoints * step, UnitTypes.Absolute) : new Unit();
StartProtection(takeProfit, stopLoss, useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, cci);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue cciValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var prevClose = _prevClose;
_prevClose = close;
if (!cciValue.IsFormed || prevClose is not decimal pc)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
if (close > pc)
SellMarket(Position);
}
else if (Position == 0 && cciValue.GetValue<decimal>() < BuyThreshold)
{
BuyMarket(Volume);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class cci_threshold_strategy(Strategy):
"""
CCI Threshold strategy.
Long only: buys when CCI(LookbackPeriod) is below BuyThreshold and closes the long when the close is above the previous close.
Optional stop loss and take profit are StopLossPoints and TakeProfitPoints price steps from the entry.
"""
def __init__(self):
super(cci_threshold_strategy, self).__init__()
self._lookback_period = self.Param("LookbackPeriod", 12).SetGreaterThanZero().SetDisplay("Lookback Period", "CCI period", "CCI")
self._buy_threshold = self.Param("BuyThreshold", -90.0).SetDisplay("Buy Threshold", "CCI level below which the strategy buys", "CCI")
self._stop_loss_points = self.Param("StopLossPoints", 100.0).SetNotNegative().SetDisplay("Stop Loss Points", "Stop loss distance in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 150.0).SetNotNegative().SetDisplay("Take Profit Points", "Take profit distance in price steps", "Risk")
self._use_stop_loss = self.Param("UseStopLoss", False).SetDisplay("Use Stop Loss", "Enable the stop loss", "Risk")
self._use_take_profit = self.Param("UseTakeProfit", False).SetDisplay("Use Take Profit", "Enable the take profit", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_close = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(cci_threshold_strategy, self).OnReseted()
self._prev_close = None
def OnStarted2(self, time):
super(cci_threshold_strategy, self).OnStarted2(time)
self._prev_close = None
cci = CommodityChannelIndex()
cci.Length = self._lookback_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(cci, self._process_candle).Start()
step = self.Security.PriceStep if self.Security is not None and self.Security.PriceStep is not None else Decimal(1)
take_points = Decimal(self._take_profit_points.Value)
stop_points = Decimal(self._stop_loss_points.Value)
take_profit = Unit(take_points * step, UnitTypes.Absolute) if self._use_take_profit.Value and take_points > 0 else Unit()
stop_loss = Unit(stop_points * step, UnitTypes.Absolute) if self._use_stop_loss.Value and stop_points > 0 else Unit()
self.StartProtection(take_profit, stop_loss, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, cci)
def _process_candle(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
pc = self._prev_close
self._prev_close = close
if not cci_value.IsFormed or pc is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
if close > pc:
self.SellMarket(self.Position)
elif self.Position == 0 and cci_value.GetValue[Decimal](None) < Decimal(self._buy_threshold.Value):
self.BuyMarket(self.Volume)
def CreateClone(self):
return cci_threshold_strategy()