Die WE TRUST Channel-Strategie ist ein High-Level-StockSharp-Port des MetaTrader 5 Expert Advisors „WE TRUST". Das System handelt Pullbacks in Richtung eines linear gewichteten Moving Average, der von Standardabweichungsbändern umgeben ist. Wenn der Preis außerhalb der Bänder schließt, antizipiert die Strategie eine Mean Reversion und eröffnet eine Marktposition zurück zur Mitte des Kanals. Signalumkehr, optionales Schließen entgegengesetzter Trades und pip-basierte Geldverwaltungsparameter spiegeln den originalen Experten wider.
Handelslogik
Abonnieren des konfigurierten Kerzentyps (standardmäßig stündliche Kerzen) und Berechnen zweier Indikatoren an der ausgewählten Preisquelle:
Ein linear gewichteter Moving Average (LWMA) mit konfigurierbarer Periode und Verschiebung.
Eine Standardabweichungshülle mit eigener Periode und Verschiebung.
Konvertieren pip-basierter Offsets in absolute Preisabstände unter Verwendung des Instrument-PriceStep. Fünf- und dreistellige Kurse multiplizieren den Schritt mit 10, um die MetaTrader-Pip-Definition zu emulieren.
Berechnen der oberen und unteren Kanalgrenzen: LWMA ± StdDev ± ChannelIndentPips (in Preiseinheiten umgerechnet).
Nur abgeschlossene Kerzen auswerten. Wenn der gewählte Kerzenkurs unterhalb des unteren Kanals schließt, generiert die Strategie ein Kauf-Signal. Wenn er oberhalb des oberen Kanals schließt, generiert er ein Verkaufs-Signal.
Optional Signale invertieren, wenn ReverseSignals aktiviert ist. Optional eine entgegengesetzte Position flatten, bevor auf ein neues Signal reagiert wird, wenn CloseOpposite aktiviert ist.
Marktorders mit dem konfigurierten Volumen senden, wenn die aktuelle Position flat oder mit der Signalrichtung ausgerichtet ist.
Risikomanagement
StopLossPips und TakeProfitPips übersetzen Pip-Abstände in absolute Schutzorders über StartProtection. Auf 0 setzen, um das jeweilige Niveau zu deaktivieren.
TrailingStopPips und TrailingStepPips steuern einen pip-basierten Trailing Stop, der profitable Trades verfolgt. Beide Parameter werden mit derselben Pip-Größen-Logik in Preisabstände umgerechnet.
Alle Ausstiege werden mit Marktorders ausgeführt, um nah an der MQL5-Implementierung zu bleiben.
Parameter
Parameter
Beschreibung
Standard
OrderVolume
Trade-Volumen mit jeder Marktorder.
0.1
StopLossPips
Stop-Loss-Abstand in Pips (0 deaktiviert den Stop).
40
TakeProfitPips
Take-Profit-Abstand in Pips (0 deaktiviert das Ziel).
60
TrailingStopPips
Trailing-Stop-Abstand in Pips.
10
TrailingStepPips
Trailing-Schritt in Pips zwischen Stop-Anpassungen.
10
MaPeriod
Periode des linear gewichteten Moving Average.
60
MaShift
Anzahl der Balken, die der Moving Average vorwärts verschoben wird.
0
StdDevPeriod
Periode der Standardabweichungsberechnung.
50
StdDevShift
Anzahl der Balken, die der Abweichungswert verschoben wird.
0
SignalBarOffset
Anzahl abgeschlossener Balken zurück bei der Signalauswertung.
1
ChannelIndentPips
Zusätzlicher Puffer außerhalb der Abweichungsbänder.
1
ReverseSignals
Kauf/Verkauf-Logik des Kanal-Ausbruchs invertieren.
false
CloseOpposite
Entgegengesetzte Position schließen, bevor ein neuer Trade eingegangen wird.
false
AppliedPrice
Kerzenpreiskomponente, die in beide Indikatoren einfließt.
Weighted
CandleType
Vom Connector angeforderter Kerzendatentyp.
1-Stunden-Zeitrahmen
Hinweise
Die Strategie verlässt sich auf gültige PriceStep-Metadaten. Wenn das Exchange diese nicht bereitstellt, fällt der Code auf Security.Step und schließlich auf 1 zurück.
Nur die C#-Implementierung ist in diesem Verzeichnis enthalten. Der Python-Port wird gemäß den Anweisungen absichtlich weggelassen.
Die Logik verarbeitet nur abgeschlossene Kerzen und versucht nicht, partielle Balkendaten zu akkumulieren.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class WeTrustChannelStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public WeTrustChannelStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class we_trust_channel_strategy(Strategy):
def __init__(self):
super(we_trust_channel_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(we_trust_channel_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(we_trust_channel_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return we_trust_channel_strategy()