Открыть на GitHub

Стратегия DreamBot

Обзор

DreamBot — это порт советника MetaTrader 4 «DreamBot» на платформу StockSharp. Стратегия анализирует осциллятор Force Index на часовых свечах и отслеживает моменты, когда импульс пересекает заданные бычий и медвежий уровни. Если Force Index пересекает бычий порог снизу вверх на предыдущей свече, открывается длинная позиция. Если индикатор пересекает медвежий порог сверху вниз, открывается короткая позиция. Сделки выполняются только при отсутствии открытых позиций, что повторяет оригинальную логику одного ордера.

Торговая логика

  • Подписка на свечи H1 и расчёт сглаженного Force Index (период по умолчанию 13).
  • Хранение двух последних завершённых значений индикатора. Сигналы формируются по данным предыдущих свечей, аналогично вызовам iForce со сдвигами 1 и 2 в MT4.
  • Открытие лонга, когда Force Index на предыдущей свече выше BullsThreshold, а значение двумя свечами ранее было ниже порога, и при этом позиция отсутствует.
  • Открытие шорта, когда Force Index на предыдущей свече ниже BearsThreshold, а значение двумя свечами ранее было выше порога, и позиция отсутствует.
  • Дополнительный трейлинг-стоп воспроизводит оригинал: после прибыли больше TrailingStepPoints стоп подтягивается на расстояние TrailingStartPoints от цены и следует за рынком.

Управление рисками

  • StartProtection добавляет классические стоп-лосс и тейк-профит, переводя значения в «пунктах» MetaTrader через шаг цены инструмента.
  • Трейлинг реализован через рыночное закрытие: при пробое рассчитанного уровня стратегия немедленно отправляет рыночный ордер на выход.
  • Учёт позиции ведётся по средневзвешенной цене входа, чтобы корректно работать с частичными исполнениями и реверсами.

Параметры

Параметр Описание
ForcePeriod Период сглаживания Force Index (по умолчанию 13).
TakeProfitPoints Дистанция тейк-профита в пунктах MetaTrader.
StopLossPoints Дистанция стоп-лосса в пунктах MetaTrader.
BullsThreshold Порог Force Index, сигнализирующий о бычьем импульсе.
BearsThreshold Порог Force Index, сигнализирующий о медвежьем импульсе.
EnableTrailing Включает логику трейлинг-стопа.
TrailingStartPoints Расстояние (в пунктах) между ценой и трейлинг-стопом после активации.
TrailingStepPoints Прибыль (в пунктах), требуемая для активации трейлинга.
CandleType Таймфрейм для расчёта Force Index (по умолчанию часовые свечи).

Примечания

  • Проверка параметров блокирует ситуацию, когда TrailingStepPoints больше TrailingStartPoints, как и в оригинальном советнике.
  • Ограничения брокера по минимальному стопу (MODE_STOPLEVEL) приближённо учитываются через шаг цены. При необходимости добавьте дополнительные проверки.
  • Комментарии и сообщения журнала оставлены на английском языке в соответствии с требованиями инструкций по конверсии.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// DreamBot strategy: Force Index momentum with EMA trend filter.
/// Buys when Force Index positive and close above EMA, sells when negative and below EMA.
/// </summary>
public class DreamBotStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _prevClose;
	private bool _hasPrevClose;
	private bool _wasBullish;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public DreamBotStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 100)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0m;
		_hasPrevClose = false;
		_wasBullish = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrevClose = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		var close = candle.ClosePrice;
		var volume = candle.TotalVolume;

		if (_hasPrevClose && volume > 0)
		{
			// Simple force index: (close - prevClose) * volume
			var forceIndex = (close - _prevClose) * volume;
			var isBullish = forceIndex > 0 && close > emaValue;

			if (isBullish && !_wasBullish && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (!isBullish && forceIndex < 0 && close < emaValue && _wasBullish && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}

			_wasBullish = isBullish;
		}

		_prevClose = close;
		_hasPrevClose = true;
	}
}