Auf GitHub ansehen

Aeron Robot Grid Strategy

This strategy implements a grid-based hedging system inspired by the AeronRobot expert advisor. It places buy and sell orders at predefined price intervals and increases position volume after each new order. The approach seeks to capture small price oscillations while controlling risk through configurable take-profit, stop-loss and trade limits.

The strategy works with both long and short positions. When price moves in steps defined by the Gap parameter, a new order is opened with volume multiplied by LotsFactor. Profits are secured when price returns by TakeProfit points, and losses are cut if the move reaches StopLoss points. The Hedging flag allows maintaining positions on both sides simultaneously.

Details

  • Entry Criteria:
    • Long: price falls by Gap points from the last buy price.
    • Short: price rises by Gap points from the last sell price.
  • Volume Management: volume of each new order is multiplied by LotsFactor.
  • Exit Criteria:
    • positions on a side are closed when profit exceeds TakeProfit points.
    • positions on a side are closed when loss exceeds StopLoss points.
  • Parameters:
    • FirstLot – initial order volume.
    • LotsFactor – multiplier for subsequent orders.
    • Gap – base distance between grid levels in points.
    • GapFactor – multiplier that expands the gap after each trade.
    • MaxTrades – maximum number of trades per side.
    • Hedging – allow simultaneous long and short positions.
    • TakeProfit – target in points.
    • StopLoss – protective limit in points.
    • CandleType – candle timeframe used for processing.
  • Long/Short: both.
  • Filters:
    • Category: Grid / Mean reversion
    • Direction: Both
    • Indicators: None
    • Stops: Yes
    • Complexity: Medium
    • Timeframe: Short-term
    • 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 strategy (converted from grid).
/// </summary>
public class AeronRobotStrategy : 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 AeronRobotStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

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

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "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;
	}
}