The MFI Histogram Strategy uses the Money Flow Index (MFI) to detect overbought and oversold conditions via configurable thresholds. The MFI combines price and volume to measure the intensity of capital inflow and outflow. When the indicator crosses above the high level from below, the strategy interprets this as rising buying pressure and enters a long position while closing any existing short. Conversely, a cross below the low level triggers a short entry and closes existing longs. Stop-loss and take-profit values are managed in ticks through the built-in protection mechanism.
The strategy operates on a user-defined candle timeframe (4 hours by default) and relies on a single indicator without additional filters. Parameters allow optimization of the MFI period, threshold levels, and risk limits, making the system adaptable to various markets and volatility regimes.
Details
Entry Criteria:
Long: MFI crosses above HighLevel from below.
Short: MFI crosses below LowLevel from above.
Long/Short: Both.
Exit Criteria:
Opposite signal generates a reversal.
Stop-loss or take-profit is reached.
Stops: StopLoss and TakeProfit in ticks.
Default Values:
MFI Period = 14
HighLevel = 60
LowLevel = 40
Candle Type = 4-hour
StopLoss = 1000 ticks
TakeProfit = 2000 ticks
Filters:
Category: Oscillator
Direction: Both
Indicators: Single
Stops: Yes
Complexity: Basic
Timeframe: Mid-term
Seasonality: No
Neural networks: No
Divergence: No
Risk level: Medium
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 histogram strategy.
/// Buys when MFI crosses above the high level.
/// Sells when MFI crosses below the low level.
/// </summary>
public class MfiHistogramStrategy : Strategy
{
private readonly StrategyParam<int> _mfiPeriod;
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<Unit> _stopLoss;
private readonly StrategyParam<Unit> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevMfi;
/// <summary>
/// Period for Money Flow Index.
/// </summary>
public int MfiPeriod
{
get => _mfiPeriod.Value;
set => _mfiPeriod.Value = value;
}
/// <summary>
/// Overbought level.
/// </summary>
public decimal HighLevel
{
get => _highLevel.Value;
set => _highLevel.Value = value;
}
/// <summary>
/// Oversold level.
/// </summary>
public decimal LowLevel
{
get => _lowLevel.Value;
set => _lowLevel.Value = value;
}
/// <summary>
/// Stop-loss value in ticks.
/// </summary>
public Unit StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take-profit value in ticks.
/// </summary>
public Unit TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize <see cref="MfiHistogramStrategy"/>.
/// </summary>
public MfiHistogramStrategy()
{
_mfiPeriod = Param(nameof(MfiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("MFI Period", "Period for Money Flow Index", "MFI");
_highLevel = Param(nameof(HighLevel), 60m)
.SetDisplay("High Level", "Overbought threshold", "MFI");
_lowLevel = Param(nameof(LowLevel), 40m)
.SetDisplay("Low Level", "Oversold threshold", "MFI");
_stopLoss = Param(nameof(StopLoss), new Unit(1000, UnitTypes.Absolute))
.SetDisplay("Stop Loss", "Stop-loss in ticks", "Risk");
_takeProfit = Param(nameof(TakeProfit), new Unit(2000, UnitTypes.Absolute))
.SetDisplay("Take Profit", "Take-profit in ticks", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMfi = 0;
}
/// <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();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
var area2 = CreateChartArea();
if (area2 != null)
DrawIndicator(area2, mfi);
}
}
private void ProcessCandle(ICandleMessage candle, decimal mfiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevMfi = mfiValue;
return;
}
// MFI crosses above high level
if (mfiValue > HighLevel && _prevMfi <= HighLevel)
{
if (Position <= 0)
BuyMarket();
}
// MFI crosses below low level
else if (mfiValue < LowLevel && _prevMfi >= LowLevel)
{
if (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_histogram_strategy(Strategy):
def __init__(self):
super(mfi_histogram_strategy, self).__init__()
self._mfi_period = self.Param("MfiPeriod", 14).SetDisplay("MFI Period", "Period for Money Flow Index", "MFI")
self._high_level = self.Param("HighLevel", 60.0).SetDisplay("High Level", "Overbought threshold", "MFI")
self._low_level = self.Param("LowLevel", 40.0).SetDisplay("Low Level", "Oversold threshold", "MFI")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Timeframe of candles", "General")
self._prev_mfi = 0.0
@property
def mfi_period(self): return self._mfi_period.Value
@property
def high_level(self): return self._high_level.Value
@property
def low_level(self): return self._low_level.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(mfi_histogram_strategy, self).OnReseted()
self._prev_mfi = 0.0
def OnStarted2(self, time):
super(mfi_histogram_strategy, self).OnStarted2(time)
mfi = MoneyFlowIndex()
mfi.Length = self.mfi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(mfi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
area2 = self.CreateChartArea()
if area2 is not None:
self.DrawIndicator(area2, mfi)
def process_candle(self, candle, mfi_value):
if candle.State != CandleStates.Finished: return
mv = float(mfi_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_mfi = mv
return
hl = float(self.high_level)
ll = float(self.low_level)
if mv > hl and self._prev_mfi <= hl:
if self.Position <= 0:
self.BuyMarket()
elif mv < ll and self._prev_mfi >= ll:
if self.Position >= 0:
self.SellMarket()
self._prev_mfi = mv
def CreateClone(self): return mfi_histogram_strategy()