Estrategia de Líneas de Tendencia Automáticas
Construye líneas de tendencia dinámicas de soporte y resistencia conectando los máximos y mínimos pivot recientes. Se genera una señal larga cuando el precio cierra por encima de la línea de resistencia, mientras que una señal corta se activa cuando el precio cae por debajo de la línea de soporte.
Detalles
- Criterios de entrada:
- Largo: El cierre cruza por encima de la línea de tendencia de resistencia.
- Corto: El cierre cruza por debajo de la línea de tendencia de soporte.
- Criterios de salida:
- Señal opuesta o reversión de posición.
- Indicadores:
- Líneas de tendencia basadas en pivots.
- Stops: Ninguno.
- Valores predeterminados:
LeftBars= 100RightBars= 15
- Filtros:
- Seguimiento de tendencia
- Marco temporal único
- Indicadores: líneas de tendencia pivot
- Stops: ninguno
- Complejidad: Bajo
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>
/// Automatic Trendlines Strategy.
/// Uses Highest/Lowest channel breakouts with EMA trend filter.
/// </summary>
public class AutomaticTrendlinesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevHighest;
private decimal _prevLowest;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Channel lookback length.
/// </summary>
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
/// <summary>
/// EMA trend filter period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public AutomaticTrendlinesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation", "General");
_channelLength = Param(nameof(ChannelLength), 30)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Lookback for Highest/Lowest", "Indicators");
_emaLength = Param(nameof(EmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter 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();
_prevHighest = 0;
_prevLowest = 0;
_barIndex = 0;
_lastTradeBar = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = ChannelLength };
var lowest = new Lowest { Length = ChannelLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal highestValue, decimal lowestValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
var cooldownOk = _barIndex - _lastTradeBar > CooldownBars;
// Breakout above resistance trendline with uptrend
var breakUp = _prevHighest > 0 && candle.ClosePrice > _prevHighest && candle.ClosePrice > emaValue;
// Breakdown below support trendline with downtrend
var breakDown = _prevLowest > 0 && candle.ClosePrice < _prevLowest && candle.ClosePrice < emaValue;
if (breakUp && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (breakDown && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevHighest = highestValue;
_prevLowest = lowestValue;
}
}
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 CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class automatic_trendlines_strategy(Strategy):
"""
Automatic Trendlines Strategy.
Uses Highest/Lowest channel breakouts with EMA trend filter.
"""
def __init__(self):
super(automatic_trendlines_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(1)) \
.SetDisplay("Candle type", "Candle type for strategy calculation", "General")
self._channel_length = self.Param("ChannelLength", 30) \
.SetGreaterThanZero() \
.SetDisplay("Channel Length", "Lookback for Highest/Lowest", "Indicators")
self._ema_length = self.Param("EmaLength", 50) \
.SetGreaterThanZero() \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 350) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Trading")
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._bar_index = 0
self._last_trade_bar = 0
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
@property
def ChannelLength(self): return self._channel_length.Value
@ChannelLength.setter
def ChannelLength(self, v): self._channel_length.Value = v
@property
def EmaLength(self): return self._ema_length.Value
@EmaLength.setter
def EmaLength(self, v): self._ema_length.Value = v
@property
def CooldownBars(self): return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, v): self._cooldown_bars.Value = v
def OnReseted(self):
super(automatic_trendlines_strategy, self).OnReseted()
self._prev_highest = 0.0
self._prev_lowest = 0.0
self._bar_index = 0
self._last_trade_bar = 0
def OnStarted2(self, time):
super(automatic_trendlines_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self.ChannelLength
lowest = Lowest()
lowest.Length = self.ChannelLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, ema, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, highest_value, lowest_value, ema_value):
if candle.State != CandleStates.Finished:
return
self._bar_index += 1
cooldown_ok = self._bar_index - self._last_trade_bar > self.CooldownBars
close = float(candle.ClosePrice)
break_up = self._prev_highest > 0 and close > self._prev_highest and close > ema_value
break_down = self._prev_lowest > 0 and close < self._prev_lowest and close < ema_value
if break_up and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif break_down and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_highest = highest_value
self._prev_lowest = lowest_value
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return automatic_trendlines_strategy()