Auf GitHub ansehen

DVD-Level-Strategie

Diese Strategie ist eine vereinfachte Übersetzung des originalen MQL5-Expertenberaters "DVD Level". Sie verwendet den Range Action Verification Index (RAVI) zur Bestimmung der Marktrichtung. RAVI wird mit exponentiellen gleitenden Durchschnitten mit Perioden 2 und 24 auf 1-Stunden-Kerzen berechnet.

Parameter

  • Volume – Ordervolumen für Trades.

Logik

  1. 1-Stunden-Kerzen abonnieren und EMA(2) und EMA(24) berechnen.
  2. RAVI = (EMA2 - EMA24) / EMA24 * 100 berechnen.
  3. Wenn RAVI unter null kreuzt, kauft die Strategie, wenn sie flat oder short ist.
  4. Wenn RAVI über null kreuzt, verkauft die Strategie, wenn sie flat oder long ist.
  5. Der integrierte Positionsschutz wird über StartProtection() aktiviert.

Der Ansatz erfasst potenzielle Umkehrungen, wenn der kurzfristige Momentum vom langfristigen Trend abweicht.

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;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// RAVI based level strategy. Opens long when the RAVI crosses below zero and short when above.
/// </summary>
public class DvdLevelStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly ExponentialMovingAverage _emaFast = new() { Length = 2 };
	private readonly ExponentialMovingAverage _emaSlow = new() { Length = 24 };
	private decimal _prevRavi;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public DvdLevelStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRavi = 0m;
		_hasPrev = false;
	}

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

		_prevRavi = 0m;
		_hasPrev = false;

		var sub = SubscribeCandles(CandleType);
		sub.Bind(_emaFast, _emaSlow, ProcessCandle).Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, sub);
			DrawIndicator(area, _emaFast);
			DrawIndicator(area, _emaSlow);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaFast, decimal emaSlow)
	{
		if (candle.State != CandleStates.Finished || emaSlow == 0)
			return;

		var ravi = (emaFast - emaSlow) / emaSlow * 100m;

		if (!_hasPrev)
		{
			_prevRavi = ravi;
			_hasPrev = true;
			return;
		}

		var crossAbove = _prevRavi <= 0 && ravi > 0;
		var crossBelow = _prevRavi >= 0 && ravi < 0;

		if (crossBelow && Position <= 0)
			BuyMarket();
		else if (crossAbove && Position >= 0)
			SellMarket();

		_prevRavi = ravi;
	}
}