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.
/// A bearish candle followed by a bullish one that closes above the prior open, with both closes above the EMA, RSI below 65
/// and a rising MACD line, is a long signal. The mirrored pattern below the EMA with RSI above 35 and a falling MACD line is
/// a short signal. ShowLong and ShowShort enable each side; an opposite signal closes or reverses the position. A trailing
/// SlPercent stop and a TpPercent take profit protect the trade.
/// </summary>
public class VelaSuperadaStrategy : Strategy
{
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<bool> _showLong;
private readonly StrategyParam<bool> _showShort;
private readonly StrategyParam<decimal> _tpPercent;
private readonly StrategyParam<decimal> _slPercent;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _prevCandle;
private decimal? _prevMacd;
/// <summary>
/// EMA period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// Allow long trades.
/// </summary>
public bool ShowLong
{
get => _showLong.Value;
set => _showLong.Value = value;
}
/// <summary>
/// Allow short trades.
/// </summary>
public bool ShowShort
{
get => _showShort.Value;
set => _showShort.Value = value;
}
/// <summary>
/// Take profit percentage from entry price.
/// </summary>
public decimal TpPercent
{
get => _tpPercent.Value;
set => _tpPercent.Value = value;
}
/// <summary>
/// Trailing stop loss percentage.
/// </summary>
public decimal SlPercent
{
get => _slPercent.Value;
set => _slPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public VelaSuperadaStrategy()
{
_emaLength = Param(nameof(EmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_showLong = Param(nameof(ShowLong), true)
.SetDisplay("Long Trades", "Allow long trades", "Trading");
_showShort = Param(nameof(ShowShort), false)
.SetDisplay("Short Trades", "Allow short trades", "Trading");
_tpPercent = Param(nameof(TpPercent), 1.2m)
.SetNotNegative()
.SetDisplay("TP %", "Take profit percentage from entry price", "Risk");
_slPercent = Param(nameof(SlPercent), 1.8m)
.SetNotNegative()
.SetDisplay("SL %", "Trailing stop loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
_prevMacd = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_prevMacd = null;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var macd = new MovingAverageConvergenceDivergence();
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ema, rsi, macd, ProcessCandle)
.Start();
StartProtection(
TpPercent > 0m ? new Unit(TpPercent, UnitTypes.Percent) : new Unit(),
SlPercent > 0m ? new Unit(SlPercent, UnitTypes.Percent) : new Unit(),
isStopTrailing: true,
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
{
DrawIndicator(oscillators, rsi);
DrawIndicator(oscillators, macd);
}
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaValue, IIndicatorValue rsiValue, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
var prevCandle = _prevCandle;
_prevCandle = candle;
if (!macdValue.IsFormed)
return;
var macd = macdValue.GetValue<decimal>();
var prevMacd = _prevMacd;
_prevMacd = macd;
if (prevCandle == null || prevMacd is not decimal previousMacd || !emaValue.IsFormed || !rsiValue.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var ema = emaValue.GetValue<decimal>();
var rsi = rsiValue.GetValue<decimal>();
var close = candle.ClosePrice;
var prevClose = prevCandle.ClosePrice;
var longSignal = prevCandle.ClosePrice < prevCandle.OpenPrice && close > candle.OpenPrice && close > prevCandle.OpenPrice
&& close > ema && prevClose > ema && rsi < 65m && macd > previousMacd;
var shortSignal = prevCandle.ClosePrice > prevCandle.OpenPrice && close < candle.OpenPrice && close < prevCandle.OpenPrice
&& close < ema && prevClose < ema && rsi > 35m && macd < previousMacd;
if (longSignal)
{
if (ShowLong && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (Position < 0)
BuyMarket(-Position);
}
else if (shortSignal)
{
if (ShowShort && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0)
SellMarket(Position);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex, MovingAverageConvergenceDivergence
from StockSharp.Algo.Strategies import Strategy
class vela_superada_strategy(Strategy):
"""
Vela Superada Strategy.
A bearish candle followed by a bullish one that closes above the prior open, with both closes above the EMA, RSI below 65
and a rising MACD line, is a long signal. The mirrored pattern below the EMA with RSI above 35 and a falling MACD line is
a short signal. ShowLong and ShowShort enable each side; an opposite signal closes or reverses the position. A trailing
SlPercent stop and a TpPercent take profit protect the trade.
"""
def __init__(self):
super(vela_superada_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 10).SetGreaterThanZero().SetDisplay("EMA Length", "EMA period", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "RSI period", "Indicators")
self._show_long = self.Param("ShowLong", True).SetDisplay("Long Trades", "Allow long trades", "Trading")
self._show_short = self.Param("ShowShort", False).SetDisplay("Short Trades", "Allow short trades", "Trading")
self._tp_percent = self.Param("TpPercent", 1.2).SetNotNegative().SetDisplay("TP %", "Take profit percentage from entry price", "Risk")
self._sl_percent = self.Param("SlPercent", 1.8).SetNotNegative().SetDisplay("SL %", "Trailing stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_candle = None
self._prev_macd = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vela_superada_strategy, self).OnReseted()
self._prev_candle = None
self._prev_macd = None
def OnStarted2(self, time):
super(vela_superada_strategy, self).OnStarted2(time)
self._prev_candle = None
self._prev_macd = None
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
macd = MovingAverageConvergenceDivergence()
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ema, rsi, macd, self._process_candle).Start()
tp = float(self._tp_percent.Value)
sl = float(self._sl_percent.Value)
self.StartProtection(
Unit(Decimal(tp), UnitTypes.Percent) if tp > 0 else Unit(),
Unit(Decimal(sl), UnitTypes.Percent) if sl > 0 else Unit(),
isStopTrailing=True,
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
self.DrawIndicator(oscillators, macd)
def _process_candle(self, candle, ema_value, rsi_value, macd_value):
if candle.State != CandleStates.Finished:
return
prev_candle = self._prev_candle
self._prev_candle = candle
if not macd_value.IsFormed:
return
macd = float(macd_value.GetValue[Decimal](None))
prev_macd = self._prev_macd
self._prev_macd = macd
if prev_candle is None or prev_macd is None or not ema_value.IsFormed or not rsi_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
ema = float(ema_value.GetValue[Decimal](None))
rsi = float(rsi_value.GetValue[Decimal](None))
open_price = float(candle.OpenPrice)
close = float(candle.ClosePrice)
prev_open = float(prev_candle.OpenPrice)
prev_close = float(prev_candle.ClosePrice)
long_signal = (prev_close < prev_open and close > open_price and close > prev_open
and close > ema and prev_close > ema and rsi < 65 and macd > prev_macd)
short_signal = (prev_close > prev_open and close < open_price and close < prev_open
and close < ema and prev_close < ema and rsi > 35 and macd < prev_macd)
if long_signal:
if self._show_long.Value and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif self.Position < 0:
self.BuyMarket(-self.Position)
elif short_signal:
if self._show_short.Value and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0:
self.SellMarket(self.Position)
def CreateClone(self):
return vela_superada_strategy()