Esta estrategia de ejemplo es un port simplificado del script MQL4 "Tester v0.14" originalmente diseñado para EURUSD en el marco temporal H4.
Lógica
Calcula una media móvil simple de 14 períodos y MACD.
Genera una señal de compra cuando el precio de cierre está por encima de la SMA y el MACD es positivo.
Genera una señal de venta cuando el precio de cierre está por debajo de la SMA y el MACD es negativo.
Después de abrir una orden, la posición se cierra tras un número configurable de barras.
Este port utiliza la API de alto nivel de StockSharp, basándose en SubscribeCandles y Bind para recibir los valores del indicador.
Parámetros
MinSignSum – número mínimo de señales requeridas para abrir una posición.
Risk – porcentaje del saldo de la cuenta utilizado para la gestión de dinero.
TakeProfit / StopLoss – niveles fijos en puntos.
BarsNumber – número de barras para mantener una posición abierta.
CandleType – serie de velas utilizada (predeterminado: 4H).
Notas
El archivo MQL original contenía cientos de combinaciones de reglas. Este ejemplo en C# ilustra la estructura usando un conjunto reducido de reglas para mayor claridad.
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>
/// Tester strategy using SMA and MACD for entries.
/// Closes after specified number of bars.
/// </summary>
public class TesterV014Strategy : Strategy
{
private readonly StrategyParam<int> _barsNumber;
private readonly StrategyParam<DataType> _candleType;
private int _barsCounter;
private bool _positionOpened;
public int BarsNumber { get => _barsNumber.Value; set => _barsNumber.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TesterV014Strategy()
{
_barsNumber = Param(nameof(BarsNumber), 3)
.SetGreaterThanZero()
.SetDisplay("Bars Number", "Holding period in bars", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_barsCounter = 0;
_positionOpened = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = 14 };
var macd = new MovingAverageConvergenceDivergence();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, macd, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaVal, decimal macdVal)
{
if (candle.State != CandleStates.Finished)
return;
// Close after specified bars
if (_positionOpened)
{
_barsCounter++;
if (_barsCounter >= BarsNumber)
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
_positionOpened = false;
_barsCounter = 0;
}
}
// Entry
if (Position == 0 && !_positionOpened)
{
if (candle.ClosePrice > smaVal && macdVal > 0)
{
BuyMarket();
_barsCounter = 0;
_positionOpened = true;
}
else if (candle.ClosePrice < smaVal && macdVal < 0)
{
SellMarket();
_barsCounter = 0;
_positionOpened = true;
}
}
}
}
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 MovingAverageConvergenceDivergence, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class tester_v014_strategy(Strategy):
def __init__(self):
super(tester_v014_strategy, self).__init__()
self._bars_number = self.Param("BarsNumber", 3) \
.SetDisplay("Bars Number", "Holding period in bars", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._bars_counter = 0
self._position_opened = False
@property
def bars_number(self):
return self._bars_number.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(tester_v014_strategy, self).OnReseted()
self._bars_counter = 0
self._position_opened = False
def OnStarted2(self, time):
super(tester_v014_strategy, self).OnStarted2(time)
sma = SimpleMovingAverage()
sma.Length = 14
macd = MovingAverageConvergenceDivergence()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, macd, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, sma_val, macd_val):
if candle.State != CandleStates.Finished:
return
# Close after specified bars
if self._position_opened:
self._bars_counter += 1
if self._bars_counter >= self.bars_number:
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._position_opened = False
self._bars_counter = 0
# Entry
if self.Position == 0 and not self._position_opened:
if candle.ClosePrice > sma_val and macd_val > 0:
self.BuyMarket()
self._bars_counter = 0
self._position_opened = True
elif candle.ClosePrice < sma_val and macd_val < 0:
self.SellMarket()
self._bars_counter = 0
self._position_opened = True
def CreateClone(self):
return tester_v014_strategy()