비트코인 트레이드 경진대회

DACON, 인공지능 비트 트레이더 경진대회 시즌1

Posted by 옐란 on 2021-04-24

목차

1
2
3
4
5
6
7
8
9
1. 접근전략
2. 개발환경, lib설치
3. 데이터 로딩/확인
4. ARIMA 모델과 페라미터
5. 학습데이터 분석(생략)
6. ARIMA 모델 적용
7. 트레이딩 모듈/로직
8. 모의투자 결과확인
9. submission 제출

접근전략

  • 비정상적 시계열 데이터를 예측하는 전통적 기법은 통계기반의 ARIMA모델을 주로 사용함
  • LSTM모델로도 추가로 확인필요(예정), 6시간학습 및 1시간후 data 예측순으로 data 구성하면 됨!
  • baseline의 코드는, 전체 코인(9개)에 대해서 하나로 묶어서 학습 및 예측함
    : 코인별로 나눠서 예측하는게 상식적이므로, 코인별로 나눠서 작업
  • 매매 관련해서는 최적화가 필요한데, 관련 기법에 대한 식견이 없어서 baseline코드를 차용함(임으로 조정해보니 결과가 나빠지기만 했음)
    : 최적매매를 위해 강화학습이 필요할 듯

개발환경 구성

  • google colab jupyter notebook 환경에서 개발
  • talib는 이동평균션 등을 구할때 필요함, ARIMA만 사용하는 경우 생략가능
    1
    2
    3
    4
    5
    6
    7
    # (2020) https://stackoverflow.com/questions/49648391/how-to-install-ta-lib-in-google-colab
    url = 'https://launchpad.net/~mario-mariomedina/+archive/ubuntu/talib/+files'
    !wget $url/libta-lib0_0.4.0-oneiric1_amd64.deb -qO libta.deb
    !wget $url/ta-lib0-dev_0.4.0-oneiric1_amd64.deb -qO ta.deb
    !dpkg -i libta.deb ta.deb
    !pip install ta-lib
    import talib

데이터 로딩/확인

데이터 다운로드

  • 나는 google drive에 올려두고 다운받는 식으로 진행
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    # 1.data 다운로드
    #구글 드라이브에서 다운로드
    from google.colab import auth
    auth.authenticate_user()
    from googleapiclient.discovery import build
    drive_service = build('drive', 'v3')
    import io
    from io import BytesIO
    from googleapiclient.http import MediaIoBaseDownload

    TEMP_PATH = '/tmp/'
    def gcp_download(file_name, key):
    #3. 모델 다운로드
    #https://drive.google.com/open?id=1TlvbayGRCjAI6bOZrUYMmv6g6b95rnRM
    request = drive_service.files().get_media(fileId=key)

    downloaded = io.BytesIO()
    downloader = MediaIoBaseDownload(downloaded, request)
    done = False
    while done is False:
    status, done = downloader.next_chunk()
    if status:
    print("Download %%%d%%." % int(status.progress() * 100))
    print("Download Complete!")
    downloaded.seek(0)

    with open(TEMP_PATH + file_name, 'wb') as f:
    f.write(downloaded.read())

    #https://drive.google.com/file/d/1ckwh5Tp9PRSPu5dhfG8IzK8VjADQRplA
    down_file_name = 'train_x_df.csv'
    gcp_download(down_file_name, '1ckwh5Tp9PRSPu5dhfG8IzK8VjADQRplA')
    # https://drive.google.com/file/d/1PgnSkO8h2Bsn6B8PdsJi9D_TvD0NvbmU/view?usp=sharing
    down_file_name = 'train_y_df.csv'
    gcp_download(down_file_name, '1PgnSkO8h2Bsn6B8PdsJi9D_TvD0NvbmU')
    # https://drive.google.com/file/d/1SZ84Xtr-okI830fOAcKmA-5X09iqETVw
    down_file_name = 'test_x_df.csv'
    gcp_download(down_file_name, '1SZ84Xtr-okI830fOAcKmA-5X09iqETVw')
    # https://drive.google.com/file/d/1SZ84Xtr-okI830fOAcKmA-5X09iqETVw
    down_file_name = 'sample_submission.csv'
    gcp_download(down_file_name, '1SZ84Xtr-okI830fOAcKmA-5X09iqETVw')

    !mv /tmp/sample_submission.csv /content/
    !mv /tmp/test_x_df.csv /content/
    !mv /tmp/train_y_df.csv /content/
    !mv /tmp/train_x_df.csv /content/

