Estrategia de cuadrícula TenPointThree MACD
Descripción general
Esta estrategia es una adaptación de C# del asesor experto MetaTrader 10p3v003 (10point3.mq4). Combina un disparador de cruce MACD con un motor de cuadrícula martingala. La lógica original se replicó utilizando el nivel alto de StockSharp API con los siguientes comportamientos clave:
- MACD lógica de señal: una dirección comercial se determina cuando la línea principal MACD cruza la línea de señal en la barra desplazada (
SignalShift). Las entradas largas requieren que el valor de la señal anterior esté por debajo de -TradingRangePips, que el valor actual MACD permanezca por debajo de cero y viceversa para las entradas cortas. Opcionalmente, las señales se pueden invertir a través de ReverseSignal.
- Capas de cuadrícula: después de abrir la primera posición, las entradas adicionales en la misma dirección solo se permiten una vez que el precio se mueve con respecto al último llenado en al menos
GridStepPips. Cada nueva pierna multiplica el volumen por LotMultiplier (o por 1.5 si MaxTrades > 12), imitando la escala de martingala de MQL4.
- Protección contra riesgos: el tramo más reciente se cierra y no se agregan más entradas cuando
OrdersToProtect o más operaciones están activas y la ganancia flotante excede el umbral monetario. El umbral se basa en el porcentaje de riesgo configurado (administración del dinero habilitada) o en la heurística del tamaño del contrato (administración del dinero deshabilitada).
- Salidas por tramo: cada tramo rastrea su propia toma de ganancias, stop-loss virtual y stop dinámico. La distancia de parada coincide con la fórmula original:
InitialStopPips + (MaxTrades - existingOrders) * GridStepPips. El seguimiento se activa solo después de que el precio se mueve TrailingStopPips + GridStepPips a favor de la posición y cierra el tramo cuando el precio retrocede TrailingStopPips.
- Filtro de sesión: cuando
UseTimeFilter está habilitado, no se inician nuevas cuadrículas mientras el tiempo de la vela esté estrictamente entre StopHour y StartHour, lo que reproduce la guardia de "zona horaria de peligro" del script.
Todas las conversiones de dinero utilizan los metadatos PriceStep/StepPrice de la seguridad. Si el intercambio no expone un tamaño de contrato, se aplica un valor alternativo de 100000, que coincide con el supuesto original de Forex.
Parámetros
| Nombre |
Descripción |
CandleType |
Suscripción de vela utilizada para el procesamiento de MACD (predeterminado: período de tiempo de 30 minutos). |
Volume |
Tamaño de lote base para el primer pedido de cuadrícula. |
TakeProfitPips |
Distance in pips for each leg's take-profit (0 disables). |
InitialStopPips |
Distancia de parada base en pips. La parada real crece con el número de espacios libres en la parrilla. |
TrailingStopPips |
Distancia del trailing stop en pips aplicada después de que el tramo sea suficientemente rentable (0 inhabilitaciones). |
MaxTrades |
Maximum number of simultaneous martingale entries. |
LotMultiplier |
Multiplier applied to the volume of each additional grid leg (overridden to 1.5 when MaxTrades > 12). |
GridStepPips |
Minimum adverse price move (in pips) required before opening the next grid entry. |
OrdersToProtect |
Minimum number of active legs before the floating-profit protection can close the latest trade. |
UseMoneyManagement |
Enables dynamic lot calculation based on account equity. |
AccountType |
Selecciona la fórmula de riesgo: 0 – Estándar (capital / 10.000); 1 – Normal (capital / 100.000); 2 – Nano (capital / 1000). |
RiskPercent |
Percentage of equity used when money management is enabled. |
ReverseSignal |
Invierte señales MACD largas/cortas. |
FastEmaLength, SlowEmaLength, SignalLength |
MACD períodos (26/12/9 de forma predeterminada). |
SignalShift |
Number of closed bars back used for the crossover check (default: 1). |
TradingRangePips |
MACD signal band (in pips) that must be breached before a crossover is accepted. |
UseTimeFilter |
Enables the session guard based on StopHour/StartHour. |
StopHour, StartHour |
Exclusive range that blocks the creation of a new grid when UseTimeFilter is true. |
notas de gestión del dinero
Cuando UseMoneyManagement está deshabilitado, el lote base (Volume) se utiliza directamente. De lo contrario, el EA calcula el tamaño del lote a partir del valor actual utilizando las mismas fórmulas que el EA original:
- Tipo de cuenta 0:
Ceil(risk% * equity / 10,000) / 10
- Tipo de cuenta 1:
risk% * equity / 100,000
- Tipo de cuenta 2:
risk% * equity / 1,000
Volumes are normalised with Security.VolumeStep, then capped by Security.MinVolume/MaxVolume.
Flujo de trabajo de ejecución
- Subscribe to the configured candle stream and feed the MACD indicator through
BindEx.
- On each finished candle, update trailing/stop logic for active legs.
- Cuando se activan las reglas de cruce MACD, asegúrese de que el filtro de sesión permita el comercio, que la dirección de la cuadrícula coincida con la posición existente y que el precio se haya movido
GridStepPips con respecto al último llenado.
- Calculate the next leg volume using the martingale multiplier and send a market order.
- Monitorear las ganancias flotantes; una vez que se alcanza el umbral de protección, cierre el tramo más nuevo y haga una pausa hasta la siguiente vela.
Notas de conversión
- Todos los comentarios se han reescrito en inglés según sea necesario.
- Se utiliza StockSharp API de alto nivel (velas +
BindEx). Se evita el acceso directo al valor del indicador.
- Los cálculos de beneficios flotantes se basan en
PriceStep/StepPrice. For exotic instruments make sure these fields are filled.
- La estrategia mantiene el estado por tramo internamente para emular la gestión de pedidos de MQL4, porque StockSharp agrega posiciones de forma predeterminada.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// 10point3 MACD Grid: EMA crossover with RSI filter and ATR stops.
/// </summary>
public class TenPointThreeMacdGridStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public TenPointThreeMacdGridStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 12)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 26)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fastEma, slowEma, rsi, atr, 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 fastVal, decimal slowVal, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0) { _prevFast = fastVal; _prevSlow = slowVal; return; }
var close = candle.ClosePrice;
if (Position > 0)
{
if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
}
_prevFast = fastVal; _prevSlow = slowVal;
}
}
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, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class ten_point_three_macd_grid_strategy(Strategy):
"""EMA crossover with RSI filter and ATR stops."""
def __init__(self):
super(ten_point_three_macd_grid_strategy, self).__init__()
self._fast_ema = self.Param("FastEmaLength", 12).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_ema = self.Param("SlowEmaLength", 26).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetDisplay("RSI Length", "RSI period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(ten_point_three_macd_grid_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
def OnStarted2(self, time):
super(ten_point_three_macd_grid_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
fast = ExponentialMovingAverage()
fast.Length = self._fast_ema.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_ema.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, rsi, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0 or atr_val <= 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
if self.Position > 0:
if (fast_val < slow_val and self._prev_fast >= self._prev_slow) or close <= self._entry_price - atr_val * 2:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
if (fast_val > slow_val and self._prev_fast <= self._prev_slow) or close >= self._entry_price + atr_val * 2:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0:
if fast_val > slow_val and self._prev_fast <= self._prev_slow and rsi_val > 50:
self._entry_price = close
self.BuyMarket()
elif fast_val < slow_val and self._prev_fast >= self._prev_slow and rsi_val < 50:
self._entry_price = close
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return ten_point_three_macd_grid_strategy()