La estrategia Basic Trailing Stop combina filtros del Commodity Channel Index (CCI) y del Relative Strength Index (RSI) con un stop trailing simple. Cuando ambos indicadores señalan condiciones de sobreventa o sobrecompra, la estrategia abre una posición de mercado y coloca inmediatamente un stop trailing medido en pips. A medida que el precio se mueve favorablemente, el nivel del stop sigue la tendencia para asegurar ganancias.
Las pruebas indican un rendimiento anual medio de aproximadamente el 32%. Funciona mejor en el mercado de divisas.
Dado que el nivel del stop sigue continuamente al precio, el riesgo se ajusta automáticamente cuando se extiende la tendencia. Las salidas ocurren solo si se alcanza el stop trailing. El sistema mantiene una posición a la vez y puede operar en ambas direcciones.
Detalles
Criterios de entrada:
Largo: CCI entre -150 y -100 y RSI entre 0 y 30.
Corto: CCI entre 100 y 250 y RSI entre 70 y 100.
Largo/Corto: Ambos.
Criterios de salida: Stop trailing alcanzado.
Stops: Solo stop trailing.
Valores predeterminados:
StopLossPips = 20
CciPeriod = 14
RsiPeriod = 14
CandleType = TimeSpan.FromMinutes(1)
Filtros:
Categoría: Momentum
Dirección: Ambos
Indicadores: CCI, RSI
Stops: Sí
Complejidad: Principiante
Marco temporal: Intradía
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>
/// Strategy implementing a basic trailing stop with CCI and RSI signals.
/// </summary>
public class BasicTrailingStopStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _stopPrice;
public decimal StopLossPct
{
get => _stopLossPct.Value;
set => _stopLossPct.Value = value;
}
public int CciPeriod
{
get => _cciPeriod.Value;
set => _cciPeriod.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public BasicTrailingStopStrategy()
{
_stopLossPct = Param(nameof(StopLossPct), 1.5m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Trailing stop distance as percentage", "Risk Management");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "Commodity Channel Index period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Relative Strength Index period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_stopPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var cci = new CommodityChannelIndex { Length = CciPeriod };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(cci, rsi, (candle, cciVal, rsiVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!cciVal.IsFormed || !rsiVal.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
ProcessCandle(candle, cciVal.ToDecimal(), rsiVal.ToDecimal());
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue, decimal rsiValue)
{
var stopOffset = candle.ClosePrice * StopLossPct / 100m;
if (Position > 0)
{
var newStop = candle.ClosePrice - stopOffset;
if (newStop > _stopPrice)
_stopPrice = newStop;
if (candle.LowPrice <= _stopPrice)
{
SellMarket();
_stopPrice = 0m;
}
return;
}
if (Position < 0)
{
var newStop = candle.ClosePrice + stopOffset;
if (_stopPrice == 0m || newStop < _stopPrice)
_stopPrice = newStop;
if (candle.HighPrice >= _stopPrice)
{
BuyMarket();
_stopPrice = 0m;
}
return;
}
// No position - evaluate entry signals
var longSignal = cciValue < -50m && rsiValue < 40m;
var shortSignal = cciValue > 50m && rsiValue > 60m;
if (longSignal)
{
BuyMarket();
_stopPrice = candle.ClosePrice - stopOffset;
}
else if (shortSignal)
{
SellMarket();
_stopPrice = candle.ClosePrice + stopOffset;
}
}
}
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 CommodityChannelIndex, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class basic_trailing_stop_strategy(Strategy):
def __init__(self):
super(basic_trailing_stop_strategy, self).__init__()
self._stop_loss_pct = self.Param("StopLossPct", 1.5) \
.SetDisplay("Stop Loss %", "Trailing stop distance as percentage", "Risk Management")
self._cci_period = self.Param("CciPeriod", 14) \
.SetDisplay("CCI Period", "Commodity Channel Index period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Relative Strength Index period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._stop_price = 0.0
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def cci_period(self):
return self._cci_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(basic_trailing_stop_strategy, self).OnReseted()
self._stop_price = 0.0
def OnStarted2(self, time):
super(basic_trailing_stop_strategy, self).OnStarted2(time)
cci = CommodityChannelIndex()
cci.Length = self.cci_period
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(cci, rsi, self.on_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def on_candle(self, candle, cci_val, rsi_val):
if candle.State != CandleStates.Finished:
return
if not cci_val.IsFormed or not rsi_val.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
self.process_candle(candle, float(cci_val), float(rsi_val))
def process_candle(self, candle, cci_value, rsi_value):
close = float(candle.ClosePrice)
stop_offset = close * float(self.stop_loss_pct) / 100.0
if self.Position > 0:
new_stop = close - stop_offset
if new_stop > self._stop_price:
self._stop_price = new_stop
if float(candle.LowPrice) <= self._stop_price:
self.SellMarket()
self._stop_price = 0.0
return
if self.Position < 0:
new_stop = close + stop_offset
if self._stop_price == 0.0 or new_stop < self._stop_price:
self._stop_price = new_stop
if float(candle.HighPrice) >= self._stop_price:
self.BuyMarket()
self._stop_price = 0.0
return
long_signal = cci_value < -50.0 and rsi_value < 40.0
short_signal = cci_value > 50.0 and rsi_value > 60.0
if long_signal:
self.BuyMarket()
self._stop_price = close - stop_offset
elif short_signal:
self.SellMarket()
self._stop_price = close + stop_offset
def CreateClone(self):
return basic_trailing_stop_strategy()