GitHub で見る

MAミラー戦略

概要

MA ミラー戦略は、MetaTrader のエキスパート MA_MirrorEA を転換したものです。システムは 2 つの単純な移動平均を比較します。 同じ期間で、異なる価格ソース (ローソク足の終値と始値) を使用して計算されます。移動平均のとき、 終値は、戦略が長期化したい始値の移動平均より上に留まります。開口部より下に落ちたとき 平均戦略は短くすることを望んでいます。構成可能なシフトパラメータにより、古いローソク足から移動平均を読み取ることができます そのため、StockSharp ポートは、元の MetaTrader インジケーターに適用された視覚的なディスプレイスメントを再現できます。

StockSharp の実装では、元の「ミラー」動作が維持されます。つまり、いつでも存在できる市場ポジションは 1 つだけであり、 信号が変化すると、まず前のポジションが閉じられ、次に反対方向に新しいポジションが開きます。 MetaTrader と同じように コードでは、戦略は仮想ショートシグナルで始まります。つまり、最初の実際の取引は終値平均の後でのみ発生します。 始値平均を上回って推移しています。

取引ロジック

  1. CandleType によって定義されたローソク足シリーズをサブスクライブし、早まった決定を避けるために完成したローソク足のみを処理します。
  2. ローソク足の終値と始値を使用して 2 つの単純な移動平均をフィードします。どちらのインジケーターも同じ MovingPeriod を共有しているため、 値を直接比較できます。
  3. 最近の移動平均値をリング バッファに保存します。バッファにより、MovingShift から値を取得できるようになります。 キャンドル前に、禁止されたインジケーター メソッドを呼び出さずに MetaTrader シフト パラメーターをエミュレートします。
  4. シフトされた終値平均がシフトされた始値平均を上回っている場合、目的のシグナルを 買い に設定します。以下の場合は設定してください。 販売したいシグナル。両方の平均が等しい場合、前の信号が保存されます。
  5. これが最初のシグナルであり、強気ではない場合は、横ばいのままにしてください。それ以外の場合、目的の信号が最後に実行された信号と異なる場合 シグナルが発生したら、既存のエクスポージャーを閉じ、新しい方向に TradeVolume ロットで新しい市場ポジションを開きます。
  6. 位置の方向は変更されないまま、後のローソク足が重複した命令を無視するように、保存されたシグナルを更新します。

パラメーター

名前 種類 デフォルト 説明
CandleType DataType 1分の時間枠 戦略によって処理される主な時間枠。
MovingPeriod int 20 終値と始値に使用される単純移動平均の長さ。
MovingShift int 0 移動平均値が後方にシフトされた完了したローソク足の数。
TradeVolume decimal 1 すべての成行注文に使用される数量。

元の MetaTrader 専門家との違い

  • MQL インクルード ファイルに含まれる資金管理ヘルパー (ストップロス、テイクプロフィット、トレーリングストップ) は移植されていません。の StockSharp バージョンは常に固定の TradeVolume を取引し、必要に応じて外部のリスク管理に依存します。
  • MetaTrader は個別の注文を保存しますが、StockSharp はネット ポジションを処理します。コンバージョンにより既存のネットポジションがクローズされます 新しいチケットを開く前に、結果の露出が EA のシングルチケットの動作と一致するようにします。
  • インジケーターの処理は、StockSharp のキャンドル サブスクリプション API と SimpleMovingAverage インジケーターを介して処理されます。 iMA を直接呼び出すのではなく、内部バッファを呼び出します。

使い方のヒント

  • 戦略を開始する前に、TradeVolume を商品のロットステップに調整します。コンストラクターも同じ値を割り当てます。 Strategy.Volume したがって、ヘルパー メソッドは予想されるサイズのオーダーを発行します。
  • たとえば、MetaTrader の動きと一致させるために、古いローソク足から移動平均を読み取りたい場合は、MovingShift を増やします。 プラットフォームはシフトされたインジケーターをプロットします。
  • チャートに戦略を追加すると、移動平均と実行された取引の両方とともにローソク足を視覚化できるため、作業が容易になります。 終値平均が始値平均を横切ったときに反転が正確に発生することを確認します。

インジケーター

  • 同じ長さの 2 つの単純な移動平均 (終値と始値)、およびオプションの後方シフト。
namespace StockSharp.Samples.Strategies;

using System;
using System.Collections.Generic;

using Ecng.Common;

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

public class MaMirrorStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _movingPeriod;

	private SimpleMovingAverage _sma;
	private decimal? _prevDiff;

	public MaMirrorStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle type", "Timeframe processed by the strategy.", "General");

		_movingPeriod = Param(nameof(MovingPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Moving period", "Length of the SMA.", "Indicator");
	}

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int MovingPeriod
	{
		get => _movingPeriod.Value;
		set => _movingPeriod.Value = value;
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevDiff = null;
		_sma = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevDiff = null;

		_sma = new SimpleMovingAverage { Length = MovingPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_sma, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal smaValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_sma.IsFormed)
			return;

		// Mirror: compare close vs SMA (of close). When close crosses above SMA = buy, below = sell.
		var diff = candle.ClosePrice - smaValue;

		if (_prevDiff is not null)
		{
			if (_prevDiff.Value <= 0 && diff > 0 && Position <= 0)
			{
				BuyMarket();
			}
			else if (_prevDiff.Value >= 0 && diff < 0 && Position >= 0)
			{
				SellMarket();
			}
		}

		_prevDiff = diff;
	}
}