La Estrategia de Cruce Q2MA opera basándose en el cruce de medias móviles suavizadas construidas sobre los precios de cierre y apertura de las velas. Se abre una posición larga cuando la media del cierre cae por debajo de la media de la apertura tras haber estado por encima, mientras que se abre una posición corta en el cruce opuesto. Las posiciones se cierran cuando aparece una tendencia contraria. La estrategia también aplica niveles de stop loss y take profit medidos en ticks.
Detalles
Criterios de entrada: cruce entre medias móviles de precios de cierre y apertura
Largo/Corto: ambas direcciones
Criterios de salida: cruce opuesto o stop loss/take profit
Stops: sí
Valores predeterminados:
Length = 8
StopLoss = 1000
TakeProfit = 2000
CandleType = TimeSpan.FromHours(4).TimeFrame()
Volume = 1
BuyPosOpen = true
SellPosOpen = true
BuyPosClose = true
SellPosClose = true
Invert = false
Filtros:
Categoría: Tendencia
Dirección: Ambos
Indicadores: Moving Average
Stops: Sí
Complejidad: Intermedio
Marco temporal: H4
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>
/// Q2MA cross strategy based on open and close moving averages.
/// Buys when close MA crosses above open MA, sells on opposite.
/// </summary>
public class Q2maCrossStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _closeMa;
private ExponentialMovingAverage _openMa;
private decimal? _prevUp;
private decimal? _prevDn;
public int Length { get => _length.Value; set => _length.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Q2maCrossStrategy()
{
_length = Param(nameof(Length), 8)
.SetDisplay("Length", "Moving average length", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Indicator timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_closeMa = null;
_openMa = null;
_prevUp = null;
_prevDn = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevUp = null;
_prevDn = null;
_closeMa = new ExponentialMovingAverage { Length = Length };
_openMa = new ExponentialMovingAverage { Length = Length };
Indicators.Add(_closeMa);
Indicators.Add(_openMa);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var t = candle.ServerTime;
var upResult = _closeMa.Process(new DecimalIndicatorValue(_closeMa, candle.ClosePrice, t) { IsFinal = true });
var dnResult = _openMa.Process(new DecimalIndicatorValue(_openMa, candle.OpenPrice, t) { IsFinal = true });
if (!_closeMa.IsFormed || !_openMa.IsFormed)
return;
var up = upResult.GetValue<decimal>();
var dn = dnResult.GetValue<decimal>();
if (_prevUp is null || _prevDn is null)
{
_prevUp = up;
_prevDn = dn;
return;
}
// Close MA crosses above Open MA -> buy signal
if (_prevUp <= _prevDn && up > dn && Position <= 0)
BuyMarket();
// Close MA crosses below Open MA -> sell signal
else if (_prevUp >= _prevDn && up < dn && Position >= 0)
SellMarket();
_prevUp = up;
_prevDn = dn;
}
}
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
from indicator_extensions import *
class q2ma_cross_strategy(Strategy):
def __init__(self):
super(q2ma_cross_strategy, self).__init__()
self._length = self.Param("Length", 8) \
.SetDisplay("Length", "Moving average length", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Indicator timeframe", "General")
self._close_ma = None
self._open_ma = None
self._prev_up = None
self._prev_dn = None
@property
def length(self):
return self._length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(q2ma_cross_strategy, self).OnReseted()
self._close_ma = None
self._open_ma = None
self._prev_up = None
self._prev_dn = None
def OnStarted2(self, time):
super(q2ma_cross_strategy, self).OnStarted2(time)
self._prev_up = None
self._prev_dn = None
self._close_ma = ExponentialMovingAverage()
self._close_ma.Length = self.length
self._open_ma = ExponentialMovingAverage()
self._open_ma.Length = self.length
self.Indicators.Add(self._close_ma)
self.Indicators.Add(self._open_ma)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
t = candle.ServerTime
up_result = process_float(self._close_ma, float(candle.ClosePrice), t, True)
dn_result = process_float(self._open_ma, float(candle.OpenPrice), t, True)
if not self._close_ma.IsFormed or not self._open_ma.IsFormed:
return
up = float(up_result)
dn = float(dn_result)
if self._prev_up is None or self._prev_dn is None:
self._prev_up = up
self._prev_dn = dn
return
if self._prev_up <= self._prev_dn and up > dn and self.Position <= 0:
self.BuyMarket()
elif self._prev_up >= self._prev_dn and up < dn and self.Position >= 0:
self.SellMarket()
self._prev_up = up
self._prev_dn = dn
def CreateClone(self):
return q2ma_cross_strategy()