data 로딩

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    # 2. data 불러오기
    import pandas as pd

    data_path = '/content'
    train_x_df = pd.read_csv(data_path + "/train_x_df.csv")
    train_y_df = pd.read_csv(data_path + "/train_y_df.csv")
    test_x_df = pd.read_csv(data_path + "/test_x_df.csv")

    print(len(train_x_df))
    print(train_x_df.head())
    print()
    print(train_x_df.iloc[:, 2:].head())

    10159560
    sample_id time coin_index ... trades tb_base_av tb_quote_av
    0 0 0 7 ... 451.157288 7.326834e+05 37725.183594
    1 0 1 7 ... 39.231071 0.000000e+00 0.000000
    2 0 2 7 ... 58.846603 1.664967e+04 857.377808
    3 0 3 7 ... 431.541779 2.189147e+06 112811.046875
    4 0 4 7 ... 176.539810 0.000000e+00 0.000000

    [5 rows x 12 columns]

    coin_index open high ... trades tb_base_av tb_quote_av
    0 7 1.010004 1.010004 ... 451.157288 7.326834e+05 37725.183594
    1 7 1.009808 1.009808 ... 39.231071 0.000000e+00 0.000000
    2 7 1.009808 1.010200 ... 58.846603 1.664967e+04 857.377808
    3 7 1.010200 1.011181 ... 431.541779 2.189147e+06 112811.046875
    4 7 1.010985 1.010985 ... 176.539810 0.000000e+00 0.000000

    [5 rows x 10 columns]
  • 코인별로 data 갯수 확인
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    # coin별로 전체 샘플 건수 확인
    train_x_df_group = train_x_df.groupby("coin_index").size()
    print(train_x_df_group.head(12))
    print()

    # coin별로 샘플 사이즈 확인(23시간으로 나눈값)
    train_x_df_group = train_x_df.groupby("coin_index").size()/1380 # 23시간 동안의 data임으로 coin단위로 sample건수 환산
    print(train_x_df_group.head(12))

    print()
    train_y_df_group = train_y_df.groupby("coin_index").size()/1380 # 23시간 동안의 data임으로 coin단위로 sample건수 환산
    print(train_y_df_group.head(12))

    print()
    test_x_df_group = test_x_df.groupby("coin_index").size()/1380 # 23시간 동안의 data임으로 coin단위로 sample건수 환산
    print(test_x_df_group.head(12))

    ### 코인별로 다르게 예측하고, sum해야함!
    coin_index
    0 1251660
    1 527160
    2 139380
    3 178020
    4 1283400
    5 752100
    6 1469700
    7 1306860
    8 1625640
    9 1625640
    dtype: int64

    coin_index
    0 907.0
    1 382.0
    2 101.0
    3 129.0
    4 930.0
    5 545.0
    6 1065.0
    7 947.0
    8 1178.0
    9 1178.0
    dtype: float64

    coin_index
    0 78.869565
    1 33.217391
    2 8.782609
    3 11.217391
    4 80.869565
    5 47.391304
    6 92.608696
    7 82.347826
    8 102.434783
    9 102.434783
    dtype: float64

    coin_index
    0 53.0
    1 53.0
    2 53.0
    3 53.0
    4 53.0
    5 53.0
    6 53.0
    7 53.0
    8 53.0
    9 52.0
    dtype: float64

