Auf GitHub ansehen

AIS4-Handelsmaschinenstrategie

Überblick

Die AIS4 Trade Machine Strategy ist ein manueller Handelsassistent, der den ursprünglichen Expertenberater „AIS4 Trade Machine“ von MetaTrader auf StockSharp portiert. Es behält den Ein-Positions-Workflow des Skripts bei: Der Operator gibt absolute Stop-Loss- und Take-Profit-Werte an, erteilt einen Befehl und die Strategie berechnet die Handelsgröße auf der Grundlage des aktuellen Kontokapitals und der Instrumentenspezifikationen. Nachdem die Marktorder ausgeführt wurde, übermittelt die Strategie sofort gepaarte Schutzorder (Stopp + Limit), sodass die angeforderten Risiko- und Ertragsniveaus auf der Börsenseite durchgesetzt werden.

Die Strategie generiert keine automatische Signale. Es ist für eine diskretionäre Ausführung konzipiert, bei der der Benutzer entscheidet, wann und wo er eine Position eingibt oder ändert.

Manueller Arbeitsablauf

  1. Stellen Sie sicher, dass das angeschlossene Instrument PriceStep, StepPrice, VolumeStep, MinVolume und MaxVolume bereitstellt. Sie müssen das Preisrisiko in Kontraktgröße umrechnen und das Ordervolumen an Börsenlimits anpassen.
  2. Stellen Sie vor dem Senden eines Befehls StopPrice und TakePrice auf die absoluten Preisniveaus ein, die Sie verwenden möchten.
  3. Ändern Sie Command in Buy oder Sell. Die Strategie:
    • Überprüft, ob keine andere Position offen ist.
    • Überprüft, ob der angeforderte Stop-Loss und Take-Profit den Mindest-Tick-Abstand einhalten.
    • Berechnet das Risikobudget aus OrderReserve × aktuellem Portfolio-Eigenkapital und stellt sicher, dass die Eigenkapitalreserve (AccountReserve) eingehalten wird.
    • Schätzt das Ordervolumen aus der Stop-Distanz und dem Tick-Wert des Instruments.
    • Sendet die Marktorder und übermittelt dann gepaarte Schutzaufträge (SellStop+SellLimit für Long-Positionen, BuyStop+BuyLimit für Short-Positionen).
  4. Command wird automatisch auf Wait zurückgesetzt, nachdem die Aktion verarbeitet wurde, sodass versehentliche doppelte Ausführungen vermieden werden.

Verwaltung einer bestehenden Position

  • Legen Sie neue Preisniveaus fest (verwenden Sie 0, um den aktuellen Wert beizubehalten) und ändern Sie Command auf Modify. Die Strategie storniert die vorherigen Schutzanordnungen und ersetzt sie durch neue, die den aktualisierten Preisen entsprechen.
  • Wechseln Sie von Command zu Close, um die aktive Position zum Marktwert zu liquidieren und alle Schutzaufträge zu stornieren.

Logik des Risikomanagements

  • AccountReserve – hält einen Bruchteil des Spitzenkapitals unberührt. Der Handel wird blockiert, solange das verfügbare Eigenkapital (equity - peak_equity × (1 - AccountReserve)) kleiner als das angeforderte Risikobudget ist.
  • OrderReserve – Bruchteil des aktuellen Eigenkapitals, der dem nächsten Trade zugewiesen wird. Das Budget wird mithilfe der Stoppentfernung und des Instrumenten-Tick-Werts (PriceStep × StepPrice) in eine Kontraktgröße umgewandelt.
  • Wenn das berechnete Volumen unter MinVolume fällt oder gegen VolumeStep verstößt, wird der Befehl abgelehnt und eine Warnung in das Protokoll geschrieben.

Parameter

