PercentX Trendfolge-Strategie
Strategie abgeleitet von PercentX Trend Follower von Trendoscope.
Die Strategie normalisiert den Preisabstand von einem ausgewählten Band (Keltner oder Bollinger) und handelt, wenn dieser Oszillator dynamische Extrembereiche kreuzt. ATR wird für die Stop-Platzierung verwendet.
Details
- Einstiegskriterien: Oszillator kreuzt oberhalb des oberen Bereichs für Long, unterhalb des unteren Bereichs für Short.
- Long/Short: Beide.
- Ausstiegskriterien: ATR-basierter Stop.
- Stops: Initialer ATR-Stop.
- Standardwerte:
BandType= KeltnerMaLength= 40LoopbackPeriod= 80OuterLoopback= 80UseInitialStop= trueAtrLength= 14TrendMultiplier= 1ReverseMultiplier= 3CandleType= TimeSpan.FromMinutes(5)
- Filter:
- Kategorie: Trend
- Richtung: Beide
- Indikatoren: BollingerBands, KeltnerChannels, ATR, Highest, Lowest
- Stops: ATR
- Komplexität: Mittel
- Zeitrahmen: Intraday (5m)
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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>
/// Percent-X trend follower using Bollinger Bands oscillator with ATR stops.
/// </summary>
public class PercentXTrendFollowerStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _reverseMultiplier;
private readonly StrategyParam<DataType> _candleType;
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
public decimal ReverseMultiplier { get => _reverseMultiplier.Value; set => _reverseMultiplier.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public PercentXTrendFollowerStrategy()
{
_maLength = Param(nameof(MaLength), 40);
_atrLength = Param(nameof(AtrLength), 14);
_reverseMultiplier = Param(nameof(ReverseMultiplier), 3m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fast = new ExponentialMovingAverage { Length = 14 };
var slow = new ExponentialMovingAverage { Length = MaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var prevF = 0m;
var prevS = 0m;
var init = false;
var lastSignal = DateTimeOffset.MinValue;
var cooldown = TimeSpan.FromMinutes(600);
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(fast, slow, atr, (candle, fVal, sVal, atrVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!fast.IsFormed || !slow.IsFormed || !atr.IsFormed)
return;
var f = fVal.IsFormed ? fVal.ToDecimal() : 0m;
var s = sVal.IsFormed ? sVal.ToDecimal() : 0m;
if (!init)
{
prevF = f;
prevS = s;
init = true;
return;
}
if (candle.OpenTime - lastSignal >= cooldown)
{
if (prevF <= prevS && f > s && Position <= 0)
{
BuyMarket();
lastSignal = candle.OpenTime;
}
else if (prevF >= prevS && f < s && Position >= 0)
{
SellMarket();
lastSignal = candle.OpenTime;
}
}
prevF = f;
prevS = s;
}).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
}
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class percent_x_trend_follower_strategy(Strategy):
def __init__(self):
super(percent_x_trend_follower_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 40)
self._atr_length = self.Param("AtrLength", 14)
self._reverse_multiplier = self.Param("ReverseMultiplier", 3.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(percent_x_trend_follower_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
def OnStarted2(self, time):
super(percent_x_trend_follower_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._initialized = False
self._last_signal_ticks = 0
self._fast = ExponentialMovingAverage()
self._fast.Length = 14
self._slow = ExponentialMovingAverage()
self._slow.Length = self._ma_length.Value
self._atr = AverageTrueRange()
self._atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._fast, self._slow, self._atr, self.OnProcess).Start()
def OnProcess(self, candle, f_val, s_val, atr_val):
if candle.State != CandleStates.Finished:
return
if not self._fast.IsFormed or not self._slow.IsFormed or not self._atr.IsFormed:
return
fv = float(f_val) if f_val.IsFormed else 0.0
sv = float(s_val) if s_val.IsFormed else 0.0
if not self._initialized:
self._prev_fast = fv
self._prev_slow = sv
self._initialized = True
return
cooldown_ticks = TimeSpan.FromMinutes(600).Ticks
current_ticks = candle.OpenTime.Ticks
if current_ticks - self._last_signal_ticks >= cooldown_ticks:
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
self._last_signal_ticks = current_ticks
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._last_signal_ticks = current_ticks
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return percent_x_trend_follower_strategy()