자동화된 거래의 부상: S&P 500을 거래하는 기계
게시 됨: 2022-03-11오늘날 다양한 자산(예: 주식, 지수 선물, 상품)을 사용하는 거래 활동의 60% 이상이 더 이상 "인간" 거래자가 아닌 자동 거래에 의존합니다. 장기적으로 긍정적인 수익을 달성하기 위해 다양한 시장에서 자산을 자동으로 사고 파는 특정 알고리즘을 기반으로 하는 특수 프로그램이 있습니다.
이 기사에서는 긍정적인 이득을 얻기 위해 다음 거래를 어떻게 해야 하는지 정확하게 예측하는 방법을 보여 드리겠습니다. 이 예에서는 거래할 기초 자산으로 S&P 500 지수를 선택했습니다. S&P 500 지수는 더 큰 자본을 보유한 500개 미국 기업의 가중 평균입니다. 구현하는 매우 간단한 전략은 월스트리트 거래소가 오전 9시 30분에 거래를 시작할 때 S&P 500 지수를 매수하고 동부 시간 오후 4시에 마감 세션에서 매도하는 것입니다. 지수의 종가가 시가보다 높으면 양의 이익이 발생하고 종가가 시가보다 낮으면 음의 이익을 얻게 됩니다. 따라서 질문은 다음과 같습니다. 거래 세션이 시작 가격보다 높은 마감 가격으로 끝날지 어떻게 알 수 있습니까? 머신 러닝은 이러한 복잡한 작업을 수행하는 강력한 도구이며 거래 결정을 지원하는 유용한 도구가 될 수 있습니다.
기계 학습은 많은 유용한 실제 응용 프로그램의 새로운 영역입니다. 금융 거래는 이들 중 하나이며 이 부문에서 매우 자주 사용됩니다. 기계 학습에 대한 중요한 개념은 패턴 인식과 같은 모든 가능한 규칙에 대한 코드를 작성할 필요가 없다는 것입니다. 머신 러닝과 관련된 모든 모델은 데이터 자체에서 학습한 다음 나중에 보이지 않는 새로운 데이터를 예측하는 데 사용할 수 있기 때문입니다.
면책 조항 : 이 기사의 목적은 기계 학습 방법을 훈련하는 방법을 보여주는 것이며 제공된 코드 예제에서 모든 기능을 설명하지는 않습니다. 이 기사는 기사 범위를 벗어나는 일부 세부 정보가 누락되어 있기 때문에 모든 코드를 복사하여 붙여넣고 제공된 동일한 테스트를 실행하도록 하기 위한 것이 아닙니다. 또한 Python에 대한 기본 지식이 필요합니다. 이 기사의 주요 의도는 기계 학습이 금융 부문에서 매수 및 매도를 예측하는 데 어떻게 효과적일 수 있는지에 대한 예를 보여주는 것입니다. 그러나 실제 돈으로 거래한다는 것은 돈 관리 및 위험 관리와 같은 다른 많은 기술을 가지고 있음을 의미합니다. 이 기사는 "큰 그림"의 작은 부분일 뿐입니다.
최초의 재무 데이터 자동 거래 프로그램 구축
재무 데이터를 분석하고 올바른 거래를 예측하는 첫 번째 프로그램을 만들고 싶습니까? 방법을 보여드리겠습니다. 저는 Machine Learning 코드에 Python을 사용할 것이며 Yahoo Finance 서비스의 과거 데이터를 사용할 것입니다. 앞서 언급했듯이, 예측을 하기 전에 모델을 훈련시키기 위해서는 과거 데이터가 필요합니다.
시작하려면 다음을 설치해야 합니다.
- Python, 특히 IPython 노트북을 사용하는 것이 좋습니다.
- 터미널 명령을 통해 Yahoo Finance Python 패키지(정확한 이름은
yahoo-finance
):pip install yahoo-finance
. - GraphLab이라는 기계 학습 패키지의 무료 평가판. 해당 라이브러리의 유용한 문서를 자유롭게 확인하십시오.
GraphLab의 일부만 오픈 소스인 SFrame이므로 전체 라이브러리를 사용하려면 라이선스가 필요합니다. 학생이나 Kaggle 대회에 참가하는 학생을 위한 30일 무료 라이선스와 비상업적 라이선스가 있습니다. 내 관점에서 GraphLab Create는 데이터를 분석하고 기계 학습 모델을 교육하는 데 매우 직관적이고 사용하기 쉬운 라이브러리입니다.
파이썬 코드 파기
인터넷에서 금융 데이터를 다운로드하는 방법을 알아보기 위해 일부 Python 코드를 살펴보겠습니다. IPython 노트북을 사용하여 다음 코드를 테스트하는 것이 좋습니다. IPython은 기존 IDE에 비해 많은 장점이 있기 때문입니다. 특히 소스 코드, 실행 코드, 테이블 데이터 및 차트를 동일한 문서에서 함께 결합해야 할 때 그렇습니다. IPython 노트북 사용에 대한 간단한 설명은 IPython 노트북 소개 기사를 참조하십시오.
이제 새 IPython 노트북을 만들고 S&P 500 지수의 과거 가격을 다운로드하는 코드를 작성해 보겠습니다. 다른 도구를 사용하려는 경우 선호하는 IDE에서 새 Python 프로젝트로 시작할 수 있습니다.
import graphlab as gl from __future__ import division from datetime import datetime from yahoo_finance import Share # download historical prices of S&P 500 index today = datetime.strftime(datetime.today(), "%Y-%m-%d") stock = Share('^GSPC') # ^GSPC is the Yahoo finance symbol to refer S&P 500 index # we gather historical quotes from 2001-01-01 up to today hist_quotes = stock.get_historical('2001-01-01', today) # here is how a row looks like hist_quotes[0] {'Adj_Close': '2091.580078', 'Close': '2091.580078', 'Date': '2016-04-22', 'High': '2094.320068', 'Low': '2081.199951', 'Open': '2091.48999', 'Symbol': '%5eGSPC', 'Volume': '3790580000'}
여기서 hist_quotes
는 사전 목록이며 각 사전 개체는 Open
, High
, Low
, Close
, Adj_close
, Volume
, Symbol
및 Date
값이 있는 거래일입니다. 각 거래일 동안 가격은 일반적으로 Open
에서 시작하여 Close
로 변경되며 최대값과 최소값인 High
및 Low
에 도달합니다. 우리는 그것을 읽고 가장 관련성이 높은 각각의 데이터 목록을 만들어야 합니다. 또한 데이터는 처음에 가장 최근 값으로 정렬되어야 하므로 이를 반대로 해야 합니다.
l_date = [] l_open = [] l_high = [] l_low = [] l_close = [] l_volume = [] # reverse the list hist_quotes.reverse() for quotes in hist_quotes: l_date.append(quotes['Date']) l_open.append(float(quotes['Open'])) l_high.append(float(quotes['High'])) l_low.append(float(quotes['Low'])) l_close.append(float(quotes['Close'])) l_volume.append(int(quotes['Volume']))
다운로드한 모든 인용문을 확장성이 뛰어난 열 기반 데이터 프레임인 SFrame
개체로 압축할 수 있으며 압축됩니다. 장점 중 하나는 디스크 기반이기 때문에 RAM 용량보다 클 수도 있다는 것입니다. 문서를 확인하여 SFrame에 대해 자세히 알아볼 수 있습니다.
따라서 기록 데이터를 저장하고 확인하겠습니다.
qq = gl.SFrame({'datetime' : l_date, 'open' : l_open, 'high' : l_high, 'low' : l_low, 'close' : l_close, 'volume' : l_volume}) # datetime is a string, so convert into datetime object qq['datetime'] = qq['datetime'].apply(lambda x:datetime.strptime(x, '%Y-%m-%d')) # just to check if data is sorted in ascending mode qq.head(3)
닫기 | 날짜 시간 | 높은 | 낮은 | 열려있는 | 용량 |
1283.27 | 2001-01-02 00:00:00 | 1320.28 | 1276.05 | 1320.28 | 1129400000 |
1347.56 | 2001-01-03 00:00:00 | 1347.76 | 1274.62 | 1283.27 | 1880700000 |
1333.34 | 2001-01-04 00:00:00 | 1350.24 | 1329.14 | 1347.56 | 2131000000 |
이제 다음과 같이 SFrame
메서드 save
를 사용하여 데이터를 디스크에 저장할 수 있습니다.
qq.save(“SP500_daily.bin”) # once data is saved, we can use the following instruction to retrieve it qq = gl.SFrame(“SP500_daily.bin/”)
S&P 500이 어떻게 생겼는지 봅시다
로드된 S&P 500 데이터가 어떻게 보이는지 보려면 다음 코드를 사용할 수 있습니다.
import matplotlib.pyplot as plt %matplotlib inline # only for those who are using IPython notebook plt.plot(qq['close'])
코드의 출력은 다음 그래프입니다.
일부 기계 학습 모델 훈련
결과 추가
이 글의 서론 부분에서 언급했듯이 각 모델의 목표는 종가가 시가보다 높을지 예측하는 것입니다. 따라서 이 경우 기초 자산을 구매할 때 플러스 수익을 얻을 수 있습니다. 따라서 target
또는 predicted
변수가 될 데이터에 outcome
열을 추가해야 합니다. 이 새 열의 모든 행은 다음과 같습니다.
-
Closing
가Opening
보다 높은 상승일 에+1
. -
Closing
가Opening
보다 낮은 하락 일 의 경우-1
입니다.
# add the outcome variable, 1 if the trading session was positive (close>open), 0 otherwise qq['outcome'] = qq.apply(lambda x: 1 if x['close'] > x['open'] else -1) # we also need to add three new columns 'ho' 'lo' and 'gain' # they will be useful to backtest the model, later qq['ho'] = qq['high'] - qq['open'] # distance between Highest and Opening price qq['lo'] = qq['low'] - qq['open'] # distance between Lowest and Opening price qq['gain'] = qq['close'] - qq['open']
마지막 거래일 이전 며칠을 평가해야 하므로 데이터를 하루 이상 지연 해야 합니다. 이러한 종류의 지연 작업에는 TimeSeries
라는 GraphLab 패키지의 다른 개체가 필요합니다. TimeSeries
에는 특정 행 수만큼 데이터를 지연시키는 방법 shift
이 있습니다.
ts = gl.TimeSeries(qq, index='datetime') # add the outcome variable, 1 if the bar was positive (close>open), 0 otherwise ts['outcome'] = ts.apply(lambda x: 1 if x['close'] > x['open'] else -1) # GENERATE SOME LAGGED TIMESERIES ts_1 = ts.shift(1) # by 1 day ts_2 = ts.shift(2) # by 2 days # ...etc.... # it's an arbitrary decision how many days of lag are needed to create a good forecaster, so # everyone can experiment by his own decision
예측 변수 추가
예측 자는 모델을 훈련하고 결과 를 예측하기 위해 선택해야 하는 일련의 기능 변수입니다. 따라서 예측 요인 선택은 가장 중요하지는 않더라도 예측자의 구성 요소입니다.
몇 가지 예를 들자면, 오늘의 종가가 어제의 종가보다 높거나 이전 2일의 종가 등으로 확장될 수 있는지 등을 고려해야 합니다. 비슷한 선택을 다음 코드로 번역할 수 있습니다.
ts['feat1'] = ts['close'] > ts_1['close'] ts['feat2'] = ts['close'] > ts_2['close']
위에 표시된 대로 비교가 참이면 1
을 포함하고 그렇지 않으면 0
을 포함하는 데이터 세트( ts
)에 feat1
및 feat2
라는 두 개의 새로운 기능 열을 추가했습니다.
이 기사는 금융 부문에 적용된 기계 학습의 예를 제공하기 위한 것입니다. 저는 기계 학습 모델을 재무 데이터와 함께 사용하는 방법에 중점을 두는 것을 선호하며 모델을 훈련하는 데 올바른 요소를 선택하는 방법에 대해서는 자세히 설명하지 않겠습니다. 복잡성의 상당한 증가로 인해 특정 요소가 다른 요소와 관련하여 사용되는 이유를 설명하는 것은 너무 포괄적입니다. 내 직업 연구는 좋은 예측 변수를 만들기 위해 요인을 선택하는 많은 가설을 연구하는 것입니다. 따라서 먼저 다양한 요인 조합을 실험하여 모델의 정확도를 높일 수 있는지 확인하는 것이 좋습니다.
# add_features is a helper function, which is out of the scope of this article, # and it returns a tuple with: # ts: a timeseries object with, in addition to the already included columns, also lagged columns # as well as some features added to train the model, as shown above with feat1 and feat2 examples # l_features: a list with all features used to train Classifier models # l_lr_features: a list all features used to train Linear Regression models ts, l_features, l_lr_features = add_features(ts) # add the gain column, for trading operations with LONG only positions. # The gain is the difference between Closing price - Opening price ts['gain'] = ts['close'] - ts['open'] ratio = 0.8 # 80% of training set and 20% of testing set training = ts.to_sframe()[0:round(len(ts)*ratio)] testing = ts.to_sframe()[round(len(ts)*ratio):]
의사결정나무 모델 훈련
GraphLab Create에는 기계 학습 모델을 구현하기 위한 매우 깨끗한 인터페이스가 있습니다. 각 모델에는 모델을 훈련 데이터 세트로 맞추는 데 사용되는 create
메서드가 있습니다. 일반적인 매개변수는 다음과 같습니다.
-
training
- 특징 열과 대상 열을 포함하는 훈련 세트입니다. -
target
- 대상 변수를 포함하는 열의 이름입니다. -
validation_set
- 모델의 일반화 성능을 모니터링하기 위한 데이터셋입니다. 우리의 경우validation_set
이 없습니다. -
features
- 모델 학습에 사용되는 기능의 열 이름 목록입니다. -
verbose
-true
훈련 중 진행 정보를 인쇄합니다.
반면에 다음과 같은 다른 매개변수는 모델 자체에 일반적입니다.
-
max_depth
- 트리의 최대 깊이입니다.
다음 코드를 사용하여 의사 결정 트리를 구축합니다.
max_tree_depth = 6 decision_tree = gl.decision_tree_classifier.create(training, validation_set=None, target='outcome', features=l_features, max_depth=max_tree_depth, verbose=False)
적합 모델의 성능 측정
정확도 는 예측자의 선함을 평가하는 중요한 지표입니다. 올바른 예측의 수를 총 데이터 포인트의 수로 나눈 값입니다. 모델에 훈련 데이터가 적합하기 때문에 훈련 세트로 평가된 정확도가 테스트 세트로 얻은 정확도보다 좋습니다.
정밀도 는 긍정적인 예측의 비율입니다. "완벽한" 승률을 달성하려면 정밀도가 1
에 가까울 필요가 있습니다. GraphLab Create 패키지의 또 다른 분류기인 우리의 decision_tree
는 적합 모델의 많은 중요한 메트릭을 얻기 위해 evaluate
하는 방법을 가지고 있습니다.
Recall 은 긍정적인 예를 예측하는 분류기의 능력을 수량화합니다. 재현율은 무작위로 선택된 긍정적인 예가 분류기에 의해 올바르게 식별될 확률로 해석될 수 있습니다. "완벽한" 승률을 달성하려면 정밀도가 1
에 더 가까운 숫자가 되어야 합니다.
다음 코드는 훈련 세트와 테스트 세트 모두에서 피팅된 모델의 정확도 를 보여줍니다.
decision_tree.evaluate(training)['accuracy'], decision_tree.evaluate(testing)['accuracy'] (0.6077348066298343, 0.577373211963589)
위와 같이 테스트 세트가 있는 모델의 정확도는 약 57%로 동전 던지기(50%)보다 다소 좋습니다.
데이터 예측
GraphLab Create에는 서로 다른 적합 모델의 데이터를 예측하기 위한 동일한 인터페이스가 있습니다. 우리의 경우에는 목표 변수를 outcome
하기 위해 테스트 세트가 필요한 predict
방법을 사용할 것입니다. 이제 테스트 세트에서 데이터를 예측할 수 있습니다.
predictions = decision_tree.predict(testing) # and we add the predictions column in testing set testing['predictions'] = predictions # let's see the first 10 predictions, compared to real values (outcome column) testing[['datetime', 'outcome', 'predictions']].head(10)
날짜 시간 | 결과 | 예측 |
2013-04-05 00:00:00 | -1 | -1 |
2013-04-08 00:00:00 | 1 | 1 |
2013-04-09 00:00:00 | 1 | 1 |
2013-04-10 00:00:00 | 1 | -1 |
2013-04-11 00:00:00 | 1 | -1 |
2013-04-12 00:00:00 | -1 | -1 |
2013-04-15 00:00:00 | -1 | 1 |
2013-04-16 00:00:00 | 1 | 1 |
2013-04-17 00:00:00 | -1 | -1 |
2013-04-18 00:00:00 | -1 | 1 |
거짓 긍정 은 모델이 긍정적인 결과를 예측하는 반면 테스트 세트의 실제 결과는 부정적인 경우입니다. 그 반대의 경우도 거짓 부정 은 모델이 테스트 세트의 실제 결과가 긍정적인 부정적인 결과를 예측하는 경우입니다.
우리의 거래 전략은 S&P 500을 Opening
에 매수하고 Closing
에 매도하는 긍정적인 예측 결과를 기다리므로 손실을 피하기 위해 가장 낮은 거짓 긍정 비율을 갖기를 희망합니다. 다시 말해서, 우리는 우리 모델이 가장 높은 정밀도 비율을 가질 것으로 기대합니다.
우리가 볼 수 있듯이, 처음 10개의 예측 값 내에는 2개의 거짓 음성(2013-04-10 및 2013-04-11)과 2개의 거짓 양성(2013-04-15 및 2013-04-18)이 있습니다. 테스트 세트.
간단한 계산을 통해 다음과 같은 10개의 작은 예측 집합을 고려합니다.
- 정확도 = 6/10 = 0.6 또는 60%
- 정밀도 =3/5 = 0.6 또는 60%
- 재현율 = 3/5 = 0.6 또는 60%
일반적으로 위의 숫자는 서로 다르지만 이 경우에는 동일합니다.
모델 백테스트
이제 모델이 예측 값을 사용하여 거래하는 방법을 시뮬레이션합니다. 예측된 결과가 +1
과 같으면 Up day 가 예상된다는 의미입니다. 상승일 에는 세션 시작 시 지수를 매수하고 같은 날 세션 종료 시 해당 지수를 매도합니다. 반대로, 예측 결과가 -1
과 같으면 다운 데이 가 예상되므로 해당 날짜에는 거래하지 않습니다.
이 예에서 라운드 턴 이라고도 하는 완전한 일일 거래에 대한 손익( pnl
)은 다음과 같습니다.
-
pnl = Close - Open
(각 거래일에 대해)
아래 표시된 코드를 사용하여 도우미 함수 plot_equity_chart
를 호출하여 누적 이익 곡선(주식 곡선)이 있는 차트를 만듭니다. 너무 깊이 들어가지 않고 일련의 손익 값을 얻고 일련의 누적 합계를 계산하여 플롯합니다.
pnl = testing[testing['predictions'] == 1]['gain'] # the gain column contains (Close - Open) values # I have written a simple helper function to plot the result of all the trades applied to the # testing set and represent the total return expressed by the index basis points # (not expressed in dollars $) plot_equity_chart(pnl,'Decision tree model')
Mean of PnL is 1.843504 Sharpe is 1.972835 Round turns 511
여기서 Sharpe는 거래 모델의 우수성을 나타내는 중요한 지표인 연간 Sharpe 비율입니다.
매일 표시되는 거래를 고려하면 mean
은 손익 목록의 평균이고 sd
는 표준 편차입니다. 위에 묘사된 공식의 단순성을 위해 저는 무위험 수익률을 0으로 간주했습니다.
거래에 대한 몇 가지 기본 사항
지수를 거래하려면 지수에서 직접 파생된 자산을 구매해야 합니다. 많은 중개인이 S&P 500 지수를 CFD (차이에 대한 계약)라고 하는 파생 상품으로 복제합니다. 이는 계약의 개시 가격과 종가 사이의 차액을 교환하기로 두 당사자 간의 합의입니다.
예 : Open
시 1 CFD S&P 500 매수(가치 2000), 당일 Close
(가치 2020)에 매도. 차이, 따라서 이득은 20점입니다. 각 포인트의 가치가 $25인 경우:
- 총 이익 은
20 points x $25 = $500
입니다.
브로커가 자체 수익을 위해 0.6포인트의 미끄러짐을 유지한다고 가정해 보겠습니다.
- 순이익 은
(20 - 0.6) points x $25 = $485
입니다.
고려해야 할 또 다른 중요한 측면은 거래 내에서 상당한 손실을 피하는 것입니다. 예측된 결과가 +1
이지만 실제 결과 값이 -1
일 때마다 발생할 수 있으므로 거짓 긍정 입니다. 이 경우 종가가 시가보다 낮은 종료 세션이 하락하는 날 이 되어 손실을 보게 됩니다.
손절매 주문 은 거래 내에서 허용할 수 있는 최대 손실로부터 보호하기 위해 이루어져야 하며 자산 가격이 이전에 설정한 고정 가치 아래로 떨어질 때마다 이러한 주문이 발동됩니다.
이 글의 시작 부분에 있는 야후 파이낸스에서 다운로드한 시계열을 보면, 매일은 그 날에 도달한 가장 Low
가격인 저가가 있습니다. Opening
가격에서 멀리 -3
포인트의 스탑 레벨을 설정하고 Low - Open = -5
스탑 오더가 발동되고 열린 포지션은 -5
대신 -3
포인트의 손실로 청산됩니다. 이것은 위험을 줄이는 간단한 방법입니다. 다음 코드는 정지 수준의 거래를 시뮬레이션하는 도우미 함수를 나타냅니다.
# This is a helper function to trade 1 bar (for example 1 day) with a Buy order at opening session # and a Sell order at closing session. To protect against adverse movements of the price, a STOP order # will limit the loss to the stop level (stop parameter must be a negative number) # each bar must contains the following attributes: # Open, High, Low, Close prices as well as gain = Close - Open and lo = Low - Open def trade_with_stop(bar, slippage = 0, stop=None): """ Given a bar, with a gain obtained by the closing price - opening price it applies a stop limit order to limit a negative loss If stop is equal to None, then it returns bar['gain'] """ bar['gain'] = bar['gain'] - slippage if stop<>None: real_stop = stop - slippage if bar['lo']<=stop: return real_stop # stop == None return bar['gain']
거래 비용
거래 비용은 증권을 매매할 때 발생하는 비용입니다. 거래 비용에는 브로커의 수수료와 스프레드(딜러가 유가 증권에 대해 지불한 가격과 구매자가 지불하는 가격의 차이)가 포함되며 실제 시나리오와 유사하게 전략을 백테스트하려는 경우 고려해야 합니다. 주식 거래의 슬리피지는 스프레드에 변화가 있을 때 종종 발생합니다. 이 예와 다음 진행 중인 시뮬레이션에서 거래 비용은 다음과 같이 고정됩니다.

