2012년 10월 15일 월요일

ANFIS and Time-Series Forecasting

※ Elliott Pattern Helper Add In
  • Download Add In for Excel 2007 
  • Download Add In for Excel 2003 


  지난 9월의 한 글에서 시계열(time-series) 데이터를 분석하고 그 결과를 기반으로 향후 흐름을 예측하는 방법을 하나 소개했었지요. 그 방법은 과거의 주가 흐름을 단순한 형태의 Fuzzy time series로 구조화(Fuzzy Inference System, 이하 FIS)하여 분석하는 것이었습니다.

  이번 글에서는 신경망(Neural Network, 이하 NN) 기반의 인공지능(Artificial Intelligence, 이하 AI) 기법을 이용한 주가 예측 방법을 한 가지 소개하고, 실제 구현하여 테스트한 결과를 공개합니다. 

  이 또한 과거에 발표되었던 논문을 기준으로 한 것이며, 이 방법에 의한 예측 결과를 실제 투자의 기준으로 활용하는 것은 부적절할 수 있음을 미리 알립니다.

  ※ 참고 논문: George S. Atsalakis, Emmanouil M. Dimitrakakis, Constantinos D.Zopounidis, 'Elliott Wave Theory and neuro-fuzzy systems, in stock market prediction: The WASP system', 2011.


1. 기술적 배경

  분석에 사용한 이론적·기술적 방법은 ANFIS, 즉 Adaptive Network-based Fuzzy Inference System(이하 ANFIS)입니다.

  일종의 FIS인데요, 그 내부에서 사용되는 membership function(이하 MF)의 parameter들을 NN의 자기학습(learning)으로 최적화함으로써 예측이나 분류 등 다양한 분석 분야에 사용됩니다.


  • Fuzzy inference system
  보통 우리가 알고 있는 함수들은 input이 가령 x = 3, y = 4일 때 output z = x^2 + y^2 = 5^2이다...처럼 실수나 복소수 값(crisp value)들을 사용합니다. 그런데 이를 전제로 하는 함수 또는 식으로 모든 시스템을 simulation할 수는 없습니다.

  특정 분야의 어떤 전문가들은 가령 수온이 꽤 높을 때 밸브를 잠근다...처럼 오랜 경험에 기초하여 시스템을 운영하기도 합니다. 이러한 전문가들의 행위를 자동화한다면 시스템을 어떻게 모델링해야 할까요? 수온이 꽤 높다...? 80도? 90도? 어떤 특정 값으로 정의하기는 어렵습니다.

  이런 문제들을 모델링하기 위해 나온 것이 fuzzy value(또는 fuzzy set)라는 개념과 이에 기초한 FIS입니다.

  FIS는 input과 output으로 crisp value가 아닌 fuzzy value를 갖는 다수의 룰(inference rule, 함수에 대응)을 정의함으로써 시스템을 모델링 합니다. 그런데, fuzzy value는 MF로 정의됩니다. 가령 '꽤 높다'라는 fuzzy value는 수온에 대해 10℃를 0으로, 20℃ → 0, ..., 60℃ → 0, 70℃ → 0.5, 80℃ → 1, 90℃ → 1, 100℃ → 1 등으로 대응시키는 함수, 즉 MF(그림 1 참조)로 정의할 수 있습니다.

그림 1. Membership function

  따라서 어떤 시스템을 FIS로 모델링 또는 simulation 한다는 것은 input과 output을 몇몇 MF로 정의하고 이들 사이의 대응관계, 즉 inference rule을 찾는 것입니다. 

  • Neural network
  인공지능(AI)이나 신경망(NN)에 대한 구체적인 거론은 기회가 되면 하기로 하구요, ANFIS와 관련해서 필요한 사항만 언급하겠습니다.

  특정 시스템을 FIS로 구현하려면, 위에서 얘기했듯이 다수의 MF를 정의해야 합니다. 그런데, 시스템의 input과 output을 정의하는 것 뿐만 아니라 MF와 inference rule을 찾는 데에도 해당 분야의 전문적인 지식이 필요하며, 수많은 시행착오를 겪을 수밖에 없습니다.

  MF는 주어진 input에 대해 0에서 1 사이의 값인 membership grade를 대응시킵니다. 대표적인 형태로 triangle, trapezoid, gaussian, bell 및 sigmoid 등이 있는데, 각각의 형태에 대해 구체적인 모양을 규정하는 parameter들이 존재합니다. 이들을 premise parameters라고 합니다. 각각의 inference rule 또한 최종 output을 산출하기 위해 몇몇 parameter들을 사용하는데요, 이들은 consequent parameters라고 불립니다. (그림 2의 pi, qi, ri 등)

