Auf GitHub ansehen

CorrectedAverage-Ausbruchstrategie

Diese Strategie handelt Ausbrüche relativ zu einem CorrectedAverage-gleitenden Durchschnitt. Der Indikator glättet den Preis mithilfe eines gleitenden Durchschnitts und passt den Glättungsfaktor basierend auf der Standardabweichung der Preisveränderungen an.

Wenn der Preis den korrigierten Durchschnitt um eine bestimmte Anzahl von Punkten überschreitet und dann zum Ausbruchsniveau zurückkehrt, öffnet die Strategie eine Long-Position. Die umgekehrte Logik gilt für Short-Trades. Stop-Loss und Take-Profit werden in absoluten Preispunkten angewendet.

Parameter

  • Candle Type – Zeitrahmen der für Berechnungen verwendeten Kerzen.
  • Length – Periode für den gleitenden Durchschnitt und die Standardabweichung.
  • MA Type – Art des gleitenden Durchschnitts (SMA, EMA, SMMA, LWMA).
  • Level Points – Ausbruchsabstand vom korrigierten Durchschnitt in Preisschritten.
  • Stop Loss Points – Stop-Loss-Abstand vom Einstiegspreis in Preisschritten.
  • Take Profit Points – Take-Profit-Abstand vom Einstiegspreis in Preisschritten.
  • Enable Long – Long-Positionen öffnen erlauben.
  • Enable Short – Short-Positionen öffnen erlauben.

Handelslogik

  1. Gleitenden Durchschnitt und Standardabweichung berechnen.
  2. Den korrigierten Durchschnitt mithilfe vorheriger Werte und des Varianzverhältnisses aufbauen, um plötzliche Sprünge zu glätten.
  3. Ausbrüche erkennen, wenn der vorherige Balken über oder unter dem korrigierten Durchschnitt plus/minus dem konfigurierten Niveau schließt.
  4. Nach einem Ausbruch auf die Rückkehr der nächsten Kerze zum Ausbruchsniveau warten und eine Position in Ausbruchsrichtung eröffnen.
  5. Entgegengesetzte Positionen schließen, wenn ein neues Ausbruchssignal erscheint.
  6. Stop-Loss- und Take-Profit-Schutz anwenden.

Hinweise

Diese Strategie ist eine Konvertierung des MQL-Skripts Exp_CorrectedAverage.mq5. Sie ist für Bildungszwecke gedacht und erfordert weitere Tests vor dem Einsatz im Live-Handel.

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;

/// <summary>
/// Strategy based on the Corrected Average breakout.
/// Monitors price relative to a corrected moving average and trades on breakouts.
/// </summary>
public class CorrectedAverageBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _length;
	private readonly StrategyParam<int> _levelPoints;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private decimal _prevCorrected;
	private decimal _prevPrevCorrected;
	private decimal _prevClose;
	private decimal _prevPrevClose;
	private bool _isInitialized;
	private decimal _level;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int Length { get => _length.Value; set => _length.Value = value; }
	public int LevelPoints { get => _levelPoints.Value; set => _levelPoints.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public CorrectedAverageBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations", "General");

		_length = Param(nameof(Length), 12)
			.SetDisplay("Length", "Period of moving average", "Indicator");

		_levelPoints = Param(nameof(LevelPoints), 300)
			.SetDisplay("Level Points", "Breakout distance in price steps", "Trading");

		_stopLossPoints = Param(nameof(StopLossPoints), 1000)
			.SetDisplay("Stop Loss Points", "Stop loss in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 2000)
			.SetDisplay("Take Profit Points", "Take profit in price steps", "Risk");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevCorrected = default;
		_prevPrevCorrected = default;
		_prevClose = default;
		_prevPrevClose = default;
		_isInitialized = default;
		_level = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var step = Security.PriceStep ?? 1m;
		_level = LevelPoints * step;

		var ma = new ExponentialMovingAverage { Length = Length };
		var std = new StandardDeviation { Length = Length };

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

		StartProtection(
			new Unit(StopLossPoints * step, UnitTypes.Absolute),
			new Unit(TakeProfitPoints * step, UnitTypes.Absolute));
	}

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		decimal corrected;

		if (!_isInitialized)
		{
			corrected = maValue;
			_isInitialized = true;
		}
		else
		{
			var v1 = stdValue * stdValue;
			var v2 = (_prevCorrected - maValue) * (_prevCorrected - maValue);
			var k = (v2 < v1 || v2 == 0m) ? 0m : 1m - (v1 / v2);
			corrected = _prevCorrected + k * (maValue - _prevCorrected);
		}

		var buySignal = _prevPrevClose > _prevPrevCorrected + _level && _prevClose <= _prevCorrected + _level;
		var sellSignal = _prevPrevClose < _prevPrevCorrected - _level && _prevClose >= _prevCorrected - _level;

		if (buySignal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (sellSignal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevPrevCorrected = _prevCorrected;
		_prevPrevClose = _prevClose;
		_prevCorrected = corrected;
		_prevClose = candle.ClosePrice;
	}
}