Estrategia de Ajuste Fino de MA
Esta estrategia monitorea la pendiente de una media móvil simple. Después de dos barras consecutivas en una dirección, un cambio de dirección de la media móvil dispara una entrada. Un giro al alza después de una bajada abre una posición larga, mientras que un giro a la baja después de un alza abre una posición corta. Las señales opuestas cierran las operaciones existentes.
El sistema fue convertido del asesor MQL "Exp_FineTuningMA" y reemplaza el indicador personalizado original con una media móvil simple estándar para mayor claridad.
Detalles
- Criterios de entrada: La MA cambia de dirección después de dos barras.
- Largo/Corto: Ambos.
- Criterios de salida: Señal opuesta o stop.
- Stops: Sí, basados en porcentaje.
- Valores predeterminados:
MaLength = 10
TakeProfitPercent = 1
StopLossPercent = 1
CandleType = TimeSpan.FromHours(4)
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: SMA
- Stops: Sí
- Complejidad: Intermedio
- Marco temporal: Swing / 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>
/// Fine Tuning MA strategy. Opens positions when the moving average changes direction.
/// </summary>
public class FineTuningMaStrategy : Strategy
{
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal _prev1;
private decimal _prev2;
private int _candleCount;
public int MaLength { get => _maLength.Value; set => _maLength.Value = value; }
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FineTuningMaStrategy()
{
_maLength = Param(nameof(MaLength), 20)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Length of the moving average", "Parameters");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 1m)
.SetDisplay("Take Profit, %", "Take profit level in percent", "Protection");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetDisplay("Stop Loss, %", "Stop loss level in percent", "Protection");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for calculations", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prev1 = default;
_prev2 = default;
_candleCount = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ma = new ExponentialMovingAverage { Length = MaLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ma, ProcessCandle).Start();
StartProtection(
new Unit(StopLossPercent, UnitTypes.Percent),
new Unit(TakeProfitPercent, UnitTypes.Percent));
}
private void ProcessCandle(ICandleMessage candle, decimal ma)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
_candleCount++;
if (_candleCount <= 2)
{
_prev2 = _prev1;
_prev1 = ma;
return;
}
var wasRising = _prev1 > _prev2;
var wasFalling = _prev1 < _prev2;
if (wasRising && ma > _prev1 && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (wasFalling && ma < _prev1 && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prev2 = _prev1;
_prev1 = ma;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fine_tuning_ma_strategy(Strategy):
def __init__(self):
super(fine_tuning_ma_strategy, self).__init__()
self._ma_length = self.Param("MaLength", 20) \
.SetDisplay("MA Length", "Length of the moving average", "Parameters")
self._take_profit_percent = self.Param("TakeProfitPercent", 1.0) \
.SetDisplay("Take Profit, %", "Take profit level in percent", "Protection")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0) \
.SetDisplay("Stop Loss, %", "Stop loss level in percent", "Protection")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles for calculations", "Parameters")
self._prev1 = 0.0
self._prev2 = 0.0
self._candle_count = 0
@property
def MaLength(self):
return self._ma_length.Value
@MaLength.setter
def MaLength(self, value):
self._ma_length.Value = value
@property
def TakeProfitPercent(self):
return self._take_profit_percent.Value
@TakeProfitPercent.setter
def TakeProfitPercent(self, value):
self._take_profit_percent.Value = value
@property
def StopLossPercent(self):
return self._stop_loss_percent.Value
@StopLossPercent.setter
def StopLossPercent(self, value):
self._stop_loss_percent.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(fine_tuning_ma_strategy, self).OnStarted2(time)
ma = ExponentialMovingAverage()
ma.Length = self.MaLength
self.SubscribeCandles(self.CandleType) \
.Bind(ma, self.ProcessCandle) \
.Start()
self.StartProtection(
stopLoss=Unit(self.StopLossPercent, UnitTypes.Percent),
takeProfit=Unit(self.TakeProfitPercent, UnitTypes.Percent)
)
def ProcessCandle(self, candle, ma_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
val = float(ma_value)
self._candle_count += 1
if self._candle_count <= 2:
self._prev2 = self._prev1
self._prev1 = val
return
was_rising = self._prev1 > self._prev2
was_falling = self._prev1 < self._prev2
if was_rising and val > self._prev1 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif was_falling and val < self._prev1 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev2 = self._prev1
self._prev1 = val
def OnReseted(self):
super(fine_tuning_ma_strategy, self).OnReseted()
self._prev1 = 0.0
self._prev2 = 0.0
self._candle_count = 0
def CreateClone(self):
return fine_tuning_ma_strategy()