지난 번 캘리의 공식을 테스트하면서 이상한 부분이 있어서 추가 테스트를 진행했습니다.

( 지난 글 : 현금도 종목이다. - 켈리(Kelly)의 공식 )


몬테카를로 시뮬레이션에서 왜 거의 항상 항상 켈리의 공식 값보다 크게 나오는가?


투자 횟수(년수)가 증가함에 따라서 최대 수익을 보이는 투자비율은 점차 켈리 값(켈리 공식의 값)에 가까워지기는 하지만, 거의 항상 켈리 값보다 컸습니다. 이유를 곰곰히 생각하다가 한 가지 가능성을 찾았습니다.  분산투자를 하는 일반적인(?) 투자 계정의 예를 살펴보겠습니다.  



위에서 보시면 확실하게 (90% 이상) 수익을 이끌고 있는 3 종목이 보입니다. 그리고, 어떤 종목은 손실을 보고 있습니다. 그런데 그 크기를 보시면 수익은 100% 이상도 가능한데, 손실은 100%가 최대입니다. 현실적인 투자에서 (제 경험상으로는... ^^;) 손실은 30% 이상 가기가 어렵습니다.  분산투자에서 한두종목이 100% 이상 수익이 나면 복리 효과로 그 금액은 상당히 빠르게 커져갑니다. 

즉, 분산투자를 하게 되면 크게 수익을 주는 주식을 만날 가능성이 높고, 이런 경우에 전체적인 수익금액을 높일 수가 있습니다.


이를 확인하기 위해 다시 몬테카를로 시뮬레이션을 진행했습니다. (맨 아래에 R 스크립트를 적습니다.)


성공확률 0.55, 성공시 보상 비율 0.4, 실패시 손실 비율 0.3일 경우, 켈리의 공식에서는 70.8 %를 제시합니다.  ( ( 0.55 * 0.4 - 0.45 * 0.3)/ (0.4 * 0.3) = 0.708333... )


이 경우에 대해서, 투자 종목 수를 각각 1, 5, 20 로 50회(년)을 투자할 경우 최대 수익이 나오는 투자 비율을 100회 찾아서 그래프로 표시했습니다.


  


0.85, 0.88, 0.91로 종목 수에 따라서 최대 수익을 내는 투자 비율이 1에 가까워 지는 것을 볼 수 있습니다. 그리고, 분산값도 줄어들고 있어서 최대 수익을 내는 비율이 점점 집중되고 있음을 알 수 있습니다.


결론적으로 분산투자는 최대 수익을 내기 위한 좋은 방법입니다.



============== 


require(dplyr)
require(ggplot2)
require(gridExtra)


set.seed(1234)

Init_money <- 100  # 초기 투자금

# 투자 년수
N <- 50

win_p <- 0.55       # 수익 확률
win_ret_rate <- 0.4        # 수익 비율
lose_ret_rate <- 0.3     # 손실 비율
bin_count = 100      # 투자 비율 변화 간격 1/100
bet_rate <- c(1:bin_count)/bin_count    # 투자 비율 배열

# 투자 종목 수
num_stocks_1 <- 1
num_stocks_2 <- 5
num_stocks_3 <- 20


# 켈리 공식의 제안 비율
bet_rate_kelly <- ( win_p * win_ret_rate - (1- win_p) * lose_ret_rate)/(win_ret_rate * lose_ret_rate)


num_tests = 100
text_size = 5
bin_width = bin_count - 10


for (num_stocks in c(num_stocks_1, num_stocks_2, num_stocks_3)) {
  max_rate <- 0     # max 결과를 보이는 rate
  # 수정 : 사용되지 않는 변수 : p_num <- p_num + 1
 
  for( l in c(1:num_tests)) {
    total_money_all_avg <- 0   # 투자 결과를 넣을 배열 초기화
   
   
    for ( k in c(1:bin_count)) {
      total_money <- 0
     
      for( j in c(1: num_stocks)){
       
        # 수익, 손실을 정해진 비율에 따라 추출
        ret_test <- sample(c(win_ret_rate, -lose_ret_rate), N, replace=TRUE, prob=c(win_p, 1-win_p))
       
        cur_money <- Init_money
        bet_money <- 0
        gain_money <- 0
       
        # 수익, 손실을 더함
        for ( i in c(1:N) ) {
          bet_money <- bet_rate[k] * cur_money
          gain_money <- bet_money *ret_test[i]
          cur_money <- cur_money + gain_money
        }
       
        total_money <- total_money + cur_money/num_stocks
      }
      # 지정된 투자 비율에 대한 투자 결과 저자
      total_money_all_avg[k] <- total_money 
    }
   
   
   
    df_result_all_avg   <- data.frame(bet_rate, total_money = round(total_money_all_avg))
    df_result_all_avg
    # 최대값 확인
    df_result_all_avg[which.max(total_money_all_avg),]
    max_rate[l] <- df_result_all_avg[which.max(total_money_all_avg),]$bet_rate
  }
 
  df_max_rate <- data.frame(max_rate)
 
 
 
 
  avg <- round( mean(max_rate), 2)
  sd  <- round(sd(max_rate), 2)
 
  if ( num_stocks == num_stocks_1) {
    p_num_stocks_1 <- df_max_rate %>% ggplot(aes(x = max_rate ) )  +
      geom_dotplot(fill="blue", binwidth = 1/bin_width) +
      xlim(0,1) +
      ylim(0,6) +
      geom_density(color="red", fill="red", alpha=0.3) +
      geom_text(x=0.5, y=6, label=paste0("종목수 = " , num_stocks), size=text_size ) +
      geom_text(x=0.5, y=5, label=paste0("평균   = " , avg), size=text_size ) +
      geom_text(x=0.5, y=4, label=paste0("분산   = ", sd), size = text_size)
  }  else if ( num_stocks == num_stocks_2) {
    p_num_stocks_2 <- df_max_rate %>% ggplot(aes(x = max_rate ) )  +
      geom_dotplot(fill="blue", binwidth = 1/bin_width) +
      xlim(0,1) +
      ylim(0,6) +
      geom_density(color="red", fill="red", alpha=0.3) +
      geom_text(x=0.5, y=6, label=paste0("종목수 = " , num_stocks), size=text_size ) +     
      geom_text(x=0.5, y=5, label=paste0("평균 = " , avg), size=text_size ) +
      geom_text(x=0.5, y=4, label=paste0("분산 = ", sd), size = text_size)
  }else {
    p_num_stocks_3 <- df_max_rate %>% ggplot(aes(x = max_rate ) )  +
      geom_dotplot(fill="blue", binwidth = 1/bin_width) +
      xlim(0,1) +
      ylim(0,6) +
      geom_density(color="red", fill="red", alpha=0.3) +
      geom_text(x=0.5, y=6, label=paste0("종목수 = " , num_stocks), size=text_size ) +     
      geom_text(x=0.5, y=5, label=paste0("평균 = " , avg), size=text_size ) +
      geom_text(x=0.5, y=4, label=paste0("분산 = ", sd), size = text_size)
  }
}

grid.arrange(p_num_stocks_1, p_num_stocks_2, p_num_stocks_3, ncol=1)


==============




+ Recent posts