ATR에 기초한 평균 반전 전략

저자:차오장, 날짜: 2023-10-17 16:27:44
태그:

img

전반적인 설명

이 전략은 ATR이 평균값에서 벗어나지 않는지 확인하기 위해 가설 테스트를 사용합니다. 가격 트렌드 예측과 결합하여 ATR에 기반한 평균 반전 전략을 구현합니다. ATR의 상당한 편차는 시장의 잠재적인 비정상적인 변동성을 나타냅니다. 가격 트렌드가 상승할 것으로 예측되면 긴 포지션을 설정 할 수 있습니다.

전략 논리

  1. 가설 검증

    • 빠른 ATR 기간 (atr_fast) 과 느린 ATR 기간 (atr_slow) 사이 두 샘플의 t 테스트를 수행합니다. null 가설 H0은 두 샘플 평균 사이에 중요한 차이가 없다는 것입니다.

    • 테스트 통계치가 임계값을 초과하면 (reliability_factor에 의해 지정된 신뢰도 간격) null 가설을 거부합니다. 즉, 빠른 ATR은 느린 ATR에서 현저하게 벗어나는 것으로 간주됩니다.

  2. 가격 동향 예측

    • 로그리듬적 수익의 이동 평균은 예상되는 유동률 (drift) 으로 계산됩니다.

    • 추세가 증가하면 현재 추세는 상승 추세로 평가됩니다.

  3. 진입 및 중지 손실 출입

    • 빠른 ATR와 느린 ATR가 크게 다르며 추세가 상승할 때 긴 경로로 이동합니다.

    • ATR을 사용하여 지속적으로 스톱 로스를 조정합니다. 가격이 스톱 로스 이하로 떨어지면 위치에서 빠져 나갑니다.

이점 분석

  • ATR 오차를 결정하기 위해 가설 테스트를 사용하는 것은 더 과학적이고 적응적입니다.

  • 가격 트렌드 예측과 결합하면 ATR 오차에만 기반한 잘못된 거래를 피할 수 있습니다.

  • 스톱 로스를 조정하면 계속 하향 위험을 관리할 수 있습니다.

위험 분석

  • 가격이 떨어지면 손실을 막을 수 없습니다.

  • 잘못된 트렌드 예측은 상위에서 구매로 이어질 수 있습니다.

  • 부적절한 매개 변수 설정은 올바른 입력 또는 불필요한 거래를 추가 할 수 있습니다.

최적화 제안

  • 오류를 피하기 위해 여러 요소 확인을 위한 다른 지표를 추가하는 것을 고려하십시오.

  • 더 안정적인 값을 찾기 위해 다른 ATR 매개 변수 조합을 테스트합니다.

  • 잘못된 파장을 피하기 위해 주요 가격 레벨의 돌파에 대한 기준을 추가합니다.

결론

이 전략의 전반적인 논리는 분명하다. 비정상적인 변동성을 감지하기 위해 가설 테스트를 사용하는 것은 합리적이다. 그러나 ATR 오차만으로는 트렌드를 결정하기에 충분하지 않다. 정확성을 향상시키기 위해 더 많은 확인 요인이 필요합니다. 스톱 손실 규칙은 신뢰할 수 있지만 절벽 스타일 충돌에 대해 효과적이지 않습니다. 입시 기준, 매개 변수 선택, 스톱 손실 최적화와 같은 분야에서 향후 개선이 가능합니다.


