GitHub で見る
M.Aブレイク戦略
この戦略は、両方のブレイクアウト方向を単一の StockSharp 実装に組み合わせることで、MetaTrader の「M.A ブレイク mt5 買い」と「M.A ブレイク mt5 売り」のエキスパートの動作を再現します。設定可能なローソク足シリーズを監視し、いくつかの指数移動平均を分析し、取引を開始する前に強いインパルスローソク足を確認します。ポジションは、固定された保護ストップとピップで測定されるターゲットによって管理されます。
取引ロジック
- トレンドの確認。 完成したローソク足の取引方向に 2 つの EMA ペア (速い対遅い) を揃える必要があります。ロングの場合、両方の高速平均が低速平均を上回っている必要があります。短編の場合、関係は逆転します。前のローソク足のオープンも、専用の EMA フィルターの正しい側にある必要があります。
- クワイエット範囲の測定。 設定可能な数の初期のキャンドル (最新のインパルス キャンドルを除く) が「クワイエット」期間を定義します。それらの最高範囲は、最小ピップしきい値と比較されます。
- インパルス検出。 最後に完成したキャンドルは、静かな範囲の少なくとも
ImpulseStrength 倍拡大する必要があります。ピップ単位のローソク足のサイズ制限を強制して、異常に小さいまたは大きい動きを無視することができます。
- ローソク足テンプレート。 インパルス キャンドルは特定の芯構造を示す必要があります。
- ロングトレード: 強気の実体、上芯がローソク足レンジの
BullUpperWickPercent を超えず、下芯が少なくともレンジの BullLowerWickPercent 以上。
- ショートトレード: 弱気の実体、少なくとも
BearUpperWickPercent の上芯、レンジの BearLowerWickPercent 以下の下芯。
- プルバック条件。 インパルス ロー (ロングの場合) またはハイ (ショートの場合) は、プルバックからブレイクアウトが発生したことを保証するために、追加の EMA をテストする必要があります。
- ポジション制御 ネット ポジションは 1 つだけ許可されます。この戦略は、新しい取引に入る前に反対側をクローズし、トレンドフィルターに対してポジションをオープンすることはありません。
- 出口管理。 ストップロスとテイクプロフィットのレベルはエントリー価格からピップ単位で計算されます。完成した各ローソク足は、価格が保護レベルに達したかどうかを確認し、それに応じて終了します。
パラメーター
| パラメータ |
説明 |
| キャンドルタイプ |
すべての計算に使用される主なローソク足シリーズ。 |
| 高速 MA 1 / 低速 MA 1 |
主要なトレンドを定義する最初の EMA ペアの期間。 |
| 高速 MA 2 / 低速 MA 2 |
追加のトレンド フィルターとして使用されるセカンダリ EMA ペアの期間。 |
| フィルター MA を開く |
以前のローソク足の始値をフィルターする EMA 期間。 |
| プルバック MA |
EMA 期間の値はインパルス芯で触れる必要があります。 |
| 静かなバー |
静かな市場範囲を測定するために使用される過去のローソク足の数。 |
| 静かな範囲 (pips) |
ブレイクアウトを検討する前に、静かなローソク足全体で必要な最小限のピップ範囲。 |
| インパルス乗数 |
インパルスキャンドルのサイズと静かな範囲の間の最小比率。 |
| 最小/最大ローソク足サイズ (pips) |
インパルスキャンドル範囲のオプションの制限。ゼロはそれぞれの境界を無効にします。 |
| 雄牛の上部芯 % / 雄牛の下部芯 % |
強気インパルスローソク足の形状フィルター。ローソク足範囲のパーセンテージとして表されます。 |
| ベア上部芯 % / ベア下部芯 % |
弱気インパルスローソク足の形状フィルター。 |
| ボリューム |
ロングエントリーとショートエントリーの両方に使用されるロットの注文サイズ。 |
| ストップロス (pips) |
エントリー価格から測定された保護ストップまでの距離。ゼロは停止を無効にします。 |
| 利益確定 (pips) |
利益目標までの距離。ゼロはターゲットを無効にします。 |
| ロングを有効にする/ショートを有効にする |
各方向のブレイクアウト取引を個別に切り替えます。 |
使用上の注意
- 元のエキスパートが使用した時間枠 (M5 や H1 など) に一致するようにローソク足シリーズを構成します。デフォルトの時間枠は 5 分です。
- この戦略では、クワイエット レンジの計算に必要な最近の履歴のみが保存され、不必要なメモリ使用が防止されます。
- エントリー価格はインパルスローソク足の終値で近似され、次の足の開始時に成行注文を発注するという元の MetaTrader の動作と一致します。
- ストップロスとテイクプロフィットのレベルは、完了したローソク足ごとに評価されます。両方のレベルが同じバー内でヒットした場合は、ソースエキスパートで使用されている保守的な処理を反映して、ストップが優先されます。
- 一方向のみを有効にすると、元の「買い」または「売り」のエキスパートアドバイザーが再現されますが、両方のトグルをアクティブのままにすると、対称的なブレイクアウト取引が可能になります。
変換の詳細
- 元の MQ5 ファイルは両方とも UTF-16 でエンコードされ、FXD エンジンによって生成されたブロックから構築されました。各ブロックは明示的な C# ロジックに変換されています。
- EMA の比較とローソク足テンプレートは、MetaTrader バージョン (
Shift = 1) と同じシフトに従います。これは、戦略が常に完全に閉じたローソク足を評価することを意味します。
- MQ5 スクリプトの仮想ストップ ロジックとチャート ラベルは、注文の配置に影響を与えないため、意図的に省略されました。
テスト
AlgoTrading.sln を通じてソリューションをコンパイルするか、StockSharp ストラテジー テスター内でストラテジーを実行します。セキュリティメタデータにこの情報が欠けている場合は、商品価格ステップを調整します。実装は一般的な FX pip 値をエミュレートするために 0.0001 にフォールバックします。
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MA Break strategy: EMA breakout with impulse candle confirmation.
/// Buys when close crosses above EMA with strong bullish candle body.
/// Sells when close crosses below EMA with strong bearish candle body.
/// </summary>
public class MaBreakStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<decimal> _bodyRatio;
private decimal _prevClose;
private decimal _prevEma;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public decimal BodyRatio { get => _bodyRatio.Value; set => _bodyRatio.Value = value; }
public MaBreakStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period for breakout", "Indicators");
_bodyRatio = Param(nameof(BodyRatio), 0.7m)
.SetDisplay("Body Ratio", "Min body/range ratio for impulse", "Pattern");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevEma = 0;
_hasPrev = false;
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;
var range = candle.HighPrice - candle.LowPrice;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
if (_hasPrev && range > 0)
{
var isImpulse = body >= range * BodyRatio;
if (_prevClose <= _prevEma && candle.ClosePrice > emaValue
&& candle.ClosePrice > candle.OpenPrice && isImpulse && Position <= 0)
BuyMarket();
else if (_prevClose >= _prevEma && candle.ClosePrice < emaValue
&& candle.ClosePrice < candle.OpenPrice && isImpulse && Position >= 0)
SellMarket();
}
_prevClose = candle.ClosePrice;
_prevEma = emaValue;
_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 ma_break_strategy(Strategy):
def __init__(self):
super(ma_break_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ema_period = self.Param("EmaPeriod", 50)
self._body_ratio = self.Param("BodyRatio", 0.7)
self._prev_close = 0.0
self._prev_ema = 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 EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def BodyRatio(self):
return self._body_ratio.Value
@BodyRatio.setter
def BodyRatio(self, value):
self._body_ratio.Value = value
def OnReseted(self):
super(ma_break_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ma_break_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
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
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
ema_val = float(ema_value)
range_val = high - low
body = abs(close - open_price)
if self._has_prev and range_val > 0:
is_impulse = body >= range_val * self.BodyRatio
if (self._prev_close <= self._prev_ema and close > ema_val and
close > open_price and is_impulse and self.Position <= 0):
self.BuyMarket()
elif (self._prev_close >= self._prev_ema and close < ema_val and
close < open_price and is_impulse and self.Position >= 0):
self.SellMarket()
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
def CreateClone(self):
return ma_break_strategy()