데이터 기반의 기술로 거래를 결합합니다.

저자:선함, 2019-08-21 13:50:23, 업데이트: 2023-10-19 21:01:31

img

짝짓기 거래는 수학 분석을 기반으로 거래 전략을 세우는 좋은 예입니다. 이 문서에서는 데이터를 사용하여 짝짓기 거래 전략을 만들고 자동화하는 방법을 보여줍니다.

기본 원칙

假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.

일시적인 가격 차이가 있을 때, 거래는 우수한 성능을 보이는 투자자를 팔고, 나쁜 성능을 보이는 투자자를 구입할 것이다. 두 투자자 사이의 이윤의 차이는 우수한 성능을 보이는 투자자의 하락, 나쁜 성능을 보이는 투자자의 회복, 또는 둘 다로 끝나는 것을 확신할 수 있다. 당신의 거래는 이러한 모든 비슷한 시나리오에서 돈을 벌 것이다. 만약 투자자가 한 번씩 상승하거나 하락하여 그 사이의 가격을 변경하지 않으면, 당신은 돈을 벌거나 손실하지 않을 것이다.

따라서 쌍거래는 시장중립적인 거래 전략으로 거래자가 거의 모든 시장 조건에서 이익을 얻을 수 있습니다: 상승 추세, 하락 추세 또는 수평 평형.

두 가지 가상의 투자 지표의 개념 설명

  • 발명가 양적 플랫폼에서 우리의 연구 환경을 구축합니다

우선, 작업이 원활하게 진행되기 위해서는 우리의 연구 환경을 구축해야 합니다.FMZ.COM이 연구 환경의 구축은 주로 이 플랫폼의 편리하고 빠른 API 인터페이스와 포괄적인 도커 시스템을 사용할 수 있도록 하기 위해 이루어졌다.

발명가들의 정량화 플랫폼의 공식 명칭에서, 이 도커 시스템은 호스트 시스템이라고 불린다.

관리자와 로봇을 배치하는 방법에 대해 이전 기사를 참조하십시오.https://www.fmz.com/bbs-topic/4140

클라우드 서버 배포 관리자를 구입하려는 독자들은 이 기사를 참조할 수 있습니다:https://www.fmz.com/bbs-topic/2848

좋은 클라우드 서비스와 관리자 시스템을 성공적으로 배치한 다음, 우리는 현재 가장 큰 파이썬 신비를 설치합니다: 아나콘다

이 문서에서 필요한 모든 관련 프로그램 환경을 구현하기 위해 ( 의존도, 버전 관리 등) 가장 쉬운 방법은 아나콘다 (Anaconda) 이다. 그것은 패키지 된 파이썬 데이터 과학 생태계와 의존도 관리자이다.

아나콘다를 설치하는 방법에 대해 아나콘다 공식 지침서를 참조하십시오:https://www.anaconda.com/distribution/

本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.

위의 기본 작업은 아나콘다 환경과 두 개의 라이브러리, 즉 피와 판다스를 설정하는 방법에 대한 나의 이전 기사를 참조할 수 있습니다.https://www.fmz.com/digest-topic/4169

다음으로, 두 가지 가설의 투자 지표를 코드를 통해 구현해 보겠습니다.

import numpy as np
import pandas as pd

import statsmodels
from statsmodels.tsa.stattools import coint
# just set the seed for the random number generator
np.random.seed(107)

import matplotlib.pyplot as plt

네, 우리는 또한 매우 유명한 파이썬의 matplotlib의 그래프 라이브러리를 사용할 것입니다.

가상의 투자 지표의 X를 생성하고 정규 분포를 통해 그것의 일일 수익을 모방하도록 합시다. 그리고 우리는 매일의 X값을 얻기 위해 더수를 수행합니다.

# Generate daily returns
Xreturns = np.random.normal(0, 1, 100) 
# sum them and shift all the prices up
X = pd.Series(np.cumsum(
    Xreturns), name='X') 
    + 50
