Esta estrategia evalúa el equilibrio entre la presión alcista y bajista utilizando los indicadores Bulls Power y Bears Power. Los dos indicadores se combinan en un único oscilador escalado de 0 a 100. Los valores altos indican el dominio de los compradores, mientras que los valores bajos señalan la fortaleza de los vendedores.
Las decisiones de trading se basan en niveles de umbral similares al experto original BullsBearsEyes. Cuando el oscilador cruza por encima del nivel de sobrecompra después de haber estado por debajo, se abre una posición larga y cualquier posición corta se cierra. Por el contrario, cruzar por debajo del nivel de sobreventa desencadena una entrada corta y cierra los largos existentes. Los valores neutrales entre los umbrales mantienen la posición actual pero cierran las operaciones opuestas.
Parámetros
Period – período de promediado para Bulls/Bears Power (por defecto: 13).
High Level – umbral de sobrecompra que genera señales largas (por defecto: 75).
Middle Level – nivel de referencia medio utilizado para la interpretación de la tendencia (por defecto: 50).
Low Level – umbral de sobreventa que genera señales cortas (por defecto: 25).
Candle Type – marco temporal de las velas procesadas por la estrategia (por defecto: velas de 4 horas).
Reglas de entrada y salida
Calcular Bulls Power y Bears Power para cada vela y derivar el valor del oscilador entre 0 y 100.
Entrada larga: el oscilador cruza por encima de High Level tras haber estado por debajo. Cualquier posición corta se cierra antes de abrir el largo.
Entrada corta: el oscilador cruza por debajo de Low Level tras haber estado por encima. Cualquier posición larga existente se cierra antes de abrir el corto.
Salida de posición: cuando el oscilador cambia de lado (por encima/por debajo de la zona central), la posición opuesta se cierra.
El oscilador también se traza junto con las velas para el análisis visual.
Notas
La estrategia utiliza la API de alto nivel SubscribeCandles y Bind para el procesamiento de indicadores.
Los mecanismos de protección se activan mediante StartProtection() al inicio.
Solo se evalúan las velas completadas para evitar señales prematuras.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// EMA crossover strategy.
/// </summary>
public class BullsBearsEyesStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BullsBearsEyesStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Parameters");
_slowPeriod = Param(nameof(SlowPeriod), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle type", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fast, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev)
{
_prevFast = fastVal;
_prevSlow = slowVal;
_hasPrev = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;
if (crossUp && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (crossDown && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}