GitHub で見る

シンプルなFXクロスオーバー戦略

概要

  • MetaTrader 4 エキスパート アドバイザ simplefx2.mq4 (Simple FX 2.0) の上位ポート。
  • 完成したローソク足の速い単純移動平均と遅い単純移動平均の間のクロスオーバーを取引します。
  • 1 つのポジションのみをオープンのままにし、支配的なトレンドが反転すると反転します。

取引ロジック

  1. 構成可能なタイムフレームパラメータを使用してローソク足を構築します。
  2. ローソク足終値の 2 つの単純移動平均 (高速と低速) を計算します。
  3. 現在と前のローソク足の両方が遅い MA を上回る速い MA を示している場合、強気トレンドを確認します。両方のローソク足が遅い MA を下回る速い MA を示している場合、弱気トレンドを確認します。
  4. 確認されたトレンドが保存されたトレンドの状態と異なる場合は、反対のポジションを閉じ、構成されたボリュームを使用して新しい方向に成行注文を直ちにオープンします。
  5. 価格ステップで表現されるオプションのストップロスおよびテイクプロフィット保護を有効にすることができます。彼らは、StockSharp の組み込み保護サービスを使用して、MT4 リスク設定をエミュレートします。

この戦略は、元のエキスパートアドバイザーの動作に近く保つために、バー内ティックではなく完成したローソク足のみを処理します。すべてのクロスオーバーの決定を監査できるように、新しいエントリごとにログが提供されます。

パラメーター

名前 説明 デフォルト 最適化
ShortPeriod 高速単純移動平均の長さ。 50 10→150ステップ5
LongPeriod 遅い単純移動平均の長さ。 200 50→400ステップ10
Volume 各市場取引で送信された注文量。 0.1 0.1→2ステップ 0.1
StopLossPoints 商品の価格ステップにおける保護停止距離 (0 無効)。 0
TakeProfitPoints 商品価格ステップでの利益目標距離 (0 無効)。 0
CandleType 分析に使用されるローソク足の時間枠。 1時間

注意点とMT4版との違い

  • MT4 永続ファイル (simplefx.dat) は必要ありません。最後のトレンドの方向は、戦略の状態によってメモリ内で追跡されます。
  • StockSharp ではルーティングの処理方法が異なるため、元のエキスパート アドバイザーからのスリッページ、注文コメント、マジック ナンバー、矢印の色のオプションは公開されません。
  • ストップロスとテイクプロフィットの距離は 価格ステップ (商品ティック) で解釈されます。ブローカーの pip 定義と一致するように調整してください。
  • いつでもオープンできるポジションは 1 つだけです。この戦略は方向を切り替える前に ClosePosition() に依存し、ロングトレードとショートトレードの間で確実に反転します。

使用法

  1. 戦略を証券/商品にアタッチし、希望のローソク足の時間枠を設定します。
  2. 移動平均期間とリスクパラメータを設定します。
  3. 戦略を開始します。ローソク足を購読し、トレンド状態を管理し、2 つの連続するローソク足でクロスオーバーが確認されたときに成行注文を送信します。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simple FX crossover strategy.
/// Uses fast and slow SMA crossover for trend detection.
/// Buys on golden cross, sells on death cross.
/// </summary>
public class SimpleFxCrossoverStrategy : Strategy
{
	private readonly StrategyParam<int> _shortPeriod;
	private readonly StrategyParam<int> _longPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevShort;
	private decimal _prevLong;
	private bool _hasPrev;

	public int ShortPeriod { get => _shortPeriod.Value; set => _shortPeriod.Value = value; }
	public int LongPeriod { get => _longPeriod.Value; set => _longPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public SimpleFxCrossoverStrategy()
	{
		_shortPeriod = Param(nameof(ShortPeriod), 10)
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");

		_longPeriod = Param(nameof(LongPeriod), 30)
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevShort = 0m;
		_prevLong = 0m;
		_hasPrev = false;
	}

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

		_hasPrev = false;

		var fast = new SimpleMovingAverage { Length = ShortPeriod };
		var slow = new SimpleMovingAverage { Length = LongPeriod };

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

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

		if (!_hasPrev)
		{
			_prevShort = fast;
			_prevLong = slow;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevShort <= _prevLong && fast > slow;
		var crossDown = _prevShort >= _prevLong && fast < slow;

		if (crossUp && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevShort = fast;
		_prevLong = slow;
	}
}