X.plot(figsize=(15,7))
plt.show()

img

투자 지표의 X, 정규 분포를 통해 매일 수익을 모방합니다.

이제 우리가 생성한 Y와 X는 매우 밀접하게 연관되어 있기 때문에 Y의 가격은 X의 변화와 매우 유사해야 합니다. 우리는 X를 가져다가 위로 이동하고 정규 분포에서 추출한 일부 무작위 노이즈를 추가하여 이것을 모델링합니다.

noise = np.random.normal(0, 1, 100)
Y = X + 5 + noise
Y.name = 'Y'
pd.concat([X, Y], axis=1).plot(figsize=(15,7))
plt.show()

img

X와 Y를 합성하는 투자 지표

협동

协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:

Y = X + e

이 경우, e는 소음이다.

두 시간 계열 사이의 거래 쌍의 경우, 이 비율은 시간이 지남에 따라 예상되는 값이 균등한 값에 반드시 일치해야 합니다. 즉, 그들은 합동되어야 합니다. 위에서 우리가 구축한 시간 계열은 합동입니다. 우리는 이제 둘 사이의 비율을 그려서 그 외형을 볼 수 있도록 할 것입니다.

(Y/X).plot(figsize=(15,7)) 
plt.axhline((Y/X).mean(), color='red', linestyle='--') 
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()

img

두 개의 융합된 투자 지표의 가격 사이의 비율과 평균

협조 테스트

statsmodels.tsa.stattools를 이용해서 편리한 테스트 방법이 있습니다. 우리는 매우 낮은 p값을 볼 수 있어야 합니다. 왜냐하면 우리는 인공적으로 가능한 한 두 개의 서로 일치하는 데이터 시리즈를 만들어냈기 때문입니다.

# compute the p-value of the cointegration test
# will inform us as to whether the ratio between the 2 timeseries is stationary
# around its mean
score, pvalue, _ = coint(X,Y)
print pvalue

그 결과는 1.81864477307e-17입니다.

참고: 관련성 및 통합성

연관성과 협조는 이론적으로 비슷하지만 동일하지 않습니다. 연관성이 있지만 협조가 아닌 데이터 시리즈의 예를 보겠습니다. 그리고 반대로도 예를 보겠습니다. 먼저 우리가 방금 생성한 일련의 연관성을 살펴 보겠습니다.

X.corr(Y)

그 결과는 0.951입니다.

우리가 예상했듯이, 이것은 매우 높습니다. 하지만 두 개의 연관되어 있지만 일치하지 않는 일련은 어떨까요? 간단한 예로는 두 개의 오차된 데이터 일련입니다.

ret1 = np.random.normal(1, 1, 100)
ret2 = np.random.normal(2, 1, 100)

s1 = pd.Series( np.cumsum(ret1), name='X')
s2 = pd.Series( np.cumsum(ret2), name='Y')

pd.concat([s1, s2], axis=1 ).plot(figsize=(15,7))
plt.show()
print 'Correlation: ' + str(X_diverging.corr(Y_diverging))
score, pvalue, _ = coint(X_diverging,Y_diverging)
print 'Cointegration test p-value: ' + str(pvalue)

img

두 개의 관련 시리즈 (함께 통합되지 않은)

관련 계수: 0.998 합동 검사 p값: 0.258

상관관계가 없는 협조의 간단한 예는 정형 분포 순서와 광파이다.

Y2 = pd.Series(np.random.normal(0, 1, 800), name='Y2') + 20
Y3 = Y2.copy()
Y3[0:100] = 30
Y3[100:200] = 10
Y3[200:300] = 30
Y3[300:400] = 10
Y3[400:500] = 30
Y3[500:600] = 10
Y3[600:700] = 30
Y3[700:800] = 10
Y2.plot(figsize=(15,7))
Y3.plot()
plt.ylim([0, 40])
plt.show()
# correlation is nearly zero
print 'Correlation: ' + str(Y2.corr(Y3))
score, pvalue, _ = coint(Y2,Y3)
print 'Cointegration test p-value: ' + str(pvalue)

