Estrategia de Acción Volátil
Esta estrategia combina un rompimiento de volatilidad a corto plazo con el filtro de tendencia Alligator de Bill Williams calculado en el marco temporal de 4 horas.
Reglas de trading
- Entrada larga cuando:
- El ATR de período 1 es mayor que Volatility Coef multiplicado por el ATR con período ATR Period.
- La vela es alcista y establece un nuevo máximo de 24 barras.
- Las líneas del Alligator están alineadas hacia arriba (Lips > Teeth > Jaw) y tanto la apertura como el cierre están por encima de la línea Teeth.
- Entrada corta cuando las condiciones anteriores se invierten en la dirección opuesta.
Al entrar, la estrategia establece niveles de stop-loss y take-profit como múltiplos del ATR(1):
- Stop-loss = precio de entrada ± Stop Coef × ATR(1)
- Take-profit = precio de entrada ± Profit Coef × ATR(1)
Parámetros
- Volatility Coef – multiplicador que compara el ATR rápido con el ATR lento.
- ATR Period – período del ATR lento.
- Stop Coef – multiplicador ATR para el stop-loss.
- Profit Coef – multiplicador ATR para el take-profit.
- Candle Type – marco temporal para el análisis principal (el Alligator usa velas de 4H).
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>
/// Volatile Action strategy.
/// Combines volatility breakout (ATR) with Alligator trend filter.
/// </summary>
public class VolatileActionStrategy : Strategy
{
private readonly StrategyParam<decimal> _volatilityCoef;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<DataType> _candleType;
private AverageTrueRange _atr1;
private AverageTrueRange _atrBase;
private SmoothedMovingAverage _jaw;
private SmoothedMovingAverage _teeth;
private SmoothedMovingAverage _lips;
public decimal VolatilityCoef { get => _volatilityCoef.Value; set => _volatilityCoef.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public VolatileActionStrategy()
{
_volatilityCoef = Param(nameof(VolatilityCoef), 1m)
.SetGreaterThanZero()
.SetDisplay("Volatility Coef", "ATR1 multiplier against base ATR", "General");
_atrPeriod = Param(nameof(AtrPeriod), 23)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "Base ATR period", "General");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for main calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_atr1 = default;
_atrBase = default;
_jaw = default;
_teeth = default;
_lips = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_atr1 = new AverageTrueRange { Length = 1 };
_atrBase = new AverageTrueRange { Length = AtrPeriod };
_jaw = new SmoothedMovingAverage { Length = 13 };
_teeth = new SmoothedMovingAverage { Length = 8 };
_lips = new SmoothedMovingAverage { Length = 5 };
Indicators.Add(_atr1);
Indicators.Add(_atrBase);
Indicators.Add(_jaw);
Indicators.Add(_teeth);
Indicators.Add(_lips);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var atr1Val = _atr1.Process(candle);
var atrBaseVal = _atrBase.Process(candle);
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var jawVal = _jaw.Process(median, candle.OpenTime, true);
var teethVal = _teeth.Process(median, candle.OpenTime, true);
var lipsVal = _lips.Process(median, candle.OpenTime, true);
if (!atr1Val.IsFormed || !atrBaseVal.IsFormed || !jawVal.IsFormed || !teethVal.IsFormed || !lipsVal.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var atr1 = atr1Val.ToDecimal();
var atrBase = atrBaseVal.ToDecimal();
var jaw = jawVal.ToDecimal();
var teeth = teethVal.ToDecimal();
var lips = lipsVal.ToDecimal();
var hl = candle.HighPrice - candle.LowPrice;
if (hl == 0) return;
var hc = Math.Abs(candle.HighPrice - candle.ClosePrice);
var lc = Math.Abs(candle.LowPrice - candle.ClosePrice);
// Alligator bullish: lips > teeth > jaw
var bullGator = lips > teeth && teeth > jaw;
// Alligator bearish: lips < teeth < jaw
var bearGator = lips < teeth && teeth < jaw;
// Volatility breakout
var volBreakout = atrBase > 0 && atr1 > VolatilityCoef * atrBase;
if (Position == 0)
{
if (volBreakout && bullGator && candle.ClosePrice > candle.OpenPrice)
{
BuyMarket();
}
else if (volBreakout && bearGator && candle.ClosePrice < candle.OpenPrice)
{
SellMarket();
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import AverageTrueRange, SmoothedMovingAverage, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class volatile_action_strategy(Strategy):
def __init__(self):
super(volatile_action_strategy, self).__init__()
self._volatility_coef = self.Param("VolatilityCoef", 1.0) \
.SetDisplay("Volatility Coef", "ATR1 multiplier against base ATR", "General")
self._atr_period = self.Param("AtrPeriod", 23) \
.SetDisplay("ATR Period", "Base ATR period", "General")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 3.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe for main calculation", "General")
self._atr1 = None
self._atr_base = None
self._jaw = None
self._teeth = None
self._lips = None
@property
def volatility_coef(self):
return self._volatility_coef.Value
@property
def atr_period(self):
return self._atr_period.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(volatile_action_strategy, self).OnReseted()
self._atr1 = None
self._atr_base = None
self._jaw = None
self._teeth = None
self._lips = None
def OnStarted2(self, time):
super(volatile_action_strategy, self).OnStarted2(time)
self._atr1 = AverageTrueRange()
self._atr1.Length = 1
self._atr_base = AverageTrueRange()
self._atr_base.Length = self.atr_period
self._jaw = SmoothedMovingAverage()
self._jaw.Length = 13
self._teeth = SmoothedMovingAverage()
self._teeth.Length = 8
self._lips = SmoothedMovingAverage()
self._lips.Length = 5
self.Indicators.Add(self._atr1)
self.Indicators.Add(self._atr_base)
self.Indicators.Add(self._jaw)
self.Indicators.Add(self._teeth)
self.Indicators.Add(self._lips)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Percent),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Percent),
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
cv1 = CandleIndicatorValue(self._atr1, candle)
atr1_val = self._atr1.Process(cv1)
cv2 = CandleIndicatorValue(self._atr_base, candle)
atr_base_val = self._atr_base.Process(cv2)
median = (candle.HighPrice + candle.LowPrice) / 2
t = candle.OpenTime
jaw_val = process_float(self._jaw, median, t, True)
teeth_val = process_float(self._teeth, median, t, True)
lips_val = process_float(self._lips, median, t, True)
if (not atr1_val.IsFormed or not atr_base_val.IsFormed or
not jaw_val.IsFormed or not teeth_val.IsFormed or not lips_val.IsFormed):
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
atr1 = float(atr1_val)
atr_base = float(atr_base_val)
jaw = float(jaw_val)
teeth = float(teeth_val)
lips = float(lips_val)
bull_gator = lips > teeth and teeth > jaw
bear_gator = lips < teeth and teeth < jaw
vol_breakout = atr_base > 0 and atr1 > float(self.volatility_coef) * atr_base
if self.Position == 0:
if vol_breakout and bull_gator and float(candle.ClosePrice) > float(candle.OpenPrice):
self.BuyMarket()
elif vol_breakout and bear_gator and float(candle.ClosePrice) < float(candle.OpenPrice):
self.SellMarket()
def CreateClone(self):
return volatile_action_strategy()