GitHub で見る
KWAN CCC戦略
概要
KWAN CCC戦略は、StockSharpの高レベルAPIを使用してMetaTraderエキスパートExp_KWAN_CCC.mq5を再現します。このシステムは、以下のように構築されたカスタムオシレーターからトレーディングシグナルを導出します:
- Chaikinオシレーターを計算します(累積/分配ラインの高速と低速移動平均の差)。
- ChaikinのValueをCommodity Channel Index(CCI)で乗算します。
- 結果をMomentumインジケーターの値で除算します。Momentumがゼロの場合、スクリプトはゼロ除算を避けるために定数値100を代入します — オリジナルコードと全く同じです。
- 結果の系列をユーザーが選択したXMAメソッドで平滑化します。
- 平滑化された系列の傾きを検出します。上昇バーは
0、下降バーは2、それ以外は1で色付けされます。
色が0から他の値に変わると、戦略はショートを閉じてロングポジションを開きます。色が2から他の値に変わると、ロングを閉じてショートを開きます。これはオプションのシグナルシフト(SignalBar)を含むMQLエキスパートに実装されたロジックを反映しています。
トレーディングルール
- ロングエントリー:
SignalBar + 1のバーの色が0に等しく、SignalBarのバーが0と異なる。
- ショートエントリー:
SignalBar + 1のバーの色が2に等しく、SignalBarのバーが2と異なる。
- ロングエグジット:
EnableLongExits = trueでショートエントリー条件がトリガーされた場合に有効。
- ショートエグジット:
EnableShortExits = trueでロングエントリー条件がトリガーされた場合に有効。
- 保護ストップとターゲット注文は、
StopLossPointsとTakeProfitPointsに楽器のPriceStepを掛けた絶対的な価格オフセットを使用してStartProtectionを通じて作成されます。
パラメーター
| パラメーター |
説明 |
OrderVolume |
新しいポジションを開く際に使用する基本注文サイズ。 |
CandleType |
すべてのインジケーター計算の時間軸。デフォルトは1時間。 |
FastPeriod / SlowPeriod |
Chaikinオシレーター内の移動平均の長さ。 |
ChaikinMethod |
累積/分配ラインに適用する移動平均タイプ(単純、指数、平滑、加重)。 |
CciPeriod |
Commodity Channel Indexのピリオド。 |
MomentumPeriod |
Momentumインジケーターのピリオド。 |
SmoothingMethod |
オリジナルオプションからマッピングされたXMA平滑化メソッド。JurX、Parabolic、T3はJurik MAにフォールバック;VidyaはChande Momentumオシレーター駆動の適応型平滑化を使用;AdaptiveはKaufman AMAを使用。 |
SmoothingLength |
選択した平滑化フィルターで使用するバーの数。 |
SmoothingPhase |
特定のメソッドで使用される追加パラメーター(例:VIDYA CMO長、AMAスロー期間)。 |
SignalBar |
色の遷移を評価するために使用するオフセット(完了したバーで)。1はMetaTraderのデフォルトを再現。 |
EnableLongEntries / EnableShortEntries |
対応する方向への新しいポジションの開設を許可または禁止。 |
EnableLongExits / EnableShortExits |
インジケーター駆動のポジション決済を許可または禁止。 |
StopLossPoints / TakeProfitPoints |
価格ステップで測定した保護ストップ/ターゲット(無効化するにはゼロに設定)。 |
実装ノート
- 戦略は完成したローソク足にのみ作用し、StockSharpの
Bindヘルパーを使用してローソク足データをインジケーターにストリームします。
- 平滑化メソッドリストはオリジナルライブラリのXMA実装を反映しています。StockSharpで利用できないメソッドは最も近い代替にマッピングされ、パラメーターテーブルに記載されています。
- MetaTraderの
VolumeType入力は省略されています。StockSharpのローソク足は既に累積/分配ラインで使用される総ボリューム情報をカプセル化しているためです。
- オリジナルエキスパートのマネー管理はカスタムロットサイジングヘルパーに依存していました。変換では
OrderVolumeで指定された固定ボリュームを前提としています。
使用上のヒント
- Chaikinオシレーターの動作が重要な場合は、インストゥルメントが意味のあるボリュームデータを提供していることを確認してください。流動性の低いインストゥルメントの場合は、ノイズを減らすために
MomentumPeriodを増やすことを検討してください。
- 平滑化パラメーターを最適化する際は、
SmoothingLengthとSmoothingPhaseを慎重に組み合わせてください:極端な組み合わせはシグナルをかなり遅延させる可能性があります。
- デフォルトの保護値(
StopLossPoints = 1000、TakeProfitPoints = 2000)は大きなオフセットに対応しています。インストゥルメントのティックサイズに合わせて調整してください。
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Strategy converted from the KWAN_CCC expert advisor.
/// Uses CCI and Momentum to detect trend transitions.
/// Enters long when CCI turns up while momentum is positive,
/// enters short when CCI turns down while momentum is negative.
/// </summary>
public class KwanCccStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal _prevCci;
private decimal _prevClose;
private bool _initialized;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
public KwanCccStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI length", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = 0m;
_prevClose = 0m;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = 0m;
_prevClose = 0m;
_initialized = false;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, (ICandleMessage candle, decimal cciValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!_initialized)
{
_prevCci = cciValue;
_prevClose = candle.ClosePrice;
_initialized = true;
return;
}
var closeUp = candle.ClosePrice > _prevClose;
var closeDown = candle.ClosePrice < _prevClose;
// Buy when CCI crosses into positive territory and price confirms the move.
if (_prevCci <= 0m && cciValue > 0m && closeUp && Position <= 0)
{
BuyMarket();
}
// Sell when CCI crosses into negative territory and price confirms the move.
else if (_prevCci >= 0m && cciValue < 0m && closeDown && Position >= 0)
{
SellMarket();
}
_prevCci = cciValue;
_prevClose = candle.ClosePrice;
})
.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 kwan_ccc_strategy(Strategy):
def __init__(self):
super(kwan_ccc_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "CCI length", "Indicators")
self._prev_cci = 0.0
self._prev_close = 0.0
self._initialized = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def CciPeriod(self):
return self._cci_period.Value
def OnReseted(self):
super(kwan_ccc_strategy, self).OnReseted()
self._prev_cci = 0.0
self._prev_close = 0.0
self._initialized = False
def OnStarted2(self, time):
super(kwan_ccc_strategy, self).OnStarted2(time)
self._prev_cci = 0.0
self._prev_close = 0.0
self._initialized = False
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(cci, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, cci)
self.DrawOwnTrades(area)
def _on_process(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
cv = float(cci_value)
close = float(candle.ClosePrice)
if not self._initialized:
self._prev_cci = cv
self._prev_close = close
self._initialized = True
return
close_up = close > self._prev_close
close_down = close < self._prev_close
if self._prev_cci <= 0 and cv > 0 and close_up and self.Position <= 0:
self.BuyMarket()
elif self._prev_cci >= 0 and cv < 0 and close_down and self.Position >= 0:
self.SellMarket()
self._prev_cci = cv
self._prev_close = close
def CreateClone(self):
return kwan_ccc_strategy()