본문 바로가기

코딩

제일제당, 존버가 답이었을까? -4편

이제부터 본격적으로 한 번 만들어보겠다.

R의 TTR package(이름부터 Techical Trading Rulesㄷㄷ)와 tidyquant package를 주로 사용하였다.

 

library(readr)
library(tidyverse)
library(lubridate)
library(tsibble)
library(tidyquant)
library(TTR)
library(ggpubr)

 

우선, 데이터부터 받아야 한다.

이전 편에는 한국거래소로부터 직접 다운로드하였다면, 이번에는 tidyquant package의 기능을 이용하겠다.

tidyverse 생태계는 ㄹㅇ 신세계

 

먼저 위와 같이 해당 url에서 종목코드와 종목명을 받아온다. 세종기업데이터에서 받아올 수 있는데, 박찬엽 연구원님의 Github에서 내용을 참고했다.

https://mrchypark.github.io/kisa_finR/

 

금융데이터 분석을 위한 R을 이용한 개발 입문

tidy data 개념과 dplyr+tidyr로 데이터 다루기 데이터 분석을 어렵게 하는 여러 이유들이 있습니다. 이게 개발 커뮤니티에서 말하는 기술 부채와 같은 개념이지 않나 생각이 들어 데이터 부채라는 표

mrchypark.github.io

url<-"https://github.com/mrchypark/sejongFinData/raw/master/codeData.csv"
download.file(url,destfile = "codeData.txt")
codeData<-read_csv("codeData.txt")

> str(codeData)
spec_tbl_df [2,260 x 2] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ 종목번호: chr [1:2260] "005930" "000660" "005935" "005380" ...
 $ 종목명  : chr [1:2260] "삼성전자" "SK하이닉스" "삼성전자우" "현대차" ...
 - attr(*, "spec")=
  .. cols(
  ..   종목번호 = col_character(),
  ..   종목명 = col_character()
  .. )
 - attr(*, "problems")=<externalptr>

 

종목번호와 종목명으로 이루어진 데이터를 확인하였다.

이후, "tidyquant package"의 "tq_get()" 함수에 종목코드를 넣으면 해당 주식의 주가정보를 받아올 수 있다.

한국 주식의 경우, "종목번호.KS"의 형식으로 넣어주면 된다.

미국 주식의 경우에는 티커만 넣어주면 된다. 

 

stockdata<- tq_get(
	paste0(codeData2 %>% 
    filter(종목명=="CJ제일제당") %>% 
    select(종목번호),".KS")
    )
    
> str(stockdata)
tibble [2,656 x 8] (S3: tbl_df/tbl/data.frame)
 $ symbol  : chr [1:2656] "097950.KS" "097950.KS" "097950.KS" "097950.KS" ...
 $ date    : Date[1:2656], format: "2011-01-03" "2011-01-04" "2011-01-05" "2011-01-06" ...
 $ open    : num [1:2656] 217000 215500 214500 211500 213000 ...
 $ high    : num [1:2656] 218500 216500 215000 213000 215500 ...
 $ low     : num [1:2656] 214000 213500 210000 211500 212500 ...
 $ close   : num [1:2656] 215500 214500 212000 213000 213500 ...
 $ volume  : num [1:2656] 60549 60286 101609 52073 51354 ...
 $ adjusted: num [1:2656] 198498 197577 195275 196196 196656 ...

 

그다음, 이동평균선을 추가해주려 했는데,

 

> stockdata %>% 
+   mutate(ma5=SMA(close,5),
+          ma20=SMA(close,20),
+          ma120=SMA(close,120)
+          )
Error: Problem with `mutate()` column `ma5`.
i `ma5 = SMA(close, 5)`.
x Series contains non-leading NAs
Run `rlang::last_error()` to see where the error occurred.

 > stockdata[is.na(stockdata$close)==TRUE,]
# A tibble: 5 x 8
  symbol    date        open  high   low close volume adjusted
  <chr>     <date>     <dbl> <dbl> <dbl> <dbl>  <dbl>    <dbl>
1 097950.KS 2017-11-16    NA    NA    NA    NA     NA       NA
2 097950.KS 2017-11-23    NA    NA    NA    NA     NA       NA
3 097950.KS 2018-01-02    NA    NA    NA    NA     NA       NA
4 097950.KS 2018-11-15    NA    NA    NA    NA     NA       NA
5 097950.KS 2019-11-14    NA    NA    NA    NA     NA       NA

 

그런데, NA가 있어서 오류가 나타났다. 5개의 날짜에 NA값이 존재했다. 저 날짜에는 거래가 이뤄졌는데, 이유가 뭘까?

귀찮아서 그냥 제거하고 진행하기로 했다. 이후에는 잘 돌아간다.

 

