This strategy reproduces the behaviour of the original EA_PUB_FibonacciPotentialEntries expert advisor. It places two limit orders at the 50% and 61% Fibonacci retracement levels and manages their lifecycle using the high-level StockSharp API.
Trading Logic
Initial placement
As soon as bid/ask quotes are available the strategy calculates the current spread and submits two limit orders:
Order #1: placed at the 50% level with a protective stop below (or above for shorts) the 61% level.
Order #2: placed at the 61% level with a protective stop placed half way towards the 100% level.
Volumes are sized so that the first trade risks 0.7% of the portfolio and the second trade risks the remaining part of the RiskPercent parameter.
Target handling
When price reaches the TargetPrice level the strategy closes half of each filled position using market orders.
After partial exit the remaining volume is protected at break-even (entry price). If the market returns to that level the rest of the position is closed automatically.
IsBullish = false mirrors the behaviour with sell limits and inverted stop/target checks.
Parameters
Name
Description
PriceOn50Level
Price level for the first limit order.
PriceOn61Level
Price level for the second limit order.
PriceOn100Level
Reference level used to compute the second trade stop.
TargetPrice
Shared profit target for both positions.
RiskPercent
Total percentage of portfolio equity risked across both entries.
IsBullish
Chooses between long and short setups.
Conversion Notes
Only high-level helpers (SubscribeLevel1, BuyLimit, SellLimit, BuyMarket, SellMarket) are used, exactly as required by the repository guidelines.
Partial exits and break-even stop adjustments are reproduced with market orders, matching the MQL robot behaviour without relying on low-level order modification calls.
Position volumes are normalised to the instrument volume step to stay consistent with StockSharp conventions.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Fibonacci Potential Entries strategy: Two-candle reversal with RSI filter.
/// Uses price swing highs/lows as fibonacci reference points.
/// </summary>
public class FibonacciPotentialEntriesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _highestHigh;
private decimal _lowestLow;
private decimal _prevClose;
private int _barCount;
private int _candlesSinceTrade;
private bool _hasPrevClose;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public FibonacciPotentialEntriesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highestHigh = 0;
_lowestLow = decimal.MaxValue;
_prevClose = 0;
_barCount = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrevClose = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highestHigh = 0;
_lowestLow = decimal.MaxValue;
_prevClose = 0;
_barCount = 0;
_candlesSinceTrade = SignalCooldownCandles;
_hasPrevClose = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (candle.HighPrice > _highestHigh) _highestHigh = candle.HighPrice;
if (candle.LowPrice < _lowestLow) _lowestLow = candle.LowPrice;
_barCount++;
if (_barCount < 20) return;
var range = _highestHigh - _lowestLow;
if (range <= 0) return;
var fib382 = _highestHigh - range * 0.382m;
var fib618 = _highestHigh - range * 0.618m;
var close = candle.ClosePrice;
var crossedIntoBuyZone = _hasPrevClose && _prevClose > fib618 && close <= fib618;
var crossedIntoSellZone = _hasPrevClose && _prevClose < fib382 && close >= fib382;
if (crossedIntoBuyZone && rsiValue < 40 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (crossedIntoSellZone && rsiValue > 60 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
_prevClose = close;
_hasPrevClose = true;
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class fibonacci_potential_entries_strategy(Strategy):
def __init__(self):
super(fibonacci_potential_entries_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._highest_high = 0.0
self._lowest_low = float('inf')
self._prev_close = 0.0
self._bar_count = 0
self._candles_since_trade = 6
self._has_prev_close = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(fibonacci_potential_entries_strategy, self).OnReseted()
self._highest_high = 0.0
self._lowest_low = float('inf')
self._prev_close = 0.0
self._bar_count = 0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev_close = False
def OnStarted2(self, time):
super(fibonacci_potential_entries_strategy, self).OnStarted2(time)
self._highest_high = 0.0
self._lowest_low = float('inf')
self._prev_close = 0.0
self._bar_count = 0
self._candles_since_trade = self.SignalCooldownCandles
self._has_prev_close = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
if high > self._highest_high:
self._highest_high = high
if low < self._lowest_low:
self._lowest_low = low
self._bar_count += 1
if self._bar_count < 20:
self._prev_close = close
self._has_prev_close = True
return
range_val = self._highest_high - self._lowest_low
if range_val <= 0:
self._prev_close = close
self._has_prev_close = True
return
fib382 = self._highest_high - range_val * 0.382
fib618 = self._highest_high - range_val * 0.618
crossed_into_buy_zone = self._has_prev_close and self._prev_close > fib618 and close <= fib618
crossed_into_sell_zone = self._has_prev_close and self._prev_close < fib382 and close >= fib382
if crossed_into_buy_zone and rsi_val < 40 and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif crossed_into_sell_zone and rsi_val > 60 and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
self._prev_close = close
self._has_prev_close = True
def CreateClone(self):
return fibonacci_potential_entries_strategy()