Volumen Segmentado por Tiempo Mejorado
El Volumen Segmentado por Tiempo Mejorado monitorea los cambios de precio ponderados por volumen. Cuando el TSV está por encima de su media móvil y es positivo, la estrategia compra. Cuando el TSV está por debajo del promedio y es negativo, vende en corto.
Detalles
- Criterios de entrada: TSV en relación con su media móvil.
- Largo/Corto: Ambas direcciones.
- Criterios de salida: Señal opuesta o stop.
- Stops: Sí.
- Valores predeterminados:
TsvLength= 13MaLength= 7CandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: Volumen, SMA
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Enhanced time segmented volume strategy.
/// TSV is the sum over TsvLength candles of the close change multiplied by the candle volume, and its SMA over MaLength is the
/// signal line. TSV above the signal line and above zero goes long, TSV below the signal line and below zero goes short; an
/// opposite signal reverses the position.
/// </summary>
public class EnhancedTimeSegmentedVolumeStrategy : Strategy
{
private readonly StrategyParam<int> _tsvLength;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _tsvSum;
private SimpleMovingAverage _tsvAverage;
private decimal? _prevClose;
/// <summary>
/// Number of candles summed into TSV.
/// </summary>
public int TsvLength
{
get => _tsvLength.Value;
set => _tsvLength.Value = value;
}
/// <summary>
/// Length of the TSV moving average.
/// </summary>
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public EnhancedTimeSegmentedVolumeStrategy()
{
_tsvLength = Param(nameof(TsvLength), 13)
.SetGreaterThanZero()
.SetDisplay("TSV Length", "Number of candles summed into TSV", "Indicators");
_maLength = Param(nameof(MaLength), 7)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Length of the TSV moving average", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
// The SMA times its length gives the rolling sum.
_tsvSum = new SimpleMovingAverage { Length = TsvLength };
_tsvAverage = new SimpleMovingAverage { Length = MaLength };
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 prevClose = _prevClose;
_prevClose = candle.ClosePrice;
if (prevClose is not decimal pc)
return;
var flow = (candle.ClosePrice - pc) * candle.TotalVolume;
var sumValue = _tsvSum.Process(new DecimalIndicatorValue(_tsvSum, flow, candle.OpenTime) { IsFinal = true });
if (!_tsvSum.IsFormed)
return;
var tsv = sumValue.GetValue<decimal>() * TsvLength;
var averageValue = _tsvAverage.Process(new DecimalIndicatorValue(_tsvAverage, tsv, candle.OpenTime) { IsFinal = true });
if (!_tsvAverage.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var average = averageValue.GetValue<decimal>();
if (tsv > average && tsv > 0m && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (tsv < average && tsv < 0m && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, DecimalIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class enhanced_time_segmented_volume_strategy(Strategy):
"""
Enhanced time segmented volume strategy.
TSV is the sum over TsvLength candles of the close change multiplied by the candle volume, and its SMA over MaLength is the
signal line. TSV above the signal line and above zero goes long, TSV below the signal line and below zero goes short; an
opposite signal reverses the position.
"""
def __init__(self):
super(enhanced_time_segmented_volume_strategy, self).__init__()
self._tsv_length = self.Param("TsvLength", 13).SetGreaterThanZero().SetDisplay("TSV Length", "Number of candles summed into TSV", "Indicators")
self._ma_length = self.Param("MaLength", 7).SetGreaterThanZero().SetDisplay("MA Length", "Length of the TSV moving average", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._tsv_sum = None
self._tsv_average = None
self._prev_close = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(enhanced_time_segmented_volume_strategy, self).OnReseted()
self._prev_close = None
def OnStarted2(self, time):
super(enhanced_time_segmented_volume_strategy, self).OnStarted2(time)
self._prev_close = None
# The SMA times its length gives the rolling sum.
self._tsv_sum = SimpleMovingAverage()
self._tsv_sum.Length = self._tsv_length.Value
self._tsv_average = SimpleMovingAverage()
self._tsv_average.Length = self._ma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
prev_close = self._prev_close
self._prev_close = close
if prev_close is None:
return
flow = (close - prev_close) * float(candle.TotalVolume)
sum_input = DecimalIndicatorValue(self._tsv_sum, Decimal(flow), candle.OpenTime)
sum_input.IsFinal = True
sum_value = self._tsv_sum.Process(sum_input)
if not self._tsv_sum.IsFormed:
return
tsv = float(sum_value.GetValue[Decimal](None)) * self._tsv_length.Value
average_input = DecimalIndicatorValue(self._tsv_average, Decimal(tsv), candle.OpenTime)
average_input.IsFinal = True
average_value = self._tsv_average.Process(average_input)
if not self._tsv_average.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
average = float(average_value.GetValue[Decimal](None))
if tsv > average and tsv > 0 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif tsv < average and tsv < 0 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return enhanced_time_segmented_volume_strategy()