코인별 DataSet 나누기

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 코인별 data-set 분리
    train_x_df_map = {}
    train_y_df_map = {}
    test_x_df_map = {}

    for idx in range(10):
    print("idx:", idx)
    df_x = train_x_df.loc[train_x_df.loc[:, "coin_index"]==idx]
    df_y = train_y_df.loc[train_y_df.loc[:, "coin_index"]==idx]
    df_z = test_x_df.loc[test_x_df.loc[:, "coin_index"]==idx]

    train_x_df_map[idx] = df_x.round(3)
    train_y_df_map[idx] = df_y.round(3)
    test_x_df_map[idx] = df_z.round(3)
  • 코인별로 3차원 데이터 만들기: 엑셀로 2차원 형태의 데이터가 존재하고, 3차원(10가지 Feature, N개의 샘플, 23시간동안의 분단위 데이터)으로 구성됨
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    def df2d_to_array3d(df_2d):
    # 입력 받은 2차원 데이터 프레임을 3차원 numpy array로 변경하는 함수
    feature_size = df_2d.iloc[:,2:].shape[1]
    time_size = len(df_2d.time.value_counts())
    sample_size = len(df_2d.sample_id.value_counts())
    array_3d = df_2d.iloc[:,2:].values.reshape([sample_size, time_size, feature_size])
    return array_3d

    train_x_df_map_arr = {}
    train_y_df_map_arr = {}
    test_x_df_map_arr = {}

    # 코인별로 나눠서 3차원 data 만들기
    for idx in train_x_df_map.keys():
    train_x_df_map_arr[idx] = df2d_to_array3d(train_x_df_map[idx])
    for idx in train_y_df_map.keys():
    train_y_df_map_arr[idx] = df2d_to_array3d(train_y_df_map[idx])
    for idx in test_x_df_map.keys():
    test_x_df_map_arr[idx] = df2d_to_array3d(test_x_df_map[idx])

    # train_x_array = df2d_to_array3d(train_sample_df)
    # train_y_array = df2d_to_array3d(val_sample_df)
    # test_x_array = df2d_to_array3d(test_x_df)

    print(f'''
    train_x_array {train_x_df_map_arr[0].shape}
    train_y_array {train_y_df_map_arr[0].shape}
    test_x_array {test_x_df_map_arr[0].shape}
    ''')

    train_x_array (907, 1380, 46)
    train_y_array (907, 120, 46)
    test_x_array (53, 1380, 46)

data 가시화 확인

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    def plot_series(x_series, y_series):
    #입력 series와 출력 series를 연속적으로 연결하여 시각적으로 보여주는 코드 입니다.
    plt.plot(x_series, label = 'input_series')
    plt.plot(np.arange(len(x_series), len(x_series)+len(y_series)),
    y_series, label = 'output_series')
    plt.axhline(1, c = 'red')
    plt.legend()

    # sample_id 1012에 해당하는 sample의 분단위 시가 변동 정보 시각화
    idx = 100
    #plot_series(train_x_array[idx,:,1], train_y_array[idx,:,1])
    plot_series(train_x_df_map_arr[0][idx,:, 1], train_y_df_map_arr[0][idx,:, 1])
    plt.show()

ARIMA 모델과 페라미터

  • lib import
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import numpy as np
    import pandas as pd
    import gc
    import math
    import os.path
    import time
    import matplotlib.pyplot as plt
    from datetime import timedelta, datetime
    from dateutil import parser
    from tqdm import tqdm
    import copy
    from statsmodels.tsa.arima_model import ARIMA # arima_model!
    import warnings
    warnings.filterwarnings("ignore")
  • ARIMA 페라미터(p,d,q)의 최적화가 필요함
    : (참고-이론) https://jukyellow.github.io/2021/04/12/statistics-time-series/
    : p는 AR모형의 페라미터, q는 MA모형의 페라미터
    : d는 비정상적 시계열 data를 차분하여 정상 시계열로 변환할때, 1차~N차 차분하는 값, 차분-인근한 두 값의 차이를 산출
    1
    2
    3
    4
    5
    6
    # 시계열 표현방식
    - 자기회귀(AR: autoregressive) 표현방식
    : 시점 t의 값(Zt)을 과거 시점의 값들을 이용한 회귀식으로 표현
    - 자기회귀 과정
    이동평균(MA: Moving average) 표현방식
    : 시점t의 값(Zt)를 현재와 과거시점의 백색잡음으로 표현, 이동평균 과정이라고도 함
  • ACF, PACF의 그래프를 보고 간소하게 판단하고 진행
    : (현시점:21/04/24) 학습이 더 필요한 상태로 참고 블로로 갈음
    : (참고) https://byeongkijeong.github.io/ARIMA-with-Python/
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # Arima (p,q,d) 최적화
    import matplotlib.pyplot as plt
    from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

    idx = 100
    #x_series = train_x_df_map_arr[0][idx,:,1] # 1: Open 가격
    #x_series = train_x_df_map[0].loc[:, 'open'] # 천만row;;
    x_series = train_x_df_map[0].loc[0:100000, 'open']
    print(x_series)
    print()

    plot_acf(x_series)
    plot_pacf(x_series)
    plt.show()

    ## 적절한 차분 차수의 계산을 위해 우선 1차 차분을 하고, ACF 및 PACF를 다시 계산한다.
    diff_1= x_series.diff(periods=1).iloc[1:]
    diff_1.plot()
    plot_acf(diff_1)
    plot_pacf(diff_1)
    plt.show()