그런데, 갑자기 든 궁금증

내가 Rollmean함수로 구하는 것과 SMA함수로 구하는 것의 차이가 있을까?

 

> head(rollmean(stockdata_ma$close,20,fill=NA,align="right"),50)
 [1]     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
[15]     NA     NA     NA     NA     NA 206050 204900 203825 202900 201975 201300 200825 200350 199875
[29] 199350 199025 198750 198725 199025 199450 199600 199575 199650 199650 199775 199975 200675 201325
[43] 201950 202700 203275 204350 205225 205950 207075 207925

> head(SMA(stockdata_ma$close,20),50)
 [1]     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA     NA
[15]     NA     NA     NA     NA     NA 206050 204900 203825 202900 201975 201300 200825 200350 199875
[29] 199350 199025 198750 198725 199025 199450 199600 199575 199650 199650 199775 199975 200675 201325
[43] 201950 202700 203275 204350 205225 205950 207075 207925

 

결과는 동일한데,

 

> microbenchmark(rollmean(stockdata_ma$close,20,fill=NA,align="right"),times = 100)
Unit: microseconds
                                                         expr   min    lq    mean median  uq    max neval
 rollmean(stockdata_ma$close, 20, fill = NA, align = "right") 600.8 612.5 747.474 619.45 657 9933.1   100

> microbenchmark(SMA(stockdata_ma$close,20),times = 100)
Unit: microseconds
                        expr   min     lq    mean median     uq   max neval
 SMA(stockdata_ma$close, 20) 394.1 397.45 421.052 399.75 403.45 784.5   100

 

패키지가 괜히 있는게 아냐 ^^

연산 속도의 차이가 엄청나다. 거의 1.5배 이상

 

그럼 이제, 단타 룰을 정할 때가 되었다.

기본적인 논리는 스윙매매처럼 "상승할 때 사서, 하락할 때 팔자"로 정했다..

 

기준은 많이 사용하는 지표들로 생각해보았는데

 

MACD가 시그널을 위에 있을 때   MACD \( >\) MACD Signal
ROC가 기준선 위에 있을 때 ROC \( >\) 0
RSI가 과매도에 가까운 상태 RSI \( \le \) 30
스토캐스틱 Slow K가 Slow D 위에 있을 때 slow %K \( >\) slow %D 

MACD가 시그널 위에 있을 때,ROC가 기준선 0 위에 있을 때,

RSI가 과매도에 가까운 상태, 

스토캐스틱의 Slow K가 Slow D 위에 있을 때 매수를

 

MACD가 시그널 아래에 있을 때,

ROC가 기준선 0 아래에 있을 때,

RSI가 과매수에 가까운 상태, 

스토캐스틱의 Slow K가 Slow D 아래에 있을 때 매도를 하도록 생각해 보았다.

 

추가해야 하는 변수들은 MACD, MACD signal, ROC, RSI, Stochastic fast K, slow K, slow D가 되겠다.

 

stockdata_ma<- stockdata %>% 
  na.omit() %>% 
  mutate(ma5=SMA(close,5),
         ma20=SMA(close,20),
         ma120=SMA(close,120),
         macd=MACD(close,12,26,9,"SMA")[,1],
         signal=MACD(close,12,26,9,"SMA")[,2],
         roc=ROC(close,14),
         rsi=RSI(close,14),
         fastk=stoch(cbind(high,low,close),nFastK = 5, nFastD = 3, nSlowD = 3)[,1],
         slowk=stoch(cbind(high,low,close),nFastK = 5, nFastD = 3, nSlowD = 3)[,2],
         slowd=stoch(cbind(high,low,close),nFastK = 5, nFastD = 3, nSlowD = 3)[,3],
         obv=OBV(close,volume)
         )

 

이동평균선들은 단순 이동평균을 사용해서 구했고5일 이동평균선, 20일 이동평균선, 120일 이동평균선을 구했다.MACD는 26일과 12일, 시그널은 9일 지수가중이동평균선으로ROC와 RSI는 14일로Stochastic은 5일, 3일, 3일을 사용했다.

 

그래프로 확인해보면 다음과 같다.

 

음... 눈으로 확인해보니...

RSI 기준을 30,70으로 잡기에는 그 범위 밖으로 나가는 횟수가 너무 적어 보인다. 얘는 너무 둔감하게 반응할 것 같고.

스토캐스틱의 기간을 (5,3,3) 보다 조금 더 길게 잡아야 할 것 같다. 얘는 너무 민감하게 반응할 것 같다.

 

그래서 RSI를 35,65로 늘리고 스토캐스틱을 (10,6,6)으로 늘리면 다음과 같다.

조금 나아 보인다. 이대로 진행~

 

 

반응형