Adx Cci 戦略
ADX と CCI インジケーターに基づく戦略。ADX > 25 かつ CCI が売られすぎ(< -100)の場合にロング参入。ADX > 25 かつ CCI が買われすぎ(> 100)の場合にショート参入。
テストでは年平均収益率は約 97% を示しています。暗号資産市場で最もパフォーマンスが優れています。
ADX はトレンドに強さがあるかどうかを評価し、CCI は押し目後のエントリータイミングを特定します。ロングとショートは ADX の方向に従います。
押し目でエントリーするモメンタムトレーダー向けです。パーセントストップがリスクを管理します。
詳細
- エントリー条件:
- ロング:
ADX > 25 && CCI < -100 - ショート:
ADX > 25 && CCI > 100
- ロング:
- ロング/ショート: 両方
- エグジット条件: トレンドが弱まるか、CCI がゼロをクロス
- ストップ:
StopLossPercentを使用したパーセントベース - デフォルト値:
AdxPeriod= 14AdxThreshold= 25CciPeriod= 20CciOversold= -100CciOverbought= 100StopLossPercent= 2CandleType= TimeSpan.FromMinutes(5).TimeFrame() ルール中の25、-100、100はAdxThreshold、CciOversold、CciOverboughtの既定値です。ADXがAdxThresholdを下回るとトレンドが弱まったとみなします。さらにロングはCCIがゼロまで上昇したとき、ショートはゼロまで下落したときにも決済します。 保有ポジションと逆方向のエントリーシグナルはドテンになります。
- フィルター:
- カテゴリ: 平均回帰
- 方向: 両方
- インジケーター: ADX, 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>
/// ADX CCI strategy.
/// While ADX is above AdxThreshold, CCI below CciOversold goes long and CCI above CciOverbought goes short, reversing an opposite position.
/// The position closes when the trend weakens, ADX falling below AdxThreshold, or when CCI crosses the zero line, and a percent stop
/// limits the loss.
/// </summary>
public class AdxCciStrategy : Strategy
{
private readonly StrategyParam<int> _adxPeriod;
private readonly StrategyParam<decimal> _adxThreshold;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _cciOversold;
private readonly StrategyParam<decimal> _cciOverbought;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Period of ADX.
/// </summary>
public int AdxPeriod
{
get => _adxPeriod.Value;
set => _adxPeriod.Value = value;
}
/// <summary>
/// ADX level of a strong trend.
/// </summary>
public decimal AdxThreshold
{
get => _adxThreshold.Value;
set => _adxThreshold.Value = value;
}
/// <summary>
/// Period of CCI.
/// </summary>
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
/// <summary>
/// CCI level for longs.
/// </summary>
public decimal CciOversold
{
get => _cciOversold.Value;
set => _cciOversold.Value = value;
}
/// <summary>
/// CCI level for shorts.
/// </summary>
public decimal CciOverbought
{
get => _cciOverbought.Value;
set => _cciOverbought.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AdxCciStrategy()
{
_adxPeriod = Param(nameof(AdxPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ADX Period", "Period of ADX", "Indicators");
_adxThreshold = Param(nameof(AdxThreshold), 25m)
.SetDisplay("ADX Threshold", "ADX level of a strong trend", "Indicators");
_cciPeriod = Param(nameof(CciPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Period of CCI", "Indicators");
_cciOversold = Param(nameof(CciOversold), -100m)
.SetDisplay("CCI Oversold", "CCI level for longs", "Indicators");
_cciOverbought = Param(nameof(CciOverbought), 100m)
.SetDisplay("CCI Overbought", "CCI level for shorts", "Indicators");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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 OnStarted2(DateTime time)
{
base.OnStarted2(time);
var adx = new AverageDirectionalIndex { Length = AdxPeriod };
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(adx, cci, ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, adx);
DrawIndicator(oscillators, cci);
}
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue adxValue, IIndicatorValue cciValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!adxValue.IsFormed || !cciValue.IsFormed)
return;
if (adxValue is not AverageDirectionalIndexValue { MovingAverage: decimal strength })
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var cci = cciValue.GetValue<decimal>();
var strong = strength > AdxThreshold;
var weak = strength < AdxThreshold;
if (strong && cci < CciOversold && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (strong && cci > CciOverbought && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && (weak || cci >= 0))
SellMarket(Position);
else if (Position < 0 && (weak || cci <= 0))
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import AverageDirectionalIndex, CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class adx_cci_strategy(Strategy):
"""
ADX CCI strategy.
While ADX is above AdxThreshold, CCI below CciOversold goes long and CCI above CciOverbought goes short, reversing an opposite position.
The position closes when the trend weakens, ADX falling below AdxThreshold, or when CCI crosses the zero line, and a percent stop
limits the loss.
"""
def __init__(self):
super(adx_cci_strategy, self).__init__()
self._adx_period = self.Param("AdxPeriod", 14).SetGreaterThanZero().SetDisplay("ADX Period", "Period of ADX", "Indicators")
self._adx_threshold = self.Param("AdxThreshold", 25.0).SetDisplay("ADX Threshold", "ADX level of a strong trend", "Indicators")
self._cci_period = self.Param("CciPeriod", 20).SetGreaterThanZero().SetDisplay("CCI Period", "Period of CCI", "Indicators")
self._cci_oversold = self.Param("CciOversold", -100.0).SetDisplay("CCI Oversold", "CCI level for longs", "Indicators")
self._cci_overbought = self.Param("CciOverbought", 100.0).SetDisplay("CCI Overbought", "CCI level for shorts", "Indicators")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(adx_cci_strategy, self).OnStarted2(time)
adx = AverageDirectionalIndex()
adx.Length = self._adx_period.Value
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(adx, cci, self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
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, adx)
self.DrawIndicator(oscillators, cci)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle, adx_value, cci_value):
if candle.State != CandleStates.Finished:
return
if not adx_value.IsFormed or not cci_value.IsFormed or adx_value.MovingAverage is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
strength = adx_value.MovingAverage
threshold = Decimal(self._adx_threshold.Value)
cci = cci_value.GetValue[Decimal](None)
strong = strength > threshold
weak = strength < threshold
zero = Decimal(0)
if strong and cci < Decimal(self._cci_oversold.Value) and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif strong and cci > Decimal(self._cci_overbought.Value) and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and (weak or cci >= zero):
self.SellMarket(self.Position)
elif self.Position < 0 and (weak or cci <= zero):
self.BuyMarket(-self.Position)
def CreateClone(self):
return adx_cci_strategy()