Открыть на GitHub

Стратегия DVD Level

Упрощённая адаптация советника "DVD Level" на платформу StockSharp. Для определения направления используется индикатор RAVI, рассчитываемый по экспоненциальным средним с периодами 2 и 24 на часовом таймфрейме.

Параметры

  • Volume – объём заявки для сделок.

Логика

  1. Подписка на часовые свечи и вычисление EMA(2) и EMA(24).
  2. Расчёт RAVI = (EMA2 - EMA24) / EMA24 * 100.
  3. При пересечении RAVI уровня 0 сверху вниз стратегия покупает, если позиции нет или открыта короткая позиция.
  4. При пересечении RAVI уровня 0 снизу вверх стратегия продаёт, если позиции нет или открыта длинная позиция.
  5. Защита позиции включается вызовом StartProtection().

Стратегия пытается поймать моменты смены краткосрочного импульса относительно долгосрочного тренда.

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;
	}
}