Estrategia Graph Style 4th Dimension RSI
Estrategia que combina el cambio de precio con los niveles del RSI.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 80%. Funciona bien en mercados volátiles.
La estrategia verifica la dirección del último cambio de precio junto con los extremos del RSI. Abre una posición cuando el RSI sale de las zonas de sobrecompra/sobreventa y el cambio de precio reciente confirma el movimiento. Las posiciones se cierran cuando el RSI vuelve al área media o aparece una señal opuesta.
Detalles
- Criterios de entrada: Dirección del cambio de precio con extremo del RSI.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Señal opuesta o RSI de regreso al medio.
- Stops: Stop loss porcentual.
- Valores predeterminados:
RsiPeriod= 14OverboughtLevel= 70mOversoldLevel= 30mStopLossPercent= 1mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: RSI
- Stops: Porcentaje
- Complejidad: Básico
- Marco temporal: Intradía (5m)
- 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>
/// Graph Style 4th Dimension RSI strategy.
/// Goes long when RSI leaves the oversold zone upward on a candle that closed higher than the previous one, and short when RSI
/// leaves the overbought zone downward on a candle that closed lower, reversing an opposite position. A long closes when RSI
/// returns to the middle level 50 from below and a short when it returns from above; a percent stop limits the loss.
/// </summary>
public class GraphStyle4thDimensionRSIStrategy : Strategy
{
private const decimal _middleLevel = 50m;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevRsi;
private decimal? _prevClose;
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public GraphStyle4thDimensionRSIStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Period of RSI", "Indicators");
_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
.SetDisplay("Overbought", "RSI overbought level", "Indicators");
_oversoldLevel = Param(nameof(OversoldLevel), 30m)
.SetDisplay("Oversold", "RSI oversold level", "Indicators");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
_prevRsi = null;
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevRsi = null;
_prevClose = null;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
var prevRsi = _prevRsi;
var prevClose = _prevClose;
_prevRsi = rsi;
_prevClose = candle.ClosePrice;
if (prevRsi is not decimal lastRsi || prevClose is not decimal lastClose)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var longSignal = lastRsi < OversoldLevel && rsi >= OversoldLevel && close > lastClose;
var shortSignal = lastRsi > OverboughtLevel && rsi <= OverboughtLevel && close < lastClose;
if (longSignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && rsi >= _middleLevel)
SellMarket(Position);
else if (Position < 0 && rsi <= _middleLevel)
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
MIDDLE_LEVEL = 50.0
class graph_style_4th_dimension_rsi_strategy(Strategy):
"""
Graph Style 4th Dimension RSI strategy.
Goes long when RSI leaves the oversold zone upward on a candle that closed higher than the previous one, and short when RSI
leaves the overbought zone downward on a candle that closed lower, reversing an opposite position. A long closes when RSI
returns to the middle level 50 from below and a short when it returns from above; a percent stop limits the loss.
"""
def __init__(self):
super(graph_style_4th_dimension_rsi_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetGreaterThanZero().SetDisplay("RSI Period", "Period of RSI", "Indicators")
self._overbought_level = self.Param("OverboughtLevel", 70.0).SetDisplay("Overbought", "RSI overbought level", "Indicators")
self._oversold_level = self.Param("OversoldLevel", 30.0).SetDisplay("Oversold", "RSI oversold level", "Indicators")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_rsi = None
self._prev_close = None
def OnReseted(self):
super(graph_style_4th_dimension_rsi_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(graph_style_4th_dimension_rsi_strategy, self).OnStarted2(time)
self._reset_state()
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(rsi, self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi = float(rsi_value)
close = float(candle.ClosePrice)
last_rsi = self._prev_rsi
last_close = self._prev_close
self._prev_rsi = rsi
self._prev_close = close
if last_rsi is None or last_close is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
oversold = float(self._oversold_level.Value)
overbought = float(self._overbought_level.Value)
long_signal = last_rsi < oversold and rsi >= oversold and close > last_close
short_signal = last_rsi > overbought and rsi <= overbought and close < last_close
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and rsi >= MIDDLE_LEVEL:
self.SellMarket(self.Position)
elif self.Position < 0 and rsi <= MIDDLE_LEVEL:
self.BuyMarket(-self.Position)
def CreateClone(self):
return graph_style_4th_dimension_rsi_strategy()