Estrategia Vela Superada
La estrategia Vela Superada opera un patrón de reversión de dos velas. Una configuración alcista ocurre cuando una vela bajista es seguida inmediatamente por una vela alcista que cierra por encima de la apertura anterior. Las operaciones se filtran con una EMA a corto plazo, RSI y tendencia MACD para evitar señales contra la tendencia. Se pueden habilitar tanto el lado largo como el corto.
La estrategia emplea niveles de take profit y stop loss basados en porcentajes y ajusta dinámicamente un trailing stop una vez que el precio se mueve favorablemente. Esto permite capturar movimientos extendidos mientras se protege contra reversiones.
Detalles
- Criterios de entrada:
- Largo: Vela anterior bajista, vela actual alcista, cierre y cierre anterior por encima de la EMA, RSI < 65, MACD subiendo.
- Corto: Vela anterior alcista, vela actual bajista, cierre y cierre anterior por debajo de la EMA, RSI > 35, MACD bajando.
- Largo/Corto: Configurable (largo por defecto).
- Criterios de salida:
- Trailing stop o señal opuesta.
- Stops: Stop loss y take profit basados en porcentaje.
- Valores predeterminados:
EmaLength= 10RsiLength= 14ShowLong= TrueShowShort= FalseTpPercent= 1.2SlPercent= 1.8
- Filtros:
- Categoría: Patrón + indicadores
- Dirección: Ambos
- Indicadores: EMA, RSI, MACD
- Stops: Sí
- Complejidad: Medio
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: Sí
- Nivel de riesgo: Medio
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Vela Superada Strategy.
/// Trades on candle pattern reversals with EMA, RSI and MACD filters.
/// Buys on bullish reversal pattern above EMA with rising MACD.
/// Sells on bearish reversal pattern below EMA with falling MACD.
/// </summary>
public class VelaSuperadaStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _ema;
private RelativeStrengthIndex _rsi;
private MovingAverageConvergenceDivergence _macd;
private decimal _prevClose;
private decimal _prevOpen;
private decimal _prevMacd;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public VelaSuperadaStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_emaLength = Param(nameof(EmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Moving Averages");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "RSI");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema = null;
_rsi = null;
_macd = null;
_prevClose = 0;
_prevOpen = 0;
_prevMacd = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = EmaLength };
_rsi = new RelativeStrengthIndex { Length = RsiLength };
_macd = new MovingAverageConvergenceDivergence();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, _rsi, _macd, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal emaVal, decimal rsiVal, decimal macdVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ema.IsFormed || !_rsi.IsFormed || !_macd.IsFormed)
{
_prevClose = candle.ClosePrice;
_prevOpen = candle.OpenPrice;
_prevMacd = macdVal;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevClose = candle.ClosePrice;
_prevOpen = candle.OpenPrice;
_prevMacd = macdVal;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevClose = candle.ClosePrice;
_prevOpen = candle.OpenPrice;
_prevMacd = macdVal;
return;
}
if (_prevClose == 0)
{
_prevClose = candle.ClosePrice;
_prevOpen = candle.OpenPrice;
_prevMacd = macdVal;
return;
}
// Candle pattern detection
var bullishReversal = _prevClose < _prevOpen && candle.ClosePrice > candle.OpenPrice; // Red->Green
var bearishReversal = _prevClose > _prevOpen && candle.ClosePrice < candle.OpenPrice; // Green->Red
// MACD momentum
var macdRising = macdVal > _prevMacd;
var macdFalling = macdVal < _prevMacd;
// Buy: bullish reversal + above EMA + RSI not overbought + MACD rising
if (bullishReversal && candle.ClosePrice > emaVal && rsiVal < 65 && macdRising && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: bearish reversal + below EMA + RSI not oversold + MACD falling
else if (bearishReversal && candle.ClosePrice < emaVal && rsiVal > 35 && macdFalling && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: bearish reversal below EMA
else if (Position > 0 && bearishReversal && candle.ClosePrice < emaVal)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: bullish reversal above EMA
else if (Position < 0 && bullishReversal && candle.ClosePrice > emaVal)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevClose = candle.ClosePrice;
_prevOpen = candle.OpenPrice;
_prevMacd = macdVal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex, MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class vela_superada_strategy(Strategy):
"""Vela Superada Strategy."""
def __init__(self):
super(vela_superada_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ema_length = self.Param("EmaLength", 10) \
.SetDisplay("EMA Length", "EMA period", "Moving Averages")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "RSI")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._ema = None
self._rsi = None
self._macd = None
self._prev_close = 0.0
self._prev_open = 0.0
self._prev_macd = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vela_superada_strategy, self).OnReseted()
self._ema = None
self._rsi = None
self._macd = None
self._prev_close = 0.0
self._prev_open = 0.0
self._prev_macd = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(vela_superada_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = int(self._ema_length.Value)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = int(self._rsi_length.Value)
self._macd = MovingAverageConvergenceDivergence()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema, self._rsi, self._macd, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_val, rsi_val, macd_val):
if candle.State != CandleStates.Finished:
return
if not self._ema.IsFormed or not self._rsi.IsFormed or not self._macd.IsFormed:
self._prev_close = float(candle.ClosePrice)
self._prev_open = float(candle.OpenPrice)
self._prev_macd = float(macd_val)
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_close = float(candle.ClosePrice)
self._prev_open = float(candle.OpenPrice)
self._prev_macd = float(macd_val)
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
ema = float(ema_val)
rsi = float(rsi_val)
macd = float(macd_val)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_close = close
self._prev_open = open_price
self._prev_macd = macd
return
if self._prev_close == 0.0:
self._prev_close = close
self._prev_open = open_price
self._prev_macd = macd
return
cooldown = int(self._cooldown_bars.Value)
bullish_reversal = self._prev_close < self._prev_open and close > open_price
bearish_reversal = self._prev_close > self._prev_open and close < open_price
macd_rising = macd > self._prev_macd
macd_falling = macd < self._prev_macd
if bullish_reversal and close > ema and rsi < 65 and macd_rising and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif bearish_reversal and close < ema and rsi > 35 and macd_falling and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and bearish_reversal and close < ema:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and bullish_reversal and close > ema:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_close = close
self._prev_open = open_price
self._prev_macd = macd
def CreateClone(self):
return vela_superada_strategy()