/*
저도 금융권 주변에서 밥을 얻어먹으면서 살아온지라.. 말씀하시는 류의 데이터를 쪼물딱거려왔는데요.
주가데이터 핸들링하는 것에 대해 상당히 고민을 하시는 것 같은데... 아는 것은 별로 없지만.. 질문하신 것을 중심으로 어떻게 주가 데이터를 사용하는가에 대해 두서없이 말씀드려볼께요.
물론 위에서처럼 종목-날짜 순이 아니라, 날짜-종목순서로 배열될 수 있겠습니다만.. Sort하면 되니까 그건 별문제 안되고요..
위와 같은 형태의 데이터를 다룸에 있어,
1. 월별일평균수익률 구하시는 방법에 대해서는 님께서 말씀하신 수익률 계산방법 말고, 다른 방법을 써도 상관이 없다면,
(월말가격/전월말가격)의 거래일수제곱근 - 1 또는 자연로그((월말가격/전월말가격)의 거래일수제곱근) 를 사용하시는 것이 간편할 것 같고요. (사실, 잘 모르지만 간편함때문이라기 보다는 수익률의 연속성이라는 관점에서..^^)
2. 위의 데이터 형태처럼 순차적으로 데이터가 배치되어 있고 앞뒤 레코드의 변수간에 계산이 필요한 경우의 처리방법에 대해 몇가지를 생각해 볼 수 있는데요.
(1) 가장 간편한 방법이 lag함수를 사용하는 것이고,
(2) 조금 기교를 부린다면, 동일한 데이터를 엇갈리게 merge해서 처리하는 방법도 있습니다.
(3) 한편 종목코드+결산년월+계정과목의 구조를 가진 재무데이터처럼 구분에 따른 레코드의 수가 정해져 있는 경우에는 proc transpose를 사용해서 데이터의 방향을 돌린 다음 간편하게 변수(컬럼)사이의 계산(예를들어 재무비율을 계산하는 경우)방식을 취할 수도 있겠습니다만, 위의 경우처럼 날짜순서로 하염없이 데이터가 연속되는 경우에는 적당하지 않은 방법입니다.
4. 위와 같은 형태의 데이터를 다루는데 있어서 또 한가지 신경쓰이게 만드는 부분이 종목이 바뀌는 경우의 처리방법입니다.
즉, 레코드 사이의 계산을 하기 위해서는 레코드사이의 종목코드를 비교해 가면서 종목코드가 바뀌는 순간에는 lag값이 사용된 산식의 결과를 버리는 과정이 필요한데..
다른 일반적인 랭귀지에서는 별다른 대책이 없이 매번 종목코드를 비교하는 프로세스를 만들어 넣어주어야 하지만,
SAS에서는 first.변수, last.변수 의 형태로 사용하는 매우 강력한 툴을 가지고 있습니다.
/* lag함수를 이용하여 일일수익률 구하기 */
data juga1;
set juga;by code;
r= (price / lag(price)) - 1;
if first.code then r = .;
/* first.code는 윗줄에서 by code; 함으로써 SAS가 자동적으로 쓸 수있게 만든 변수인데..(SAS는 automatic variable이라고 부릅니다)
앞의 레코드에서 처리했던 code라는 변수가 가진 값과 이번에 처리하는 레코드의 code값이 같으면 FALSE(0), 다르면 TRUE(1)의 값을 가지게 됩니다. 즉, 새로운 code가 시작되는 순간 TRUE 값을 갖는 것이지요.
이런 류의 변수로 last.code도 있습니다. 미루어 짐작컨대.. 아시겠지요? 이번이 마지막코드라는 뜻입니다.
*/
/* 여기서 lag함수를 쓸 때 매우 조심하여야 할 점이 있는데... 다음처럼 lag함수를 조건절에 포함시켰다간... */
if first.code then r2=.;else r2 = (price / lag(price)) - 1;
/*
같은 결과를 보여줄 것 같지만.. 큰일납니다.
종목코드가 바뀔 때 r과 r2값이 어떤 값을 갖는지 비교해보세요.(2003년 12월1일 A000050의 r=-0.02133, r2=8.62963)
이렇게 되는 이유는.. lag함수가 가지는 값은 레코드의 물리적 위치에 따른 것이 아니라, scan한 순서에 따라 갖기 때문인데..
first.code가 TRUE인 경우, else 구문을 그대로 skip하게 되고 다음 레코드를 처리할 때, lag함수는 실제로는 전전레코드의 price값을 가지고 있기 때문입니다.
*/
run;
proc print;run;
/* 다음으로 위의 결과를 이용해서 월별 일평균수익률을 구하는 것은 여러 방법을 쓸 수 있는데....
1. data 스텝의 경우는, 일간 수익률을 누적할 변수와 거래일 수를 누적할 변수를 만들어서 retain한 다음, 위에서 이용한 first.변수를 이용해서 월이 바뀌는 순간 평균값을 계산하는 방식으로 만들면 되겠는데.. 아무래도 조금 복잡하겠지요?
2. 이런 것을 대비해서 SAS는 프로시져를 만들어 놓았는데.. proc means(또는 summary)가 그것입니다.
3. 그리고.. SQL을 이용할 수도 있습니다.
아시겠지만, SQL은 오라클, MS-SQL 등 범용DB를 다루는데에 기본이 되는 것이므로 굳이 SAS 때문이 아니더라도 배워두시는 것이 좋습니다. 비교적 문법도 간단하기 때문에 쉽게 접근하실 수 있을 겁니다.
SQL을 써본다면.. 다음과 같이 계산할 수 있겠습니다.
*/
proc sql;
create table monthly_return as
select code, yy, mm, mean(r) as return_mon, count(r) as return_cnt
from juga1
group by code, yy, mm;
quit;
proc print;run;
/*
한편, 앞서 말씀드렸던, 전월말가격과 금월말가격으로 월별일평균수익률을 구하는 것은 다음과 같이 계산하면 되겠군요.
*/
data monthly_return;
set juga;by code yy mm;
retain si cnt 0;
if first.code then do;si=price;cnt=0;end; *새로운 종목이 시작될 때의 가격을 최초월의 시초가로 하고 거래일수를 reset.;
if last.mm then /* 월말이 되면 -- 다음에 읽어들일 레코드의 code 또는 yy 또는 mm의 값이 현재 레코드의 것과 다르다면 last.mm=TRUE 가 됩니다. */
do;
r=log((price/si)**(1/cnt)); /* 앞서 잡아놨던 전월말값으로 현재의 가격을 나누어 제곱근을 구하고 자연로그를 취함 */
output; /* 계산결과를 출력 */
cnt=0; /* 거래일수를 reset */
si=price;/* 다음달의 수익률계산을 위해 현재의 월말가격을 다음달의 시가로 잡아놓음 */
end;
cnt+1; /* 거래일수 하나 증가 -- 거래일수라기 보다는 수익률 계산일수 */
run;
proc print;run;
/*
데이터 핸들링에 관한한, SAS만큼 간편하고 쉬운 툴이 없을 겁니다.
엑셀처럼 데이터를 보면서 다루는 것이 아니라서 문턱은 약간 높아 보이지만,
성의를 가지고 하다보면 금방 넘으실 수 있을 겁니다.
그렇지만 SAS를 익히기 위해 다른 랭귀지를 공부하신다던가 하는 것은 너무 돌아가시는 것이라고 생각합니다.
그럼...
*/
첫댓글최홍규님! 정말 대단하십니다. 옜말에 "세상은 넓고 인재는 많다"는 말이 이런 경우 사용하라고 있는가 봅니다. 저도 이번에 제가 아는 프로그래머 모두에 질문하여 해결법을 구했는데 그 중 한분이 sql을 추천하였습니다. 님의 말씀대로 공부하겠습니다. 모르는 것이 있으면 한번해보고 고민하다가 질문드리겠습니다. *^^*
첫댓글 최홍규님! 정말 대단하십니다. 옜말에 "세상은 넓고 인재는 많다"는 말이 이런 경우 사용하라고 있는가 봅니다. 저도 이번에 제가 아는 프로그래머 모두에 질문하여 해결법을 구했는데 그 중 한분이 sql을 추천하였습니다. 님의 말씀대로 공부하겠습니다. 모르는 것이 있으면 한번해보고 고민하다가 질문드리겠습니다. *^^*
정말 대단 동감!! 많이 배웁니다.