스트래티지에서 비현실적인 미래 결과가 나옵니다

파인 랭귀지를 개발한 것은 유저엑 되도록 많은 쓸모있는 툴을 만들어 주고자 함입니다. 이러한 툴은 여러 쓸모가 있으며, 몇몇 인디케이터 및 차트 타입들은 약간의 작업으로 미래의 바 또는 트레이드 데이터를 뽑을 수 있도록 해 줍니다 (현재 처리되는 바 기준으로). 이러한 데이터를 트레이더는 실시간으로 받을 수 없기 때문에 그 기반으로 만들어진 스트래티지는 백테스팅에서는 믿을 수 없는 프라핏 결과를 내지만 실제 트레이딩에서는 이러한 트레이드는 로스를 내곤 합니다. 스트래티지에서 미래 정보를 쓰는 실수를 룩어헤드 바이어스라 부릅니다.

몇몇 트레이딩뷰 유저들은, 잘 모르고 그랬던 아니면 나쁜 마음을 먹고 그랬던, 이러한 피처를 악용해 아이디어나 스크립트 퍼블리싱을 하곤 합니다. 트레이딩뷰는 이 피처 자체는 쓸모가 있기 때문에 없앨 순 없지만 또한 동시에 이러한 행동을 하는 유저에게 경고를 하고 있습니다.

일본 스타일 캔들을 쓰는 스트래티지

이러한 행동을 하는 흔한 까닭은 일본 스타일 차트 (렌코, 카기 등) 에 대한 스트래티지 백테스팅입니다. 스트래티지 백테스팅 엔진은 각 바를 오픈, 하이, 로우, 클로즈 이 4 개 프라이스의 트랜잭션으로 보기 때문에 문제가 생기는 것입니다 (레귤러 캔들 스틱 차트에서도 마찬가지). 이 때문에 렌코 차트에서는 스트래티지 백테스팅 엔진은 실제로는 없는 프라이스에서 포지션을 엔터/엑싯할 수 있게 됩니다. 게다가, 박스 사이즈 밸류를  mintick 보다 더 작게 세팅하면 백테스팅 엔진이 실제 프라이스를 처리하기 앞서 넥스트 프라이스가 커런트 프라이스보다 높을지 아니면 낮을지를 체크한 뒤 미리 포지션을 엔터/엑싯할 수 있습니다.

//@version=4strategy("My Strategy", overlay=true)if close < close[1]    strategy.entry("ShortEntryId", strategy.short)strategy.close("ShortEntryId", when = close > close[1])if close > close[1]    strategy.entry("LongEntryId", strategy.long)strategy.close("LongEntryId", when = close < close[1])
JavaScript
위 스크린샷에서 보시다시피 이 심플한 스트래티지로 맥시멈/미니멈에 아주 가까운 프라이스로 거래를 할 수 있습니다.

calc_on_order_fills = true파라미터를 쓰는 스트래티지 

스트래티지 펑크션에 calc_on_order_fills = true 파라미터를 쓰면 백테스팅 엔진은 오더가 체결된 뒤 그 바안에서 셈을 더하게 됩니다 (보통 스트래티지는 그 바의 클로즈에 딱 한 번 셈이 됩니다). 그 셈을 하면서 스트래티지는 하이 및 로우 밸류 등 여러 바 파라미터를 읽게 됩니다. 이것이 바로 백테스팅에서 엄청난 퍼포먼스를 내는 스트래티지를 쓸 수 있는 까닭입니다:
//@version=4strategy("CalcOnOrderFillsStrategy", overlay=true, calc_on_order_fills=true)// a variable is used to prevent double entry on the same barvar lastTimeEntry = 0 longCondition = close > sma(close, 14)  and lastTimeEntry != timeif longCondition    strategy.entry("LongEntryId", strategy.long) strategy.exit("exitId", "LongEntryId", limit=high)lastTimeEntry := time
JavaScript

위 스크린샷에서 바의 오픈 프라이스에 엔트리를 하고 같은 바의 하이에 엑싯을 함을 볼 수 있습니다. 그러니까 오더가 실행된 뒤 셈을 하면서 strategy.exit 리밋 프라이스를 커런트 바의 하이 레벨과 같도록 셋을 하는데 이는 리얼 트레이딩에서는 할 수 없습니다.

파인 security 의 lookahead = barmerge.lookahead_on 파라미터

파인 security 펑크션으로 다른 심볼 및 타임 프레임에 대해 데이터를 불러올 수 있습니다. 이 기능으로 스트래티지에서 미래 데이터를 받을 수 있습니다: 보기로, 백테스팅을 하면서 데일리 바의 클로즈나 하이를 요청하면 그 스트래티지는 그 날의 오픈때 바로 이들 값을 알수 있게 됩니다.

버전 3 전에는, security 펑크션은 액세스할 수조차 없는 더 높은 타임프레임의 값을 리턴하였습니다. 버전 3에서 이 버그는 필스되었지만 호완성을 위해 lookahead 파라미터를 security 펑크션에 더했습니다. 디폴트는 false 입니다 (i.e., future vision 은 오프입니다). 하지만 lookahead 파라미터 밸류를 barmerge.lookahead_on 으로 셋하여 켤 수 있습니다).

이 피처를 써서 만든 프라핏 스트래티지 보기입니다:

//@version=4strategy("My Strategy", overlay=true)dayStart = security(syminfo.tickerid, "1D", time, lookahead=barmerge.lookahead_on)dayHigh = security(syminfo.tickerid, "1D", high, lookahead=barmerge.lookahead_on)dayLow = security(syminfo.tickerid, "1D", low, lookahead=barmerge.lookahead_on)// entry at first bar of a dayif time == dayStart    // distance to daily high is further, so we can earn more    if abs(open - dayHigh) > abs(open - dayLow)        strategy.entry("LongEntryId", strategy.long)        strategy.exit("exitLongId", "LongEntryId", limit=dayHigh)    else        strategy.entry("ShortEntryId", strategy.short)        strategy.exit("exitShortId", "ShortEntryId", limit=dayLow)        plot(dayHigh)plot(dayLow)
JavaScript

첫 바에서 오프닝 프라이스 대비 프라이스가 오를 지 내릴 지를 분석한 뒤 이를 바탕으로 롱 또는 숏 포지션을 들어가고 그 날의 맥시멈 또는 미니멈 프라이스에 엑싯을 합니다.

Note that not all cases where security() 가 barmerge.lookahead_on 아규먼트를 가진 모든 security() 가 다 앞날을 들여다 보는 것은 아닙니다: 보기로, 위 코드에서  security() 안의 time/high/low 를 time[1]/high[1]/low[1] 로 바꾸면 이미 클로즈된 바의 밸류를 받게 됩니다. 경험이 많은 트레이더는 이 방법으로 아무런 lookahead 리스크없이 security() 로부터 데이터를 받곤 합니다.

현재는 이러한 방법으로 스트래티지에서 미래를 들여다 볼 수 있습니다. 이 설명으로 여러분이 이러한 단점이 없는 스트래티지를 만드는데 도움이 되기를 바라며 아울러 이러한 피처를 악용하는 오써가 퍼블리쉬한 스트래티지를 피할 수 있기를 바랍니다.