
선물 트레이딩의 전설
*2022-02-02 글
Larry Willams, 그는 누구인가
래리 윌리엄스는 1942년 10월 6일에 태어나 트레이딩으로 이름을 알린 인물입니다.
주로 선물시장에서 단기적으로 거래를 하는 전략만을 추구하였으며,
윌리엄스가 만든 지표들에는 Williams' AD(Williams' Accumulation / Distribution), Williams' %R 등, 지표를 많이 접한 분들에게 익숙한 지표들이 있습니다.
저서
- - Long-term secrets to short-term trading
- - The right stock at the right time
- - How to Prosper in the Coming Good Years
투자 방법
그의 투자 방법은 "변동성돌파전략"으로 널리 알려진 방법이 대표적입니다.
변동성돌파전략이란, 단기적으로 형성되어있는 변동성 밖으로 추세가 흘러가면 그에 맞게 포지션을 정하는 것을 의미합니다.
해당 전략을 지표화한 자료로 설명드리겠습니다.
지표 상의 밴드 밖으로 시세가 이탈됨에 따라 중앙선의 색이 바뀌게끔 설정 된 지표입니다.
중앙선이 녹색일 때 시세가 오르는 성향, 중앙선이 적색일 때 시세가 내리는 성향이 존재한다는 것을 확인할 수 있습니다.
그런데 추세는 단순이동평균선만으로도 확인할 수 있지 않던가요?
맞습니다. 추세는 단순이동평균만으로도 확인이 가능합니다. 하나의 기준일 뿐이기 때문입니다.
위자료는 20일과 50일 단순이동평균을 나타낸 자료입니다. 이 두개만으로도 충분히 추세를 확인할 수 있는 모습입니다.
그러나 왜 윌리엄스는 이러한 전략을 채택하였을까요?
여기에는 몇가지 이유가 존재하는 것으로 확인됩니다.
- - 시세에 직관적인 영향을 받는 변동성을 채택하였기에 추세전환의 판단기준이 민감함
- - 시장 상황(변동성)에 기준이 조정됨
- - 추세를 판단하기 어려운 상황(ex.이동평균선이 서로 겹치는 상황)에서 추세에 대해 보다 명확한 판단을 내릴 수 있음
두가지를 비교해보았습니다. 확실히 변동성을 기준으로 추세를 정의한 쪽이 더 직관적임을 알 수 있습니다. 물론 이동평균선의 기간을 줄이면 추세의 전환을 더 신속하게 판단할 수는 있겠으나, 이동평균선은 기간이 짧아질수록 불필요한 움직임이 많아진다는 특징이 존재합니다.
이런식으로 추세 중간에 기준의 변화가 너무 자주 일어난다면 거래빈도수가 증가하게 되고,
증가하는 거래빈도수에 적당한 손익비와 승률이 뒷받침되지 못한다면 결국 손실로 이어지게 됩니다.
그렇기에 이는 비효율적이라고 말씀드릴 수 있습니다. 다행히 변동성을 기준으로 한 방법은 필요 이상의 거래로 유도하지 않는 모습입니다.
그런데, 이 기준만으로 수익을 꾸준히 낼 수 있을까요?
아닙니다. 그는 그의 리스크관리방법이 있었기 때문에 손실에 대한 자금관리를 꾸준히 이어올 수 있었습니다.
윌리엄스는 보수적인 투자자들은 ~5%, 보통의 투자자들이라면 ~10%, 리스크를 선호하는 투자자들은 ~15%로 투자하는 것을 권장하였습니다.
그는 계약의 수를 본인이 생각하는 리스크 정도에 따라 다르게 결정하였고, 그 방법은 다음과 같습니다.
(Account balance * Risk percent) / Largest loss = Contracts or shares to trade
- Largest Loss = Peak/Valley Drawdown
- Risk percent = personal risk/reward expectation (5% to 18%)
해석하자면,
(자산 잔액 * 리스크비율) / 최대손실 = 거래 할 계약 혹은 주식의 수
- 최대 손실 = MDD
- 리스크비율 = 손실 감안 (5% ~ 18%)
예시를 들어보겠습니다.
자산 잔액이 1,000,000원이라고 가정하고, 리스크 비율, 즉 손실 10%까지는 괜찮겠다라고 생각하겠습니다.
전략을 백테스팅해본 결과 MDD가 5%, 즉 50,000원 일 때, 계산을 해보면
(1,000,000 * 10%) / 50,000 = 2
2계약까지는 괜찮은 것으로 계산됩니다.
TradingView
앞서 소개드린 지표의 코드입니다. 아래 링크를 참고하셔서 사용하시면 적용하실 수 있습니다.
참고글: 난 내가 코딩해서 투자해: TradingView 따라잡기 (입문편)
//@version=4 study(title="변동성돌파", overlay=true) //Conditional Sampling EMA Function Cond_EMA(x, cond, n)=> var val = array.new_float(0) var ema_val = array.new_float(1) if cond array.push(val, x) if array.size(val) > 1 array.remove(val, 0) if na(array.get(ema_val, 0)) array.fill(ema_val, array.get(val, 0)) array.set(ema_val, 0, (array.get(val, 0) - array.get(ema_val, 0))*(2/(n + 1)) + array.get(ema_val, 0)) EMA = array.get(ema_val, 0) EMA //Conditional Sampling SMA Function Cond_SMA(x, cond, n)=> var vals = array.new_float(0) if cond array.push(vals, x) if array.size(vals) > n array.remove(vals, 0) SMA = array.avg(vals) SMA //Standard Deviation Function Stdev(x, n)=> sqrt(Cond_SMA(pow(x, 2), 1, n) - pow(Cond_SMA(x, 1, n), 2)) //Range Size Function rng_size(x, scale, qty, n)=> ATR = Cond_EMA(tr(true), 1, n) AC = Cond_EMA(abs(x - x[1]), 1, n) SD = Stdev(x, n) rng_size = scale=="Pips" ? qty*0.0001 : scale=="Points" ? qty*syminfo.pointvalue : scale=="% of Price" ? close*qty/100 : scale=="ATR" ? qty*ATR : scale=="Average Change" ? qty*AC : scale=="Standard Deviation" ? qty*SD : scale=="Ticks" ? qty*syminfo.mintick : qty //Two Type Range Filter Function rng_filt(h, l, rng_, n, type, smooth, sn, av_rf, av_n)=> rng_smooth = Cond_EMA(rng_, 1, sn) r = smooth ? rng_smooth : rng_ var rfilt = array.new_float(2, (h + l)/2) array.set(rfilt, 1, array.get(rfilt, 0)) if type=="Type 1" if h - r > array.get(rfilt, 1) array.set(rfilt, 0, h - r) if l + r < array.get(rfilt, 1) array.set(rfilt, 0, l + r) if type=="Type 2" if h >= array.get(rfilt, 1) + r array.set(rfilt, 0, array.get(rfilt, 1) + floor(abs(h - array.get(rfilt, 1))/r)*r) if l <= array.get(rfilt, 1) - r array.set(rfilt, 0, array.get(rfilt, 1) - floor(abs(l - array.get(rfilt, 1))/r)*r) rng_filt1 = array.get(rfilt, 0) hi_band1 = rng_filt1 + r lo_band1 = rng_filt1 - r rng_filt2 = Cond_EMA(rng_filt1, rng_filt1 != rng_filt1[1], av_n) hi_band2 = Cond_EMA(hi_band1, rng_filt1 != rng_filt1[1], av_n) lo_band2 = Cond_EMA(lo_band1, rng_filt1 != rng_filt1[1], av_n) rng_filt = av_rf ? rng_filt2 : rng_filt1 hi_band = av_rf ? hi_band2 : hi_band1 lo_band = av_rf ? lo_band2 : lo_band1 [hi_band, lo_band, rng_filt] //Inputs //Filter Type f_type = input(defval="Type 1", options=["Type 1", "Type 2"], title="Filter Type") //Movement Source mov_src = input(defval="Close", options=["Wicks", "Close"], title="Movement Source") //Range Size Inputs rng_qty = input(defval=2.618, minval=0.0000001, title="Range Size") rng_scale = input(defval="Average Change", options=["Points", "Pips", "Ticks", "% of Price", "ATR", "Average Change", "Standard Deviation", "Absolute"], title="Range Scale") //Range Period rng_per = input(defval=14, minval=1, title="Range Period (for ATR, Average Change, and Standard Deviation)") //Range Smoothing Inputs smooth_range = input(defval=false, title="Smooth Range") smooth_per = input(defval=27, minval=1, title="Smoothing Period") //Filter Value Averaging Inputs av_vals = input(defval=false, title="Average Filter Changes") av_samples = input(defval=2, minval=1, title="Number Of Changes To Average") //Definitions //High And Low Values h_val = mov_src=="Wicks" ? high : close l_val = mov_src=="Wicks" ? low : close //Range Filter Values [h_band, l_band, filt] = rng_filt(h_val, l_val, rng_size((h_val + l_val)/2, rng_scale, rng_qty, rng_per), rng_per, f_type, smooth_range, smooth_per, av_vals, av_samples) //Direction Conditions var fdir = 0.0 fdir := filt > filt[1] ? 1 : filt < filt[1] ? -1 : fdir upward = fdir==1 ? 1 : 0 downward = fdir==-1 ? 1 : 0 //Colors filt_color = upward ? #05ff9b : downward ? #ff0583 : #cccccc bar_color = upward and (close > filt) ? (close > close[1] ? #05ff9b : #00b36b) : downward and (close < filt) ? (close < close[1] ? #ff0583 : #b8005d) : #cccccc //Outputs //Filter Plot filt_plot = plot(filt, color=filt_color, linewidth=3, transp=0, title="Filter") //Band Plots h_band_plot = plot(h_band, color=#05ff9b, transp=100, title="High Band") l_band_plot = plot(l_band, color=#ff0583, transp=100, title="Low Band") //Band Fills fill(h_band_plot, filt_plot, color=#00b36b, transp=85, title="High Band Fill") fill(l_band_plot, filt_plot, color=#b8005d, transp=85, title="Low Band Fill") //Bar Color barcolor(bar_color) //External Trend Output plot(fdir, transp=100, editable=false, display=display.none, title="External Output - Trend Signal")