상대량 가격 전략 (relative volume price strategy) 은 비정상적인 거래량과 가격 변동성을 기반으로 하는 양적 거래 전략이다. 이 전략은 현재 거래량과 역사적 평균을 비교하여 거래량이 비정상적인지 여부를 결정한다. 또한 가격이 상대적으로 안정적인지 여부를 결정하기 위해 평균 진정한 범위 간격을 결합한다. 거래량이 비정상적으로 증가하고 가격이 상대적으로 안정적일 때, 그것은 입시 신호로 간주된다.
상대적 거래량 가격 전략의 핵심 논리는 판단을 위한 두 가지 지표에 기초합니다. 상대적 거래량과 가격 변동 범위입니다.
먼저, 우리는 가장 최근의 20 기간 동안 거래량의 단순한 이동 평균을 역사적인 평균 거래량으로 계산합니다. 그런 다음 우리는 여러 매개 변수를 설정합니다. 현재 거래량이 평균 거래량보다 1.5 배 이상일 때, 우리는 거래량이 비정상적이고
두 번째로, 우리는 가장 최근의 14 기간 동안의 평균 진정한 범위 (ATR) 를 가격 변동의 척도로 계산합니다. 동시에, 우리는 평균 변동의 표준편차를 계산합니다. 현재 진정한 변동이 평균 더 이상 또는 마이너스 한 표준편차 사이에 있다면, 우리는 가격 변동이 상대적으로 안정적인 범위 안에 있다고 생각합니다.
위의 두 가지 조건이 동시에 충족되면 긴 신호가 발행되어 긴 포지션을 개설합니다. 보유 기간 동안 ATR의 두 배가 스톱 로스 수준으로 사용되며, ATR의 두 배를 빼는 가장 높은 가격이 수익 수준으로 사용됩니다.
상대량 가격 전략의 가장 큰 장점은 비정상적인 거래량으로 인해 발생하는 가격 추세를 포착한다는 것입니다. 거래량이 급증하면 시장 참여자의 태도 변화가 나타납니다. 이는 종종 가격 브레이크와 새로운 트렌드의 형성을 신호합니다. 거래량과 역사적 평균 사이의 관계를 비교함으로써 전략은 비정상적인 거래량의 타이밍을 효과적으로 결정할 수 있습니다.
한편, 전략은 변동률을 고려하여 상대적으로 안정적인 가격 기간 동안 신호가 발생하도록합니다. 이것은 폭력적인 변동 중 최고치를 추격함으로써 발생하는 큰 손실 위험을 피합니다. 경향이 일반적으로 상대적 안정성 이후에 돌파되기 때문에 수익 기회를 증가시킵니다.
이 전략의 가장 큰 위험은 거래량 지표가 새로운 추세에 대해 100% 확신 할 수 없다는 것입니다. 거래량 급증은 잘못된 브레이크오웃이 될 수 있으며 가격이 빠르게 역전 될 수 있습니다. 그러한 경우 전략은 더 큰 손실을 겪습니다.
손실을 줄이기 위해,
이 전략은 다음과 같은 측면에서 최적화 될 수 있습니다.
거래량 비정상 신호를 더 신뢰할 수 있도록 변화 비율, 매출 등 다른 판단 지표를 추가하십시오.
ATR 매개 변수는 다른 주식에 최적화되어 안정적인 가격 범위를 더 정확하게 결정할 수 있습니다.
기계 학습 알고리즘을 추가해서 비정상적인 거래량을 평가할 수 있습니다. 단순히 역사적인 평균과 비교하는 것이 아니라요.
딥러닝 모델을 사용해서 가격 변동성을 예측합니다. 역사적인 ATR에 근거해서가 아니라요.
상대량 가격 전략은 특유의 신호로 비정상적인 거래량을 포착하고 거래 신호를 발행하기 위해 가격 안정 판단을 결합합니다. 전략은 간단하고 실용적이며 비정상적인 주식 거래량을 추적하는 데 잘 작동합니다. 그러나 효과를 향상시키기 위해 지표 판단에 의해 더 최적화되어야하는 잘못된 신호의 위험이 있습니다.
/*backtest start: 2022-12-21 00:00:00 end: 2023-12-27 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 (kevinhhl) //@version=4 strategy("[KL] Relative Volume + ATR Strategy",overlay=true,pyramiding=1) ENUM_LONG = "Long" // Timeframe { backtest_timeframe_start = input(defval = timestamp("01 Apr 2016 13:30 +0000"), title = "Backtest Start Time", type = input.time) USE_ENDTIME = input(false,title="Define backtest end-time (If false, will test up to most recent candle)") backtest_timeframe_end = input(defval = timestamp("01 May 2021 19:30 +0000"), title = "Backtest End Time (if checked above)", type = input.time) within_timeframe = true // } len_volat = input(14,title="Length of ATR to determine volatility") ATR_volat = atr(len_volat) avg_ATR_volat = sma(ATR_volat, len_volat) std_ATR_volat = stdev(ATR_volat, len_volat) // } // Trailing stop loss { ATR_X2_TSL = atr(input(14,title="Length of ATR for trailing stop loss")) * input(2.0,title="ATR Multiplier for trailing stop loss",type=input.float) TSL_source = low var stop_loss_price = float(0) TSL_line_color = color.green, TSL_transp = 100 if strategy.position_size == 0 or not within_timeframe TSL_line_color := color.black stop_loss_price := TSL_source - ATR_X2_TSL else if strategy.position_size > 0 stop_loss_price := max(stop_loss_price, TSL_source - ATR_X2_TSL) TSL_transp := 0 plot(stop_loss_price, color=color.new(TSL_line_color, TSL_transp)) // } // Signals for entry { _avg_vol = sma(volume,input(20, title="SMA(volume) length (for relative comparison)")) _relative_vol = _avg_vol * input(1.5,title="Multiple of avg vol to consider relative volume as being high",type=input.float) __lowerOfOpenClose = min(open,close) _wickRatio_lower = (__lowerOfOpenClose - low) / (high - low) entry_signal1 = volume > _relative_vol entry_signal2 = ATR_volat < avg_ATR_volat + std_ATR_volat and ATR_volat > avg_ATR_volat - std_ATR_volat // } alert_per_bar(msg)=> prefix = "[" + syminfo.root + "] " suffix = "(P=" + tostring(close) + "; atr=" + tostring(ATR_volat) + ")" alert(tostring(prefix) + tostring(msg) + tostring(suffix), alert.freq_once_per_bar) // MAIN: if within_timeframe if strategy.position_size > 0 and strategy.position_size[1] > 0 and (stop_loss_price/stop_loss_price[1]-1) > 0.005 alert_per_bar("TSL raised to " + tostring(stop_loss_price)) // EXIT :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // placed before entry, will re-enter if stopped out exit_msg = close <= strategy.position_avg_price ? "stop loss" : "take profit" if strategy.position_size > 0 and TSL_source <= stop_loss_price strategy.close(ENUM_LONG, comment=exit_msg) // ENTRY ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: if entry_signal1 and entry_signal2// and entry_signal3 entry_msg = strategy.position_size > 0 ? "adding" : "initial" strategy.entry(ENUM_LONG, strategy.long, comment=entry_msg) // CLEAN UP: if strategy.position_size == 0 stop_loss_price := float(0)