GitHub で見る

FXF セーフ トレンド スカルプ V1 (C#)

FXF Safe Trend Scalp V1 戦略は、ZigZag ベースのトレンドラインからのブレイクアウトをトレードし、元の MetaTrader 4 エキスパート アドバイザーの動作を反映しています。現在の価格と、最近のジグザグピボットから構築された動的レジスタンス/サポートラインとの間の距離を観察し、取引を単純な移動平均のペアに合わせます。保護的なストップロス、テイクプロフィット、および変動利益エグジットは、ソースコードから資金管理ルールを再現します。

取引ロジック

  1. ジグザグトレンドライン
    • 手動の ZigZag 検出器は、設定可能な深さ、偏差、バックステップ パラメーターを使用して、交互のスイングの高値と安値を検索します。
    • 最後の 4 つのスイング高値がアクティブなレジスタンス ラインを定義し、最後の 4 つのスイング安値がアクティブなサポート ラインを定義します。この戦略は、これらのラインを現在のバーに継続的に外挿します。
    • 終値が固定オフセット(デフォルトでは 10 ポイント)内のラインに近づくと、エントリーシグナルが準備されます。
  2. 移動平均フィルター
    • 速い単純移動平均 (長さ 2) と遅い単純移動平均 (長さ 50) がトレンドをフィルターします。
    • ショート ポジションには低速 MA を下回る高速 MA が必要ですが、ロング ポジションには低速 MA を上回る高速 MA が必要です。
  3. 注文の実行
    • シグナルは、MetaTrader バージョンの「新しいバー」ロジックに一致して、次に完成したローソク足で保存およびアクティブ化されます。
    • ポジションをオープンする前に、ストラテジーはスプレッドが設定された最大値を超えていないこと、および現在オープンなポジションがないことを確認します。
  4. リスク管理
    • ストップロスとテイクプロフィットの距離はポイントで表現され、注文が約定された直後に適用されます。
    • 変動利益ターゲットは、未実現利益 (価格単位×出来高) がロットごとに設定された報酬を超えるとポジションをクローズします。

パラメーター

名前 説明
Candle Type シグナル生成に使用されるタイムフレーム。
Volume 各エントリーで送信された取引高。
ZigZag Depth 確認されたピボット間のバーの最小数。
ZigZag Deviation (pts) 方向が変わる前のポイント単位の最小価格変動。
ZigZag Backstep 逆のピボットを受け入れる前にバーが必要です。
Trend Offset (pts) シグナルをトリガーするトレンドラインからの距離。
Fast MA Length 高速単純移動平均の長さ。
Slow MA Length 遅い単純移動平均の長さ。
Max Spread (pts) 最大許容スプレッド (ポイント単位で表現)。
Stop Loss (pts) エントリー価格から測定される保護停止距離。
Take Profit (pts) エントリー価格から測定される利益目標距離。
Profit Target per Lot ポジションを決済するには変動利益(価格単位×数量)が必要です。

注意事項

  • 一度に保持できるポジションは 1 つだけです。取引が開かれている間、シグナルは無視されます。
  • スプレッド フィルターは最良の買値/売値に依存するため、戦略はレベル 1 の情報を提供するデータ ソースに接続する必要があります。
  • 戦略の Python バージョンは、要求に応じて意図的に省略されています。

ファイル

  • CS/FXFSafeTrendScalpV1Strategy.cs – エキスパートアドバイザーの StockSharp 実装。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// FXF Safe Trend Scalp V1 strategy: SMA crossover with ATR volatility filter.
/// Enters long when fast SMA crosses above slow SMA and ATR confirms volatility.
/// Enters short when fast SMA crosses below slow SMA.
/// </summary>
public class FxfSafeTrendScalpV1Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _candlesSinceTrade;

	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 AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public FxfSafeTrendScalpV1Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 3)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between entries", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0m;
		_prevSlow = 0m;
		_hasPrev = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, atr, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_hasPrev)
		{
			var close = candle.ClosePrice;
			var longSignal = _prevFast <= _prevSlow && fast > slow && close > slow + atr * 0.25m;
			var shortSignal = _prevFast >= _prevSlow && fast < slow && close < slow - atr * 0.25m;

			if (_candlesSinceTrade >= SignalCooldownCandles)
			{
				if (longSignal && Position <= 0)
				{
					BuyMarket();
					_candlesSinceTrade = 0;
				}
				else if (shortSignal && Position >= 0)
				{
					SellMarket();
					_candlesSinceTrade = 0;
				}
			}
		}

		_prevFast = fast;
		_prevSlow = slow;
		_hasPrev = true;
	}
}