ダイナミック・サポート&レジスタンス・ピボット戦略
この戦略は、直近のピボット高値・安値からダイナミックなサポートとレジスタンスレベルを導出します。価格がレベル付近でサポートを上抜けたときにロングエントリーし、レジスタンスを下抜けたときにショートエントリーします。リスク管理は固定パーセントのストップロスと利益確定レベルを使用します。
詳細
- エントリー条件: 価格がサポート/レジスタンスから
SupportResistanceDistanceパーセント以内にあり、サポートを上抜けまたはレジスタンスを下抜け。 - ロング/ショート: 両方。
- エグジット条件: 固定の利益確定とストップロス。
- ストップ: はい。
- デフォルト値:
PivotLength= 2SupportResistanceDistance= 0.4mStopLossPercent= 10.0mTakeProfitPercent= 26.0mCandleType= TimeSpan.FromMinutes(5)
- フィルター:
- カテゴリ: ブレイクアウト
- 方向: 両方
- インジケーター: Pivot
- ストップ: はい
- 複雑さ: 初心者
- 時間軸: イントラデイ
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Dynamic Support and Resistance Pivot strategy.
/// Support is the last pivot low and resistance the last pivot high, a pivot being a candle whose low (high) is beyond those of the
/// PivotLength candles on each side. A close crossing above support goes long and a close crossing below resistance goes short,
/// reversing an opposite position, when the close is within SupportResistanceDistance percent of that level. Percent stop loss and
/// take profit manage the position.
/// </summary>
public class DynamicSupportAndResistancePivotStrategy : Strategy
{
private readonly StrategyParam<int> _pivotLength;
private readonly StrategyParam<decimal> _supportResistanceDistance;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _highs = [];
private readonly List<decimal> _lows = [];
private decimal? _support;
private decimal? _resistance;
private decimal? _prevClose;
/// <summary>
/// Candles on each side of a pivot.
/// </summary>
public int PivotLength
{
get => _pivotLength.Value;
set => _pivotLength.Value = value;
}
/// <summary>
/// Maximum distance of the close from the level, in percent.
/// </summary>
public decimal SupportResistanceDistance
{
get => _supportResistanceDistance.Value;
set => _supportResistanceDistance.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Take profit percentage from entry price.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DynamicSupportAndResistancePivotStrategy()
{
_pivotLength = Param(nameof(PivotLength), 2)
.SetGreaterThanZero()
.SetDisplay("Pivot Length", "Candles on each side of a pivot", "Pivots");
_supportResistanceDistance = Param(nameof(SupportResistanceDistance), 0.4m)
.SetNotNegative()
.SetDisplay("S/R Distance %", "Maximum distance of the close from the level, in percent", "Pivots");
_stopLossPercent = Param(nameof(StopLossPercent), 10.0m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 26.0m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit 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();
ResetState();
}
private void ResetState()
{
_highs.Clear();
_lows.Clear();
_support = null;
_resistance = null;
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var take = TakeProfitPercent > 0 ? new Unit(TakeProfitPercent, UnitTypes.Percent) : new Unit();
var stop = StopLossPercent > 0 ? new Unit(StopLossPercent, UnitTypes.Percent) : new Unit();
StartProtection(take, stop, useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var length = PivotLength;
var size = length * 2 + 1;
_highs.Add(candle.HighPrice);
_lows.Add(candle.LowPrice);
if (_highs.Count > size)
{
_highs.RemoveAt(0);
_lows.RemoveAt(0);
}
if (_highs.Count == size)
{
var centerHigh = _highs[length];
var centerLow = _lows[length];
var isPivotHigh = true;
var isPivotLow = true;
for (var i = 0; i < size; i++)
{
if (i == length)
continue;
if (_highs[i] >= centerHigh)
isPivotHigh = false;
if (_lows[i] <= centerLow)
isPivotLow = false;
}
if (isPivotHigh)
_resistance = centerHigh;
if (isPivotLow)
_support = centerLow;
}
var close = candle.ClosePrice;
var prevClose = _prevClose;
_prevClose = close;
if (prevClose is not decimal pc)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var maxDistance = SupportResistanceDistance / 100m;
var longSignal = _support is decimal support && support > 0
&& pc <= support && close > support
&& Math.Abs(close - support) / support <= maxDistance;
var shortSignal = _resistance is decimal resistance && resistance > 0
&& pc >= resistance && close < resistance
&& Math.Abs(close - resistance) / resistance <= maxDistance;
if (longSignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class dynamic_support_and_resistance_pivot_strategy(Strategy):
"""
Dynamic Support and Resistance Pivot strategy.
Support is the last pivot low and resistance the last pivot high, a pivot being a candle whose low (high) is beyond those of the
PivotLength candles on each side. A close crossing above support goes long and a close crossing below resistance goes short,
reversing an opposite position, when the close is within SupportResistanceDistance percent of that level. Percent stop loss and
take profit manage the position.
"""
def __init__(self):
super(dynamic_support_and_resistance_pivot_strategy, self).__init__()
self._pivot_length = self.Param("PivotLength", 2).SetGreaterThanZero().SetDisplay("Pivot Length", "Candles on each side of a pivot", "Pivots")
self._support_resistance_distance = self.Param("SupportResistanceDistance", 0.4).SetNotNegative().SetDisplay("S/R Distance %", "Maximum distance of the close from the level, in percent", "Pivots")
self._stop_loss_percent = self.Param("StopLossPercent", 10.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._take_profit_percent = self.Param("TakeProfitPercent", 26.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit 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._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._highs = []
self._lows = []
self._support = None
self._resistance = None
self._prev_close = None
def OnReseted(self):
super(dynamic_support_and_resistance_pivot_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(dynamic_support_and_resistance_pivot_strategy, self).OnStarted2(time)
self._reset_state()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
take_percent = Decimal(self._take_profit_percent.Value)
stop_percent = Decimal(self._stop_loss_percent.Value)
take = Unit(take_percent, UnitTypes.Percent) if take_percent > 0 else Unit()
stop = Unit(stop_percent, UnitTypes.Percent) if stop_percent > 0 else Unit()
self.StartProtection(take, stop, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
length = self._pivot_length.Value
size = length * 2 + 1
self._highs.append(candle.HighPrice)
self._lows.append(candle.LowPrice)
if len(self._highs) > size:
self._highs.pop(0)
self._lows.pop(0)
if len(self._highs) == size:
center_high = self._highs[length]
center_low = self._lows[length]
is_pivot_high = True
is_pivot_low = True
for i in range(size):
if i == length:
continue
if self._highs[i] >= center_high:
is_pivot_high = False
if self._lows[i] <= center_low:
is_pivot_low = False
if is_pivot_high:
self._resistance = center_high
if is_pivot_low:
self._support = center_low
close = candle.ClosePrice
pc = self._prev_close
self._prev_close = close
if pc is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
max_distance = Decimal(self._support_resistance_distance.Value) / Decimal(100)
support = self._support
resistance = self._resistance
long_signal = support is not None and support > 0 and pc <= support and close > support and \
abs(close - support) / support <= max_distance
short_signal = resistance is not None and resistance > 0 and pc >= resistance and close < resistance and \
abs(close - resistance) / resistance <= max_distance
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return dynamic_support_and_resistance_pivot_strategy()