/*backtest
start: 2022-10-16 00:00:00
end: 2023-10-16 00:00:00
period: 1d
basePeriod: 1h
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/
// © DojiEmoji

//@version=5
strategy("Mean Reversion (ATR) Strategy v2 [KL] ", overlay=true, pyramiding=1)
var string ENUM_LONG = "Long"
var string GROUP_TEST = "Hypothesis testing"
var string GROUP_TSL = "Stop loss"
var string GROUP_TREND = "Trend prediction"

backtest_timeframe_start = input(defval=timestamp("01 Apr 2000 13:30 +0000"), title="Backtest Start Time")
within_timeframe = true

// TSL: calculate the stop loss price. {
ATR_TSL      = ta.atr(input(14, title="Length of ATR for trailing stop loss", group=GROUP_TSL)) * input(2.0, title="ATR Multiplier for trailing stop loss", group=GROUP_TSL)
TSL_source      = low
TSL_line_color  = color.green
TSL_transp      = 100
var stop_loss_price = float(0)

if strategy.position_size == 0 or not within_timeframe
    TSL_line_color := color.black
    stop_loss_price := TSL_source - ATR_TSL
else if strategy.position_size > 0
    stop_loss_price := math.max(stop_loss_price, TSL_source - ATR_TSL)
    TSL_transp := 0

plot(stop_loss_price, color=color.new(TSL_line_color, TSL_transp))
// } end of "TSL" block

// Entry variables {
// ATR diversion test via Hypothesis testing (2-tailed):
//     H0 : atr_fast equals atr_slow
//     Ha : reject H0 if z_stat is above critical value, say reliability factor of 1.96 for a 95% confidence interval
len_fast    = input(14,title="Length of ATR (fast) for diversion test", group=GROUP_TEST)
atr_fast    = ta.atr(len_fast)
std_error   = ta.stdev(ta.tr, len_fast) / math.pow(len_fast, 0.5) // Standard Error (SE) = std / sq root(sample size)

atr_slow = ta.atr(input(28,title="Length of ATR (slow) for diversion test", group=GROUP_TEST))
test_stat = (atr_fast - atr_slow) / std_error
reject_H0 = math.abs(test_stat) > input.float(1.645,title="Reliability factor", tooltip="Strategy uses 2-tailed test; Confidence Interval = Point Estimate (avg ATR) +/- Reliability Factor x Standard Error; i.e use 1.645 for a 90% confidence interval", group=GROUP_TEST)

// main entry signal, subject to confirmation(s), gets passed onto the next bar
var _signal_diverted_ATR = false
if not _signal_diverted_ATR
    _signal_diverted_ATR := reject_H0


// confirmation: trend prediction; based on expected lognormal returns
_prcntge_chng = math.log(close / close[1]) 

// Expected return (drift) = average percentage change + half variance over the lookback period
len_drift = input(14, title="Length of drift", group=GROUP_TREND)
_drift = ta.sma(_prcntge_chng, len_drift) - math.pow(ta.stdev(_prcntge_chng, len_drift), 2) * 0.5
_signal_uptrend = _drift > _drift[1]

entry_signal_all = _signal_diverted_ATR and _signal_uptrend // main signal + confirmations
// } end of "Entry variables" block

// MAIN {
// Update the stop limit if strategy holds a position
if strategy.position_size > 0 and ta.change(stop_loss_price)
    strategy.exit(ENUM_LONG, comment="sl", stop=stop_loss_price)

// Entry
if within_timeframe and entry_signal_all
    strategy.entry(ENUM_LONG, strategy.long, comment=strategy.position_size > 0 ? "adding" : "initial")

// Alerts
_atr = ta.atr(14)
alert_helper(msg) =>
    prefix = "[" + syminfo.root + "] "
    suffix = "(P=" + str.tostring(close, "#.##") + "; atr=" + str.tostring(_atr, "#.##") + ")"
    alert(str.tostring(prefix) + str.tostring(msg) + str.tostring(suffix), alert.freq_once_per_bar)

if strategy.position_size > 0 and ta.change(strategy.position_size)
    if strategy.position_size > strategy.position_size[1]
        alert_helper("BUY")
    else if strategy.position_size < strategy.position_size[1]
        alert_helper("SELL")

// Clean up - set the variables back to default values once no longer in use
if strategy.position_size == 0
    stop_loss_price := float(0)
if ta.change(strategy.position_size)
    _signal_diverted_ATR := false
// } end of MAIN block

더 많은