CCI Automated
CCI Automated 是一个基于商品通道指数(CCI)阈值交叉的反转策略。当 CCI 先跌破 -90 后再上穿 -80 时做多;当 CCI 先突破 90 后再下穿 80 时做空。策略允许同时打开多笔仓位,通过固定的止盈和止损控制风险,并使用可配置的追踪止损锁定利润。
该方法旨在捕捉超买或超卖后的早期动量变化。通过逐步加仓并在价格推进时移动止损,策略试图把握持续的反转走势,同时限制潜在回撤。
详情
- 入场条件:CCI 从低于 -90 上穿 -80 做多;从高于 90 下穿 80 做空。
- 多空方向:双向。
- 离场条件:止损、止盈或追踪止损。
- 止损:有。
- 默认值:
CciPeriod= 9TradesDuplicator= 3Volume= 0.03StopLoss= 50TakeProfit= 200TrailingStop= 50CandleType= TimeSpan.FromMinutes(5)
- 筛选:
- 类型:均值回归
- 方向:双向
- 指标:CCI
- 止损:是
- 复杂度:基础
- 时间框架:日内(5分钟)
- 季节性:无
- 神经网络:无
- 背离:无
- 风险水平:中等
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()