Auf GitHub ansehen

WE TRUST Channel-Strategie

Übersicht

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

  1. 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.
  2. 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.
  3. Berechnen der oberen und unteren Kanalgrenzen: LWMA ± StdDev ± ChannelIndentPips (in Preiseinheiten umgerechnet).
  4. 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.
  5. Optional Signale invertieren, wenn ReverseSignals aktiviert ist. Optional eine entgegengesetzte Position flatten, bevor auf ein neues Signal reagiert wird, wenn CloseOpposite aktiviert ist.
  6. 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;
	}
}