GitHub で見る

フランクス 4 時間指値注文戦略

概要

フランクス 4 時間指値注文戦略 は、MetaTrader 4 エキスパート アドバイザーを MQL/7684/Franks_4hour_limit_orders.mq4 から StockSharp の高レベル API に移植します。オリジナルの EA は、アレクサンダー エルダーのトリプル スクリーンのアイデアを組み合わせたものです。MACD ヒストグラム (OsMA) とフォース インデックスを使用して 4 時間足チャートの勢いを評価し、前のローソク足の極値付近に逆張りの指値注文を配置します。 StockSharp 実装は、リポジトリ ガイドライン (タブ、高レベルの API、カスタム コレクションなし) に従いながら、このマルチ インジケーター ロジックを維持し、明確にするために英語で広範なインライン コメントを追加します。

取引ロジック

  1. データ ソース – この戦略は、デフォルトで 4 時間足のローソク足を設定する構成可能なローソク足タイプをサブスクライブします。すべての計算は、MT4 エキスパートの動作と一致するように、完了したローソク足に対してのみ実行されます。
  2. インジケーター – 2 つの管理インジケーターが使用されます。
    • MovingAverageConvergenceDivergenceSignal(12, 26, 9) は、MACD ラインと信号ラインの両方を提供します。それらの差により、EA で使用される OsMA ヒストグラムが再作成されます。
    • ForceIndex(24) は、前のローソクの力を測定します。最終的な指標値のみが考慮されます。
  3. 歴史的背景 – EA では、インジケーターの傾きを決定するために 2 つの完成したローソク足が必要です。ポートは、この要件を反映するために、以前の OsMA 値、以前のフォース インデックス値、および以前のローソク足の高値/安値を保存します。
  4. 売り設定 – OsMA ヒストグラムが増加し (OsMA[1] > OsMA[2])、前のフォース インデックス値が負の場合、ロボットは逆張りの売り指値注文を計画します。
    • 基準価格は、直前のローソク足の高値に 1 ポイントを加えたものです。
    • 現在の入札に対して 16 ピップの安全バッファ (設定可能) が適用されます。目標価格は基準価格と Bid + buffer の間の最大値となります。
    • ストップロスとテイクプロフィットの価格は、設定されたピップ距離 (デフォルトでは 35 ピップスと 150 ピップス) を使用して商品価格ステップに合わせられます。
  5. 買いのセットアップ – OsMA ヒストグラムが減少し (OsMA[1] < OsMA[2])、以前のフォース インデックスがプラスの場合、戦略は市場を下回る買い指値注文を準備します。
    • 基準価格は、直前のローソク足の安値から 1 ポイントを引いた値です。
    • このアルゴリズムは、現在のアスクに対して同じ 16 ピップのバッファを適用し、基準価格と Ask - buffer の間の最小値を選択します。
  6. 未決注文のメンテナンス – 約定前に OsMA の傾きが逆方向に反転した場合、対応する未決注文はキャンセルされます。片側が埋まると、二重露光を避けるために反対側の未決注文が削除されます。
  7. ポジション管理 – 実行時に約定価格が保存され、事前計算されたストップロスとテイクプロフィットのレベルが有効になります。この戦略は、価格がエントリーとトレーリング距離を超えて進んだ場合にのみ保護ストップを有利な方向に移動させる、ピップベースのトレーリングストップ (デフォルトでは 30 ピップ) も実装しています。
  8. 出口 – 完了したすべてのキャンドルで保護命令が監視されます。ローソク足の安値がストップに接触するか、ローソク足の高値がターゲットに達すると、ロングポジションは閉じられます。ショート ポジションはミラーリング ルールを使用します。

パラメーター

パラメータ デフォルト 説明
OrderVolume 1 未決の指値注文に使用される固定量。
StopLossPips 35 エントリー価格と保護ストップの間の距離(ピップ単位)。
TakeProfitPips 150 エントリー価格とテイクプロフィットレベルの間の距離(ピップ単位)。
TrailingStopPips 30 価格が十分に大きく動いた後に利益を確定させるトレーリングストップまでの距離(ピップ単位)。
EntryBufferPips 16 現在の市場価格と未決注文の間の最小ギャップ (ピップ単位)。
PipSize 0.0001 価格変換に使用されるピップサイズ。デフォルトは 0.0001 ですが、エキゾチックなシンボルに合わせることができます。
CandleType 4時間枠 戦略的に加工されたキャンドルシリーズ。

ファイル

  • CS/Franks4HourLimitOrdersStrategy.cs – 詳細な英語コメントを含むメインの C# 実装。
  • README.md – アルゴリズムの英語の説明。
  • README_ru.md – ロシア語のドキュメント。
  • README_zh.md – 中国語のドキュメント。

実装メモ

  • この戦略は、高レベルの API (SubscribeCandles、インジケーター バインディング、コンビニエンス オーダー ヘルパー) のみに依存します。
  • 無効なレベルを避けるために、すべての価格計算は商品の価格ステップに合わせて行われます。
  • 状態変数には、カスタム コレクションを禁止するリポジトリ ルールに従って、必要な履歴データのみが保存されます。
  • ストップロス、テイクプロフィット、およびトレーリングストップの管理は、MT4 トレーリング動作をエミュレートするためにローソク足処理ルーチン内で実行されます。
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>
/// Franks 4H strategy - EMA crossover with momentum filter.
/// Buys on bullish EMA crossover with positive momentum.
/// Sells on bearish EMA crossover with negative momentum.
/// </summary>
public class Franks4HourLimitOrdersStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _momentumPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Franks4HourLimitOrdersStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_momentumPeriod = Param(nameof(MomentumPeriod), 10)
			.SetDisplay("Momentum", "Momentum period", "Indicators");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }

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

		_hasPrev = false;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var momentum = new Momentum { Length = MomentumPeriod };

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

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

		if (!_hasPrev)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fast > slow;
		var crossDown = _prevFast >= _prevSlow && fast < slow;

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

		_prevFast = fast;
		_prevSlow = slow;
	}
}