Auf GitHub ansehen

CoensioTrader1 V06 Strategie

Überblick

CoensioTrader1 V06 ist eine Trendfolge-Ausbruch-Strategie, die ursprünglich als MetaTrader Expert Advisor verteilt wurde. Der StockSharp-Port behält die diskretionäre Mustererkennungslogik bei und entfernt die broker- und internetspezifischen Funktionen aus der MQL-Implementierung. Die Strategie operiert auf einem einzelnen Wertpapier und Zeitrahmen und verwendet Bollinger Bands zusammen mit einem doppelten exponentiellen gleitenden Durchschnitt (DEMA), um Erschöpfungsbewegungen gefolgt von Trendwiederaufnahme zu identifizieren.

Der ursprüngliche Roboter erlaubte den Handel mit bis zu sechs Währungspaaren mit individuellen Parametersätzen, unterstützte DLL-basierte Lizenzierung und meldete Optimierungsergebnisse an einen Remote-Server. Diese Hilfsdienste werden in diesem Port absichtlich weggelassen. Der Fokus liegt auf dem zentralen Einstiegs- und Ausstiegsworkflow, der auf Bollinger-Band-Ablehnungen reagiert, die durch Swing-Struktur und die DEMA-Steigung bestätigt werden.

Strategielogik

  1. Datenabonnement – Die Strategie abonniert den konfigurierten Kerzentyp (Standard: 1 Stunde) und bindet Bollinger Bands zusammen mit einem DEMA.
  2. Bollinger-Band-Ablehnung – Signale werden auf der letzten vollständig geschlossenen Kerze ausgewertet.
    • Long-Setup
      • Die Kerze öffnete unterhalb des vorherigen unteren Bollinger Bands und schloss wieder darüber (fehlgeschlagener Ausbruch nach unten).
      • Die Kerze bildete ein höheres Tief im Vergleich zur vorherigen Bar, während diese frühere Bar ein niedrigeres Tief im Vergleich zu ihrem Vorgänger bildete (Doppelboden-Struktur).
      • Der DEMA steigt strikt über die letzten drei Beobachtungen (aktueller Wert > vorheriger > zweiter vorheriger).
    • Short-Setup
      • Die Kerze öffnete oberhalb des vorherigen oberen Bollinger Bands und schloss wieder darunter (fehlgeschlagener Ausbruch nach oben).
      • Die Kerze bildete ein niedrigeres Hoch im Vergleich zur vorherigen Bar, während diese frühere Bar ein höheres Hoch im Vergleich zu ihrem Vorgänger bildete (Doppeltop-Struktur).
      • Der DEMA fällt strikt über die letzten drei Beobachtungen.
  3. Orderausführung – Marktorders werden unmittelbar nach Bestätigung des Signals auf einer fertigen Kerze gesendet. Optionale Positionsglättung bei entgegengesetzten Signalen kann aktiviert werden.
  4. Risikomanagement – Optionale Stop-Loss- und Take-Profit-Abstände werden über StartProtection bereitgestellt. Beide sind absolute Preisabstände; die Trailing-Stop-Funktionalität des ursprünglichen Experts wird nicht reproduziert.

Parameter

Name Beschreibung Standard
BollingerPeriod Periode für die Bollinger-Band-Berechnung. 30
BollingerDeviation Standardabweichungsmultiplikator für die Bänder. 1.5
DemaPeriod Länge des doppelten exponentiellen gleitenden Durchschnitts zur Trendbestätigung. 20
StopLossDistance Absoluter Stop-Loss-Abstand, der an StartProtection übergeben wird. Auf null setzen zum Deaktivieren. 0 (absolute)
TakeProfitDistance Absoluter Take-Profit-Abstand, der an StartProtection übergeben wird. Auf null setzen zum Deaktivieren. 0 (absolute)
CloseOnSignal Aktuelle Position schließen, bevor eine neue in entgegengesetzter Richtung eröffnet wird. false
CandleType Kerzendatentyp oder Zeitrahmen. Standard ist 1-Stunden-Zeitrahmen. 1h