img

관련자: 0.007546 합동 검사 p값: 0.0

그리고 그 결과, 우리는 이 모든 것들을 모두 다룰 수 있었습니다.

어떻게 짝짓기를 할 수 있을까요?

두 개의 합동 시간 순서 (예를 들어 위의 X와 Y) 가 서로 대립하고 서로 편차하기 때문에, 때때로 기하급수 높고 낮은 기하급수 상황이 발생합니다. 우리는 한 지표를 구입하고 다른 지표를 팔고 쌍으로 거래합니다. 따라서 두 지표가 함께 하락하거나 상승하면 우리는 돈을 벌지 않고 잃지 않습니다. 즉, 우리는 시장의 중립자입니다.

상단 Y= X + e의 X와 Y로 돌아가서 비율 (Y / X) 가 그 평균값의 주위를 움직이게 되면, 우리는 평균값이 돌아오는 비율을 통해 돈을 벌습니다. 이것을 하기 위해 우리는 X와 Y가 멀리 떨어져 있는 경우, 즉 문턱이 너무 높거나 너무 낮을 때 주의를 기울일 것입니다:

  • 더 많은 비율을 만들어: 이것은 비율이 매우 작고 우리는 그것을 더 커질 것으로 예상할 때입니다. 위의 예제에서 우리는 더 많은 Y를하고 X를 공허하게 함으로써 거래를 시작합니다.

  • 공백비율: 이것은 비율이 크게 증가하고 우리는 그것을 시간으로 바뀔 것으로 기대합니다. 위의 예제에서 우리는 공백 Y와 더 많은 X를 함으로써 거래를 시작합니다.

참고로, 우리는 항상 헤지 포지션을 가지고 있습니다: 거래 지표의 구매 손실 가치가 있다면, 빈 포지션은 돈을 벌고, 반대로, 따라서 우리는 전체 시장 움직임에 면역됩니다.

거래 지표의 X와 Y가 서로 상대적으로 움직이면 우리는 돈을 벌거나 손실합니다.

데이터 검색을 통해 비슷한 거래 지표를 찾습니다

이렇게 하는 가장 좋은 방법은 합동 거래 지표가 될 수 있다고 의심하는 지표에서 시작하여 통계 테스트를 수행하는 것입니다.다중 비교 편차이 모든 것은 우리들의 희생물입니다.