Parameter Standard Beschreibung
Command Wait Manueller Befehl zur Ausführung (Buy, Sell, Modify, Close). Kehrt nach der Bearbeitung automatisch zu Wait zurück.
StopPrice 0 Absolutes Stop-Loss-Niveau. Muss für Long-Positionen unter dem Einstiegspreis und für Short-Positionen über dem Einstiegspreis liegen.
TakePrice 0 Absolutes Take-Profit-Niveau. Muss bei Long-Positionen über dem Einstiegspreis und bei Shorts darunter liegen.
AccountReserve 0.20 Bruchteil des Eigenkapitals, der als Reserve gehalten wird. Höhere Werte erfordern ein größeres Polster, bevor neue Geschäfte akzeptiert werden.
OrderReserve 0.04 Anteil des pro Trade riskierten Eigenkapitals. Wird zur Berechnung der Kontraktgröße aus der Stoppdistanz verwendet.
CandleType 1 minute Zeitrahmen Kerzenserien werden verwendet, um die neuesten Preise für Validierung und Protokollierung zu beobachten.

Hinweise und Einschränkungen

  • Es wird jeweils nur eine Position unterstützt, entsprechend dem ursprünglichen Expert Advisor-Design.
  • Befehle, die den Mindestpreisabstand, die Kapitalreserve oder Volumenbeschränkungen verletzen, werden ignoriert und eine Warnung wird im Strategieprotokoll aufgezeichnet.
  • Schutzaufträge werden bei jeder Änderung oder Neubesetzung ersetzt, um die Volumina mit der tatsächlichen Positionsgröße synchron zu halten.
  • Die Strategie basiert auf genauen Marktdaten für PriceStep/StepPrice. Instrumente, die diese Felder nicht bereitstellen, können über diesen Port nicht sicher gehandelt werden.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// AIS Trade Machine: EMA crossover strategy with ATR-based risk management.
/// Entry on EMA cross confirmed by RSI, exit on reversal or ATR stop.
/// </summary>
public class AisTradeMachineStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _stopMultiplier;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private decimal _stopPrice;

	public AisTradeMachineStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastLength = Param(nameof(FastLength), 10)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowLength = Param(nameof(SlowLength), 30)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

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

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

		_stopMultiplier = Param(nameof(StopMultiplier), 2.0m)
			.SetDisplay("Stop Multiplier", "ATR multiplier for stop.", "Risk");
	}

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

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

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

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

	public decimal StopMultiplier
	{
		get => _stopMultiplier.Value;
		set => _stopMultiplier.Value = value;
	}

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

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_stopPrice = 0;
	}

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

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_stopPrice = 0;

		var fast = new ExponentialMovingAverage { Length = FastLength };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };

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

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

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

		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;
		var stopDist = atrVal * StopMultiplier;

		var bullishCross = _prevFast <= _prevSlow && fastVal > slowVal;
		var bearishCross = _prevFast >= _prevSlow && fastVal < slowVal;

		// Stop management
		if (Position > 0 && _stopPrice > 0 && close <= _stopPrice)
		{
			SellMarket();
			_entryPrice = 0;
			_stopPrice = 0;
		}
		else if (Position < 0 && _stopPrice > 0 && close >= _stopPrice)
		{
			BuyMarket();
			_entryPrice = 0;
			_stopPrice = 0;
		}

		// Exit on opposite cross
		if (Position > 0 && bearishCross)
		{
			SellMarket();
			_entryPrice = 0;
			_stopPrice = 0;
		}
		else if (Position < 0 && bullishCross)
		{
			BuyMarket();
			_entryPrice = 0;
			_stopPrice = 0;
		}

		// Trail stop
		if (Position > 0)
		{
			var trail = close - stopDist;
			if (trail > _stopPrice) _stopPrice = trail;
		}
		else if (Position < 0 && _stopPrice > 0)
		{
			var trail = close + stopDist;
			if (trail < _stopPrice) _stopPrice = trail;
		}

		// Entry on cross + RSI confirmation
		if (Position == 0)
		{
			if (bullishCross && rsiVal > 50)
			{
				_entryPrice = close;
				_stopPrice = close - stopDist;
				BuyMarket();
			}
			else if (bearishCross && rsiVal < 50)
			{
				_entryPrice = close;
				_stopPrice = close + stopDist;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}