- VAA란?
- 공격자산, 수비자산으로 나누고 최근 실적에 따라 공격 or 수비자산으로 자산을 투자하는 전략
- 공격자산 : SPY(미국 주식), VEA(선진국 주식), VWO(개발도상국 주식), AGG(미국 잡채권)
- 수비자산 : SHY(미국 단기국채), IEF(미국 중기국채), LQD(미국 회사채)
- 상대모멘텀 : 4개 공격 자산 중 최근 잘 나가는 1개를 산다
- 단, 4개 공격 자산 중 하나라도 마이너스라면 수비로 전환
- 최근의 정의는 (12 * 1개월) + (4 * 3개월) + (2 * 6개월) + (1 * 12개월) 수익
- 공격자산, 수비자산으로 나누고 최근 실적에 따라 공격 or 수비자산으로 자산을 투자하는 전략
- 백테스팅은 tradingview를 통해 진행
- Pine 에디터에서 코딩가능
우선 다른 종목들을 불러와 보자
// ...
//@version=4
study("내 스크립트")
spy = security("SPY", timeframe.period, close)
// 티커 : SPY, 현재 그래프의 전체시간을 : timeframe.period, 종가기준으로 : close
plot(spy)
// 출력해달라
참고) 함수가 궁금할때 Pine 스크립트 언어 레퍼런스를 참조
- spy의 모멘텀 스코어를 구해보자
- 모멘텀 스코어 : (당월 종가 / 전월 종가)
- 당월 종가가 더 높다면 1초과 / 전월 종가가 높다면 1미만 출력될 것
- 우선 1개월 단위 수익률을 계산해 보자
([당월 종가] / [전월 종가] - 1) * 100
// ...
//@version=4
study("내 스크립트")
spy = security("SPY", timeframe.period, close)
y = (spy/spy[1]-1)*100
// y = (spy/spy[2]-1)*100 // 2개월 수익률
// y = (spy/spy[6]-1)*100 // 6개월 수익률
/*
spy : 당월 종가
spy[1] : 1개월 전 종가
spy[6] : 6개월 전 종가
*/
plot(y)
- 우리가 사용할 데이터는 1, 3, 6, 12 개월의 수익률이니
// ...
//@version=4
study("내 스크립트")
spy = security("SPY", timeframe.period, close)
// X개월 수익률을 구하는 함수를 만들어 보자
getYield(m) => (spy/spy[m]-1)*100 // m is month
y1 = getYield(1)
y3 = getYield(3)
y6 = getYield(6)
y12 = getYield(12)
plot(y1, "y1", color.red)
plot(y3, "y3", color.orange)
plot(y6, "y6", color.green)
plot(y12, "y12", color.blue)
- 모멘터 스코어의 점수를 구해보자
// ...
//@version=4
study("내 스크립트")
spy = security("SPY", timeframe.period, close)
getYield(m) => (spy/spy[m]-1)*100
score = 12 * getYield(1) + 4 * getYield(3) + 2 * getYield(6) + 1 * getYield(12)
plot(score, "score", color.red)
- 여기까지 spy의 스코어를 계산, 나머지 자산에 대하 스코어를 계산해보자
// ...
//@version=4
study("VAA")
// 공격
spy = security("AMEX:SPY", timeframe.period, close)
efa = security("AMEX:EFA", timeframe.period, close)
eem = security("AMEX:EEM", timeframe.period, close)
agg = security("AMEX:AGG", timeframe.period, close)
// 수비
lqd = security("AMEX:LQD", timeframe.period, close)
ief = security("NASDAQ:IEF", timeframe.period, close)
shy = security("NASDAQ:SHY", timeframe.period, close)
getYield(src, m) => (src/src[m]-1)*100
getScore(src) => 12 * getYield(src, 1) + 4 * getYield(src, 3) + 2 * getYield(src, 6) + 1 * getYield(src, 12)
// 공격
scoreSPY = getScore(spy)
scoreEFA = getScore(efa)
scoreEEM = getScore(eem)
scoreAGG = getScore(agg)
// 수비
scoreLQD = getScore(lqd)
scoreIEF = getScore(ief)
scoreSHY = getScore(shy)
plot(scoreSPY, "scoreSPY", color.red)
plot(scoreEFA, "scoreEFA", color.red)
plot(scoreEEM, "scoreEEM", color.red)
plot(scoreAGG, "scoreAGG", color.red)
plot(scoreLQD, "scoreLQD", color.blue)
plot(scoreIEF, "scoreIEF", color.blue)
plot(scoreSHY, "scoreSHY", color.blue)
백테스팅
// ...
//@version=4
study("각 공격형 자산의 모멘텀 스코어가 가장 높을때 월별 수익률")
// 공격
spy = security("AMEX:SPY", timeframe.period, close)
efa = security("AMEX:EFA", timeframe.period, close)
eem = security("AMEX:EEM", timeframe.period, close)
agg = security("AMEX:AGG", timeframe.period, close)
// 수비
lqd = security("AMEX:LQD", timeframe.period, close)
ief = security("NASDAQ:IEF", timeframe.period, close)
shy = security("NASDAQ:SHY", timeframe.period, close)
getYield(src, m) => (src/src[m]-1)*100
getScore(src) => 12 * getYield(src, 1) + 4 * getYield(src, 3) + 2 * getYield(src, 6) + 1 * getYield(src, 12)
// 공격
scoreSPY = getScore(spy)
scoreEFA = getScore(efa)
scoreEEM = getScore(eem)
scoreAGG = getScore(agg)
// 수비
scoreLQD = getScore(lqd)
scoreIEF = getScore(ief)
scoreSHY = getScore(shy)
// 공격 자산중 가장 작은 값이 0보다 작은지 확인
// 작을 경우 방어자산으로...
offenseCondition = not(min(scoreSPY, scoreEFA, scoreEEM, scoreAGG) < 0)
// defenseCondition = min(scoreLQD, scoreIEF, scoreSHY) < 0
// 공격형 자산의 점수
scoreOffense = max(scoreSPY, scoreEFA, scoreEEM, scoreAGG)
// 수비형 자산의 점수
scoreDefense = max(scoreLQD, scoreIEF, scoreSHY)
rangeSPY = getYield(spy, 1)
rangeEFA = getYield(efa, 1)
rangeEEM = getYield(eem, 1)
rangeAGG = getYield(agg, 1)
range = (scoreOffense[1] == scoreSPY[1]) ? rangeSPY : (scoreOffense[1] == scoreEFA[1]) ? rangeEFA : (scoreOffense[1] == scoreEEM[1]) ? rangeEEM : rangeAGG
plot(range, "range", color.red)
// ...
//@version=4
study("각 공격형 자산의 모멘텀 스코어가 가장 높을때 월별 수익률")
// 공격
spy = security("AMEX:SPY", timeframe.period, close)
efa = security("AMEX:EFA", timeframe.period, close)
eem = security("AMEX:EEM", timeframe.period, close)
agg = security("AMEX:AGG", timeframe.period, close)
// 수비
lqd = security("AMEX:LQD", timeframe.period, close)
ief = security("NASDAQ:IEF", timeframe.period, close)
shy = security("NASDAQ:SHY", timeframe.period, close)
getYield(src, m) => (src/src[m]-1)*100
getScore(src) => 12 * getYield(src, 1) + 4 * getYield(src, 3) + 2 * getYield(src, 6) + 1 * getYield(src, 12)
// 공격
scoreSPY = getScore(spy)
scoreEFA = getScore(efa)
scoreEEM = getScore(eem)
scoreAGG = getScore(agg)
// 수비
scoreLQD = getScore(lqd)
scoreIEF = getScore(ief)
scoreSHY = getScore(shy)
offenseCondition = not(min(scoreSPY, scoreEFA, scoreEEM, scoreAGG) < 0)
defenseCondition = min(scoreLQD, scoreIEF, scoreSHY) < 0
scoreOffense = max(scoreSPY, scoreEFA, scoreEEM, scoreAGG)
scoreDefense = max(scoreLQD, scoreIEF, scoreSHY)
rangeSPY = getYield(spy, 1)
rangeEFA = getYield(efa, 1)
rangeEEM = getYield(eem, 1)
rangeAGG = getYield(agg, 1)
rangeLQD = getYield(lqd, 1)
rangeIEF = getYield(ief, 1)
rangeSHY = getYield(shy, 1)
// 공격일때 공격자산 넣고 아닐때 0넣게 수정
range = offenseCondition
? ( (scoreOffense[1] == scoreSPY[1])
? rangeSPY : (scoreOffense[1] == scoreEFA[1])
? rangeEFA : (scoreOffense[1] == scoreEEM[1])
? rangeEEM : (scoreOffense[1] == scoreAGG[1])
? rangeAGG : 0 ) : 0
// 공격일때 공격자산 넣고 아닐때 수비형자산 넣게 수정
range2 = offenseCondition
? ( (scoreOffense[1] == scoreSPY[1])
? rangeSPY : (scoreOffense[1] == scoreEFA[1])
? rangeEFA : (scoreOffense[1] == scoreEEM[1])
? rangeEEM : rangeAGG )
: ( (scoreDefense[1] == scoreLQD[1])
? rangeLQD : (scoreDefense[1] == scoreIEF[1])
? rangeIEF : rangeSHY )
plot(range2, "range", color.red)
- Pine 스크립트에서 줄바꿈을 하고 싶을경우
// 들여쓰기(스페이스바) 주의
var = condition
? a
: b
누적수익률 계산하기
// ...
//@version=4
study("각 공격형 자산의 모멘텀 스코어가 가장 높을때 월별 수익률")
// 공격
spy = security("AMEX:SPY", timeframe.period, close)
efa = security("AMEX:EFA", timeframe.period, close)
eem = security("AMEX:EEM", timeframe.period, close)
agg = security("AMEX:AGG", timeframe.period, close)
// 수비
lqd = security("AMEX:LQD", timeframe.period, close)
ief = security("NASDAQ:IEF", timeframe.period, close)
shy = security("NASDAQ:SHY", timeframe.period, close)
getYield(src, m) => (src/src[m]-1)*100
getScore(src) => 12 * getYield(src, 1) + 4 * getYield(src, 3) + 2 * getYield(src, 6) + 1 * getYield(src, 12)
// 공격
scoreSPY = getScore(spy)
scoreEFA = getScore(efa)
scoreEEM = getScore(eem)
scoreAGG = getScore(agg)
// 수비
scoreLQD = getScore(lqd)
scoreIEF = getScore(ief)
scoreSHY = getScore(shy)
offenseCondition = not(min(scoreSPY, scoreEFA, scoreEEM, scoreAGG) < 0)
defenseCondition = min(scoreLQD, scoreIEF, scoreSHY) < 0
scoreOffense = max(scoreSPY, scoreEFA, scoreEEM, scoreAGG)
scoreDefense = max(scoreLQD, scoreIEF, scoreSHY)
rangeSPY = getYield(spy, 1)
rangeEFA = getYield(efa, 1)
rangeEEM = getYield(eem, 1)
rangeAGG = getYield(agg, 1)
rangeLQD = getYield(lqd, 1)
rangeIEF = getYield(ief, 1)
rangeSHY = getYield(shy, 1)
range = offenseCondition
? ( (scoreOffense[1] == scoreSPY[1])
? rangeSPY : (scoreOffense[1] == scoreEFA[1])
? rangeEFA : (scoreOffense[1] == scoreEEM[1])
? rangeEEM : (scoreOffense[1] == scoreAGG[1])
? rangeAGG : 0 ) : 0
range2 = offenseCondition
? ( (scoreOffense[1] == scoreSPY[1])
? rangeSPY : (scoreOffense[1] == scoreEFA[1])
? rangeEFA : (scoreOffense[1] == scoreEEM[1])
? rangeEEM : rangeAGG )
: ( (scoreDefense[1] == scoreLQD[1])
? rangeLQD : (scoreDefense[1] == scoreIEF[1])
? rangeIEF : rangeSHY )
var accRange = 0.0 // var = static
// 누적수익률
accRange := ((1 + accRange / 100) * (1 + range / 100) - 1) * 100
plot(accRange, "accRange", color.red)