Sysmetic trading

[트레이딩] 클러스터링 기법을 이용한 롱숏 시스템 트레이딩(1)

quantoasis 2023. 4. 27. 14:43
반응형

 

 

이번 포스팅에서는 머신러닝 기법중 비지도학습인 클러스터링을 이용한 롱숏트레이딩에 대해 적어보겠습니다.

 

이 연구를 하게된 계기는 아래 논문때문인데요. 논문의 방법론은 아래와 같습니다.

 

1. 클러스터링 기법으로 KOSPI200 개별종목을 군집화

2. 군집 내에서 수익률 순위로 페어를 결정

3. 페어간 수익률 차이(spread)를 표준편차로 나타내 임계값을 넘으면 롱숏 전략 수행

 

백테스트결과는 아래와 같은데 훌륭해 보이죠?

 

 

:: Journal of Korean Society of Industrial and Systems Engineering ::

1. 서 론 페어 트레이딩은 유사한 가격흐름을 지닌 두 종목 간의 스프레드를 활용하는 투자전략으로 주로 기업의 펀더멘털 보다는 주식 시계열 특성에 기반 한 통계적 차익거래 (Statistical Arbitrage

www.ksie.ne.kr

 

위 논문에서 아이디어를 얻어 클러스터링을 이용한 시스템트레이딩 전략을 테스트해보았습니다. 

 

두가지 방식으로 백테스팅을 해볼건데, 한 가지는 모멘텀(momentum)을 이용하고 다른 하나는 평균회귀(mean-reversion)을 이용해 볼 것입니다.

 

 

먼저, 모멘텀전략에 대해 ChatGPT에게 물어봤는데 아래와 같이 답변하더라구요.

 

모멘텀 전략은 최근 상승한 자산을 매수하고, 최근 하락한 자산을 매도하는 금융 시장에서 인기 있는 투자 전략입니다. 이전의 가격 동향을 분석하여 상승하는 자산을 따라가는 것이 목적입니다. 이 전략은 일반적으로 중장기적인 시점에서 적용되며, 투자자들이 상승하는 자산을 따라가는 것이 목적입니다. 이를 통해 높은 수익률을 제공할 수 있지만, 시장 상황에 따라서는 큰 손실을 입을 수도 있습니다. 따라서 이 전략을 적용할 때에는 적절한 리스크 관리가 필요합니다.

 

모멘텀전략이 통하는 이유는 인간이 가지는 행동학적 편향때문이라고 알려져 있는데요, 대표적으로 양떼효과가 있습니다.

 

정보를 먼저 습득한 투자자들이 매수하면서 자산의 가격이 한쪽으로 상승하면, 사람들에게 많이 알려지게 되고 뒤늦게 매수에 참여한 투자자들이 가격을 올리게 된다는 논리입니다.

 

최근 에코프로나 금양 같은 주식들이 개인들의 FOMO에 의해 크게 오르는 것도 이 양떼효과로 설명될 것 같습니다.

 

이외에도 모멘텀을 설명할 수 있는 효과들은 아래와 같습니다.

 

 

다음으로 필요한 기술적 백그라운드는 머신러닝 클러스터링 기법중 하나인 k-means 클러스터링입니다. 역시 chatGPT는 이렇게 답하네요.

 

k-means 알고리즘은 각 클러스터의 중심값을 대표하는 k개의 중심점(Centroid)을 먼저 초기에 설정한 후, 데이터 포인트들을 가장 가까운 중심점에 할당합니다. 이 후, 각 클러스터의 중심점을 클러스터 내 데이터 포인트들의 평균값으로 업데이트하고, 다시 각 데이터 포인트들을 가장 가까운 중심점에 할당합니다. 이 과정을 클러스터의 변화가 없을 때까지 반복합니다.

 

쉽게 설명해서 랜덤으로 공간에 seed를 던지고 가까운 점들끼리 묶는거에요.

 

https://www.javatpoint.com/k-means-clustering-algorithm-in-machine-learning

 

이제 군집화 + 모멘텀으로 실제 금융시장에서 수익을 낼 수 있을지 확인해보겠습니다.

 

기초데이터는 20여개의 상품(Commodity)데이터입니다. 기간은 2010년부터 2023년 까지입니다.

 

백테스팅 절차는 아래와 같습니다. 매월마다 과거 1년의 수익률을 이용해 상품을 군집화하고, 군집된 상품들의 평균수익률을 이용하여 가장 크게 오른 군집을 롱, 가장 크게 떨어진 군집을 숏하는 방식입니다.

 

 

아래는 코드입니다. 

 

코드에 논리적 오류가 있을 수도 있으니, 투자전략으로 사용하시려면 꼭 검증해보시기 바랍니다!

 

또한, 실전 트레이딩에서는 제약사항들이 많으니(증권사마다 취급하는 상품선물 다를 수 있고, 각 상품마다 trade time이 다름 등) 고려하셔야합니다.

 

import pandas as pd
import numpy as np
import datetime as dt
import seaborn as sns
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans

먼저 필요한 모듈 import를 했습니다.

commodity = pd.read_csv('commodity_20230221.csv', index_col='logdate')
commodity.index = pd.to_datetime(commodity.index, format='%Y%m%d')
commodity = commodity.resample('M').last()
commodity = commodity.pct_change().dropna()
commodity

그 다음 commodity.csv 파일을 import 했습니다 파일은 아래에 같이 첨부합니다.

 

commodity_20230221.csv
0.45MB

 

 

 

이후 resample 함수를 통해 월간데이터만 남겨 주었구요, pct_change 함수를 통해 수익률을 산출했습니다.

 

 

이제 클러스터링에 필요한 함수입니다. cluster개수는 5개로 했고, 시드는 고정시켰습니다.

def labeling(data):

    kmeans = KMeans(n_clusters=5, algorithm='auto', random_state=np.random.RandomState(seed=1)).fit(data_scaled)
    clusters = kmeans.labels_
    data["cluster_no"] = clusters
    data["cluster_no"] = data["cluster_no"] + 1
    data['ret'] = data[data.columns[1:-2]].sum(axis=1)
    return data

 

 

 

아래 백테스팅 코드가 동작하는 과정은 아래와 같습니다.

 

1. commodity 데이터에서 일부 데이터를 선택하고, 이를 스케일링 및 클러스터링

2. 최대 수익과 최소 수익을 가진 클러스터를 찾음

3. 최대 수익을 가진 클러스터의 종목에는 매수하고, 최소 수익을 가진 클러스터의 종목에는 매도

4. 이러한 매매 결과를 리스트에 저장

 

cul_ret =[]

for i in range(12,len(commodity)):
    setdata =[]
    data = commodity[:i].T
    data_nextmonth = commodity[i:i+1]#1달 뒤의 수익률
    names = data.columns
    indexes = data.index
    sc = MinMaxScaler((0, 1))
    df = sc.fit_transform(data)
    data_scaled = pd.DataFrame(df, columns=names, index=indexes)
    label_data = labeling(data_scaled)
    data_agg =label_data.groupby("cluster_no").agg(np.mean)
    seq_max = data_agg[data_agg['ret']==data_agg['ret'].max()].index.values
    seq_min = data_agg[data_agg['ret']==data_agg['ret'].min()].index.values
    long =  label_data[label_data['cluster_no']== seq_max[0]].index.values
    short=label_data[label_data['cluster_no']== seq_min[0]].index.values
    long = long.tolist()
    short= short.tolist()
    long_ret = data_nextmonth[long].mean(axis=1)
    short_ret = data_nextmonth[short].mean(axis=1)
    #ret = (long_ret-short_ret)[0]*0.01
    ret = (short_ret-long_ret)[0]
    date = long_ret.index.values
    setdata.append(date[0])
    setdata.append(ret)
    cul_ret.append(setdata)


df = pd.DataFrame(cul_ret,columns=['logdate','ret'])
df['logdate'] = pd.to_datetime(df['logdate'])
df = df.set_index('logdate')
df = df.squeeze()

 

이제 결과를 볼까요? MDD가 -30%수준이고 Sharpe는 3.96이네요. 

 

물론 슬리피지도 주지 않았고 실제 트레이딩이 가능한 상품인지 알아보지도 않았지만, 롱숏전략의 아이디어로서 훌륭한 것 같습니다.

 

 

 

이 아이디어를 디벨롭 할 수 있는 방법은 무엇이 있을까요?

 

클러스터링 방법을 바꿀 수도있고, time frame을 바꿀 수도 있고, 기초자산이나 매매시점 등 개선할 수 있는 여지는 무한히 많습니다.

 

이것이 시스템트레이디 운용의 핵심인 것 같습니다. 누구나 할 수 있는 전략으로 시장에 들어가면 퇴출되기 십상이거든요. 

 

다음 전략으로는 클러스터링 후에 페어트레이딩을 하는 전략으로 찾아뵙겠습니다.

 

읽어주셔서 감사합니다 ^^

 

 

반응형