Estrategia de Futuros con Patrón de Vela Envolvente por Tamaño
Opera una vez al día cuando el rango de una vela supera un umbral de ticks dentro de una ventana horaria seleccionada. La dirección sigue el cuerpo de la vela y la salida se realiza mediante take profit y stop loss.
Detalles
- Criterios de entrada: Rango de la vela en ticks dentro de la sesión de trading.
- Largo/Corto: Ambos.
- Criterios de salida: Take profit o stop loss.
- Stops: Take Profit y Stop Loss.
- Valores predeterminados:
CandleType= 1 minuteCandleSizeThresholdTicks= 25TakeProfitTicks= 50StopLossTicks= 40StartHour= 7StartMinute= 0EndHour= 9EndMinute= 15
- Filtros:
- Categoría: Patrón
- Dirección: Ambos
- Indicadores: Candlestick
- Stops: Sí
- Complejidad: Principiante
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Futures Engulfing Candle Size strategy.
/// Inside the StartHour:StartMinute..EndHour:EndMinute window (candle open time, UTC) the first candle whose high-low range reaches
/// CandleSizeThresholdTicks price steps opens one trade for the day in the direction of its body. The trade exits through a
/// take profit of TakeProfitTicks and a stop loss of StopLossTicks price steps.
/// </summary>
public class FuturesEngulfingCandleSizeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _candleSizeThresholdTicks;
private readonly StrategyParam<int> _takeProfitTicks;
private readonly StrategyParam<int> _stopLossTicks;
private readonly StrategyParam<int> _startHour;
private readonly StrategyParam<int> _startMinute;
private readonly StrategyParam<int> _endHour;
private readonly StrategyParam<int> _endMinute;
private DateTime _lastTradeDay;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Minimum candle range in price steps.
/// </summary>
public int CandleSizeThresholdTicks
{
get => _candleSizeThresholdTicks.Value;
set => _candleSizeThresholdTicks.Value = value;
}
/// <summary>
/// Take profit in price steps.
/// </summary>
public int TakeProfitTicks
{
get => _takeProfitTicks.Value;
set => _takeProfitTicks.Value = value;
}
/// <summary>
/// Stop loss in price steps.
/// </summary>
public int StopLossTicks
{
get => _stopLossTicks.Value;
set => _stopLossTicks.Value = value;
}
/// <summary>
/// Session start hour (UTC).
/// </summary>
public int StartHour
{
get => _startHour.Value;
set => _startHour.Value = value;
}
/// <summary>
/// Session start minute.
/// </summary>
public int StartMinute
{
get => _startMinute.Value;
set => _startMinute.Value = value;
}
/// <summary>
/// Session end hour (UTC).
/// </summary>
public int EndHour
{
get => _endHour.Value;
set => _endHour.Value = value;
}
/// <summary>
/// Session end minute.
/// </summary>
public int EndMinute
{
get => _endMinute.Value;
set => _endMinute.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public FuturesEngulfingCandleSizeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_candleSizeThresholdTicks = Param(nameof(CandleSizeThresholdTicks), 25)
.SetGreaterThanZero()
.SetDisplay("Candle Size Ticks", "Minimum candle range in price steps", "Signal");
_takeProfitTicks = Param(nameof(TakeProfitTicks), 50)
.SetNotNegative()
.SetDisplay("Take Profit Ticks", "Take profit in price steps", "Risk");
_stopLossTicks = Param(nameof(StopLossTicks), 40)
.SetNotNegative()
.SetDisplay("Stop Loss Ticks", "Stop loss in price steps", "Risk");
_startHour = Param(nameof(StartHour), 7)
.SetRange(0, 23)
.SetDisplay("Start Hour", "Session start hour (UTC)", "Session");
_startMinute = Param(nameof(StartMinute), 0)
.SetRange(0, 59)
.SetDisplay("Start Minute", "Session start minute", "Session");
_endHour = Param(nameof(EndHour), 9)
.SetRange(0, 23)
.SetDisplay("End Hour", "Session end hour (UTC)", "Session");
_endMinute = Param(nameof(EndMinute), 15)
.SetRange(0, 59)
.SetDisplay("End Minute", "Session end minute", "Session");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastTradeDay = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_lastTradeDay = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var step = Security?.PriceStep ?? 1m;
StartProtection(
new Unit(TakeProfitTicks * step, UnitTypes.Absolute),
new Unit(StopLossTicks * step, UnitTypes.Absolute),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var time = candle.OpenTime;
var day = time.Date;
if (_lastTradeDay == day || Position != 0)
return;
var minutes = time.Hour * 60 + time.Minute;
if (minutes < StartHour * 60 + StartMinute || minutes > EndHour * 60 + EndMinute)
return;
var step = Security?.PriceStep ?? 1m;
if (step <= 0)
step = 1m;
if ((candle.HighPrice - candle.LowPrice) / step < CandleSizeThresholdTicks)
return;
if (candle.ClosePrice > candle.OpenPrice)
{
BuyMarket();
_lastTradeDay = day;
}
else if (candle.ClosePrice < candle.OpenPrice)
{
SellMarket();
_lastTradeDay = day;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class futures_engulfing_candle_size_strategy(Strategy):
"""
Futures Engulfing Candle Size strategy.
Inside the StartHour:StartMinute..EndHour:EndMinute window (candle open time, UTC) the first candle whose high-low range reaches
CandleSizeThresholdTicks price steps opens one trade for the day in the direction of its body. The trade exits through a
take profit of TakeProfitTicks and a stop loss of StopLossTicks price steps.
"""
def __init__(self):
super(futures_engulfing_candle_size_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._candle_size_threshold_ticks = self.Param("CandleSizeThresholdTicks", 25).SetGreaterThanZero().SetDisplay("Candle Size Ticks", "Minimum candle range in price steps", "Signal")
self._take_profit_ticks = self.Param("TakeProfitTicks", 50).SetNotNegative().SetDisplay("Take Profit Ticks", "Take profit in price steps", "Risk")
self._stop_loss_ticks = self.Param("StopLossTicks", 40).SetNotNegative().SetDisplay("Stop Loss Ticks", "Stop loss in price steps", "Risk")
self._start_hour = self.Param("StartHour", 7).SetRange(0, 23).SetDisplay("Start Hour", "Session start hour (UTC)", "Session")
self._start_minute = self.Param("StartMinute", 0).SetRange(0, 59).SetDisplay("Start Minute", "Session start minute", "Session")
self._end_hour = self.Param("EndHour", 9).SetRange(0, 23).SetDisplay("End Hour", "Session end hour (UTC)", "Session")
self._end_minute = self.Param("EndMinute", 15).SetRange(0, 59).SetDisplay("End Minute", "Session end minute", "Session")
self._last_trade_day = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(futures_engulfing_candle_size_strategy, self).OnReseted()
self._last_trade_day = None
def _price_step(self):
step = self.Security.PriceStep if self.Security is not None and self.Security.PriceStep is not None else None
step = float(step) if step is not None else 1.0
return step if step > 0 else 1.0
def OnStarted2(self, time):
super(futures_engulfing_candle_size_strategy, self).OnStarted2(time)
self._last_trade_day = None
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
step = self._price_step()
self.StartProtection(
Unit(Decimal(self._take_profit_ticks.Value * step), UnitTypes.Absolute),
Unit(Decimal(self._stop_loss_ticks.Value * step), UnitTypes.Absolute),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
time = candle.OpenTime
day = time.Date
if self._last_trade_day == day or self.Position != 0:
return
minutes = time.Hour * 60 + time.Minute
start = self._start_hour.Value * 60 + self._start_minute.Value
end = self._end_hour.Value * 60 + self._end_minute.Value
if minutes < start or minutes > end:
return
if (float(candle.HighPrice) - float(candle.LowPrice)) / self._price_step() < self._candle_size_threshold_ticks.Value:
return
if candle.ClosePrice > candle.OpenPrice:
self.BuyMarket()
self._last_trade_day = day
elif candle.ClosePrice < candle.OpenPrice:
self.SellMarket()
self._last_trade_day = day
def CreateClone(self):
return futures_engulfing_candle_size_strategy()