ストリートに血が流れる戦略
この戦略は、直近の高値からの現在のドローダウンが標準偏差の閾値を下回ったときに買いを入れます。ポジションは固定本数のバー後に決済されます。
詳細
- エントリー条件:
- ロング: ドローダウン ≤ 平均 +
StdDevThreshold× 標準偏差
- ロング: ドローダウン ≤ 平均 +
- ロング/ショート: ロングのみ
- エグジット条件:
ExitBars本のバー後にポジションを決済 - ストップ: なし
- デフォルト値:
LookbackPeriod= 50StdDevLength= 50StdDevThreshold= -1mExitBars= 35CandleType= TimeSpan.FromMinutes(1).TimeFrame()
- フィルター:
- カテゴリ: リバーサル
- 方向: ロング
- インジケーター: Highest, SMA, StandardDeviation
- ストップ: いいえ
- 複雑さ: 基本
- 時間軸: 中期
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Blood In The Streets strategy.
/// The drawdown is the percent distance of the close below the highest high of the last LookbackPeriod candles. When it falls to
/// its StdDevLength mean plus StdDevThreshold standard deviations or lower, the strategy buys, and it closes the long after ExitBars candles.
/// </summary>
public class BloodInTheStreetsStrategy : Strategy
{
private readonly StrategyParam<int> _lookbackPeriod;
private readonly StrategyParam<int> _stdDevLength;
private readonly StrategyParam<decimal> _stdDevThreshold;
private readonly StrategyParam<int> _exitBars;
private readonly StrategyParam<DataType> _candleType;
private Highest _highest;
private SimpleMovingAverage _drawdownMean;
private StandardDeviation _drawdownDeviation;
private int _barsInPosition;
/// <summary>
/// Candles the highest high spans.
/// </summary>
public int LookbackPeriod
{
get => _lookbackPeriod.Value;
set => _lookbackPeriod.Value = value;
}
/// <summary>
/// Candles the drawdown mean and standard deviation span.
/// </summary>
public int StdDevLength
{
get => _stdDevLength.Value;
set => _stdDevLength.Value = value;
}
/// <summary>
/// Standard deviations from the mean the drawdown has to reach.
/// </summary>
public decimal StdDevThreshold
{
get => _stdDevThreshold.Value;
set => _stdDevThreshold.Value = value;
}
/// <summary>
/// Candles a position is held.
/// </summary>
public int ExitBars
{
get => _exitBars.Value;
set => _exitBars.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BloodInTheStreetsStrategy()
{
_lookbackPeriod = Param(nameof(LookbackPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Lookback Period", "Candles the highest high spans", "Indicators");
_stdDevLength = Param(nameof(StdDevLength), 50)
.SetGreaterThanZero()
.SetDisplay("StdDev Length", "Candles the drawdown mean and standard deviation span", "Indicators");
_stdDevThreshold = Param(nameof(StdDevThreshold), -1m)
.SetDisplay("StdDev Threshold", "Standard deviations from the mean the drawdown has to reach", "Indicators");
_exitBars = Param(nameof(ExitBars), 35)
.SetGreaterThanZero()
.SetDisplay("Exit Bars", "Candles a position is held", "Exit");
_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();
_highest = null;
_drawdownMean = null;
_drawdownDeviation = null;
_barsInPosition = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highest = new Highest { Length = LookbackPeriod };
_drawdownMean = new SimpleMovingAverage { Length = StdDevLength };
_drawdownDeviation = new StandardDeviation { Length = StdDevLength };
_barsInPosition = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var highestValue = _highest.Process(new DecimalIndicatorValue(_highest, candle.HighPrice, candle.OpenTime) { IsFinal = true });
if (!highestValue.IsFormed)
return;
var highest = highestValue.GetValue<decimal>();
if (highest <= 0)
return;
var drawdown = (candle.ClosePrice - highest) / highest * 100m;
var meanValue = _drawdownMean.Process(new DecimalIndicatorValue(_drawdownMean, drawdown, candle.OpenTime) { IsFinal = true });
var deviationValue = _drawdownDeviation.Process(new DecimalIndicatorValue(_drawdownDeviation, drawdown, candle.OpenTime) { IsFinal = true });
if (Position > 0)
_barsInPosition++;
if (!meanValue.IsFormed || !deviationValue.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position > 0)
{
if (_barsInPosition >= ExitBars)
SellMarket(Position);
return;
}
var threshold = meanValue.GetValue<decimal>() + StdDevThreshold * deviationValue.GetValue<decimal>();
if (Position == 0 && drawdown <= threshold)
{
BuyMarket(Volume);
_barsInPosition = 0;
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, SimpleMovingAverage, StandardDeviation, DecimalIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class blood_in_the_streets_strategy(Strategy):
"""
Blood In The Streets strategy.
The drawdown is the percent distance of the close below the highest high of the last LookbackPeriod candles. When it falls to
its StdDevLength mean plus StdDevThreshold standard deviations or lower, the strategy buys, and it closes the long after ExitBars candles.
"""
def __init__(self):
super(blood_in_the_streets_strategy, self).__init__()
self._lookback_period = self.Param("LookbackPeriod", 50).SetGreaterThanZero().SetDisplay("Lookback Period", "Candles the highest high spans", "Indicators")
self._std_dev_length = self.Param("StdDevLength", 50).SetGreaterThanZero().SetDisplay("StdDev Length", "Candles the drawdown mean and standard deviation span", "Indicators")
self._std_dev_threshold = self.Param("StdDevThreshold", -1.0).SetDisplay("StdDev Threshold", "Standard deviations from the mean the drawdown has to reach", "Indicators")
self._exit_bars = self.Param("ExitBars", 35).SetGreaterThanZero().SetDisplay("Exit Bars", "Candles a position is held", "Exit")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._highest = None
self._drawdown_mean = None
self._drawdown_deviation = None
self._bars_in_position = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(blood_in_the_streets_strategy, self).OnReseted()
self._highest = None
self._drawdown_mean = None
self._drawdown_deviation = None
self._bars_in_position = 0
def OnStarted2(self, time):
super(blood_in_the_streets_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self._lookback_period.Value
self._drawdown_mean = SimpleMovingAverage()
self._drawdown_mean.Length = self._std_dev_length.Value
self._drawdown_deviation = StandardDeviation()
self._drawdown_deviation.Length = self._std_dev_length.Value
self._bars_in_position = 0
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process(self, indicator, value, time):
indicator_input = DecimalIndicatorValue(indicator, value, time)
indicator_input.IsFinal = True
return indicator.Process(indicator_input)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
highest_value = self._process(self._highest, candle.HighPrice, candle.OpenTime)
if not highest_value.IsFormed:
return
highest = highest_value.GetValue[Decimal](None)
if highest <= 0:
return
drawdown = (candle.ClosePrice - highest) / highest * Decimal(100)
mean_value = self._process(self._drawdown_mean, drawdown, candle.OpenTime)
deviation_value = self._process(self._drawdown_deviation, drawdown, candle.OpenTime)
if self.Position > 0:
self._bars_in_position += 1
if not mean_value.IsFormed or not deviation_value.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self.Position > 0:
if self._bars_in_position >= self._exit_bars.Value:
self.SellMarket(self.Position)
return
threshold = mean_value.GetValue[Decimal](None) + Decimal(self._std_dev_threshold.Value) * deviation_value.GetValue[Decimal](None)
if self.Position == 0 and drawdown <= threshold:
self.BuyMarket(self.Volume)
self._bars_in_position = 0
def CreateClone(self):
return blood_in_the_streets_strategy()