GitHub で見る

DLMv FX Fish Grid 戦略

概要

DLMv FX Fish Grid 戦略は、「FX Fish 2MA」オシレーターを中心に構築されたMetaTraderの元のエキスパートアドバイザーの動作を再現します。戦略は価格のFisher変換を評価し、移動平均で平滑化し、オシレーターがゼロの適切な側で平滑化された基準線を横切るときにポジションを開きます。ポジション管理はソースEAのグリッドのような動作を模倣します:追加エントリーは設定可能な距離でスペースが置かれ、保留中の指値注文を重ねることができ、保護的自動化がリスクコントロールを処理します。

取引ロジック

  1. インジケーター計算
    • CalculatePeriod ローソク足にわたる最高値と最安値がローリングレンジを定義します。
    • MT5インジケーターと同じ0.67平滑化係数を使用して、選択した価格(AppliedPrice)にFisher変換が適用されます。
    • Fisher値の単純移動平均(MaPeriod)がシグナル基準線を提供します。
  2. シグナル生成
    • ロングシグナル: 現在と前のFisher値がゼロ未満で、オシレーターが移動平均を上方にクロスする(前の値が平均未満、現在の値が平均超)。
    • ショートシグナル: 現在と前のFisher値がゼロ超で、オシレーターが移動平均を下方にクロスする(前の値が平均超、現在の値が平均未満)。
    • ReverseSignals を有効にするとシグナルを反転できます。
  3. 注文執行
    • 買い(または売り)シグナルが現れたとき、戦略はオプションで既存の反対エクスポージャーをクローズできます(CloseOpposite)。
    • 追加エントリーは合計数が MaxTrades に達するまで許可されます。各新規エントリーは最後の約定トレードからの DistancePips による最小間隔を守る必要があります。
    • オプションの指値注文(SetLimitOrders)は設定された間隔で待機中の買い注文/売り注文を配置し、元のEAの段階的なグリッドを再現します。
  4. リスク管理
    • 固定ストップロス、テイクプロフィット、トレーリングストップの値は StartProtection を通じて適用され、全てpipsで定義されます。
    • TimeLiveSeconds は、トレードが許可された有効期間より長く開いている場合に全エクスポージャーをクローズします。
    • 金曜日には取引を無効にできます(TradeOnFriday = false)。無効にすると、金曜日のローソク足が到着するとすぐに戦略はポジションをクローズし、保留中の注文をキャンセルします。

パラメーター

パラメーター 説明
OrderVolume 各エントリーの注文サイズ(ロット)。
StopLossPips エントリーからの保護ストップロスの距離。無効にするには0に設定。
TakeProfitPips テイクプロフィットレベルの距離。無効にするには0に設定。
TrailingStopPips トレーリングストップ距離(0でトレーリング無効化)。
TrailingStepPips トレーリングストップが引き締められるステップ。
MaxTrades 方向ごとの同時トレードの最大数。0 で制限なし。
DistancePips 連続エントリー間の最小距離とオプショングリッド注文の距離。
TradeOnFriday false の場合、戦略は金曜日の取引を停止しエクスポージャーを清算します。
TimeLiveSeconds ポジションが強制クローズされる前に開いたままでいられる最大時間(秒)。
ReverseSignals ロング/ショート条件を反転する。
SetLimitOrders DistancePips での追加待機指値注文を有効にする。
CloseOpposite 新しいトレードに入る前に反対のエクスポージャーをクローズする。
CalculatePeriod Fisher変換レンジのルックバック。
MaPeriod Fisher値に適用する移動平均の期間。
AppliedPrice Fisher変換で使用する価格ソース(close、open、high、low、median、typical、weighted)。
CandleType 戦略が処理するローソク足のデータタイプ/時間軸。

注意事項

  • ストップロス、テイクプロフィット、トレーリングストップの距離は、MQLバージョンの5桁pip論理に一致するよう、Security.PriceStep * 10 を使用してpipsから絶対価格オフセットに変換されます。
  • 指値注文は、シグナルがフリップしたとき、取引が一時停止されたとき、または時間/金曜日の保護がトリガーされたときに自動的にキャンセルされます。
  • Fisher変換は値の繰り返し検索を避け、代わりにオシレーターと基準線の前の読み取り値を格納して正確なクロス検出を行います。
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>
/// DLMv FX Fish Grid strategy. Uses Highest/Lowest range with Fisher transform crossover.
/// </summary>
public class DlmvFxFishGridStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _period;

	private decimal? _prevFish;
	private decimal _prevValue;

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

	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

	public DlmvFxFishGridStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_period = Param(nameof(Period), 20)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Lookback period for high/low range", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFish = null;
		_prevValue = 0m;
	}

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

		_prevFish = null;
		_prevValue = 0m;

		var highest = new Highest { Length = Period };
		var lowest = new Lowest { Length = Period };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var range = high - low;
		var midPrice = (candle.HighPrice + candle.LowPrice) / 2m;

		var normalized = range != 0m ? (midPrice - low) / range : 0.5m;
		var value = 0.66m * (normalized - 0.5m) + 0.67m * _prevValue;
		value = Math.Min(Math.Max(value, -0.999m), 0.999m);

		var ratio = (double)((1m + value) / (1m - value));
		var fish = 0.5m * (decimal)Math.Log(ratio);

		_prevValue = value;

		if (_prevFish == null)
		{
			_prevFish = fish;
			return;
		}

		// Fisher crosses zero from below → buy
		if (_prevFish.Value < 0m && fish >= 0m && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Fisher crosses zero from above → sell
		else if (_prevFish.Value > 0m && fish <= 0m && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevFish = fish;
	}
}