MFI 水平交叉策略
该策略利用资金流量指数(MFI)震荡指标来识别超买和超卖。当 MFI 穿越预设阈值时,策略会开仓或反转仓位。根据选择的趋势模式,它可以顺势交易或逆势交易。
默认情况下,策略监控四小时K线并计算周期为14的 MFI。当 MFI 跌破下限时开多,当 MFI 突破上限时开空。若设置为 "Against" 模式,则信号逻辑反转,在指标方向的反面进行交易。
风险控制通过内置的止损和止盈完成,参数以入场价的百分比表示。
细节
- 入场条件:
- Trend Mode: Direct:
- 多头:前一根 MFI > 下限且当前 MFI ≤ 下限。
- 空头:前一根 MFI < 上限且当前 MFI ≥ 上限。
- Trend Mode: Against:
- 多头:前一根 MFI < 上限且当前 MFI ≥ 上限。
- 空头:前一根 MFI > 下限且当前 MFI ≤ 下限。
- Trend Mode: Direct:
- 多空方向:双向。
- 出场条件:出现反向信号时反手,或由保护模块止损/止盈。
- 止损/止盈:以入场价百分比表示。
- 默认值:
K线类型= 四小时。MFI 周期= 14。下限= 40。上限= 60。止损 %= 1。止盈 %= 2。
- 过滤器:
- 分类:震荡指标
- 方向:可配置
- 指标:Money Flow Index
- 止损:是
- 复杂度:基础
- 时间框架:中期
- 季节性:否
- 神经网络:否
- 背离:否
- 风险级别:中等
备注
该实现基于 StockSharp 的高级 API。策略订阅K线数据,直接绑定 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;
}
}
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()