Ver no GitHub

BuySell Strategy

This strategy emulates the BuySell MetaTrader expert. It combines a moving average with the Average True Range (ATR) to detect trend reversals. When the moving average turns upward, the system considers the market bullish; when it turns downward, it considers the market bearish. A trade is opened only if the previous bar was in the opposite state, confirming a reversal. Optional stop-loss and take-profit levels are expressed in price points.

Details

  • Entry Logic
    • Long: moving average changes from falling to rising and the previous bar was bearish.
    • Short: moving average changes from rising to falling and the previous bar was bullish.
  • Exit Logic
    • Long: moving average turns down or stop-loss / take-profit triggers.
    • Short: moving average turns up or stop-loss / take-profit triggers.
  • Indicators: Simple Moving Average (SMA) and ATR.
  • Stops: Both stop-loss and take-profit in points.
  • Permissions: separate flags allow or forbid opening/closing long and short positions.
  • Default Timeframe: 4-hour candles.

Parameters

Name Default Description
MaPeriod 14 Moving average period.
AtrPeriod 60 ATR period.
StopLoss 1000 Stop-loss in price points.
TakeProfit 2000 Take-profit in price points.
AllowLongEntry true Permission to open long positions.
AllowShortEntry true Permission to open short positions.
AllowLongExit true Permission to close long positions.
AllowShortExit true Permission to close short positions.
CandleType H4 Timeframe used for calculations.

Usage

  1. Add the strategy to your StockSharp solution.
  2. Configure the parameters as needed.
  3. Run the strategy in live or backtest mode. Trades are executed using BuyMarket and SellMarket orders.

The approach is suitable for markets where trend reversals are accompanied by volatility changes captured by ATR.

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>
/// Buy/Sell strategy based on EMA crossover.
/// </summary>
public class BuySellStrategy : 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 BuySellStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 28)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_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;
	}
}