GitHub で見る

経験値TEMA戦略

Exp TEMA 戦略は、MetaTrader エキスパート アドバイザー Exp_TEMA.mq5 の StockSharp 移植です。オリジナルのシステムは複数の外国為替ペアをスキャンし、三重指数移動平均 (TEMA) の傾きを監視します。傾きが反転するたびに、エキスパートは新しいトレンドフォローポジションに入るか、反対のポジションから抜け出します。この C# 変換は、同じインジケーター ロジックを維持しながら、StockSharp の戦略に割り当てられた単一の証券に焦点を当てます。

取引ロジック

この戦略は、選択された CandleType パラメータによって生成された完成したローソク足で動作します。構成可能な TemaPeriod 長さの TEMA は、ローソク足の終値ごとに計算されます。 3 つの連続した TEMA 読み取り値が比較され、MQL5 専門家の傾き検出スキームが再現されます。

  1. tema[0] を最新のローソク足の値、tema[1] を前のローソク足の値、tema[2] を 2 つ前のローソク足の値とします。
  2. 短期的な傾きは d1 = tema[1] - tema[2] ですが、古い傾きは d2 = tema[2] - tema[3] です。
  3. 強気エントリーは、勾配が上昇したときにトリガーされます (d2 < 0 および d1 > 0)。ショートポジションはすべて最初にクローズされ、その後、Volume + |Position| ロットのロング注文が発注されます。
  4. 弱気エントリーは、勾配が下降したときにトリガーされます (d2 > 0 および d1 < 0)。ロングポジションは最初にフラット化され、次に Volume + |Position| ロットのショート注文が送信されます。
  5. 保護出口は元のストップフラグを模倣します。現在の傾きが負になるとロングポジションがクローズされ、正の傾きはショートポジションをクローズします。

これにより、履歴バッファ アクセスを使用せずにソース EA と同じ信号タイミングが再現され、高レベル StockSharp API 内に留まります。

パラメーター

パラメータ デフォルト 説明
TemaPeriod 15 三重指数移動平均の長さ。
TradeVolume 1 基本注文量。約定サイズは「Trade Volume +」となります。 ポジション `後退するとき。
StopLossPoints 1000 価格ステップで表されるストップロス距離。陽性の場合は StartProtection に渡されます。
TakeProfitPoints 2000年 価格ステップで表される利食い距離。陽性の場合は StartProtection に渡されます。
CandleType 15分キャンドル インジケーターを供給するローソク式。元の専門家が使用したチャートと一致する時間枠を選択してください。

すべてのパラメータは StrategyParam<T> で作成されるため、デザイナー内で最適化できます。

MQL5 エキスパートとの違い

  • MQL バージョンは、最大 12 個のシンボルを同時に管理します。 StockSharp 戦略は特定の Security にバインドされているため、このポートは戦略の開始時に割り当てられた商品を取引します。複数のシンボルのカバレッジが必要な場合は、複数のストラテジ インスタンスを実行します。
  • 注文管理は、元の成行注文、ストップ、ターゲットを StockSharp の上位レベルの API にマッピングする BuyMarket/SellMarketStartProtection に依存しています。
  • インジケーターへのアクセスは SubscribeCandles().Bind(...) を通じて実行され、手動によるバッファーのコピーを回避し、リポジトリ ガイドラインに準拠した状態を保ちます。

使用のヒント

  1. 戦略を目的の証券にアタッチし、分析時間枠に一致する CandleType を設定します。
  2. 商品のボラティリティに応じて、価格ステップでストップとテイクプロフィットの距離を調整します。
  3. オプション: TemaPeriodStopLossPoints、および TakeProfitPoints で最適化を実行し、MetaTrader で実行されたパラメータ スイープを複製します。
  4. 付属のチャート領域を監視して、ローソク足、TEMA ライン、および実行された取引を視覚化します。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that trades TEMA slope reversals from the original Exp_TEMA expert advisor.
/// Enters long when TEMA slope turns positive, short when negative.
/// </summary>
public class ExpTemaStrategy : Strategy
{
	private readonly StrategyParam<int> _temaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private ExponentialMovingAverage _tema;
	private decimal? _prev1;
	private decimal? _prev2;
	private decimal? _prev3;

	public int TemaPeriod
	{
		get => _temaPeriod.Value;
		set => _temaPeriod.Value = value;
	}

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

	public ExpTemaStrategy()
	{
		_temaPeriod = Param(nameof(TemaPeriod), 40)
			.SetGreaterThanZero()
			.SetDisplay("TEMA Period", "Length of Triple Exponential Moving Average", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for TEMA calculation", "General");
	}

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

		_tema = new ExponentialMovingAverage { Length = TemaPeriod };
		_prev1 = null;
		_prev2 = null;
		_prev3 = null;

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

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _tema);
			DrawOwnTrades(area);
		}
	}

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

		if (!_tema.IsFormed)
		{
			_prev1 = temaValue;
			return;
		}

		if (_prev1 is null)
		{
			_prev1 = temaValue;
			return;
		}

		if (_prev2 is null)
		{
			_prev2 = _prev1;
			_prev1 = temaValue;
			return;
		}

		if (_prev3 is null)
		{
			_prev3 = _prev2;
			_prev2 = _prev1;
			_prev1 = temaValue;
			return;
		}

		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		var dtema1 = _prev1.Value - _prev2.Value;
		var dtema2 = _prev2.Value - _prev3.Value;

		// Entry on slope reversal
		var turnedUp = dtema2 < 0 && dtema1 > 0;
		var turnedDown = dtema2 > 0 && dtema1 < 0;

		if (turnedUp && Position <= 0)
		{
			BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		else if (turnedDown && Position >= 0)
		{
			SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prev3 = _prev2;
		_prev2 = _prev1;
		_prev1 = temaValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_tema = null;
		_prev1 = null;
		_prev2 = null;
		_prev3 = null;

		base.OnReseted();
	}
}