GitHub で見る

T3MA(MTC)戦略

MetaTrader 4 Expert Advisor T3MA(MTC).mq4 (ディレクトリ MQL/7904) から変換されました。オリジナルのロボットは、「T3MA-ALARM」インジケーターからのシグナルを取引します。二重平滑化指数移動平均を構築し、その曲線の傾きが下降から上昇、またはその逆に反転するたびに注文を出します。 StockSharp ポートは、慣用的な高レベル API と同じロジックをミラーリングします。

取引アイデア

  1. 選択したローソクの種類と期間を使用して最初の EMA を構築します。
  2. 同じ期間の 2 番目の EMA でそのシリーズを平滑化します。
  3. 平滑化された値を前の値と比較します (オプションで MaShift だけシフト)。
  4. 傾斜の方向が変わると、戦略は信号を記録します。注文は設定された CalculationBarOffset 遅延の後に実行され、EA の CalculationBarIndex パラメータが再現されます。
  5. 各シグナルは、MetaTrader の LastOrder 変数と同様に、バーの安値 (ロング エントリーの場合) または高値 (ショート エントリーの場合) を一意のマーカーとして使用し、重複取引を回避します。

移植の詳細

  • 2 つの ExponentialMovingAverage インスタンスを使用して、T3MA-ALARM スムージング チェーンをエミュレートします。
  • MaShift ルックバックをサポートするために、最近平滑化された値の小さなキューを維持します。
  • シグナルは FIFO キューに保存され、要求された数のキャンドルが完成した後に実行されます。
  • 保護注文は、MetaTrader ポイントに一致する価格ステップで表現された距離を持つ StartProtection を通じて管理されます。
  • AllowMultiplePositions フラグは MultiPositions 入力を再現します。無効にすると、ストラテジーは新しい信号に作用する前にネット ポジションがフラットになるまで待機します。

パラメーター

  • MaPeriod – 両方のスムージング パスに使用される EMA の長さ (デフォルト: 4)。
  • MaShift – 傾きを比較する前に平滑化シリーズをシフトするバーの数 (デフォルト: 0)。
  • CalculationBarOffset – シグナルの検出と注文の送信の間の遅延(終了キャンドル単位)(デフォルト: 1)。
  • TradeVolume – ロット単位の基本注文量 (デフォルト: 1)。
  • UseStopLoss / StopLossPoints – 価格ステップでのストップロスの有効化と距離 (デフォルト: 有効、40 ステップ)。
  • UseTakeProfit / TakeProfitPoints – 価格ステップでの利食いの有効化と距離 (デフォルト: 有効、11 ステップ)。
  • AllowMultiplePositions – 反対側のポジションが開いている場合でも、スタックポジションを許可します (デフォルト: 有効)。
  • CandleType – インジケーターチェーンにフィードするために使用される時間枠またはデータタイプ (デフォルト: 5 分足ローソク足)。

取引ワークフロー

  1. 選択したローソク足シリーズを購読し、ダブル EMA チェーンを通じて終値をフィードします。
  2. 現在の傾斜方向を追跡し、反転したときに信号を生成します。
  3. MQL4 スクリプトが古いインジケーター バッファを読み取るのと同じように、CalculationBarOffset のローソク足が完了した直後に実行が行われるように、各シグナル (またはシグナルの欠落) を遅延キューにプッシュします。
  4. 成熟したシグナルが実行されると、次のようになります。
    • 取引が無効になっている場合、プラットフォームの準備ができていない場合、またはネットポジションがすでにオープンしているときに AllowMultiplePositions がオフになっている場合は、スキップしてください。
    • 重複を防ぐために、信号マーカーが以前のものと異なることを確認してください。
    • 設定された数量で成行注文 (BuyMarket/SellMarket) を送信します。有効にすると、保護ストップが自動的に接続されます。

注意事項

  • 価格比較では、LastOrder の類似品をチェックする際の浮動小数点アーチファクトを避けるために、小さな小数許容誤差を使用します。
  • この戦略は、AllowMultiplePositions が無効になっている場合に反対のポジションを自動決済せず、保護的出口に依存した元の EA を模倣します。
  • チャート作成サブシステムが存在する場合、ローソク足と自身の取引の視覚化が可能です。
using System;

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

namespace StockSharp.Samples.Strategies;

public class T3MaMtc9Strategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _momentumPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevMom;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public T3MaMtc9Strategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 50).SetDisplay("EMA Period", "EMA lookback", "Indicators");
		_momentumPeriod = Param(nameof(MomentumPeriod), 14).SetDisplay("Momentum", "Momentum period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 150).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevEma = default;
		_prevMom = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevEma = 0;
		_prevMom = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var mom = new Momentum { Length = MomentumPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, mom, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal ema, decimal mom)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!_hasPrev) { _prevEma = ema; _prevMom = mom; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevEma = ema;
			_prevMom = mom;
			return;
		}

		if (close > ema && _prevMom <= 0 && mom > 0 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (close < ema && _prevMom >= 0 && mom < 0 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevEma = ema;
		_prevMom = mom;
	}
}