ARIMA 모델 적용

Train 훈련

  • Train x와 y는 모델의 결과를 확인하고(train/validation), 페라미터를 최적화하는 용으로 사용되는 듯하다?

  • submission 제출은 Test셋으로 학습한 모델의 결과로 돌려서 제출하였다.

  • 사실, Train셋으로 학습하고, Validation(y)셋으로 검증하고, Test셋으로 최종 결과를 확인해야하는데, Test셋으로 학습하는게 맞는건가 의문점이 있긴하다.

  • 나는 ARIMA모델을 사용할 경우 페라미터 최적화가 필요하니, Train X/Y를 그 용도로 사용하고, 최종 Test셋으로 학습하고 submission data를 돌려서 제출하였다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # train 샘플 훈련하기

    idx = 100
    # train data 중 sample_id 1121에 해당하는 x_series로 arima 모델을 학습한 후
    # y_sereis를 추론
    x_series = train_x_df_map_arr[0][idx,:,1]
    y_series = train_x_df_map_arr[0][idx,:,1]

    # ARIMA의 (p,d,q) 값은 최적화 되지않은 값 입니다.
    model = ARIMA(x_series, order=(3,0,1))
    #model = ARIMA(x_series, order=(5,1,1))
    fit = model.fit()
    #fit = model.fit(trend='nc',full_output=True, disp=1)
    print(type(fit))
    #preds = fit.predict(1,120, typ='levels')
    preds = fit.predict(1,120)

    plot_series(x_series, y_series)
    plt.plot(np.arange(1380, 1380+120), preds, label = 'prediction')
    plt.legend()
    plt.show()

    print(fit.summary())

  • 학습 및 추론하기

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # ARIMA의 (p,d,q) 값이 (5,1,1)에서 수렴하지 않을 경우
    # (4,1,1)로 변경하여 다시 학습 및 추론
    for idx in tqdm(range(valid_x_array.shape[0])):
    try:
    try:
    x_series = valid_x_array[idx,:,1]

    #model = ARIMA(x_series, order=(5,1,1))
    model = ARIMA(x_series, order=(3,0,1))
    fit = model.fit()
    preds = fit.predict(1,120, typ='levels')
    valid_pred_array[idx,:] = preds# - (preds[0]-x_series[-1])
    except:
    print("order 4 1 1")
    x_series = valid_x_array[idx,:,1]

    model = ARIMA(x_series, order=(4,1,1))
    fit = model.fit()
    preds = fit.predict(1,120, typ='levels')
    valid_pred_array[idx,:] = preds
    except:
    print(idx, " 샘플은 수렴하지 않습니다.")
    # ARIMA의 (p,d,q) 값이 (5,1,1), (4,1,1)에서 수렴하지 않을 경우
    # 모두 0으로 채움
    pass

트레이딩 모듈/로직

추론한 data로 매매시점 잡기

  • baseline코드 그대로 사용, 115% 상승인 경우만 전략 매수
  • 매수후 최고치로 예상한 시점에 매도
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    # valid_pred_array 로부터 buy_quantity, sell_time 구하기

    #def array_to_submission(x_array, pred_array):
    def array_to_submission(valid_x_df_0, pred_array):
    # 입력 x_arrry와 출력 pred_arry를 통해서
    # buy_quantitiy와 sell_time을 결정
    submission = pd.DataFrame(np.zeros([pred_array.shape[0],2], np.int64),
    columns = ['buy_quantity', 'sell_time'])
    #print('submission1:', submission.head())
    submission = submission.reset_index()
    #print('submission2:', submission.head())
    submission.loc[:, 'buy_quantity'] = 0.1

    buy_price = []
    for idx, sell_time in enumerate(np.argmax(pred_array, axis = 1)):
    buy_price.append(pred_array[idx, sell_time])
    buy_price = np.array(buy_price)
    # 115% 이상 상승한하고 예측한 sample에 대해서만 100% 매수
    submission.loc[:, 'buy_quantity'] = (buy_price > 1.15) * 1
    # 모델이 예측값 중 최대 값에 해당하는 시간에 매도
    submission['sell_time'] = np.argmax(pred_array, axis = 1)
    submission.columns = ['sample_id','buy_quantity', 'sell_time']
    submission['sample_id_orgin'] = valid_x_df_0.sample_id.unique()
    return submission

    valid_submission = array_to_submission(valid_x_df_0, valid_pred_array)
    print(valid_submission)

    submission1: buy_quantity sell_time
    0 0 0
    1 0 0
    2 0 0
    3 0 0
    4 0 0
    submission2: index buy_quantity sell_time
    0 0 0 0
    1 1 0 0
    2 2 0 0
    3 3 0 0
    4 4 0 0
    sample_id buy_quantity sell_time sample_id_orgin
    0 0 0 24 1
    1 1 0 119 16
    2 2 0 13 19
    3 3 0 21 26
    4 4 0 118 30
    .. ... ... ... ...
    120 120 0 83 973
    121 121 0 12 978
    122 122 0 53 984
    123 123 0 55 989
    124 124 0 51 998

    [125 rows x 4 columns]

