View on GitHub

AntiFragile EA Strategy

Grid strategy placing layered limit orders above and below current price with increasing volume. Positions are protected by an initial stop and trailed as price moves favorably.

Details

  • Entry Criteria:
    • Long: Place buy limit orders every SpaceBetweenTrades steps below bid.
    • Short: Place sell limit orders every SpaceBetweenTrades steps above ask.
  • Long/Short: Optional for each side via TradeLong and TradeShort.
  • Exit Criteria: Trailing stop or opposite grid side execution.
  • Stops: Initial StopLossPips and trailing via TrailingStopPips.
  • Default Values:
    • StartingVolume = 0.1m
    • IncreasePercentage = 1m
    • SpaceBetweenTrades = 700m
    • NumberOfTrades = 50
    • StopLossPips = 300m
    • TrailingStopPips = 100m
    • TradeLong = true
    • TradeShort = true
    • CandleType = TimeSpan.FromMinutes(1).TimeFrame()
  • Filters:
    • Category: Grid trading
    • Direction: Both
    • Indicators: None
    • Stops: Trailing
    • Complexity: Intermediate
    • Timeframe: Any
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: High
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>
/// EMA crossover trend-following strategy.
/// </summary>
public class AntiFragileStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public AntiFragileStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "EMA");

		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "EMA");

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

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fast, slow, ProcessCandle)
			.Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
		var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}