Convertido del MetaTrader 4 experto original "Billy_expert.mq4".
Estrategia de impulso de solo largo que espera cuatro máximos descendentes consecutivos y abre antes de entrar.
Utiliza dos osciladores estocásticos (rápido en el marco temporal de negociación, lento en un marco temporal más alto) para confirmar que el impulso se está desplazando hacia arriba.
Diseñado para pares de divisas al contado, pero se puede aplicar a cualquier instrumento que proporcione velas basadas en minutos.
Lógica de señal
Filtro de acción de precio
Evalúe las velas terminadas en el período principal.
Requiere cuatro velas consecutivas donde tanto el máximo como la apertura disminuyen. Esto recrea las comprobaciones MT4 High[0] < High[1] < High[2] < High[3] y Open[0] < Open[1] < Open[2] < Open[3].
El patrón sugiere un movimiento bajista agotado y prepara la estrategia para una operación de reversión.
Confirmación del oscilador
Calcule un oscilador estocástico rápido en el período de negociación y un estocástico lento en el período de confirmación.
Para cada oscilador, exija que la línea %K esté por encima de la línea %D tanto en la vela completa actual como en la anterior (%K(0) > %D(0) y %K(1) > %D(1)).
La operación se activa sólo cuando ambos osciladores confirman simultáneamente un impulso alcista.
Gestión de pedidos
Entradas: compras de mercado dimensionadas por el parámetro de estrategia Volume (si existe una posición corta, se cierra y se revierte automáticamente).
Stop loss: distancia fija por debajo del precio de cumplimiento utilizando el parámetro Stop Loss (pts). Un valor de 0 desactiva la parada.
Take Profit: distancia fija por encima del precio de cumplimiento utilizando el parámetro Take Profit (pts). Un valor de 0 desactiva el objetivo.
Límite de posición: Max Orders limita cuántas entradas largas pueden estar activas al mismo tiempo. Debido a que StockSharp mantiene una posición neta, la estrategia se aproxima al comportamiento de MT4 al contar cuántos bloques Volume están abiertos actualmente.
Trailing stop: el EA original declaró una entrada de trailing stop pero no la implementó. La versión convertida también omite la lógica final de paridad.
Parámetros
Nombre
Descripción
Predeterminado
Trading Candle
Marco temporal principal para el patrón de precios y el estocástico rápido.
1 minuto
Slow Stochastic Candle
Marco de tiempo más alto utilizado para el estocástico de confirmación.
5 minutos
Stochastic Length
Ventana retrospectiva para %K.
5
%K Smoothing
Suavizado aplicado a la línea %K.
3
%D Period
Suavizado aplicado a la línea %D.
3
Slowing
Factor de suavizado adicional para %K.
3
Stop Loss (pts)
Distancia de stop loss en pasos de precio.
0
Take Profit (pts)
Tome la distancia de beneficio en pasos de precio.
12
Max Orders
Máximo de entradas largas simultáneas.
1
Notas de uso
Establezca la propiedad Volume antes de iniciar la estrategia; StockSharp tiene como valor predeterminado 0, lo que bloquearía la realización de pedidos.
El paso del precio se lee desde Security.PriceStep (vuelve a Security.Step o 1). Asegúrese de que los metadatos de su instrumento estén configurados correctamente para obtener niveles de parada/objetivo precisos.
Cuando el período de confirmación difiere del período de negociación, la vela lenta completada más recientemente se reutiliza hasta que aparece una nueva, que coincide con el comportamiento del script MT4 original.
El EA no logró salidas más allá del stop loss y la toma de ganancias del lado del corredor. La conversión refleja este comportamiento al enviar órdenes de mercado protectoras cuando se tocan los niveles.
Debido a que StockSharp agrega posiciones, Max Orders > 1 funciona mejor cuando cada entrada usa el mismo tamaño Volume.
Diferencias con la versión MT4
Comprobación de seguridad para detectar información faltante sobre el paso del precio con una advertencia de registro en lugar de utilizar Point de forma silenciosa.
Se agregaron cláusulas de protección para garantizar que la estrategia se opere solo cuando todos los datos requeridos (historial de precios y ambos osciladores estocásticos) estén disponibles.
La estrategia se ejecuta únicamente con velas terminadas, mientras que MT4 procesó ticks pero se limitó por el tiempo de la barra. Este cambio evita evaluaciones duplicadas y mantiene la lógica determinista.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Long-only reversal strategy that looks for consecutive descending highs
/// and enters when RSI confirms oversold conditions with momentum turning up.
/// </summary>
public class BillyExpertReversalStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private decimal _prevHigh1, _prevHigh2, _prevHigh3;
private int _barCount;
private decimal _prevRsi;
private bool _hasPrevRsi;
private decimal _entryPrice;
public BillyExpertReversalStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis.", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "Length for RSI indicator.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh1 = 0;
_prevHigh2 = 0;
_prevHigh3 = 0;
_barCount = 0;
_prevRsi = 50;
_hasPrevRsi = false;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHigh1 = 0;
_prevHigh2 = 0;
_prevHigh3 = 0;
_barCount = 0;
_prevRsi = 50;
_hasPrevRsi = false;
_entryPrice = 0;
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_barCount++;
var high = candle.HighPrice;
var close = candle.ClosePrice;
// Check descending highs pattern (3 consecutive lower highs)
var descendingHighs = _barCount >= 4 &&
high < _prevHigh1 &&
_prevHigh1 < _prevHigh2 &&
_prevHigh2 < _prevHigh3;
// RSI turning up from oversold
var rsiBullish = _hasPrevRsi && _prevRsi < 40 && rsiValue > _prevRsi;
// Manage long position
if (Position > 0)
{
// Exit on take-profit, stop-loss, or RSI overbought
if (_entryPrice > 0 && close >= _entryPrice * 1.015m)
{
SellMarket();
}
else if (_entryPrice > 0 && close <= _entryPrice * 0.985m)
{
SellMarket();
}
else if (rsiValue > 75)
{
SellMarket();
}
}
// Manage short position (exit only, this is mostly long-only)
if (Position < 0)
{
if (rsiValue < 30)
{
BuyMarket();
}
}
// Entry: descending highs (selling exhaustion) + RSI confirms reversal
if (Position == 0)
{
if (descendingHighs && rsiBullish)
{
_entryPrice = close;
BuyMarket();
}
// Also allow short on ascending lows pattern with overbought RSI
else if (_barCount >= 4 && rsiValue > 70 && _prevRsi > 70)
{
_entryPrice = close;
SellMarket();
}
}
// Update history
_prevHigh3 = _prevHigh2;
_prevHigh2 = _prevHigh1;
_prevHigh1 = high;
_prevRsi = rsiValue;
_hasPrevRsi = 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.Strategies import Strategy
from StockSharp.Algo.Indicators import RelativeStrengthIndex
class billy_expert_reversal_strategy(Strategy):
def __init__(self):
super(billy_expert_reversal_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "Length for RSI indicator", "Indicators")
self._prev_high1 = 0.0
self._prev_high2 = 0.0
self._prev_high3 = 0.0
self._bar_count = 0
self._prev_rsi = 50.0
self._has_prev_rsi = False
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def RsiLength(self):
return self._rsi_length.Value
def OnStarted2(self, time):
super(billy_expert_reversal_strategy, self).OnStarted2(time)
self._prev_high1 = 0.0
self._prev_high2 = 0.0
self._prev_high3 = 0.0
self._bar_count = 0
self._prev_rsi = 50.0
self._has_prev_rsi = False
self._entry_price = 0.0
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.RsiLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._rsi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
self._bar_count += 1
high = float(candle.HighPrice)
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
# Check descending highs pattern (3 consecutive lower highs)
descending_highs = (self._bar_count >= 4 and
high < self._prev_high1 and
self._prev_high1 < self._prev_high2 and
self._prev_high2 < self._prev_high3)
# RSI turning up from oversold
rsi_bullish = self._has_prev_rsi and self._prev_rsi < 40 and rsi_val > self._prev_rsi
# Manage long position
if self.Position > 0:
if self._entry_price > 0 and close >= self._entry_price * 1.015:
self.SellMarket()
elif self._entry_price > 0 and close <= self._entry_price * 0.985:
self.SellMarket()
elif rsi_val > 75:
self.SellMarket()
# Manage short position (exit only)
if self.Position < 0:
if rsi_val < 30:
self.BuyMarket()
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_high3 = self._prev_high2
self._prev_high2 = self._prev_high1
self._prev_high1 = high
self._prev_rsi = rsi_val
self._has_prev_rsi = True
return
# Entry
if self.Position == 0:
if descending_highs and rsi_bullish:
self._entry_price = close
self.BuyMarket()
elif self._bar_count >= 4 and rsi_val > 70 and self._prev_rsi > 70:
self._entry_price = close
self.SellMarket()
# Update history
self._prev_high3 = self._prev_high2
self._prev_high2 = self._prev_high1
self._prev_high1 = high
self._prev_rsi = rsi_val
self._has_prev_rsi = True
def OnReseted(self):
super(billy_expert_reversal_strategy, self).OnReseted()
self._prev_high1 = 0.0
self._prev_high2 = 0.0
self._prev_high3 = 0.0
self._bar_count = 0
self._prev_rsi = 50.0
self._has_prev_rsi = False
self._entry_price = 0.0
def CreateClone(self):
return billy_expert_reversal_strategy()