アウトサイドバー・リバーサル戦略
アウトサイドバーは、ローソク足のレンジが前のローソク足を超える時に発生し、ボラティリティの一時的な急増を引き起こします。この戦略は、アウトサイドバーが前のトレンドと反対方向に終値を付けた場合、均衡への回帰を見込んで動きに逆張りします。
テストでは年平均リターンが約121%であることが示されています。暗号資産市場で最も良いパフォーマンスを発揮します。
アウトサイドバーが形成されると、アルゴリズムはローソク足が強気か弱気かを判断します。下落後の強気のアウトサイドバーはバーの安値の下にストップを置いてロングポジションを開きます。上昇後の弱気のアウトサイドバーはその高値の上にストップを置いてショートを起動します。その後価格がその極値を突き抜けるとトレードを決済します。
このセットアップは消耗的な急騰後の素早いリバーサルを求め、強いトレンド相場よりもチョッピーな市場で最もよく機能します。
詳細
- エントリー条件: 前の動きと反対方向に終値を付けるアウトサイドバー。
- ロング/ショート: 両方。
- エグジット条件: 価格がアウトサイドバーの高値/安値を突き抜けるか、ストップロス。
- ストップ: はい、パターンの外側に配置。
- デフォルト値:
CandleType= 5 minuteStopLossPercent= 1 エントリー価格からこの割合(%)離れた保護ストップで、足と足の間でも監視します。終値がアウトサイドバーの反対側の極値を抜けた場合もポジションを閉じます。
- フィルター:
- カテゴリ: パターン
- 方向: 両方
- インジケーター: Candlestick
- ストップ: はい
- 複雑さ: 中級
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
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>
/// Outside Bar Reversal strategy.
/// An outside bar's high and low both exceed the previous candle's. While flat, a bullish outside bar after a bearish candle buys
/// and a bearish one after a bullish candle sells. The position closes when a close breaks through the outside bar's opposite
/// extreme, and a percent stop from the entry price, watched between candles, limits the loss.
/// </summary>
public class OutsideBarReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _prevCandle;
private decimal _exitLevel;
/// <summary>
/// Stop-loss percentage from the entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type and timeframe.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public OutsideBarReversalStrategy()
{
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
_prevCandle = null;
_exitLevel = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
_exitLevel = default;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var previous = _prevCandle;
_prevCandle = candle;
if (previous == null || !IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close < _exitLevel)
SellMarket(Position);
return;
}
if (Position < 0)
{
if (close > _exitLevel)
BuyMarket(-Position);
return;
}
var isOutsideBar = candle.HighPrice > previous.HighPrice && candle.LowPrice < previous.LowPrice;
if (!isOutsideBar)
return;
var afterDecline = previous.ClosePrice < previous.OpenPrice;
var afterRally = previous.ClosePrice > previous.OpenPrice;
if (close > candle.OpenPrice && afterDecline)
{
BuyMarket(Volume);
_exitLevel = candle.LowPrice;
}
else if (close < candle.OpenPrice && afterRally)
{
SellMarket(Volume);
_exitLevel = candle.HighPrice;
}
}
}
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, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class outside_bar_reversal_strategy(Strategy):
"""
Outside Bar Reversal strategy.
An outside bar's high and low both exceed the previous candle's. While flat, a bullish outside bar after a bearish candle buys
and a bearish one after a bullish candle sells. The position closes when a close breaks through the outside bar's opposite
extreme, and a percent stop from the entry price, watched between candles, limits the loss.
"""
def __init__(self):
super(outside_bar_reversal_strategy, self).__init__()
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_candle = None
self._exit_level = Decimal(0)
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(outside_bar_reversal_strategy, self).OnReseted()
self._prev_candle = None
self._exit_level = Decimal(0)
def OnStarted2(self, time):
super(outside_bar_reversal_strategy, self).OnStarted2(time)
self._prev_candle = None
self._exit_level = Decimal(0)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
previous = self._prev_candle
self._prev_candle = candle
if previous is None or not self.IsFormedAndOnlineAndAllowTrading():
return
close = candle.ClosePrice
if self.Position > 0:
if close < self._exit_level:
self.SellMarket(self.Position)
return
if self.Position < 0:
if close > self._exit_level:
self.BuyMarket(-self.Position)
return
is_outside_bar = candle.HighPrice > previous.HighPrice and candle.LowPrice < previous.LowPrice
if not is_outside_bar:
return
after_decline = previous.ClosePrice < previous.OpenPrice
after_rally = previous.ClosePrice > previous.OpenPrice
if close > candle.OpenPrice and after_decline:
self.BuyMarket(self.Volume)
self._exit_level = candle.LowPrice
elif close < candle.OpenPrice and after_rally:
self.SellMarket(self.Volume)
self._exit_level = candle.HighPrice
def CreateClone(self):
return outside_bar_reversal_strategy()