Auf GitHub ansehen

Strategie für nicht saisonbereinigtes ATR und Prognose

Übersicht

Diese Strategie analysiert die durchschnittliche Handelsspanne der letzten Kerzen und prognostiziert die nächste Spanne mithilfe linearer Trendregression. Sie platziert keine Trades, sondern zeigt Statistiken an, die für manuelle Entscheidungen genutzt werden können.

Parameter

  • SampleSize – Anzahl der letzten Kerzen für die Berechnungen.
  • DesiredRange – Zielspanne für die Schätzung des Konfidenzintervalls.
  • CandleType – zu analysierende Kerzenserie.

Indikatoren

  • SimpleMovingAverage – wird zur Berechnung der durchschnittlichen Spanne verwendet.
  • StandardDeviation – misst die Volatilität der Spanne.
  • Lineare Regression (benutzerdefiniert) – prognostiziert die nächste Spanne und den MAPE.

Verhalten

Für jede abgeschlossene Kerze führt die Strategie folgendes aus:

  1. Berechnet die Spanne (Hoch minus Tief) und aktualisiert Durchschnitt und Standardabweichung.
  2. Schätzt ein Konfidenzintervall für die gewünschte Spanne.
  3. Erstellt einen linearen Trend der Spannen und prognostiziert die nächste.
  4. Bewertet den mittleren absoluten prozentualen Fehler (MAPE) der Prognose.

Werte werden in der Strategieausgabe protokolliert und können auf dem Chart visualisiert werden.

Hinweise

  • Die Strategie ist informativ und führt keine Orders aus.
  • Spannen werden in Preiseinheiten gemessen; passen Sie den Parameter DesiredRange an Ihr Instrument an.
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>
/// EMA crossover strategy with volatility awareness.
/// </summary>
public class UnseasonalisedAtrForecastStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public UnseasonalisedAtrForecastStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Parameters");
		_slowPeriod = Param(nameof(SlowPeriod), 36)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Parameters");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fast, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
		var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}