Die Pearson's R-Oszillator-Strategie sucht dynamisch nach dem Zeitraum, in dem der Preis am besten in einen linearen Regressionskanal passt, indem der Pearson-Korrelationskoeffizient verwendet wird. Wenn die Korrelation den angegebenen positiven oder negativen Schwellenwert erreicht, bildet die Strategie einen Regressionskanal und handelt Ausbrüche.
Positionen werden eröffnet, wenn der Preis die Kanalgrenzen kreuzt, und können bei Mittellinienkreuzungen geschlossen werden. Der Ansatz passt sich den Marktbedingungen an, indem das Analysefenster automatisch auf die stärkste Korrelation eingestellt wird.
Details
Einstiegskriterien:
Preis kreuzt über die obere Regressionslinie → Long.
Preis kreuzt unter die untere Regressionslinie → Short.
Long/Short: Beide Seiten.
Ausstiegskriterien:
Mittellinienkreuzung in entgegengesetzter Richtung.
Stops: Keine.
Standardwerte:
MinPeriod = 48
MaxPeriod = 360
Step = 12
IdealPositive = 0.85
IdealNegative = -0.85
Deviations = 2
Filter:
Kategorie: Trendfolge
Richtung: Beide
Indikatoren: Pearson's R, Lineare Regression
Stops: Keine
Komplexität: Moderat
Zeitrahmen: Beliebig
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>
/// Pearson's R Oscillator strategy.
/// Uses linear regression channel crossover for entries with EMA trend filter.
/// </summary>
public class PearsonsROscillatorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevRsi;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// EMA trend filter period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public PearsonsROscillatorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_emaLength = Param(nameof(EmaLength), 40)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 350)
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = 0;
_barIndex = 0;
_lastTradeBar = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;
// RSI crosses above oversold with uptrend
var longSignal = _prevRsi > 0 && _prevRsi < 45 && rsiValue >= 45 && candle.ClosePrice > emaValue;
// RSI crosses below overbought with downtrend
var shortSignal = _prevRsi > 0 && _prevRsi > 55 && rsiValue <= 55 && candle.ClosePrice < emaValue;
if (longSignal && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (shortSignal && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevRsi = rsiValue;
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class pearsons_r_oscillator_strategy(Strategy):
def __init__(self):
super(pearsons_r_oscillator_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._ema_length = self.Param("EmaLength", 40) \
.SetGreaterThanZero() \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetGreaterThanZero() \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 350) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading")
self._prev_rsi = 0.0
self._bar_index = 0
self._last_trade_bar = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
@cooldown_bars.setter
def cooldown_bars(self, value):
self._cooldown_bars.Value = value
def OnReseted(self):
super(pearsons_r_oscillator_strategy, self).OnReseted()
self._prev_rsi = 0.0
self._bar_index = 0
self._last_trade_bar = 0
def OnStarted2(self, time):
super(pearsons_r_oscillator_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, rsi, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_val, rsi_val):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
ema_v = float(ema_val)
rsi_v = float(rsi_val)
close = float(candle.ClosePrice)
cooldown_ok = self._bar_index - self._last_trade_bar > self.cooldown_bars
long_signal = self._prev_rsi > 0 and self._prev_rsi < 45.0 and rsi_v >= 45.0 and close > ema_v
short_signal = self._prev_rsi > 0 and self._prev_rsi > 55.0 and rsi_v <= 55.0 and close < ema_v
if long_signal and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif short_signal and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_rsi = rsi_v
def CreateClone(self):
return pearsons_r_oscillator_strategy()