Estrategia de Divergencia AO
La estrategia busca divergencias alcistas y bajistas entre el Awesome Oscillator (AO) y el precio. Una divergencia alcista ocurre cuando el precio forma un mínimo más bajo mientras el AO forma un mínimo más alto. Una divergencia bajista aparece cuando el precio forma un máximo más alto mientras el AO forma un máximo más bajo.
Cuando se detecta una divergencia alcista, la estrategia abre una posición larga. Una divergencia bajista activa una posición corta. Las posiciones se revierten con señales opuestas.
Detalles
- Criterios de entrada: Divergencia alcista o bajista del AO con el precio.
- Largo/Corto: Ambos.
- Criterios de salida: Señal de divergencia opuesta.
- Stops: No.
- Valores predeterminados:
CandleType= 5 minutosFastLength= 5SlowLength= 34Lookback= 5UseEma= false
- Filtros:
- Categoría: Indicador
- Dirección: Ambos
- Indicadores: Awesome Oscillator
- Stops: No
- Complejidad: Intermedio
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: Sí
- 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>
/// AO Divergence strategy.
/// Buys when AO crosses above zero, sells when AO crosses below zero.
/// Uses EMA as trend filter.
/// </summary>
public class AoDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevAo;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// EMA trend filter period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AoDivergenceStrategy()
{
_emaLength = Param(nameof(EmaLength), 40)
.SetDisplay("EMA Length", "EMA trend filter period", "Indicator");
_cooldownBars = Param(nameof(CooldownBars), 380)
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevAo = 0;
_barIndex = 0;
_lastTradeBar = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
var ao = new AwesomeOscillator();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, ao, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal aoValue)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;
// AO zero line crossover with EMA trend
var aoCrossUp = _prevAo <= 0 && aoValue > 0;
var aoCrossDown = _prevAo >= 0 && aoValue < 0;
if (aoCrossUp && candle.ClosePrice > emaValue && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (aoCrossDown && candle.ClosePrice < emaValue && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevAo = aoValue;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AwesomeOscillator
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class ao_divergence_strategy(Strategy):
"""
AO Divergence strategy.
Buys when AO crosses above zero with EMA uptrend, sells when AO crosses below zero with downtrend.
"""
def __init__(self):
super(ao_divergence_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 40) \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicator")
self._cooldown_bars = self.Param("CooldownBars", 380) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading")
self._candle_type = self.Param("CandleType", tf(1)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_ao = 0.0
self._bar_index = 0
self._last_trade_bar = 0
@property
def EmaLength(self): return self._ema_length.Value
@EmaLength.setter
def EmaLength(self, v): self._ema_length.Value = v
@property
def CooldownBars(self): return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, v): self._cooldown_bars.Value = v
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
def OnReseted(self):
super(ao_divergence_strategy, self).OnReseted()
self._prev_ao = 0.0
self._bar_index = 0
self._last_trade_bar = 0
def OnStarted2(self, time):
super(ao_divergence_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
ao = AwesomeOscillator()
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, ao, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ema_value, ao_value):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
cooldown_ok = self._bar_index - self._last_trade_bar > self.CooldownBars
ao_cross_up = self._prev_ao <= 0 and ao_value > 0
ao_cross_down = self._prev_ao >= 0 and ao_value < 0
if ao_cross_up and float(candle.ClosePrice) > ema_value and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif ao_cross_down and float(candle.ClosePrice) < ema_value and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_ao = ao_value
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return ao_divergence_strategy()