Ver no GitHub

Machine Learning SuperTrend TP SL

Strategy based on SuperTrend indicator with trailing take profit and stop loss.

The stop and profit levels follow the SuperTrend line, aiming to capture sustained moves while locking in gains as momentum fades.

Details

  • Entry Criteria: Price crossing the SuperTrend line.
  • Long/Short: Both directions.
  • Exit Criteria: Opposite signal or hitting trailing take profit/stop loss.
  • Stops: Yes, trailing by SuperTrend.
  • Default Values:
    • AtrPeriod = 4
    • AtrFactor = 2.94m
    • StopLossMultiplier = 0.0025m
    • TakeProfitMultiplier = 0.022m
    • CandleType = TimeSpan.FromMinutes(5)
  • Filters:
    • Category: Trend
    • Direction: Both
    • Indicators: ATR, SuperTrend
    • Stops: Yes
    • Complexity: Intermediate
    • Timeframe: Intraday (5m)
    • 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 strategy with trailing take profit and stop loss.
	/// </summary>
	public class MachineLearningSuperTrendStrategy : Strategy
	{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrFactor;
	private readonly StrategyParam<decimal> _stopLossMultiplier;
	private readonly StrategyParam<decimal> _takeProfitMultiplier;
	private readonly StrategyParam<int> _cooldownBars;
	
	private SuperTrend _superTrend;
	private int _prevDirection;
	private decimal _stopLoss;
	private decimal _takeProfit;
	private int _barsFromSignal;
	
	/// <summary>
	/// Candle type for strategy calculation.
	/// </summary>
	public DataType CandleType
	{
	get => _candleType.Value;
	set => _candleType.Value = value;
	}
	
	/// <summary>
	/// ATR period for SuperTrend calculation.
	/// </summary>
	public int AtrPeriod
	{
	get => _atrPeriod.Value;
	set => _atrPeriod.Value = value;
	}
	
	/// <summary>
	/// ATR multiplier for SuperTrend.
	/// </summary>
	public decimal AtrFactor
	{
	get => _atrFactor.Value;
	set => _atrFactor.Value = value;
	}
	
	/// <summary>
	/// Stop loss multiplier relative to SuperTrend value.
	/// </summary>
	public decimal StopLossMultiplier
	{
	get => _stopLossMultiplier.Value;
	set => _stopLossMultiplier.Value = value;
	}
	
	/// <summary>
	/// Take profit multiplier relative to SuperTrend value.
	/// </summary>
	public decimal TakeProfitMultiplier
	{
	get => _takeProfitMultiplier.Value;
	set => _takeProfitMultiplier.Value = value;
	}

	/// <summary>
	/// Minimum bars between trade actions.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}
	
	/// <summary>
	/// Initialize strategy parameters.
	/// </summary>
	public MachineLearningSuperTrendStrategy()
	{
	_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(10).TimeFrame())
	.SetDisplay("Candle Type", "Type of candles to use", "General");
	
	_atrPeriod = Param(nameof(AtrPeriod), 4)
	.SetGreaterThanZero()
	.SetDisplay("ATR Period", "ATR length for SuperTrend", "SuperTrend")
	
	.SetOptimize(3, 20, 1);
	
	_atrFactor = Param(nameof(AtrFactor), 2.94m)
	.SetRange(0.5m, 10m)
	.SetDisplay("Multiplier", "ATR multiplier for SuperTrend", "SuperTrend")
	
	.SetOptimize(1m, 5m, 0.5m);
	
	_stopLossMultiplier = Param(nameof(StopLossMultiplier), 0.01m)
	.SetRange(0m, 0.05m)
	.SetDisplay("Stop Loss Mult", "Percentage from SuperTrend", "Risk Management");
	
	_takeProfitMultiplier = Param(nameof(TakeProfitMultiplier), 0.03m)
	.SetRange(0m, 0.1m)
	.SetDisplay("Take Profit Mult", "Percentage from SuperTrend", "Risk Management");

	_cooldownBars = Param(nameof(CooldownBars), 8)
		.SetGreaterThanZero()
		.SetDisplay("Cooldown Bars", "Bars between trade actions", "Risk Management");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
	return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
	base.OnReseted();
	_superTrend = null;
	_prevDirection = 0;
	_stopLoss = 0;
	_takeProfit = 0;
	_barsFromSignal = CooldownBars;
	}
	
	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
	base.OnStarted2(time);
	_barsFromSignal = CooldownBars;
	
	_superTrend = new SuperTrend
	{
	Length = AtrPeriod,
	Multiplier = AtrFactor
	};
	
	var dummyEma1 = new ExponentialMovingAverage { Length = 10 };
	var dummyEma2 = new ExponentialMovingAverage { Length = 20 };

	var subscription = SubscribeCandles(CandleType);
	subscription
	.Bind(dummyEma1, dummyEma2, ProcessCandle)
	.Start();
	
	var area = CreateChartArea();
	if (area != null)
	{
	DrawCandles(area, subscription);
	DrawIndicator(area, _superTrend);
	DrawOwnTrades(area);
	}
	}
	
	private void ProcessCandle(ICandleMessage candle, decimal d1, decimal d2)
	{
	if (candle.State != CandleStates.Finished)
	return;

	var stResult = _superTrend.Process(new CandleIndicatorValue(_superTrend, candle));
	if (!_superTrend.IsFormed || stResult.IsEmpty)
	return;

	var superTrendValue = stResult.GetValue<decimal>();
	var direction = candle.ClosePrice > superTrendValue ? 1 : -1;
	var directionChanged = _prevDirection != 0 && direction != _prevDirection;
	_barsFromSignal++;
	var canTradeNow = _barsFromSignal >= CooldownBars;
	
	_stopLoss = direction == 1
	? superTrendValue - superTrendValue * StopLossMultiplier
	: superTrendValue + superTrendValue * StopLossMultiplier;
	
	_takeProfit = direction == 1
	? superTrendValue + superTrendValue * TakeProfitMultiplier
	: superTrendValue - superTrendValue * TakeProfitMultiplier;
	
	if (canTradeNow && directionChanged)
	{
	if (direction == 1 && Position <= 0)
	BuyMarket();
	else if (direction == -1 && Position >= 0)
	SellMarket();
	_barsFromSignal = 0;
	}
	
	if (canTradeNow && Position > 0)
	{
	if (candle.ClosePrice <= _stopLoss || candle.ClosePrice >= _takeProfit)
	{
	SellMarket();
	_barsFromSignal = 0;
	}
	}
	else if (canTradeNow && Position < 0)
	{
	if (candle.ClosePrice >= _stopLoss || candle.ClosePrice <= _takeProfit)
	{
	BuyMarket();
	_barsFromSignal = 0;
	}
	}
	
	_prevDirection = direction;
	}
	}