Estrategia Cryptocurrency Fibonacci MAs (StockSharp)
Descripción general
Esta estrategia adapta el asesor experto de MetaTrader "Cryptocurrency Fibonacci MAs" a la API de alto nivel de StockSharp. El sistema rastrea una pila de medias móviles exponenciales basadas en Fibonacci (8/13/21/55), valida momentum en un marco temporal superior y confirma la tendencia macro con un filtro MACD mensual antes de enviar órdenes de mercado. Solo se procesan velas completadas y todas las actualizaciones de indicadores se realizan mediante la canalización Bind/BindEx.
Comparada con la versión MetaTrader, se hicieron los siguientes ajustes intencionales:
Se omitieron take profit basado en dinero, equity stop-out, trailing vela a vela y automatización de break-even. La adaptación StockSharp usa stop-loss y take-profit clásicos basados en pips mediante StartProtection.
La piramidación de órdenes se limita a una posición neta por dirección. Las inversiones cierran primero la exposición opuesta, reflejando el modelo de posición neteada de StockSharp.
Los datos multitemporales se proporcionan mediante suscripciones adicionales de velas en lugar de solicitudes ad hoc de indicadores bajo demanda.
Lógica de trading
Entrada larga
Alineación EMA: 8 > 13 > 21 > 55 en el marco temporal principal.
Momentum de marco temporal superior: la desviación absoluta del Momentum de 14 períodos respecto al nivel neutral 100 está por encima del umbral de compra configurado en al menos una de las tres últimas velas del marco temporal superior.
Filtro MACD mensual: la línea principal MACD está por encima de la línea de señal.
Filtro de posición: la posición neta actual debe estar plana o corta y permanecer por debajo del volumen máximo configurado.
Entrada corta
Alineación EMA: 8 < 13 < 21 < 55.
Desviación de momentum por encima del umbral de venta en al menos una de las tres últimas velas del marco temporal superior.
Línea principal MACD por debajo de su línea de señal.
La exposición neta debe estar plana o larga y dentro del límite MaxPositions.
Lógica de salida
StartProtection coloca órdenes de stop-loss y take-profit de protección expresadas en distancias pip. No se aplica lógica adicional de trailing ni break-even en esta adaptación.
Las señales de inversión envían el tamaño de orden de mercado opuesto, que primero compensa la posición existente antes de establecer la nueva exposición.
Mapeo multitemporal
El marco temporal superior usado para el indicador de momentum refleja la tabla de coeficientes original:
Marco temporal principal
Marco temporal de momentum
1 minuto
15 minutos
5 minutos
30 minutos
15 minutos
1 hora
30 minutos
4 horas
1 hora
1 día
4 horas
1 semana
1 día
1 mes
1 semana
1 mes
1 mes
1 mes
La confirmación MACD siempre se ejecuta en una aproximación mensual de 30 días.
Parámetros
Nombre
Descripción
Predeterminado
TradeVolume
Tamaño de orden en lotes.
0.1
StopLossPips
Distancia de stop-loss en pips.
20
TakeProfitPips
Distancia de take-profit en pips.
50
MomentumBuyThreshold
Desviación absoluta mínima de momentum desde 100 requerida para operaciones largas.
0.3
MomentumSellThreshold
Desviación absoluta mínima de momentum desde 100 requerida para operaciones cortas.
0.3
MaxPositions
Volumen neto máximo por dirección expresado como múltiplos de TradeVolume.
1
CandleType
Marco temporal principal para cálculos EMA.
Velas de 1 hora
Notas de uso
Adjunte la estrategia a un símbolo y seleccione un marco temporal apropiado mediante CandleType.
Asegúrese de que la fuente de datos pueda proporcionar tanto el marco temporal principal como los marcos temporales superiores derivados (momentum y mensual).
Ajuste los parámetros de riesgo basados en pips para que coincidan con el tamaño de tick del instrumento. El helper convierte pips a pasos del instrumento usando Security.PriceStep.
El backtesting y la optimización pueden ajustar los umbrales de momentum y las distancias de stop usando los rangos de parámetros proporcionados.
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;
public class CryptocurrencyFibonacciMAsStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public CryptocurrencyFibonacciMAsStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class cryptocurrency_fibonacci_m_as_strategy(Strategy):
def __init__(self):
super(cryptocurrency_fibonacci_m_as_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(cryptocurrency_fibonacci_m_as_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(cryptocurrency_fibonacci_m_as_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return cryptocurrency_fibonacci_m_as_strategy()