Estrategia de agotamiento de la envolvente MA de Firebird
La estrategia replica el experto en reversión de sobres de Firebird v0.60. Mide una media móvil simple y la compensa en un porcentaje para formar las envolventes superior e inferior. Cuando el precio atraviesa la banda superior, la estrategia vende, y cuando la banda inferior se rompe, compra. Las posiciones adicionales se promedian solo si el precio se mueve al menos un pip configurable más allá de la entrada anterior. El stop loss total se comparte entre todas las entradas, lo que evita que las tendencias desbocadas vuelvan a entrar repetidamente en la misma dirección.
Detalles
Criterios de entrada:
Calcule un SMA en la apertura de cualquiera de las velas o en el punto medio alto/bajo.
Sobre superior = SMA × (1 + Porcentaje/100); sobre inferior = SMA × (1 − Porcentaje/100).
Ingrese en corto en un cierre por encima de la banda superior (a menos que una parada reciente bloquee los cortos), ingrese en largo en un cierre por debajo de la banda inferior (a menos que los largos estén bloqueados).
Se permiten operaciones de entrada promedio una vez que el precio se mueve PipStep pips (opcionalmente escalado por potencia) más allá del último llenado.
Largo/Corto: Largo y corto.
Criterios de salida:
Toma de ganancias compartida al precio de entrada promedio ± TakeProfit pips.
Stop loss compartido al precio de entrada promedio ∓ StopLoss / position count pips.
La bandera de bloqueo impide el reingreso en la misma dirección hasta que se activa una señal opuesta después de una parada.
Paradas: Sí, stop loss agregado y toma de ganancias.
Valores predeterminados:
MaLength = 10
Percent = 0,3
TradeOnFriday = verdadero
UseHighLow = falso (usar abre)
PipStep = 30
IncreasementPower = 0
TakeProfit = 30
StopLoss = 200
TradeVolume = 1
Filtros:
Categoría: Reversión media
Dirección: Ambos
Indicadores: SMA sobres
Paradas: Sí
Complejidad: Media
Plazo: Cualquiera
Estacionalidad: filtro de viernes opcional
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Alto debido al promedio
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Firebird MA Envelope Exhaustion strategy - Bollinger Bands mean reversion.
/// Buys when close drops below lower band (exhaustion).
/// Sells when close rises above upper band (exhaustion).
/// Exits at the middle band.
/// </summary>
public class FirebirdMaEnvelopeExhaustionStrategy : Strategy
{
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bbWidth;
private readonly StrategyParam<DataType> _candleType;
public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
public decimal BbWidth { get => _bbWidth.Value; set => _bbWidth.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FirebirdMaEnvelopeExhaustionStrategy()
{
_bbPeriod = Param(nameof(BbPeriod), 10)
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_bbWidth = Param(nameof(BbWidth), 2m)
.SetDisplay("BB Width", "Bollinger Bands width", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands { Length = BbPeriod, Width = BbWidth };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
if (!value.IsFinal || value.IsEmpty)
return;
var bbVal = value as BollingerBandsValue;
if (bbVal == null)
return;
var upper = bbVal.UpBand;
var lower = bbVal.LowBand;
var middle = bbVal.MovingAverage;
if (upper == null || lower == null || middle == null)
return;
var close = candle.ClosePrice;
// Close below lower band = exhaustion, buy
if (close < lower.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Close above upper band = exhaustion, sell
else if (close > upper.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
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 BollingerBands
from StockSharp.Algo.Strategies import Strategy
class firebird_ma_envelope_exhaustion_strategy(Strategy):
def __init__(self):
super(firebird_ma_envelope_exhaustion_strategy, self).__init__()
self._bb_period = self.Param("BbPeriod", 10).SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
self._bb_width = self.Param("BbWidth", 2.0).SetDisplay("BB Width", "Bollinger Bands width", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def bb_period(self): return self._bb_period.Value
@property
def bb_width(self): return self._bb_width.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(firebird_ma_envelope_exhaustion_strategy, self).OnReseted()
def OnStarted2(self, time):
super(firebird_ma_envelope_exhaustion_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.bb_period
bb.Width = self.bb_width
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.process_candle).Start()
def process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFinal or bb_value.IsEmpty:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
close = float(candle.ClosePrice)
if close < lower and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif close > upper and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return firebird_ma_envelope_exhaustion_strategy()