GitHub で見る
明けの明星/宵の明星 CCI 戦略
概要
この戦略は、StockSharp の高レベル API を使用して、MetaTrader 5 Expert Advisor Expert_AMS_ES_CCI を複製します。モーニングスターとイブニングスターの3本のローソク足反転パターンをスキャンし、新しいポジションを開く前に商品チャネル指数(CCI)からの確認を必要とします。このロジックは完成したキャンドルでのみ機能し、戦略設定で指定されたプライマリ証券で動作します。
取引ロジック
- モーニングスターのロングエントリー
- 明けの明星パターンを形成する 3 つの連続するローソク足を検出します。
- ローソク足 1: 強い弱気の実体 (選択したウィンドウの平均実体よりも実体サイズが大きい)。
- キャンドル 2: キャンドル 1 よりもギャップが低い小型のキャンドル。
- ローソク足 3: ローソク足 1 の中点より上で終了します。
- シグナルバーの CCI 値が負のエントリーしきい値 (デフォルトは -50) 未満であることを確認します。
- イブニングスターショートエントリー
- 有効な宵の明星のパターンを検出します。
- キャンドル 1: 強い強気のボディ。
- キャンドル 2: キャンドル 1 の上にある小さな本体のキャンドル。
- ローソク足 3: ローソク足 1 の中点より下で終了します。
- シグナルバーの CCI の値がポジティブエントリーしきい値 (デフォルトは +50) より大きいことを確認します。
- ポジションのエグジットルール
- CCI が -NeutralThreshold を上回って戻るか、+NeutralThreshold (デフォルト ±80) を下回った場合、ショート ポジションを閉じます。
- CCI が +NeutralThreshold を下回るか、-NeutralThreshold を下回った場合、ロング ポジションを閉じます。
- 追加のストップロスやテイクプロフィットルールは組み込まれていません。ユーザーは必要に応じて外部保護を追加できます。
インジケーター
- 商品チャネル インデックス (CCI) – 確認フィルター、デフォルト期間 25。
- ローソク本体の単純移動平均 – パターンの強さを検証するために、最後の BodyAveragePeriod ローソク足 (デフォルトは 5) にわたる平均実体サイズを計算します。
パラメーター
| 名前 |
説明 |
デフォルト |
注意事項 |
CciPeriod |
CCI の計算に使用されるバーの数。 |
25 |
最適化可能。 |
BodyAveragePeriod |
平均的な体のサイズを測定するために使用されるキャンドルの数。 |
5 |
最適化可能。 |
EntryThreshold |
新しい取引には絶対 CCI 値が必要です。 |
50 |
正の値。戦略は ±EntryThreshold をチェックします。 |
NeutralThreshold |
出口ゾーンを定義する絶対 CCI レベル。 |
80 |
正の値。戦略は ±NeutralThreshold をチェックします。 |
CandleType |
分析に使用されるローソク足のタイプ (タイムフレーム)。 |
1時間枠 |
希望の解像度に合わせて変更します。 |
注意事項
- この戦略は、
SubscribeCandles 経由でローソク足の更新をサブスクライブし、Bind を使用してインジケーター値を受け取ります。
- 取引は、
BuyMarket と SellMarket を使用して成行注文で実行されます。
- コード内のすべてのコメントは、必要に応じて英語で記述されます。
- リスク管理を拡張するには、戦略を
StartProtection またはカスタムの資金管理モジュールと組み合わせます。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Morning/Evening Star + CCI strategy.
/// Buys on morning star with negative CCI, sells on evening star with positive CCI.
/// </summary>
public class MorningEveningStarCciStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _cciLevel;
private ICandleMessage _prevCandle;
private ICandleMessage _prevPrevCandle;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public decimal CciLevel { get => _cciLevel.Value; set => _cciLevel.Value = value; }
public MorningEveningStarCciStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
_cciLevel = Param(nameof(CciLevel), 0m)
.SetDisplay("CCI Level", "CCI threshold for confirmation", "Signals");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_prevPrevCandle = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_prevPrevCandle = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevCandle != null && _prevPrevCandle != null)
{
var prevBody = Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice);
var prevRange = _prevCandle.HighPrice - _prevCandle.LowPrice;
var isSmallBody = prevRange > 0 && prevBody < prevRange * 0.3m;
var firstBearish = _prevPrevCandle.OpenPrice > _prevPrevCandle.ClosePrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var isMorningStar = firstBearish && isSmallBody && currBullish &&
candle.ClosePrice > _prevPrevCandle.OpenPrice * 0.5m + _prevPrevCandle.ClosePrice * 0.5m;
var firstBullish = _prevPrevCandle.ClosePrice > _prevPrevCandle.OpenPrice;
var currBearish = candle.OpenPrice > candle.ClosePrice;
var isEveningStar = firstBullish && isSmallBody && currBearish &&
candle.ClosePrice < _prevPrevCandle.OpenPrice * 0.5m + _prevPrevCandle.ClosePrice * 0.5m;
if (isMorningStar && cciValue < -CciLevel && Position <= 0)
BuyMarket();
else if (isEveningStar && cciValue > CciLevel && Position >= 0)
SellMarket();
}
_prevPrevCandle = _prevCandle;
_prevCandle = candle;
}
}
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 morning_evening_star_cci_strategy(Strategy):
"""
Morning/Evening Star + CCI: buy on morning star with negative CCI, sell on evening star with positive CCI.
"""
def __init__(self):
super(morning_evening_star_cci_strategy, self).__init__()
self._cci_period = self.Param("CciPeriod", 14).SetDisplay("CCI Period", "CCI period", "Indicators")
self._cci_level = self.Param("CciLevel", 0.0).SetDisplay("CCI Level", "CCI threshold", "Signals")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_candle = None
self._prev_prev_candle = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(morning_evening_star_cci_strategy, self).OnReseted()
self._prev_candle = None
self._prev_prev_candle = None
def OnStarted2(self, time):
super(morning_evening_star_cci_strategy, self).OnStarted2(time)
cci = CommodityChannelIndex()
cci.Length = self._cci_period.Value
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_val):
if candle.State != CandleStates.Finished:
return
cci = float(cci_val)
cci_level = float(self._cci_level.Value)
if self._prev_candle is not None and self._prev_prev_candle is not None:
prev_body = abs(float(self._prev_candle.ClosePrice) - float(self._prev_candle.OpenPrice))
prev_range = float(self._prev_candle.HighPrice) - float(self._prev_candle.LowPrice)
is_small_body = prev_range > 0 and prev_body < prev_range * 0.3
pp_open = float(self._prev_prev_candle.OpenPrice)
pp_close = float(self._prev_prev_candle.ClosePrice)
c_open = float(candle.OpenPrice)
c_close = float(candle.ClosePrice)
first_bearish = pp_open > pp_close
curr_bullish = c_close > c_open
is_morning = first_bearish and is_small_body and curr_bullish and c_close > pp_open * 0.5 + pp_close * 0.5
first_bullish = pp_close > pp_open
curr_bearish = c_open > c_close
is_evening = first_bullish and is_small_body and curr_bearish and c_close < pp_open * 0.5 + pp_close * 0.5
if is_morning and cci < -cci_level and self.Position <= 0:
self.BuyMarket()
elif is_evening and cci > cci_level and self.Position >= 0:
self.SellMarket()
self._prev_prev_candle = self._prev_candle
self._prev_candle = candle
def CreateClone(self):
return morning_evening_star_cci_strategy()