모의투자 결과확인

투자후 금액 계산

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    # 투자 후 금액 계산하기

    def df2d_to_answer(df_2d):
    # valid_y_df로부터
    # open 가격 정보가 포함된
    # [샘플 수, 120분] 크기의
    # 2차원 array를 반환하는 함수
    feature_size = df_2d.iloc[:,2:].shape[1]
    #print('feature_size:', feature_size)

    time_size = len(df_2d.time.value_counts())
    #print('time_size:', time_size)

    sample_size = len(df_2d.sample_id.value_counts())
    #print('sample_size:', sample_size)

    sample_index = df_2d.sample_id.value_counts().index
    #print('df_2d.sample_id.value_counts():', df_2d.sample_id.value_counts())
    #print('sample_index:', sample_index)

    array_2d = df_2d.open.values.reshape([sample_size, time_size])
    #print('array_2d.shape:', array_2d.shape)

    sample_index = list(sample_index)
    return array_2d, sample_index


    def COIN(y_df, submission, df2d_to_answer = df2d_to_answer, money = 10000):
    # 2차원 데이터프레임에서 open 시점 데이터만 추출하여 array로 복원
    # sample_id정보를 index에 저장
    y_array, index = df2d_to_answer(y_df) # index: sample_id index
    #print('y_array.shape:', y_array.shape)
    #print('index:', index)

    # index 기준으로 submission을 다시 선택
    #print('submission.columns[0]:', submission.columns[0])
    #submission = submission.set_index(submission.columns[0]) # sample_id
    #index를 다시 잡으면 아래 for 순회시 sample_id로 잡혀서 out_of_range발생.. 그냥 row_index를 사용하도록 둠.
    #submission = submission.set_index('sample_id_orgin') # sample_id

    #print('submission.shape:', submission.shape)
    #submission = submission.iloc[index, :]
    #print('submission:', submission.head())
    #print('submission:', submission.tail())

    # 초기 투자 비용은 10000 달러
    total_momey = money # dolors
    total_momey_list = []

    # 가장 처음 sample_id값
    start_index = submission.index[0]
    #print('submission.index:', submission.index)
    #print('len(y_array):', len(y_array))
    for row_idx in submission.index:
    sell_time = submission.loc[row_idx, 'sell_time']
    #print('row_idx - start_index:', row_idx - start_index)
    buy_price = y_array[row_idx - start_index, 0]
    sell_price = y_array[row_idx - start_index, sell_time]
    buy_quantity = submission.loc[row_idx, 'buy_quantity'] * total_momey
    residual = total_momey - buy_quantity
    ratio = sell_price / buy_price
    total_momey = buy_quantity * ratio * 0.9995 * 0.9995 + residual
    total_momey_list.append(total_momey)

    return total_momey, total_momey_list

    total_momey, total_momey_list = COIN(valid_y_df_0, valid_submission)

    # 투자 후 금액
    print(total_momey)

    # 투자 히스토리
    plt.plot(total_momey_list)
    plt.title("history")
    plt.show()

submission 제출

