GitHub で見る
平均足巻き込み戦略
概要
この戦略は、単一の StockSharp の高レベル戦略内で両方向を組み合わせることにより、MetaTrader の 5 人の専門家 heiken ashi engulf ea buy mt5.mq5 と heiken ashi engulf sell ea mt5.mq5 の動作を再現します。登録されたタイムフレームから古典的な平均足ローソク足を再構築し、巻き込みパターンを待ち、移動平均アライメントと 2 つの RSI ベースのフィルターでそれを確認し、最後に MetaTrader ピップスで表されるオプションの固定ストップロスとテイクプロフィット距離を使用して市場ポジションを開きます。
変換により、元の「買い」構成と「売り」構成が分離されたままになるため、それぞれの側を個別に最適化できます。方向セレクターを使用すると、トレーダーは強気のみ、弱気のみ、または両方のプレイブックを同時に実行できます。
取引ロジック
平均足の再構築
- 完成したローソク足ごとに、戦略は以前の合成始値と終値 (標準 MT アルゴリズム) を使用して平均足の始値、高値、安値、終値を構築します。
- 2 つの過去の平均足ローソク足 (
shift = 1 と shift = 2) は、MetaTrader コードからの Shift パラメータをエミュレートするために保存されています。
長いセットアップ
- オープンポジションは許可されません (
NoOpenedOrders ブロックに相当)。
- 最新の平均足ローソク足は強気であり、前の平均足ローソク足は弱気である必要があります (
ChosenCandleType = 1、PreviousCandleType = 2)。
- 最新の実際のローソク足は、その前のローソク足の高値 (
Close[1] > High[2]) を上回って終了する必要がありますが、その前のローソク足は弱気でなければなりません (Close[2] < Open[2])。
- 最新のローソク足の平均足終値は、ベースライン移動平均 (
iMA、パラメータ BuyBaselineMethod/Period) を上回っている必要があります。
- 高速トレンド MA は低速トレンド MA (
BuyFast 対 BuySlow) を上回っている必要があります。
- 2 つの RSI フィルターは、指定されたローソク数の設定された制限内に値を維持する必要があります (例外カウンターを含む、
IndicatorWithinLimits ブロックと同じロジック)。
- すべての条件が合格した場合、戦略はリクエストされた数量を購入し、設定されたストップロスとテイクプロフィットの距離をピップから価格単位に変換し、
SetStopLoss / SetTakeProfit を通じて保護注文を設定します。オプションのログ メッセージは、MetaTrader アラートを複製します。
短いセットアップ
短いロジックは、反対の比較を行う長いルールを反映しています。
- フラットな位置。
- 最新の平均足ローソク足は弱気で、前の平均足ローソク足は強気です。
- 最新の実際のローソク足は、その前のローソク足の安値 (
Close[1] < Low[2]) を下回って終了し、その前のローソク足は強気です。
- 平均足の終値は弱気のベースラインMAを下回ったままですが、速いMAは遅いMAを下回ったままです。
- 両方の RSI フィルターは、独自のシフト/ピリオド/例外構成を使用して、その境界内に留まります。
- 成行売り注文が出され、ショートのストップロス/テイクプロフィット距離が適用されます。
パラメーター
| 名前 |
デフォルト |
説明 |
CandleType |
H1 |
すべてのインジケーターとシグナルに使用される時間枠。 |
Direction |
両方 |
巻き込みプレイブックのどちら側をアクティブにするか (BuyOnly、SellOnly、Both)。 |
BuyVolume |
0.01 |
ロングトレードのロットサイズ。 |
BuyStopLossPips |
50 |
ロングのエントリーとストップロスの間には MetaTrader ピップがあります。 0 は固定停止を無効にします。 |
BuyTakeProfitPips |
50 |
ロングのエントリーとテイクプロフィットの間には MetaTrader ピップがあります。 0 は固定ターゲットを無効にします。 |
BuyBaselinePeriod / BuyBaselineMethod |
20 / 指数関数的 |
MA は強気の平均足ローソク足 (ミラー inp1_Ro_*) と比較しました。 |
BuyFastPeriod / BuyFastMethod |
20 / 指数関数的 |
高速トレンド MA (inp12_Lo_*)。 |
BuySlowPeriod / BuySlowMethod |
30 / 指数関数的 |
スロートレンド MA (inp12_Ro_*)。 |
BuyPrimaryRsi* |
14、シフト 1、ウィンドウ 2、例外 0、制限 [0;100] |
最初の RSI フィルタ (inp13_* と一致)。 |
BuySecondaryRsi* |
5、シフト 2、ウィンドウ 3、例外 0、制限 [0;100] |
2 番目の RSI フィルター (inp14_*)。 |
SellVolume |
0.01 |
短期取引のロットサイズ。 |
SellStopLossPips |
50 |
ショートのエントリーとストップロスの間は MetaTrader ピップです。 |
SellTakeProfitPips |
50 |
ショートのエントリーとテイクプロフィットの間の MetaTrader ピップ。 |
SellBaselinePeriod / SellBaselineMethod |
20 / 指数関数的 |
弱気セットアップのベースライン MA (inp15_*)。 |
SellFastPeriod / SellFastMethod |
20 / 指数関数的 |
高速トレンド MA (inp26_Lo_*)。 |
SellSlowPeriod / SellSlowMethod |
30 / 指数関数的 |
スロートレンド MA (inp26_Ro_*)。 |
SellPrimaryRsi* |
14、シフト 1、ウィンドウ 2、例外 0、制限 [0;100] |
ショートパンツ用の最初の RSI フィルタ (inp27_*)。 |
SellSecondaryRsi* |
5、シフト 2、ウィンドウ 3、例外 0、制限 [0;100] |
ショートパンツ用の 2 番目の RSI フィルタ (inp28_*)。 |
AlertTitle |
「警告メッセージ」 |
取引が開始されるときにログに書き込まれるテキスト。 |
SendNotification |
本当の |
MetaTrader ポップアップ/通知を置き換える情報ログ メッセージを有効にします。 |
リスク管理
- ストップロスとテイクプロフィットの距離は、MetaTrader ピップから価格単位に変換されます。変換では、セキュリティ ティック サイズに応じて値が自動的にスケーリングされます (3/5 桁の引用符のサポートが含まれます)。
- 新しい取引が実行されると、予想される結果のポジションが
SetStopLoss / SetTakeProfit に渡され、元の仮想/実際のストップ配置を模倣します。
- ソース EA には追加の末尾ロジックが存在しないため、何も導入されません。
注意事項
- RSI フィルタは、MetaTrader ビルダーと同じ「例外のあるウィンドウ」ロジックを使用します。利用可能なローソク足の数が不十分な場合、十分な履歴が収集されるまで取引シグナルは無視されます。
- 平均足の値はローソクごとにキャッシュされるため、インジケーターのシフト (
Shift + CandlesShift) は元の .mq5 ファイルの動作と一致します。
Direction を BuyOnly または SellOnly に設定すると、パラメータを変更せずに反対側が完全に無効になり、最適化中に役立ちます。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Heiken Ashi Engulf strategy: WMA crossover with candle direction filter.
/// Buys when price crosses above WMA with bullish candle, sells on bearish cross below.
/// </summary>
public class HeikenAshiEngulfStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal _prevClose;
private decimal _prevWma;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public HeikenAshiEngulfStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_period = Param(nameof(Period), 50)
.SetGreaterThanZero()
.SetDisplay("Period", "WMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevWma = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevWma = 0;
_hasPrev = false;
var wma = new ExponentialMovingAverage { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(wma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal wmaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
var bullish = candle.ClosePrice > candle.OpenPrice;
var bearish = candle.ClosePrice < candle.OpenPrice;
if (_prevClose <= _prevWma && candle.ClosePrice > wmaValue && bullish && Position <= 0)
BuyMarket();
else if (_prevClose >= _prevWma && candle.ClosePrice < wmaValue && bearish && Position >= 0)
SellMarket();
}
_prevClose = candle.ClosePrice;
_prevWma = wmaValue;
_hasPrev = true;
}
}
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 heiken_ashi_engulf_strategy(Strategy):
def __init__(self):
super(heiken_ashi_engulf_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._period = self.Param("Period", 50)
self._prev_close = 0.0
self._prev_wma = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def Period(self):
return self._period.Value
@Period.setter
def Period(self, value):
self._period.Value = value
def OnReseted(self):
super(heiken_ashi_engulf_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_wma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(heiken_ashi_engulf_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_wma = 0.0
self._has_prev = False
wma = ExponentialMovingAverage()
wma.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(wma, self._process_candle).Start()
def _process_candle(self, candle, wma_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
wma_val = float(wma_value)
if self._has_prev:
bullish = close > open_price
bearish = close < open_price
if self._prev_close <= self._prev_wma and close > wma_val and bullish and self.Position <= 0:
self.BuyMarket()
elif self._prev_close >= self._prev_wma and close < wma_val and bearish and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_wma = wma_val
self._has_prev = True
def CreateClone(self):
return heiken_ashi_engulf_strategy()