Estrategia Market Slayer
Esta estrategia utiliza un cruce de medias móviles ponderadas con confirmación de tendencia SSL en un marco temporal superior. Se abre una posición larga cuando la WMA corta cruza por encima de la WMA larga con tendencia alcista; se abre una posición corta en condiciones opuestas. Se puede habilitar opcionalmente un take profit y stop loss absolutos.
Detalles
- Criterios de entrada:
- Largo: la WMA corta cruza por encima de la WMA larga y el SSL del marco temporal superior es alcista.
- Corto: la WMA corta cruza por debajo de la WMA larga y el SSL del marco temporal superior es bajista.
- Largo/Corto: Ambos lados.
- Criterios de salida:
- El filtro de tendencia cambia al lado opuesto.
- Stop loss o take profit opcionales cuando están habilitados.
- Stops: Opcional.
- Valores predeterminados:
ShortLength= 10.LongLength= 20.ConfirmationTrendValue= 2.CandleType= TimeSpan.FromMinutes(5).TimeFrame().TrendCandleType= TimeSpan.FromMinutes(240).TimeFrame().TakeProfitEnabled= false.TakeProfitValue= 20.StopLossEnabled= false.StopLossValue= 50.
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: WMA, SSL
- Stops: Opcional
- Complejidad: Básico
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// Market Slayer strategy.
/// The SSL channel on TrendCandleType is built from WMAs of highs and lows over ConfirmationTrendValue candles: a close above the
/// high WMA makes the trend bullish, a close below the low WMA makes it bearish, otherwise the previous state is kept. On CandleType
/// the short WMA crossing above the long WMA in a bullish trend goes long and crossing below in a bearish trend goes short. A position
/// closes when the trend turns opposite. Optional take profit and stop loss are distances in price steps.
/// </summary>
public class MarketSlayerStrategy : Strategy
{
private readonly StrategyParam<int> _shortLength;
private readonly StrategyParam<int> _longLength;
private readonly StrategyParam<int> _confirmationTrendValue;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<DataType> _trendCandleType;
private readonly StrategyParam<bool> _takeProfitEnabled;
private readonly StrategyParam<decimal> _takeProfitValue;
private readonly StrategyParam<bool> _stopLossEnabled;
private readonly StrategyParam<decimal> _stopLossValue;
private WeightedMovingAverage _trendHigh;
private WeightedMovingAverage _trendLow;
private int _trendHlv;
private decimal? _prevShort;
private decimal? _prevLong;
/// <summary>
/// Short WMA length.
/// </summary>
public int ShortLength
{
get => _shortLength.Value;
set => _shortLength.Value = value;
}
/// <summary>
/// Long WMA length.
/// </summary>
public int LongLength
{
get => _longLength.Value;
set => _longLength.Value = value;
}
/// <summary>
/// SSL WMA length on the trend timeframe.
/// </summary>
public int ConfirmationTrendValue
{
get => _confirmationTrendValue.Value;
set => _confirmationTrendValue.Value = value;
}
/// <summary>
/// Signal candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Trend candle type.
/// </summary>
public DataType TrendCandleType
{
get => _trendCandleType.Value;
set => _trendCandleType.Value = value;
}
/// <summary>
/// Enable take profit.
/// </summary>
public bool TakeProfitEnabled
{
get => _takeProfitEnabled.Value;
set => _takeProfitEnabled.Value = value;
}
/// <summary>
/// Take profit distance in price steps.
/// </summary>
public decimal TakeProfitValue
{
get => _takeProfitValue.Value;
set => _takeProfitValue.Value = value;
}
/// <summary>
/// Enable stop loss.
/// </summary>
public bool StopLossEnabled
{
get => _stopLossEnabled.Value;
set => _stopLossEnabled.Value = value;
}
/// <summary>
/// Stop loss distance in price steps.
/// </summary>
public decimal StopLossValue
{
get => _stopLossValue.Value;
set => _stopLossValue.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public MarketSlayerStrategy()
{
_shortLength = Param(nameof(ShortLength), 10)
.SetGreaterThanZero()
.SetDisplay("Short Length", "Short WMA length", "Indicators");
_longLength = Param(nameof(LongLength), 20)
.SetGreaterThanZero()
.SetDisplay("Long Length", "Long WMA length", "Indicators");
_confirmationTrendValue = Param(nameof(ConfirmationTrendValue), 2)
.SetGreaterThanZero()
.SetDisplay("Trend Length", "SSL WMA length on the trend timeframe", "Trend");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Signal candle type", "General");
_trendCandleType = Param(nameof(TrendCandleType), TimeSpan.FromMinutes(240).TimeFrame())
.SetDisplay("Trend Candle Type", "Higher timeframe for the SSL trend", "Trend");
_takeProfitEnabled = Param(nameof(TakeProfitEnabled), false)
.SetDisplay("Use Take Profit", "Enable take profit", "Risk");
_takeProfitValue = Param(nameof(TakeProfitValue), 20m)
.SetNotNegative()
.SetDisplay("Take Profit", "Take profit distance in price steps", "Risk");
_stopLossEnabled = Param(nameof(StopLossEnabled), false)
.SetDisplay("Use Stop Loss", "Enable stop loss", "Risk");
_stopLossValue = Param(nameof(StopLossValue), 50m)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop loss distance in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType), (Security, TrendCandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_trendHigh = null;
_trendLow = null;
_trendHlv = 0;
_prevShort = null;
_prevLong = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_trendHlv = 0;
_prevShort = null;
_prevLong = null;
var shortWma = new WeightedMovingAverage { Length = ShortLength };
var longWma = new WeightedMovingAverage { Length = LongLength };
_trendHigh = new WeightedMovingAverage { Length = ConfirmationTrendValue };
_trendLow = new WeightedMovingAverage { Length = ConfirmationTrendValue };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(shortWma, longWma, ProcessCandle)
.Start();
SubscribeCandles(TrendCandleType)
.Bind(ProcessTrendCandle)
.Start();
if (TakeProfitEnabled || StopLossEnabled)
{
var step = Security?.PriceStep ?? 1m;
StartProtection(
TakeProfitEnabled ? new Unit(TakeProfitValue * step, UnitTypes.Absolute) : new Unit(),
StopLossEnabled ? new Unit(StopLossValue * step, UnitTypes.Absolute) : new Unit(),
useMarketOrders: true);
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, shortWma);
DrawIndicator(area, longWma);
DrawOwnTrades(area);
}
}
private void ProcessTrendCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var highValue = _trendHigh.Process(new DecimalIndicatorValue(_trendHigh, candle.HighPrice, candle.OpenTime) { IsFinal = true });
var lowValue = _trendLow.Process(new DecimalIndicatorValue(_trendLow, candle.LowPrice, candle.OpenTime) { IsFinal = true });
if (!_trendHigh.IsFormed || !_trendLow.IsFormed)
return;
var high = highValue.GetValue<decimal>();
var low = lowValue.GetValue<decimal>();
if (candle.ClosePrice > high)
_trendHlv = 1;
else if (candle.ClosePrice < low)
_trendHlv = -1;
}
private void ProcessCandle(ICandleMessage candle, decimal shortValue, decimal longValue)
{
if (candle.State != CandleStates.Finished)
return;
var prevShort = _prevShort;
var prevLong = _prevLong;
_prevShort = shortValue;
_prevLong = longValue;
if (prevShort is not decimal ps || prevLong is not decimal pl)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bullish = _trendHlv > 0;
var bearish = _trendHlv < 0;
if (Position > 0 && bearish)
{
SellMarket(Position);
return;
}
if (Position < 0 && bullish)
{
BuyMarket(-Position);
return;
}
if (ps <= pl && shortValue > longValue && bullish && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (ps >= pl && shortValue < longValue && bearish && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class market_slayer_strategy(Strategy):
"""
Market Slayer strategy.
The SSL channel on TrendCandleType is built from WMAs of highs and lows over ConfirmationTrendValue candles: a close above the
high WMA makes the trend bullish, a close below the low WMA makes it bearish, otherwise the previous state is kept. On CandleType
the short WMA crossing above the long WMA in a bullish trend goes long and crossing below in a bearish trend goes short. A position
closes when the trend turns opposite. Optional take profit and stop loss are distances in price steps.
"""
def __init__(self):
super(market_slayer_strategy, self).__init__()
self._short_length = self.Param("ShortLength", 10).SetGreaterThanZero().SetDisplay("Short Length", "Short WMA length", "Indicators")
self._long_length = self.Param("LongLength", 20).SetGreaterThanZero().SetDisplay("Long Length", "Long WMA length", "Indicators")
self._confirmation_trend_value = self.Param("ConfirmationTrendValue", 2).SetGreaterThanZero().SetDisplay("Trend Length", "SSL WMA length on the trend timeframe", "Trend")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Signal candle type", "General")
self._trend_candle_type = self.Param("TrendCandleType", DataType.TimeFrame(TimeSpan.FromMinutes(240))).SetDisplay("Trend Candle Type", "Higher timeframe for the SSL trend", "Trend")
self._take_profit_enabled = self.Param("TakeProfitEnabled", False).SetDisplay("Use Take Profit", "Enable take profit", "Risk")
self._take_profit_value = self.Param("TakeProfitValue", 20.0).SetNotNegative().SetDisplay("Take Profit", "Take profit distance in price steps", "Risk")
self._stop_loss_enabled = self.Param("StopLossEnabled", False).SetDisplay("Use Stop Loss", "Enable stop loss", "Risk")
self._stop_loss_value = self.Param("StopLossValue", 50.0).SetNotNegative().SetDisplay("Stop Loss", "Stop loss distance in price steps", "Risk")
self._trend_high = None
self._trend_low = None
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
@property
def trend_candle_type(self):
return self._trend_candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.candle_type), (self.Security, self.trend_candle_type)]
def _reset_state(self):
self._trend_hlv = 0
self._prev_short = None
self._prev_long = None
def OnReseted(self):
super(market_slayer_strategy, self).OnReseted()
self._trend_high = None
self._trend_low = None
self._reset_state()
def OnStarted2(self, time):
super(market_slayer_strategy, self).OnStarted2(time)
self._reset_state()
short_wma = WeightedMovingAverage()
short_wma.Length = self._short_length.Value
long_wma = WeightedMovingAverage()
long_wma.Length = self._long_length.Value
self._trend_high = WeightedMovingAverage()
self._trend_high.Length = self._confirmation_trend_value.Value
self._trend_low = WeightedMovingAverage()
self._trend_low.Length = self._confirmation_trend_value.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(short_wma, long_wma, self._process_candle).Start()
self.SubscribeCandles(self.trend_candle_type).Bind(self._process_trend_candle).Start()
use_tp = self._take_profit_enabled.Value
use_sl = self._stop_loss_enabled.Value
if use_tp or use_sl:
step = Decimal(1)
if self.Security is not None and self.Security.PriceStep is not None:
step = self.Security.PriceStep
tp = Unit(Decimal(self._take_profit_value.Value) * step, UnitTypes.Absolute) if use_tp else Unit()
sl = Unit(Decimal(self._stop_loss_value.Value) * step, UnitTypes.Absolute) if use_sl else Unit()
self.StartProtection(tp, sl, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, short_wma)
self.DrawIndicator(area, long_wma)
self.DrawOwnTrades(area)
def _process_trend_candle(self, candle):
if candle.State != CandleStates.Finished:
return
high_value = process_value(self._trend_high, candle.HighPrice, candle.OpenTime, True)
low_value = process_value(self._trend_low, candle.LowPrice, candle.OpenTime, True)
if not self._trend_high.IsFormed or not self._trend_low.IsFormed:
return
high = high_value.GetValue[Decimal](None)
low = low_value.GetValue[Decimal](None)
if candle.ClosePrice > high:
self._trend_hlv = 1
elif candle.ClosePrice < low:
self._trend_hlv = -1
def _process_candle(self, candle, short_value, long_value):
if candle.State != CandleStates.Finished:
return
ps = self._prev_short
pl = self._prev_long
self._prev_short = short_value
self._prev_long = long_value
if ps is None or pl is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
bullish = self._trend_hlv > 0
bearish = self._trend_hlv < 0
if self.Position > 0 and bearish:
self.SellMarket(self.Position)
return
if self.Position < 0 and bullish:
self.BuyMarket(-self.Position)
return
if ps <= pl and short_value > long_value and bullish and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif ps >= pl and short_value < long_value and bearish and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return market_slayer_strategy()