MFIレベルクロス戦略
この戦略はMoney Flow Index(MFI)オシレーターを使用して買われすぎと売られすぎの状態を識別します。MFIが事前定義された閾値レベルをクロスするとき、戦略はポジションをエントリーまたは反転させます。選択されたトレンドモードに応じて、クロスの方向または反対方向で動作できます。
デフォルト設定は4時間ローソク足を監視し、14期間のMFIを評価します。MFIが下限閾値を下回るとロングポジションをオープンし、上限閾値を上回るとショートポジションをオープンします。"Against"モードに設定すると、エントリーロジックが逆転し、インジケーター方向に逆らって取引します。
リスク管理はエントリー価格からのパーセンテージで表される組み込みのストップロスとテイクプロフィットパラメーターを通じて処理されます。
詳細
- エントリー条件:
- Trend Mode: Direct:
- ロング: 前のMFI > 低レベル、現在のMFI ≤ 低レベル。
- ショート: 前のMFI < 高レベル、現在のMFI ≥ 高レベル。
- Trend Mode: Against:
- ロング: 前のMFI < 高レベル、現在のMFI ≥ 高レベル。
- ショート: 前のMFI > 低レベル、現在のMFI ≤ 低レベル。
- Trend Mode: Direct:
- ロング/ショート: 両方向。
- エグジット条件: 反対のシグナルが現れるとポジションが反転され、または保護モジュールによってクローズされます。
- ストップ: ストップロスとテイクプロフィットはエントリー価格からのパーセントで表されます。
- デフォルト値:
Candle Type= 4時間ローソク足。MFI Period= 14。Low Level= 40。High Level= 60。Stop Loss %= 1。Take Profit %= 2。
- フィルター:
- カテゴリ: オシレーター
- 方向: 設定可能
- インジケーター: Money Flow Index
- ストップ: はい
- 複雑さ: 基本
- 時間軸: 中期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
注記
この実装はStockSharpの高レベルAPIに依存しています。ローソク足データを購読し、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()