Esta estrategia es una interpretación del asesor experto original de MQL5 "MA Rounding Candle". Utiliza dos medias móviles suavizadas aplicadas a los precios de apertura y cierre de las velas. La posición relativa de estas medias define el color de una vela sintética: verde cuando el cierre suavizado está por encima de la apertura, roja cuando el cierre está por debajo de la apertura y gris cuando son iguales. Un cambio de color respecto a la barra anterior genera señales de trading.
Algoritmo
Para cada vela completada, los valores de apertura y cierre se suavizan con una media móvil simple de longitud configurable.
El color de la vela se define comparando los valores suavizados:
Vela alcista – el cierre suavizado es mayor que la apertura suavizada.
Vela bajista – el cierre suavizado es menor que la apertura suavizada.
Neutral – ambos valores son iguales.
Si la vela anterior fue alcista y la actual ya no lo es, la estrategia entra en una posición larga y cierra cualquier corta.
Si la vela anterior fue bajista y la actual ya no lo es, la estrategia entra en una posición corta y cierra cualquier larga.
Parámetros
MaLength – período de las medias móviles suavizadoras (predeterminado 12).
CandleType – marco temporal de las velas procesadas.
Notas
La estrategia demuestra cómo recrear señales de un indicador personalizado usando solo las herramientas integradas de StockSharp. No se aplica stop loss ni take profit; las posiciones se invierten inmediatamente cuando aparece la señal opuesta.
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>
/// MA Rounding Candle strategy.
/// Opens a long position when a smoothed candle is bullish and a short position when it is bearish.
/// </summary>
public class MaRoundingCandleStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _openMa;
private ExponentialMovingAverage _closeMa;
private int _prevColor = 1;
public MaRoundingCandleStrategy()
{
_maLength = Param(nameof(MaLength), 12)
.SetDisplay("MA Length", "Moving average length", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame());
}
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_openMa = default;
_closeMa = default;
_prevColor = 1;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_openMa = new ExponentialMovingAverage { Length = MaLength };
_closeMa = new ExponentialMovingAverage { Length = MaLength };
Indicators.Add(_openMa);
Indicators.Add(_closeMa);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _openMa);
DrawIndicator(area, _closeMa);
DrawOwnTrades(area);
}
StartProtection(null, null);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var openVal = _openMa.Process(candle.OpenPrice, candle.OpenTime, true).ToDecimal();
var closeVal = _closeMa.Process(candle.ClosePrice, candle.OpenTime, true).ToDecimal();
if (!_openMa.IsFormed || !_closeMa.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var color = openVal < closeVal ? 2 : openVal > closeVal ? 0 : 1;
if (_prevColor == 2 && color != 2 && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (_prevColor == 0 && color != 0 && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_prevColor = color;
}
}
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 ma_rounding_candle_strategy(Strategy):
def __init__(self):
super(ma_rounding_candle_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 12) \
.SetDisplay("MA Length", "Moving average length", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._open_ma = None
self._close_ma = None
self._prev_color = 1
@property
def ma_length(self):
return self._ma_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_rounding_candle_strategy, self).OnReseted()
self._open_ma = None
self._close_ma = None
self._prev_color = 1
def OnStarted2(self, time):
super(ma_rounding_candle_strategy, self).OnStarted2(time)
self._open_ma = ExponentialMovingAverage()
self._open_ma.Length = self.ma_length
self._close_ma = ExponentialMovingAverage()
self._close_ma.Length = self.ma_length
self.Indicators.Add(self._open_ma)
self.Indicators.Add(self._close_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.DrawIndicator(area, self._open_ma)
self.DrawIndicator(area, self._close_ma)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_result = process_float(self._open_ma, candle.OpenPrice, candle.OpenTime, True)
close_result = process_float(self._close_ma, candle.ClosePrice, candle.OpenTime, True)
if not self._open_ma.IsFormed or not self._close_ma.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
open_val = float(open_result)
close_val = float(close_result)
if open_val < close_val:
color = 2
elif open_val > close_val:
color = 0
else:
color = 1
if self._prev_color == 2 and color != 2 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_color == 0 and color != 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_color = color
def CreateClone(self):
return ma_rounding_candle_strategy()