TestSet으로 학습

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    test_x_array_map = {}
    for idx in range(10):
    test_x_array_map[idx] = test_x_df_map_arr[idx]
    print(test_x_array_map[0].shape)

    # test 데이터 학습하고 추론하기 ??
    # 훈련모델로 test 데이터 추론만 하면되는거 아닌가??
    test_pred_array_map = {}
    for key in test_x_array_map.keys():
    test_x_array = test_x_array_map[key]
    test_pred_array_map[key] = np.zeros([test_x_array.shape[0],120])

    for idx in tqdm(range(test_x_array.shape[0])):
    try:
    try:
    x_series = test_x_array[idx,:,1]

    model = ARIMA(x_series, order=(5,1,1))
    fit = model.fit()
    preds = fit.predict(1,120, typ='levels')
    test_pred_array_map[key][idx,:] = preds
    except:
    x_series = test_x_array[idx,:,1]
    model = ARIMA(x_series, order=(4,1,1))
    fit = model.fit()
    preds = fit.predict(1,120, typ='levels')
    test_pred_array_map[key][idx,:] = preds
    except:
    print(idx, " 샘플은 수렴하지 않습니다.")
    pass
  • 가시화 확인 : ARIMA모델은 summary정보로 페라미터의 최적화 여부를 판단할수 있다고 함(아직 학습 부족)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    def plot_series2(x_series):
    #입력 series와 출력 series를 연속적으로 연결하여 시각적으로 보여주는 코드 입니다.
    plt.plot(x_series, label = 'input_series')
    # plt.plot(np.arange(len(x_series), len(x_series)+len(y_series)),
    # y_series, label = 'output_series')
    plt.axhline(1, c = 'red')
    plt.legend()

    x_series = test_x_array_map[0]
    print(x_series.shape)
    print(x_series[idx, :, 1].shape)
    preds = test_pred_array_map[0]
    print(preds.shape)
    print(preds[idx, :].shape)

    idx = 0
    plot_series2(x_series[idx, :, 1])
    plt.plot(np.arange(1380, 1380+120), preds[idx, :], label = 'prediction')
    plt.legend()
    plt.show()

    print(fit.summary())

모델 추론

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    submission_map = {}
    for idx in test_x_df_map.keys():
    test_x_df = test_x_df_map[idx]
    #print(test_x_df.shape)

    # 추론한 test_pred_array를 바탕으로 submission df 생성하기
    submission_map[idx] = array_to_submission(test_x_df, test_pred_array_map[idx])

    for idx in submission_map.keys():
    if idx == 0:
    submission = submission_map[0]
    continue
    submission = pd.concat([submission, submission_map[idx]], ignore_index=True)

    #submission.to_csv("submission.csv", index = False)
    submission.head()

    sample_id buy_quantity sell_time sample_id_orgin
    0 0 0 17 1
    1 1 0 74 13
    2 2 0 0 16
    3 3 0 15 29
    4 4 0 112 31
  • 제출본 파일 정리 및 파일 생성
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    print(len(submission))
    print(submission.head())

    # 컬럼제거
    submission = submission.drop("sample_id", axis=1) # df = df.drop(columns="A")
    print(submission.head())

    # 컬럼(index) 이름 변경
    submission.rename(columns = {'sample_id_orgin' : 'sample_id'}, inplace = True)
    #submission.columns = ['sample_id', 'buy_quantity', 'sell_time']
    print(submission.head())

    #index 변경
    submission = submission.set_index("sample_id")
    print(submission.head())

    # 정렬
    submission = submission.sort_values(by=["sample_id"], ascending=True)
    print(submission.head(10))

    submission.to_csv("submission.csv", index = True)
  • 결과분석: 24개의 data에 대해서 115% 상승할걸로 예측하고 매수/매매 수행함.
    1
    2
    3
    4
    5
    6
    print(submission.buy_quantity.value_counts())
    print(submission.shape)
    0 505
    1 24
    Name: buy_quantity, dtype: int64
    (529, 2)
  • 모의투자 결과 확인
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    sum_total_momey = 0
    for idx in test_x_df_map.keys():
    test_x_df = test_x_df_map[idx]
    submission = submission_map[idx]

    total_momey, total_momey_list = COIN(test_x_df, submission, money=1000)
    sum_total_momey += total_momey
    # 투자 후 금액
    print(total_momey)

    print('sum_total_momey:', sum_total_momey)

    # 투자 히스토리
    plt.plot(total_momey_list)
    plt.title("history")
    plt.show()

    1009.7421682107649
    1006.3181052913283
    1011.6921491682841
    1031.4396417705539
    1033.560917828394
    1513.9069470545141
    1006.8950006146904
    1043.1674991382877
    1013.5708148457784
    1004.5865519310078
    sum_total_momey: 10674.879795853603

    sumission 파일 제출

  • 생성된 submission.csv파일을 제출!

최종결과