다중 비교 편차많은 테스트를 실행할 때 중요한 p값을 잘못 생성할 확률이 증가하는 경우를 말합니다. 왜냐하면 우리는 많은 테스트를 실행해야 하기 때문입니다. 만약 무작위 데이터에 100번 테스트를 한다면, 우리는 0.05보다 낮은 5개의 p값을 볼 수 있을 것입니다. 만약 n개의 트랜잭션 지표를 전체적으로 협동하기 위해 비교해야 한다면, 당신은 n ((n-1) / 2개의 비교를 수행할 것이고, 많은 잘못된 p값을 볼 수 있을 것입니다. 이것은 당신의 테스트 샘플이 증가함에 따라 증가할 것입니다. 이러한 상황을 피하기 위해, 몇 개의 트랜잭션 쌍을 선택하여 당신이 협동할 가능성이 있다고 확신할 이유가 있는 몇 가지 트랜잭션을 선택하고 개별적으로 테스트하십시오. 이것은 크게 감소할 것입니다.다중 비교 편차

따라서 협조를 나타내는 지표를 찾으려고 노력해보자. S&P 500 지표의 한 바구니의 미국 대기업 기술 주식을 예로 들어보자. 이 지표들은 비슷한 세그먼트 시장에서 운영되고 있으며 협조가 있습니다. 우리는 거래 지표의 목록을 스캔하고 모든 쌍 사이의 협조를 테스트합니다.

복귀된 공동성 검사 분자 매트릭스, p값 매트릭스 및 p값이 0.05보다 작은 모든 페어링들.이 방법은 여러 비교 오차가 발생할 수 있기 때문에 실제로 두 번째 검증이 필요합니다.이 문서는 우리의 설명의 편의를 위해 예를 들어서 이것을 무시하기로 선택했습니다.

def find_cointegrated_pairs(data):
    n = data.shape[1]
    score_matrix = np.zeros((n, n))
    pvalue_matrix = np.ones((n, n))
    keys = data.keys()
    pairs = []
    for i in range(n):
        for j in range(i+1, n):
            S1 = data[keys[i]]
            S2 = data[keys[j]]
            result = coint(S1, S2)
            score = result[0]
            pvalue = result[1]
            score_matrix[i, j] = score
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.02:
                pairs.append((keys[i], keys[j]))
    return score_matrix, pvalue_matrix, pairs

참고: 우리는 데이터에 시장 지표 (SPX) 를 포함하고 있습니다. 시장은 많은 거래 지표의 흐름을 촉진합니다. 일반적으로 두 개의 서로 협력하는 것처럼 보이는 거래 지표를 발견 할 수 있습니다. 그러나 실제로는 서로 협력하지 않고 시장과 협력합니다. 이것은 혼성 변수라고합니다. 당신이 발견하는 모든 관계에서 시장 참여를 검사하는 것이 중요합니다.

from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2007/12/01'
endDateStr = '2017/12/01'
cachedFolderName = 'yahooData/'
dataSetId = 'testPairsTrading'
instrumentIds = ['SPY','AAPL','ADBE','SYMC','EBAY','MSFT','QCOM',
                 'HPQ','JNPR','AMD','IBM']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')
data = ds.getBookDataByFeature()['Adj Close']
data.head(3)

img

이제 우리의 방법을 사용하여 합동 트레이드 페어링을 찾으려고 노력하겠습니다.

# Heatmap to show the p-values of the cointegration test
# between each pair of stocks
scores, pvalues, pairs = find_cointegrated_pairs(data)
import seaborn
m = [0,0.2,0.4,0.6,0.8,1]
seaborn.heatmap(pvalues, xticklabels=instrumentIds, 
                yticklabels=instrumentIds, cmap=’RdYlGn_r’, 
                mask = (pvalues >= 0.98))
plt.show()
print pairs
[('ADBE', 'MSFT')]

img

ADBE 염기소와 MSFT 염기소가 함께 작동하는 것처럼 보입니다. 가격을 살펴보고 그것이 정말로 의미 있는지 확인하십시오.

S1 = data['ADBE']
S2 = data['MSFT']
score, pvalue, _ = coint(S1, S2)
print(pvalue)
ratios = S1 / S2
ratios.plot()
plt.axhline(ratios.mean())
plt.legend([' Ratio'])
plt.show()

img

2008 - 2017 MSFT와 ADBE 사이의 가격 비율 그래프

이 비율은 실제로 안정적인 평균값처럼 보입니다. 절대 비율은 통계적으로 유용하지 않습니다. z 점수로 간주하여 우리의 신호를 표준화하는 것이 더 도움이됩니다. z 점수는 다음과 같이 정의됩니다.

Z 점수 (값) = (값 평균) / 표준편차

경고

사실, 우리는 보통 데이터에 약간의 확장을 시도하지만, 그 데이터가 정규 분포라고 가정합니다. 그러나, 많은 금융 데이터가 정규 분포가 아니기 때문에, 우리는 통계 자료를 생성할 때 단순하게 정규 분포를 또는 어떤 특정 분포를 가정하지 않도록 매우 조심해야 합니다. 비율의 진실 분포는 뚱뚱한 꼬리 효과를 가질 수 있으며, 극단적으로 기울는 데이터는 우리의 모델을 혼란스럽게 만들고 엄청난 손실을 초래할 수 있습니다.

def zscore(series):
    return (series - series.mean()) / np.std(series)
zscore(ratios).plot()
plt.axhline(zscore(ratios).mean())
plt.axhline(1.0, color=’red’)
plt.axhline(-1.0, color=’green’)
plt.show()

img

MSFT와 ADBE 사이의 Z 가격 비율 2008 - 2017

이제 비율이 평균에 가까운 이동을 더 쉽게 관찰 할 수 있지만 때로는 평균과 큰 차이가 발생할 수 있습니다. 우리는 이것을 활용 할 수 있습니다.

이제 우리는 거래 전략의 기초를 논의하고 역사적인 가격에 따라 공동 통합된 거래 지표를 결정했습니다. 먼저 데이터 기술을 사용하여 거래 신호를 개발하는 단계를 살펴 보겠습니다.

  • 신뢰할 수 있는 데이터를 수집하고 데이터를 청소합니다.

  • 거래 신호/논리를 식별하기 위해 데이터에서 기능을 만드는 것

  • 기능은 이동 평균 또는 가격 데이터, 관련성 또는 더 복잡한 신호의 비율이 될 수 있습니다.

  • 이러한 기능을 사용하여 거래 신호를 생성합니다.

다행히도 우리는 발명가 양적 플랫폼을 가지고 있습니다.fmz.com이 네 가지 측면에 대한 작업은 전략 개발자들에게 큰 축복이 될 것입니다. 우리는 전략 논리의 디자인과 기능 확장에 모든 에너지와 시간을 할애 할 수 있습니다.

발명가들의 정량화 플랫폼에는 다양한 주류 거래소의 인터페이스가 포장되어 있습니다. 우리가 해야 할 일은 API를 호출하는 것뿐입니다.

이 논리의 완전성과 원리에 대한 설명을 위해, 우리는 여기서 이러한 기본 논리를 틴처럼 풀어 놓을 것이지만 실제 동작에서는 독자들이 직접 발명자의 양적 API 인터페이스를 호출하여 위의 네 가지 사항을 수행 할 수 있습니다.

자 이제 시작합시다.

첫 번째 단계: 문제를 설정합니다.

여기서 우리는 신호를 만들어 다음 순간에 이 비율이 구매가 될지 판매가 될지 알려줍니다. 우리의 예측 변수 Y:

Y = 비율은 구매 (1) 또는 판매 (-1) 입니다.

Y(t)= Sign(Ratio(t+1) Ratio(t))

참고로, 우리는 실제 거래 지표의 가격을 예측할 필요가 없습니다. 심지어는 비율의 실제 가치를 예측할 필요가 없습니다. (하지만 우리는 할 수 있습니다.)

두 번째 단계: 신뢰할 수 있고 정확한 데이터를 수집합니다.

발명자 양성은 당신의 친구입니다! 당신은 단지 거래하고자 하는 거래 지표와 사용하고자 하는 데이터 소스를 지정하면, 그것은 필요한 데이터를 추출하고 이산화탄소와 거래 지표의 분할을 위해 그것을 정화합니다. 그래서 우리는 여기에 데이터를 깨끗하게했습니다.

우리는 지난 10년 (약 2500개의 데이터 포인트) 의 거래일에 대해 야후 재무를 사용하여 얻은 다음 데이터를 수집했습니다: 오픈 가격, 종료 가격, 최고 가격, 최저 가격, 거래량

세 번째 단계: 데이터 분할

모델의 정확성을 테스트하는 매우 중요한 단계를 잊지 마십시오. 우리는 다음 데이터를 사용하여 훈련 / 검증 / 테스트 분할을하고 있습니다.

  • 교육 7년 ~ 70%

  • 테스트 ~ 3년 30%

ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]

