Ver no GitHub

Escape Strategy

This strategy trades based on simple moving averages of candle open prices. It compares the most recent 5-minute close with two moving averages calculated on the open price:

  • Fast SMA (4 periods) – used as threshold for short entries.
  • Slow SMA (5 periods) – used as threshold for long entries.

How it works

  1. On each finished 5-minute candle the strategy updates two SMAs of the candle open price.
  2. If there is no active position:
    • Enter long when the latest close is below the slow SMA.
    • Enter short when the latest close is above the fast SMA.
  3. After entering a position the strategy sets fixed stop-loss and take-profit levels measured in price units.
  4. Position is closed when either take-profit or stop-loss is reached.

The logic uses high level StockSharp API and is intended for educational purposes.

Parameters

Name Description Default
FastLength Period of the fast SMA. 4
SlowLength Period of the slow SMA. 5
TakeProfitLong Take profit distance for long trades in price units. 25
TakeProfitShort Take profit distance for short trades in price units. 26
StopLossLong Stop loss distance for long trades in price units. 25
StopLossShort Stop loss distance for short trades in price units. 3
CandleType Candle type used for analysis. TimeFrame(5m)

All parameters can be optimized via the StockSharp optimizer.

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>
/// Simple strategy based on SMA of open prices and previous close comparison.
/// Buys when the previous close is below the slow SMA.
/// Sells short when the previous close is above the fast SMA.
/// Uses fixed take profit and stop loss levels for both directions.
/// </summary>
public class EscapeStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<decimal> _takeProfitLong;
	private readonly StrategyParam<decimal> _takeProfitShort;
	private readonly StrategyParam<decimal> _stopLossLong;
	private readonly StrategyParam<decimal> _stopLossShort;
	private readonly StrategyParam<DataType> _candleType;

	private SimpleMovingAverage _fastMa;
	private SimpleMovingAverage _slowMa;
	private bool _initialized;
	private decimal _previousClose;
	private decimal _previousFast;
	private decimal _previousSlow;

	/// <summary>
	/// Length of fast SMA.
	/// </summary>
	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	/// <summary>
	/// Length of slow SMA.
	/// </summary>
	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	/// <summary>
	/// Take profit distance for long positions in price units.
	/// </summary>
	public decimal TakeProfitLong
	{
		get => _takeProfitLong.Value;
		set => _takeProfitLong.Value = value;
	}

	/// <summary>
	/// Take profit distance for short positions in price units.
	/// </summary>
	public decimal TakeProfitShort
	{
		get => _takeProfitShort.Value;
		set => _takeProfitShort.Value = value;
	}

	/// <summary>
	/// Stop loss distance for long positions in price units.
	/// </summary>
	public decimal StopLossLong
	{
		get => _stopLossLong.Value;
		set => _stopLossLong.Value = value;
	}

	/// <summary>
	/// Stop loss distance for short positions in price units.
	/// </summary>
	public decimal StopLossShort
	{
		get => _stopLossShort.Value;
		set => _stopLossShort.Value = value;
	}

	/// <summary>
	/// Candle type to analyze.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public EscapeStrategy()
	{
		_fastLength = Param(nameof(FastLength), 4)
			.SetDisplay("Fast SMA Length", "Length of fast SMA", "Parameters")
			.SetGreaterThanZero()
			;

		_slowLength = Param(nameof(SlowLength), 5)
			.SetDisplay("Slow SMA Length", "Length of slow SMA", "Parameters")
			.SetGreaterThanZero()
			;

		_takeProfitLong = Param(nameof(TakeProfitLong), 25m)
			.SetDisplay("Take Profit Long", "Take profit for long trades", "Trading")
			.SetGreaterThanZero();

		_takeProfitShort = Param(nameof(TakeProfitShort), 26m)
			.SetDisplay("Take Profit Short", "Take profit for short trades", "Trading")
			.SetGreaterThanZero();

		_stopLossLong = Param(nameof(StopLossLong), 25m)
			.SetDisplay("Stop Loss Long", "Stop loss for long trades", "Trading")
			.SetGreaterThanZero();

		_stopLossShort = Param(nameof(StopLossShort), 3m)
			.SetDisplay("Stop Loss Short", "Stop loss for short trades", "Trading")
			.SetGreaterThanZero();

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

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_fastMa = null;
		_slowMa = null;
		_initialized = false;
		_previousClose = 0m;
		_previousFast = 0m;
		_previousSlow = 0m;
	}

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

		_fastMa = new SMA { Length = FastLength };
		_slowMa = new SMA { Length = SlowLength };

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

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

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);
	}

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

		var fast = _fastMa!.Process(new DecimalIndicatorValue(_fastMa, candle.OpenPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();
		var slow = _slowMa!.Process(new DecimalIndicatorValue(_slowMa, candle.OpenPrice, candle.OpenTime) { IsFinal = true }).ToDecimal();

		if (!_initialized)
		{
			_initialized = true;
			_previousClose = candle.ClosePrice;
			_previousFast = fast;
			_previousSlow = slow;
			return;
		}

		var close = candle.ClosePrice;
		var buySignal = _previousClose >= _previousSlow && close < slow;
		var sellSignal = _previousClose <= _previousFast && close > fast;

		if (Position == 0)
		{
			if (buySignal)
				BuyMarket();
			else if (sellSignal)
				SellMarket();
		}

		_previousClose = close;
		_previousFast = fast;
		_previousSlow = slow;
	}
}