MFS三蜡烛形态策略
该策略在下跌趋势中寻找由三根蜡烛组成的看涨反转序列。它检测一根大阳线作为“点火”蜡烛,随后出现一根较小的回调阴线,最后是收盘价高于回调高点的确认阳线。趋势过滤要求长周期SMA>中周期SMA>短周期SMA,并且点火蜡烛的收盘价低于短期SMA。
当形态出现时策略开多仓,并在点火蜡烛的最低价设置止损,同时根据指定的风险回报比设置止盈。
详情
- 入场条件:点火、回调和确认蜡烛,在下行趋势中。
- 多空方向:仅做多。
- 出场条件:点火最低价止损或风险回报比止盈。
- 止损止盈:是,包含止损与止盈。
- 默认值:
CandleType= 15 分钟SmaShortLength= 20SmaMedLength= 50SmaLongLength= 200IgniteMultiplier= 3MaxPullbackSize= 0.33MinConfirmationSize= 0.33RiskReward= 2
- 筛选:
- 类别:形态
- 方向:做多
- 指标:蜡烛图、移动平均
- 止损:是
- 复杂度:中等
- 时间框架:日内
- 季节性:否
- 神经网络:否
- 背离:否
- 风险等级:中等
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Mfs3BarsPatternStrategy : Strategy
{
private readonly StrategyParam<int> _smaLength;
private readonly StrategyParam<decimal> _riskReward;
private readonly StrategyParam<int> _signalCooldownBars;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _sma;
private ICandleMessage _prev1;
private ICandleMessage _prev2;
private decimal _stopPrice;
private decimal _takePrice;
private int _barsFromSignal;
public int SmaLength { get => _smaLength.Value; set => _smaLength.Value = value; }
public decimal RiskReward { get => _riskReward.Value; set => _riskReward.Value = value; }
public int SignalCooldownBars { get => _signalCooldownBars.Value; set => _signalCooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Mfs3BarsPatternStrategy()
{
_smaLength = Param(nameof(SmaLength), 30)
.SetGreaterThanZero()
.SetDisplay("SMA Length", "SMA period", "General");
_riskReward = Param(nameof(RiskReward), 2.5m)
.SetGreaterThanZero()
.SetDisplay("Risk Reward", "Target reward to risk ratio", "General");
_signalCooldownBars = Param(nameof(SignalCooldownBars), 50)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown Bars", "Minimum bars between entries", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candles timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sma = null;
_prev1 = null;
_prev2 = null;
_stopPrice = 0m;
_takePrice = 0m;
_barsFromSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_sma = new SimpleMovingAverage { Length = SmaLength };
_prev1 = null;
_prev2 = null;
_stopPrice = 0;
_takePrice = 0;
_barsFromSignal = SignalCooldownBars;
var dummyEma = new ExponentialMovingAverage { Length = 10 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(_sma, dummyEma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue, decimal dummyValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_sma.IsFormed || _prev1 == null || _prev2 == null)
{
_prev2 = _prev1;
_prev1 = candle;
return;
}
// 3-bar pattern: big bullish bar, small pullback, bullish confirmation
var bar1Bullish = _prev2.ClosePrice > _prev2.OpenPrice;
var bar1Body = Math.Abs(_prev2.ClosePrice - _prev2.OpenPrice);
var bar2Bearish = _prev1.ClosePrice < _prev1.OpenPrice;
var bar2Body = Math.Abs(_prev1.ClosePrice - _prev1.OpenPrice);
var bar3Bullish = candle.ClosePrice > candle.OpenPrice;
var bodyPercent = candle.ClosePrice > 0m ? bar1Body / candle.ClosePrice * 100m : 0m;
var strongBar1 = bodyPercent >= 0.05m;
var confirmation = candle.ClosePrice > _prev1.HighPrice;
var pattern = bar1Bullish && strongBar1 && bar2Bearish && bar2Body < bar1Body * 0.5m && bar3Bullish && confirmation;
_barsFromSignal++;
if (_barsFromSignal >= SignalCooldownBars && pattern && Position == 0)
{
BuyMarket();
_stopPrice = _prev2.LowPrice;
_takePrice = candle.ClosePrice + (candle.ClosePrice - _stopPrice) * RiskReward;
_barsFromSignal = 0;
}
if (Position > 0)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
SellMarket();
}
_prev2 = _prev1;
_prev1 = candle;
}
}
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
from StockSharp.Algo.Indicators import SimpleMovingAverage, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class mfs_3_bars_pattern_strategy(Strategy):
def __init__(self):
super(mfs_3_bars_pattern_strategy, self).__init__()
self._sma_length = self.Param("SmaLength", 30) \
.SetGreaterThanZero() \
.SetDisplay("SMA Length", "SMA period", "General")
self._risk_reward = self.Param("RiskReward", 2.5) \
.SetGreaterThanZero() \
.SetDisplay("Risk Reward", "Target reward to risk ratio", "General")
self._signal_cooldown_bars = self.Param("SignalCooldownBars", 50) \
.SetGreaterThanZero() \
.SetDisplay("Signal Cooldown Bars", "Minimum bars between entries", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candles timeframe", "General")
self._prev1_close = 0.0
self._prev1_open = 0.0
self._prev1_high = 0.0
self._prev1_low = 0.0
self._prev2_close = 0.0
self._prev2_open = 0.0
self._prev2_high = 0.0
self._prev2_low = 0.0
self._bar_count = 0
self._stop_price = 0.0
self._take_price = 0.0
self._bars_from_signal = 0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(mfs_3_bars_pattern_strategy, self).OnReseted()
self._prev1_close = 0.0
self._prev1_open = 0.0
self._prev1_high = 0.0
self._prev1_low = 0.0
self._prev2_close = 0.0
self._prev2_open = 0.0
self._prev2_high = 0.0
self._prev2_low = 0.0
self._bar_count = 0
self._stop_price = 0.0
self._take_price = 0.0
self._bars_from_signal = 0
def OnStarted2(self, time):
super(mfs_3_bars_pattern_strategy, self).OnStarted2(time)
self._bar_count = 0
self._stop_price = 0.0
self._take_price = 0.0
self._bars_from_signal = self._signal_cooldown_bars.Value
self._sma = SimpleMovingAverage()
self._sma.Length = self._sma_length.Value
dummy = ExponentialMovingAverage()
dummy.Length = 10
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._sma, dummy, self.OnProcess).Start()
def OnProcess(self, candle, sma_value, dummy_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
opn = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if not self._sma.IsFormed or self._bar_count < 2:
self._prev2_close = self._prev1_close
self._prev2_open = self._prev1_open
self._prev2_high = self._prev1_high
self._prev2_low = self._prev1_low
self._prev1_close = close
self._prev1_open = opn
self._prev1_high = high
self._prev1_low = low
self._bar_count += 1
return
bar1_bullish = self._prev2_close > self._prev2_open
bar1_body = abs(self._prev2_close - self._prev2_open)
bar2_bearish = self._prev1_close < self._prev1_open
bar2_body = abs(self._prev1_close - self._prev1_open)
bar3_bullish = close > opn
body_pct = bar1_body / close * 100.0 if close > 0.0 else 0.0
strong_bar1 = body_pct >= 0.05
confirmation = close > self._prev1_high
pattern = bar1_bullish and strong_bar1 and bar2_bearish and bar2_body < bar1_body * 0.5 and bar3_bullish and confirmation
self._bars_from_signal += 1
cd = self._signal_cooldown_bars.Value
rr = float(self._risk_reward.Value)
if self._bars_from_signal >= cd and pattern and self.Position == 0:
self.BuyMarket()
self._stop_price = self._prev2_low
self._take_price = close + (close - self._stop_price) * rr
self._bars_from_signal = 0
if self.Position > 0:
if low <= self._stop_price or high >= self._take_price:
self.SellMarket()
self._prev2_close = self._prev1_close
self._prev2_open = self._prev1_open
self._prev2_high = self._prev1_high
self._prev2_low = self._prev1_low
self._prev1_close = close
self._prev1_open = opn
self._prev1_high = high
self._prev1_low = low
def CreateClone(self):
return mfs_3_bars_pattern_strategy()