Esta estrategia opera basándose en la dirección de una media móvil de tercera generación. El indicador es una combinación de dos medias móviles exponenciales y se vuelve azul cuando sube y rosa cuando baja. Se registra una señal de compra cuando la media gira hacia arriba, y una señal de venta cuando gira hacia abajo.
Las órdenes se colocan solo en un horario especificado por el usuario después de que aparece una señal. Las posiciones también pueden cerrarse cuando se detecta la señal opuesta o cuando vence un período de tenencia predefinido. Los niveles opcionales de stop-loss y take-profit se miden en puntos.
Parámetros
Length – período de suavizado de la media de tercera generación.
StartHour – hora en que se pueden abrir nuevas posiciones.
StartMinute – minuto dentro de la hora en que se permiten aperturas.
HoldMinutes – tiempo máximo para mantener una posición abierta.
Volume – volumen de orden utilizado para las entradas.
StopLoss – distancia de stop-loss en puntos. 0 deshabilita el stop.
TakeProfit – distancia de take-profit en puntos. 0 deshabilita el objetivo.
UseLongEntries – habilitar entradas largas.
UseShortEntries – habilitar entradas cortas.
CloseLongBySignal – cerrar posiciones largas cuando aparece una señal de venta.
CloseShortBySignal – cerrar posiciones cortas cuando aparece una señal de compra.
CandleType – marco temporal de las velas usadas para cálculos.
Lógica
Suscribirse a velas del marco temporal seleccionado.
Calcular la media móvil de tercera generación para cada vela.
Detectar cuándo la media sube o baja entre velas consecutivas.
Almacenar una señal de compra o venta basada en el cambio de dirección.
En el horario de apertura especificado, entrar en la dirección de la señal almacenada.
Cerrar posiciones en señales opuestas, cuando transcurre el tiempo de tenencia, o cuando se alcanzan los niveles de stop-loss/take-profit.
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>
/// Color 3rd Generation XMA strategy.
/// Uses two EMAs of different periods to approximate 3rd generation moving average.
/// Opens long when fast EMA crosses above slow EMA, short when crosses below.
/// </summary>
public class Color3RdGenXmaStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<decimal> _minSpread;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _isFirst = true;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public decimal MinSpread { get => _minSpread.Value; set => _minSpread.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Color3RdGenXmaStrategy()
{
_fastLength = Param(nameof(FastLength), 20)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period", "General");
_slowLength = Param(nameof(SlowLength), 50)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period", "General");
_minSpread = Param(nameof(MinSpread), 20m)
.SetGreaterThanZero()
.SetDisplay("Min Spread", "Minimum EMA spread in price steps", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0m;
_prevSlow = 0m;
_isFirst = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0m;
_prevSlow = 0m;
_isFirst = true;
var fastEma = new ExponentialMovingAverage { Length = FastLength };
var slowEma = new ExponentialMovingAverage { Length = SlowLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, 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 fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (_isFirst)
{
_prevFast = fast;
_prevSlow = slow;
_isFirst = false;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var step = Security.PriceStep ?? 1m;
var spread = Math.Abs(fast - slow);
if (spread < MinSpread * step)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var prevAbove = _prevFast > _prevSlow;
var curAbove = fast > slow;
if (!prevAbove && curAbove && Position <= 0)
BuyMarket();
else if (prevAbove && !curAbove && Position >= 0)
SellMarket();
_prevFast = fast;
_prevSlow = slow;
}
}
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 color_3rd_gen_xma_strategy(Strategy):
def __init__(self):
super(color_3rd_gen_xma_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 20) \
.SetDisplay("Fast EMA", "Fast EMA period", "General")
self._slow_length = self.Param("SlowLength", 50) \
.SetDisplay("Slow EMA", "Slow EMA period", "General")
self._min_spread = self.Param("MinSpread", 20.0) \
.SetDisplay("Min Spread", "Minimum EMA spread in price steps", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for calculations", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_first = True
@property
def fast_length(self):
return self._fast_length.Value
@property
def slow_length(self):
return self._slow_length.Value
@property
def min_spread(self):
return self._min_spread.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(color_3rd_gen_xma_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_first = True
def OnStarted2(self, time):
super(color_3rd_gen_xma_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_first = True
fast_ema = ExponentialMovingAverage()
fast_ema.Length = int(self.fast_length)
slow_ema = ExponentialMovingAverage()
slow_ema.Length = int(self.slow_length)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema, slow_ema, self.process_candle).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 process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast = float(fast)
slow = float(slow)
if self._is_first:
self._prev_fast = fast
self._prev_slow = slow
self._is_first = False
return
spread = abs(fast - slow)
ms = float(self.min_spread)
price_step = float(self.Security.PriceStep) if self.Security.PriceStep is not None else 1.0
if spread < ms * price_step:
self._prev_fast = fast
self._prev_slow = slow
return
prev_above = self._prev_fast > self._prev_slow
cur_above = fast > slow
if not prev_above and cur_above and self.Position <= 0:
self.BuyMarket()
elif prev_above and not cur_above and self.Position >= 0:
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return color_3rd_gen_xma_strategy()