그림 2. ANFIS

  FIS를 정의하는 이 parameter들을 찾기 위해, ANFIS는 노력과 시행착오를 줄이기 위한 방편으로 NN의 자기학습(learning) 기법을 사용합니다.


  2. 시스템 모델링

   모델링 대상은 time-series로서 KOSPI 종목 LG전자 주가의 흐름이며, 시스템의 input과 output은 위 논문의 내용을 따릅니다. 아이디어를 간략히 기술하면, 3일 동안의 Elliott wave oscillator(이하 EWO) 흐름으로 주가 흐름을 예측하는 것으로서, EWO가 (+)에서 (-)로 또는 (-)에서 (+)로 바뀔 때를 의미있는 진입시점으로 관측하기 위함입니다.
  • Input: 3일간의 Elliott wave oscillator (EWOt-2, EWOt-1, EWOt)
  • Output:(t+1)일의 주가 흐름 (if positive rate of change then 1, else -1)
  각각의 input에 대한 membership function의 갯수는 2개로서 '높다'와 '낮다' 두 개의 fuzzy value만을 사용하는 것입니다.

  논문에서는 MF를 이런 저런 형태로 바꿔가면서, NN의 step size(learning과 관련된 parameter)를 다양한 값으로 변경해가며, 총 42개의 ANFIS 모델을 사용했다고 합니다. 테스트 데이터(training data set)에 대해 학습을 수행한 후 에러율이 낮은 모델을 선택하여 예측치를 산출하고 그 결과를 바탕으로 진입/청산을 한 것이지요. 자세한 내용은 논문을 참조하시기 바랍니다.

  이 글은 위 논문의 아이디어를 LG전자 종목에 대해 제가 구현한 테스트 시스템을 사용하여 몇몇 MF type으로 테스트한 결과를 포함합니다.


3. 테스트 시스템 구축

  테스트 시스템은 Ubuntu(VirtualBox guest)에서 GNU Scientific Library(GSL)를 사용하여 개발한 후, Windows용으로 porting하여 향후 Elliott Pattern Helper에서 활용할 수 있도록 했습니다.

  이 과정에서 GSL을 Windows용으로 porting해야 했는데요, 다행히도 Visual Studio용 솔루션 파일을 구할 수 있었습니다. 이것을 이용하여 Visual Studio 2012 Express에서 GSL을 porting 했습니다.
  테스트 데이터로는 2008년 6월 10일부터 2012년 10월 5일까지 총 1,084개의 LG전자 주가 데이터를 사용했으며, 이를 NN의 training data set과 검증용(check) data set으로 나누어 테스트를 수행했습니다. 


4. 테스트 결과

  Training data set으로는 전체 1,084 개의 데이터 중 50%를 사용하고 나머지 50%를 검증에 사용했습니다. 

  반복 learning 횟수(epochs)는 MF 별로 over fitting으로 인한 error measure의 상승이 관측되기 전까지로 했으며, error measure로는 Root Mean Square Error(이하 RMSE)를 사용했습니다. 

  결과는 실제 주가의 흐름(상승 또는 하락)과 ANFIS의 계산 결과(+ 또는 -)를 단순비교하여 백분율로 표시하겠습니다.

  • Gauss MF, 500 Epochs

그림 3. Epoch별 RMSE 추이 - Gauss MF

             ▶ 결과: training data set: 57%
                          check data set:   49%

  • Bell MF, 240 Epochs

그림 4. Epoch별 RMSE 추이 - Bell MF

             ▶ 결과: training data set: 52%
                          check data set:   52%


  • Triangle MF, 300 Epochs
