Desaceleración MFI
La estrategia monitorea el Índice de Flujo de Dinero (MFI) en un marco temporal superior y reacciona cuando alcanza zonas extremas. Si SeekSlowdown está habilitado, una señal se confirma solo cuando el valor del MFI cambia menos de un punto entre dos barras consecutivas. En una señal ascendente cierra posiciones cortas y opcionalmente abre una nueva posición larga; en una señal descendente cierra posiciones largas y puede abrir una corta. La gestión del riesgo se maneja mediante StartProtection.
Detalles
- Criterios de entrada:
- Señal ascendente:
MFI >= UpperThresholdy (sin verificación de desaceleración o desaceleración detectada). - Señal descendente:
MFI <= LowerThresholdy (sin verificación de desaceleración o desaceleración detectada).
- Señal ascendente:
- Largo/Corto: Ambos, dependiendo de los parámetros.
- Criterios de salida:
- La señal opuesta cierra la posición.
- Stop-loss y take-profit mediante
StopLossPercentyTakeProfitPercent.
- Stops: Sí, mediante StartProtection.
- Valores predeterminados:
MfiPeriod= 2UpperThreshold= 90LowerThreshold= 10SeekSlowdown= trueTakeProfitPercent= 2StopLossPercent= 1CandleType= marco temporal de 6 horasBuyPosOpen=BuyPosClose=SellPosOpen=SellPosClose= true
- Filtros:
- Categoría: Momentum
- Dirección: Ambos
- Indicadores: MFI
- Stops: Sí
- Complejidad: Bajo
- Marco temporal: Cualquiera
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: Opcional (verificación de desaceleración)
- Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Money Flow Index strategy that reacts to extreme values and optional slowdown.
/// Closes opposite positions and optionally opens new ones on signals.
/// Uses StartProtection for stop-loss and take-profit.
/// </summary>
public class MfiSlowdownStrategy : Strategy
{
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<decimal> _upperThreshold;
private readonly StrategyParam<decimal> _lowerThreshold;
private readonly StrategyParam<bool> _seekSlowdown;
private readonly StrategyParam<bool> _buyPosOpen;
private readonly StrategyParam<bool> _buyPosClose;
private readonly StrategyParam<bool> _sellPosOpen;
private readonly StrategyParam<bool> _sellPosClose;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevMfi;
/// <summary>
/// Period for MFI calculation.
/// </summary>
public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
/// <summary>
/// Upper threshold for MFI.
/// </summary>
public decimal UpperThreshold { get => _upperThreshold.Value; set => _upperThreshold.Value = value; }
/// <summary>
/// Lower threshold for MFI.
/// </summary>
public decimal LowerThreshold { get => _lowerThreshold.Value; set => _lowerThreshold.Value = value; }
/// <summary>
/// Require MFI slowdown before signaling.
/// </summary>
public bool SeekSlowdown { get => _seekSlowdown.Value; set => _seekSlowdown.Value = value; }
/// <summary>
/// Allow opening long positions.
/// </summary>
public bool BuyPosOpen { get => _buyPosOpen.Value; set => _buyPosOpen.Value = value; }
/// <summary>
/// Allow closing long positions.
/// </summary>
public bool BuyPosClose { get => _buyPosClose.Value; set => _buyPosClose.Value = value; }
/// <summary>
/// Allow opening short positions.
/// </summary>
public bool SellPosOpen { get => _sellPosOpen.Value; set => _sellPosOpen.Value = value; }
/// <summary>
/// Allow closing short positions.
/// </summary>
public bool SellPosClose { get => _sellPosClose.Value; set => _sellPosClose.Value = value; }
/// <summary>
/// Take-profit percentage.
/// </summary>
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initializes a new instance of the <see cref="MfiSlowdownStrategy"/> class.
/// </summary>
public MfiSlowdownStrategy()
{
_mfiPeriod = Param(nameof(MfiPeriod), 2)
.SetGreaterThanZero()
.SetDisplay("MFI Period", "Period for the MFI indicator", "Indicator");
_upperThreshold = Param(nameof(UpperThreshold), 90m)
.SetRange(0m, 100m)
.SetDisplay("Upper Threshold", "MFI upper level", "Signal");
_lowerThreshold = Param(nameof(LowerThreshold), 10m)
.SetRange(0m, 100m)
.SetDisplay("Lower Threshold", "MFI lower level", "Signal");
_seekSlowdown = Param(nameof(SeekSlowdown), true)
.SetDisplay("Seek Slowdown", "Require MFI to slow down", "Signal");
_buyPosOpen = Param(nameof(BuyPosOpen), true)
.SetDisplay("Open Long", "Allow opening long positions", "Trading");
_buyPosClose = Param(nameof(BuyPosClose), true)
.SetDisplay("Close Long", "Allow closing long positions", "Trading");
_sellPosOpen = Param(nameof(SellPosOpen), true)
.SetDisplay("Open Short", "Allow opening short positions", "Trading");
_sellPosClose = Param(nameof(SellPosClose), true)
.SetDisplay("Close Short", "Allow closing short positions", "Trading");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetRange(0m, 10m)
.SetDisplay("Take Profit %", "Take-profit percentage", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetRange(0m, 10m)
.SetDisplay("Stop Loss %", "Stop-loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(6).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMfi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var mfi = new MoneyFlowIndex { Length = MfiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(mfi, ProcessCandle)
.Start();
StartProtection(
new Unit(TakeProfitPercent, UnitTypes.Percent),
new Unit(StopLossPercent, UnitTypes.Percent)
);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, mfi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal mfiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var slowdown = _prevMfi.HasValue && Math.Abs(mfiValue - _prevMfi.Value) < 1m;
var upSignal = mfiValue >= UpperThreshold && (!SeekSlowdown || slowdown);
var downSignal = mfiValue <= LowerThreshold && (!SeekSlowdown || slowdown);
if (upSignal)
{
if (SellPosClose && Position < 0)
BuyMarket();
if (BuyPosOpen && Position <= 0)
BuyMarket();
}
else if (downSignal)
{
if (BuyPosClose && Position > 0)
SellMarket();
if (SellPosOpen && Position >= 0)
SellMarket();
}
_prevMfi = mfiValue;
}
}
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 MoneyFlowIndex
from StockSharp.Algo.Strategies import Strategy
class mfi_slowdown_strategy(Strategy):
def __init__(self):
super(mfi_slowdown_strategy, self).__init__()
self._mfi_period = self.Param("MfiPeriod", 2) \
.SetDisplay("MFI Period", "Period for the MFI indicator", "Indicator")
self._upper_threshold = self.Param("UpperThreshold", 90.0) \
.SetDisplay("Upper Threshold", "MFI upper level", "Signal")
self._lower_threshold = self.Param("LowerThreshold", 10.0) \
.SetDisplay("Lower Threshold", "MFI lower level", "Signal")
self._seek_slowdown = self.Param("SeekSlowdown", True) \
.SetDisplay("Seek Slowdown", "Require MFI to slow down", "Signal")
self._buy_pos_open = self.Param("BuyPosOpen", True) \
.SetDisplay("Open Long", "Allow opening long positions", "Trading")
self._buy_pos_close = self.Param("BuyPosClose", True) \
.SetDisplay("Close Long", "Allow closing long positions", "Trading")
self._sell_pos_open = self.Param("SellPosOpen", True) \
.SetDisplay("Open Short", "Allow opening short positions", "Trading")
self._sell_pos_close = self.Param("SellPosClose", True) \
.SetDisplay("Close Short", "Allow closing short positions", "Trading")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0) \
.SetDisplay("Take Profit %", "Take-profit percentage", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0) \
.SetDisplay("Stop Loss %", "Stop-loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(6))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_mfi = None
@property
def mfi_period(self):
return self._mfi_period.Value
@property
def upper_threshold(self):
return self._upper_threshold.Value
@property
def lower_threshold(self):
return self._lower_threshold.Value
@property
def seek_slowdown(self):
return self._seek_slowdown.Value
@property
def buy_pos_open(self):
return self._buy_pos_open.Value
@property
def buy_pos_close(self):
return self._buy_pos_close.Value
@property
def sell_pos_open(self):
return self._sell_pos_open.Value
@property
def sell_pos_close(self):
return self._sell_pos_close.Value
@property
def take_profit_percent(self):
return self._take_profit_percent.Value
@property
def stop_loss_percent(self):
return self._stop_loss_percent.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(mfi_slowdown_strategy, self).OnReseted()
self._prev_mfi = None
def OnStarted2(self, time):
super(mfi_slowdown_strategy, self).OnStarted2(time)
self._prev_mfi = None
mfi = MoneyFlowIndex()
mfi.Length = int(self.mfi_period)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(mfi, self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(float(self.take_profit_percent), UnitTypes.Percent),
stopLoss=Unit(float(self.stop_loss_percent), UnitTypes.Percent))
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, mfi)
self.DrawOwnTrades(area)
def process_candle(self, candle, mfi_value):
if candle.State != CandleStates.Finished:
return
mfi_value = float(mfi_value)
slowdown = self._prev_mfi is not None and abs(mfi_value - self._prev_mfi) < 1.0
ut = float(self.upper_threshold)
lt = float(self.lower_threshold)
up_signal = mfi_value >= ut and (not self.seek_slowdown or slowdown)
down_signal = mfi_value <= lt and (not self.seek_slowdown or slowdown)
if up_signal:
if self.sell_pos_close and self.Position < 0:
self.BuyMarket()
if self.buy_pos_open and self.Position <= 0:
self.BuyMarket()
elif down_signal:
if self.buy_pos_close and self.Position > 0:
self.SellMarket()
if self.sell_pos_open and self.Position >= 0:
self.SellMarket()
self._prev_mfi = mfi_value
def CreateClone(self):
return mfi_slowdown_strategy()