Eine Beispielstrategie, die zeigt, wie man mit Richtungswechseln eines geglätteten Medianpreises handelt. Der ursprüngliche MQL-Experte verwendete den Volatility Quality-Indikator; diese Implementierung nähert ihn mit einem einfachen gleitenden Durchschnitt des Medianpreises an.
Strategielogik
Den Medianpreis jeder Kerze (High + Low) / 2 berechnen.
Den Medianpreis mit einem einfachen gleitenden Durchschnitt (SMA) glätten.
Die Indikatorfarbe bestimmen: steigende Werte werden als auf (Farbe 0) und fallende Werte als ab (Farbe 1) behandelt.
Wenn die Farbe von auf nach ab wechselt, schließt die Strategie jede Short-Position und eröffnet eine Long-Position.
Wenn die Farbe von ab nach auf wechselt, schließt die Strategie jede Long-Position und eröffnet eine Short-Position.
Grundlegendes Risikomanagement wird über feste Stop-Loss- und Take-Profit-Niveaus angewendet.
Parameter
Name
Beschreibung
Length
Glättungsperiode für den SMA, angewendet auf den Medianpreis.
Candle Type
Zeitrahmen der für Berechnungen verwendeten Kerzen.
Haftungsausschluss
Dieses Beispiel dient zu Lehrzwecken. Es vereinfacht den ursprünglichen Algorithmus und kann sich anders verhalten als die MQL-Version. Verwendung auf eigenes Risiko.
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>
/// Volatility Quality strategy. Trades when smoothed median price slope changes direction.
/// </summary>
public class VolatilityQualityStrategy : Strategy
{
private readonly StrategyParam<int> _lengthParam;
private readonly StrategyParam<DataType> _candleTypeParam;
private ExponentialMovingAverage _sma;
private decimal _prevSma;
private int _prevColor;
/// <summary>
/// Smoothing period for median price.
/// </summary>
public int Length
{
get => _lengthParam.Value;
set => _lengthParam.Value = value;
}
/// <summary>
/// Candle type used for analysis.
/// </summary>
public DataType CandleType
{
get => _candleTypeParam.Value;
set => _candleTypeParam.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="VolatilityQualityStrategy"/> class.
/// </summary>
public VolatilityQualityStrategy()
{
_lengthParam = Param(nameof(Length), 5)
.SetGreaterThanZero()
.SetDisplay("Length", "Smoothing period for median price", "Parameters")
.SetOptimize(5, 30, 5);
_candleTypeParam = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "Common");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_prevSma = 0m;
_prevColor = -1;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicator for smoothed median price
_sma = new ExponentialMovingAverage { Length = Length };
// Subscribe to candle series and bind indicator
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, ProcessCandle)
.Start();
// Draw chart elements if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
// Basic position protection
StartProtection(
takeProfit: new Unit(2m, UnitTypes.Percent),
stopLoss: new Unit(1m, UnitTypes.Percent));
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
// Determine indicator color based on slope
int color;
if (_prevSma == 0m)
{
_prevSma = smaValue;
_prevColor = -1;
return;
}
if (smaValue > _prevSma)
color = 0; // rising line
else if (smaValue < _prevSma)
color = 1; // falling line
else
color = _prevColor; // unchanged
// Check for color change and trade accordingly
if (_prevColor == 1 && color == 0 && Position <= 0)
{
// Slope turned up - buy
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevColor == 0 && color == 1 && Position >= 0)
{
// Slope turned down - sell
if (Position > 0)
SellMarket();
SellMarket();
}
_prevSma = smaValue;
_prevColor = color;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class volatility_quality_strategy(Strategy):
def __init__(self):
super(volatility_quality_strategy, self).__init__()
self._length = self.Param("Length", 5) \
.SetDisplay("Length", "Smoothing period for median price", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for strategy", "Common")
self._sma = None
self._prev_sma = 0.0
self._prev_color = -1
@property
def length(self):
return self._length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(volatility_quality_strategy, self).OnReseted()
self._sma = None
self._prev_sma = 0.0
self._prev_color = -1
def OnStarted2(self, time):
super(volatility_quality_strategy, self).OnStarted2(time)
self._sma = ExponentialMovingAverage()
self._sma.Length = self.length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._sma, self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(2.0, UnitTypes.Percent),
stopLoss=Unit(1.0, UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._sma)
self.DrawOwnTrades(area)
def process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
sma_value = float(sma_value)
if self._prev_sma == 0.0:
self._prev_sma = sma_value
self._prev_color = -1
return
if sma_value > self._prev_sma:
color = 0 # rising
elif sma_value < self._prev_sma:
color = 1 # falling
else:
color = self._prev_color
# Slope turned up - buy
if self._prev_color == 1 and color == 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Slope turned down - sell
elif self._prev_color == 0 and color == 1 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_sma = sma_value
self._prev_color = color
def CreateClone(self):
return volatility_quality_strategy()