Die Exp Amstell Strategy ist ein Grid-Trading-System, das aus dem ursprünglichen MetaTrader 4 Expert Advisor exp_Amstell.mq4 umgewandelt wurde. Es platziert kontinuierlich Kauf- und Verkaufsaufträge auf dem Markt, wenn der Preis um eine konfigurierbare Anzahl von Punkten von der letzten Ausführung abweicht. Jeder einzelne Handel wird unabhängig verwaltet: Sobald sich der Markt um die angegebene Take-Profit-Distanz bewegt, sendet die Strategie einen Gegenauftrag, um den Gewinn für diese einzelne Ebene zu erfassen.
Im Gegensatz zu impulsgesteuerten Systemen bleibt Exp Amstell jederzeit aktiv. Es wartet nicht auf die Bestätigung von Indikatoren und sammelt stattdessen Positionen auf beiden Seiten des Buchs, während der Markt schwankt. Dieses Verhalten macht es sehr empfindlich gegenüber den gewählten Punktabständen und der Größe jeder Bestellung.
Handelslogik
Tick-basierte Verarbeitung. Die Strategie abonniert Kurse der Stufe 1 und reagiert auf jede Änderung des besten Geld- und Briefkurses, genau wie die Funktion start() im ursprünglichen MQL-Code.
Unabhängige Long- und Short-Stacks. Kaufaufträge sind zulässig, wenn keine Long-Trades offen sind oder wenn der Briefkurs um mindestens die Wiedereintrittsdistanz vom letzten Long-Einstieg gefallen ist. Verkaufsaufträge nutzen die symmetrische Bedingung für den Geldkurs.
Take-Profit pro Trade. Jede offene Ebene wird separat verfolgt. Wenn der Geldkurs (für Long-Positionen) oder der Briefkurs (für Short-Positionen) um die konfigurierten Take-Profit-Punkte steigt, schließt die Strategie nur diese Ebene mit einer Marktorder ab. Andere Schichten bleiben unberührt.
FIFO-Emulation. Ausgeführte Geschäfte werden im FIFO aufgezeichnet, um die Ticket-basierte Abrechnung zu reproduzieren, die MetaTrader auf abgesicherte Positionen anwendet. Dadurch wird gewährleistet, dass Teilfüllungen zuerst die älteste ausstehende Schicht abbauen.
Netted Portfolio Awareness. StockSharp verwaltet Nettopositionen. Wenn eine neue Kauforder eine offene Short-Position ausgleicht, entfernt die Strategie diese Short-Position aus ihrem synthetischen Stack, bevor der Rest als neue Long-Position erfasst wird.
Parameter
Name
Typ
Standard
Beschreibung
TradeVolume
decimal
0.1
Volumen jeder Marktorder, die eine neue Rasterschicht öffnet.
TakeProfitPoints
int
30
Entfernung in MetaTrader Punkten, die vom Preis abgedeckt werden muss, bevor eine einzelne Ebene geschlossen wird.
ReentryDistancePoints
int
10
Minimaler Punktabstand vom letzten Eintrag, bevor auf derselben Seite eine weitere Ordnung hinzugefügt wird.
Die Strategie wandelt Punkte mithilfe des PriceStep des Instruments automatisch in tatsächliche Preisschritte um. Fünf- und dreistellige Anführungszeichen erhalten den MetaTrader-spezifischen Multiplikator, sodass 1 point gleich 0.0001 ist (oder 0.01 für Symbole im JPY-Stil).
Implementierungshinweise
Daten der Stufe 1 sind ausreichend; Es ist kein Kerzenabonnement erforderlich. Die Strategie deklariert dies, indem sie GetWorkingSecurities() überschreibt und (Security, DataType.Level1) anfordert.
StartProtection() wird während OnStarted aufgerufen, um sicherzustellen, dass der Läufer alle verbleibenden Positionen schließt, wenn die Strategie unerwartet stoppt.
Alle Kommentare in der C#-Datei bleiben in Englisch und entsprechen den Projektrichtlinien.
Da StockSharp saldierte Positionen verwendet, kann der Hafen gegensätzliche Käufe und Verkäufe nicht gleichzeitig offen halten. Wenn beide Seiten gleichzeitig handeln, verringert die neuere Order das bestehende Risiko, bevor eine neue Ebene entsteht.
Nutzungstipps
Kalibrieren Sie die Punktabstände. Kleinere Abstände erzeugen dichtere Gitter, die in volatilen Märkten zu übermäßigem Handel führen können. Größere Abstände reduzieren die Aktivität, erhöhen aber den Absinken pro Schicht.
Größe der Bestellungen mit Bedacht. Grid-Systeme bauen schnell Risiko auf. Testen Sie konservative Volumina im Designer/Backtester, bevor Sie zum Live-Handel wechseln.
Erwägen Sie manuelle Risikokontrollen. Der ursprüngliche Experte hat keinen globalen Stop-Loss. Kombinieren Sie die Strategie mit Schutzmaßnahmen auf Portfolioebene, um das Extremrisiko zu begrenzen.
Überwachen Sie die Ausführungsqualität. Der Algorithmus geht davon aus, dass Marktaufträge in der Nähe des besten Geld-/Briefkurses ausgeführt werden. Slippage wirkt sich direkt auf die erzielten Take-Profit-Distanzen aus.
Quelle
Konvertiert von MQL/9027/exp_Amstell.mq4.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Exp Amstell: Grid-style strategy that scales into positions
/// on ATR-based price movements and closes on profit targets.
/// </summary>
public class ExpAmstellStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<int> _emaLength;
private decimal _entryPrice;
private decimal _prevEma;
private int _gridCount;
public ExpAmstellStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period for grid distance.", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "EMA period for trend.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_prevEma = 0;
_gridCount = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_prevEma = 0;
_gridCount = 0;
var atr = new AverageTrueRange { Length = AtrLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrVal, decimal emaVal)
{
if (candle.State != CandleStates.Finished)
return;
if (atrVal <= 0 || _prevEma == 0)
{
_prevEma = emaVal;
return;
}
var close = candle.ClosePrice;
// Grid exit: take profit at 1.5 ATR or stop at 3 ATR
if (Position > 0)
{
if (close >= _entryPrice + atrVal * 1.5m)
{
SellMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (close <= _entryPrice - atrVal * 3m)
{
SellMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (_gridCount < 3 && close <= _entryPrice - atrVal)
{
// Scale in: add to position on pullback
_entryPrice = (_entryPrice + close) / 2m;
_gridCount++;
BuyMarket();
}
}
else if (Position < 0)
{
if (close <= _entryPrice - atrVal * 1.5m)
{
BuyMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (close >= _entryPrice + atrVal * 3m)
{
BuyMarket();
_entryPrice = 0;
_gridCount = 0;
}
else if (_gridCount < 3 && close >= _entryPrice + atrVal)
{
_entryPrice = (_entryPrice + close) / 2m;
_gridCount++;
SellMarket();
}
}
// Entry: EMA direction determines initial direction
if (Position == 0)
{
if (close > emaVal && emaVal > _prevEma)
{
_entryPrice = close;
_gridCount = 0;
BuyMarket();
}
else if (close < emaVal && emaVal < _prevEma)
{
_entryPrice = close;
_gridCount = 0;
SellMarket();
}
}
_prevEma = emaVal;
}
}
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.Indicators import AverageTrueRange, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_amstell_strategy(Strategy):
"""
Grid-style strategy that scales into positions on ATR-based price movements.
Enters based on EMA direction, scales in on pullbacks, exits on ATR-based TP/SL.
"""
def __init__(self):
super(exp_amstell_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period for grid distance", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period for trend", "Indicators")
self._entry_price = 0.0
self._prev_ema = 0.0
self._grid_count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(exp_amstell_strategy, self).OnReseted()
self._entry_price = 0.0
self._prev_ema = 0.0
self._grid_count = 0
def OnStarted2(self, time):
super(exp_amstell_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._prev_ema = 0.0
self._grid_count = 0
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(atr, ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, atr_val, ema_val):
if candle.State != CandleStates.Finished:
return
atr_val = float(atr_val)
ema_val = float(ema_val)
if atr_val <= 0 or self._prev_ema == 0:
self._prev_ema = ema_val
return
close = float(candle.ClosePrice)
if self.Position > 0:
if close >= self._entry_price + atr_val * 1.5:
self.SellMarket()
self._entry_price = 0.0
self._grid_count = 0
elif close <= self._entry_price - atr_val * 3.0:
self.SellMarket()
self._entry_price = 0.0
self._grid_count = 0
elif self._grid_count < 3 and close <= self._entry_price - atr_val:
self._entry_price = (self._entry_price + close) / 2.0
self._grid_count += 1
self.BuyMarket()
elif self.Position < 0:
if close <= self._entry_price - atr_val * 1.5:
self.BuyMarket()
self._entry_price = 0.0
self._grid_count = 0
elif close >= self._entry_price + atr_val * 3.0:
self.BuyMarket()
self._entry_price = 0.0
self._grid_count = 0
elif self._grid_count < 3 and close >= self._entry_price + atr_val:
self._entry_price = (self._entry_price + close) / 2.0
self._grid_count += 1
self.SellMarket()
if self.Position == 0:
if close > ema_val and ema_val > self._prev_ema:
self._entry_price = close
self._grid_count = 0
self.BuyMarket()
elif close < ema_val and ema_val < self._prev_ema:
self._entry_price = close
self._grid_count = 0
self.SellMarket()
self._prev_ema = ema_val
def CreateClone(self):
return exp_amstell_strategy()