The Daydream Strategy is a direct conversion of the MQL4 expert advisor Daydream by Cothool. The original robot trades the USD/JPY H1 chart by watching for breakouts of a recent price channel and then managing trades with a virtual, trailing take profit. This StockSharp port keeps the same core logic while using the high-level API: Donchian Channels deliver the breakout levels, orders are placed through BuyMarket / SellMarket, and all trailing logic is handled inside the strategy without placing actual take-profit orders at the exchange.
Key characteristics:
Single-position breakout system that only flips direction after a candle closes outside the previous channel extremes.
Virtual take profit measured in pips that ratchets with price to lock profits and closes trades when reached.
Entry throttling so that only one trading action (open/close) can happen per candle, mirroring the MQL4 LastOrderTime restriction.
Trading Logic
Build a Donchian Channel with ChannelPeriod completed candles and store the previous upper/lower levels.
When a candle closes below the previous lower band:
Close an existing short position.
On the next candle, open a new long position with OrderVolume and set the virtual take-profit level to close + TakeProfitPips * pipSize.
When a candle closes above the previous upper band:
Close an existing long position.
On the next candle, open a new short position and set the virtual take-profit to close - TakeProfitPips * pipSize.
While a position is active, tighten the virtual take-profit price each bar. If price hits that level on a subsequent candle, exit the trade.
The pip size is derived from the security PriceStep. For JPY pairs this converts a 0.001 step into a 0.01 pip increment, matching the MQL behavior.
Parameters
Name
Description
Default
Notes
OrderVolume
Volume used for each new market entry.
1
Matches the Lots input from the MQL expert.
ChannelPeriod
Number of completed candles in the Donchian Channel.
25
Mirrors ChannelPeriod in MQL.
Slippage
Allowed slippage in points.
3
Stored for completeness; market orders ignore it.
TakeProfitPips
Distance of the virtual take profit in pips.
15
Moves with price while the position is open.
CandleType
Timeframe used to build the Donchian Channel.
1 hour
Default timeframe of the original strategy.
Workflow Diagram
Candle closes
│
├─► Update Donchian Channel (previous bands)
│
├─► Breakout below previous low? ──► Close short → schedule long next bar
│
├─► Breakout above previous high? ─► Close long → schedule short next bar
│
└─► Trail virtual take profit in the direction of the open position
└─► Price reached virtual target? → Close position
Usage Notes
Attach the strategy to any security with streaming candles. The default settings match the original USD/JPY H1 recommendation.
Only one position exists at a time. The strategy prevents opening and closing trades within the same candle to replicate the MQL4 logic.
The take profit is virtual: the exit occurs through a market order once the calculated level is breached. No actual TP orders are sent to the broker.
Adjust CandleType to run on different timeframes. Higher periods require sufficient historical data to warm up the Donchian Channel.
Differences from the MQL4 Version
Uses StockSharp DonchianChannels indicator instead of manually scanning highs and lows.
Trailing take profit and action throttling are preserved, but the execution uses StockSharp market orders without relying on MT4 ticket management.
The Slippage parameter is kept for parity, although market execution in StockSharp does not apply slippage the same way as MT4.
Files
CS/DaydreamStrategy.cs – strategy implementation in C#.
Python version: not yet implemented.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Daydream strategy - Donchian channel breakout.
/// Buys when price crosses above the midpoint of the channel.
/// Sells when price crosses below the midpoint.
/// </summary>
public class DaydreamStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public DaydreamStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 20)
.SetDisplay("Channel Period", "Donchian channel lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevMid = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev)
{
_prevClose = close;
_prevMid = mid;
_hasPrev = true;
return;
}
// Cross above midpoint
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Cross below midpoint
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevMid = mid;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class daydream_strategy(Strategy):
def __init__(self):
super(daydream_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 20) \
.SetDisplay("Channel Period", "Donchian channel lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
@property
def channel_period(self):
return self._channel_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(daydream_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(daydream_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
high_val = float(highest)
low_val = float(lowest)
mid = (high_val + low_val) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return daydream_strategy()