Estratégia de Cruzamento de Nível MFI
Esta estratégia usa o oscilador Money Flow Index (MFI) para identificar condições de sobrecompra e sobrevenda. Quando o MFI cruza níveis de limite predefinidos, a estratégia entra ou reverte posições. Pode operar na direção do cruzamento ou na direção oposta, dependendo do modo de tendência selecionado.
A configuração padrão monitora velas de quatro horas e avalia o MFI de 14 períodos. A estratégia abre uma posição comprada quando o MFI cai abaixo do limite inferior e uma posição vendida quando sobe acima do limite superior. Quando definido para o modo "Against", a lógica de entrada é invertida para negociar contra a direção do indicador.
O gerenciamento de risco é feito através de parâmetros integrados de stop-loss e take-profit expressos como porcentagens do preço de entrada.
Detalhes
- Critérios de entrada:
- Trend Mode: Direct:
- Comprado: MFI anterior > nível baixo e MFI atual ≤ nível baixo.
- Vendido: MFI anterior < nível alto e MFI atual ≥ nível alto.
- Trend Mode: Against:
- Comprado: MFI anterior < nível alto e MFI atual ≥ nível alto.
- Vendido: MFI anterior > nível baixo e MFI atual ≤ nível baixo.
- Comprado/Vendido: Ambas as direções.
- Critérios de saída: A posição é revertida quando o sinal oposto aparece ou fechada pelo módulo de proteção.
- Stops: Stop-loss e take-profit expressos em percentual do preço de entrada.
- Valores padrão:
Candle Type = velas de 4 horas.
MFI Period = 14.
Low Level = 40.
High Level = 60.
Stop Loss % = 1.
Take Profit % = 2.
- Filtros:
- Categoria: Oscilador
- Direção: Configurável
- Indicadores: Money Flow Index
- Stops: Sim
- Complexidade: Básico
- Período: Médio prazo
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Médio
Notas
Esta implementação depende da API de alto nível do StockSharp. Assina dados de velas, vincula o indicador MFI diretamente e executa ordens de mercado quando as condições de cruzamento são atendidas. A proteção de posição é inicializada uma vez na inicialização para gerenciar o risco automaticamente.
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 based strategy that opens positions when the indicator crosses predefined levels.
/// The strategy can trade in the direction of the crossing or in the opposite direction based on Trend Mode.
/// </summary>
public class MfiLevelCrossStrategy : Strategy
{
public enum TrendModes
{
Direct,
Against
}
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<TrendModes> _trend;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private decimal _prevMfi;
private bool _isFirst;
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Period for the Money Flow Index indicator.
/// </summary>
public int MfiPeriod { get => _mfiPeriod.Value; set => _mfiPeriod.Value = value; }
/// <summary>
/// Oversold threshold for the MFI.
/// </summary>
public decimal LowLevel { get => _lowLevel.Value; set => _lowLevel.Value = value; }
/// <summary>
/// Overbought threshold for the MFI.
/// </summary>
public decimal HighLevel { get => _highLevel.Value; set => _highLevel.Value = value; }
/// <summary>
/// Trading mode selection.
/// </summary>
public TrendModes Trend { get => _trend.Value; set => _trend.Value = value; }
/// <summary>
/// Stop loss in percent from entry price.
/// </summary>
public decimal StopLossPercent { get => _stopLossPercent.Value; set => _stopLossPercent.Value = value; }
/// <summary>
/// Take profit in percent from entry price.
/// </summary>
public decimal TakeProfitPercent { get => _takeProfitPercent.Value; set => _takeProfitPercent.Value = value; }
/// <summary>
/// Initializes a new instance of the <see cref="MfiLevelCrossStrategy"/>.
/// </summary>
public MfiLevelCrossStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of candles used", "General");
_mfiPeriod = Param(nameof(MfiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("MFI Period", "Period of the Money Flow Index indicator", "Indicator");
_lowLevel = Param(nameof(LowLevel), 30m)
.SetRange(0m, 100m)
.SetDisplay("Low Level", "Oversold threshold for MFI", "Signal");
_highLevel = Param(nameof(HighLevel), 70m)
.SetRange(0m, 100m)
.SetDisplay("High Level", "Overbought threshold for MFI", "Signal");
_trend = Param(nameof(Trend), TrendModes.Direct)
.SetDisplay("Trend Mode", "Trade with trend (Direct) or against it (Against)", "Signal");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetRange(0m, 100m)
.SetDisplay("Stop Loss %", "Stop loss as percent from entry price", "Risk");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetRange(0m, 100m)
.SetDisplay("Take Profit %", "Take profit as percent from entry price", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMfi = 0m;
_isFirst = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(
new Unit(TakeProfitPercent, UnitTypes.Percent),
new Unit(StopLossPercent, UnitTypes.Percent));
var mfi = new MoneyFlowIndex { Length = MfiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(mfi, ProcessCandle)
.Start();
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 (_isFirst)
{
_prevMfi = mfiValue;
_isFirst = false;
return;
}
var crossBelowLow = _prevMfi > LowLevel && mfiValue <= LowLevel;
var crossAboveHigh = _prevMfi < HighLevel && mfiValue >= HighLevel;
if (Trend == TrendModes.Direct)
{
if (crossBelowLow && Position <= 0)
BuyMarket();
else if (crossAboveHigh && Position >= 0)
SellMarket();
}
else
{
if (crossBelowLow && Position >= 0)
SellMarket();
else if (crossAboveHigh && Position <= 0)
BuyMarket();
}
_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_level_cross_strategy(Strategy):
DIRECT = 0
AGAINST = 1
def __init__(self):
super(mfi_level_cross_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._mfi_period = self.Param("MfiPeriod", 14)
self._low_level = self.Param("LowLevel", 30.0)
self._high_level = self.Param("HighLevel", 70.0)
self._trend = self.Param("Trend", 0)
self._stop_loss_percent = self.Param("StopLossPercent", 1.0)
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0)
self._prev_mfi = 0.0
self._is_first = True
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MfiPeriod(self):
return self._mfi_period.Value
@MfiPeriod.setter
def MfiPeriod(self, value):
self._mfi_period.Value = value
@property
def LowLevel(self):
return self._low_level.Value
@LowLevel.setter
def LowLevel(self, value):
self._low_level.Value = value
@property
def HighLevel(self):
return self._high_level.Value
@HighLevel.setter
def HighLevel(self, value):
self._high_level.Value = value
@property
def Trend(self):
return self._trend.Value
@Trend.setter
def Trend(self, value):
self._trend.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 TakeProfitPercent(self):
return self._take_profit_percent.Value
@TakeProfitPercent.setter
def TakeProfitPercent(self, value):
self._take_profit_percent.Value = value
def OnStarted2(self, time):
super(mfi_level_cross_strategy, self).OnStarted2(time)
self._prev_mfi = 0.0
self._is_first = True
self.StartProtection(
Unit(self.TakeProfitPercent, UnitTypes.Percent),
Unit(self.StopLossPercent, UnitTypes.Percent))
mfi = MoneyFlowIndex()
mfi.Length = self.MfiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(mfi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, mfi_value):
if candle.State != CandleStates.Finished:
return
mfi_val = float(mfi_value)
if self._is_first:
self._prev_mfi = mfi_val
self._is_first = False
return
cross_below_low = self._prev_mfi > float(self.LowLevel) and mfi_val <= float(self.LowLevel)
cross_above_high = self._prev_mfi < float(self.HighLevel) and mfi_val >= float(self.HighLevel)
if self.Trend == self.DIRECT:
if cross_below_low and self.Position <= 0:
self.BuyMarket()
elif cross_above_high and self.Position >= 0:
self.SellMarket()
else:
if cross_below_low and self.Position >= 0:
self.SellMarket()
elif cross_above_high and self.Position <= 0:
self.BuyMarket()
self._prev_mfi = mfi_val
def OnReseted(self):
super(mfi_level_cross_strategy, self).OnReseted()
self._prev_mfi = 0.0
self._is_first = True
def CreateClone(self):
return mfi_level_cross_strategy()