Konvertiert aus dem MetaTrader 5-Experten "MA Envelopes". Die Strategie sucht nach Preiskorrekturen in Richtung eines gleitenden Durchschnitts, der von einem Envelope-Kanal umgeben ist. Wenn eine abgeschlossene Kerze zwischen dem gleitenden Durchschnitt und einer der Envelope-Bänder während des konfigurierten Handelsfensters schließt, platziert die Strategie Limit-Einstiege beim gleitenden Durchschnitt mit aus dem Envelope abgeleiteten Schutzausstiegsorders.
Handelslogik
Ein gleitender Durchschnitt wird mit der ausgewählten Methode, Preisquelle und Periode berechnet. Derselbe Wert wird verwendet, um symmetrische Envelope-Bänder mithilfe des Deviationsparameters aufzubauen.
Wenn eine abgeschlossene Kerze über dem gleitenden Durchschnitt, aber unter dem oberen Envelope-Band schließt und der aktuelle Ask-Preis über dem gleitenden Durchschnitt bleibt, wird eine gestaffelte Sequenz von Kauf-Limit-Orders zum gleitenden Durchschnittspreis vorbereitet.
Jedes Kauf-Limit verwendet den unteren Envelope als Stop-Loss-Level und den oberen Envelope plus einem zusätzlichen Pip-Offset als Take-Profit.
Bis zu drei unabhängige Orders werden verwaltet, jede mit ihrem eigenen Take-Profit-Offset (First, Second, Third SL/TP-Parameter).
Wenn eine abgeschlossene Kerze unter dem gleitenden Durchschnitt, aber über dem unteren Envelope-Band schließt und der aktuelle Bid-Preis unter dem gleitenden Durchschnitt bleibt, wird die Logik für Verkaufs-Limit-Orders gespiegelt.
Das Handelsfenster wird durch StartHour und EndHour (Terminalzeit) gesteuert. Nach der Endstunde werden alle noch aktiven Einstiegsorders storniert.
Das Risiko pro Trade wird über MaximumRisk geschätzt und nach aufeinanderfolgenden Verlusten mittels DecreaseFactor reduziert. Das Ordervolumen wird an den Volumenschritt und die Limits des Instruments angepasst.
Sobald eine Einstiegsorder vollständig gefüllt ist, werden sofort Schutz-Stop-Loss- und Take-Profit-Orders registriert. Wenn eine Ausstiegsorder ausgelöst wird, wird die Gegenorder storniert und, falls noch Positionsvolumen übrig ist, werden neue Schutzorders für den Rest ausgegeben.
Parameter
Parameter
Beschreibung
MaximumRisk
Anteil des verfügbaren Eigenkapitals, das pro Position riskiert wird.
DecreaseFactor
Reduziert die Positionsgröße nach aufeinanderfolgenden Verlust-Trades.
First/Second/ThirdStopTakeProfitPips
Pip-Abstände, die zu den Envelope-Bändern für die drei gestaffelten Orders hinzugefügt werden.
StartHour, EndHour
Handelssitzungsgrenzen in Terminalzeit (0–23).
MaPeriod, MaShift, MaMethodType, AppliedPrice
Konfiguration des gleitenden Durchschnitts.
EnvelopeDeviation
Breite des Envelope-Kanals in Prozent.
CandleType
Zeitrahmen der für die Berechnungen verwendeten Kerzen.
Hinweise
Schutzorders werden neu erstellt, wenn nur ein Teil einer Position geschlossen wurde, um die verbleibende Größe abzudecken.
Ausstehende Einstiegsorders werden am Ende der Sitzung storniert; offene Positionen bleiben von ihren Schutzorders verwaltet.
Die Strategie verlässt sich auf Order-Book-Updates, um die neuesten Bid/Ask-Preise zu erfassen; Kerzenschlusspreise werden als Fallback verwendet, wenn Order-Book-Daten nicht verfügbar sind.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class MaEnvelopesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevHigh, _prevLow;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public MaEnvelopesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 15).SetGreaterThanZero().SetDisplay("Channel Period", "Channel lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = null;
_prevLow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh = null; _prevLow = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(highest, lowest, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevHigh = high; _prevLow = low; return; }
if (_prevHigh == null || _prevLow == null) { _prevHigh = high; _prevLow = low; return; }
if (candle.ClosePrice > _prevHigh.Value && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (candle.ClosePrice < _prevLow.Value && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevHigh = high; _prevLow = low;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class ma_envelopes_strategy(Strategy):
def __init__(self):
super(ma_envelopes_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 15) \
.SetDisplay("Channel Period", "Channel lookback", "Indicators")
self._prev_high = None
self._prev_low = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(ma_envelopes_strategy, self).OnReseted()
self._prev_high = None
self._prev_low = None
def OnStarted2(self, time):
super(ma_envelopes_strategy, self).OnStarted2(time)
self._prev_high = None
self._prev_low = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
if self._prev_high is None or self._prev_low is None:
self._prev_high = hv
self._prev_low = lv
return
close = float(candle.ClosePrice)
if close > self._prev_high and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close < self._prev_low and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_high = hv
self._prev_low = lv
def CreateClone(self):
return ma_envelopes_strategy()