The Wedge Pattern Strategy is a conversion of the MetaTrader expert advisor Wedge pattern.mq4 into the StockSharp high-level API. The strategy searches for symmetrical wedge consolidations derived from Bill Williams fractals and trades the breakouts when trend and momentum filters align.
The high-level implementation replaces the original manual order management with StockSharp features while preserving the decision logic:
Trend filter – compares a fast and a slow Linear Weighted Moving Average (LWMA) calculated on typical prices.
Momentum filter – evaluates the absolute distance of the 14-period momentum indicator from its neutral level (100). The last three momentum readings must exceed a configurable threshold.
MACD confirmation – requires the MACD main line to be above the signal line for longs (or below for shorts).
Fractal wedge detection – collects upper and lower fractal points to build converging trendlines. Trading signals are produced when price closes beyond these trendlines plus a configurable confirmation buffer.
Risk management – mimics the MQL implementation with fixed stop-loss and take-profit distances, automatic break-even move, and trailing stop adjustments.
How it Works
Subscribe to a single timeframe defined by the CandleType parameter.
Update indicator values with each completed candle and maintain rolling buffers for highs and lows to detect new fractals.
Build wedge trendlines from the two most recent high and low fractals. Only converging wedges (lower highs and higher lows) are considered valid setups.
A long trade is opened when:
Fast LWMA > Slow LWMA.
MACD line > signal line.
Any of the last three momentum readings exceeds the configured threshold.
The current candle closes above the projected upper trendline by at least the breakout buffer.
A short trade mirrors the conditions with the lines and thresholds inverted.
After entry the strategy immediately places stop-loss and take-profit orders. It can later move the stop to break-even and trail it as the position becomes profitable.
Parameters
Parameter
Description
CandleType
Timeframe used for analysis and orders.
FastMaPeriod
Length of the fast LWMA filter.
SlowMaPeriod
Length of the slow LWMA filter.
MomentumPeriod
Lookback period for the momentum indicator (default 14).
MomentumThreshold
Minimum distance from 100 required from the momentum indicator to consider the market impulsive.
Extra buffer applied to the wedge breakout confirmation.
All pip-based settings are converted to price distances using the security's tick size. The default pip calculation accounts for fractional pricing (3 or 5 decimal places) exactly as in the original Expert Advisor.
Usage Guidelines
Attach the strategy to the desired instrument and select the candle timeframe matching the original setup (e.g., 15-minute candles).
Configure position size via the base Strategy.Volume property.
Optionally adjust filter and risk parameters to match the target market's volatility.
Start the strategy; it will subscribe to candles, draw chart data, and trade automatically once wedge breakouts occur.
Differences from the MQL Version
The StockSharp version uses high-level SubscribeCandles and indicator binding APIs, avoiding manual tick processing.
Trailing stop and break-even management rely on SetStopLoss/SetTakeProfit, integrating with the built-in protective behaviour.
Only one position is maintained at a time; the MetaTrader script supported pyramiding up to a maximum number of trades.
Alert, mail, and notification functions are omitted; event handling should be implemented externally if needed.
Despite these adaptations, the core entry logic and protective rules follow the original MetaTrader expert closely while using idiomatic StockSharp patterns.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Wedge Pattern strategy: WMA crossover + Momentum.
/// Buys when fast WMA crosses above slow WMA and momentum > 100.
/// Sells on cross below with momentum < 100.
/// </summary>
public class WedgePatternStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _momPeriod;
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 int MomPeriod
{
get => _momPeriod.Value;
set => _momPeriod.Value = value;
}
public WedgePatternStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 40)
.SetGreaterThanZero()
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_momPeriod = Param(nameof(MomPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Momentum", "Momentum period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
var mom = new Momentum { Length = MomPeriod };
decimal? prevFast = null;
decimal? prevSlow = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, mom, (candle, fastVal, slowVal, momVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevFast.HasValue && prevSlow.HasValue)
{
var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;
if (crossUp && momVal > 100m && Position <= 0)
BuyMarket();
else if (crossDown && momVal < 100m && Position >= 0)
SellMarket();
}
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
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 WeightedMovingAverage, Momentum
from StockSharp.Algo.Strategies import Strategy
class wedge_pattern_strategy(Strategy):
def __init__(self):
super(wedge_pattern_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._fast_period = self.Param("FastPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 40) \
.SetGreaterThanZero() \
.SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._mom_period = self.Param("MomPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("Momentum", "Momentum period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(wedge_pattern_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(wedge_pattern_strategy, self).OnStarted2(time)
self._fast_ind = WeightedMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = WeightedMovingAverage()
self._slow_ind.Length = self._slow_period.Value
self._mom_ind = Momentum()
self._mom_ind.Length = self._mom_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._mom_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_value, slow_value, mom_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
fast_val = float(fast_value)
slow_val = float(slow_value)
mom_val = float(mom_value)
if self._prev_fast is not None and self._prev_slow is not None:
cross_up = self._prev_fast <= self._prev_slow and fast_val > slow_val
cross_down = self._prev_fast >= self._prev_slow and fast_val < slow_val
if cross_up and mom_val > 100.0 and self.Position <= 0:
self.BuyMarket()
elif cross_down and mom_val < 100.0 and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return wedge_pattern_strategy()