Estratégia de Fogo Rápido RoNz
Esta estratégia combina uma média móvel com o indicador Parabolic SAR para detectar mudanças rápidas de tendência. Uma posição comprada é aberta quando o preço de fechamento sobe acima da média móvel enquanto o Parabolic SAR vira para abaixo do preço. Uma posição vendida é aberta nas condições opostas. As posições podem opcionalmente ser médias quando a tendência continua.
Como Funciona
- Entrada comprado: Preço de fechamento > SMA e Parabolic SAR muda para abaixo do preço.
- Entrada vendido: Preço de fechamento < SMA e Parabolic SAR muda para acima do preço.
- Fechamento: Por stop loss/take profit ou por sinal oposto dependendo do modo selecionado.
- Médias: Adiciona novas posições quando a tendência persiste.
- Trailing Stop: Ajusta o preço de stop à medida que a operação avança no lucro.
Parâmetros
Volume– volume da operação.StopLoss– stop loss em ticks.TakeProfit– take profit em ticks.TrailingStop– trailing stop em ticks.Averaging– ativar médias de posições.MaPeriod– período da média móvel.PsarStep– passo do Parabolic SAR.PsarMax– valor máximo do Parabolic SAR.CloseType–SlCloseusa apenas stops,TrendClosefecha em tendência oposta.CandleType– série de candles para cálculos.
Notas
- Funciona com qualquer instrumento suportado pelo StockSharp.
- Requer candles históricos para o
CandleTypeselecionado.
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()