View on GitHub

Sophia 1_1 Strategy

Sophia 1_1 is a grid-based martingale trading strategy. The strategy opens a position after four consecutive candles move in the same direction:

  • Four rising candles trigger a short entry.
  • Four falling candles trigger a long entry.

Once in the market, the algorithm adds positions every time the price moves against the current position by a fixed number of price steps (Pip Step). The volume of each additional trade is multiplied by Lot Exponent, forming a classic martingale grid.

Risk management is handled through Take Profit, Stop Loss and an optional trailing stop. The trailing mechanism starts after the profit reaches Trail Start and trails the stop level by Trail Stop price steps.

Parameters

  • Volume – base volume for the first trade.
  • Pip Step – distance in price steps before adding a new position.
  • Lot Exponent – multiplier for the volume of each additional trade.
  • Max Trades – maximum number of positions in the grid.
  • Take Profit – profit target in price steps from the average entry price.
  • Stop Loss – loss threshold in price steps from the average entry price.
  • Use Trailing – enable or disable the trailing stop.
  • Trail Start – profit required before the trailing stop becomes active.
  • Trail Stop – distance of the trailing stop in price steps.
  • Candle Type – timeframe of the candles used for calculations.
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>
/// Grid mean-reversion strategy. Enters on 3-bar momentum, exits at SMA or ATR stop.
/// </summary>
public class Sophia11Strategy : Strategy
{
	private readonly StrategyParam<int> _smaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prev1, _prev2, _prev3;

	public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Sophia11Strategy()
	{
		_smaPeriod = Param(nameof(SmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "SMA for exit target", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR for stops", "Indicators");
		_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();
		_prev1 = _prev2 = _prev3 = 0;
	}

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

		var sma = new SimpleMovingAverage { Length = SmaPeriod };
		var atr = new StandardDeviation { Length = AtrPeriod };

		SubscribeCandles(CandleType).Bind(sma, atr, ProcessCandle).Start();
	}

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

		var close = candle.ClosePrice;

		if (_prev3 > 0)
		{
			// 3-bar declining => counter-trend buy
			if (_prev1 < _prev2 && _prev2 < _prev3 && Position <= 0)
			{
				if (Position < 0) BuyMarket();
				BuyMarket();
			}
			// 3-bar rising => counter-trend sell
			else if (_prev1 > _prev2 && _prev2 > _prev3 && Position >= 0)
			{
				if (Position > 0) SellMarket();
				SellMarket();
			}
			// Exit long at SMA or ATR stop
			else if (Position > 0 && (close >= sma || (atr > 0 && close < sma - atr * 3)))
			{
				SellMarket();
			}
			// Exit short at SMA or ATR stop
			else if (Position < 0 && (close <= sma || (atr > 0 && close > sma + atr * 3)))
			{
				BuyMarket();
			}
		}

		_prev3 = _prev2;
		_prev2 = _prev1;
		_prev1 = close;
	}
}