This strategy is a StockSharp port of the MetaTrader 4 expert advisor "PROphet". The original EA evaluates the recent trading ran
ge across four historical candles and uses those weighted ranges to trigger new trades. It keeps positions open only between the
European and U.S. sessions and trails the stop-loss whenever price moves a fixed distance in favour of the trade. The StockSharp
implementation keeps all of those mechanics while adapting them to the netting model used by StockSharp portfolios.
Trading logic
Subscribe to the configured timeframe (CandleType, default M5) and process only finished candles.
Maintain the three most recent completed candles to reproduce the High[i] and Low[i] indexing used by the MQL version.
Compute the long trigger Qu(X1, X2, X3, X4) and the short trigger Qu(Y1, Y2, Y3, Y4) on every bar. Each term multiplies a
weighted range (for example |High[1] - Low[2]|) by the corresponding weight minus one hundred, exactly as in the original code.
Allow new entries only when the current hour falls between TradeStartHour and TradeEndHour (inclusive). This mimics the man
ual trading window from the MQL expert (10:00 through 18:00 by default).
Use a single market order whose volume neutralises any opposite exposure before opening the new position. This mirrors the Mag
ic Number filters from the MetaTrader implementation.
Risk management and trailing
The strategy converts the MetaTrader point-based stop distances to price units via the instrument PriceStep. The defaults (B uyStopLossPoints = 68, SellStopLossPoints = 72) match the MQL extern variables.
Once the bid (for long trades) or the ask (for short trades) moves beyond the existing stop by spread + 2 * stopDistance, th
e trailing stop is advanced to currentPrice ± stopDistance, using live Level-1 data when available.
Open trades are force-closed after ExitHour. The default value (18) reproduces the original behaviour of closing the position
s after 18:00 server time.
Protective exits use market orders because StockSharp's high-level API does not automatically generate stop orders. This keeps
behaviour deterministic across brokers.
Parameters
Parameter
Description
AllowBuy
Enables long trades.
AllowSell
Enables short trades.
X1, X2, X3, X4
Weights applied to the long-side range components inside the Qu formula.
BuyStopLossPoints
Stop-loss distance for long trades expressed in MetaTrader points.
Y1, Y2, Y3, Y4
Weights applied to the short-side range components inside the Qu formula.
SellStopLossPoints
Stop-loss distance for short trades expressed in MetaTrader points.
TradeVolume
Base volume (lots) used for new entries. Extra volume is added automatically to close opposite exposure.
TradeStartHour
First hour of the trading window (inclusive).
TradeEndHour
Last hour of the trading window (inclusive).
ExitHour
Hour after which all open trades are closed.
CandleType
Timeframe of the candles used for analysis.
Notes
StockSharp portfolios are netting by default. When a new signal appears the strategy adds the volume required to flatten the ex
isting position before opening the new trade, which reproduces the single-position-per-direction design from the MetaTrader expe
rt.
The MQL script used the symbol spread reported by MarketInfo. The port retrieves the spread from Level-1 data when available
and falls back to a single price step otherwise.
Because the trailing stop is evaluated on the close of each finished candle, slippage may occur compared to the tick-level stop
updates performed by the original EA.
using System;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Translation of the MetaTrader "PROphet" expert advisor.
/// Uses a range-weighted signal from previous candles to enter trades.
/// </summary>
public class ProphetStrategy : Strategy
{
private readonly StrategyParam<int> _x1;
private readonly StrategyParam<int> _x2;
private readonly StrategyParam<int> _x3;
private readonly StrategyParam<int> _x4;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _candle1;
private ICandleMessage _candle2;
private ICandleMessage _candle3;
private decimal _entryPrice;
public ProphetStrategy()
{
_x1 = Param(nameof(X1), 9)
.SetDisplay("X1", "Weight applied to |High[1] - Low[2]|.", "Signal");
_x2 = Param(nameof(X2), 29)
.SetDisplay("X2", "Weight applied to |High[3] - Low[2]|.", "Signal");
_x3 = Param(nameof(X3), 94)
.SetDisplay("X3", "Weight applied to |High[2] - Low[1]|.", "Signal");
_x4 = Param(nameof(X4), 125)
.SetDisplay("X4", "Weight applied to |High[2] - Low[3]|.", "Signal");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations.", "General");
}
public int X1 { get => _x1.Value; set => _x1.Value = value; }
public int X2 { get => _x2.Value; set => _x2.Value = value; }
public int X3 { get => _x3.Value; set => _x3.Value = value; }
public int X4 { get => _x4.Value; set => _x4.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candle1 = null;
_candle2 = null;
_candle3 = null;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Shift history
_candle3 = _candle2;
_candle2 = _candle1;
_candle1 = candle;
if (_candle1 == null || _candle2 == null || _candle3 == null)
return;
// Manage position - simple exit on reversal signal
if (Position > 0)
{
var sellSignal = CalculateSignal(true);
if (sellSignal > 0)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
var buySignal = CalculateSignal(false);
if (buySignal > 0)
{
BuyMarket();
_entryPrice = 0;
}
}
// Entry
if (Position == 0)
{
var buySignal = CalculateSignal(false);
var sellSignal = CalculateSignal(true);
if (buySignal > 0 && buySignal > sellSignal)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (sellSignal > 0 && sellSignal > buySignal)
{
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
}
private decimal CalculateSignal(bool isSell)
{
var term1 = Math.Abs(_candle1.HighPrice - _candle2.LowPrice);
var term2 = Math.Abs(_candle3.HighPrice - _candle2.LowPrice);
var term3 = Math.Abs(_candle2.HighPrice - _candle1.LowPrice);
var term4 = Math.Abs(_candle2.HighPrice - _candle3.LowPrice);
if (isSell)
{
// For sell, use inverted weights
return (100 - X1) * term1 + (100 - X2) * term2 + (X3 - 100) * term3 + (X4 - 100) * term4;
}
// For buy, use standard weights
return (X1 - 100) * term1 + (X2 - 100) * term2 + (100 - X3) * term3 + (100 - X4) * term4;
}
}