この戦略は"アダプティブATRトレーリングストップ損失戦略"と呼ばれています.これはATR指標を使用してストップ損失レベルを設定し,リスクを制御しながらトレンドに従うためにエントリー後に緊密なストップから緩いストップに切り替えます.
具体的な論理は
入力信号として,特定の期間中の最高値と最低値の範囲を計算します.入場は価格が範囲を突破すると起動します.
入力後には,入境後損失を制限するために,最初にATR値の1.5倍に固定されたより緊密なATRストップが使用されます.
トレードホールディングの間,ストップは4倍ATRのローザーに切り替わります.ストップは価格を後押ししますが,トレンドが拡大するためのより多くのスペースを可能にします.
ストップレベルは,常に最低価格 (ロングトレード) または最高価格 (ショートトレード) を追跡し,価格変動に合わせて調整し,トレーリングストップ効果を達成します.
価格がストップレベル (ロング) 以下の値を下げたり,それ以上の値 (ショート) を上げると,ストップロスは引き起こす.
この戦略の利点は,早期のストップアウトを回避しながらリスク制御を確保するために適応型ストップ損失メカニズムを使用することです.しかし,ATRパラメータと倍数は最適化が必要であり,ストップはトレンド分析で使用する必要があります.
結論として,ダイナミック・トレリング・ストップは収益性を向上させる重要な手段である.柔軟なストップ・ロスの適用により,トレンド・プロフィートとリスクを制御することができる.
/*backtest start: 2023-08-13 00:00:00 end: 2023-09-12 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ //@version=4 //@author=Takazudo strategy("ATR trailing SL tight to slack [Takazudo]", overlay=true, default_qty_type=strategy.fixed, initial_capital=0, currency=currency.USD) posSize = strategy.position_size hasNoPos = posSize == 0 hasLongPos = posSize > 0 hasShortPos = posSize < 0 //============================================================================ // consts, inputs //============================================================================ // colors var COLOR_SL_LINE = color.new(#e0f64d, 20) var COLOR_SL_LINE_THIN = color.new(#e0f64d, 90) var COLOR_ENTRY_BAND = color.new(#43A6F5, 30) var COLOR_TRANSPARENT = color.new(#000000, 100) // Entry strategy _g1 = 'Entry strategy' var config_entryBandBars = input(defval = 100, title = "Entry band bar count", minval=1, group=_g1) _g2 = 'ATR SL' var config_slAtr_length = input(24, title = "Trailing stop ATR Length", group=_g2) var config_slAtr_multi1 = input(1.5, title = "Trailing stop ATR Multiple on tight", type=input.float, step=0.1, group=_g2) var config_slAtr_multi2 = input(4, title = "Trailing stop ATR Multiple on slack", type=input.float, step=0.1, group=_g2) _g3 = 'Backtesting range' var config_fromYear = input(defval = 2016, title = "From Year", minval = 1970, group=_g3) var config_fromMonth = input(defval = 1, title = "From Month", minval = 1, maxval = 12, group=_g3) var config_fromDay = input(defval = 1, title = "From Day", minval = 1, maxval = 31, group=_g3) var config_toYear = input(defval = 2021, title = "To Year", minval = 1970, group=_g3) var config_toMonth = input(defval = 4, title = "To Month", minval = 1, maxval = 12, group=_g3) var config_toDay = input(defval = 5, title = "To Day", minval = 1, maxval = 31, group=_g3) //============================================================================ // Range Edge calculation //============================================================================ f_calcEntryBand_high() => _highest = max(open[3], close[3]) for i = 4 to (config_entryBandBars - 1) _highest := max(_highest, open[i], close[i]) _highest f_calcEntryBand_low() => _lowest = min(open[3], close[3]) for i = 4 to (config_entryBandBars - 1) _lowest := min(_lowest, open[i], close[i]) _lowest entryBand_high = f_calcEntryBand_high() entryBand_low = f_calcEntryBand_low() entryBand_height = entryBand_high - entryBand_low plot(entryBand_high, color=COLOR_ENTRY_BAND, linewidth=1) plot(entryBand_low, color=COLOR_ENTRY_BAND, linewidth=1) rangeBreakDetected_long = entryBand_high < close rangeBreakDetected_short = entryBand_low > close shouldMakeEntryLong = (strategy.position_size == 0) and rangeBreakDetected_long shouldMakeEntryShort = (strategy.position_size == 0) and rangeBreakDetected_short //============================================================================ // ATR based stuff //============================================================================ sl_atrHeight_tight = atr(config_slAtr_length) * config_slAtr_multi1 sl_atrHeight_slack = atr(config_slAtr_length) * config_slAtr_multi2 sl_tight_bull = min(open, close) - sl_atrHeight_tight sl_tight_bear = max(open, close) + sl_atrHeight_tight sl_slack_bull = min(open, close) - sl_atrHeight_slack sl_slack_bear = max(open, close) + sl_atrHeight_slack plot(sl_tight_bull, color=COLOR_SL_LINE_THIN, transp=0, linewidth=1) plot(sl_tight_bear, color=COLOR_SL_LINE_THIN, transp=0, linewidth=1) plot(sl_slack_bull, color=COLOR_SL_LINE_THIN, transp=0, linewidth=1) plot(sl_slack_bear, color=COLOR_SL_LINE_THIN, transp=0, linewidth=1) //============================================================================ // Sl //============================================================================ var trailingSl_long = hl2 var trailingSl_short = hl2 trailingSl_long := if hasLongPos max(trailingSl_long, sl_slack_bull) else sl_tight_bull trailingSl_short := if hasShortPos min(trailingSl_short, sl_slack_bear) else sl_tight_bear color_sl_long = hasLongPos ? COLOR_SL_LINE : COLOR_TRANSPARENT color_sl_short = hasShortPos ? COLOR_SL_LINE : COLOR_TRANSPARENT plot(trailingSl_long, color=color_sl_long, transp=0, linewidth=2) plot(trailingSl_short, color=color_sl_short, transp=0, linewidth=2) //============================================================================ // make entries //============================================================================ // Calculate start/end date and time condition startDate = timestamp(config_fromYear, config_fromMonth, config_fromDay, 00, 00) finishDate = timestamp(config_toYear, config_toMonth, config_toDay, 00, 00) if (true) if shouldMakeEntryLong strategy.entry(id="Long", long=true, stop=close) if shouldMakeEntryShort strategy.entry(id="Short", long=false, stop=close) strategy.exit('Long-SL/TP', 'Long', stop=trailingSl_long) strategy.exit('Short-SL/TP', 'Short', stop=trailingSl_short)