Открыть на GitHub

Стратегия Godbot

Стратегия торгует с помощью индикатора Bollinger Bands и скользящих средних для поиска разворотов и подтверждения тренда.

Логика

  • Работает на основном таймфрейме свечей (по умолчанию 30 минут).
  • На этом таймфрейме рассчитываются Bollinger Bands и EMA.
  • Дополнительно на более высоком таймфрейме (по умолчанию 1 день) вычисляется DEMA для определения глобального тренда.
  • Закрывает длинные позиции, когда цена возвращается ниже верхней полосы.
  • Закрывает короткие позиции, когда цена возвращается выше нижней полосы.
  • Открывает длинную позицию, когда цена пересекает нижнюю полосу вверх при растущих DEMA и EMA.
  • Открывает короткую позицию, когда цена пересекает верхнюю полосу вниз при падающих DEMA и EMA.

Параметры

  • Bollinger Period – период Bollinger Bands.
  • Bollinger Deviation – множитель ширины полос.
  • EMA Period – период EMA для фильтра тренда.
  • DEMA Period – период DEMA на старшем таймфрейме.
  • Candle Type – таймфрейм для Bollinger Bands и EMA.
  • DEMA Candle Type – таймфрейм для DEMA.

Примечания

  • В один момент времени поддерживается только одна позиция.
  • Для входов и выходов используются рыночные заявки.
  • Перед началом торговли необходимо накопить достаточное количество данных DEMA.
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>
/// Strategy based on Bollinger Bands and EMA trend confirmation.
/// Buys when price crosses below lower band with uptrend, sells when above upper band with downtrend.
/// </summary>
public class GodbotStrategy : Strategy
{
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private bool _hasPrevEma;

	public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
	public decimal BollingerDeviation { get => _bollingerDeviation.Value; set => _bollingerDeviation.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public GodbotStrategy()
	{
		_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetGreaterThanZero()
			.SetDisplay("BB Deviation", "Bollinger Bands deviation", "Indicators");

		_maPeriod = Param(nameof(MaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period for trend", "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();
		_prevEma = 0;
		_hasPrevEma = false;
	}

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

		var bb = new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};
		var ema = new ExponentialMovingAverage { Length = MaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, ProcessEma);
		subscription
			.BindEx(bb, ProcessBB)
			.Start();
	}

	private void ProcessEma(ICandleMessage candle, decimal emaVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		_prevEma = emaVal;
		_hasPrevEma = true;
	}

	private void ProcessBB(ICandleMessage candle, IIndicatorValue bbValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_hasPrevEma)
			return;

		var bb = (BollingerBandsValue)bbValue;
		if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower || bb.MovingAverage is not decimal middle)
			return;

		var close = candle.ClosePrice;

		// Buy: price below lower band
		if (close < lower && Position <= 0)
			BuyMarket();
		// Sell: price above upper band
		else if (close > upper && Position >= 0)
			SellMarket();
	}
}