Estrategia CoeffofLine True
Esta estrategia porta el experto MQL5 Exp_CoeffofLine_true.mq5 al framework StockSharp. Rastrea la Pendiente de Regresión Lineal de los precios medianos y reacciona a los cruces de cero.
Una posición larga se abre cuando la pendiente se vuelve positiva después de ser negativa. Una posición corta se abre cuando la pendiente se vuelve negativa después de ser positiva. Las posiciones existentes se cierran ante señales opuestas. Solo se procesan las velas completadas.
Parámetros
- Candle Type – marco temporal para la serie de velas.
- Slope Period – longitud de la regresión lineal utilizada para calcular la pendiente.
- Signal Bar – índice de barra histórica utilizado para la evaluación de señales.
- Buy Open / Sell Open – permisos para abrir posiciones largas o cortas.
- Buy Close / Sell Close – permisos para cerrar posiciones largas o cortas.
La estrategia se suscribe a las velas, vincula el indicador a través de la API de alto nivel y opera sin solicitudes manuales de valores del indicador.
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>
/// Strategy based on zero crossing of a smoothed slope proxy.
/// </summary>
public class CoeffofLineTrueStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _slopePeriod;
private readonly StrategyParam<int> _signalBar;
private readonly StrategyParam<bool> _buyOpen;
private readonly StrategyParam<bool> _sellOpen;
private readonly StrategyParam<bool> _buyClose;
private readonly StrategyParam<bool> _sellClose;
private readonly StrategyParam<int> _cooldownBars;
private readonly List<decimal> _slopes = [];
private ExponentialMovingAverage _slopeProxy = null!;
private decimal? _prevValue;
private int _cooldownRemaining;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int SlopePeriod { get => _slopePeriod.Value; set => _slopePeriod.Value = value; }
public int SignalBar { get => _signalBar.Value; set => _signalBar.Value = value; }
public bool BuyPosOpen { get => _buyOpen.Value; set => _buyOpen.Value = value; }
public bool SellPosOpen { get => _sellOpen.Value; set => _sellOpen.Value = value; }
public bool BuyPosClose { get => _buyClose.Value; set => _buyClose.Value = value; }
public bool SellPosClose { get => _sellClose.Value; set => _sellClose.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public CoeffofLineTrueStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for candles", "General");
_slopePeriod = Param(nameof(SlopePeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Slope Period", "Slope proxy length", "Parameters");
_signalBar = Param(nameof(SignalBar), 1)
.SetNotNegative()
.SetDisplay("Signal Bar", "Historical bar index for signal", "Parameters");
_buyOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Buy Open", "Allow opening long positions", "Trading");
_sellOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Sell Open", "Allow opening short positions", "Trading");
_buyClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Buy Close", "Allow closing long positions", "Trading");
_sellClose = Param(nameof(SellPosClose), true)
.SetDisplay("Sell Close", "Allow closing short positions", "Trading");
_cooldownBars = Param(nameof(CooldownBars), 4)
.SetDisplay("Cooldown Bars", "Completed candles to wait after a position change", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_slopes.Clear();
_slopeProxy = null!;
_prevValue = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(null, null);
_slopeProxy = new ExponentialMovingAverage { Length = SlopePeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_slopeProxy, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal proxyValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_cooldownRemaining > 0)
_cooldownRemaining--;
if (_prevValue is not decimal prevValue)
{
_prevValue = proxyValue;
return;
}
var slope = proxyValue - prevValue;
_prevValue = proxyValue;
_slopes.Add(slope);
if (_slopes.Count > SignalBar + 2)
_slopes.RemoveAt(0);
if (_slopes.Count <= SignalBar + 1)
return;
var prev = _slopes[^ (SignalBar + 1)];
var prev2 = _slopes[^ (SignalBar + 2)];
var buyOpen = BuyPosOpen && prev2 <= 0m && prev > 0m;
var sellOpen = SellPosOpen && prev2 >= 0m && prev < 0m;
var buyClose = BuyPosClose && prev2 >= 0m && prev < 0m;
var sellClose = SellPosClose && prev2 <= 0m && prev > 0m;
if (buyClose && Position > 0)
{
SellMarket();
_cooldownRemaining = CooldownBars;
}
if (sellClose && Position < 0)
{
BuyMarket();
_cooldownRemaining = CooldownBars;
}
if (_cooldownRemaining == 0 && buyOpen)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownBars;
}
if (_cooldownRemaining == 0 && sellOpen)
{
if (Position > 0)
SellMarket();
SellMarket();
_cooldownRemaining = CooldownBars;
}
}
}
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 coeffof_line_true_strategy(Strategy):
def __init__(self):
super(coeffof_line_true_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for candles", "General")
self._slope_period = self.Param("SlopePeriod", 5) \
.SetDisplay("Slope Period", "Slope proxy length", "Parameters")
self._signal_bar = self.Param("SignalBar", 1) \
.SetDisplay("Signal Bar", "Historical bar index for signal", "Parameters")
self._buy_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Buy Open", "Allow opening long positions", "Trading")
self._sell_open = self.Param("SellPosOpen", True) \
.SetDisplay("Sell Open", "Allow opening short positions", "Trading")
self._buy_close = self.Param("BuyPosClose", True) \
.SetDisplay("Buy Close", "Allow closing long positions", "Trading")
self._sell_close = self.Param("SellPosClose", True) \
.SetDisplay("Sell Close", "Allow closing short positions", "Trading")
self._cooldown_bars = self.Param("CooldownBars", 4) \
.SetDisplay("Cooldown Bars", "Completed candles to wait after a position change", "Trading")
self._slopes = []
self._prev_value = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
@property
def slope_period(self):
return self._slope_period.Value
@property
def signal_bar(self):
return self._signal_bar.Value
@property
def buy_open(self):
return self._buy_open.Value
@property
def sell_open(self):
return self._sell_open.Value
@property
def buy_close(self):
return self._buy_close.Value
@property
def sell_close(self):
return self._sell_close.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnReseted(self):
super(coeffof_line_true_strategy, self).OnReseted()
self._slopes = []
self._prev_value = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(coeffof_line_true_strategy, self).OnStarted2(time)
slope_proxy = ExponentialMovingAverage()
slope_proxy.Length = self.slope_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(slope_proxy, self.process_candle).Start()
def process_candle(self, candle, proxy_value):
if candle.State != CandleStates.Finished:
return
proxy_value = float(proxy_value)
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
if self._prev_value is None:
self._prev_value = proxy_value
return
slope = proxy_value - self._prev_value
self._prev_value = proxy_value
self._slopes.append(slope)
sb = self.signal_bar
if len(self._slopes) > sb + 2:
self._slopes.pop(0)
if len(self._slopes) <= sb + 1:
return
prev = self._slopes[-(sb + 1)]
prev2 = self._slopes[-(sb + 2)]
buy_open_sig = self.buy_open and prev2 <= 0 and prev > 0
sell_open_sig = self.sell_open and prev2 >= 0 and prev < 0
buy_close_sig = self.buy_close and prev2 >= 0 and prev < 0
sell_close_sig = self.sell_close and prev2 <= 0 and prev > 0
if buy_close_sig and self.Position > 0:
self.SellMarket()
self._cooldown_remaining = self.cooldown_bars
if sell_close_sig and self.Position < 0:
self.BuyMarket()
self._cooldown_remaining = self.cooldown_bars
if self._cooldown_remaining == 0 and buy_open_sig:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_bars
if self._cooldown_remaining == 0 and sell_open_sig:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_bars
def CreateClone(self):
return coeffof_line_true_strategy()