布林带与DEMA策略
该策略结合30分钟K线的布林带和日线的双指数移动平均线(DEMA),用于在趋势确认下交易突破。
当看涨蜡烛向上穿越下轨且DEMA连续三天上升时,产生做多信号。当看跌蜡烛向下穿越上轨且DEMA连续三天下降时,产生做空信号。当相反颜色的蜡烛向不利方向穿越外轨时,仓位被平仓。
细节
- 入场条件:
- 多头:蜡烛收盘价高于下轨且开盘价低于下轨,且日线DEMA连续三天上升。
- 空头:蜡烛收盘价低于上轨且开盘价高于上轨,且日线DEMA连续三天下降。
- 多空方向:双向。
- 出场条件:
- 多头:看跌蜡烛开在上轨之上并收在上轨之下。
- 空头:看涨蜡烛开在下轨之下并收在下轨之上。
- 止损:无。
- 默认参数:
BollingerPeriod= 20DemaPeriod= 20Deviation= 2CandleType= 30分钟周期
- 过滤器:
- 分类:均值回归
- 方向:双向
- 指标:布林带、DEMA
- 止损:无
- 复杂度:中等
- 时间框架:日内结合日线趋势过滤
- 季节性:无
- 神经网络:无
- 背离:无
- 风险等级:中等
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>
/// Strategy using Bollinger Bands for entries and DEMA for trend confirmation.
/// Enters long when a bullish candle crosses above the lower band and DEMA is rising.
/// Enters short when a bearish candle crosses below the upper band and DEMA is falling.
/// Exits long on bearish cross of the upper band and exits short on bullish cross of the lower band.
/// </summary>
public class BollingerBandsDemaStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<int> _demaPeriod;
private readonly StrategyParam<decimal> _deviation;
private readonly StrategyParam<DataType> _candleType;
private decimal? _dema0;
private decimal? _dema1;
private decimal? _dema2;
/// <summary>
/// Bollinger Bands period.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// DEMA period.
/// </summary>
public int DemaPeriod
{
get => _demaPeriod.Value;
set => _demaPeriod.Value = value;
}
/// <summary>
/// Standard deviation for Bollinger Bands.
/// </summary>
public decimal Deviation
{
get => _deviation.Value;
set => _deviation.Value = value;
}
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="BollingerBandsDemaStrategy"/>.
/// </summary>
public BollingerBandsDemaStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "Length of Bollinger Bands", "Indicators")
.SetOptimize(10, 40, 5);
_demaPeriod = Param(nameof(DemaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("DEMA Period", "Length of double EMA", "Indicators")
.SetOptimize(10, 40, 5);
_deviation = Param(nameof(Deviation), 2m)
.SetGreaterThanZero()
.SetDisplay("Deviation", "Standard deviation for Bollinger Bands", "Indicators")
.SetOptimize(1m, 3m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Time frame for Bollinger calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType), (Security, TimeSpan.FromMinutes(5).TimeFrame())];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_dema0 = _dema1 = _dema2 = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands { Length = BollingerPeriod, Width = Deviation };
var dema = new DEMA { Length = DemaPeriod };
var demaSub = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
demaSub
.Bind(dema, (candle, value) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!dema.IsFormed)
return;
_dema2 = _dema1;
_dema1 = _dema0;
_dema0 = value;
})
.Start();
var mainSub = SubscribeCandles(CandleType);
mainSub
.BindEx(bollinger, ProcessMain)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, mainSub);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
}
}
private void ProcessMain(ICandleMessage candle, IIndicatorValue value)
{
if (candle.State != CandleStates.Finished)
return;
var bb = (BollingerBandsValue)value;
if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower || bb.MovingAverage is not decimal middle)
return;
if (_dema0 is null || _dema1 is null || _dema2 is null)
return;
var demaUp = _dema0 > _dema1 && _dema1 > _dema2;
var demaDown = _dema0 < _dema1 && _dema1 < _dema2;
var buyCondition = candle.ClosePrice > lower && candle.OpenPrice < lower && demaUp;
var sellCondition = candle.ClosePrice < upper && candle.OpenPrice > upper && demaDown;
var buyClose = candle.ClosePrice < upper && candle.OpenPrice > upper;
var sellClose = candle.ClosePrice > lower && candle.OpenPrice < lower;
if (buyCondition && Position <= 0)
BuyMarket();
if (sellCondition && Position >= 0)
SellMarket();
if (buyClose && Position > 0)
SellMarket();
if (sellClose && Position < 0)
BuyMarket();
}
}
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 BollingerBands, DoubleExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bollinger_bands_dema_strategy(Strategy):
def __init__(self):
super(bollinger_bands_dema_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Length of Bollinger Bands", "Indicators")
self._dema_period = self.Param("DemaPeriod", 20) \
.SetDisplay("DEMA Period", "Length of double EMA", "Indicators")
self._deviation = self.Param("Deviation", 2.0) \
.SetDisplay("Deviation", "Standard deviation for Bollinger Bands", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Time frame for Bollinger calculation", "General")
self._dema0 = None
self._dema1 = None
self._dema2 = None
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def dema_period(self):
return self._dema_period.Value
@property
def deviation(self):
return self._deviation.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_bands_dema_strategy, self).OnReseted()
self._dema0 = None
self._dema1 = None
self._dema2 = None
def OnStarted2(self, time):
super(bollinger_bands_dema_strategy, self).OnStarted2(time)
self._dema0 = None
self._dema1 = None
self._dema2 = None
bollinger = BollingerBands()
bollinger.Length = int(self.bollinger_period)
bollinger.Width = float(self.deviation)
dema = DoubleExponentialMovingAverage()
dema.Length = int(self.dema_period)
dema_sub = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
dema_sub.Bind(dema, self._process_dema).Start()
main_sub = self.SubscribeCandles(self.candle_type)
main_sub.BindEx(bollinger, self._process_main).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, main_sub)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
def _process_dema(self, candle, value):
if candle.State != CandleStates.Finished:
return
value = float(value)
self._dema2 = self._dema1
self._dema1 = self._dema0
self._dema0 = value
def _process_main(self, candle, value):
if candle.State != CandleStates.Finished:
return
if not value.IsFormed:
return
upper = value.UpBand
lower = value.LowBand
middle = value.MovingAverage
if upper is None or lower is None or middle is None:
return
upper = float(upper)
lower = float(lower)
if self._dema0 is None or self._dema1 is None or self._dema2 is None:
return
dema_up = self._dema0 > self._dema1 and self._dema1 > self._dema2
dema_down = self._dema0 < self._dema1 and self._dema1 < self._dema2
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
buy_condition = close > lower and open_p < lower and dema_up
sell_condition = close < upper and open_p > upper and dema_down
buy_close = close < upper and open_p > upper
sell_close = close > lower and open_p < lower
if buy_condition and self.Position <= 0:
self.BuyMarket()
if sell_condition and self.Position >= 0:
self.SellMarket()
if buy_close and self.Position > 0:
self.SellMarket()
if sell_close and self.Position < 0:
self.BuyMarket()
def CreateClone(self):
return bollinger_bands_dema_strategy()