Estrategia de Reversión VRS Vegas
Estrategia de reversión que utiliza las mechas de las velas.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 37%. Funciona mejor en el mercado de criptomonedas.
El sistema busca grandes picos relativos al precio de cierre. Una mecha inferior grande activa una entrada larga mientras que una mecha superior grande activa una entrada corta. Las posiciones se cierran cuando el precio se mueve el doble del tamaño del pico en beneficio.
Detalles
- Criterios de entrada:
- Largo: mecha inferior ≥ Spike% * close y sin pico superior.
- Corto: mecha superior ≥ Spike% * close y sin pico inferior.
- Largo/Corto: Ambos lados.
- Criterios de salida: Objetivo en entrada ± (pico * 2).
- Stops: No.
- Valores predeterminados:
SpikePercent= 0.025CandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Reversión
- Dirección: Ambos
- Indicadores: Price action
- Stops: No
- Complejidad: Básico
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Alto
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>
/// Vegas Reversal strategy based on spike percentage.
/// Enters long on large lower wick and short on large upper wick.
/// Exits when price moves twice the spike length in favor.
/// </summary>
public class VrsVegasReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _spikePercent;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _spikeSize;
private bool _isLong;
/// <summary>
/// Spike percentage relative to close price.
/// </summary>
public decimal SpikePercent
{
get => _spikePercent.Value;
set => _spikePercent.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="VrsVegasReversalStrategy"/>.
/// </summary>
public VrsVegasReversalStrategy()
{
_spikePercent = Param(nameof(SpikePercent), 0.025m)
.SetGreaterThanZero()
.SetDisplay("Spike %", "Spike percentage threshold", "Reversal")
.SetOptimize(0.01m, 0.05m, 0.005m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_spikeSize = 0;
_isLong = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Volume = NormalizeVolume(1m);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var upperSpike = candle.HighPrice - Math.Max(candle.ClosePrice, candle.OpenPrice);
var lowerSpike = Math.Min(candle.ClosePrice, candle.OpenPrice) - candle.LowPrice;
var validUpper = upperSpike >= candle.ClosePrice * SpikePercent;
var validLower = lowerSpike >= candle.ClosePrice * SpikePercent;
var valid = (validUpper && !validLower) || (validLower && !validUpper);
var enterLong = valid && validLower;
var enterShort = valid && validUpper;
if (enterLong && Position <= 0)
{
_entryPrice = candle.ClosePrice;
_spikeSize = lowerSpike;
_isLong = true;
BuyMarket(NormalizeVolume(Volume + Math.Abs(Position)));
}
else if (enterShort && Position >= 0)
{
_entryPrice = candle.ClosePrice;
_spikeSize = upperSpike;
_isLong = false;
SellMarket(NormalizeVolume(Volume + Math.Abs(Position)));
}
if (Position > 0 && _isLong)
{
var target = _entryPrice + _spikeSize * 2m;
if (candle.ClosePrice >= target)
SellMarket(Position);
}
else if (Position < 0 && !_isLong)
{
var target = _entryPrice - _spikeSize * 2m;
if (candle.ClosePrice <= target)
BuyMarket(-Position);
}
}
private decimal NormalizeVolume(decimal volume)
{
var step = Security?.VolumeStep ?? 1m;
if (step <= 0m)
step = 1m;
var minimum = Security?.MinVolume ?? step;
if (volume < minimum)
volume = minimum;
var rounded = Math.Ceiling(volume / step) * step;
return rounded < minimum ? minimum : rounded;
}
}
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.Strategies import Strategy
class vrs_vegas_reversal_strategy(Strategy):
def __init__(self):
super(vrs_vegas_reversal_strategy, self).__init__()
self._spike_percent = self.Param("SpikePercent", 0.025) \
.SetDisplay("Spike %", "Spike percentage threshold", "Reversal")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
self._spike_size = 0.0
self._is_long = False
@property
def spike_percent(self):
return self._spike_percent.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(vrs_vegas_reversal_strategy, self).OnReseted()
self._entry_price = 0.0
self._spike_size = 0.0
self._is_long = False
def OnStarted2(self, time):
super(vrs_vegas_reversal_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle):
if candle.State != CandleStates.Finished:
return
upper_spike = float(candle.HighPrice) - max(float(candle.ClosePrice), float(candle.OpenPrice))
lower_spike = min(float(candle.ClosePrice), float(candle.OpenPrice)) - float(candle.LowPrice)
close = float(candle.ClosePrice)
sp = float(self.spike_percent)
valid_upper = upper_spike >= close * sp
valid_lower = lower_spike >= close * sp
valid = (valid_upper and not valid_lower) or (valid_lower and not valid_upper)
enter_long = valid and valid_lower
enter_short = valid and valid_upper
if enter_long and self.Position <= 0:
self._entry_price = close
self._spike_size = lower_spike
self._is_long = True
self.BuyMarket(self.Volume + Math.Abs(self.Position))
elif enter_short and self.Position >= 0:
self._entry_price = close
self._spike_size = upper_spike
self._is_long = False
self.SellMarket(self.Volume + Math.Abs(self.Position))
if self.Position > 0 and self._is_long:
target = self._entry_price + self._spike_size * 2.0
if close >= target:
self.SellMarket(self.Position)
elif self.Position < 0 and not self._is_long:
target = self._entry_price - self._spike_size * 2.0
if close <= target:
self.BuyMarket(-self.Position)
def CreateClone(self):
return vrs_vegas_reversal_strategy()