GitHub で見る

新しいFSCEA戦略

概要

新しい FSCEA 戦略は、元の MetaTrader 4 エキスパート アドバイザー new_fscea.mq4 から移植された MACD ベースのトレンド追跡システムです。この戦略は、古典的な MACD クロスオーバー確認と EMA スロープ フィルター、静的なテイクプロフィット ターゲット、オープン ポジションを管理するためのトレーリング ストップを組み合わせたものです。一度に単一のシンボルを取引し、市場でポジションを 1 つだけオープンします。

取引ロジック

ロングエントリー

  • MACD メインラインはゼロを下回っていますが、現在閉じているローソク足のシグナルラインを上回っています。
  • 前のローソク足にはまだシグナルラインの下に MACD のラインがありました (クロスオーバーを確認します)。
  • MACD ラインの絶対値が OpenLevelPoints のしきい値 (価格ステップごとに調整) を超えています。
  • シフトされた EMA の傾きは正です (EMA_shifted_now > EMA_shifted_previous)。
  • 現在募集中のポジションはありません。

ショートエントリー

  • MACD メインラインはゼロの上にありますが、現在閉じているローソク足のシグナルラインの下で交差しています。
  • 前のローソク足ではまだシグナルラインの上に MACD ラインがありました。
  • MACD のメインラインが OpenLevelPoints のしきい値を超えています (価格ステップによって調整されます)。
  • シフトされた EMA の傾きは負です (EMA_shifted_now < EMA_shifted_previous)。
  • 現在募集中のポジションはありません。

長い出口

  • MACD がゼロ以上の状態で信号線を下回り、MACD の値が CloseLevelPoints のしきい値を超えるとトリガーされます。
  • または、ローソク足の高値が仮想テイクプロフィットレベル(entry + TakeProfitPoints * priceStep)に達したとき。
  • または、ローソク足の安値がトレーリングストップレベルに達したとき(価格が有利に動くと動的に更新されます)。

短い出口

  • MACD がゼロ未満のまま信号線の上を横切り、MACD の絶対値が CloseLevelPoints のしきい値を超えるとトリガーされます。
  • または、ローソク足の安値が仮想テイクプロフィットレベル(entry - TakeProfitPoints * priceStep)に達したとき。
  • または、ローソク足の高値がトレーリングストップレベルに達したとき(価格が有利に動くと動的に更新されます)。

リスク管理

  • テイクプロフィットは商品ポイントで表され、Security.PriceStepを乗じて価格に変換されます。
  • トレーリングストップはポイント単位で機能し、変動利益がトレーリング距離よりも大きくなると引き締められます。
  • MT4 エキスパートアドバイザーの動作を反映して、いつでもオープンできるポジションは 1 つだけです。
  • 位置保護は、組み込みの StartProtection() ヘルパーを通じて有効になります。

インジケーター

  • MACD (12, 26, 9) – メインのクロスオーバー エンジン。ヒストグラムの大きさは、開始閾値と終了閾値を提供します。
  • EMA (TrendPeriod) – 終値に適用されます。スロープ比較では、構成可能なシフト (TrendShift) を使用して MT4 ma_shift パラメーターをエミュレートします。

パラメーター

パラメータ デフォルト 説明
TakeProfitPoints 300 利益目標までの距離 (ポイント単位)。シンボル価格ステップを使用して価格に変換されます。
TrailingStopPoints 20 トレーリングストップのサイズ (ポイント単位)。取引がこの距離を超えて有利になった場合にのみ有効になります。
OpenLevelPoints 3 新しい取引が許可される前に、最小 MACD マグニチュード (ポイント) が必要です。
CloseLevelPoints 2 MACD クロスオーバーを介して取引を終了するには、MACD マグニチュード (ポイント) が必要です。
TrendPeriod 10 EMA トレンド フィルターの長さ。
TrendShift 2 傾きを評価するときに EMA に適用される水平方向のシフト (バー単位)。値が大きいほどトレンドの確認が遅れます。
TradeVolume 0.1 成行注文とともに送信されるデフォルトの注文量。
CandleType 1時間枠 インジケーターの計算に使用されるローソク足のタイプ。ご希望の時間枠に合わせて変更可能です。

実装メモ

  • この戦略は、ロジックを MT4 バージョンに近づけるために、完成したキャンドルのみを処理します。
  • EMA シフトは、インジケーター出力をバッファリングし、TrendShift バー離れた値を比較することによってエミュレートされます。
  • トレーリング ストップとテイク プロフィットは、高レベルの API 要件内に収まるように仮想的に実装されます (実際のストップ/指値注文はありません)。
  • このコードは、リポジトリ ガイドラインに準拠するために、高レベルのキャンドル サブスクリプション API (SubscribeCandles().BindEx(...)) のみに依存しています。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// NewFSCEA: EMA trend with RSI momentum and ATR stops.
/// </summary>
public class NewFsceaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevClose;
	private decimal _entryPrice;

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

		_emaLength = Param(nameof(EmaLength), 20)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

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

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

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

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

		_prevClose = 0;
		_entryPrice = 0;
	}

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

		_prevClose = 0;
		_entryPrice = 0;

		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, rsi, atr, ProcessCandle)
			.Start();

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

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

		var close = candle.ClosePrice;

		if (_prevClose == 0 || atrVal <= 0)
		{
			_prevClose = close;
			return;
		}

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 75)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 25)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		if (Position == 0)
		{
			if (close > emaVal && _prevClose <= emaVal && rsiVal > 50)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (close < emaVal && _prevClose >= emaVal && rsiVal < 50)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevClose = close;
	}
}