Verwendungshinweise

  • Die StockSharp-Version handelt nur das primäre Strategy.Security. Um das Multi-Symbol-Verhalten des ursprünglichen Experts nachzuahmen, starten Sie separate Strategieinstanzen mit unterschiedlichen Parametersätzen.
  • Die MQL-Lot-Sizing-Logik (RiskMax, LotSize, LotBalanceDivider) wurde nicht übersetzt. Konfigurieren Sie Volume in der Strategie oder über den Risikomanager entsprechend Ihren Portfolioregeln.
  • Die DLL-basierte Aktivierung, das Remote-Optimierungsprotokoll und die UI-Zeichenroutinen in den MQL-Dateien wurden absichtlich entfernt.
  • Stop-Loss- und Take-Profit-Werte sind absolute Preisabstände. Passen Sie sie an die Tickgröße oder den Pip-Wert des Instruments an, wenn Sie die Strategie konfigurieren.
  • Der ursprüngliche Trailing-Stop-Schritt-Mechanismus ist nicht implementiert. Wenn Trailing-Management erforderlich ist, lagern Sie ein dediziertes Risikomodul auf dieser Strategie auf.
  • Alle Codekommentare und -logiken werden wie gewünscht auf Englisch gehalten; README-Übersetzungen werden separat bereitgestellt.

Unterschiede zur MQL-Version

  • Multi-Symbol-Management: durch ein Einzelinstrument-Design für Klarheit und einfacheres Testen ersetzt.
  • Netzwerk und Lizenzierung: entfernt; es werden keine externen HTTP-Anfragen oder DLL-Aufrufe durchgeführt.
  • Order-Sizing: vereinfacht, um auf StockSharps Standard-Volume-Handling zu setzen.
  • Visuelle Objekte: Chart-Anmerkungen aus MetaTrader (Pfeile, Beschriftungen, Farbthemen) werden nicht nachgebaut. Verwenden Sie StockSharp-Chart-Helper, wenn Visualisierung erforderlich ist.
  • Trailing Stop: nicht portiert; nur die anfänglichen Schutzorders werden konfiguriert.

Diese Dokumentation soll erschöpfend sein, damit der Port überprüft, getestet und erweitert werden kann, ohne den ursprünglichen MQL-Quellcode lesen zu müssen.

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

using StockSharp.Algo;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Port of the CoensioTrader1 V06 MQL strategy.
/// The strategy buys after a lower Bollinger Band rejection paired with a higher low pattern and bullish DEMA trend.
/// It sells after an upper Bollinger Band rejection with a lower high structure and bearish DEMA trend.
/// </summary>
public class CoensioTrader1V06Strategy : Strategy
{
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;
	private readonly StrategyParam<int> _demaPeriod;
	private readonly StrategyParam<Unit> _stopLossDistance;
	private readonly StrategyParam<Unit> _takeProfitDistance;
	private readonly StrategyParam<bool> _closeOnSignal;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevOpen;
	private decimal? _prevHigh;
	private decimal? _prevLow;
	private decimal? _prevClose;

	private decimal? _prev2High;
	private decimal? _prev2Low;
	private decimal? _prev3High;
	private decimal? _prev3Low;

	private decimal? _prevUpperBand;
	private decimal? _prevLowerBand;

	private decimal? _prevDema;
	private decimal? _prev2Dema;