이상적으로, 우리는 또한 검증 집합을 만들어야 하지만, 우리는 지금 당장 그렇게 하지 않을 것이다.

네 번째 단계: 특징 엔지니어링

관련 기능은 무엇인가? 우리는 비율의 변화 방향을 예측하고자 한다. 우리는 이미 우리의 두 거래 지표가 합동이라는 것을 보았고, 따라서 이 비율은 종종 이동하고 평균으로 돌아간다. 우리의 특징은 비율의 평균의 어떤 메터릭스가 되어야 하며, 현재 값과 평균의 차이는 우리의 거래 신호를 생성할 수 있는 것처럼 보인다.

우리는 다음과 같은 기능을 사용합니다.

  • 60일 이동평균 비율: 롤링 평균의 측정

  • 5일 이동 평균 비율: 평균의 현재 값의 측정

  • 60일 표준차기

  • z 점수: ((5d MA - 60d MA) / 60d SD

ratios_mavg5 = train.rolling(window=5,
                               center=False).mean()
ratios_mavg60 = train.rolling(window=60,
                               center=False).mean()
std_60 = train.rolling(window=60,
                        center=False).std()
zscore_60_5 = (ratios_mavg5 - ratios_mavg60)/std_60
plt.figure(figsize=(15,7))
plt.plot(train.index, train.values)
plt.plot(ratios_mavg5.index, ratios_mavg5.values)
plt.plot(ratios_mavg60.index, ratios_mavg60.values)
plt.legend(['Ratio','5d Ratio MA', '60d Ratio MA'])
plt.ylabel('Ratio')
plt.show()

img

60d와 5d MA의 가격 비율

plt.figure(figsize=(15,7))
zscore_60_5.plot()
plt.axhline(0, color='black')
plt.axhline(1.0, color='red', linestyle='--')
plt.axhline(-1.0, color='green', linestyle='--')
plt.legend(['Rolling Ratio z-Score', 'Mean', '+1', '-1'])
plt.show()

img

60-5 Z 점수 가격 비율

이 점수는 실제로 비율의 평균 회귀성을 나타냅니다.

5단계: 모델 선택

아주 간단한 모델에서 시작해 보겠습니다. z 점수의 그래프를 보면 z 점수가 너무 높거나 너무 낮을 때마다 돌아오는 것을 볼 수 있습니다.

  • z가 -1보다 작을 때, 이 비율은 사 (1) 입니다. z가 0으로 돌아갈 것으로 예상하기 때문에 이 비율은 증가합니다.

  • z가 1.0보다 높을 때, 비율은 <-1>로 팔립니다. z가 0으로 돌아갈 것으로 예상하기 때문에 비율은 감소합니다.

단계 6: 훈련, 검증 및 최적화

마지막으로, 우리의 모델이 실제 데이터에 미치는 실제 영향을 봅시다.

# Plot the ratios and buy and sell signals from z score
plt.figure(figsize=(15,7))
train[60:].plot()
buy = train.copy()
sell = train.copy()
buy[zscore_60_5>-1] = 0
sell[zscore_60_5<1] = 0
buy[60:].plot(color=’g’, linestyle=’None’, marker=’^’)
sell[60:].plot(color=’r’, linestyle=’None’, marker=’^’)
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,ratios.min(),ratios.max()))
plt.legend([‘Ratio’, ‘Buy Signal’, ‘Sell Signal’])
plt.show()

