Estrategia Extrem N
La estrategia Extrem N opera reversiones basadas en nuevos máximos y mínimos detectados en una ventana deslizante.
La estrategia se basa en el indicador de Canal de Donchian para marcar los extremos de precio. Cuando una barra establece un nuevo máximo relativo al período de retrospección y la siguiente barra establece un nuevo mínimo, se abre una posición larga. Se abre una posición corta cuando un nuevo mínimo es seguido por un nuevo máximo. Las señales opuestas cierran las posiciones existentes.
- Condiciones de entrada:
- Largo: la barra anterior estableció un nuevo máximo y la barra actual estableció un nuevo mínimo.
- Corto: la barra anterior estableció un nuevo mínimo y la barra actual estableció un nuevo máximo.
- Condiciones de salida:
- Las posiciones largas se cierran con una señal de entrada corta.
- Las posiciones cortas se cierran con una señal de entrada larga.
- Parámetros:
Period– período de retrospección de Donchian (por defecto 9).CandleType– marco temporal de procesamiento (por defecto 4 horas).BuyPosOpen– permitir abrir posiciones largas (por defecto true).SellPosOpen– permitir abrir posiciones cortas (por defecto true).BuyPosClose– permitir cerrar posiciones largas (por defecto true).SellPosClose– permitir cerrar posiciones cortas (por defecto true).
- Indicadores: Canal de Donchian.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy trading reversals after alternating price extremes.
/// </summary>
public class ExtremNStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosClose;
private decimal _prevUpper;
private decimal _prevLower;
private bool _upPrev;
private bool _dnPrev;
private bool _upPrev2;
private bool _dnPrev2;
private bool _isFirst;
/// <summary>
/// Donchian lookback period.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// Candle type to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Enable opening long positions.
/// </summary>
public bool BuyPosOpen
{
get => _buyPosOpen.Value;
set => _buyPosOpen.Value = value;
}
/// <summary>
/// Enable opening short positions.
/// </summary>
public bool SellPosOpen
{
get => _sellPosOpen.Value;
set => _sellPosOpen.Value = value;
}
/// <summary>
/// Enable closing long positions.
/// </summary>
public bool BuyPosClose
{
get => _buyPosClose.Value;
set => _buyPosClose.Value = value;
}
/// <summary>
/// Enable closing short positions.
/// </summary>
public bool SellPosClose
{
get => _sellPosClose.Value;
set => _sellPosClose.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExtremNStrategy"/>.
/// </summary>
public ExtremNStrategy()
{
_period = Param(nameof(Period), 9)
.SetDisplay("Period", "Donchian lookback period", "General")
.SetOptimize(5, 30, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Buy Open", "Allow long entries", "Trading");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Sell Open", "Allow short entries", "Trading");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Buy Close", "Allow closing longs", "Trading");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Sell Close", "Allow closing shorts", "Trading");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevUpper = default;
_prevLower = default;
_upPrev = default;
_dnPrev = default;
_upPrev2 = default;
_dnPrev2 = default;
_isFirst = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var donchian = new DonchianChannels
{
Length = Period
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(donchian, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, donchian);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var dc = (IDonchianChannelsValue)value;
if (dc.UpperBand is not decimal upper || dc.LowerBand is not decimal lower)
return;
if (!_isFirst)
{
_prevUpper = upper;
_prevLower = lower;
_isFirst = true;
return;
}
var up = candle.HighPrice > _prevUpper;
var dn = candle.LowPrice < _prevLower;
if (_upPrev2 && !_dnPrev2)
{
if (SellPosClose && Position < 0)
BuyMarket();
if (BuyPosOpen && dn && Position <= 0)
BuyMarket();
}
else if (!_upPrev2 && _dnPrev2)
{
if (BuyPosClose && Position > 0)
SellMarket();
if (SellPosOpen && up && Position >= 0)
SellMarket();
}
_upPrev2 = _upPrev;
_dnPrev2 = _dnPrev;
_upPrev = up;
_dnPrev = dn;
_prevUpper = upper;
_prevLower = lower;
}
}
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 DonchianChannels
from StockSharp.Algo.Strategies import Strategy
class extrem_n_strategy(Strategy):
def __init__(self):
super(extrem_n_strategy, self).__init__()
self._period = self.Param("Period", 9).SetDisplay("Period", "Donchian lookback period", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Timeframe", "General")
self._buy_pos_open = self.Param("BuyPosOpen", True).SetDisplay("Buy Open", "Allow long entries", "Trading")
self._sell_pos_open = self.Param("SellPosOpen", True).SetDisplay("Sell Open", "Allow short entries", "Trading")
self._buy_pos_close = self.Param("BuyPosClose", True).SetDisplay("Buy Close", "Allow closing longs", "Trading")
self._sell_pos_close = self.Param("SellPosClose", True).SetDisplay("Sell Close", "Allow closing shorts", "Trading")
self._prev_upper = 0.0
self._prev_lower = 0.0
self._up_prev = False
self._dn_prev = False
self._up_prev2 = False
self._dn_prev2 = False
self._is_first = False
@property
def period(self): return self._period.Value
@property
def candle_type(self): return self._candle_type.Value
@property
def buy_pos_open(self): return self._buy_pos_open.Value
@property
def sell_pos_open(self): return self._sell_pos_open.Value
@property
def buy_pos_close(self): return self._buy_pos_close.Value
@property
def sell_pos_close(self): return self._sell_pos_close.Value
def OnReseted(self):
super(extrem_n_strategy, self).OnReseted()
self._prev_upper = 0.0
self._prev_lower = 0.0
self._up_prev = False
self._dn_prev = False
self._up_prev2 = False
self._dn_prev2 = False
self._is_first = False
def OnStarted2(self, time):
super(extrem_n_strategy, self).OnStarted2(time)
donchian = DonchianChannels()
donchian.Length = self.period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(donchian, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, donchian)
self.DrawOwnTrades(area)
def process_candle(self, candle, value):
if candle.State != CandleStates.Finished: return
if not self.IsFormedAndOnlineAndAllowTrading(): return
upper = value.UpperBand
lower = value.LowerBand
if upper is None or lower is None: return
upper = float(upper)
lower = float(lower)
if not self._is_first:
self._prev_upper = upper
self._prev_lower = lower
self._is_first = True
return
up = float(candle.HighPrice) > self._prev_upper
dn = float(candle.LowPrice) < self._prev_lower
if self._up_prev2 and not self._dn_prev2:
if self.sell_pos_close and self.Position < 0:
self.BuyMarket()
if self.buy_pos_open and dn and self.Position <= 0:
self.BuyMarket()
elif not self._up_prev2 and self._dn_prev2:
if self.buy_pos_close and self.Position > 0:
self.SellMarket()
if self.sell_pos_open and up and self.Position >= 0:
self.SellMarket()
self._up_prev2 = self._up_prev
self._dn_prev2 = self._dn_prev
self._up_prev = up
self._dn_prev = dn
self._prev_upper = upper
self._prev_lower = lower
def CreateClone(self): return extrem_n_strategy()