Estrategia de Trampa de Volumen por Captura de Liquidez
Esta estrategia espera una captura de liquidez bajista en volumen plano que forma una brecha de valor razonable. Cuando el precio cierra por encima de la parte superior de la brecha mientras el volumen se mantiene cerca de su media móvil, coloca una orden limitada de compra en la parte inferior de la brecha con stop loss y take profit simétricos.
Detalles
- Condición de entrada:
Close[2] < Open[1]&&Close > High[1]&& ruptura bajista con volumen plano - Criterios de salida: stop loss a la altura de la brecha por debajo del fondo, take profit en
High[1] - Tipo: Reversión
- Indicadores: SMA de Volumen
- Marco temporal: 1 minuto (predeterminado)
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Liquidity Grab Strategy (Volume Trap).
/// Detects liquidity grabs where price sweeps beyond recent range
/// then reverses back, indicating a trap.
/// </summary>
public class LiquidityGrabVolumeTrapStrategy : Strategy
{
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private Highest _highest;
private Lowest _lowest;
private int _barsSinceSignal;
private decimal _prevHigh;
private decimal _prevLow;
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public LiquidityGrabVolumeTrapStrategy()
{
_lookback = Param(nameof(Lookback), 10)
.SetDisplay("Lookback", "Bars for range", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candles for calculations", "General");
_cooldownBars = Param(nameof(CooldownBars), 50)
.SetDisplay("Cooldown Bars", "Min bars between signals", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highest = new Highest { Length = Lookback };
_lowest = new Lowest { Length = Lookback };
_barsSinceSignal = 0;
_prevHigh = 0;
_prevLow = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_highest, _lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highest = null;
_lowest = null;
_barsSinceSignal = 0;
_prevHigh = 0;
_prevLow = 0;
}
private void ProcessCandle(ICandleMessage candle, decimal highVal, decimal lowVal)
{
if (candle.State != CandleStates.Finished)
return;
_barsSinceSignal++;
if (!_highest.IsFormed || !_lowest.IsFormed)
{
_prevHigh = highVal;
_prevLow = lowVal;
return;
}
// Use previous bar's range values
var rangeHigh = _prevHigh;
var rangeLow = _prevLow;
// Update previous values for next bar
_prevHigh = highVal;
_prevLow = lowVal;
// Bullish grab: wick swept below prior range low but closed back inside
var bullGrab = candle.LowPrice < rangeLow && candle.ClosePrice > rangeLow;
// Bearish grab: wick swept above prior range high but closed back inside
var bearGrab = candle.HighPrice > rangeHigh && candle.ClosePrice < rangeHigh;
// Cooldown check
if (_barsSinceSignal < CooldownBars)
return;
if (bullGrab && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_barsSinceSignal = 0;
}
else if (bearGrab && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_barsSinceSignal = 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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class liquidity_grab_volume_trap_strategy(Strategy):
"""
Detects liquidity grabs where price sweeps beyond recent range
then reverses back, indicating a trap.
"""
def __init__(self):
super(liquidity_grab_volume_trap_strategy, self).__init__()
self._lookback = self.Param("Lookback", 10) \
.SetDisplay("Lookback", "Bars for range", "General")
self._cooldown_bars = self.Param("CooldownBars", 50) \
.SetDisplay("Cooldown Bars", "Min bars between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candles for calculations", "General")
self._highest = None
self._lowest = None
self._bars_since_signal = 0
self._prev_high = 0.0
self._prev_low = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(liquidity_grab_volume_trap_strategy, self).OnReseted()
self._highest = None
self._lowest = None
self._bars_since_signal = 0
self._prev_high = 0.0
self._prev_low = 0.0
def OnStarted2(self, time):
super(liquidity_grab_volume_trap_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self._lookback.Value
self._lowest = Lowest()
self._lowest.Length = self._lookback.Value
self._bars_since_signal = 0
self._prev_high = 0.0
self._prev_low = 0.0
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._highest, self._lowest, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle, high_val, low_val):
if candle.State != CandleStates.Finished:
return
self._bars_since_signal += 1
hv = float(high_val)
lv = float(low_val)
if not self._highest.IsFormed or not self._lowest.IsFormed:
self._prev_high = hv
self._prev_low = lv
return
range_high = self._prev_high
range_low = self._prev_low
self._prev_high = hv
self._prev_low = lv
close = float(candle.ClosePrice)
low = float(candle.LowPrice)
high = float(candle.HighPrice)
bull_grab = low < range_low and close > range_low
bear_grab = high > range_high and close < range_high
if self._bars_since_signal < self._cooldown_bars.Value:
return
if bull_grab and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._bars_since_signal = 0
elif bear_grab and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._bars_since_signal = 0
def CreateClone(self):
return liquidity_grab_volume_trap_strategy()