Ver en GitHub

VWAP Mean Magnet v9 (Simple Alert) Strategy

This simplified version of the VWAP Mean Magnet strategy uses VWAP and RSI without volume filtering. Trades open when price deviates from VWAP and RSI reaches extreme levels. Positions are closed when price reverts back to VWAP.

Details

  • Entry Criteria:
    • Long: price < VWAP and RSI < oversold.
    • Short: price > VWAP and RSI > overbought.
  • Long/Short: Both.
  • Exit Criteria:
    • Close position when price returns to VWAP.
  • Stops: Yes, percent stop-loss.
  • Default Values:
    • VWAP length = 60
    • RSI length = 14
    • RSI overbought = 65
    • RSI oversold = 25
    • Stop loss % = 0.5
  • Filters:
    • Category: Mean reversion
    • Direction: Both
    • Indicators: Multiple
    • Stops: Yes
    • Complexity: Simple
    • Timeframe: Intraday
using System;
using System.Linq;
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>
/// VWAP mean reversion with RSI.
/// </summary>
public class VwapMeanMagnetV9SimpleAlertStrategy : Strategy
{
	private readonly StrategyParam<int> _vwapLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _rsiOverbought;
	private readonly StrategyParam<int> _rsiOversold;
	private readonly StrategyParam<decimal> _stopLossPercent;
	private readonly StrategyParam<DataType> _candleType;

	public int VwapLength { get => _vwapLength.Value; set => _vwapLength.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int RsiOverbought { get => _rsiOverbought.Value; set => _rsiOverbought.Value = value; }
	public int RsiOversold { get => _rsiOversold.Value; set => _rsiOversold.Value = value; }
	public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public VwapMeanMagnetV9SimpleAlertStrategy()
	{
		_vwapLength = Param(nameof(VwapLength), 20).SetDisplay("VWAP Length", "VWAP Length", "General");
		_rsiLength = Param(nameof(RsiLength), 14).SetDisplay("RSI Length", "RSI Length", "General");
		_rsiOverbought = Param(nameof(RsiOverbought), 65).SetDisplay("RSI Overbought", "RSI Overbought", "General");
		_rsiOversold = Param(nameof(RsiOversold), 35).SetDisplay("RSI Oversold", "RSI Oversold", "General");
		_stopLossPercent = Param(nameof(StopLossPercent), 0.5m).SetDisplay("Stop Loss %", "Stop Loss %", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame()).SetDisplay("Candle Type", "Candle Type", "General");
	}

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

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

		var vwap = new VolumeWeightedMovingAverage { Length = VwapLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(vwap, rsi, ProcessCandle).Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, vwap);
			DrawIndicator(area, rsi);
			DrawOwnTrades(area);
		}
	}

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

		if (candle.ClosePrice < vwapValue && rsiValue < RsiOversold && Position <= 0)
			BuyMarket();
		else if (candle.ClosePrice > vwapValue && rsiValue > RsiOverbought && Position >= 0)
			SellMarket();

		if (Position > 0 && candle.ClosePrice >= vwapValue)
			SellMarket();
		else if (Position < 0 && candle.ClosePrice <= vwapValue)
			BuyMarket();
	}
}