強化版タイム・セグメンテッド・ボリューム戦略
強化版タイム・セグメンテッド・ボリュームは、出来高加重の価格変化を監視します。TSVが移動平均を上回りプラスの場合、戦略は買います。TSVが平均を下回りマイナスの場合、空売りします。
詳細
- エントリー条件: 移動平均に対するTSVの位置。
- ロング/ショート: 両方向。
- エグジット条件: 逆シグナルまたはストップ。
- ストップ: あり。
- デフォルト値:
TsvLength= 13MaLength= 7CandleType= TimeSpan.FromMinutes(5)
- フィルター:
- カテゴリ: モメンタム
- 方向: 両方
- インジケーター: 出来高, SMA
- ストップ: あり
- 複雑さ: 基本
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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()