Cci Threshold 策略
基于 CCI 阈值的简单策略。当 CCI 低于阈值时买入,当收盘价高于上一根收盘价时平仓。 可选的止损和止盈(点数)。
详情
- 入场条件:
- 多头:
CCI < BuyThreshold
- 多头:
- 多/空: 仅多头
- 离场条件:
ClosePrice > 上一根收盘价
- 止损: 可通过
UseStopLoss和UseTakeProfit - 默认值:
LookbackPeriod= 12BuyThreshold= -90StopLossPoints= 100mTakeProfitPoints= 150mUseStopLoss= falseUseTakeProfit= falseCandleType= TimeSpan.FromMinutes(15).TimeFrame()
- 筛选:
- 类别: 均值回归
- 方向: 多头
- 指标: 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()