La estrategia MA Price Cross es una conversión directa del MetaTrader 4 asesor experto "MA Price Cross" al API de alto nivel de StockSharp. Espera a que la media móvil seleccionada cruce el precio actual mientras se permite la negociación dentro de un período de tiempo configurable. Cuando el cruce se produce desde abajo, el algoritmo abre una posición larga; cuando el cruce ocurre desde arriba, abre una posición corta. Las distancias protectoras de stop-loss y take-profit se definen en MetaTrader puntos y se traducen automáticamente a compensaciones de precios absolutas utilizando el PriceStep del instrumento.
A diferencia de la implementación original MQL, que reacciona en cada tic, la versión StockSharp funciona con velas terminadas y utiliza la suscripción de alto nivel SubscribeCandles. Esto garantiza que las decisiones comerciales se ejecuten una vez por barra y sigan siendo compatibles con el proceso de vinculación del indicador. El promedio móvil se puede configurar para que coincida con los cuatro modos MetaTrader y acepta diferentes fuentes de precios (cierre, apertura, máximo, mínimo, mediana, típico, ponderado).
Lógica comercial
Espere a que la hora actual caiga dentro de la ventana de negociación [StartTime, StopTime). Las ventanas nocturnas se mantienen alrededor de la medianoche.
Procese solo velas completadas. Alimente la media móvil configurada con el precio aplicado elegido.
Almacene el valor de media móvil anterior para emular la lógica de cambio iMA utilizada en MetaTrader.
Cuando el promedio anterior esté por debajo del último precio y el nuevo promedio esté por encima del precio, abra (o invierta) una posición larga.
Cuando el promedio anterior esté por encima del último precio y el nuevo promedio esté por debajo del precio, abra (o invierta) una posición corta.
Antes de abrir una nueva posición en el lado opuesto, aplane cualquier exposición existente para reflejar la restricción OrdersTotal() == 0 del código original.
Inicie un stop-loss y take-profit virtual con distancias expresadas en MetaTrader puntos multiplicados por el instrumento actual PriceStep.
Parámetros predeterminados
Parámetro
Predeterminado
Descripción
CandleType
TimeFrame(1m)
Serie de velas que impulsa todos los cálculos.
MaPeriod
160
Número de barras utilizadas por la media móvil.
MaMethod
Simple
Tipo de media móvil: simple, exponencial, suavizada o ponderada lineal.
PriceType
Close
Fuente del precio remitida a la media móvil (cierre/apertura/máximo/mínimo/mediana/típica/ponderada).
StartTime
01:00
Hora del día en que se activa la negociación.
StopTime
22:00
Hora del día en la que se detienen las nuevas entradas.
StopLossPoints
200
MetaTrader puntos convertidos en una distancia de parada de protección absoluta.
TakeProfitPoints
600
MetaTrader puntos convertidos en una distancia objetivo de beneficio absoluto.
OrderVolume
0.1
Volumen predeterminado presentado con órdenes de mercado.
Notas
Si StartTime es igual a StopTime, el filtro de tiempo está deshabilitado y se permite operar durante todo el día.
Cuando StopLossPoints o TakeProfitPoints es igual a cero, no se registra el nivel de protección correspondiente.
El filtro de tiempo utiliza el tiempo de cierre de la vela (candle.CloseTime.TimeOfDay) para que se adapte a la zona horaria del intercambio proporcionada por MarketDataConnector.
Si la seguridad no expone PriceStep, las distancias basadas en puntos se utilizan directamente sin escalar.
Referencia de estrategia original
Fuente: MQL/44133/MA Price Cross.mq4
Autor: JBlanked (2023)
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "MA Price Cross" MetaTrader expert.
/// Enters when SMA crosses above/below the current close price.
/// </summary>
public class MaPriceCrossStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _maPeriod;
private ExponentialMovingAverage _sma;
private decimal? _prevAverage;
private decimal? _prevClose;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
public MaPriceCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for MA cross detection", "General");
_maPeriod = Param(nameof(MaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("MA Period", "SMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new ExponentialMovingAverage { Length = MaPeriod };
_prevAverage = null;
_prevClose = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed)
{
_prevAverage = smaValue;
_prevClose = candle.ClosePrice;
return;
}
if (_prevAverage is null || _prevClose is null)
{
_prevAverage = smaValue;
_prevClose = candle.ClosePrice;
return;
}
var close = candle.ClosePrice;
var volume = Volume;
if (volume <= 0)
volume = 1;
// MA was below price, now crosses above -> sell signal (price goes under MA)
var sellSignal = _prevClose.Value >= _prevAverage.Value && close < smaValue;
// MA was above price, now crosses below -> buy signal (price goes above MA)
var buySignal = _prevClose.Value <= _prevAverage.Value && close > smaValue;
if (buySignal)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (sellSignal)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevAverage = smaValue;
_prevClose = close;
}
/// <inheritdoc />
protected override void OnReseted()
{
_sma = null;
_prevAverage = null;
_prevClose = null;
base.OnReseted();
}
}
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 ma_price_cross_strategy(Strategy):
def __init__(self):
super(ma_price_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ma_period = self.Param("MaPeriod", 100)
self._prev_average = None
self._prev_close = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MaPeriod(self):
return self._ma_period.Value
@MaPeriod.setter
def MaPeriod(self, value):
self._ma_period.Value = value
def OnReseted(self):
super(ma_price_cross_strategy, self).OnReseted()
self._prev_average = None
self._prev_close = None
def OnStarted2(self, time):
super(ma_price_cross_strategy, self).OnStarted2(time)
self._prev_average = None
self._prev_close = None
sma = ExponentialMovingAverage()
sma.Length = self.MaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma, self._process_candle).Start()
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
sma_val = float(sma_value)
close = float(candle.ClosePrice)
if self._prev_average is None or self._prev_close is None:
self._prev_average = sma_val
self._prev_close = close
return
# Price crosses above MA -> buy
buy_signal = self._prev_close <= self._prev_average and close > sma_val
# Price crosses below MA -> sell
sell_signal = self._prev_close >= self._prev_average and close < sma_val
if buy_signal:
if self.Position <= 0:
self.BuyMarket()
elif sell_signal:
if self.Position >= 0:
self.SellMarket()
self._prev_average = sma_val
self._prev_close = close
def CreateClone(self):
return ma_price_cross_strategy()