強化版BarUpDn戦略
この戦略は、Bollinger Bandsとトレンド確認を組み合わせて強気または弱気のバーを探します。上昇トレンドでは強気のギャップでロング、下降トレンドでは弱気のギャップでショートにエントリーします。エグジットにはATRベースのストップロスとテイクプロフィットレベルを使用します。
詳細
- エントリー条件:
- ロング: 上方ギャップのある強気ローソク足、トレンドMAの上かつBollinger Bandsの下限より上で終値。
- ショート: 下方ギャップのある弱気ローソク足、トレンドMAの下かつBollinger Bandsの上限より下で終値。
- ロング/ショート: 両方。
- エグジット条件:
- 価格がATRベースのストップロスまたはテイクプロフィット(1.5× ATR)に達する。
- ストップ: ATRベースのストップとテイクプロフィット。
- デフォルト値:
BbLength= 20BbMultiplier= 2MaLength= 50AtrLength= 14AtrMultiplierSl= 2AtrMultiplierTp= 3
- フィルター:
- カテゴリ: トレンドフォロー
- 方向: 両方
- インジケーター: Bollinger Bands, SMA, ATR
- ストップ: あり
- 複雑さ: 低
- 時間軸: 任意
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
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;
/// <summary>
/// Enhanced BarUpDn strategy.
/// A bullish candle that opens above the previous close goes long when it closes above the trend SMA and above the lower
/// Bollinger band; a bearish candle that opens below the previous close goes short when it closes below the trend SMA and below
/// the upper band. An opposite signal reverses the position. The stop lies AtrMultiplierSl ATR and the target AtrMultiplierTp ATR
/// from the entry.
/// </summary>
public class EnhancedBarUpDnStrategy : Strategy
{
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<decimal> _bbMultiplier;
private readonly StrategyParam<int> _maLength;
private readonly StrategyParam<int> _atrLength;
private readonly StrategyParam<decimal> _atrMultiplierSl;
private readonly StrategyParam<decimal> _atrMultiplierTp;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevClose;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Bollinger Bands length.
/// </summary>
public int BbLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BbMultiplier
{
get => _bbMultiplier.Value;
set => _bbMultiplier.Value = value;
}
/// <summary>
/// Trend SMA length.
/// </summary>
public int MaLength
{
get => _maLength.Value;
set => _maLength.Value = value;
}
/// <summary>
/// ATR length.
/// </summary>
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <summary>
/// Stop loss distance in ATR.
/// </summary>
public decimal AtrMultiplierSl
{
get => _atrMultiplierSl.Value;
set => _atrMultiplierSl.Value = value;
}
/// <summary>
/// Take profit distance in ATR.
/// </summary>
public decimal AtrMultiplierTp
{
get => _atrMultiplierTp.Value;
set => _atrMultiplierTp.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public EnhancedBarUpDnStrategy()
{
_bbLength = Param(nameof(BbLength), 20)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger Bands length", "Indicators");
_bbMultiplier = Param(nameof(BbMultiplier), 2m)
.SetGreaterThanZero()
.SetDisplay("BB Multiplier", "Bollinger Bands deviation multiplier", "Indicators");
_maLength = Param(nameof(MaLength), 50)
.SetGreaterThanZero()
.SetDisplay("MA Length", "Trend SMA length", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Length", "ATR length", "Risk");
_atrMultiplierSl = Param(nameof(AtrMultiplierSl), 2m)
.SetNotNegative()
.SetDisplay("ATR Stop", "Stop loss distance in ATR", "Risk");
_atrMultiplierTp = Param(nameof(AtrMultiplierTp), 3m)
.SetNotNegative()
.SetDisplay("ATR Target", "Take profit distance in ATR", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
var bollinger = new BollingerBands { Length = BbLength, Width = BbMultiplier };
var ma = new SimpleMovingAverage { Length = MaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, ma, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawIndicator(area, ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue maValue, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var prevClose = _prevClose;
_prevClose = candle.ClosePrice;
if (!bollingerValue.IsFormed || !maValue.IsFormed || !atrValue.IsFormed)
return;
if (bollingerValue is not IBollingerBandsValue { UpBand: decimal upper, LowBand: decimal lower })
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0 && ((AtrMultiplierSl > 0m && candle.LowPrice <= _stopPrice) || (AtrMultiplierTp > 0m && candle.HighPrice >= _takePrice)))
{
SellMarket(Position);
return;
}
if (Position < 0 && ((AtrMultiplierSl > 0m && candle.HighPrice >= _stopPrice) || (AtrMultiplierTp > 0m && candle.LowPrice <= _takePrice)))
{
BuyMarket(-Position);
return;
}
if (prevClose is not decimal pc)
return;
var ma = maValue.GetValue<decimal>();
var atr = atrValue.GetValue<decimal>();
var open = candle.OpenPrice;
var close = candle.ClosePrice;
var longSignal = close > open && open > pc && close > ma && close > lower;
var shortSignal = close < open && open < pc && close < ma && close < upper;
if (longSignal && Position <= 0)
{
_stopPrice = close - atr * AtrMultiplierSl;
_takePrice = close + atr * AtrMultiplierTp;
BuyMarket(Volume + Math.Abs(Position));
}
else if (shortSignal && Position >= 0)
{
_stopPrice = close + atr * AtrMultiplierSl;
_takePrice = close - atr * AtrMultiplierTp;
SellMarket(Volume + Math.Abs(Position));
}
}
}
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 BollingerBands, SimpleMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class enhanced_bar_up_dn_strategy(Strategy):
"""
Enhanced BarUpDn strategy.
A bullish candle that opens above the previous close goes long when it closes above the trend SMA and above the lower
Bollinger band; a bearish candle that opens below the previous close goes short when it closes below the trend SMA and below
the upper band. An opposite signal reverses the position. The stop lies AtrMultiplierSl ATR and the target AtrMultiplierTp ATR
from the entry.
"""
def __init__(self):
super(enhanced_bar_up_dn_strategy, self).__init__()
self._bb_length = self.Param("BbLength", 20).SetGreaterThanZero().SetDisplay("BB Length", "Bollinger Bands length", "Indicators")
self._bb_multiplier = self.Param("BbMultiplier", 2.0).SetGreaterThanZero().SetDisplay("BB Multiplier", "Bollinger Bands deviation multiplier", "Indicators")
self._ma_length = self.Param("MaLength", 50).SetGreaterThanZero().SetDisplay("MA Length", "Trend SMA length", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetGreaterThanZero().SetDisplay("ATR Length", "ATR length", "Risk")
self._atr_multiplier_sl = self.Param("AtrMultiplierSl", 2.0).SetNotNegative().SetDisplay("ATR Stop", "Stop loss distance in ATR", "Risk")
self._atr_multiplier_tp = self.Param("AtrMultiplierTp", 3.0).SetNotNegative().SetDisplay("ATR Target", "Take profit distance in ATR", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._prev_close = None
self._stop_price = 0.0
self._take_price = 0.0
def OnReseted(self):
super(enhanced_bar_up_dn_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(enhanced_bar_up_dn_strategy, self).OnStarted2(time)
self._reset_state()
bollinger = BollingerBands()
bollinger.Length = self._bb_length.Value
bollinger.Width = Decimal(float(self._bb_multiplier.Value))
ma = SimpleMovingAverage()
ma.Length = self._ma_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, ma, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawIndicator(area, ma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, bollinger_value, ma_value, atr_value):
if candle.State != CandleStates.Finished:
return
prev_close = self._prev_close
close = float(candle.ClosePrice)
self._prev_close = close
if not bollinger_value.IsFormed or not ma_value.IsFormed or not atr_value.IsFormed:
return
if bollinger_value.UpBand is None or bollinger_value.LowBand is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
sl_mult = float(self._atr_multiplier_sl.Value)
tp_mult = float(self._atr_multiplier_tp.Value)
if self.Position > 0 and ((sl_mult > 0 and low <= self._stop_price) or (tp_mult > 0 and high >= self._take_price)):
self.SellMarket(self.Position)
return
if self.Position < 0 and ((sl_mult > 0 and high >= self._stop_price) or (tp_mult > 0 and low <= self._take_price)):
self.BuyMarket(-self.Position)
return
if prev_close is None:
return
upper = float(bollinger_value.UpBand)
lower = float(bollinger_value.LowBand)
ma = float(ma_value.GetValue[Decimal](None))
atr = float(atr_value.GetValue[Decimal](None))
open_price = float(candle.OpenPrice)
long_signal = close > open_price and open_price > prev_close and close > ma and close > lower
short_signal = close < open_price and open_price < prev_close and close < ma and close < upper
if long_signal and self.Position <= 0:
self._stop_price = close - atr * sl_mult
self._take_price = close + atr * tp_mult
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self._stop_price = close + atr * sl_mult
self._take_price = close - atr * tp_mult
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return enhanced_bar_up_dn_strategy()