그림 5. Epoch별 RMSE 추이 - Triangle MF


             ▶ 결과: training data set: 52%
                          check data set:   50%

  • Trapezoid MF, 64 Epochs

그림 6. Epoch별 RMSE 추이 - Trapezoid MF

             ▶ 결과: training data set: 57%
                          check data set:   46%



  • Sigmoid MF, 200 Epochs

그림 7. Epoch별 RMSE 추이 - Sigmoid MF


             ▶ 결과: training data set: 45%
                          check data set:   45%



5. 결 론

  Training data set에 대해서는 최고 57%의 결과를 얻었지만, learning 이후 실제 예측에서는 최고 52%로 그리 만족할만한 수치가 아니군요. Training data set의 비율을 70%, 80%로 늘려도 결과는 거의 비슷하게 나왔습니다.

  소득이 있다면, MF의 종류에 따라 그 결과가 확연히 다르다는 것을 알 수 있었다는 것입니다. 그렇다면 MF의 수를 달리하면 어떻게 될까요..? 그리고, LG전자가 아닌 다른 종목에 대해 테스트를 하면 어떻게 될까요..?

  우선은 ANFIS 테스트 시스템을 구축한 것으로 만족해야 겠습니다. 이후에는 input과 output을 EWO나 주가 등락이 아닌 다른 변수로 바꾸어가며 테스트를 해보고 그 결과를 올리도록 하겠습니다.

2012년 10월 7일 일요일

Some samples for windows batch script

※ Elliott Pattern Helper Add In
  • Download Add In for Excel 2007 
  • Download Add In for Excel 2003 

▶ Counting lines of a data file


 @echo off
 echo.

 set WF_DATA=sample.dat

 set /a nlines=0
 for /f %%a in ('type "%WF_DATA%"^| find "" /v /c') do set /a nlines=%%a
 echo The number of lines of %WF_DATA% is %nlines%


▶ Counting columns of a data file
    (※ gawk for windows must be pre-installed)

 @echo off
 echo.

 set WF_DATA=sample.dat

 for /f %%a in ('gawk ^
 "BEGIN {^
         FS = """ """^
 }^
 END {^
         print NF^
 }^
 " %WF_DATA%') do set N=%%a
 echo The number of columns is %N%


▶ Finding Min / Max of a column in a data file
    (※ gawk for windows must be pre-installed)

 @echo off
 echo.

 set WF_ANFIS=anfis.dat
 for /f "tokens=1-2" %%a in ('gawk -f bound.awk %WF_ANFIS%') do (
 set XLOW=%%a
 set XHIGH=%%b
 )
 echo XLOW %XLOW%
 echo XHIGH %XHIGH%


 (※ bound.awk is as follows)
 C:\Users\drstones\Documents\Visual Studio 2012\Projects\anfis_wf>type bound.awk
 BEGIN {
         first_x_val = 99999999999
         last_x_val = -99999999999
 }
 {
         if ($1 < first_x_val) {
                 first_x_val = $1;
         }
         if ($1 > last_x_val) {
                 last_x_val = $1;
         }
 }
 END {
         print first_x_val " " last_x_val;
 }


▶ Incrementing a variable in for /f loop

 @echo off
 echo.

 set WF_ANFIS=anfis.dat
 set cnt=0
 for /f %%b in ('gawk -f bound1.awk %WF_ANFIS%') do (
 if !cnt! == 0 (
 set XLOW=%%b
 ) else (
 set XHIGH=%%b
 )
 set /a cnt=cnt+1
 )
 echo XLOW %XLOW%
 echo XHIGH %XHIGH%


 (※ bound1.awk is as follows)
 C:\Users\drstones\Documents\Visual Studio 2012\Projects\anfis_wf>type bound1.awk
 BEGIN {
         first_x_val = 99999999999
         last_x_val = -99999999999
 }
 {
         if ($1 < first_x_val) {
                 first_x_val = $1;
         }
         if ($1 > last_x_val) {
                 last_x_val = $1;
         }
 }
 END {
         print first_x_val;
         print last_x_val;
 }