The Pull Back strategy reproduces the logic of the original MetaTrader "PULL BACK" expert advisor using StockSharp high-level APIs. The approach searches for pullbacks into a fast weighted moving average on a higher timeframe, confirms momentum strength across several bars, and trades in the direction of the monthly MACD trend. Once a position is open, the algorithm applies money management rules that include stop-loss, take-profit, break-even and trailing stop handling.
Data and indicators
Trading timeframe: user-selectable candle type (CandleType, default 15-minute candles).
Momentum indicator with absolute distance from the neutral value (100).
Pull-back detection when the previous candle touches the fast WMA.
MACD timeframe: separate subscription (MacdCandleType, default 30-day candles) to read the MACD signal line direction.
Indicators:
Weighted Moving Average (WMA) on trading and higher timeframes.
Momentum (period configurable) on the higher timeframe.
Moving Average Convergence Divergence (MACD) on the long timeframe.
Trading logic
Long setup
The higher timeframe fast WMA is above the slow WMA.
The most recent completed higher timeframe candle opened above the fast WMA and touched it with its low (pull-back confirmation).
At least one of the last three absolute momentum readings exceeds MomentumBuyThreshold.
MACD main line is above its signal line on the MACD timeframe.
On the trading timeframe, the fast WMA is above the slow WMA.
When all rules are satisfied the strategy sends a market buy order. The entry price is recorded to control risk parameters.
Short setup
The higher timeframe fast WMA is below the slow WMA.
The recent candle opened below the fast WMA and touched it with its high.
One of the last three momentum values exceeds MomentumSellThreshold.
MACD main line is below the signal line.
The trading timeframe fast WMA is below the slow WMA.
A market sell order is sent when conditions align.
Position management
Stop loss:StopLossTicks distance from the entry (converted to absolute price using the security price step).
Take profit:TakeProfitTicks distance from the entry.
Break-even: when price advances by BreakEvenTriggerTicks, the stop is moved to entry plus BreakEvenOffsetTicks in the trade direction if UseBreakEven is enabled.
Trailing stop: if UseTrailingStop is true, the stop follows price by TrailingStopTicks once the position moves in profit.
Exit checks: run on every finished trading timeframe candle. If stop or target is reached the strategy closes the entire position with a market order.
Parameters
Parameter
Description
FastMaLength
Fast WMA length on the trading timeframe (default 6).
SlowMaLength
Slow WMA length on the trading timeframe (default 85).
BounceSlowLength
Slow WMA length on the confirmation timeframe (default 200).
MomentumLength
Momentum lookback on the higher timeframe (default 14).
MomentumBuyThreshold
Minimum
Momentum-100
for long entries (default 0.3).
MomentumSellThreshold
Minimum
Momentum-100
for short entries (default 0.3).
StopLossTicks
Stop-loss distance in ticks (default 200).
TakeProfitTicks
Take-profit distance in ticks (default 500).
UseTrailingStop
Enable trailing stop logic (default true).
TrailingStopTicks
Trailing stop distance in ticks (default 400).
UseBreakEven
Enable break-even adjustment (default true).
BreakEvenTriggerTicks
Profit trigger for break-even in ticks (default 300).
BreakEvenOffsetTicks
Offset added to the break-even stop in ticks (default 300).
MacdFastLength
Fast EMA period of MACD (default 12).
MacdSlowLength
Slow EMA period of MACD (default 26).
MacdSignalLength
Signal EMA period of MACD (default 9).
CandleType
Trading timeframe candle type.
HigherCandleType
Confirmation timeframe candle type.
MacdCandleType
MACD timeframe candle type.
Notes
The strategy expects Security.PriceStep to be populated so that tick-based risk controls translate to price distances correctly.
Only one net position is maintained at a time; opposite signals are ignored until the current position is closed.
The logic processes only finished candles to avoid acting on partial data.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class PullBackStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast, _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 PullBackStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 5).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 15).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(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 fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast; _prevSlow = slow;
if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); 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 pull_back_strategy(Strategy):
def __init__(self):
super(pull_back_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 EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 15) \
.SetDisplay("Slow EMA", "Slow EMA period", "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(pull_back_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(pull_back_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 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return pull_back_strategy()