GitHub で見る

2つのMA 4レベルバンド戦略

概要

この戦略は、MetaTrader エキスパート アドバイザー ytg_2MA_4Level を再作成します。速い移動平均と遅い移動平均を比較し、速い曲線が遅い曲線と直接交差するか、または 4 つの構成可能なオフセット バンド内で交差するときにエントリーをトリガーします。元の実装と同様に、ポジションはピップで表現される対称的なストップロスとテイクプロフィットの距離によって保護されます。

信号ロジック

  1. 選択したローソク足シリーズで 2 つの移動平均が計算されます。平均化方法 (SMA、EMA、SMMA、LWMA) と適用される価格は両方とも、高速回線と低速回線に対して個別に調整できます。
  2. 終了したローソク足ごとに、戦略は移動平均を CalculationBar バー前(デフォルトは 1)前と 1 バー前にサンプリングします。これは、MetaTrader iMA(..., shift) 呼び出しを反映し、閉じたローソク足のみが取引を生成するようにします。
  3. 買いシグナルは、ファースト平均がスロー平均を上回ったとき、またはクロスオーバーがスロー平均の上または下で UpperLevel1UpperLevel2LowerLevel1、または LowerLevel2 ピップシフトされたときに発生します。
  4. 売り シグナルは、低速ラインを下回る高速平均クロス (および同じ 4 つのオフセット バンド) を備えたミラー条件を使用します。
  5. この戦略は、アクティブな注文がなく、現在のポジションが横ばいの場合にのみ新しい市場ポジションをオープンし、MQL エキスパートのシングルチケット行動と一致します。

パラメーター

名前 種類 デフォルト 説明
TakeProfitPips int 130 利益確定距離 (pips)。ターゲットを無効にするには、0 に設定します。
StopLossPips int 1000 ピップス単位のストップロス距離。保護停止を無効にするには、0 に設定します。
TradeVolume decimal 1 各注文とともに送信される基本ロット サイズ (VolumeStep に自動調整されます)。
CalculationBar int 1 MA 比較のアンカーとして使用されるバーの数 (MetaTrader shift)。
FastPeriod / SlowPeriod int 14 / 180 移動平均の期間の長さ。
FastMethod / SlowMethod MovingAverageMethod Smoothed 平均化手法: SimpleExponentialSmoothed、または LinearWeighted
FastPrice / SlowPrice CandlePrice Median 各移動平均で使用される適用価格。
UpperLevel1 / UpperLevel2 int 500 / 250 許容値チェックのために低速 MA に正のオフセット (ピップ単位) が追加されました。
LowerLevel1 / LowerLevel2 int 500 / 250 許容誤差チェックのために低速 MA から差し引かれた負のオフセット (ピップ単位)。
CandleType DataType 15m 時間枠 インジケーターが動作するローソク足シリーズ。

実装メモ

  • ストップロス注文とテイクプロフィット注文は、商品の PriceStep を使用してピップから価格単位に変換された距離を持つ StartProtection を通じてエミュレートされます。 5 桁の為替相場には、MetaTrader スタイルの *10 乗数が自動的に適用されます。
  • 内部キューには、shift ロジックの再現に必要なデータのみが保存されます。ローソク足の完全な履歴は蓄積されません。
  • 注文は BuyMarket / SellMarket で発行され、UI がアクティブなロット サイズを反映するように正規化された数量を継承します。
  • チャート出力では、移動平均と実行された取引の両方とともにローソク足シリーズを描画し、簡単に視覚的に検査できます。
  • プロジェクト ガイドラインに準拠するため、インライン コメントはすべて英語で記載されています。

使い方のヒント

  • MetaTrader で使用するのと同じローソク足の間隔を選択します。デフォルトの 15 分のシリーズは、CandleType を介して変更できます。
  • オフセット レベルを下げて信号の選択性を高めるか、オフセット レベルを大きくしてより広い「ニアミス」クロスオーバーを受け入れます。
  • CalculationBar0 に設定すると、戦略は最後に閉じたローソク足に反応します (遅延なし)。値を高くすると、追加の確認のためにトリガーがさらに過去に移動します。
  • 出口を手動または別のモジュールで管理する必要がある場合は、保護脚 (StopLossPips = 0TakeProfitPips = 0) を無効にします。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Two MA with four level bands: trades when fast MA crosses slow MA
/// or its offset bands. Exits on opposite crossover.
/// </summary>
public class TwoMaFourLevelBandsStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _bandMultiplier;

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

	public TwoMaFourLevelBandsStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastPeriod = Param(nameof(FastPeriod), 14)
			.SetDisplay("Fast MA", "Fast EMA period.", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 180)
			.SetDisplay("Slow MA", "Slow SMA period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR for band calculation.", "Indicators");

		_bandMultiplier = Param(nameof(BandMultiplier), 1.5m)
			.SetDisplay("Band Mult", "ATR multiplier for offset bands.", "Bands");
	}

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public decimal BandMultiplier
	{
		get => _bandMultiplier.Value;
		set => _bandMultiplier.Value = value;
	}

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

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, atr, ProcessCandle)
			.Start();

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

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

		if (_prevFast == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var bandOffset = atrVal * BandMultiplier;

		// Check crossovers at multiple band levels
		var bullish = false;
		var bearish = false;

		// Main line cross
		if (_prevFast <= _prevSlow && fastVal > slowVal) bullish = true;
		if (_prevFast >= _prevSlow && fastVal < slowVal) bearish = true;

		// Upper band cross
		if (_prevFast <= _prevSlow + bandOffset && fastVal > slowVal + bandOffset) bullish = true;
		if (_prevFast >= _prevSlow + bandOffset && fastVal < slowVal + bandOffset) bearish = true;

		// Lower band cross
		if (_prevFast <= _prevSlow - bandOffset && fastVal > slowVal - bandOffset) bullish = true;
		if (_prevFast >= _prevSlow - bandOffset && fastVal < slowVal - bandOffset) bearish = true;

		// Upper band 2
		if (_prevFast <= _prevSlow + bandOffset * 2 && fastVal > slowVal + bandOffset * 2) bullish = true;
		if (_prevFast >= _prevSlow + bandOffset * 2 && fastVal < slowVal + bandOffset * 2) bearish = true;

		// Lower band 2
		if (_prevFast <= _prevSlow - bandOffset * 2 && fastVal > slowVal - bandOffset * 2) bullish = true;
		if (_prevFast >= _prevSlow - bandOffset * 2 && fastVal < slowVal - bandOffset * 2) bearish = true;

		// Exit
		if (Position > 0 && bearish)
		{
			SellMarket();
			_entryPrice = 0;
		}
		else if (Position < 0 && bullish)
		{
			BuyMarket();
			_entryPrice = 0;
		}

		// Entry
		if (Position == 0)
		{
			if (bullish)
			{
				_entryPrice = candle.ClosePrice;
				BuyMarket();
			}
			else if (bearish)
			{
				_entryPrice = candle.ClosePrice;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}