Estratégia de Pesquisa Donchian Quest
Esta estratégia usa dois canais Donchian com comprimentos diferentes. Um rompimento acima da banda superior do canal mais longo abre uma posição comprada, enquanto um rompimento abaixo da banda inferior abre uma posição vendida. As posições são fechadas quando o preço toca a banda oposta do canal mais curto.
Parâmetros
OpenPeriod= 50ClosePeriod= 50
Indicadores
- Canal Donchian
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>
/// Donchian Quest Research strategy.
/// A close above the upper band of the OpenPeriod Donchian channel goes long and a close below its lower band goes short,
/// reversing an opposite position. A long closes when price touches the lower band of the ClosePeriod channel and a short
/// when price touches its upper band. Both channels are measured on the candles before the current one.
/// </summary>
public class DonchianQuestResearchStrategy : Strategy
{
private readonly StrategyParam<int> _openPeriod;
private readonly StrategyParam<int> _closePeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevOpenUpper;
private decimal? _prevOpenLower;
private decimal? _prevCloseUpper;
private decimal? _prevCloseLower;
/// <summary>
/// Period of the entry channel.
/// </summary>
public int OpenPeriod
{
get => _openPeriod.Value;
set => _openPeriod.Value = value;
}
/// <summary>
/// Period of the exit channel.
/// </summary>
public int ClosePeriod
{
get => _closePeriod.Value;
set => _closePeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DonchianQuestResearchStrategy()
{
_openPeriod = Param(nameof(OpenPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Open Period", "Period of the entry Donchian channel", "Indicators");
_closePeriod = Param(nameof(ClosePeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Close Period", "Period of the exit Donchian channel", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).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();
ResetState();
}
private void ResetState()
{
_prevOpenUpper = null;
_prevOpenLower = null;
_prevCloseUpper = null;
_prevCloseLower = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var openChannel = new DonchianChannels { Length = OpenPeriod };
var closeChannel = new DonchianChannels { Length = ClosePeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(openChannel, closeChannel, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, openChannel);
DrawIndicator(area, closeChannel);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue openValue, IIndicatorValue closeValue)
{
if (candle.State != CandleStates.Finished)
return;
var openUpper = _prevOpenUpper;
var openLower = _prevOpenLower;
var closeUpper = _prevCloseUpper;
var closeLower = _prevCloseLower;
if (openValue.IsFormed && openValue is IDonchianChannelsValue { UpperBand: decimal ou, LowerBand: decimal ol })
{
_prevOpenUpper = ou;
_prevOpenLower = ol;
}
if (closeValue.IsFormed && closeValue is IDonchianChannelsValue { UpperBand: decimal cu, LowerBand: decimal cl })
{
_prevCloseUpper = cu;
_prevCloseLower = cl;
}
if (openUpper is not decimal entryHigh || openLower is not decimal entryLow || closeUpper is not decimal exitHigh || closeLower is not decimal exitLow)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (close > entryHigh && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (close < entryLow && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && candle.LowPrice <= exitLow)
SellMarket(Position);
else if (Position < 0 && candle.HighPrice >= exitHigh)
BuyMarket(-Position);
}
}
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 donchian_quest_research_strategy(Strategy):
"""
Donchian Quest Research strategy.
A close above the upper band of the OpenPeriod Donchian channel goes long and a close below its lower band goes short,
reversing an opposite position. A long closes when price touches the lower band of the ClosePeriod channel and a short
when price touches its upper band. Both channels are measured on the candles before the current one.
"""
def __init__(self):
super(donchian_quest_research_strategy, self).__init__()
self._open_period = self.Param("OpenPeriod", 50).SetGreaterThanZero().SetDisplay("Open Period", "Period of the entry Donchian channel", "Indicators")
self._close_period = self.Param("ClosePeriod", 50).SetGreaterThanZero().SetDisplay("Close Period", "Period of the exit Donchian channel", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_open_upper = None
self._prev_open_lower = None
self._prev_close_upper = None
self._prev_close_lower = None
def OnReseted(self):
super(donchian_quest_research_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(donchian_quest_research_strategy, self).OnStarted2(time)
self._reset_state()
open_channel = DonchianChannels()
open_channel.Length = self._open_period.Value
close_channel = DonchianChannels()
close_channel.Length = self._close_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(open_channel, close_channel, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, open_channel)
self.DrawIndicator(area, close_channel)
self.DrawOwnTrades(area)
def _process_candle(self, candle, open_value, close_value):
if candle.State != CandleStates.Finished:
return
open_upper = self._prev_open_upper
open_lower = self._prev_open_lower
close_upper = self._prev_close_upper
close_lower = self._prev_close_lower
if open_value.IsFormed and open_value.UpperBand is not None and open_value.LowerBand is not None:
self._prev_open_upper = open_value.UpperBand
self._prev_open_lower = open_value.LowerBand
if close_value.IsFormed and close_value.UpperBand is not None and close_value.LowerBand is not None:
self._prev_close_upper = close_value.UpperBand
self._prev_close_lower = close_value.LowerBand
if open_upper is None or open_lower is None or close_upper is None or close_lower is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
if close > open_upper and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif close < open_lower and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and candle.LowPrice <= close_lower:
self.SellMarket(self.Position)
elif self.Position < 0 and candle.HighPrice >= close_upper:
self.BuyMarket(-self.Position)
def CreateClone(self):
return donchian_quest_research_strategy()