GitHub で見る

MARE5.1 シフトクロスオーバー戦略

概要

MARE5.1 戦略は、MetaTrader 4 Expert Advisor MARE5_1.mq4 の C# ポートです。オリジナルのロボットは M1 データを取引し、3 つの異なる履歴オフセットで評価された 1 対の単純移動平均に依存して体制の変化を検出しました。この StockSharp 実装は、構成可能なパラメータを使用して動作を再現し、MetaTrader スタイルの保護注文を添付し、詳細な取引ウィンドウ フィルターを公開します。

取引ロジック

  1. 市場データ
    • CandleType で定義された 1 つのキャンドル サブスクリプション (デフォルト: 1 分) が計算にフィードされます。
    • すべてのキャンドルは、成形途中のバーの使用を避けるために、閉じた後にのみ処理されます。
  2. 指標
    • 2 つの SimpleMovingAverage インスタンスは、高速 (FastPeriod) コンポーネントと低速 (SlowPeriod) コンポーネントを表します。
    • 両方の平均は、MQL iMA 関数の ma_shift 引数とまったく同様に、MovingAverageShift だけ前方にシフトされます。
    • 各平均の追加の遅延コピーは、元の iMA(..., shift=2/5) 呼び出しをミラーリングするために、MovingAverageShift + 2MovingAverageShift + 5 をシフトして取得されます。
  3. 信号検出
    • 平均間の差は少なくとも 1 つの価格ステップ (MetaTrader 用語では Point) を超える必要があります。金融商品の PriceStep がゼロの場合は、正の差があれば十分です。
    • 販売セットアップ:
      • 前のローソク足は弱気 (Close < Open) である必要があります。
      • 現在のシフトされた低速平均は高速平均よりも大きくなります。
      • ファースト平均より 2 ロウソク足と 5 ロウソク足でも依然としてスロー平均を上回っており、勢いが反転していることを示しています。
    • セットアップを購入:
      • 前のローソク足は強気 (Close > Open) でなければなりません。
      • 現在のシフトされた高速平均は低速平均よりも大きくなります。
      • 2 ロウソク足と 5 ロウソク足では、スロー平均が依然としてリードしており、弱気から強気の状況への移行を確認しています。
    • EA から OrdersTotal() < 1 ガードを複製して、一度にオープンできるポジションは 1 つだけです。
  4. 時間フィルター
    • 取引は、評価されたローソク足の終了時間が [TimeOpenHour, TimeCloseHour] 間隔内にある場合にのみ許可されます。
    • 終了時間が開始時間より短い場合、その時間枠は夜間として扱われます(例: 22 から 5)。

リスク管理

  • StartProtection は、商品 PriceStep を使用して、MetaTrader ポイントから絶対価格オフセットに変換されたストップロスとテイクプロフィットの距離で構成されています。
  • 元のコードでは TrailingStop が宣言されていますが、使用されていないため、トレーリングストップは実装されていません。
  • 注文は、TradeVolume で定義された数量で送信されます。この戦略はポジションをピラミッド型にしたりスケールアウトしたりしません。

パラメーター

名前 説明 デフォルト 注意事項
TradeVolume 市場エントリーのロットサイズ。 7.8 StockSharp コネクタによる交換ルールに従って丸められます。
FastPeriod 高速単純移動平均の期間。 13 戦略が価格の変化にどれだけ早く反応するかを制御します。
SlowPeriod 遅い単純移動平均の期間。 55 長期的なトレンドの参考情報を提供します。
MovingAverageShift 両方の移動平均に前方シフトが適用されます。 2 MQL iMA 関数の ma_shift パラメータと一致します。
StopLossPoints 保護停止距離 (MetaTrader ポイント)。 80 機器 PriceStep を通じて絶対オフセットに変換されます。
TakeProfitPoints 目標距離を MetaTrader ポイント単位で獲得します。 110 テイクプロフィットを無効にするには、0 に設定します。
TimeOpenHour 許可された取引ウィンドウの始まり (時間、0 ~ 23)。 8 ローソク足の終了時間に対して評価されます。
TimeCloseHour 許可された取引ウィンドウの終了 (時間、0 ~ 23)。 14 TimeOpenHour より低くても午前 0 時をまたがることができます。
CandleType キャンドルのサブスクリプションに使用される時間枠。 1 minute 他の TimeFrame() 値を指定することもできます。

実装メモ

  • Shift インジケーターは、インジケーター バッファーに直接アクセスせずに、MQL 実装の正確な履歴オフセットを再現するために内部で使用されます。
  • IsDifferenceSatisfied はポイントとしきい値の比較をカプセル化し、さまざまなティック サイズを持つ商品との戦略の互換性を保ちます。
  • 取引ウィンドウのチェックでは、ローソクの終了時間を使用します。これは、終了したローソクのみが処理される場合の、MetaTrader からの Hour() の最良の近似値です。
  • すべてのコメントは英語で書かれており、コードはプロジェクト ガイドラインで要求されている高レベルの API (SubscribeCandles().Bind(...)) のみに依存しています。

MQL バージョンとの違い

  • シグナルは閉じたローソク足で評価され、MetaTrader の足内ティックで発生する可能性のある再描画を排除します。
  • ストップロス注文とテイクプロフィット注文は、すべての OrderSend コールに手動で付加されるのではなく、StartProtection によって処理されます。
  • 未使用の TrailingStop 入力は、機能しないパラメータの公開を避けるために意図的に省略されました。
  • 時間フィルタは設計上夜間セッションをサポートしますが、元の EA は暗黙的に TimeOpen <= TimeClose を想定していました。
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// MARE5.1 Shift Crossover: SMA crossover with ATR stops.
/// </summary>
public class Mare51ShiftCrossoverStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastSmaLength;
	private readonly StrategyParam<int> _slowSmaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public Mare51ShiftCrossoverStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_fastSmaLength = Param(nameof(FastSmaLength), 13)
			.SetDisplay("Fast SMA", "Fast SMA period.", "Indicators");
		_slowSmaLength = Param(nameof(SlowSmaLength), 55)
			.SetDisplay("Slow SMA", "Slow SMA period.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastSmaLength { get => _fastSmaLength.Value; set => _fastSmaLength.Value = value; }
	public int SlowSmaLength { get => _slowSmaLength.Value; set => _slowSmaLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
		var fastEma = new ExponentialMovingAverage { Length = FastSmaLength };
		var slowEma = new ExponentialMovingAverage { Length = SlowSmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fastEma, slowEma, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fastEma); DrawIndicator(area, slowEma); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow) { _entryPrice = close; BuyMarket(); }
			else if (fastVal < slowVal && _prevFast >= _prevSlow) { _entryPrice = close; SellMarket(); }
		}
		_prevFast = fastVal; _prevSlow = slowVal;
	}
}