Strategie Parabolic Sar Volume
Strategie, die Parabolic SAR mit Volumenbestätigung kombiniert. Einstieg in Trades, wenn der Preis den Parabolic SAR bei überdurchschnittlichem Volumen kreuzt.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 151%. Sie funktioniert am besten auf dem Aktienmarkt.
Parabolic SAR identifiziert Trendwechsel und höheres Volumen validiert das Signal. Trades beginnen, wenn der SAR-Wechsel mit zunehmendem Volumen einhergeht.
Nützlich für Trader, die volumenbasierte Bewegungen verfolgen. Der SAR-Trail und ein ATR-Faktor schützen vor großen Verlusten.
Details
- Einstiegskriterien:
- Long:
Close > SAR && Volume > AvgVolume - Short:
Close < SAR && Volume > AvgVolume
- Long:
- Long/Short: Beide
- Ausstiegskriterien: SAR-Wechsel
- Stops: Verwendet Parabolic SAR als Trailing Stop
- Standardwerte:
Acceleration= 0.02mMaxAcceleration= 0.2mVolumePeriod= 20CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filter:
- Kategorie: Ausbruch
- Richtung: Beide
- Indikatoren: Parabolic SAR, Parabolic SAR, Volumen
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Mittelfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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 that combines Parabolic SAR with volume confirmation.
/// Enters trades when price crosses the Parabolic SAR with above-average volume.
/// </summary>
public class ParabolicSarVolumeStrategy : Strategy
{
private readonly StrategyParam<decimal> _acceleration;
private readonly StrategyParam<decimal> _maxAcceleration;
private readonly StrategyParam<int> _volumePeriod;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private ParabolicSar _parabolicSar;
private VolumeIndicator _volumeIndicator;
private SimpleMovingAverage _volumeAverage;
private decimal _prevSar;
private decimal _currentAvgVolume;
private bool _prevPriceAboveSar;
private int _cooldown;
/// <summary>
/// Parabolic SAR acceleration factor.
/// </summary>
public decimal Acceleration
{
get => _acceleration.Value;
set => _acceleration.Value = value;
}
/// <summary>
/// Parabolic SAR maximum acceleration factor.
/// </summary>
public decimal MaxAcceleration
{
get => _maxAcceleration.Value;
set => _maxAcceleration.Value = value;
}
/// <summary>
/// Period for volume moving average.
/// </summary>
public int VolumePeriod
{
get => _volumePeriod.Value;
set => _volumePeriod.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="ParabolicSarVolumeStrategy"/>.
/// </summary>
public ParabolicSarVolumeStrategy()
{
_acceleration = Param(nameof(Acceleration), 0.02m)
.SetRange(0.01m, 0.1m)
.SetDisplay("SAR Acceleration", "Starting acceleration factor", "Indicators");
_maxAcceleration = Param(nameof(MaxAcceleration), 0.2m)
.SetRange(0.1m, 0.5m)
.SetDisplay("SAR Max Acceleration", "Maximum acceleration factor", "Indicators");
_volumePeriod = Param(nameof(VolumePeriod), 20)
.SetRange(10, 50)
.SetDisplay("Volume Period", "Period for volume moving average", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 30)
.SetRange(1, 100)
.SetDisplay("Cooldown Bars", "Bars between entries", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
_prevSar = 0;
_currentAvgVolume = 0;
_prevPriceAboveSar = false;
_cooldown = 0;
_parabolicSar = null;
_volumeIndicator = null;
_volumeAverage = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Initialize indicators
_parabolicSar = new ParabolicSar
{
Acceleration = Acceleration,
AccelerationMax = MaxAcceleration
};
_volumeIndicator = new VolumeIndicator();
_volumeAverage = new SMA
{
Length = VolumePeriod
};
// Create candle subscription
var subscription = SubscribeCandles(CandleType);
// Binding for Parabolic SAR indicator
subscription
.Bind(_parabolicSar, _volumeIndicator, ProcessIndicators)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _parabolicSar);
var volumeArea = CreateChartArea();
if (volumeArea != null)
{
DrawIndicator(volumeArea, _volumeIndicator);
DrawIndicator(volumeArea, _volumeAverage);
}
DrawOwnTrades(area);
}
}
private void ProcessIndicators(ICandleMessage candle, decimal sarValue, decimal volumeValue)
{
var avgValue = _volumeAverage.Process(new DecimalIndicatorValue(_volumeAverage, volumeValue, candle.ServerTime));
if (avgValue == null)
return;
_currentAvgVolume = avgValue.ToDecimal();
if (_currentAvgVolume <= 0)
return;
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Wait until strategy and indicators are ready
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Get current price and volume
var currentPrice = candle.ClosePrice;
var currentVolume = candle.TotalVolume;
var isPriceAboveSar = currentPrice > sarValue;
// Determine if volume is above average
var isHighVolume = currentVolume > _currentAvgVolume * 1.5m;
if (_cooldown > 0)
{
_cooldown--;
_prevSar = sarValue;
_prevPriceAboveSar = isPriceAboveSar;
return;
}
// Check for SAR crossover with volume confirmation
// Bullish crossover: Price crosses above SAR with high volume
if (isPriceAboveSar && !_prevPriceAboveSar && isHighVolume && Position <= 0)
{
CancelActiveOrders();
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = CooldownBars;
}
// Bearish crossover: Price crosses below SAR with high volume
else if (!isPriceAboveSar && _prevPriceAboveSar && isHighVolume && Position >= 0)
{
CancelActiveOrders();
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = CooldownBars;
}
// Exit signals based on SAR crossover (without volume confirmation)
else if ((Position > 0 && !isPriceAboveSar) || (Position < 0 && isPriceAboveSar))
{
ClosePosition();
_cooldown = CooldownBars;
}
// Update previous values for next candle
_prevSar = sarValue;
_prevPriceAboveSar = isPriceAboveSar;
}
}
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 ParabolicSar, VolumeIndicator, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class parabolic_sar_volume_strategy(Strategy):
"""
Strategy that combines Parabolic SAR with volume confirmation.
"""
def __init__(self):
super(parabolic_sar_volume_strategy, self).__init__()
self._acceleration = self.Param("Acceleration", 0.02) \
.SetRange(0.01, 0.1) \
.SetDisplay("SAR Acceleration", "Starting acceleration factor", "Indicators")
self._maxAcceleration = self.Param("MaxAcceleration", 0.2) \
.SetRange(0.1, 0.5) \
.SetDisplay("SAR Max Acceleration", "Maximum acceleration factor", "Indicators")
self._volumePeriod = self.Param("VolumePeriod", 20) \
.SetRange(10, 50) \
.SetDisplay("Volume Period", "Period for volume moving average", "Indicators")
self._cooldownBars = self.Param("CooldownBars", 30) \
.SetRange(1, 100) \
.SetDisplay("Cooldown Bars", "Bars between entries", "General")
self._candleType = self.Param("CandleType", tf(15)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._parabolicSar = None
self._volumeIndicator = None
self._volumeAverage = None
self._prevSar = 0.0
self._currentAvgVolume = 0.0
self._prevPriceAboveSar = False
self._cooldown = 0
@property
def CandleType(self):
return self._candleType.Value
def OnStarted2(self, time):
super(parabolic_sar_volume_strategy, self).OnStarted2(time)
self._prevSar = 0.0
self._currentAvgVolume = 0.0
self._prevPriceAboveSar = False
self._cooldown = 0
self._parabolicSar = ParabolicSar()
self._parabolicSar.Acceleration = self._acceleration.Value
self._parabolicSar.AccelerationMax = self._maxAcceleration.Value
self._volumeIndicator = VolumeIndicator()
self._volumeAverage = SimpleMovingAverage()
self._volumeAverage.Length = self._volumePeriod.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._parabolicSar, self._volumeIndicator, self.ProcessIndicators).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._parabolicSar)
volumeArea = self.CreateChartArea()
if volumeArea is not None:
self.DrawIndicator(volumeArea, self._volumeIndicator)
self.DrawIndicator(volumeArea, self._volumeAverage)
self.DrawOwnTrades(area)
def OnReseted(self):
super(parabolic_sar_volume_strategy, self).OnReseted()
self._prevSar = 0.0
self._currentAvgVolume = 0.0
self._prevPriceAboveSar = False
self._cooldown = 0
self._parabolicSar = None
self._volumeIndicator = None
self._volumeAverage = None
def ProcessIndicators(self, candle, sarValue, volumeValue):
# Process volume average
avgResult = process_float(self._volumeAverage, volumeValue, candle.ServerTime, True)
if avgResult is None:
return
self._currentAvgVolume = float(avgResult)
if self._currentAvgVolume <= 0:
return
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
currentPrice = float(candle.ClosePrice)
currentVolume = float(candle.TotalVolume)
isPriceAboveSar = currentPrice > float(sarValue)
# Volume must be 1.5x above average
isHighVolume = currentVolume > self._currentAvgVolume * 1.5
if self._cooldown > 0:
self._cooldown -= 1
self._prevSar = float(sarValue)
self._prevPriceAboveSar = isPriceAboveSar
return
cooldown = int(self._cooldownBars.Value)
# Bullish crossover
if isPriceAboveSar and not self._prevPriceAboveSar and isHighVolume and self.Position <= 0:
self.CancelActiveOrders()
volume = self.Volume + abs(self.Position)
self.BuyMarket(volume)
self._cooldown = cooldown
# Bearish crossover
elif not isPriceAboveSar and self._prevPriceAboveSar and isHighVolume and self.Position >= 0:
self.CancelActiveOrders()
volume = self.Volume + abs(self.Position)
self.SellMarket(volume)
self._cooldown = cooldown
# Exit signals
elif (self.Position > 0 and not isPriceAboveSar) or (self.Position < 0 and isPriceAboveSar):
self.ClosePosition()
self._cooldown = cooldown
self._prevSar = float(sarValue)
self._prevPriceAboveSar = isPriceAboveSar
def CreateClone(self):
return parabolic_sar_volume_strategy()