AIS5 Trade Machine portiert den MetaTrader 4 Expertenberater AIS5TM.mq4 in die StockSharp High-Level-Strategie API. Das Original
Das Programm konzentrierte sich auf die Erstellung von Marktprofilhistogrammen für zwei Zeitrahmen und die Bereitstellung einer halbautomatischen Ausführungskonsole. Die
Die Version StockSharp behält die Idee bei, starke und schwache Preiszonen aus der Tick-Volumen-Aggregation hervorzuheben, und verwandelt sie in eine
Automatisiertes Breakout-System mit adaptiver Risikokontrolle basierend auf der Average True Range (ATR).
Die Strategie abonniert zwei Kerzenströme:
Ein Profil-Zeitrahmen (Standard 15 Minuten), der das Volumen akkumuliert, um starke und schwache Zonen zu erkennen.
Ein Handelszeitraum (Standard 1 Minute), der nach volumenbestätigten Ausbrüchen außerhalb dieser Zonen sucht.
Positionen werden durch ATR-proportionale Stopps und skalierbare Ziele geschützt. Volumenkontraktionen lösen frühzeitige Ausstiege aus, um dies nachzuahmen
Überwachungsdisziplin im MT4-Code.
Strategielogik
Erkennung von Volumenzonen (Profilzeitrahmen)
Jede abgeschlossene Kerze in einem höheren Zeitrahmen aktualisiert zwei einfache gleitende Durchschnitte (SMA) des Tick-Volumens.
Eine Kerze wird als starke Zone bezeichnet, wenn ihr Volumen den Durchschnitt um den konfigurierbaren Multiplikator (Strong Volume Mult) überschreitet.
Der Schlusskurs der Kerze wird zum jüngsten starken Niveau.
Eine Kerze wird als Schwachzone bezeichnet, wenn ihr Volumen unter den Durchschnitt dividiert durch den konfigurierten Teiler fällt
(Weak Volume Divider). Der Schlusskurs dieser Kerze wird zum jüngsten schwachen Niveau.
Es nehmen nur fertige Kerzen teil. Die Strategie ignoriert Zonen, bis das Profil SMA vollständig gebildet ist, um vorzeitige Ereignisse zu vermeiden
Signale während der Aufwärmphase.
Breakout-Einträge (Handelszeitraum)
Der untere Zeitrahmen wartet darauf, dass sich sowohl sein Volumen SMA als auch der Indikator ATR vollständig bilden.
Bei einem Long-Setup muss der Schlusskurs das letzte starke Niveau um die Summe der Zonen-Basispunkte und überschreiten
Zone Step Points Puffer (umgerechnet über den Preisschritt des Instruments). Die Kerze muss auch einen relativen Volumenanstieg liefern
zum Intraday-Durchschnitt.
Ein Short-Setup spiegelt die Logik rund um das letzte schwache Niveau wider und erfordert einen Durchbruch über den kombinierten Puffer hinaus und eine Bestätigung
Volumenerweiterung.
Der ursprüngliche MT4-Experte erlaubte manuelle Befehle und Multi-Order-Raster. Der StockSharp-Port behält ein Einzelpositionsmodell bei, also a
Auf einen Ausbruch wird nur dann reagiert, wenn die aktuelle Nettoposition flach ist.
Exit-Management
Beim Einstieg speichert die Strategie den Füllpreis, berechnet einen ATR-basierten Schutzstopp (ATR multipliziert mit ATR Multiplier und
festgeklemmt durch den Basiszonenpuffer) und legt das Ziel als Stoppdistanz multipliziert mit dem schwachen Volumenteiler fest. Das hält
Risiko und Ertrag sind auf die Volumenstruktur abgestimmt.
Während eine Position offen ist, überwacht die Strategie jede abgeschlossene Handelskerze:
Wenn der Preis das Gewinnziel oder den Schutzstopp erreicht, wird die Position sofort abgeflacht.
Wenn das Tick-Volumen den Schwellenwert für schwaches Volumen unterschreitet, bevor eines der beiden Niveaus erreicht wird, wird der Handel frühzeitig geschlossen, um dies zu vermeiden
Verweilen in inaktiven Zonen.
Wenn die Nettoposition auf Null zurückkehrt, wird der interne Zustand zurückgesetzt, sodass der nächste Ausbruch von Grund auf neu bewertet werden kann.
Parameter
Profilkerze – Kerzentyp, der das Volumenprofil speist (Standard: 15-Minuten-Kerzen).
Handelskerze – kürzerer Zeitrahmen für Ausbrüche und Ausstiege (Standard: 1-Minuten-Kerzen).
Volumenrückblick – Anzahl der Kerzen für beide Volumen-SMAs und den Zeitraum ATR.
Strong Volume Mult – Multiplikator über dem durchschnittlichen Volumen, das eine starke Zone markiert (entspricht Parameter.1 in MQL).
Schwächer-Volumen-Teiler – Teiler unter dem durchschnittlichen Volumen, der Schwachstellen markiert und das Gewinnziel bestimmt (entspricht
Parameter.2).
ATR Multiplikator – Skalierungsfaktor, der bei der Berechnung des adaptiven Stoppabstands auf ATR angewendet wird (entspricht Parameter.3).
Zonenbasispunkte – Mindestpuffer in Punkten, der der Zonenebene hinzugefügt wird, bevor Ausbrüche überprüft werden (entspricht ZoneBasePoints).
Zone Step Points – zusätzlicher Ausbruchspuffer in Punkten, der den Abstand von der Zone vor Eintritten vergrößert
ausgelöst (entspricht ZoneStepPoints).
Volume – geerbt von der Basisklasse Strategy; definiert die Ordergröße für Markteintritte.
Zusätzliche Hinweise
Die Strategie greift automatisch auf einen Standardpreisschritt von 0.0001 zurück, wenn das Wertpapier keinen solchen vorgibt. Dadurch bleibt die
punktbasierte Parameter, die mit den meisten FX-Symbolen kompatibel sind.
Alle Indikatorberechnungen basieren auf fertigen Kerzen, um der MT4-Implementierung zu entsprechen, die bei vollständig geschlossenen Balken funktionierte.
Im Gegensatz zum ursprünglichen EA gibt es kein manuelles Bedienfeld oder dateibasierten Profillader. Zonen werden rein live neu aufgebaut
Kerzendaten, um den Port in sich geschlossen zu halten.
Die StockSharp-Version enthält keine Python-Übersetzung.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// AIS5 Trade Machine: EMA breakout with RSI filter and ATR stops.
/// </summary>
public class Ais5TradeMachineStrategy : 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 Ais5TradeMachineStrategy()
{
_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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex, AverageTrueRange
class ais5_trade_machine_strategy(Strategy):
def __init__(self):
super(ais5_trade_machine_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter.", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period.", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period.", "Indicators")
self._prev_close = 0.0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaLength(self):
return self._ema_length.Value
@property
def RsiLength(self):
return self._rsi_length.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(ais5_trade_machine_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._entry_price = 0.0
self._ema = ExponentialMovingAverage()
self._ema.Length = self.EmaLength
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ema, self._rsi, self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ema_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
ev = float(ema_val)
rv = float(rsi_val)
av = float(atr_val)
close = float(candle.ClosePrice)
if self._prev_close == 0 or av <= 0:
self._prev_close = close
return
if self.Position > 0:
if close >= self._entry_price + av * 2.5 or close <= self._entry_price - av * 1.5 or rv > 75:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close <= self._entry_price - av * 2.5 or close >= self._entry_price + av * 1.5 or rv < 25:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_close = close
return
if self.Position == 0:
if close > ev and self._prev_close <= ev and rv > 50:
self._entry_price = close
self.BuyMarket()
elif close < ev and self._prev_close >= ev and rv < 50:
self._entry_price = close
self.SellMarket()
self._prev_close = close
def OnReseted(self):
super(ais5_trade_machine_strategy, self).OnReseted()
self._prev_close = 0.0
self._entry_price = 0.0
def CreateClone(self):
return ais5_trade_machine_strategy()