Estrategia IU BBB de Barra de Gran Cuerpo
Esta estrategia entra cuando el cuerpo de la vela actual es varias veces mayor que el tamaño promedio del cuerpo de las últimas 20 velas. Una gran vela alcista abre una posición larga, mientras que una gran vela bajista abre una corta. Las posiciones están protegidas con un stop dinámico basado en ATR.
Detalles
- Criterios de entrada:
- Largo: cuerpo > cuerpo promedio * BigBodyThreshold y cierre > apertura.
- Corto: cuerpo > cuerpo promedio * BigBodyThreshold y cierre < apertura.
- Largo/Corto: Ambos.
- Criterios de salida: Stop dinámico ATR.
- Stops: Stop dinámico usando ATR * AtrFactor.
- Valores predeterminados:
BigBodyThreshold= 4AtrLength= 14AtrFactor= 2CandleType= 5 minute
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: SMA, ATR
- Stops: Sí
- Complejidad: Básico
- 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.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Big body bar strategy with ATR trailing stop.
/// </summary>
public class IuBbbBigBodyBarStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _bigBodyThreshold;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _atrFactor;
private decimal _sumBody;
private int _bodyCount;
private decimal? _atrStop;
private decimal _entryPrice;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Big body threshold multiplier.
/// </summary>
public decimal BigBodyThreshold { get => _bigBodyThreshold.Value; set => _bigBodyThreshold.Value = value; }
/// <summary>
/// ATR period.
/// </summary>
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <summary>
/// ATR factor for trailing stop.
/// </summary>
public decimal AtrFactor { get => _atrFactor.Value; set => _atrFactor.Value = value; }
/// <summary>
/// Initializes a new instance of <see cref="IuBbbBigBodyBarStrategy"/>.
/// </summary>
public IuBbbBigBodyBarStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use.", "General");
_bigBodyThreshold = Param(nameof(BigBodyThreshold), 1.5m)
.SetDisplay("Big Body Threshold", "Multiplier of average body.", "Parameters");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Period", "ATR indicator period.", "Indicators");
_atrFactor = Param(nameof(AtrFactor), 2m)
.SetDisplay("ATR Factor", "ATR multiplier for trailing stop.", "Risk Management");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sumBody = 0m;
_bodyCount = 0;
_atrStop = null;
_entryPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sumBody = 0m;
_bodyCount = 0;
_atrStop = null;
_entryPrice = 0m;
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, atr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atr)
{
if (candle.State != CandleStates.Finished)
return;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
// Track running average of body sizes
_sumBody += body;
_bodyCount++;
var avgBody = _sumBody / _bodyCount;
if (_bodyCount < 20 || avgBody <= 0m)
return;
var longCond = body > avgBody * BigBodyThreshold && candle.ClosePrice > candle.OpenPrice;
var shortCond = body > avgBody * BigBodyThreshold && candle.ClosePrice < candle.OpenPrice;
// Exit logic first
if (Position > 0)
{
if (_atrStop is null)
_atrStop = _entryPrice - atr * AtrFactor;
else
_atrStop = Math.Max(_atrStop.Value, candle.ClosePrice - atr * AtrFactor);
if (candle.LowPrice <= _atrStop)
{
SellMarket();
_atrStop = null;
}
return;
}
else if (Position < 0)
{
if (_atrStop is null)
_atrStop = _entryPrice + atr * AtrFactor;
else
_atrStop = Math.Min(_atrStop.Value, candle.ClosePrice + atr * AtrFactor);
if (candle.HighPrice >= _atrStop)
{
BuyMarket();
_atrStop = null;
}
return;
}
// Entry logic
if (longCond)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (shortCond)
{
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
}
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 AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class iu_bbb_big_body_bar_strategy(Strategy):
def __init__(self):
super(iu_bbb_big_body_bar_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(240))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._big_body_threshold = self.Param("BigBodyThreshold", 1.5) \
.SetDisplay("Big Body Threshold", "Multiplier of average body", "Parameters")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Period", "ATR indicator period", "Indicators")
self._atr_factor = self.Param("AtrFactor", 2.0) \
.SetDisplay("ATR Factor", "ATR multiplier for trailing stop", "Risk Management")
self._sum_body = 0.0
self._body_count = 0
self._atr_stop = None
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(iu_bbb_big_body_bar_strategy, self).OnReseted()
self._sum_body = 0.0
self._body_count = 0
self._atr_stop = None
self._entry_price = 0.0
def OnStarted2(self, time):
super(iu_bbb_big_body_bar_strategy, self).OnStarted2(time)
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, atr)
self.DrawOwnTrades(area)
def OnProcess(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
atr_v = float(atr_val)
body = abs(close - open_p)
self._sum_body += body
self._body_count += 1
avg_body = self._sum_body / self._body_count
if self._body_count < 20 or avg_body <= 0:
return
threshold = float(self._big_body_threshold.Value)
factor = float(self._atr_factor.Value)
long_cond = body > avg_body * threshold and close > open_p
short_cond = body > avg_body * threshold and close < open_p
if self.Position > 0:
if self._atr_stop is None:
self._atr_stop = self._entry_price - atr_v * factor
else:
new_stop = close - atr_v * factor
if new_stop > self._atr_stop:
self._atr_stop = new_stop
if low <= self._atr_stop:
self.SellMarket()
self._atr_stop = None
return
elif self.Position < 0:
if self._atr_stop is None:
self._atr_stop = self._entry_price + atr_v * factor
else:
new_stop = close + atr_v * factor
if new_stop < self._atr_stop:
self._atr_stop = new_stop
if high >= self._atr_stop:
self.BuyMarket()
self._atr_stop = None
return
if long_cond:
self.BuyMarket()
self._entry_price = close
elif short_cond:
self.SellMarket()
self._entry_price = close
def CreateClone(self):
return iu_bbb_big_body_bar_strategy()