Стратегия использует осциллятор Money Flow Index (MFI) для определения перекупленности и перепроданности. Когда MFI пересекает заданные пороговые уровни, стратегия открывает или разворачивает позиции. В зависимости от выбранного режима она может торговать по направлению пересечения или против него.
По умолчанию анализируются четырёхчасовые свечи и рассчитывается MFI с периодом 14. Стратегия открывает длинную позицию, когда MFI опускается ниже нижнего уровня, и короткую позицию, когда поднимается выше верхнего уровня. В режиме "Against" логика входа инвертируется и торгуется против направления индикатора.
Управление риском осуществляется с помощью стоп-лосса и тейк-профита, задаваемых в процентах от цены входа.
Подробности
Условия входа:
Режим Direct:
Long: Предыдущее значение MFI > нижний уровень и текущее значение MFI ≤ нижний уровень.
Short: Предыдущее значение MFI < верхний уровень и текущее значение MFI ≥ верхний уровень.
Режим Against:
Long: Предыдущее значение MFI < верхний уровень и текущее значение MFI ≥ верхний уровень.
Short: Предыдущее значение MFI > нижний уровень и текущее значение MFI ≤ нижний уровень.
Long/Short: Оба направления.
Условия выхода: Позиция разворачивается при появлении противоположного сигнала или закрывается модулем защиты.
Стопы: Стоп-лосс и тейк-профит в процентах от цены входа.
Значения по умолчанию:
Тип свечей = четырёхчасовые.
Период MFI = 14.
Нижний уровень = 40.
Верхний уровень = 60.
Стоп-лосс % = 1.
Тейк-профит % = 2.
Фильтры:
Категория: Осциллятор
Направление: Настраивается
Индикаторы: Money Flow Index
Стопы: Да
Сложность: Базовая
Таймфрейм: Среднесрочный
Сезонность: Нет
Нейросети: Нет
Дивергенция: Нет
Уровень риска: Средний
Примечания
Реализация использует высокоуровневый API StockSharp. Стратегия подписывается на данные свечей, связывает индикатор MFI и исполняет рыночные заявки при выполнении условий. Модуль защиты инициализируется один раз при старте и автоматически управляет риском.
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;
}
}