Estrategia de Cruce de Nube TSI
La Estrategia de Cruce de Nube TSI compara el True Strength Index (TSI) con una copia retardada de sí mismo para formar una nube. Se abre una posición larga cuando el TSI cruza por encima de la línea desplazada, indicando impulso alcista. Se abre una posición corta cuando el TSI cruza por debajo de la línea desplazada. Las señales pueden invertirse y las posiciones opuestas pueden cerrarse opcionalmente.
Detalles
- Criterios de entrada:
- TSI cruza por encima de su valor desplazado (largo).
- TSI cruza por debajo de su valor desplazado (corto).
- Largo/Corto: Ambos.
- Criterios de salida:
- Cierre opcional con señal opuesta.
- Stops: Ninguno.
- Valores predeterminados:
LongLength= 25ShortLength= 13TriggerShift= 1Invert= false
- Filtros:
- Categoría: Oscilador de momentum
- Dirección: Largo/Corto
- Indicadores: True Strength Index
- Stops: No
- Complejidad: Bajo
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Bajo
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>
/// True Strength Index cross with shifted TSI line.
/// Opens long when TSI crosses above its shifted value and short on opposite cross.
/// </summary>
public class TsiCloudCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _firstLength;
private readonly StrategyParam<int> _secondLength;
private readonly StrategyParam<int> _triggerShift;
private TrueStrengthIndex _tsi;
private readonly Queue<decimal> _tsiValues = new();
private decimal _prevTsi;
private decimal _prevTrigger;
private bool _isInitialized;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FirstLength { get => _firstLength.Value; set => _firstLength.Value = value; }
public int SecondLength { get => _secondLength.Value; set => _secondLength.Value = value; }
public int TriggerShift { get => _triggerShift.Value; set => _triggerShift.Value = value; }
public TsiCloudCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_firstLength = Param(nameof(FirstLength), 25)
.SetDisplay("First Length", "First smoothing period for TSI", "TSI")
.SetGreaterThanZero();
_secondLength = Param(nameof(SecondLength), 13)
.SetDisplay("Second Length", "Second smoothing period for TSI", "TSI")
.SetGreaterThanZero();
_triggerShift = Param(nameof(TriggerShift), 1)
.SetDisplay("Trigger Shift", "Bars to shift TSI for trigger", "TSI")
.SetGreaterThanZero();
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_tsi = null;
_tsiValues.Clear();
_prevTsi = 0;
_prevTrigger = 0;
_isInitialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_tsiValues.Clear();
_isInitialized = false;
_tsi = new TrueStrengthIndex
{
FirstLength = FirstLength,
SecondLength = SecondLength,
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_tsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _tsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (value is not ITrueStrengthIndexValue tsiVal || tsiVal.Tsi is not decimal tsiValue)
return;
if (!_tsi.IsFormed)
return;
_tsiValues.Enqueue(tsiValue);
if (_tsiValues.Count > TriggerShift + 1)
_tsiValues.Dequeue();
if (_tsiValues.Count < TriggerShift + 1)
{
_prevTsi = tsiValue;
_prevTrigger = tsiValue;
return;
}
var trigger = _tsiValues.Peek();
if (!_isInitialized)
{
_prevTsi = tsiValue;
_prevTrigger = trigger;
_isInitialized = true;
return;
}
var crossUp = _prevTsi <= _prevTrigger && tsiValue > trigger;
var crossDown = _prevTsi >= _prevTrigger && tsiValue < trigger;
_prevTsi = tsiValue;
_prevTrigger = trigger;
if (crossUp && Position <= 0)
BuyMarket();
else if (crossDown && Position >= 0)
SellMarket();
}
}
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 TrueStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class tsi_cloud_cross_strategy(Strategy):
def __init__(self):
super(tsi_cloud_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._first_length = self.Param("FirstLength", 25) \
.SetDisplay("First Length", "First smoothing period for TSI", "TSI")
self._second_length = self.Param("SecondLength", 13) \
.SetDisplay("Second Length", "Second smoothing period for TSI", "TSI")
self._trigger_shift = self.Param("TriggerShift", 1) \
.SetDisplay("Trigger Shift", "Bars to shift TSI for trigger", "TSI")
self._tsi = None
self._tsi_values = []
self._prev_tsi = 0.0
self._prev_trigger = 0.0
self._is_initialized = False
@property
def candle_type(self):
return self._candle_type.Value
@property
def first_length(self):
return self._first_length.Value
@property
def second_length(self):
return self._second_length.Value
@property
def trigger_shift(self):
return self._trigger_shift.Value
def OnReseted(self):
super(tsi_cloud_cross_strategy, self).OnReseted()
self._tsi = None
self._tsi_values = []
self._prev_tsi = 0.0
self._prev_trigger = 0.0
self._is_initialized = False
def OnStarted2(self, time):
super(tsi_cloud_cross_strategy, self).OnStarted2(time)
self._tsi_values = []
self._is_initialized = False
self._tsi = TrueStrengthIndex()
self._tsi.FirstLength = self.first_length
self._tsi.SecondLength = self.second_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._tsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._tsi)
self.DrawOwnTrades(area)
def process_candle(self, candle, value):
if candle.State != CandleStates.Finished:
return
tsi_val = value.Tsi
if tsi_val is None:
return
tsi_value = float(tsi_val)
if not self._tsi.IsFormed:
return
shift = int(self.trigger_shift)
self._tsi_values.append(tsi_value)
if len(self._tsi_values) > shift + 1:
self._tsi_values.pop(0)
if len(self._tsi_values) < shift + 1:
self._prev_tsi = tsi_value
self._prev_trigger = tsi_value
return
trigger = self._tsi_values[0]
if not self._is_initialized:
self._prev_tsi = tsi_value
self._prev_trigger = trigger
self._is_initialized = True
return
cross_up = self._prev_tsi <= self._prev_trigger and tsi_value > trigger
cross_down = self._prev_tsi >= self._prev_trigger and tsi_value < trigger
self._prev_tsi = tsi_value
self._prev_trigger = trigger
if cross_up and self.Position <= 0:
self.BuyMarket()
elif cross_down and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return tsi_cloud_cross_strategy()