The Forex Fraus M1 strategy replicates the MetaTrader 5 expert advisor "Forex Fraus M1" in the StockSharp framework. It is a contrarian system that monitors a long-lookback Williams %R oscillator (period 360) on one-minute candles. Whenever the oscillator touches extreme values, the strategy attempts to fade the move, aiming for a quick reversion toward the recent range mid-point. The implementation keeps the original expert's money management, including optional trading hours, static stop-loss and take-profit levels measured in pips, and a pip-based trailing stop.
Trading Logic
Indicator: Williams %R with a 360-period lookback.
Buy signal: When Williams %R drops below -99.9, the market is considered extremely oversold. The strategy sends a market buy order if there is no existing long position. If CloseOppositePositions is enabled, any short exposure is closed in the same order request.
Sell signal: When Williams %R rises above -0.1, the market is extremely overbought. The strategy issues a market sell order, optionally closing any open long exposure first.
Time filter: When UseTimeControl is enabled the strategy only evaluates signals between StartHour (inclusive) and EndHour (exclusive). If the session wraps midnight (StartHour > EndHour), trading is allowed from StartHour to 23 and from 0 to EndHour - 1.
Risk Management
Stop-loss: Calculated as StopLossPips * PipSize below (for longs) or above (for shorts) the entry price. When the candle low touches the stop level, the position is closed at market.
Take-profit: Calculated as TakeProfitPips * PipSize above (for longs) or below (for shorts) the entry price. When the candle high/low reaches this level, the position is closed to secure profits.
Trailing stop: If both TrailingStopPips and TrailingStepPips are positive, the stop is tightened once price moves by at least TrailingStopPips + TrailingStepPips pips in favor of the trade. For longs the stop trails the close minus TrailingStopPips; for shorts it trails the close plus TrailingStopPips.
Pip size: PipSize defines the monetary value of one pip. For five-digit Forex symbols set PipSize to 0.0001, for three-digit JPY pairs use 0.01, etc.
The strategy checks stop-loss and take-profit conditions using candle highs/lows. When both are touched within the same candle, the protective stop takes precedence, mirroring the conservative behavior of the original expert.
Parameters
Name
Default
Description
OrderVolume
0.1
Trade volume used for new positions.
StopLossPips
50
Stop-loss distance in pips from the entry price. Set to zero to disable.
TakeProfitPips
150
Take-profit distance in pips from the entry price. Set to zero to disable.
TrailingStopPips
1
Base trailing stop distance in pips. Set to zero to disable trailing.
TrailingStepPips
1
Minimum additional pip gain before the trailing stop moves.
UseTimeControl
true
Enables the intraday session filter.
StartHour
7
Start hour for the trading session (0-23).
EndHour
17
End hour for the trading session (1-24, exclusive).
CloseOppositePositions
true
If enabled, reverses existing positions in a single order.
WilliamsPeriod
360
Lookback period for the Williams %R indicator.
CandleType
1 minute
Candle type used to evaluate Williams %R and trading rules.
PipSize
0.0001
Value of a single pip in price units.
Additional Notes
The strategy uses StockSharp's high-level candle subscription API and indicator binding for concise logic without manual buffer management.
Stop-loss, take-profit, and trailing computations happen on completed candles to avoid acting on unfinished price data.
The implementation calls StartProtection() once on startup to align with the project guidelines, while actual risk handling is managed inside the strategy logic.
Adjust the PipSize parameter to match the traded instrument so that pip-based distances map correctly to price movements.
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>
/// Forex Fraus M1 strategy using fast EMA crossover on short timeframes.
/// </summary>
public class ForexFrausM1Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public ForexFrausM1Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 15)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (prevAbove && !currAbove)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class forex_fraus_m1_strategy(Strategy):
def __init__(self):
super(forex_fraus_m1_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast Period", "Fast EMA", "Indicators")
self._slow_period = self.Param("SlowPeriod", 15) \
.SetDisplay("Slow Period", "Slow EMA", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(forex_fraus_m1_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(forex_fraus_m1_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return forex_fraus_m1_strategy()