在 GitHub 上查看

DVD Level 策略

本策略为原版 "DVD Level" MQL5 程序的简化移植。它使用 RAVI 指标判断市场方向,RAVI 通过在 1 小时K线上计算 2 和 24 周期指数移动平均得出。

参数

  • Volume – 下单数量。

逻辑

  1. 订阅1小时K线并计算 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;
	}
}