Estrategia Agresiva de Alta IV
La Estrategia Agresiva de Alta IV combina cruces de EMA con un filtro de volatilidad ATR. Las operaciones se abren solo cuando la volatilidad supera su media en una desviación estándar y se cierran con objetivos basados en ATR.
Las pruebas indican retornos sólidos en mercados de alta volatilidad.
La estrategia entra en cruces de EMA durante períodos de volatilidad elevada, buscando ganancias rápidas con controles de riesgo predefinidos.
Las posiciones se cierran utilizando niveles de stop-loss y take-profit basados en ATR.
Detalles
- Criterios de entrada: EMA rápida cruza EMA lenta con ATR por encima de su media más la desviación estándar.
- Largo/Corto: Ambos.
- Criterios de salida: Stop-loss o take-profit basado en ATR alcanzado.
- Stops: Sí.
- Valores predeterminados:
FastEmaLength= 10SlowEmaLength= 30AtrLength= 14AtrMeanLength= 20AtrStdLength= 20RiskFactor= 0.01mCandleType= TimeSpan.FromMinutes(15)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: EMA, ATR
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Alto
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>
/// Aggressive strategy for high implied volatility markets.
/// Uses EMA crossover with ATR volatility filter and ATR-based exits.
/// </summary>
public class AggressiveHighIvStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldownRemaining;
public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public AggressiveHighIvStrategy()
{
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("Fast EMA Length", "Period for fast EMA", "Parameters");
_slowEmaLength = Param(nameof(SlowEmaLength), 30)
.SetGreaterThanZero()
.SetDisplay("Slow EMA Length", "Period for slow EMA", "Parameters");
_atrLength = Param(nameof(AtrLength), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Length", "ATR calculation period", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_entryPrice = 0m;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastEma, decimal slowEma, decimal atrValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastEma;
_prevSlow = slowEma;
return;
}
if (_prevFast == 0)
{
_prevFast = fastEma;
_prevSlow = slowEma;
return;
}
// Check ATR-based stop/take for existing positions
if (Position > 0 && _entryPrice > 0 && atrValue > 0)
{
if (candle.ClosePrice <= _entryPrice - 2m * atrValue || candle.ClosePrice >= _entryPrice + 4m * atrValue)
{
SellMarket(Math.Abs(Position));
_entryPrice = 0;
_cooldownRemaining = CooldownBars;
_prevFast = fastEma;
_prevSlow = slowEma;
return;
}
}
else if (Position < 0 && _entryPrice > 0 && atrValue > 0)
{
if (candle.ClosePrice >= _entryPrice + 2m * atrValue || candle.ClosePrice <= _entryPrice - 4m * atrValue)
{
BuyMarket(Math.Abs(Position));
_entryPrice = 0;
_cooldownRemaining = CooldownBars;
_prevFast = fastEma;
_prevSlow = slowEma;
return;
}
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fastEma;
_prevSlow = slowEma;
return;
}
var longCross = _prevFast <= _prevSlow && fastEma > slowEma;
var shortCross = _prevFast >= _prevSlow && fastEma < slowEma;
if (longCross && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_entryPrice = candle.ClosePrice;
_cooldownRemaining = CooldownBars;
}
else if (shortCross && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_entryPrice = candle.ClosePrice;
_cooldownRemaining = CooldownBars;
}
_prevFast = fastEma;
_prevSlow = slowEma;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class aggressive_high_iv_strategy(Strategy):
def __init__(self):
super(aggressive_high_iv_strategy, self).__init__()
self._fast_ema_length = self.Param("FastEmaLength", 10) \
.SetGreaterThanZero() \
.SetDisplay("Fast EMA Length", "Period for fast EMA", "Parameters")
self._slow_ema_length = self.Param("SlowEmaLength", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow EMA Length", "Period for slow EMA", "Parameters")
self._atr_length = self.Param("AtrLength", 14) \
.SetGreaterThanZero() \
.SetDisplay("ATR Length", "ATR calculation period", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(aggressive_high_iv_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(aggressive_high_iv_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = int(self._fast_ema_length.Value)
slow_ema = ExponentialMovingAverage()
slow_ema.Length = int(self._slow_ema_length.Value)
atr = AverageTrueRange()
atr.Length = int(self._atr_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema, slow_ema, atr, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = float(fast_val)
self._prev_slow = float(slow_val)
return
fast = float(fast_val)
slow = float(slow_val)
atr_v = float(atr_val)
close = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
if self._prev_fast == 0:
self._prev_fast = fast
self._prev_slow = slow
return
# Check ATR-based stop/take for existing positions
if self.Position > 0 and self._entry_price > 0 and atr_v > 0:
if close <= self._entry_price - 2.0 * atr_v or close >= self._entry_price + 4.0 * atr_v:
self.SellMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._cooldown_remaining = cooldown
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0 and atr_v > 0:
if close >= self._entry_price + 2.0 * atr_v or close <= self._entry_price - 4.0 * atr_v:
self.BuyMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._cooldown_remaining = cooldown
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_fast = fast
self._prev_slow = slow
return
long_cross = self._prev_fast <= self._prev_slow and fast > slow
short_cross = self._prev_fast >= self._prev_slow and fast < slow
if long_cross and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._entry_price = close
self._cooldown_remaining = cooldown
elif short_cross and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._entry_price = close
self._cooldown_remaining = cooldown
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return aggressive_high_iv_strategy()