GitHub で見る

ニーナ EA 戦略

概要

Nina EA 戦略は、MetaTrader 4 エキスパート「NinaEA」から変換された 1 ポジションのトレンド フォロワーです。オリジナルのロボットは NINA という名前のカスタム指標を使用し、指標の強気バッファと弱気バッファの差がゼロを上回るか下回るたびに取引します。 StockSharp バージョンでは、カスタム インジケーターが組み込みの SuperTrend インジケーターに置き換えられ、個別の強気バッファーと弱気バッファーも公開されます。 SuperTrend 方向の反転は、ゼロクロス代理として機能します。トレンドが強気になった場合、戦略は買いになり、弱気になった場合、戦略は売りになります。

この戦略では、オープン ポジションは常に最大 1 つだけ維持されます。反対のシグナルは既存のポジションを即座に決済し、新しい方向で新しい取引を確立します。価格ポイントで表されるオプションのストップロスを有効にして、元の「ストップロス」入力を模倣することができます。

取引ロジック

  1. 設定されたローソク足シリーズをサブスクライブし、指定された ATR 期間と乗数を使用して SuperTrend を計算します。
  2. シグナルに反応する前に、戦略とインジケーターの両方が形成されるまで待ちます。
  3. 完成したキャンドルごとに:
    • 保護的なストップ価格に触れた場合は、市場でオープンポジションを終了します。
    • SuperTrend が弱気から強気に反転した場合は、短期エクスポージャーを閉じて、設定された数量で購入します。
    • SuperTrend が強気から弱気に反転した場合は、ロングエクスポージャーを閉じて、設定されたボリュームで売ります。
    • 次の反転を検出するために、現在の SuperTrend 方向を保存します。

このロジックは、MetaTrader の専門家の動作を再現しており、nina = Buffer0 - Buffer1 と符号の変更によって退店と新規参入の両方が引き起こされます。

ポジションとリスクの管理

  • 一度にアクティブにできるポジションは 1 つだけです。すべての取引は複数の注文を重ねるのではなく、方向を逆にします。
  • 価格ポイントのオプションのストップロスは、約定価格から計算されます。ロングトレードの場合、ストップはエントリーの下に配置され、ショートトレードの場合、ストップはエントリーの上に配置されます。パラメータをゼロに設定すると、停止が無効になります。
  • StartProtection() は、必要に応じて組み込みの StockSharp 保護を構成できるように呼び出されます。

パラメーター

パラメータ デフォルト 説明
Volume 0.1 新しいエントリごとに使用される注文量。
AtrPeriod 10 ATR 期間が SuperTrend 計算に渡されました (元の PeriodWATR をマップします)。
AtrMultiplier 1 SuperTrend の ATR 乗数 (元の Kwatr をマップします)。
StopLossPoints 0 価格ポイントでのオプションのストップロス距離。ゼロはストップを無効のままにし、ストップ価格なしで成行注文を送信した MetaTrader コードと同じです。
CandleType TimeFrame(1 minute) インジケーターと取引ロジックをフィードするキャンドル シリーズ。

変換メモ

  • MetaTrader の専門家はカスタムの NINA インジケーターを利用しました。その 2 つのバッファーは、取引においてその差と符号のみが重要であるため、強気/弱気の SuperTrend ラインとして解釈されました。 SuperTrend は、IsUpTrend フラグを通じて同じ情報を公開するため、手動のバッファ処理を必要としない適切な高レベルの置き換えとなります。
  • 注文クローズのロジックは、元のスクリプトの OrdersTotal() ループを反映しています。トレンド反転は、まず現在のポジションをフラットにし、次に新しい方向に取引を開始します。
  • 未使用の MetaTrader 入力 (highlowcbarsfrommaPSMAspreadSlippage) は、元のファイルの取引ルールに影響を与えないため省略されます。

使用のヒント

  1. 戦略を証券に添付し、MetaTrader のテストに一致するローソク足の時間枠を構成します。
  2. ATR の期間と乗数を調整して、元のインジケーターの動作を再現します。
  3. 厳密なリスク制限が必要な場合は、StopLossPoints を増やします。それ以外の場合は、純粋な信号ベースの終了の場合はゼロのままにしておきます。
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>
/// SuperTrend-based strategy from NinaEA.
/// Trades on SuperTrend direction flips - buy on up trend, sell on down trend.
/// </summary>
public class NinaEaStrategy : Strategy
{
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMultiplier;
	private readonly StrategyParam<DataType> _candleType;

	private bool? _previousTrendUp;

	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public NinaEaStrategy()
	{
		_atrPeriod = Param(nameof(AtrPeriod), 10)
			.SetDisplay("ATR Period", "ATR length for SuperTrend", "Indicators");

		_atrMultiplier = Param(nameof(AtrMultiplier), 1m)
			.SetDisplay("ATR Multiplier", "SuperTrend multiplier", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
		_previousTrendUp = null;
	}

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

		_previousTrendUp = null;

		var superTrend = new SuperTrend
		{
			Length = AtrPeriod,
			Multiplier = AtrMultiplier
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(superTrend, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue superTrendValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!superTrendValue.IsFinal)
			return;

		var stValue = (SuperTrendIndicatorValue)superTrendValue;
		var isUpTrend = stValue.IsUpTrend;

		if (_previousTrendUp is bool prevUp)
		{
			// Trend flipped to up - go long
			if (isUpTrend && !prevUp)
			{
				if (Position < 0)
					BuyMarket();
				if (Position <= 0)
					BuyMarket();
			}
			// Trend flipped to down - go short
			else if (!isUpTrend && prevUp)
			{
				if (Position > 0)
					SellMarket();
				if (Position >= 0)
					SellMarket();
			}
		}

		_previousTrendUp = isUpTrend;
	}
}