- 미끄러짐 = 0.6 포인트
- 커미션 = 각 거래에 대해 1$(1턴의 비용은 2$)
몇 가지 숫자를 쓰자면, 총 이익이 10포인트, 1포인트 = $25이므로 거래 비용을 포함하여 $250이면 순 이익은 (10 - 0.6)*$25 - 2 = $233
입니다.
다음 코드는 손절매가 -3포인트인 이전 거래 전략의 시뮬레이션을 보여줍니다. 파란색 곡선은 누적 수익률 곡선입니다. 설명된 유일한 비용은 슬리피지(0.6포인트)이며 결과는 베이시스 포인트(Yahoo Finance에서 다운로드한 S&P 500 값의 동일한 기본 단위)로 표시됩니다.
SLIPPAGE = 0.6 STOP = -3 trades = testing[testing['predictions'] == 1][('datetime', 'gain', 'ho', 'lo', 'open', 'close')] trades['pnl'] = trades.apply(lambda x: trade_with_stop(x, slippage=SLIPPAGE, stop=STOP)) plot_equity_chart(trades['pnl'],'Decision tree model') print("Slippage is %s, STOP level at %s" % (SLIPPAGE, STOP))
Mean of PnL is 2.162171 Sharpe is 3.502897 Round turns 511 Slippage is 0.6 STOP level at -3
다음 코드는 약간 다른 방식으로 예측하는 데 사용됩니다. 추가 매개변수 output_type = “probability”
와 함께 호출되는 predict
메소드에 주의하십시오. 이 매개변수는 클래스 예측 대신 예측된 값의 확률을 반환하는 데 사용됩니다(긍정적으로 예측된 결과의 경우 +1
, 부정적으로 예측된 결과의 경우 -1
). 0.5
이상의 확률은 예측 값 +1
과 연관되고 0.5
미만의 확률 값은 예측 값 -1
과 연관됩니다. 확률이 높을수록 실제 Up Day 를 예측해야 할 확률이 높아집니다.
predictions_prob = decision_tree.predict(testing, output_type = 'probability') # predictions_prob will contain probabilities instead of the predicted class (-1 or +1)
이제 슬리피지 및 커미션을 포함한 일련의 누적 수익을 계산하고 해당 값을 플롯하는 backtest_ml_model
이라는 도우미 함수로 모델을 백테스트합니다. 간결함을 위해 backtest_ml_model
함수를 철저히 설명하지 않고 강조해야 할 중요한 세부 사항은 이전 예에서와 같이 predictions_prob
된 outcome = 1
로 해당 날짜를 필터링하는 대신 이제 threshold = 0.5
이상인 predicts_prob를 필터링한다는 것입니다. 다음과 같이:
trades = testing[predictions_prob>=0.5][('datetime', 'gain', 'ho', 'lo', 'open', 'close')]
각 거래일의 순 이익 은 다음과 같습니다. Net gain = (Gross gain - SLIPPAGE) * MULT - 2 * COMMISSION
.
거래 전략의 장점을 평가하는 데 사용되는 또 다른 중요한 지표는 Maximum Drawdown 입니다. 일반적으로 투자된 포트폴리오의 가치에서 정점에서 바닥까지 가장 큰 단일 하락을 측정합니다. 우리의 경우, 이것은 주가 곡선의 정점에서 바닥까지 가장 큰 하락입니다(우리 포트폴리오에는 S&P 500이라는 자산이 하나만 있습니다). 따라서 이익 및 손실 pnl
의 SArray
가 주어지면 다음과 같이 드로다운을 계산합니다.
drawdown = pnl - pnl.cumulative_max() max_drawdown = min(drawdown)
도우미 함수 내에서 backtest_summary
가 계산됩니다.
- 위와 같은 최대 인출액(달러).
-
Graphlab.evaluation
방법으로 정확도. -
Graphlab.evaluation
방법을 사용하는 정밀도. -
Graphlab.evaluation
메서드를 사용하여 회상합니다.
모든 것을 종합하면 다음 예는 모든 값이 달러로 표시된 모델 전략의 누적 수익을 나타내는 자기자본 곡선을 보여줍니다.
model = decision_tree predictions_prob = model.predict(testing, output_type="probability") THRESHOLD = 0.5 bt_1_1 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree') backtest_summary(bt_1_1)
Mean of PnL is 54.054286 Sharpe is 3.502897 Round turns 511 Name: DecisionTree Accuracy: 0.577373211964 Precision: 0.587084148728 Recall: 0.724637681159 Max Drawdown: -1769.00025
예측된 값의 정밀도를 높이기 위해 0.5
(50%)의 표준 확률 대신 더 높은 임계값을 선택하여 모델이 Up day 를 예측한다는 확신을 갖게 합니다.
THRESHOLD = 0.55 # it's the minimum threshold to predict an Up day so hopefully a good day to trade bt_1_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree') backtest_summary(bt_1_2)
Mean of PnL is 118.244689 Sharpe is 6.523478 Round turns 234 Name: DecisionTree Accuracy: 0.560468140442 Precision: 0.662393162393 Recall: 0.374396135266 Max Drawdown: -1769.00025
위의 차트에서 볼 수 있듯이 주식 곡선은 더 적은 라운드 회전에도 불구하고 이전보다 훨씬 낫습니다(Sharpe는 3.5 대신 6.5임).
이 시점부터 우리는 표준 값보다 높은 임계 값을 가진 모든 다음 모델을 고려할 것입니다.
물류 분류기 훈련
이전에 의사 결정 트리에서 했던 것처럼 우리의 연구를 Logistic Classifier 모델에 적용할 수 있습니다. GraphLab Create는 Logistic Classifier 객체와 동일한 인터페이스를 가지며 동일한 매개변수 목록으로 모델을 빌드하기 위해 create
메소드를 호출합니다. 게다가, 우리는 예측된 클래스 벡터 대신 확률 벡터를 예측하는 것을 선호하므로(긍정적인 결과의 경우 +1
, 부정적인 결과의 경우 -1
로 구성됨), 더 나은 정밀도를 달성하기 위해 임계값이 0.5
보다 커야 합니다. 예측.
model = gl.logistic_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.6 bt_2_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_2_2)
Mean of PnL is 112.704215 Sharpe is 6.447859 Round turns 426 Name: LogisticClassifier Accuracy: 0.638491547464 Precision: 0.659624413146 Recall: 0.678743961353 Max Drawdown: -1769.00025
이 경우 Decision Tree와 매우 유사한 요약이 있습니다. 결국 두 모델 모두 분류기이며 이진 결과 클래스( +1
, -1
)만 예측합니다.
선형 회귀 모델 훈련
이 모델의 주요 차이점은 앞에서 언급한 것처럼 이진 클래스 대신 연속 값을 처리한다는 것입니다. Up 일 에 대해 +1
및 Down 일 에 대해 -1
과 동일한 목표 변수를 사용하여 모델을 훈련할 필요는 없으며 목표는 연속 변수여야 합니다. 우리는 양의 이득, 즉 시작 가격보다 높은 종가 를 예측하기를 원하기 때문에 이제 목표는 훈련 세트의 이득 열이어야 합니다. 또한 기능 목록은 이전 Open
, Close
등과 같은 연속 값으로 구성되어야 합니다.
간결함을 위해 올바른 기능을 선택하는 방법에 대한 자세한 내용은 다루지 않을 것입니다. 이는 이 기사의 범위를 벗어나므로 데이터 세트에 대해 다양한 기계 학습 모델을 적용하는 방법을 보여주는 경향이 더 큽니다. create 메소드에 전달된 매개변수 목록은 다음과 같습니다.
-
training
- 특징 열과 대상 열을 포함하는 훈련 세트입니다. -
target
- 대상 변수를 포함하는 열의 이름입니다. -
validation_set
- 모델의 일반화 성능을 모니터링하기 위한 데이터셋입니다. 우리의 경우validation_set
이 없습니다. -
features
- 모델 교육에 사용되는 기능의 열 이름 목록입니다. 이 모델의 경우 분류기 모델에 대해 다른 집합을 사용합니다. -
verbose
-true
훈련 중 진행 정보를 인쇄합니다. -
max_iterations
- 데이터를 통과할 수 있는 최대 허용 횟수입니다. 데이터를 더 많이 전달하면 더 정확하게 훈련된 모델이 생성될 수 있습니다.
model = gl.linear_regression.create(training, target='gain', features = l_lr_features, validation_set=None, verbose=False, max_iterations=100) predictions = model.predict(testing) # a linear regression model, predict continuous values, so we need to make an estimation of their # probabilities of success and normalize all values in order to have a vector of probabilities predictions_max, predictions_min = max(predictions), min(predictions) predictions_prob = (predictions - predictions_min)/(predictions_max - predictions_min)
지금까지 예측된 이득의 SArray
인 predictions_prob
이 있는 반면 SArray
는 predictions
값이 정규화된 SArray입니다. 이전 모델과 비교할 수 있는 좋은 정확도와 특정 라운드 회전 수를 얻기 위해 임계값을 0.4
로 선택했습니다. 0.4
미만의 predictions_prob
의 경우 backtest_linear_model
도우미 함수는 다운 데이 가 예상되기 때문에 거래를 열지 않습니다. 그렇지 않으면 거래가 열립니다.
THRESHOLD = 0.4 bt_3_2 = backtest_linear_model(testing, predictions_prob, target='gain', threshold=THRESHOLD, STOP = -3, plot_title=model.name()) backtest_summary(bt_3_2)
Mean of PnL is 138.868280 Sharpe is 7.650187 Round turns 319 Name: LinearRegression Accuracy: 0.631989596879 Precision: 0.705329153605 Recall: 0.54347826087 Max Drawdown: -1769.00025
부스트 트리 훈련
이전에 의사결정 트리를 훈련했던 것처럼 이제 다른 분류기 모델에 사용된 것과 동일한 매개변수를 사용하여 부스트 트리 분류기를 훈련할 것입니다. 또한 최대 부스팅 반복 횟수를 늘리기 위해 max_iterations = 12
로 설정했습니다. 각 반복은 추가 트리를 생성합니다. 또한 정밀도를 높이기 위해 임계값을 0.5
보다 높게 설정했습니다.
model = gl.boosted_trees_classifier.create(training, target='outcome', features=l_features, validation_set=None, max_iterations=12, verbose=False) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.7 bt_4_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_4_2)
Mean of PnL is 112.002338 Sharpe is 6.341981 Round turns 214 Name: BoostedTreesClassifier Accuracy: 0.563068920676 Precision: 0.682242990654 Recall: 0.352657004831 Max Drawdown: -1769.00025
랜덤 포레스트 훈련
이것은 의사 결정 트리의 앙상블로 구성된 마지막 훈련된 모델인 Random Forest Classifier입니다. 모델에서 사용할 최대 트리 수는 num_trees = 10
으로 설정되어 너무 많은 복잡성과 과적합을 방지합니다.
model = gl.random_forest_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False, num_trees = 10) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.6 bt_5_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_5_2)
Mean of PnL is 114.786962 sharpe is 6.384243 Round turns 311 Name: RandomForestClassifier Accuracy: 0.598179453836 Precision: 0.668810289389 Recall: 0.502415458937 Max Drawdown: -1769.00025
모든 모델을 함께 수집
Now we can join all the strategies together and see the overall result. It's interesting to see the summary of all Machine Learning models, sorted by their precision.
이름 | 정확성 | 정도 | round turns | 날카롭게 |
선형 회귀 | 0.63 | 0.71 | 319 | 7.65 |
BoostedTreesClassifier | 0.56 | 0.68 | 214 | 6.34 |
RandomForest 분류자 | 0.60 | 0.67 | 311 | 6.38 |
DecisionTree | 0.56 | 0.66 | 234 | 6.52 |
LogisticClassifier | 0.64 | 0.66 | 426 | 6.45 |
If we collect all the profit and loss for each one of the previous models in the array pnl
, the following chart depicts the equity curve obtained by the sum of each profit and loss, day by day.
Mean of PnL is 119.446463 Sharpe is 6.685744 Round turns 1504 First trading day 2013-04-09 Last trading day 2016-04-22 Total return 179647
Just to give some numbers, with about 3 years of trading, all models have a total gain of about 180,000 dollars. The maximum exposition is 5 CFD contracts in the market, but to reduce the risk they all are closed at the end of each day, so overnight positions are not allowed.
Statistics of the Aggregation of All Models Together
Since each model can open a trade, but we added 5 concurrent models together, during the same day there could be from 1 contract up to 5 CFD contracts. If all models agree to open trades during the same day, there is a high chance to have an Up day predicted. Moreover, we can group by the number of models that open a trade at the same time during the opening session of the day. Then we evaluate precision as a function of the number of concurrent models.
As we can see by the chart depicted above, the precision gets better as the number of models do agree to open a trade. The more models agree, the more precision we get. For instance, with 5 models triggered the same day, the chance to predict an Up day is greater than 85%.
결론
Even in the financial world, Machine Learning is welcomed as a powerful instrument to learn from data and give us great forecasting tools. Each model shows different values of accuracy and precision, but in general, all models can be aggregated to achieve a better result than each one of them taken singularly. GraphLab Create is a great library, easy to use, scalable and able to manage Big Data very quickly. It implements different scientific and forecasting models, and there is a free license for students and Kaggle competitions.
Additional disclosure: This article has been prepared solely for information purposes, and is not an offer to buy or sell or a solicitation of an offer to buy or sell any security or instrument or to participate in any particular trading strategy. Examples presented on these sites are for educational purposes only. Past results are not necessarily indicative of future results.