Auf GitHub ansehen

MFI Histogram Strategy

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;
	}
}