Auf GitHub ansehen

NNFX Autohandelsstrategie

Überblick

Die NNFX Auto Trade Strategy repliziert den Risikodimensionierungs- und Management-Workflow des ursprünglichen NNFX MetaTrader 4-Panels innerhalb von StockSharp. Anstelle einer grafischen Oberfläche stellt die Strategie manuelle Befehle über Parameter bereit. Händler können Long- oder Short-Einträge anfordern, das Engagement sofort abflachen oder Breakeven- und Trailing-Logik anwenden, die den Expertenberater widerspiegelt.

Hauptmerkmale:

  • ATR-gesteuerte Volatilitätsgrößenbestimmung mit einer optionalen Überschreibung für manuelle Stop- und Take-Profit-Distanzen.
  • Positionseinträge sind in zwei Teile aufgeteilt: einen mit einem prognostizierten Ziel und einen Läufer, der für die diskretionäre Verwaltung offen bleibt.
  • Breakeven- und Trailing-Befehle werden bei Bedarf ausgeführt und aktualisieren die gespeicherten Stop-Level, ohne automatisch bei jedem Balken ausgelöst zu werden.
  • Bei der Berechnung des monetären Risikos kann zusätzliches Kapital einbezogen werden, das dem Verhalten des MQL-Skripts entspricht.

Handelslogik

  1. ATR-Sammlung – Die Strategie abonniert den konfigurierten Kerzentyp und verarbeitet einen Average True Range-Indikator. Wenn UsePreviousDailyAtr aktiviert ist, kopiert es den ATR-Wert des Vortages während der ersten 12 Stunden des neuen Handelstages und imitiert so das ursprüngliche Skript.
  2. Risikobasierte Dimensionierung – Bei einem manuellen Buy- oder Sell-Befehl berechnet die Engine das monetäre Risiko pro Einheit anhand der Schutzstoppdistanz und wandelt den gewünschten Risikoprozentsatz in ein ausführbares Volumen um.
  3. Positionssplit – Das Einstiegsvolumen wird in zwei Hälften geteilt. Die erste Hälfte wird automatisch liquidiert, wenn das projizierte Ziel erreicht wird, während die zweite Hälfte so lange verbleibt, bis der Händler weitere Befehle erteilt.
  4. Stopp-Handhabung – Die anfänglichen Stopps werden intern gespeichert und bei jeder fertigen Kerze ausgewertet. Manuelle Befehle können den Stopp auf die Gewinnschwelle bringen oder ihn gemäß der NNFX-Trailing-Formel erhöhen.
  5. AusstiegskontrollenCloseAll glättet das Buch sofort, während Stop-Verletzungen oder Teilziele Marktausstiege auslösen, die die berechneten Volumina respektieren.

Parameter

Parameter Standard Beschreibung
RiskPercent 2.0 Prozentsatz des Kontokapitals (plus AdditionalCapital), das pro Trade riskiert wird.
AdditionalCapital 0 Bei der Größenbestimmung von Positionen wird der Eigenkapitalbasis zusätzliches Kapital hinzugefügt.
UseAdvancedTargets false Ändert die Risikoentfernungen von ATR-Vielfachen auf manuelle Pip-Werte.
AdvancedStopPips 0 Stoppdistanz in Pips, wenn der erweiterte Modus aktiv ist.
AdvancedTakeProfitPips 0 Zielentfernung in Pips für den teilweisen Ausgang, wenn der erweiterte Modus aktiv ist.
UsePreviousDailyAtr true Kopiert den vorherigen Tageswert ATR während der ersten 12 Stunden eines neuen Tages.
AtrPeriod 14 ATR Lookback-Länge.
AtrStopMultiplier 1.5 Bei der Berechnung der Stoppentfernung wird ein Multiplikator auf ATR angewendet.
AtrTakeProfitMultiplier 1.0 Bei der Berechnung der Take-Profit-Distanz wird ein Multiplikator auf ATR angewendet.
CandleType 1 Minute Kerzentyp, der für ATR und die Preisüberwachung verwendet wird.
BuyCommand false Manuelles Flag – auf true gesetzt, um einen langen Eintrag anzufordern. Wird automatisch zurückgesetzt.
SellCommand false Manuelles Flag – auf true gesetzt, um einen kurzen Eintrag anzufordern. Wird automatisch zurückgesetzt.
BreakevenCommand false Manuelle Flagge – Bewegen Sie den Schutzstopp auf den Einstiegspreis. Wird automatisch zurückgesetzt.
TrailingCommand false Manuelle Markierung – wenden Sie die NNFX-Nachlaufformel einmal an. Wird automatisch zurückgesetzt.
CloseAllCommand false Manuelle Markierung – alle offenen Positionen sofort schließen. Wird automatisch zurückgesetzt.

Nutzungshinweise

  • Die Strategie erfordert ein verbundenes Portfolio und Sicherheit mit gültigen Step-, StepPrice- und VolumeStep-Metadaten für genaue Risikoberechnungen.
  • Befehle werden für fertige Kerzen ausgewertet, daher muss nach dem Umschalten eines manuellen Parameters ein neuer Balken (oder eine Kerzenaktualisierung) empfangen werden.
  • Wenn Sie erweiterte Entfernungen verwenden, stellen Sie sicher, dass sowohl AdvancedStopPips als auch AdvancedTakeProfitPips ausgefüllt sind. andernfalls bleiben die ATR-basierten Standardeinstellungen in Kraft.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// NNFX Auto Trade strategy: ATR-based trend following with EMA filter.
/// Enters on EMA direction with ATR-based trailing stop management.
/// </summary>
public class NnfxAutoTradeStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMultiplier;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _entryPrice;
	private decimal _bestPrice;
	private bool _wasBullish;
	private bool _hasPrevSignal;
	private int _candlesSinceTrade;

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

	public NnfxAutoTradeStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(120).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 100)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period", "Indicators");
		_atrMultiplier = Param(nameof(AtrMultiplier), 2.5m)
			.SetDisplay("ATR Multiplier", "ATR multiplier for stop", "Risk");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 12)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_entryPrice = 0m;
		_bestPrice = 0m;
		_wasBullish = false;
		_hasPrevSignal = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_entryPrice = 0;
		_bestPrice = 0;
		_hasPrevSignal = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, atr, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;
		var stopDist = atrValue * AtrMultiplier;
		var isBullish = close > emaValue;

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		// Trailing stop check
		if (Position > 0)
		{
			if (close > _bestPrice) _bestPrice = close;
			if (_bestPrice - close > stopDist)
			{
				SellMarket();
				_entryPrice = 0;
				_bestPrice = 0;
				_candlesSinceTrade = 0;
				return;
			}
		}
		else if (Position < 0)
		{
			if (close < _bestPrice) _bestPrice = close;
			if (close - _bestPrice > stopDist)
			{
				BuyMarket();
				_entryPrice = 0;
				_bestPrice = 0;
				_candlesSinceTrade = 0;
				return;
			}
		}

		// Entry signals
		if (_hasPrevSignal && isBullish != _wasBullish && _candlesSinceTrade >= SignalCooldownCandles)
		{
			if (isBullish && Position <= 0)
			{
				BuyMarket();
				_entryPrice = close;
				_bestPrice = close;
				_candlesSinceTrade = 0;
			}
			else if (!isBullish && Position >= 0)
			{
				SellMarket();
				_entryPrice = close;
				_bestPrice = close;
				_candlesSinceTrade = 0;
			}
		}

		_wasBullish = isBullish;
		_hasPrevSignal = true;
	}
}