Strategie Volume Supertrend
Diese Strategie verwendet Volume Supertrend Indikatoren zur Signalgenerierung. Ein Long-Einstieg erfolgt, wenn Volume > Avg(Volume) && Price > Supertrend (Volumenanstieg mit Aufwärtstrend). Ein Short-Einstieg erfolgt, wenn Volume > Avg(Volume) && Price < Supertrend (Volumenanstieg mit Abwärtstrend). Sie eignet sich für Trader, die Chancen in Trendmärkten suchen.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 64%. Sie funktioniert am besten auf dem Devisenmarkt.
Details
- Einstiegskriterien:
- Long: Volume > Avg(Volume) && Price > Supertrend (volume surge with uptrend)
- Short: Volume > Avg(Volume) && Price < Supertrend (volume surge with downtrend)
- Long/Short: Beide Seiten.
- Ausstiegskriterien:
- Long: Long-Position schließen, wenn Supertrend nach unten dreht
- Short: Short-Position schließen, wenn Supertrend nach oben dreht
- Stops: Ja.
- Standardwerte:
VolumeAvgPeriod= 20SupertrendPeriod= 10SupertrendMultiplier= 3CandleType= TimeSpan.FromMinutes(5)StopLossPercent= 2 Avg(Volume) ist das durchschnittliche Volumen der vorherigen VolumeAvgPeriod Kerzen. Ein Long schließt, sobald der Supertrend nach unten dreht, ein Short, sobald er nach oben dreht; der Stop liegt bei festen StopLossPercent vom Einstiegspreis und wird auch zwischen den Kerzen überwacht. Ein Einstiegssignal gegen eine offene Position dreht sie.
- Filter:
- Kategorie: Trend
- Richtung: Beide
- Indikatoren: Volume Supertrend
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
using System;
using System.Collections.Generic;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Volume Supertrend strategy.
/// A close above the Supertrend line on volume above the average of the previous VolumeAvgPeriod candles goes long and a close below it
/// on such volume goes short, reversing an opposite position. A long closes once the Supertrend turns down and a short once it turns up,
/// and a percent stop limits the loss.
/// </summary>
public class VolumeSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _volumeAvgPeriod;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _volumes = [];
/// <summary>
/// Previous candles the volume is averaged over.
/// </summary>
public int VolumeAvgPeriod
{
get => _volumeAvgPeriod.Value;
set => _volumeAvgPeriod.Value = value;
}
/// <summary>
/// ATR period of Supertrend.
/// </summary>
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
/// <summary>
/// ATR multiplier of Supertrend.
/// </summary>
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public VolumeSupertrendStrategy()
{
_volumeAvgPeriod = Param(nameof(VolumeAvgPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Volume Avg Period", "Previous candles the volume is averaged over", "Volume");
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Supertrend Period", "ATR period of Supertrend", "Supertrend");
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3m)
.SetGreaterThanZero()
.SetDisplay("Supertrend Multiplier", "ATR multiplier of Supertrend", "Supertrend");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_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();
_volumes.Clear();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_volumes.Clear();
var supertrend = new SuperTrend { Length = SupertrendPeriod, Multiplier = SupertrendMultiplier };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(supertrend, ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, supertrend);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue supertrendValue)
{
if (candle.State != CandleStates.Finished)
return;
// Volume is compared with the candles before this one.
var average = _volumes.Count == VolumeAvgPeriod ? _volumes.Average() : (decimal?)null;
_volumes.Add(candle.TotalVolume);
if (_volumes.Count > VolumeAvgPeriod)
_volumes.RemoveAt(0);
if (!supertrendValue.IsFormed || supertrendValue is not SuperTrendIndicatorValue value || average is not decimal avgVolume)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var line = value.Value;
var close = candle.ClosePrice;
var surge = candle.TotalVolume > avgVolume;
if (surge && close > line && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (surge && close < line && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && !value.IsUpTrend)
SellMarket(Position);
else if (Position < 0 && value.IsUpTrend)
BuyMarket(-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, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Indicators import SuperTrend
from StockSharp.Algo.Strategies import Strategy
class volume_supertrend_strategy(Strategy):
"""
Volume Supertrend strategy.
A close above the Supertrend line on volume above the average of the previous VolumeAvgPeriod candles goes long and a close below it
on such volume goes short, reversing an opposite position. A long closes once the Supertrend turns down and a short once it turns up,
and a percent stop limits the loss.
"""
def __init__(self):
super(volume_supertrend_strategy, self).__init__()
self._volume_avg_period = self.Param("VolumeAvgPeriod", 20).SetGreaterThanZero().SetDisplay("Volume Avg Period", "Previous candles the volume is averaged over", "Volume")
self._supertrend_period = self.Param("SupertrendPeriod", 10).SetGreaterThanZero().SetDisplay("Supertrend Period", "ATR period of Supertrend", "Supertrend")
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 3.0).SetGreaterThanZero().SetDisplay("Supertrend Multiplier", "ATR multiplier of Supertrend", "Supertrend")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._volumes = []
def OnReseted(self):
super(volume_supertrend_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(volume_supertrend_strategy, self).OnStarted2(time)
self._reset_state()
supertrend = SuperTrend()
supertrend.Length = self._supertrend_period.Value
supertrend.Multiplier = Decimal(self._supertrend_multiplier.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(supertrend, self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, supertrend)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle, supertrend_value):
if candle.State != CandleStates.Finished:
return
# Volume is compared with the candles before this one.
period = self._volume_avg_period.Value
average = None
if len(self._volumes) == period:
total = Decimal(0)
for volume in self._volumes:
total += volume
average = total / Decimal(period)
self._volumes.append(candle.TotalVolume)
if len(self._volumes) > period:
self._volumes.pop(0)
if not supertrend_value.IsFormed or average is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
line = supertrend_value.Value
close = candle.ClosePrice
surge = candle.TotalVolume > average
if surge and close > line and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif surge and close < line and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and not supertrend_value.IsUpTrend:
self.SellMarket(self.Position)
elif self.Position < 0 and supertrend_value.IsUpTrend:
self.BuyMarket(-self.Position)
def CreateClone(self):
return volume_supertrend_strategy()