View on GitHub

Supertrend Ema Vol Strategy

Strategy combining Supertrend with EMA trend confirmation and volume filter. Enters on Supertrend reversals when price is above or below the EMA and volume exceeds its EMA. Implements ATR-based stop loss.

Details

  • Entry Criteria:
    • Long: Supertrend turns up, price above EMA, volume above Volume EMA
    • Short: Supertrend turns down, price below EMA, volume above Volume EMA
  • Long/Short: Configurable
  • Exit Criteria: Supertrend reversal or ATR-based stop loss
  • Stops: ATR multiple
  • Default Values:
    • AtrPeriod = 10
    • AtrMultiplier = 3m
    • EmaLength = 21
    • StartDate = new DateTimeOffset(2024, 1, 2, 0, 0, 0, TimeSpan.Zero)
    • AllowLong = true
    • AllowShort = false
    • SlMultiplier = 2m
    • UseVolumeFilter = true
    • VolumeEmaLength = 20
    • CandleType = TimeSpan.FromMinutes(1).TimeFrame()
  • Filters:
    • Category: Trend
    • Direction: Both
    • Indicators: Supertrend, EMA, Volume EMA, ATR
    • Stops: ATR
    • Complexity: Intermediate
    • Timeframe: Intraday
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: Medium
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>
/// Supertrend EMA volume strategy using EMA crossover.
/// </summary>
public class SupertrendEmaVolStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

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

	public SupertrendEmaVolStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var prevF = 0m; var prevS = 0m; var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, (candle, f, s) =>
		{
			if (candle.State != CandleStates.Finished) return;
			if (!fast.IsFormed || !slow.IsFormed) return;
			if (!init) { prevF = f; prevS = s; init = true; return; }
			if (candle.OpenTime - lastSignal >= cooldown)
			{
				if (prevF <= prevS && f > s && Position <= 0) { BuyMarket(); lastSignal = candle.OpenTime; }
				else if (prevF >= prevS && f < s && Position >= 0) { SellMarket(); lastSignal = candle.OpenTime; }
			}
			prevF = f; prevS = s;
		}).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}
}