GitHub で見る
Ichimoku プライスアクション戦略
概要
Ichimoku プライスアクション戦略は、MQL4 エキスパート「Ichimoku プライスアクション戦略 v1.0」から StockSharp のハイレベル API に移植された、時間フィルターされた MACD モメンタム システムです。元の EA は、商品の取引が有効になるたびに成行注文を開始し、オプションの MACD フィルターは方向を確認しました。この C# ポートは同じ考え方を維持しながら、ストップロスの配置、損益分岐点の処理、トレーリング エグジットの詳細なリスク管理を提供します。
この戦略は、インジケーターへの依存を最小限に抑えて時間帯方向性プレイを自動化したい裁量トレーダー向けに設計されています。すべての取引シグナルは、ATR およびスイングベースの保護ストップの補助時間枠をサポートしながら、選択した取引時間枠の完了したローソク足で評価されます。
重要: StockSharp バージョンは、一度に最大 1 つのネット ポジションを維持します。 StockSharp Strategy はネット ポジションで動作するため、元のテンプレートからのヘッジ スタイルの同時ロング/ショート エクスポージャーはサポートされていません。他のすべての資金管理機能は、完成したキャンドルごとに実行されるストップ、ターゲット、およびトレーリング ロジックを通じて表現されます。
取引ロジック
- セッション フィルタ – 現在の時刻が
[StartTime; EndTime] ウィンドウ内にある場合にのみエントリが許可されます。両方のパラメータを 00:00 に設定すると、セッション フィルタが無効になります。
- MACD の確認 (オプション) –
UseMacdFilter = true の場合、ロングは信号線の上に MACD の主線を必要とし、ショートはその逆を必要とします。 MACD 設定は完全に構成可能です。
- 注文の発行 – 方向に対して取引が有効で、オープンなポジションがない場合、ストラテジーは構成された
Volume で成行注文を送信します。
- 保護ストップ –
StopLossModeに応じて、固定ピップ距離、ATRの倍数、またはより低い時間枠から収集された最新のスイングの極値を使用して最初のストップが配置されます。ストップはローソク足ごとに再計算され、新たに計算されたレベルがより保守的になると引き締められます。
- ターゲット – 固定ピップターゲットまたはアクティブストップに基づく動的なリスク/リワードターゲットがローソク足ごとにチェックされます。到達すると、ポジションは市場でクローズされます。
- 損益分岐点とトレーリング – 未実現利益が
MoveToBreakEven に達すると、ストップはエントリー価格に引き下げられます。 TrailingTrigger ピップの利益の後、トレーリングモジュールがアクティブになり、ローソク足の終値から TrailingStop ピップの距離を維持しながら、価格が TrailingStep ピップ改善するたびにストップを押し続けます。
- リバース イグジット –
CloseOnReverse = true の場合、反対のエントリー シグナルは、新しい方向に反転する可能性がある前に、直ちに現在のポジションを閉じます。
リスク管理
- ストップロス
- 固定pips –
StopLossPipsに商品の価格ステップを乗算した値を使用します。
- ATR 乗数 –
AtrCandleType の最新の ATR 値を AtrMultiplier で乗算した値を使用します。
- スイング高/低 –
SwingBars ルックバックを使用して SwingCandleType によって計算された最新のスイングの極値を使用します。
- 利益確定
- 固定pips –
TakeProfitPipsを使用します。
- リスク/報酬 – 現在の停止距離に
TakeProfitRatio を掛けた値を使用します。
- 損益分岐点 –
MoveToBreakEven は、ストップがエントリー価格でロックされるまでに必要な収益性の高いピップ数を定義します。
- トレーリング – 市場が有利に推移した後に利益を維持するために、
TrailingStop、TrailingTrigger、および TrailingStep によって制御されます。
パラメーター
| グループ |
名前 |
説明 |
| 一般 |
BuyMode |
長いエントリを許可します。 |
| 一般 |
SellMode |
短い入力を許可します。 |
| 一般 |
CandleType |
取引時間枠 (デフォルトは 1 時間)。 |
| スケジュール |
StartTime / EndTime |
交換時間のセッションウィンドウ (00:00 → 無効)。 |
| フィルター |
UseMacdFilter |
MACD の確認を有効にします。 |
| フィルター |
MacdFast, MacdSlow, MacdSignal |
MACD 周期は高速 EMA、低速 EMA、信号 EMA です。 |
| リスク |
StopLossMode |
ストップロスの計算: FixedPips、AtrMultiplier、SwingHighLow。 |
| リスク |
StopLossPips |
固定モードが選択されている場合の距離 (pips)。 |
| リスク |
AtrMultiplier, AtrPeriod, AtrCandleType |
ATR ベースの停止構成。 |
| リスク |
SwingBars, SwingCandleType |
スイングハイ/ローストップ構成。 |
| リスク |
TakeProfitMode |
ターゲット モード: FixedPips または RiskReward。 |
| リスク |
TakeProfitPips, TakeProfitRatio |
ターゲットの距離。 |
| リスク |
CloseOnReverse |
反対のシグナルが現れたら、アクティブなポジションを閉じます。 |
| 注文 |
Volume |
成行注文量 (ロット/契約)。 |
| リスク |
MoveToBreakEven |
ストップからエントリーに移動するための利益しきい値 (ピップ単位)。 |
| リスク |
TrailingStop, TrailingTrigger, TrailingStep |
トレーリングストップの設定(ピップ単位)。 |
使用上の注意
- 機器に
PriceStep が定義されていることを確認してください。それ以外の場合、ストラテジーはピップサイズを 0.0001 と想定します。
- ATR またはスイング ストップが有効になると、対応する補助サブスクリプションが自動的に追加されます。データ フィードがそれらの時間枠を提供していることを確認してください。
- 損益分岐点動作またはトレーリング動作を無効にする必要がある場合は、対応するパラメータを
0 に設定します。
- セッション開始時のデフォルトでは、戦略は中立です。同じ方向に複数の位置を積み重ねることはありません。再エントリーは、前の取引が終了した後にのみ行われます。
MQL バージョンとの制限事項
- ネット ポジションのみがサポートされます (StockSharp 制限)。ヘッジスタイルのロングとショートの同時取引は再現されません。
- ケリーのサイジングや部分的な利益確定などの資金管理モードは、このポートの一部ではありません。
- MQL テンプレートの手動確認、ダッシュボード グラフィックス、スクリーンショット機能は意図的に省略されています。
バックテストのチェックリスト
- 目的の
CandleType および補助タイムフレームを構成します。
- 元の EA 設定と一致するように、
Volume とストップ/ターゲット パラメータを調整します。
- テンプレートの使用状況に応じて、MACD 確認を有効または無効にします。
- シミュレーションを実行して、取引セッションウィンドウが元のテストと一致していることを確認します。
- 生成されたログ メッセージを確認して、停止イベントとターゲット イベントが予想どおりに発生することを確認します。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Ichimoku Price Action strategy: EMA trend with price action confirmation.
/// Buys on bullish candle above EMA, sells on bearish candle below EMA.
/// </summary>
public class IchimokuPriceActionStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private ICandleMessage _prevCandle;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public IchimokuPriceActionStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_candlesSinceTrade = SignalCooldownCandles;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (_prevCandle != null)
{
var prevBearish = _prevCandle.ClosePrice < _prevCandle.OpenPrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var prevBullish = _prevCandle.ClosePrice > _prevCandle.OpenPrice;
var currBearish = candle.ClosePrice < candle.OpenPrice;
var bullishBreakout = candle.ClosePrice > _prevCandle.HighPrice;
var bearishBreakout = candle.ClosePrice < _prevCandle.LowPrice;
if (prevBearish && currBullish && bullishBreakout && candle.ClosePrice > emaValue && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (prevBullish && currBearish && bearishBreakout && candle.ClosePrice < emaValue && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ichimoku_price_action_strategy(Strategy):
def __init__(self):
super(ichimoku_price_action_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ema_period = self.Param("EmaPeriod", 50)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._prev_candle = None
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(ichimoku_price_action_strategy, self).OnReseted()
self._prev_candle = None
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(ichimoku_price_action_strategy, self).OnStarted2(time)
self._prev_candle = None
self._candles_since_trade = self.SignalCooldownCandles
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
if self._prev_candle is not None:
prev_bearish = float(self._prev_candle.ClosePrice) < float(self._prev_candle.OpenPrice)
curr_bullish = float(candle.ClosePrice) > float(candle.OpenPrice)
prev_bullish = float(self._prev_candle.ClosePrice) > float(self._prev_candle.OpenPrice)
curr_bearish = float(candle.ClosePrice) < float(candle.OpenPrice)
bullish_breakout = float(candle.ClosePrice) > float(self._prev_candle.HighPrice)
bearish_breakout = float(candle.ClosePrice) < float(self._prev_candle.LowPrice)
ema_val = float(ema_value)
if prev_bearish and curr_bullish and bullish_breakout and float(candle.ClosePrice) > ema_val and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif prev_bullish and curr_bearish and bearish_breakout and float(candle.ClosePrice) < ema_val and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_candle = candle
def CreateClone(self):
return ichimoku_price_action_strategy()