	/// <summary>
	/// Initializes a new instance of the <see cref="CoensioTrader1V06Strategy"/> class.
	/// </summary>
	public CoensioTrader1V06Strategy()
	{
		_bollingerPeriod = Param(nameof(BollingerPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Bollinger Period", "Length of Bollinger Bands", "Indicators")
			;

		_bollingerDeviation = Param(nameof(BollingerDeviation), 1.5m)
			.SetGreaterThanZero()
			.SetDisplay("Bollinger Deviation", "Standard deviation multiplier", "Indicators")
			;

		_demaPeriod = Param(nameof(DemaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("DEMA Period", "Length of double exponential moving average", "Indicators")
			;

		_stopLossDistance = Param(nameof(StopLossDistance), new Unit(0m, UnitTypes.Absolute))
			.SetDisplay("Stop Loss", "Absolute stop loss offset from entry", "Risk");

		_takeProfitDistance = Param(nameof(TakeProfitDistance), new Unit(0m, UnitTypes.Absolute))
			.SetDisplay("Take Profit", "Absolute take profit offset from entry", "Risk");

		_closeOnSignal = Param(nameof(CloseOnSignal), false)
			.SetDisplay("Close On Opposite Signal", "Close current trades when opposite setup appears", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Time frame for signal calculations", "General");

		Volume = 0.01m;
	}

	/// <summary>
	/// Bollinger Bands period.
	/// </summary>
	public int BollingerPeriod
	{
		get => _bollingerPeriod.Value;
		set => _bollingerPeriod.Value = value;
	}

	/// <summary>
	/// Bollinger Bands standard deviation multiplier.
	/// </summary>
	public decimal BollingerDeviation
	{
		get => _bollingerDeviation.Value;
		set => _bollingerDeviation.Value = value;
	}

	/// <summary>
	/// Double exponential moving average period.
	/// </summary>
	public int DemaPeriod
	{
		get => _demaPeriod.Value;
		set => _demaPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance from entry price.
	/// </summary>
	public Unit StopLossDistance
	{
		get => _stopLossDistance.Value;
		set => _stopLossDistance.Value = value;
	}

	/// <summary>
	/// Take-profit distance from entry price.
	/// </summary>
	public Unit TakeProfitDistance
	{
		get => _takeProfitDistance.Value;
		set => _takeProfitDistance.Value = value;
	}

	/// <summary>
	/// Close current position when an opposite signal appears.
	/// </summary>
	public bool CloseOnSignal
	{
		get => _closeOnSignal.Value;
		set => _closeOnSignal.Value = value;
	}

	/// <summary>
	/// Candle type used for indicator calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevOpen = null;
		_prevHigh = null;
		_prevLow = null;
		_prevClose = null;

		_prev2High = null;
		_prev2Low = null;
		_prev3High = null;
		_prev3Low = null;

		_prevUpperBand = null;
		_prevLowerBand = null;

		_prevDema = null;
		_prev2Dema = null;
	}

	/// <inheritdoc />
	private BollingerBands _bollinger;
	private DoubleExponentialMovingAverage _dema;

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_bollinger = new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};

		_dema = new DoubleExponentialMovingAverage
		{
			Length = DemaPeriod
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var bollingerResult = _bollinger.Process(candle);
		var demaResult = _dema.Process(candle);

		if (bollingerResult.IsEmpty || demaResult.IsEmpty || !_bollinger.IsFormed || !_dema.IsFormed)
		{
			_prevOpen = candle.OpenPrice;
			_prevClose = candle.ClosePrice;
			_prevLow = candle.LowPrice;
			_prevHigh = candle.HighPrice;
			return;
		}

		var bollingerValue = (BollingerBandsValue)bollingerResult;
		var upper = bollingerValue.UpBand ?? 0m;
		var lower = bollingerValue.LowBand ?? 0m;
		var demaValue = demaResult.GetValue<decimal>();

		if (_prevOpen.HasValue && _prevClose.HasValue && _prevLow.HasValue && _prevHigh.HasValue &&
			_prevLowerBand.HasValue && _prevUpperBand.HasValue && _prevDema.HasValue)
		{
			// Long setup: lower band rejection with rising DEMA.
			var crossedLowerBand = _prevLow.Value <= _prevLowerBand.Value && _prevClose.Value > _prevLowerBand.Value;
			var bullishTrend = demaValue > _prevDema.Value;

			if (crossedLowerBand && bullishTrend)
			{
				if (CloseOnSignal && Position < 0)
					{
					if (Position > 0) SellMarket(Position);
					else if (Position < 0) BuyMarket(-Position);
				}

				if (Position <= 0)
					BuyMarket();
			}

			// Short setup: upper band rejection with falling DEMA.
			var crossedUpperBand = _prevHigh.Value >= _prevUpperBand.Value && _prevClose.Value < _prevUpperBand.Value;
			var bearishTrend = demaValue < _prevDema.Value;

			if (crossedUpperBand && bearishTrend)
			{
				if (CloseOnSignal && Position > 0)
					{
					if (Position > 0) SellMarket(Position);
					else if (Position < 0) BuyMarket(-Position);
				}

				if (Position >= 0)
					SellMarket();
			}
		}

		_prev3Low = _prev2Low;
		_prev3High = _prev2High;
		_prev2Low = _prevLow;
		_prev2High = _prevHigh;

		_prevLowerBand = lower;
		_prevUpperBand = upper;

		_prev2Dema = _prevDema;
		_prevDema = demaValue;

		_prevOpen = candle.OpenPrice;
		_prevClose = candle.ClosePrice;
		_prevLow = candle.LowPrice;
		_prevHigh = candle.HighPrice;
	}
}