Inicio
/
Ejemplos de estrategias
Ver en GitHub
Estrategia de Sentimiento de Órdenes por Sesión
Descripción general
Esta estrategia opera basándose en el desequilibrio entre órdenes de compra y venta observadas en el libro de órdenes. Mide las proporciones de recuentos de órdenes y volúmenes totales para ambos lados del libro y abre una posición cuando el dominio de un lado supera los umbrales configurables. El trading solo está permitido durante una ventana de tiempo especificada.
Después de abrir una posición, los umbrales se reducen para monitorear el lado opuesto. Si el lado opuesto crece más allá de estos umbrales reducidos, la posición se cierra. También se aplican un stop loss y un take profit usando puntos de precio absolutos.
Reglas de trading
Entrada larga : Comprar cuando
BUY volume / SELL volume >= DiffVolumesEx y BUY orders / SELL orders >= DiffTradersEx
Cualquier lado cumple MinTraders y MinVolume
El tiempo actual pasa CheckTradingTime
Entrada corta : Vender cuando la lógica anterior se aplica en espejo para el lado vendedor.
Salida :
Cerrar el largo cuando SELL volume / BUY volume > 1 / DiffVolumes o SELL orders / BUY orders > 1 / DiffTraders
Cerrar el corto cuando SELL volume / BUY volume < DiffVolumes o SELL orders / BUY orders < DiffTraders
Cerrar todas las posiciones fuera del horario de trading
Stops : Usa Stop Loss y Take Profit medidos en puntos de precio.
Parámetros
MinVolume – volumen total mínimo requerido en cualquier lado del libro (por defecto: 20000)
MinTraders – número mínimo de órdenes en cualquier lado (por defecto: 1000)
DiffVolumesEx – ratio de volumen requerido para entrada (por defecto: 2.0)
DiffTradersEx – ratio de recuento de órdenes requerido para entrada (por defecto: 1.5)
MinDiffVolumesEx – ratio de volumen usado después de abrir posición (por defecto: 1.5)
MinDiffTradersEx – ratio de recuento de órdenes usado después de abrir posición (por defecto: 1.3)
SleepMinutes – retraso entre verificaciones del libro de órdenes en minutos (por defecto: 5)
TpPips – take profit en puntos de precio (por defecto: 500)
SlPips – stop loss en puntos de precio (por defecto: 500)
Notas
La estrategia no incluye una versión en Python.
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>
/// Strategy trading on volume sentiment using candle data.
/// Compares bullish vs bearish volume over a lookback period.
/// </summary>
public class SessionOrderSentimentStrategy : Strategy
{
private readonly StrategyParam<decimal> _volumeRatio;
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal vol, bool isBull)> _volumeHistory = new();
private decimal _entryPrice;
/// <summary>
/// Volume ratio required for entry.
/// </summary>
public decimal VolumeRatio
{
get => _volumeRatio.Value;
set => _volumeRatio.Value = value;
}
/// <summary>
/// Lookback period in candles.
/// </summary>
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
/// <summary>
/// Stop loss percentage.
/// </summary>
public decimal StopLossPct
{
get => _stopLossPct.Value;
set => _stopLossPct.Value = value;
}
/// <summary>
/// Candle type for processing.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="SessionOrderSentimentStrategy"/>.
/// </summary>
public SessionOrderSentimentStrategy()
{
_volumeRatio = Param(nameof(VolumeRatio), 1.5m)
.SetDisplay("Volume Ratio", "Bull/bear volume ratio for entry", "General")
.SetGreaterThanZero();
_lookback = Param(nameof(Lookback), 10)
.SetDisplay("Lookback", "Number of candles to look back", "General")
.SetGreaterThanZero();
_stopLossPct = Param(nameof(StopLossPct), 1m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for analysis", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var isBull = candle.ClosePrice >= candle.OpenPrice;
_volumeHistory.Add((candle.TotalVolume, isBull));
if (_volumeHistory.Count > Lookback)
_volumeHistory.RemoveAt(0);
if (_volumeHistory.Count < Lookback)
return;
var bullVolume = 0m;
var bearVolume = 0m;
foreach (var (vol, bull) in _volumeHistory)
{
if (bull)
bullVolume += vol;
else
bearVolume += vol;
}
if (bearVolume == 0) bearVolume = 1;
if (bullVolume == 0) bullVolume = 1;
var bullBearRatio = bullVolume / bearVolume;
var bearBullRatio = bearVolume / bullVolume;
var close = candle.ClosePrice;
// Check stop loss
if (Position > 0 && close <= _entryPrice * (1m - StopLossPct / 100m))
{
SellMarket();
return;
}
if (Position < 0 && close >= _entryPrice * (1m + StopLossPct / 100m))
{
BuyMarket();
return;
}
// Bullish sentiment
if (bullBearRatio >= VolumeRatio)
{
if (Position < 0)
{
BuyMarket();
}
if (Position <= 0)
{
_entryPrice = close;
BuyMarket();
}
}
// Bearish sentiment
else if (bearBullRatio >= VolumeRatio)
{
if (Position > 0)
{
SellMarket();
}
if (Position >= 0)
{
_entryPrice = close;
SellMarket();
}
}
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_volumeHistory.Clear();
_entryPrice = 0m;
}
}
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.Strategies import Strategy
class session_order_sentiment_strategy(Strategy):
def __init__(self):
super(session_order_sentiment_strategy, self).__init__()
self._volume_ratio = self.Param("VolumeRatio", 1.5) \
.SetDisplay("Volume Ratio", "Bull/bear volume ratio for entry", "General")
self._lookback = self.Param("Lookback", 10) \
.SetDisplay("Lookback", "Number of candles to look back", "General")
self._stop_loss_pct = self.Param("StopLossPct", 1.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._volume_history = []
self._entry_price = 0.0
@property
def volume_ratio(self):
return self._volume_ratio.Value
@property
def lookback(self):
return self._lookback.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(session_order_sentiment_strategy, self).OnReseted()
self._volume_history = []
self._entry_price = 0.0
def OnStarted2(self, time):
super(session_order_sentiment_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
is_bull = float(candle.ClosePrice) >= float(candle.OpenPrice)
vol = float(candle.TotalVolume)
lb = int(self.lookback)
self._volume_history.append((vol, is_bull))
if len(self._volume_history) > lb:
self._volume_history.pop(0)
if len(self._volume_history) < lb:
return
bull_volume = 0.0
bear_volume = 0.0
for v, b in self._volume_history:
if b:
bull_volume += v
else:
bear_volume += v
if bear_volume == 0:
bear_volume = 1.0
if bull_volume == 0:
bull_volume = 1.0
bull_bear_ratio = bull_volume / bear_volume
bear_bull_ratio = bear_volume / bull_volume
close = float(candle.ClosePrice)
sl = float(self.stop_loss_pct)
vr = float(self.volume_ratio)
# Check stop loss
if self.Position > 0 and close <= self._entry_price * (1.0 - sl / 100.0):
self.SellMarket()
return
if self.Position < 0 and close >= self._entry_price * (1.0 + sl / 100.0):
self.BuyMarket()
return
# Bullish sentiment
if bull_bear_ratio >= vr:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self._entry_price = close
self.BuyMarket()
# Bearish sentiment
elif bear_bull_ratio >= vr:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self._entry_price = close
self.SellMarket()
def CreateClone(self):
return session_order_sentiment_strategy()