Estrategia de Barra de Reversión Alcista
Implementación de la estrategia - Barra de Reversión Alcista. Entra en largo cuando se forma una barra de reversión alcista por debajo de las líneas del Alligator y el precio rompe por encima del máximo de la barra. Los filtros opcionales pueden habilitar el Awesome Oscillator y las barras squat del Market Facilitation Index.
La configuración busca un nuevo mínimo que cierre en la mitad superior de la vela mientras la tendencia se vuelve alcista. La confirmación llega cuando el precio supera el máximo de la barra.
Detalles
- Criterios de entrada:
- Largo:
bullish reversal bar && close > confirmation level
- Largo:
- Largo/Corto: Solo largos
- Criterios de salida:
- Stop-loss en el mínimo de la barra o cuando la tendencia gira a la baja
- Stops: Mínimo de la barra almacenado en
_stopLoss - Valores predeterminados:
EnableAo= falseEnableMfi= falseCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Largo
- Indicadores: Alligator, Awesome Oscillator, Market Facilitation Index
- Stops: Sí
- Complejidad: Avanzado
- Marco temporal: Corto plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Confirms a bullish reversal below the shifted Alligator with a later close above its high.
/// Optional AO and MFI squat filters qualify the setup; its low protects the long position.
/// </summary>
public class BullishReversalBarStrategy : Strategy
{
private readonly StrategyParam<bool> _enableAo;
private readonly StrategyParam<bool> _enableMfi;
private readonly StrategyParam<DataType> _candleType;
private Alligator _alligator;
private AwesomeOscillator _ao;
private MarketFacilitationIndex _mfi;
private decimal? _previousLow, _previousLips, _previousAo, _previousMfi;
private decimal _previousVolume;
private (decimal High, decimal Low)? _pending;
private decimal _stopLoss;
private bool _exitPending;
public bool EnableAo { get => _enableAo.Value; set => _enableAo.Value = value; }
public bool EnableMfi { get => _enableMfi.Value; set => _enableMfi.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BullishReversalBarStrategy()
{
_enableAo = Param(nameof(EnableAo), false);
_enableMfi = Param(nameof(EnableMfi), false);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType), (Security, DataType.Level1)];
protected override void OnReseted()
{
base.OnReseted();
ResetState();
_alligator = null;
_ao = null;
_mfi = null;
}
private void ResetState()
{
_previousLow = _previousLips = _previousAo = _previousMfi = null;
_previousVolume = _stopLoss = 0m;
_pending = null;
_exitPending = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
_alligator = new Alligator();
_ao = EnableAo ? new AwesomeOscillator() : null;
_mfi = EnableMfi ? new MarketFacilitationIndex() : null;
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(_alligator, (candle, value) => ProcessCandle(candle, (IAlligatorValue)value), true).Start();
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = Level1Fields.BestBidPrice;
SubscribeLevel1(quotes).Bind(ProcessQuote).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _alligator);
if (_ao != null)
DrawIndicator(area, _ao);
if (_mfi != null)
DrawIndicator(area, _mfi);
DrawOwnTrades(area);
}
}
private static decimal? ProcessFilter(IIndicator indicator, ICandleMessage candle)
{
if (indicator == null)
return null;
var value = indicator.Process(new CandleIndicatorValue(indicator, candle));
return indicator.IsFormed && !value.IsEmpty ? value.GetValue<decimal>() : null;
}
private void ProcessCandle(ICandleMessage candle, IAlligatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var previousLow = _previousLow;
var previousLips = _previousLips;
var previousAo = _previousAo;
var previousMfi = _previousMfi;
var previousVolume = _previousVolume;
var ao = ProcessFilter(_ao, candle);
var mfi = ProcessFilter(_mfi, candle);
_previousLow = candle.LowPrice;
_previousLips = value.Lips;
_previousAo = ao;
_previousMfi = mfi;
_previousVolume = candle.TotalVolume;
if (value.Jaw is not decimal jaw || value.Teeth is not decimal teeth || value.Lips is not decimal lips
|| !IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0m)
{
if (candle.LowPrice <= _stopLoss || lips < previousLips)
CloseLong();
return;
}
if (Position != 0m)
return;
_exitPending = false;
// A setup is invalidated before confirmation if its low has already been touched.
if (_pending is { } invalidated && candle.LowPrice <= invalidated.Low)
_pending = null;
if (_pending is { } confirmation && candle.ClosePrice > confirmation.High)
{
_stopLoss = confirmation.Low;
_pending = null;
BuyMarket();
return;
}
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var reversal = candle.LowPrice < previousLow && candle.ClosePrice > median
&& candle.HighPrice < Math.Min(jaw, Math.Min(teeth, lips)) && lips > previousLips;
var aoFilter = !EnableAo || ao is decimal a && previousAo is decimal pa && a > pa;
var squat = !EnableMfi || mfi is decimal m && previousMfi is decimal pm && m < pm && candle.TotalVolume > previousVolume;
if (reversal && aoFilter && squat)
_pending = (candle.HighPrice, candle.LowPrice);
}
private void ProcessQuote(Level1ChangeMessage message)
{
if (Position == 0m)
{
_exitPending = false;
return;
}
if (Position > 0m && _stopLoss > 0m
&& message.TryGetDecimal(Level1Fields.BestBidPrice) is decimal bid && bid <= _stopLoss)
CloseLong();
}
private void CloseLong()
{
if (_exitPending || Position <= 0m)
return;
_exitPending = true;
SellMarket(Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal, Math
from StockSharp.Messages import DataType, CandleStates, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import Alligator, AwesomeOscillator, MarketFacilitationIndex, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class bullish_reversal_bar_strategy(Strategy):
"""Below-Alligator reversal, later high confirmation, optional AO/MFI and a fixed bar-low stop."""
def __init__(self):
super(bullish_reversal_bar_strategy, self).__init__()
self._enable_ao = self.Param("EnableAo", False)
self._enable_mfi = self.Param("EnableMfi", False)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._alligator = None
self._ao = None
self._mfi = None
self._reset_state()
def GetWorkingSecurities(self):
return [(self.Security, self._candle_type.Value), (self.Security, DataType.Level1)]
def OnReseted(self):
super(bullish_reversal_bar_strategy, self).OnReseted()
self._reset_state()
self._alligator = None
self._ao = None
self._mfi = None
def _reset_state(self):
self._previous_low = None
self._previous_lips = None
self._previous_ao = None
self._previous_mfi = None
self._previous_volume = Decimal.Zero
self._pending = None
self._stop_loss = Decimal.Zero
self._exit_pending = False
def OnStarted2(self, time):
super(bullish_reversal_bar_strategy, self).OnStarted2(time)
self._reset_state()
self._alligator = Alligator()
self._ao = AwesomeOscillator() if self._enable_ao.Value else None
self._mfi = MarketFacilitationIndex() if self._enable_mfi.Value else None
subscription = self.SubscribeCandles(self._candle_type.Value)
subscription.BindEx(self._alligator, self._process_candle, True).Start()
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = Level1Fields.BestBidPrice
self.SubscribeLevel1(quotes).Bind(self._process_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._alligator)
if self._ao is not None:
self.DrawIndicator(area, self._ao)
if self._mfi is not None:
self.DrawIndicator(area, self._mfi)
self.DrawOwnTrades(area)
@staticmethod
def _process_filter(indicator, candle):
if indicator is None:
return None
value = indicator.Process(CandleIndicatorValue(indicator, candle))
return value.GetValue[Decimal](None) if indicator.IsFormed and not value.IsEmpty else None
def _process_candle(self, candle, value):
if candle.State != CandleStates.Finished:
return
previous_low = self._previous_low
previous_lips = self._previous_lips
previous_ao = self._previous_ao
previous_mfi = self._previous_mfi
previous_volume = self._previous_volume
ao = self._process_filter(self._ao, candle)
mfi = self._process_filter(self._mfi, candle)
self._previous_low = candle.LowPrice
self._previous_lips = value.Lips
self._previous_ao = ao
self._previous_mfi = mfi
self._previous_volume = candle.TotalVolume
jaw, teeth, lips = value.Jaw, value.Teeth, value.Lips
if jaw is None or teeth is None or lips is None or not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
if candle.LowPrice <= self._stop_loss or previous_lips is not None and lips < previous_lips:
self._close_long()
return
if self.Position != 0:
return
self._exit_pending = False
if self._pending is not None and candle.LowPrice <= self._pending[1]:
self._pending = None
if self._pending is not None and candle.ClosePrice > self._pending[0]:
self._stop_loss = self._pending[1]
self._pending = None
self.BuyMarket()
return
median = (candle.HighPrice + candle.LowPrice) / Decimal(2)
reversal = (previous_low is not None and candle.LowPrice < previous_low and
candle.ClosePrice > median and
candle.HighPrice < Math.Min(jaw, Math.Min(teeth, lips)) and
previous_lips is not None and lips > previous_lips)
ao_filter = (not self._enable_ao.Value or
ao is not None and previous_ao is not None and ao > previous_ao)
squat = (not self._enable_mfi.Value or
mfi is not None and previous_mfi is not None and
mfi < previous_mfi and candle.TotalVolume > previous_volume)
if reversal and ao_filter and squat:
self._pending = (candle.HighPrice, candle.LowPrice)
def _process_quote(self, message):
if self.Position == 0:
self._exit_pending = False
return
bid = message.Changes[Level1Fields.BestBidPrice] if message.Changes.ContainsKey(Level1Fields.BestBidPrice) else None
if self.Position > 0 and self._stop_loss > 0 and bid is not None and bid <= self._stop_loss:
self._close_long()
def _close_long(self):
if self._exit_pending or self.Position <= 0:
return
self._exit_pending = True
self.SellMarket(self.Position)
def CreateClone(self):
return bullish_reversal_bar_strategy()