Auf GitHub ansehen

DreamBot Strategy

Overview

DreamBot is a StockSharp port of the MetaTrader 4 expert advisor "DreamBot". The strategy monitors the Force Index oscillator on hourly candles and waits for the momentum to cross bullish or bearish thresholds. When the Force Index crosses above the bullish level after being below it on the previous bar, the strategy opens a long position. When the Force Index crosses below the bearish level after being above it, the strategy opens a short position. Trading occurs only when there is no existing position, mirroring the single-position logic of the original robot.

Trading logic

  • Subscribe to H1 candles and compute a smoothed Force Index (length 13 by default).
  • Track the last two completed Force Index values. Signals are generated using the previous bar values, exactly like the MT4 implementation (iForce with shift 1 and 2).
  • Enter long when the Force Index on the previous candle is above BullsThreshold and the value two candles back was below the threshold, provided no position is open.
  • Enter short when the Force Index on the previous candle is below BearsThreshold and the value two candles back was above the threshold, provided no position is open.
  • Optional trailing stop replicates the original EA: once profit exceeds TrailingStepPoints, a stop level is pulled to TrailingStartPoints away from price and follows further advances.

Risk management

  • StartProtection attaches classic stop-loss and take-profit orders using the MetaTrader "points" distance converted through the instrument price step.
  • Trailing protection is market-based: when the computed trailing level is breached, the strategy sends a market order to close the position immediately.
  • Position tracking captures the volume-weighted entry price so the trailing logic aligns with partial fills and reversals.

Parameters

Parameter Description
ForcePeriod Force Index smoothing period (default 13).
TakeProfitPoints Take-profit distance in MetaTrader points.
StopLossPoints Stop-loss distance in MetaTrader points.
BullsThreshold Bullish Force Index threshold that enables long entries.
BearsThreshold Bearish Force Index threshold that enables short entries.
EnableTrailing Enables the trailing stop logic.
TrailingStartPoints Distance (in points) maintained between price and trailing stop once activated.
TrailingStepPoints Profit (in points) required before the trailing stop activates.
CandleType Timeframe used for Force Index calculations (defaults to H1 candles).

Notes

  • The parameter validation keeps the trailing trigger (TrailingStepPoints) from exceeding the trailing distance (TrailingStartPoints), matching the MetaTrader safety check.
  • Stop-level enforcement from the original EA (broker MODE_STOPLEVEL) is approximated through StockSharp's price-step conversions. Depending on broker constraints, additional validation may be required.
  • All code comments and logs are provided in English as requested by the conversion guidelines.
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;
	}
}