3-Bar Low 策略
3-Bar Low 策略在收盘价跌破前一根K线的三根最低收盘价时做多,并在收盘价突破前一根K线的七根最高收盘价时平仓。可选的 EMA 过滤器要求价格在进场前位于长期均线上方。
细节
- 入场条件:
- 收盘价低于前三根K线最低收盘价的前值。
- 可选:开启过滤器时,收盘价需高于 EMA。
- 方向:仅做多。
- 出场条件:
- 收盘价高于前七根K线最高收盘价的前值。
- 止损:无。
- 默认参数:
MaPeriod= 200LowestLength= 3HighestLength= 7UseEmaFilter= false
- 过滤器:
- 类型:突破
- 方向:多头
- 指标:EMA, Highest/Lowest
- 止损:否
- 复杂度:低
- 时间框架:任意
- 季节性:否
- 神经网络:否
- 背离:否
- 风险等级:低
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Three Bar Low Strategy.
/// A long opens when the close falls below the lowest close of the previous LowestLength candles and, with UseEmaFilter,
/// the close is above the MaPeriod EMA. The long closes when the close rises above the highest close of the previous
/// HighestLength candles.
/// </summary>
public class ThreeBarLowStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<int> _lowestLength;
private readonly StrategyParam<int> _highestLength;
private readonly StrategyParam<bool> _useEmaFilter;
private readonly StrategyParam<DataType> _candleType;
private Lowest _lowestClose;
private Highest _highestClose;
private decimal? _prevLowest;
private decimal? _prevHighest;
/// <summary>
/// EMA period of the filter.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Previous candles of the lowest close.
/// </summary>
public int LowestLength
{
get => _lowestLength.Value;
set => _lowestLength.Value = value;
}
/// <summary>
/// Previous candles of the highest close.
/// </summary>
public int HighestLength
{
get => _highestLength.Value;
set => _highestLength.Value = value;
}
/// <summary>
/// Require the close above the EMA for entries.
/// </summary>
public bool UseEmaFilter
{
get => _useEmaFilter.Value;
set => _useEmaFilter.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public ThreeBarLowStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("MA Period", "EMA period of the filter", "Indicators");
_lowestLength = Param(nameof(LowestLength), 3)
.SetGreaterThanZero()
.SetDisplay("Lowest Length", "Previous candles of the lowest close", "Indicators");
_highestLength = Param(nameof(HighestLength), 7)
.SetGreaterThanZero()
.SetDisplay("Highest Length", "Previous candles of the highest close", "Indicators");
_useEmaFilter = Param(nameof(UseEmaFilter), false)
.SetDisplay("Use EMA Filter", "Require the close above the EMA for entries", "Filters");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLowest = null;
_prevHighest = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevLowest = null;
_prevHighest = null;
var ema = new ExponentialMovingAverage { Length = MaPeriod };
_lowestClose = new Lowest { Length = LowestLength };
_highestClose = new Highest { Length = HighestLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
// Both levels are measured on the candles before this one.
var lowest = _prevLowest;
var highest = _prevHighest;
var currentLowest = _lowestClose.Process(close, candle.OpenTime, true).ToDecimal();
var currentHighest = _highestClose.Process(close, candle.OpenTime, true).ToDecimal();
if (_lowestClose.IsFormed)
_prevLowest = currentLowest;
if (_highestClose.IsFormed)
_prevHighest = currentHighest;
if (lowest is not decimal lowLevel || highest is not decimal highLevel)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
if (close > highLevel)
SellMarket(Position);
return;
}
var emaOk = !UseEmaFilter || (emaValue.IsFormed && close > emaValue.GetValue<decimal>());
if (Position == 0 && close < lowLevel && emaOk)
BuyMarket(Volume);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class three_bar_low_strategy(Strategy):
"""
Three Bar Low Strategy.
A long opens when the close falls below the lowest close of the previous LowestLength candles and, with UseEmaFilter,
the close is above the MaPeriod EMA. The long closes when the close rises above the highest close of the previous
HighestLength candles.
"""
def __init__(self):
super(three_bar_low_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 200).SetGreaterThanZero().SetDisplay("MA Period", "EMA period of the filter", "Indicators")
self._lowest_length = self.Param("LowestLength", 3).SetGreaterThanZero().SetDisplay("Lowest Length", "Previous candles of the lowest close", "Indicators")
self._highest_length = self.Param("HighestLength", 7).SetGreaterThanZero().SetDisplay("Highest Length", "Previous candles of the highest close", "Indicators")
self._use_ema_filter = self.Param("UseEmaFilter", False).SetDisplay("Use EMA Filter", "Require the close above the EMA for entries", "Filters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._lowest_close = None
self._highest_close = None
self._prev_lowest = None
self._prev_highest = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(three_bar_low_strategy, self).OnReseted()
self._prev_lowest = None
self._prev_highest = None
def OnStarted2(self, time):
super(three_bar_low_strategy, self).OnStarted2(time)
self._prev_lowest = None
self._prev_highest = None
ema = ExponentialMovingAverage()
ema.Length = self._ma_period.Value
self._lowest_close = Lowest()
self._lowest_close.Length = self._lowest_length.Value
self._highest_close = Highest()
self._highest_close.Length = self._highest_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
# Both levels are measured on the candles before this one.
lowest = self._prev_lowest
highest = self._prev_highest
current_lowest = float(process_float(self._lowest_close, candle.ClosePrice, candle.OpenTime, True).GetValue[Decimal](None))
current_highest = float(process_float(self._highest_close, candle.ClosePrice, candle.OpenTime, True).GetValue[Decimal](None))
if self._lowest_close.IsFormed:
self._prev_lowest = current_lowest
if self._highest_close.IsFormed:
self._prev_highest = current_highest
if lowest is None or highest is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
if close > highest:
self.SellMarket(self.Position)
return
ema_ok = not self._use_ema_filter.Value or (ema_value.IsFormed and close > float(ema_value.GetValue[Decimal](None)))
if self.Position == 0 and close < lowest and ema_ok:
self.BuyMarket(self.Volume)
def CreateClone(self):
return three_bar_low_strategy()