Tutorial - Añadir sesiones a estrategias
Estrategia basada en RSI que opera solo durante una sesión configurable. Entra largo cuando el RSI cruza por encima del nivel inferior, entra corto cuando cruza por debajo del nivel superior. Las posiciones se cierran cuando el mercado abandona la sesión.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI session strategy using RSI momentum with EMA trend filter.
/// </summary>
public class TutorialAddingSessionsToStrategiesStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _upper;
private readonly StrategyParam<decimal> _lower;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi;
private decimal _prevFast;
private decimal _prevSlow;
private int _cooldown;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal Upper { get => _upper.Value; set => _upper.Value = value; }
public decimal Lower { get => _lower.Value; set => _lower.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TutorialAddingSessionsToStrategiesStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI calculation length", "RSI");
_upper = Param(nameof(Upper), 70m)
.SetDisplay("Upper Level", "Overbought threshold", "RSI");
_lower = Param(nameof(Lower), 30m)
.SetDisplay("Lower Level", "Oversold threshold", "RSI");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_prevFast = 0;
_prevSlow = 0;
_cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var emaFast = new ExponentialMovingAverage { Length = 8 };
var emaSlow = new ExponentialMovingAverage { Length = 21 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, emaFast, emaSlow, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaFast, decimal emaSlow)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevRsi == 0 || _prevFast == 0 || _prevSlow == 0)
{
_prevRsi = rsiVal;
_prevFast = emaFast;
_prevSlow = emaSlow;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsiVal;
_prevFast = emaFast;
_prevSlow = emaSlow;
return;
}
var hist = emaFast - emaSlow;
var histUp = hist > 0m;
var histDown = hist < 0m;
var rsiCrossUp = _prevRsi <= 50m && rsiVal > 50m;
var rsiCrossDown = _prevRsi >= 50m && rsiVal < 50m;
// Exit
if (Position > 0 && rsiCrossDown)
{
SellMarket();
_cooldown = 30;
}
else if (Position < 0 && rsiCrossUp)
{
BuyMarket();
_cooldown = 30;
}
// Entry
if (Position == 0)
{
if (rsiCrossUp && histUp)
{
BuyMarket();
_cooldown = 30;
}
else if (rsiCrossDown && histDown)
{
SellMarket();
_cooldown = 30;
}
}
_prevRsi = rsiVal;
_prevFast = emaFast;
_prevSlow = emaSlow;
}
}
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 DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class tutorial_adding_sessions_to_strategies_strategy(Strategy):
"""RSI momentum with EMA trend filter: buy on RSI cross above 50 in uptrend."""
def __init__(self):
super(tutorial_adding_sessions_to_strategies_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14).SetGreaterThanZero().SetDisplay("RSI Period", "RSI length", "RSI")
self._upper = self.Param("Upper", 70.0).SetDisplay("Upper Level", "Overbought", "RSI")
self._lower = self.Param("Lower", 30.0).SetDisplay("Lower Level", "Oversold", "RSI")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(tutorial_adding_sessions_to_strategies_strategy, self).OnReseted()
self._prev_rsi = 0
self._prev_fast = 0
self._prev_slow = 0
self._cooldown = 0
def OnStarted2(self, time):
super(tutorial_adding_sessions_to_strategies_strategy, self).OnStarted2(time)
self._prev_rsi = 0
self._prev_fast = 0
self._prev_slow = 0
self._cooldown = 0
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_period.Value
ema_fast = ExponentialMovingAverage()
ema_fast.Length = 8
ema_slow = ExponentialMovingAverage()
ema_slow.Length = 21
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(rsi, ema_fast, ema_slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, ema_fast)
self.DrawIndicator(area, ema_slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, rsi_val, fast, slow):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_val)
fast = float(fast)
slow = float(slow)
if self._prev_rsi == 0 or self._prev_fast == 0 or self._prev_slow == 0:
self._prev_rsi = rsi_val
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_rsi = rsi_val
self._prev_fast = fast
self._prev_slow = slow
return
hist_up = fast > slow
hist_down = fast < slow
rsi_cross_up = self._prev_rsi <= 50 and rsi_val > 50
rsi_cross_down = self._prev_rsi >= 50 and rsi_val < 50
if self.Position > 0 and rsi_cross_down:
self.SellMarket()
self._cooldown = 30
elif self.Position < 0 and rsi_cross_up:
self.BuyMarket()
self._cooldown = 30
if self.Position == 0:
if rsi_cross_up and hist_up:
self.BuyMarket()
self._cooldown = 30
elif rsi_cross_down and hist_down:
self.SellMarket()
self._cooldown = 30
self._prev_rsi = rsi_val
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return tutorial_adding_sessions_to_strategies_strategy()