Стратегия Vela Superada
Стратегия Vela Superada торгует разворотный паттерн из двух свечей. Бычий сигнал появляется, когда за медвежьей свечой следует бычья, закрывающаяся выше открытия предыдущей. Для фильтрации используются краткосрочная EMA, RSI и MACD, что помогает избегать сигналов против тренда. Возможна работа как в длинную, так и в короткую сторону.
Стратегия использует процентные уровни тейк-профита и стоп-лосса и динамически подтягивает трейлинг-стоп по мере движения цены в прибыль. Это позволяет удерживать длительные движения и одновременно защищает от разворота.
Подробности
- Условия входа:
- Лонг: предыдущая свеча медвежья, текущая бычья, закрытие и предыдущее закрытие выше EMA, RSI < 65, MACD растёт.
- Шорт: предыдущая свеча бычья, текущая медвежья, закрытие и предыдущее закрытие ниже EMA, RSI > 35, MACD падает.
- Направление: настраиваемое (по умолчанию только лонг).
- Условия выхода:
- Трейлинг-стоп или противоположный сигнал.
- Стопы: процентный стоп и тейк-профит.
- Параметры по умолчанию:
EmaLength= 10RsiLength= 14ShowLong= TrueShowShort= FalseTpPercent= 1.2SlPercent= 1.8
- Фильтры:
- Категория: Паттерн + индикаторы
- Направление: Обе
- Индикаторы: EMA, RSI, MACD
- Стопы: Да
- Сложность: Средняя
- Таймфрейм: Любой
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Да
- Уровень риска: Средний
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()