La estrategia Bobnaley reproduce el MetaTrader 5 asesor experto "bobnaley" utilizando el StockSharp alto nivel API. Combina un filtro de tendencia de media móvil simple con el oscilador estocástico para buscar oportunidades de reversión. El experto original evaluó los precios de las garrapatas; el puerto utiliza velas completadas y mantiene intactas las reglas de gestión de pedidos.
Cómo funciona
Indicadores
Una media móvil simple con el período configurado filtra la dirección predominante.
Un oscilador estocástico (líneas principal y de señal) identifica situaciones de sobreventa y sobrecompra. Sólo se necesita la línea principal para las señales; la línea de señal se calcula para que esté completa.
Condiciones de entrada
La estrategia espera hasta que finalice la vela actual y se formen todos los indicadores.
Las entradas largas requieren que el promedio móvil sea estrictamente decreciente durante las últimas tres muestras mientras el precio cierra por encima del último promedio. Al mismo tiempo, la línea principal estocástica debe estar por debajo del nivel de sobreventa y su valor anterior debe ser mayor que el anterior, reflejando el requisito EA original stochVal[1] > stochVal[2].
Las entradas cortas son la imagen especular: la media móvil debe estar subiendo en las últimas tres muestras mientras el precio cierra por debajo de ella, y la línea principal estocástica debe estar por encima del nivel de sobrecompra mientras su valor anterior es más bajo que el anterior.
Las nuevas operaciones se abren solo cuando no hay ninguna posición activa actualmente, replicando la guardia PositionSelect de MetaTrader.
Gestión de riesgos
Cuando se abre una posición, la estrategia se basa en el servicio de protección de StockSharp para colocar una toma de ganancias y un límite de pérdidas en unidades de precio absoluto. Estas distancias coinciden con las entradas MetaTrader (0,007 y 0,0035 de forma predeterminada).
Antes de cada decisión, el valor de la cartera se compara con el parámetro Minimum Balance, reflejando el filtro de margen libre (ACCOUNT_FREEMARGIN > 5000) del código original. Si el valor de la cuenta es conocido y está por debajo del umbral, se omite la entrada.
Manejo de volumen
Los pedidos utilizan un parámetro fijo Base Volume. Esto reproduce la configuración de lote que utilizó el script MetaTrader después de aplicar su propia rutina de redondeo.
Parámetros
categoría
Nombre
Descripción
Predeterminado
generales
Tipo de vela
Tipo de datos de vela utilizado para los cálculos del indicador.
marco de tiempo de 5 minutos
Comercio
Volumen básico
Volumen de orden fijo aplicado a cada nueva posición.
5
Indicadores
Período MA
Longitud de la media móvil simple.
76
Indicadores
Stochastic Período
Mirando hacia atrás para ver la línea principal estocástica.
5
Indicadores
Stochastic %K
Longitud de suavizado para la línea %K.
3
Indicadores
Stochastic%D
Longitud de suavizado para la línea %D.
3
Indicadores
Stochastic Sobreventa
Umbral que define el territorio de sobreventa para la línea principal.
30
Indicadores
Stochastic Sobrecomprado
Umbral que define el territorio de sobrecompra para la línea principal.
70
Gestión de riesgos
Tomar ganancias
Distancia entre el precio de entrada y la toma de ganancias en unidades de precio.
0.007
Gestión de riesgos
Detener pérdidas
Distancia entre el precio de entrada y el stop-loss en unidades de precio.
0.0035
Gestión de riesgos
Saldo Mínimo
Se requiere un valor mínimo de cartera antes de poder enviar un nuevo pedido.
5000
Notas
El experto original utilizó cotizaciones de oferta y demanda; en StockSharp el cierre de la vela se utiliza como indicador del precio de ejecución.
No se implementan salidas finales: la operación se cierra únicamente con las órdenes de protección.
Los cálculos de Stochastic siguen la configuración predeterminada de MetaTrader (5/3/3), pero se pueden optimizar mediante los parámetros expuestos.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Bobnaley strategy: EMA trend with ATR volatility filter.
/// </summary>
public class BobnaleyStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public BobnaleyStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA period", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
decimal? prevClose = null;
decimal? prevEma = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, (candle, emaVal, atrVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (prevClose.HasValue && prevEma.HasValue)
{
var crossUp = prevClose.Value <= prevEma.Value && close > emaVal;
var crossDown = prevClose.Value >= prevEma.Value && close < emaVal;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
prevClose = close;
prevEma = emaVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
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 ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class bobnaley_strategy(Strategy):
def __init__(self):
super(bobnaley_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._ema_period = self.Param("EmaPeriod", 14) \
.SetDisplay("EMA Period", "EMA period", "Indicators")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period", "Indicators")
self._prev_close = None
self._prev_ema = None
@property
def candle_type(self):
return self._candle_type.Value
@property
def ema_period(self):
return self._ema_period.Value
@property
def atr_period(self):
return self._atr_period.Value
def OnReseted(self):
super(bobnaley_strategy, self).OnReseted()
self._prev_close = None
self._prev_ema = None
def OnStarted2(self, time):
super(bobnaley_strategy, self).OnStarted2(time)
self._prev_close = None
self._prev_ema = None
ema = ExponentialMovingAverage()
ema.Length = self.ema_period
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._prev_close is not None and self._prev_ema is not None:
cross_up = self._prev_close <= self._prev_ema and close > float(ema_val)
cross_down = self._prev_close >= self._prev_ema and close < float(ema_val)
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_ema = float(ema_val)
def CreateClone(self):
return bobnaley_strategy()