ATR 기반 평균 회귀 전략


생성 날짜: 2023-10-17 16:27:44 마지막으로 수정됨: 2023-10-17 16:27:44
복사: 2 클릭수: 890
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

ATR 기반 평균 회귀 전략

개요

이 전략은 가정 테스트의 방법을 사용하여 ATR이 평균에서 벗어났는지 판단하고, 가격 움직임에 대한 예측과 결합하여 ATR을 기반으로 한 평균 회귀 거래 전략을 구현합니다. ATR이 눈에 띄는 편차가 발생하면 시장이 비정상적인 변동이있을 수 있음을 나타냅니다.

전략 원칙

  1. 가설 테스트

    • 빠른 ATR 주기 ((변수atr_fast) 과 느린 ATR 주기 ((변수atr_slow) 의 두 샘플 t 검사를 수행한다. 가설 검사의 0 가설 H0은 두 샘플의 평균값으로 뚜렷한 차이가 없다.

    • 테스트 통계가 임계값 (the confidence interval specified by the parameter reliability_factor) 보다 높으면, 빠른 ATR이 느린 ATR에서 명백하게 이탈했다고 보는 기본 가설을 거부한다.

  2. 가격 추세

    • 좌표 수익률의 이동 평균을 예상 기동율 (변수 기동) 으로 계산한다.

    • 만약 유류율이 상승한다면, 현재는 낙관주의적 경향이라고 판단할 수 있다.

  3. 입점과 퇴출

    • 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