Esta estrategia es un port para StockSharp del asesor experto de MetaTrader 4 "Crypto Analysis". Busca rupturas que aparecen después de que el precio toque la banda exterior de Bollinger en el marco principal de negociación, mientras la estructura del mercado permanece bajista (LWMA rápida por debajo de la LWMA lenta). El sistema solo permite operaciones cuando una ráfaga de momentum en un marco superior y un filtro MACD mensual coinciden con la dirección deseada. Una vez dentro del mercado, la posición se gestiona mediante un bloque de protección por capas que replica el EA original: stops basados en pips, trailing basado en dinero, reubicación a break-even y controles de drawdown de cartera.
Lógica de negociación
Marco de señal: configurable (M15 por defecto). Todas las reglas de entrada/salida se evalúan en estas velas.
Disparador de volatilidad: el mínimo de la vela anterior debe tocar o perforar la banda inferior de Bollinger (20, 2) para preparar una configuración larga; tocar la banda superior prepara una configuración corta.
Filtro de tendencia: ambos escenarios requieren que la media móvil ponderada lineal rápida (LWMA, 6 por defecto) permanezca por debajo de la LWMA lenta (85 por defecto), replicando el sesgo bajista del EA.
Confirmación RSI: RSI(14) debe estar por encima de 50 para largos y por debajo de 50 para cortos.
Ráfaga de momentum: la desviación absoluta máxima de los tres últimos valores Momentum(14) del marco superior frente a la línea base 100 debe superar los umbrales de compra/venta. Esto captura los picos de momentum usados por el código MQL.
Filtro MACD mensual: un MACD separado mensual (velas de 30 días por defecto) (12, 26, 9) confirma la dirección; los largos requieren MACD principal sobre señal, los cortos exigen lo contrario.
Ejecución de entrada: cuando todos los filtros se alinean, la estrategia abre una orden de mercado. Las posiciones opuestas se aplanan antes de revertir para mantener una sola posición neta, lo que refleja el comportamiento del EA al cerrar operaciones contrarias.
Gestión de posición
Stop y objetivo iniciales: las distancias configurables en pips se convierten desde el tick del instrumento con el mismo manejo de 5 dígitos/3 dígitos que el EA (los pasos 0.00001 y 0.001 se multiplican por 10).
Trailing stop: después de formar un nuevo máximo (largo) o mínimo (corto), el stop se arrastra detrás del precio por TrailingStopPips, respetando siempre el mejor nivel alcanzado.
Break-even: cuando el beneficio alcanza BreakEvenTriggerPips, el stop se mueve al precio de entrada más BreakEvenOffsetPips (largo) o menos el desplazamiento (corto).
Objetivos monetarios: topes opcionales de beneficio absoluto o porcentual cierran la posición tan pronto como el PnL flotante alcanza el nivel solicitado.
Trailing monetario: cuando el beneficio no realizado supera MoneyTrailTarget, la estrategia sigue el máximo y cierra la posición si la devolución alcanza o supera MoneyTrailStop.
Stop de patrimonio: se controla el patrimonio flotante (valor actual de cartera más PnL no realizado); si el drawdown desde el máximo supera EquityRiskPercent, la posición se aplana.
Datos multimarco
Se registran automáticamente tres suscripciones:
Serie principal de velas para las reglas Bollinger/LWMA/RSI.
Velas de marco superior para el filtro de momentum (H1 por defecto).
Velas mensuales para la confirmación MACD (barras de 30 días por defecto).
Parámetros
Parámetro
Descripción
OrderVolume
Tamaño base de orden. Las posiciones opuestas se cierran antes de abrir una nueva.
UseMoneyTakeProfit
Activa el objetivo de take-profit monetario absoluto.
MoneyTakeProfit
Beneficio en la moneda de la cartera que dispara una salida cuando UseMoneyTakeProfit es verdadero.
UsePercentTakeProfit
Activa el objetivo de take-profit porcentual calculado desde el patrimonio inicial.
PercentTakeProfit
Porcentaje de beneficio requerido para cerrar la posición cuando el objetivo porcentual está activo.
EnableMoneyTrailing
Activa el bloque de trailing basado en dinero.
MoneyTrailTarget
Nivel de beneficio que inicia el trailing monetario.
MoneyTrailStop
Devolución máxima permitida de beneficio después de alcanzar MoneyTrailTarget.
StopLossPips
Distancia inicial de stop-loss en pips.
TakeProfitPips
Distancia inicial de take-profit en pips.
TrailingStopPips
Distancia del trailing stop en pips.
UseBreakEven
Activa la reubicación del stop a break-even.
BreakEvenTriggerPips
Beneficio en pips necesario antes de activar la protección break-even.
BreakEvenOffsetPips
Pips adicionales añadidos al precio de entrada al colocar el stop de break-even.
FastMaPeriod
Longitud de la LWMA rápida calculada sobre precio típico.
SlowMaPeriod
Longitud de la LWMA lenta calculada sobre precio típico.
MomentumPeriod
Periodo del indicador Momentum en el marco superior.
MomentumBuyThreshold
Desviación mínima de momentum para entradas largas.
MomentumSellThreshold
Desviación mínima de momentum para entradas cortas.
MacdFastLength
Longitud de EMA rápida para el filtro MACD de marco superior.
MacdSlowLength
Longitud de EMA lenta para el filtro MACD de marco superior.
MacdSignalLength
Longitud de señal para el filtro MACD de marco superior.
UseEquityStop
Activa la protección contra drawdown de cartera.
EquityRiskPercent
Porcentaje permitido de drawdown de patrimonio antes de cerrar la posición por fuerza.
CandleType
Marco principal usado para entradas.
MomentumCandleType
Marco superior usado para confirmación de momentum.
MacdCandleType
Marco superior usado para confirmación MACD.
Notas
El port StockSharp mantiene una sola posición neta, igual que el EA que cierra órdenes opuestas antes de abrir una nueva operación.
Todas las reglas de protección operan sobre velas cerradas para replicar el procesamiento de "nueva barra" del script original.
Al usar símbolos sintéticos o instrumentos sin tamaño de pip estándar, ajuste StopLossPips y parámetros relacionados al valor de tick de la bolsa.
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 CryptoAnalysisStrategy : 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 CryptoAnalysisStrategy()
{
_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 crypto_analysis_strategy(Strategy):
def __init__(self):
super(crypto_analysis_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(crypto_analysis_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(crypto_analysis_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 crypto_analysis_strategy()