img

구매 및 판매 가격 비율 신호

이 신호는 합리적으로 보이지만, 우리는 높은 또는 증가하는 비율 (붉은 점) 을 팔고 낮은 (녹색 점) 과 감소하는 비율을 다시 구입하는 것처럼 보입니다. 이것이 우리가 거래하는 실제 거래 지표에 무엇을 의미합니까?

# Plot the prices and buy and sell signals from z score
plt.figure(figsize=(18,9))
S1 = data['ADBE'].iloc[:1762]
S2 = data['MSFT'].iloc[:1762]
S1[60:].plot(color='b')
S2[60:].plot(color='c')
buyR = 0*S1.copy()
sellR = 0*S1.copy()
# When buying the ratio, buy S1 and sell S2
buyR[buy!=0] = S1[buy!=0]
sellR[buy!=0] = S2[buy!=0]
# When selling the ratio, sell S1 and buy S2 
buyR[sell!=0] = S2[sell!=0]
sellR[sell!=0] = S1[sell!=0]
buyR[60:].plot(color='g', linestyle='None', marker='^')
sellR[60:].plot(color='r', linestyle='None', marker='^')
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,min(S1.min(),S2.min()),max(S1.max(),S2.max())))
plt.legend(['ADBE','MSFT', 'Buy Signal', 'Sell Signal'])
plt.show()

