Diese Strategie ist eine StockSharp-Portierung des MetaTrader 4-Expertenberaters TrainYourself-V1_1-1. Es stellt die Kanalaufbau- und Breakout-Logik wieder her und ersetzt gleichzeitig die grafischen Schaltflächen des MT4-Skripts durch explizite Methodenaufrufe. Der Algorithmus baut kontinuierlich einen Preiskanal im Donchian-Stil neu auf und löst einen Handel aus, sobald der Preis den Kanal verlässt, nachdem er sich zunächst darin konsolidiert hat.
Handelslogik
Kanalbau
Ein DonchianChannels-Indikator mit ChannelLength Perioden wird für jede abgeschlossene Kerze des ausgewählten CandleType ausgewertet.
Die rohen oberen und unteren Bänder werden mit einem zusätzlichen MetaTrader-ähnlichen Puffer erweitert: BufferPoints multipliziert mit dem Instrument PriceStep. Dies reproduziert das ursprüngliche Skript, bei dem die Trendlinien zunächst 50 Punkte vom aktuellen Geld-/Briefkurs entfernt platziert wurden, bevor sie über die jüngsten Hochs und Tiefs gleiten.
Die resultierenden UpperBand/LowerBand-Werte werden als schreibgeschützte Eigenschaften bereitgestellt, sodass sie in benutzerdefinierten Dashboards angezeigt werden können.
Scharfschaltzustand
Die Breakout-Engine bleibt deaktiviert, während eine Position offen ist oder wenn EnableTrendTrade falsch ist.
Wenn keine Position vorhanden ist, muss der Preis innerhalb des Kanals mit einer zusätzlichen Marge von ActivationPoints * PriceStep von beiden Grenzen schließen. Erst dann wird _isArmed zu true und ahmt die MetaTrader-Flagge q=1 nach, die gesetzt wurde, als der Preis wieder in den Kanal zurückging.
Breakout-Ausführung
Sobald der Kurs aktiviert ist, wird bei einem Schlusskurs bei oder über UpperBand eine Marktkauforder platziert (sofern AllowBuyOpen aktiviert ist). Ein Schlusskurs bei oder unter LowerBand platziert einen Marktverkaufsauftrag (in Bezug auf AllowSellOpen).
Nachdem eine Order aufgegeben wurde, entschärft sich die Strategie, bis der Preis ohne offene Positionen wieder in den Kanal eintritt.
Risikomanagement
StartProtection konfiguriert automatische Schutzanordnungen. Entfernungen werden durch Multiplikation von TakeProfitPoints und StopLossPoints mit dem aktuellen PriceStep berechnet. Wenn der Broker einen Schritt nicht meldet, wird ein Fallback von 0.0001 verwendet, der dem Verhalten von MetaTrader Point entspricht.
Manuelle Steuerung
Die MT4-Labels (BUY_TRIANGLE, SELL_TRIANGLE, CLOSE_ORDER) werden durch drei öffentliche Methoden ersetzt: TriggerManualBuy(), TriggerManualSell() und ClosePositionManually(). Sie respektieren AllowBuyOpen/AllowSellOpen, überprüfen den Verbindungsstatus über IsFormedAndOnlineAndAllowTrading() und deaktivieren außerdem die Breakout-Logik, sodass manuelle Trades nicht sofort automatische Einträge auslösen.
Parameter
Parameter
Standard
Beschreibung
CandleType
30m Zeitrahmen
Primäres Kerzenabonnement, das für alle Berechnungen verwendet wird.
ChannelLength
20
Anzahl der vom Kanal Donchian analysierten Kerzen.
BufferPoints
50
Zusätzliche MetaTrader Punkte wurden rund um den letzten Schlusskurs vor Abschluss des Kanals hinzugefügt.
ActivationPoints
2
Marge (in Punkten), die der Preis von den Kanalrändern fernhalten muss, bevor ein Ausbruch ausgelöst werden kann.
StopLossPoints
100
Stop-Loss-Distanz in Punkten; durch Multiplikation mit PriceStep in den absoluten Preis umgerechnet.
TakeProfitPoints
100
Take-Profit-Distanz in Punkten; mit PriceStep in absoluten Preis umgerechnet.
EnableTrendTrade
true
Ermöglicht den automatischen Breakout-Handel. Bei false können nur die manuellen Hilfsmethoden Positionen öffnen/schließen.
Volume
1
Ordergröße für automatische und manuelle Trades.
Nutzungshinweise
Der ursprüngliche Expert Advisor erforderte das Ziehen von Symbolen auf dem Chart, um Trendlinien (neu) aufzubauen. In StockSharp wird der Kanal bei jeder Kerze automatisch neu aufgebaut, sodass keine manuelle Aktualisierung erforderlich ist.
Da die Strategie UpperBand, LowerBand und IsArmed verfügbar macht, können Dashboards oder UI-Widgets das ursprüngliche visuelle Feedback reproduzieren, ohne auf Diagrammobjekte angewiesen zu sein.
Stop-Loss- und Take-Profit-Level sind optional. Setzen Sie die entsprechenden Parameter auf 0, um die Schutzanordnungen zu deaktivieren. Dies spiegelt das Verhalten von MetaTrader wider, bei dem die Änderungsroutinen übersprungen wurden, wenn der externe Wert Null war.
Manuelle Eingaben berücksichtigen denselben Volume-Parameter und profitieren automatisch von den konfigurierten Schutzabständen.
Um den Ausbruchsstatus manuell zurückzusetzen, rufen Sie ClosePositionManually() auf (wodurch auch IsArmed gelöscht wird) oder warten Sie, bis der Preis wieder in den Kanal eintritt, damit die Aktivierungsbedingung wieder erfüllt ist.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// TrainYourself: Donchian channel breakout strategy.
/// Uses Highest/Lowest as channel, arms after price is inside channel,
/// then trades breakouts.
/// </summary>
public class TrainYourselfStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevHighest;
private decimal _prevLowest;
private bool _isArmed;
private decimal _entryPrice;
public TrainYourselfStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_channelLength = Param(nameof(ChannelLength), 20)
.SetDisplay("Channel Length", "Highest/Lowest period.", "Channel");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR for stop distance.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHighest = 0;
_prevLowest = 0;
_isArmed = false;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHighest = 0;
_prevLowest = 0;
_isArmed = false;
_entryPrice = 0;
var highest = new Highest { Length = ChannelLength };
var lowest = new Lowest { Length = ChannelLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal highVal, decimal lowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevHighest == 0 || _prevLowest == 0 || atrVal <= 0)
{
_prevHighest = highVal;
_prevLowest = lowVal;
return;
}
var close = candle.ClosePrice;
var upper = _prevHighest;
var lower = _prevLowest;
// Manage position: exit on channel re-entry
if (Position > 0)
{
if (close < (upper + lower) / 2m)
{
SellMarket();
_entryPrice = 0;
_isArmed = false;
}
}
else if (Position < 0)
{
if (close > (upper + lower) / 2m)
{
BuyMarket();
_entryPrice = 0;
_isArmed = false;
}
}
// Arm when price is inside channel
if (Position == 0)
{
if (!_isArmed)
{
var margin = atrVal * 0.2m;
if (close > lower + margin && close < upper - margin)
_isArmed = true;
}
else
{
// Breakout entry
if (close > upper)
{
_entryPrice = close;
BuyMarket();
_isArmed = false;
}
else if (close < lower)
{
_entryPrice = close;
SellMarket();
_isArmed = false;
}
}
}
_prevHighest = highVal;
_prevLowest = lowVal;
}
}
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, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class train_yourself_strategy(Strategy):
"""Donchian channel breakout: arm inside channel, trade on breakout, exit at midline."""
def __init__(self):
super(train_yourself_strategy, self).__init__()
self._channel_length = self.Param("ChannelLength", 20).SetDisplay("Channel Length", "Highest/Lowest period", "Channel")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR for stop distance", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(train_yourself_strategy, self).OnReseted()
self._prev_highest = 0
self._prev_lowest = 0
self._is_armed = False
self._entry_price = 0
def OnStarted2(self, time):
super(train_yourself_strategy, self).OnStarted2(time)
self._prev_highest = 0
self._prev_lowest = 0
self._is_armed = False
self._entry_price = 0
highest = Highest()
highest.Length = self._channel_length.Value
lowest = Lowest()
lowest.Length = self._channel_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(highest, lowest, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnProcess(self, candle, high_val, low_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_highest == 0 or self._prev_lowest == 0 or atr_val <= 0:
self._prev_highest = float(high_val)
self._prev_lowest = float(low_val)
return
close = float(candle.ClosePrice)
upper = self._prev_highest
lower = self._prev_lowest
mid = (upper + lower) / 2.0
# Manage position: exit on channel re-entry
if self.Position > 0:
if close < mid:
self.SellMarket()
self._entry_price = 0
self._is_armed = False
elif self.Position < 0:
if close > mid:
self.BuyMarket()
self._entry_price = 0
self._is_armed = False
# Arm when price is inside channel
if self.Position == 0:
if not self._is_armed:
margin = float(atr_val) * 0.2
if close > lower + margin and close < upper - margin:
self._is_armed = True
else:
if close > upper:
self._entry_price = close
self.BuyMarket()
self._is_armed = False
elif close < lower:
self._entry_price = close
self.SellMarket()
self._is_armed = False
self._prev_highest = float(high_val)
self._prev_lowest = float(low_val)
def CreateClone(self):
return train_yourself_strategy()