Esta estrategia reproduce el comportamiento del asesor experto EA_PUB_FibonacciPotentialEntries original. Coloca dos órdenes límite en los niveles de retroceso del 50 % y 61 % Fibonacci y gestiona su ciclo de vida utilizando el nivel alto StockSharp API.
Lógica de trading
Colocación inicial
Tan pronto como las cotizaciones de oferta/demanda estén disponibles, la estrategia calcula el diferencial actual y envía dos órdenes límite:
Orden #1: colocada en el nivel del 50% con un stop protector por debajo (o por encima para cortos) del nivel del 61%.
Orden #2: colocada en el nivel del 61% con un tope protector colocado a medio camino hacia el nivel del 100%.
Los volúmenes están dimensionados para que la primera operación arriesgue el 0,7% de la cartera y la segunda operación arriesgue la parte restante del parámetro RiskPercent.
Manejo de objetivos
Cuando el precio alcanza el nivel TargetPrice, la estrategia cierra la mitad de cada posición ocupada utilizando órdenes de mercado.
Después de una salida parcial, el volumen restante está protegido hasta el punto de equilibrio (precio de entrada). Si el mercado vuelve a ese nivel el resto de la posición se cierra automáticamente.
Dirección
IsBullish = true crea límites de compra (plantilla alcista original).
IsBullish = false refleja el comportamiento con límites de venta y controles de parada/objetivo invertidos.
Parámetros
Nombre
Descripción
PriceOn50Level
Nivel de precio para la primera orden límite.
PriceOn61Level
Nivel de precio para la segunda orden límite.
PriceOn100Level
Nivel de referencia utilizado para calcular la segunda parada comercial.
TargetPrice
Objetivo de beneficio compartido para ambas posiciones.
RiskPercent
Porcentaje total del capital de la cartera arriesgado en ambas entradas.
IsBullish
Elige entre configuraciones largas y cortas.
Notas de conversión
Solo se utilizan ayudantes de alto nivel (SubscribeLevel1, BuyLimit, SellLimit, BuyMarket, SellMarket), exactamente como lo exigen las pautas del repositorio.
Las salidas parciales y los ajustes de punto de equilibrio se reproducen con órdenes de mercado, coincidiendo con el comportamiento del robot MQL sin depender de llamadas de modificación de órdenes de bajo nivel.
Los volúmenes de posición están normalizados al paso de volumen del instrumento para mantenerse consistentes con las convenciones StockSharp.
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()