Открыть на GitHub

Стратегия MFI Histogram

Стратегия MFI Histogram использует индекс денежного потока (MFI) для определения зон перекупленности и перепроданности по настраиваемым уровням. MFI объединяет цену и объём, оценивая силу притока и оттока капитала. Когда индикатор пересекает сверху заданный верхний уровень, стратегия рассматривает это как усиление покупок, открывает длинную позицию и закрывает короткую. При пересечении нижнего уровня снизу выполняется вход в короткую и закрытие длинных. Стоп-лосс и тейк-профит задаются в тиках и обрабатываются встроенной системой защиты.

Стратегия работает на свечах выбранного таймфрейма (по умолчанию 4 часа) и использует только один индикатор без дополнительных фильтров. Параметры позволяют оптимизировать период MFI, пороговые уровни и значения рисков, что делает систему гибкой для разных рынков и режимов волатильности.

Детали

  • Критерии входа:
    • Длинная позиция: MFI пересекает HighLevel снизу вверх.
    • Короткая позиция: MFI пересекает LowLevel сверху вниз.
  • Длинные/короткие: обе стороны.
  • Критерии выхода:
    • Обратный сигнал разворачивает позицию.
    • Достижение стоп-лосса или тейк-профита.
  • Стопы: StopLoss и TakeProfit в тиках.
  • Значения по умолчанию:
    • MFI Period = 14
    • HighLevel = 60
    • LowLevel = 40
    • Candle Type = 4 часа
    • StopLoss = 1000 тиков
    • TakeProfit = 2000 тиков
  • Фильтры:
    • Категория: Осциллятор
    • Направление: Обе
    • Индикаторы: Один
    • Стопы: Да
    • Сложность: Базовая
    • Таймфрейм: Среднесрочный
    • Сезонность: Нет
    • Нейросети: Нет
    • Дивергенция: Нет
    • Уровень риска: Средний
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;
	}
}