Стратегия Linear Regression (All Data)
Стратегия строит линию линейной регрессии по всем доступным барам и отображает её на графике. Также выводятся значения наклона, интерсепта и коэффициентов корреляции.
Детали
- Условия входа: нет.
- Лонг/Шорт: нет.
- Условия выхода: нет.
- Стопы: нет.
- Значения по умолчанию:
MaxBarsBack= 5000.CandleType= TimeSpan.FromMinutes(1).TimeFrame().
- Фильтры:
- Категория: Служебная
- Направление: нет
- Индикаторы: Linear Regression
- Стопы: нет
- Сложность: базовая
- Таймфрейм: любой
- Сезонность: нет
- Нейросети: нет
- Дивергенция: нет
- Уровень риска: низкий
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>
/// Linear Regression (All Data) strategy.
/// Calculates linear regression using all available bars and trades based on deviation from regression line.
/// </summary>
public class LinearRegressionAllDataStrategy : Strategy
{
private readonly StrategyParam<int> _maxBarsBack;
private readonly StrategyParam<decimal> _deviationThreshold;
private readonly StrategyParam<decimal> _exitThreshold;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private long _index;
private decimal _sumX;
private decimal _sumY;
private decimal _sumX2;
private decimal _sumXY;
private int _barsFromSignal;
public int MaxBarsBack { get => _maxBarsBack.Value; set => _maxBarsBack.Value = value; }
public decimal DeviationThreshold { get => _deviationThreshold.Value; set => _deviationThreshold.Value = value; }
public decimal ExitThreshold { get => _exitThreshold.Value; set => _exitThreshold.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LinearRegressionAllDataStrategy()
{
_maxBarsBack = Param(nameof(MaxBarsBack), 5000)
.SetGreaterThanZero()
.SetDisplay("Max Bars Back", "Maximum number of bars for drawing", "General");
_deviationThreshold = Param(nameof(DeviationThreshold), 0.008m)
.SetDisplay("Deviation Threshold", "Deviation from regression to trigger trade", "General");
_exitThreshold = Param(nameof(ExitThreshold), 0.002m)
.SetDisplay("Exit Threshold", "Deviation level to close a position", "General");
_cooldownBars = Param(nameof(CooldownBars), 8)
.SetGreaterThanZero()
.SetDisplay("Cooldown Bars", "Minimum bars between signals", "General");
_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();
_index = 0;
_sumX = 0m;
_sumY = 0m;
_sumX2 = 0m;
_sumXY = 0m;
_barsFromSignal = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_index = 0;
_sumX = 0m;
_sumY = 0m;
_sumX2 = 0m;
_sumXY = 0m;
_barsFromSignal = CooldownBars;
var dummyEma1 = new ExponentialMovingAverage { Length = 10 };
var dummyEma2 = new ExponentialMovingAverage { Length = 20 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(dummyEma1, dummyEma2, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal d1, decimal d2)
{
if (candle.State != CandleStates.Finished)
return;
_index++;
var x = (decimal)_index;
var y = candle.ClosePrice;
_sumX += x;
_sumY += y;
_sumX2 += x * x;
_sumXY += x * y;
if (_index < 20)
return;
var n = (decimal)_index;
var denom = n * _sumX2 - _sumX * _sumX;
if (denom == 0)
return;
var slope = (n * _sumXY - _sumX * _sumY) / denom;
var intercept = (_sumY - slope * _sumX) / n;
// Current predicted value from regression
var predicted = slope * x + intercept;
if (predicted == 0)
return;
// Deviation from regression line
var deviation = (candle.ClosePrice - predicted) / predicted;
_barsFromSignal++;
if (_barsFromSignal < CooldownBars)
return;
if (Position == 0)
{
if (deviation <= -DeviationThreshold)
{
BuyMarket();
_barsFromSignal = 0;
}
else if (deviation >= DeviationThreshold)
{
SellMarket();
_barsFromSignal = 0;
}
return;
}
if (Position > 0 && deviation >= -ExitThreshold)
{
SellMarket();
_barsFromSignal = 0;
}
else if (Position < 0 && deviation <= ExitThreshold)
{
BuyMarket();
_barsFromSignal = 0;
}
}
}
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
from StockSharp.Algo.Strategies import Strategy
class linear_regression_all_data_strategy(Strategy):
"""
Linear regression using all available bars. Trades based on
deviation from regression line as percentage of predicted value.
"""
def __init__(self):
super(linear_regression_all_data_strategy, self).__init__()
self._max_bars_back = self.Param("MaxBarsBack", 5000) \
.SetDisplay("Max Bars Back", "Maximum number of bars for drawing", "General")
self._deviation_threshold = self.Param("DeviationThreshold", 0.008) \
.SetDisplay("Deviation Threshold", "Deviation to trigger trade", "General")
self._exit_threshold = self.Param("ExitThreshold", 0.002) \
.SetDisplay("Exit Threshold", "Deviation to close position", "General")
self._cooldown_bars = self.Param("CooldownBars", 8) \
.SetDisplay("Cooldown Bars", "Min bars between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._index = 0
self._sum_x = 0.0
self._sum_y = 0.0
self._sum_x2 = 0.0
self._sum_xy = 0.0
self._bars_from_signal = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(linear_regression_all_data_strategy, self).OnReseted()
self._index = 0
self._sum_x = 0.0
self._sum_y = 0.0
self._sum_x2 = 0.0
self._sum_xy = 0.0
self._bars_from_signal = self._cooldown_bars.Value
def OnStarted2(self, time):
super(linear_regression_all_data_strategy, self).OnStarted2(time)
self._index = 0
self._sum_x = 0.0
self._sum_y = 0.0
self._sum_x2 = 0.0
self._sum_xy = 0.0
self._bars_from_signal = self._cooldown_bars.Value
dummy_ema1 = ExponentialMovingAverage()
dummy_ema1.Length = 10
dummy_ema2 = ExponentialMovingAverage()
dummy_ema2.Length = 20
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(dummy_ema1, dummy_ema2, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle, d1, d2):
if candle.State != CandleStates.Finished:
return
self._index += 1
x = float(self._index)
y = float(candle.ClosePrice)
self._sum_x += x
self._sum_y += y
self._sum_x2 += x * x
self._sum_xy += x * y
if self._index < 20:
return
n = float(self._index)
denom = n * self._sum_x2 - self._sum_x * self._sum_x
if denom == 0:
return
slope = (n * self._sum_xy - self._sum_x * self._sum_y) / denom
intercept = (self._sum_y - slope * self._sum_x) / n
predicted = slope * x + intercept
if predicted == 0:
return
deviation = (y - predicted) / predicted
self._bars_from_signal += 1
if self._bars_from_signal < self._cooldown_bars.Value:
return
dev_th = self._deviation_threshold.Value
exit_th = self._exit_threshold.Value
if self.Position == 0:
if deviation <= -dev_th:
self.BuyMarket()
self._bars_from_signal = 0
elif deviation >= dev_th:
self.SellMarket()
self._bars_from_signal = 0
return
if self.Position > 0 and deviation >= -exit_th:
self.SellMarket()
self._bars_from_signal = 0
elif self.Position < 0 and deviation <= exit_th:
self.BuyMarket()
self._bars_from_signal = 0
def CreateClone(self):
return linear_regression_all_data_strategy()