img

MSFT 및 ADBE 주식을 구매하고 판매하는 신호

우리는 때때로 짧은 다리, 때로는 긴 다리, 때로는 둘 다로 돈을 벌 수 있습니다.

우리는 훈련 데이터의 신호에 만족합니다. 이 신호가 어떤 수익을 가져올 수 있는지 보자. 비율이 낮을 때 우리는 간단한 리코더를 만들 수 있습니다. 1 비율을 구매하십시오. (ADBE 주식 1개를 구입하고 MSFT 주식 x 판매 비율을 구매하십시오.)

# Trade using a simple strategy
def trade(S1, S2, window1, window2):
    
    # If window length is 0, algorithm doesn't make sense, so exit
    if (window1 == 0) or (window2 == 0):
        return 0
    
    # Compute rolling mean and rolling standard deviation
    ratios = S1/S2
    ma1 = ratios.rolling(window=window1,
                               center=False).mean()
    ma2 = ratios.rolling(window=window2,
                               center=False).mean()
    std = ratios.rolling(window=window2,
                        center=False).std()
    zscore = (ma1 - ma2)/std
    
    # Simulate trading
    # Start with no money and no positions
    money = 0
    countS1 = 0
    countS2 = 0
    for i in range(len(ratios)):
        # Sell short if the z-score is > 1
        if zscore[i] > 1:
            money += S1[i] - S2[i] * ratios[i]
            countS1 -= 1
            countS2 += ratios[i]
            print('Selling Ratio %s %s %s %s'%(money, ratios[i], countS1,countS2))
        # Buy long if the z-score is < 1
        elif zscore[i] < -1:
            money -= S1[i] - S2[i] * ratios[i]
            countS1 += 1
            countS2 -= ratios[i]
            print('Buying Ratio %s %s %s %s'%(money,ratios[i], countS1,countS2))
        # Clear positions if the z-score between -.5 and .5
        elif abs(zscore[i]) < 0.75:
            money += S1[i] * countS1 + S2[i] * countS2
            countS1 = 0
            countS2 = 0
            print('Exit pos %s %s %s %s'%(money,ratios[i], countS1,countS2))
            
            
    return money
trade(data['ADBE'].iloc[:1763], data['MSFT'].iloc[:1763], 60, 5)

그 결과는 1783.375입니다.

이제 우리는 이동 평균 시간 창을 변경하여 구매/판매 평형 포지션의 문턱을 변경하여 더 이상 최적화 할 수 있으며 확인 데이터의 성능 향상을 확인할 수 있습니다.

더 복잡한 모델, 예를 들어 로지스틱 회귀, SVM 등을 시도하여 1/-1 예측을 할 수도 있습니다.

이제, 이 모델을 좀 더 발전시켜 보겠습니다.

7단계: 테스트 데이터를 재검토합니다.

여기에 또 다른 발명자의 정량화 플랫폼을 들자면, 고성능의 QPS/TPS 재검토 엔진을 사용하여 실제적인 역사적 환경을 재현하여 일반적인 정량화 재검토 함정을 제거하고 전략의 결함을 조기에 발견하여 실제 투자에 더 나은 도움을 줍니다.

이 문서는 원리를 설명하기 위해 선택되었거나, 실제 응용에서 기본 논리를 보여주거나, 독자들이 발명자의 정량화 플랫폼을 사용하도록 권장합니다.

이 함수들은 PnL를 볼 수 있습니다.

trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)

그 결과는: 5262,868입니다.

