Estrategia de Fuego Rápido RoNz
Esta estrategia combina una media móvil con el indicador Parabolic SAR para detectar cambios rápidos de tendencia. Se abre una posición larga cuando el precio de cierre supera la media móvil mientras el Parabolic SAR gira por debajo del precio. Se abre una posición corta en las condiciones opuestas. Las posiciones pueden promediarse opcionalmente cuando la tendencia continúa.
Cómo Funciona
- Entrada largo: Precio de cierre > SMA y Parabolic SAR cambia a por debajo del precio.
- Entrada corto: Precio de cierre < SMA y Parabolic SAR cambia a por encima del precio.
- Cierre: Por stop loss/take profit o por señal opuesta según el modo seleccionado.
- Promediado: Añade nuevas posiciones cuando la tendencia persiste.
- Trailing Stop: Ajusta el precio de stop a medida que la operación avanza en beneficio.
Parámetros
Volume– volumen de la operación.StopLoss– stop loss en ticks.TakeProfit– take profit en ticks.TrailingStop– trailing stop en ticks.Averaging– activar promediado de posiciones.MaPeriod– período de la media móvil.PsarStep– paso del Parabolic SAR.PsarMax– valor máximo del Parabolic SAR.CloseType–SlCloseusa solo stops,TrendClosecierra en tendencia opuesta.CandleType– serie de velas para los cálculos.
Notas
- Funciona con cualquier instrumento compatible con StockSharp.
- Requiere velas históricas para el
CandleTypeseleccionado.
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>
/// RoNz Rapid-Fire strategy based on MA and Parabolic SAR trend signals.
/// </summary>
public class RoNzRapidFireStrategy : Strategy
{
public enum CloseTypes
{
SlClose,
TrendClose
}
private readonly StrategyParam<int> _stopLoss;
private readonly StrategyParam<int> _takeProfit;
private readonly StrategyParam<int> _trailingStop;
private readonly StrategyParam<bool> _averaging;
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _psarStep;
private readonly StrategyParam<decimal> _psarMax;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<CloseTypes> _closeType;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _stopPrice;
private decimal _takePrice;
private decimal _prevClose;
private decimal _prevSma;
private decimal _tick;
private int _barsSinceTrade;
/// <summary>
/// Stop loss in ticks.
/// </summary>
public int StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit in ticks.
/// </summary>
public int TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Trailing stop in ticks.
/// </summary>
public int TrailingStop
{
get => _trailingStop.Value;
set => _trailingStop.Value = value;
}
/// <summary>
/// Enable averaging.
/// </summary>
public bool Averaging
{
get => _averaging.Value;
set => _averaging.Value = value;
}
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Parabolic SAR step.
/// </summary>
public decimal PsarStep
{
get => _psarStep.Value;
set => _psarStep.Value = value;
}
/// <summary>
/// Parabolic SAR maximum.
/// </summary>
public decimal PsarMax
{
get => _psarMax.Value;
set => _psarMax.Value = value;
}
/// <summary>
/// Minimum number of bars between entries.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Close mode.
/// </summary>
public CloseTypes CloseType
{
get => _closeType.Value;
set => _closeType.Value = value;
}
/// <summary>
/// Candle series type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public RoNzRapidFireStrategy()
{
_stopLoss = Param(nameof(StopLoss), 150)
.SetDisplay("Stop Loss", "Stop loss in ticks", "Risk");
_takeProfit = Param(nameof(TakeProfit), 100)
.SetDisplay("Take Profit", "Take profit in ticks", "Risk");
_trailingStop = Param(nameof(TrailingStop), 0)
.SetDisplay("Trailing Stop", "Trailing stop in ticks", "Risk");
_averaging = Param(nameof(Averaging), false)
.SetDisplay("Averaging", "Add to position on continuing trend", "General");
_maPeriod = Param(nameof(MaPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Indicator");
_psarStep = Param(nameof(PsarStep), 0.02m)
.SetGreaterThanZero()
.SetDisplay("PSAR Step", "Parabolic SAR step", "Indicator");
_psarMax = Param(nameof(PsarMax), 0.2m)
.SetGreaterThanZero()
.SetDisplay("PSAR Max", "Parabolic SAR maximum", "Indicator");
_cooldownBars = Param(nameof(CooldownBars), 6)
.SetGreaterThanZero()
.SetDisplay("Cooldown Bars", "Bars between entries", "General");
_closeType = Param(nameof(CloseType), CloseTypes.SlClose)
.SetDisplay("Close Type", "Use stops or trend reversals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_stopPrice = 0m;
_takePrice = 0m;
_prevClose = 0m;
_prevSma = 0m;
_tick = 0m;
_barsSinceTrade = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_tick = Security?.PriceStep ?? 1m;
_barsSinceTrade = CooldownBars;
var sma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
_barsSinceTrade++;
var upSignal = _prevClose != 0m && _prevSma != 0m && _prevClose <= _prevSma && candle.ClosePrice > smaValue;
var downSignal = _prevClose != 0m && _prevSma != 0m && _prevClose >= _prevSma && candle.ClosePrice < smaValue;
if (Position > 0)
{
if (CloseType == CloseTypes.TrendClose && downSignal)
{
SellMarket(Position);
_barsSinceTrade = 0;
}
if (TakeProfit > 0 && candle.HighPrice >= _takePrice)
{
SellMarket(Position);
_barsSinceTrade = 0;
}
if (StopLoss > 0 && candle.LowPrice <= _stopPrice)
{
SellMarket(Position);
_barsSinceTrade = 0;
}
if (TrailingStop > 0)
{
var trail = candle.ClosePrice - TrailingStop * _tick;
if (trail > _stopPrice)
_stopPrice = trail;
}
if (Averaging && upSignal && _barsSinceTrade >= CooldownBars)
EnterLong(candle);
}
else if (Position < 0)
{
if (CloseType == CloseTypes.TrendClose && upSignal)
{
BuyMarket(Math.Abs(Position));
_barsSinceTrade = 0;
}
if (TakeProfit > 0 && candle.LowPrice <= _takePrice)
{
BuyMarket(Math.Abs(Position));
_barsSinceTrade = 0;
}
if (StopLoss > 0 && candle.HighPrice >= _stopPrice)
{
BuyMarket(Math.Abs(Position));
_barsSinceTrade = 0;
}
if (TrailingStop > 0)
{
var trail = candle.ClosePrice + TrailingStop * _tick;
if (trail < _stopPrice)
_stopPrice = trail;
}
if (Averaging && downSignal && _barsSinceTrade >= CooldownBars)
EnterShort(candle);
}
else
{
if (upSignal && _barsSinceTrade >= CooldownBars)
EnterLong(candle);
else if (downSignal && _barsSinceTrade >= CooldownBars)
EnterShort(candle);
}
_prevClose = candle.ClosePrice;
_prevSma = smaValue;
}
private void EnterLong(ICandleMessage candle)
{
BuyMarket(Volume);
_entryPrice = candle.ClosePrice;
_stopPrice = StopLoss > 0 ? _entryPrice - StopLoss * _tick : 0m;
_takePrice = TakeProfit > 0 ? _entryPrice + TakeProfit * _tick : 0m;
_barsSinceTrade = 0;
}
private void EnterShort(ICandleMessage candle)
{
SellMarket(Volume);
_entryPrice = candle.ClosePrice;
_stopPrice = StopLoss > 0 ? _entryPrice + StopLoss * _tick : 0m;
_takePrice = TakeProfit > 0 ? _entryPrice - TakeProfit * _tick : 0m;
_barsSinceTrade = 0;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
# CloseTypes: 0 = SlClose, 1 = TrendClose
class ro_nz_rapid_fire_strategy(Strategy):
def __init__(self):
super(ro_nz_rapid_fire_strategy, self).__init__()
self._stop_loss = self.Param("StopLoss", 150) \
.SetDisplay("Stop Loss", "Stop loss in ticks", "Risk")
self._take_profit = self.Param("TakeProfit", 100) \
.SetDisplay("Take Profit", "Take profit in ticks", "Risk")
self._trailing_stop = self.Param("TrailingStop", 0) \
.SetDisplay("Trailing Stop", "Trailing stop in ticks", "Risk")
self._averaging = self.Param("Averaging", False) \
.SetDisplay("Averaging", "Add to position on continuing trend", "General")
self._ma_period = self.Param("MaPeriod", 30) \
.SetDisplay("MA Period", "Moving average period", "Indicator")
self._psar_step = self.Param("PsarStep", 0.02) \
.SetDisplay("PSAR Step", "Parabolic SAR step", "Indicator")
self._psar_max = self.Param("PsarMax", 0.2) \
.SetDisplay("PSAR Max", "Parabolic SAR maximum", "Indicator")
self._cooldown_bars = self.Param("CooldownBars", 6) \
.SetDisplay("Cooldown Bars", "Bars between entries", "General")
self._close_type = self.Param("CloseType", 0) \
.SetDisplay("Close Type", "0=StopClose, 1=TrendClose", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles for calculations", "General")
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
self._prev_close = 0.0
self._prev_sma = 0.0
self._tick = 0.0
self._bars_since_trade = 0
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def TrailingStop(self):
return self._trailing_stop.Value
@TrailingStop.setter
def TrailingStop(self, value):
self._trailing_stop.Value = value
@property
def Averaging(self):
return self._averaging.Value
@Averaging.setter
def Averaging(self, value):
self._averaging.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
@property
def PsarStep(self):
return self._psar_step.Value
@PsarStep.setter
def PsarStep(self, value):
self._psar_step.Value = value
@property
def PsarMax(self):
return self._psar_max.Value
@PsarMax.setter
def PsarMax(self, value):
self._psar_max.Value = value
@property
def CooldownBars(self):
return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, value):
self._cooldown_bars.Value = value
@property
def CloseType(self):
return self._close_type.Value
@CloseType.setter
def CloseType(self, value):
self._close_type.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(ro_nz_rapid_fire_strategy, self).OnStarted2(time)
sec = self.Security
self._tick = float(sec.PriceStep) if sec is not None and sec.PriceStep is not None else 1.0
self._bars_since_trade = self.CooldownBars
sma = SimpleMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(sma, self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
self._bars_since_trade += 1
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
sma_val = float(sma_value)
up_signal = (self._prev_close != 0.0 and self._prev_sma != 0.0
and self._prev_close <= self._prev_sma and close > sma_val)
down_signal = (self._prev_close != 0.0 and self._prev_sma != 0.0
and self._prev_close >= self._prev_sma and close < sma_val)
pos = self.Position
if pos > 0:
if self.CloseType == 1 and down_signal:
self.SellMarket(pos)
self._bars_since_trade = 0
if self.TakeProfit > 0 and high >= self._take_price:
self.SellMarket(self.Position)
self._bars_since_trade = 0
if self.StopLoss > 0 and low <= self._stop_price:
self.SellMarket(self.Position)
self._bars_since_trade = 0
if self.TrailingStop > 0:
trail = close - self.TrailingStop * self._tick
if trail > self._stop_price:
self._stop_price = trail
if self.Averaging and up_signal and self._bars_since_trade >= self.CooldownBars:
self._enter_long(candle)
elif pos < 0:
if self.CloseType == 1 and up_signal:
self.BuyMarket(abs(pos))
self._bars_since_trade = 0
if self.TakeProfit > 0 and low <= self._take_price:
self.BuyMarket(abs(self.Position))
self._bars_since_trade = 0
if self.StopLoss > 0 and high >= self._stop_price:
self.BuyMarket(abs(self.Position))
self._bars_since_trade = 0
if self.TrailingStop > 0:
trail = close + self.TrailingStop * self._tick
if trail < self._stop_price:
self._stop_price = trail
if self.Averaging and down_signal and self._bars_since_trade >= self.CooldownBars:
self._enter_short(candle)
else:
if up_signal and self._bars_since_trade >= self.CooldownBars:
self._enter_long(candle)
elif down_signal and self._bars_since_trade >= self.CooldownBars:
self._enter_short(candle)
self._prev_close = close
self._prev_sma = sma_val
def _enter_long(self, candle):
self.BuyMarket(self.Volume)
self._entry_price = float(candle.ClosePrice)
self._stop_price = self._entry_price - self.StopLoss * self._tick if self.StopLoss > 0 else 0.0
self._take_price = self._entry_price + self.TakeProfit * self._tick if self.TakeProfit > 0 else 0.0
self._bars_since_trade = 0
def _enter_short(self, candle):
self.SellMarket(self.Volume)
self._entry_price = float(candle.ClosePrice)
self._stop_price = self._entry_price + self.StopLoss * self._tick if self.StopLoss > 0 else 0.0
self._take_price = self._entry_price - self.TakeProfit * self._tick if self.TakeProfit > 0 else 0.0
self._bars_since_trade = 0
def OnReseted(self):
super(ro_nz_rapid_fire_strategy, self).OnReseted()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
self._prev_close = 0.0
self._prev_sma = 0.0
self._tick = 0.0
self._bars_since_trade = self.CooldownBars
def CreateClone(self):
return ro_nz_rapid_fire_strategy()