이 모델은 아주 잘 작동했습니다. 이것은 우리의 첫 번째 간단한 쌍용 거래 모델이 되었습니다.

너무 잘 어울리지 않도록

토론을 끝마치기 전에, 나는 특히 과도한 적합성에 대해 논의하고 싶습니다. 과도한 적합성은 거래 전략에서 가장 위험한 함정입니다. 과도한 적합 알고리즘은 재검토에서 매우 잘 수행 할 수 있지만 새로운 눈에 보이지 않는 데이터에서 실패 할 수 있습니다. 즉, 그것은 데이터의 어떤 경향을 실제로 밝혀내지 않으며 진정한 예측 능력이 없습니다. 간단한 예를 들어 보겠습니다.

우리 모델에서, 우리는 롤러 파라미터 예측을 사용 하 고 시간 창 길이에 의해 최적화 되길 바랍니다. 우리는 간단하게 모든 가능성을 반복, 합리적인 시간 창 길이 결정 할 수 있습니다, 그리고 우리의 모델이 수행에 따라 가장 좋은 시간 길이를 선택 합니다. 아래에서 우리는 훈련 데이터에 따라 시간 창 길이를 PNL 점수를 부여하고 최적의 루프를 찾기 위해 간단한 루프를 작성 합니다.

# Find the window length 0-254 
# that gives the highest returns using this strategy
length_scores = [trade(data['ADBE'].iloc[:1762], 
                data['MSFT'].iloc[:1762], l, 5) 
                for l in range(255)]
best_length = np.argmax(length_scores)
print ('Best window length:', best_length)
('Best window length:', 40)

이제 우리는 테스트 데이터에 대한 모델의 성능을 검사하고, 우리는 이 시간 창의 길이가 최적의 길이가 아니라는 것을 발견했습니다! 이것은 우리가 원래 선택한 것이 표본 데이터에 명백히 너무 적합했기 때문입니다.

# Find the returns for test data
# using what we think is the best window length
length_scores2 = [trade(data['ADBE'].iloc[1762:], 
                  data['MSFT'].iloc[1762:],l,5) 
                  for l in range(255)]
print (best_length, 'day window:', length_scores2[best_length])
# Find the best window length based on this dataset, 
# and the returns using this window length
best_length2 = np.argmax(length_scores2)
print (best_length2, 'day window:', length_scores2[best_length2])
(40, 'day window:', 1252233.1395)
(15, 'day window:', 1449116.4522)

분명히 우리의 샘플 데이터에 적합한 것은 항상 미래에 좋은 결과를 가져오지 않습니다. 단지 테스트를 위해 두 데이터 세트에서 계산된 길이 분수를 그려봅시다.

plt.figure(figsize=(15,7))
plt.plot(length_scores)
plt.plot(length_scores2)
plt.xlabel('Window length')
plt.ylabel('Score')
plt.legend(['Training', 'Test'])
plt.show()

img

우리는 20-50 사이의 모든 것이 시간 창에 좋은 선택 사항이라고 볼 수 있습니다.

과도한 적합성을 피하기 위해, 우리는 경제 추론이나 알고리즘의 특성을 사용하여 시간 창의 길이를 선택할 수 있다. 우리는 또한 칼만 필터를 사용할 수 있다. 그것은 우리가 길이를 지정할 필요가 없다. 이 방법은 나중에 다른 기사에서 소개될 것이다.

다음 단계

이 기사에서는 거래 전략을 개발하는 과정을 보여주는 간단한 소개 방법을 제시합니다. 실제로는 더 복잡한 통계 자료를 사용해야 합니다. 아래와 같은 옵션을 고려할 수 있습니다.

  • 허스터 지수

  • 오른슈타인-울렌베크 과정으로부터 추론된 평균값 회귀의 반성기

  • 칼만 필터


관련

더 많은

bk_fund파키지를 찾을 수 없습니다.

bk_fund배크테스터.데이터소스.야후_데이터_소스를 설치할 수 있는 곳