거래에서 기계 학습 기술의 적용

저자:선함, 2019-08-29 09:42:00, 업데이트: 2023-10-19 21:02:44

img

이 글의 영감을 얻은 것은 발명가 양자 플랫폼을 연구하는 동안, 거래 문제에 기계 학습 기술을 적용하려고 시도했을 때 몇 가지 일반적인 경고와 함정을 관찰한 결과입니다.

만약 여러분이 제 이전 기사를 아직 읽지 않았다면, 이 기사를 읽기 전에 제 발명한 계량화 플랫폼에서 구축된 자동화된 데이터 연구 환경 및 거래 전략을 세우는 체계적인 방법에 대한 지침을 읽어보시기 바랍니다.

이쪽 주소입니다:https://www.fmz.com/digest-topic/4187그리고https://www.fmz.com/digest-topic/4169 这两篇文章.

연구 환경 구축에 관한

이 튜토리얼은 모든 기술 수준의 아마추어, 엔지니어 및 데이터 과학자를 위해 고안되었습니다. 업계의 거소 또는 프로그래머가 될지라도 필요한 유일한 기술은 파이썬 프로그래밍 언어의 기본 지식과 명령 줄 동작에 대한 충분한 지식입니다. (데이터 과학 프로젝트를 설정 할 수 있습니다.)

  • 발명자 양적 호스트를 설치하고 아나콘다를 설정

发明者量化平台FMZ.COM除了提供优质的各大主流交易所的数据源,还提供一套丰富的API接口以帮助我们在完成数据的分析后进行自动化交易。这套接口包括查询账户信息,查询各个主流交易所的高,开,低,收价格,成交量,各种常用技术分析指标等实用工具,特别是对于实际交易过程中连接各大主流交易所的公共API接口,提供了强大的技术支持。

위와 같은 모든 기능들이 도커와 비슷한 시스템으로 포장되어 있습니다. 우리가 해야 할 일은 클라우드 서비스를 구매하거나 임대한 후에 도커를 배포하는 것입니다.

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

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

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

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

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

우리는 Anaconda를 클라우드 서비스에서 설치하기 때문에, 우리는 클라우드 서버에 Anaconda의 명령 줄 버전의 리눅스 시스템을 설치하는 것이 좋습니다.

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

만약 당신이 경험이 많은 파이썬 프로그래머이고, 아나콘다를 사용하지 않아도 된다고 생각한다면, 그것은 전혀 문제가 아닙니다. 저는 당신이 필수적인 의존 환경을 설치하는 데 도움이 필요하지 않다고 가정합니다. 당신은 이 부분을 바로 건너갈 수 있습니다.

거래 전략을 세우는 것

거래 전략의 최종 출력은 다음과 같은 질문에 답해야 합니다.

  • 방향: 자산이 저렴하거나 비싸거나 가치가 공정하다는 것을 결정합니다.

  • 开仓条件:如果资产价格便宜或者昂贵,你应该做多或者做空.

  • 평형 거래: 자산의 가격이 합리적이고 우리가 그 자산에 지분을 보유하고 있다면 (전 구매 또는 판매) 평형해야 하는가

  • 가격 범위: 오픈 거래의 가격 (또는 범위)

  • 양: 거래 자금의 양 (예를 들어 디지털 통화 또는 상품 선물의 수)

기계 학습은 위의 모든 질문에 답할 수 있지만, 이 글의 나머지 부분에서는 첫 번째 질문, 즉 거래 방향에 초점을 맞출 것입니다.

전략적 방법

전략 구축에는 두 가지 유형의 방법이 있습니다. 하나는 모델 기반이며 다른 하나는 데이터 기반 채굴입니다. 이 두 가지 방법은 기본적으로 서로 반대되는 방법입니다.

모델 기반 전략 구축에서 우리는 시장 저효율 모델에서 시작하여 수학 표현 (예를 들어, 가격, 수익) 을 구축하고 더 긴 시간 주기에서 그 효과를 테스트합니다. 이 모델은 일반적으로 진정한 복잡한 모델의 단순화 버전이며, 긴 주기의 의미와 안정성을 검증해야 합니다. 일반적인 추세는 다음과 같습니다. 평형 회귀와 유치 전략은 모두이 범주에 속합니다.

반면, 우리는 먼저 가격 패턴을 찾고 데이터 채굴 방법에서 알고리즘을 시도합니다. 이러한 패턴의 원인이 중요하지 않습니다. 왜냐하면 특정 패턴만이 앞으로 반복될 것이기 때문입니다. 이것은 맹목적인 분석 방법이며, 우리는 무작위 패턴에서 진정한 패턴을 식별하기 위해 엄격한 검사를 필요로합니다.

분명히, 기계 학습은 데이터 채굴 방법에 쉽게 적용될 수 있습니다. 이제 데이터 채굴을 통해 거래 신호를 만드는 데 기계 학습을 사용하는 방법을 살펴 보겠습니다.

코드 예제들은 발명자 정량화 플랫폼에 기반한 재검토 도구와 자동화 거래 API 인터페이스를 사용합니다. 위의 섹션에서 호스트를 배포하고 아나콘다를 설치한 후, 필요한 데이터 과학 분석 라이브러리와 유명한 기계 학습 모델 스키키트-러닝을 설치합니다. 이 부분에 대한 내용은 더 이상 설명하지 않습니다.

pip install -U scikit-learn

기계 학습을 사용하여 거래 전략 신호를 만듭니다.

  • 데이터 채굴

우리가 시작하기 전에, 표준 기계 학습 문제 체계는 다음과 같습니다.

img

기계 학습 문제 시스템

우리가 만들고자 하는 특성은 어떤 예측 능력을 가지고 있어야 합니다 (X), 우리는 목표 변수를 (Y) 예측하고, 역사적 데이터를 사용하여 Y를 가능한 한 실제 값에 가깝게 예측할 수 있는 ML 모델을 훈련시키고 있습니다. 마지막으로, 우리는 이 모델을 사용하여 Y에 대해 알려지지 않은 새로운 데이터를 예측합니다. 이것은 우리에게 첫 번째 단계로 안내합니다:

첫 번째 단계: 문제를 설정하세요.

  • 어떤 예측을 하고 싶으세요? 좋은 예측은 무엇일까요? 그리고 그 결과를 어떻게 평가하시겠습니까?

Y는 어떻게 될까요?

img

당신은 무엇을 예측하고 싶습니까?

미래 가격을 예측하고, 미래 수익/Pnl, 구매/판매 신호, 포트폴리오 분배를 최적화하고, 거래를 효율적으로 실행하려고 하고 싶으십니까?

만약 우리가 다음 시간대에 가격을 예측하려고 한다면. 이 경우, Y (t) = 가격 (t + 1) 입니다. 이제 우리는 우리의 프레임을 역사적 데이터로 완성할 수 있습니다.

참고로 Y (t) 는 리모델링에서만 알려져 있지만, 우리가 우리의 모델을 사용할 때, 우리는 시간 t의 값을 알 수 없습니다. 우리는 우리의 모델을 사용하여 Y (t) 를 예측하고, t를 예측하고, 시간 t + 1에서만 실제 값과 비교합니다. 이것은 당신이 Y를 예측 모델의 특성으로 사용할 수 없다는 것을 의미합니다.

일단 목표 Y를 알게 되면, 우리는 또한 우리의 예측을 어떻게 평가할지 결정할 수 있다. 이것은 우리가 시도할 데이터의 다른 모델을 구별하는 데 매우 중요합니다. 우리가 해결하고 있는 문제에 따라, 우리의 모델의 효율성을 측정하는 지표를 선택하십시오. 예를 들어, 우리가 가격을 예측한다면, 우리는 평방 루트 오차를 지표로 사용할 수 있습니다. 몇 가지 일반적인 지표 (평방선, MACD 및 미분수 등) 는 발명자의 정량화 도구 상에 미리 코딩되어 있으며, 당신은 API 인터페이스를 통해 전 세계적으로 이러한 지표를 호출할 수 있습니다.

img

미래 가격을 예측하는 ML 프레임워크

예시를 위해, 우리는 다음과 같은 가정적 투자 지표의 미래 예상 기준 (basis) 값을 예측하는 예측 모델을 만들 것입니다.

basis = Price of Stock — Price of Future

basis(t)=S(t)−F(t)

Y(t) = future expected value of basis = Average(basis(t+1),basis(t+2),basis(t+3),basis(t+4),basis(t+5))

이것은 회귀 문제이기 때문에, 우리는 RMSE (평변 루트 오류) 에서 모델을 평가할 것입니다. 우리는 또한 전체 Pnl를 평가 기준으로 사용합니다.

참고: RMSE에 대한 관련 수학 지식은 백과사전 관련 내용을 참조하십시오.

  • 我们的目标:创建一个模型,使预测值尽可能接近Y.

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

데이터를 수집하고 정리하는 것은 바로 앞에 있는 문제를 해결하는 데 도움이 됩니다.

어떤 데이터가 목표 변수 Y에 대한 예측력을 가지고 있는지 고려해야합니까? 만약 우리가 가격을 예측한다면, 당신은 투자 지표의 가격 데이터, 투자 지표의 거래량 데이터, 관련 투자 지표의 유사한 데이터, 투자 지표의 지표의 밸류에이션 전체 시장 지표, 다른 관련 자산의 가격 등을 사용할 수 있습니다.

이 데이터에 대한 데이터 접근 권한을 설정하고 데이터의 정확성을 확인하고 손실된 데이터를 해결해야 합니다. (매우 흔한 문제) 동시에 데이터의 편견이 없음을 확인하고 모든 시장 조건을 충분히 표현해야 합니다. (예를 들어, 같은 수의 손실/이익 시나리오) 모델에서 오차가 발생하지 않도록 하기 위해. 또한 데이터를 정리하여 배당, 투자 지표 분할, 연속 등을 얻을 수 있습니다.

만약 당신이 발명가 양적 플랫폼을 사용한다면FMZ.COM우리는 구글, 야후, NSE, 그리고 쿼들에서 무료 글로벌 데이터; CTP와 이식과 같은 국내 상품 선물의 깊이 데이터; Binance, OKEX, Huobi, BitMex와 같은 주요 디지털 통화 거래소의 데이터에 액세스 할 수 있습니다. 발명자 양자 플랫폼은 또한 투자 지표의 분할 및 깊이 시장 데이터와 같은 데이터를 미리 청소하고 필터링하고 양자 작업자가 쉽게 이해할 수있는 형식으로 전략 개발자에게 제시합니다.

이 문서의 시범을 돕기 위해, 우리는 다음 데이터를 가상 투자 지표의 Auquan MQK 으로 사용했고, Auquan s Toolbox라는 매우 편리한 측정 도구를 사용했습니다. 더 많은 정보를 참조하십시오:https://github.com/Auquan/auquan-toolbox-python

# Load the data
from backtester.dataSource.quant_quest_data_source import QuantQuestDataSource
cachedFolderName = '/Users/chandinijain/Auquan/qq2solver-data/historicalData/'
dataSetId = 'trainingData1'
instrumentIds = ['MQK']
ds = QuantQuestDataSource(cachedFolderName=cachedFolderName,
                                    dataSetId=dataSetId,
                                    instrumentIds=instrumentIds)
def loadData(ds):
    data = None
    for key in ds.getBookDataByFeature().keys():
        if data is None:
            data = pd.DataFrame(np.nan, index = ds.getBookDataByFeature()[key].index, columns=[])
        data[key] = ds.getBookDataByFeature()[key]
    data['Stock Price'] =  ds.getBookDataByFeature()['stockTopBidPrice'] + ds.getBookDataByFeature()['stockTopAskPrice'] / 2.0
    data['Future Price'] = ds.getBookDataByFeature()['futureTopBidPrice'] + ds.getBookDataByFeature()['futureTopAskPrice'] / 2.0
    data['Y(Target)'] = ds.getBookDataByFeature()['basis'].shift(-5)
    del data['benchmark_score']
    del data['FairValue']
    return data
data = loadData(ds)

위의 코드로 Auquans Toolbox는 데이터를 데이터 사전에 다운로드하고 업로드했습니다. 이제 우리가 원하는 형식으로 데이터를 준비해야 합니다. ds.getBookDataByFeature () 함수는 데이터의 사전을 반환하고, 각각의 특징은 데이터입니다. 우리는 모든 특징을 가진 주식들을 위해 새로운 데이터을 만듭니다.

세 번째 단계: 데이터 분할

  • 데이터에서 트레이닝 세트를 만들고, 크로스 검증하고 테스트합니다.

이 모든 것은 매우 중요한 단계입니다.우리가 계속하기 전에, 우리는 데이터를 훈련 데이터 세트로 나누어야합니다. 당신의 모델을 훈련시키기 위해; 테스트 데이터 세트로 모델의 성능을 평가하기 위해. 60~70%의 훈련 세트와 30-40%의 테스트 세트로 나누는 것이 좋습니다.

img

데이터를 트레이닝 세트와 테스트 세트로 분리합니다.

훈련 데이터는 모델의 매개 변수를 평가하기 위해 사용되기 때문에, 당신의 모델은 이러한 훈련 데이터에 지나치게 적합할 수 있으며, 훈련 데이터는 모델의 성능을 오해할 수 있다. 만약 당신이 별도의 테스트 데이터를 보관하지 않고 모든 데이터를 훈련하기 위해 사용하지 않는다면, 당신의 모델이 새로운 보이지 않는 데이터에 대해 얼마나 잘 또는 나쁘게 수행하는지 알 수 없다. 이것은 훈련된 ML 모델이 실시간 데이터에 실패하는 주요 이유 중 하나입니다. 사람들은 사용 가능한 모든 데이터를 훈련하고 훈련된 데이터 지표에 흥분하지만 모델은 훈련되지 않은 실시간 데이터에 대해 의미있는 예측을 할 수 없습니다.

img

데이터를 트레이닝 세트, 검증 세트, 테스트 세트로 분할합니다.

이 방식에는 문제가 있다. 만약 우리가 훈련 데이터를 반복적으로 훈련시키고, 테스트 데이터의 성능을 평가하고, 성능에 만족할 때까지 우리의 모델을 최적화한다면, 우리는 임의로 테스트 데이터를 훈련 데이터의 일부로 간주한다. 결국, 우리의 모델은 훈련과 테스트 데이터의 그룹에 대해 잘 수행할 수 있지만, 새로운 데이터를 잘 예측할 수 있는 보장은 없다.

이 문제를 해결하기 위해, 우리는 개별적인 검증 데이터 세트를 만들 수 있습니다. 이제, 당신은 데이터를 훈련시킬 수 있습니다. 검증 데이터의 성능을 평가하고, 성능에 만족할 때까지 최적화하고, 마지막으로 테스트 데이터를 테스트 할 수 있습니다.

테스트 데이터의 성능을 확인한 후 모델을 더 이상 최적화하려고 시도하지 마십시오. 만약 모델이 좋은 결과를 주지 않는 것을 발견한다면 모델을 완전히 폐기하고 다시 시작하십시오. 훈련 데이터의 60%와 검증 데이터의 20%와 테스트 데이터의 20%를 분할하는 것이 좋습니다.

우리의 문제에 대해, 우리는 사용할 수 있는 세 개의 데이터 세트를 가지고 있습니다. 우리는 하나의 훈련 세트를 사용할 것입니다. 두 번째는 검증 세트, 세 번째는 우리의 테스트 세트.

# Training Data
dataSetId =  'trainingData1'
ds_training = QuantQuestDataSource(cachedFolderName=cachedFolderName,
                                    dataSetId=dataSetId,
                                    instrumentIds=instrumentIds)
training_data = loadData(ds_training)
# Validation Data
dataSetId =  'trainingData2'
ds_validation = QuantQuestDataSource(cachedFolderName=cachedFolderName,
                                    dataSetId=dataSetId,
                                    instrumentIds=instrumentIds)
validation_data = loadData(ds_validation)
# Test Data
dataSetId =  'trainingData3'
ds_test = QuantQuestDataSource(cachedFolderName=cachedFolderName,
                                    dataSetId=dataSetId,
                                    instrumentIds=instrumentIds)
out_of_sample_test_data = loadData(ds_test)

이 각각의 경우, 우리는 목표변수 Y를 더하고, 다음 5개의 기본값의 평균값으로 정의합니다.

def prepareData(data, period):
    data['Y(Target)'] = data['basis'].rolling(period).mean().shift(-period)
    if 'FairValue' in data.columns:
        del data['FairValue']
    data.dropna(inplace=True)
period = 5
prepareData(training_data, period)
prepareData(validation_data, period)
prepareData(out_of_sample_test_data, period)

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

데이터의 행동을 분석하고 예측 가능한 특징을 만듭니다.

이제 진짜 공학이 시작됩니다. ■ 특징 선택의 황금 법칙은 예측 능력이 모델보다 특징에서 주로 나온다는 것입니다. ■ 특징 선택이 모델 선택보다 훨씬 더 큰 성능에 영향을 미친다는 것을 알게 될 것입니다. ■ 특징 선택의 몇 가지 주의 사항:

  • 목표 변수와의 관계를 아직 탐구하지 않은 상태에서 하나의 특징 집합을 무작위로 선택하지 마십시오.

  • 목표 변수와 거의 또는 전혀 관련이 없는 경우 과도한 적합성이 발생할 수 있습니다.

  • 여러분이 선택한 특징들은 서로 매우 관련이 있을 수 있습니다. 이 경우 소수의 특징들이 목표에 대한 설명이 될 수도 있습니다.

  • 저는 종종 직관적인 특징을 만들어서 목표 변수가 그 특징과 어떤 관계를 가지고 있는지, 그리고 어떤 변수를 사용할지 결정하기 위해 그 사이의 관계를 봅니다.

  • 또한 최대 정보 계수 (MIC) 에 따라 후보 특성을 분류하고 주성분석 (PCA) 및 기타 방법을 시도할 수 있습니다.

특유의 전환/규범화:

ML 모델은 표준화에서 잘하는 경향이 있다. 그러나, 미래 데이터 범위가 알려지지 않기 때문에 시간 계열 데이터를 처리할 때 규범화는 까다롭다. 당신의 데이터는 표준화 범위를 초과하여 모델 오류를 초래할 수 있다. 그러나 당신은 여전히 어느 정도의 평형을 강요할 수 있다:

  • 확장: 표준차별 또는 4자리 범위로 구분되는 특징

  • 거주자: 현재 값에서 역사적 평균을 빼

  • 통일: 위의 ((x - mean) /stdev의 두 회귀 기간

  • 정규 집약: 거슬러 올라가는 시간 (x-min) /max-min에서 데이터를 -1에서 +1까지의 범위로 표준화하고 중심을 다시 정의합니다.

참고로, 우리는 역사적 연속 평균, 표준편차, 최대값 또는 최소값을 거꾸로 거슬러 올라가는 기간 이상으로 사용하기 때문에, 특성의 통일 표준화 값은 다른 시간에 다른 실제 값을 나타낼 것이다. 예를 들어, 특성의 현재 값이 5일 경우, 연속 30주기 평균은 4.5일 경우, 중간에 0.5로 변환된다. 그 후, 연속 30주기 평균값이 3이 되면, 값은 3.5이 된다. 이것은 모델 오류의 원인이 될 수 있다. 따라서 규격화는 까다롭고, 실제로 모델의 성능을 개선한 것이 무엇인지를 알아내야 한다. (만약이 있다면).

우리 문제에서 첫 번째 반복을 위해, 우리는 혼합 변수를 사용하여 많은 특성을 생성했습니다. 나중에 우리는 특성의 수를 줄일 수 있는지 확인하려고 노력할 것입니다.

def difference(dataDf, period):
    return dataDf.sub(dataDf.shift(period), fill_value=0)
def ewm(dataDf, halflife):
    return dataDf.ewm(halflife=halflife, ignore_na=False,
                      min_periods=0, adjust=True).mean()
def rsi(data, period):
    data_upside = data.sub(data.shift(1), fill_value=0)
    data_downside = data_upside.copy()
    data_downside[data_upside > 0] = 0
    data_upside[data_upside < 0] = 0
    avg_upside = data_upside.rolling(period).mean()
    avg_downside = - data_downside.rolling(period).mean()
    rsi = 100 - (100 * avg_downside / (avg_downside + avg_upside))
    rsi[avg_downside == 0] = 100
    rsi[(avg_downside == 0) & (avg_upside == 0)] = 0
return rsi
def create_features(data):
    basis_X = pd.DataFrame(index = data.index, columns =  [])
    
    basis_X['mom3'] = difference(data['basis'],4)
    basis_X['mom5'] = difference(data['basis'],6)
    basis_X['mom10'] = difference(data['basis'],11)
    
    basis_X['rsi15'] = rsi(data['basis'],15)
    basis_X['rsi10'] = rsi(data['basis'],10)
    
    basis_X['emabasis3'] = ewm(data['basis'],3)
    basis_X['emabasis5'] = ewm(data['basis'],5)
    basis_X['emabasis7'] = ewm(data['basis'],7)
    basis_X['emabasis10'] = ewm(data['basis'],10)
    basis_X['basis'] = data['basis']
    basis_X['vwapbasis'] = data['stockVWAP']-data['futureVWAP']
    
    basis_X['swidth'] = data['stockTopAskPrice'] -
                        data['stockTopBidPrice']
    basis_X['fwidth'] = data['futureTopAskPrice'] -
                        data['futureTopBidPrice']
    
    basis_X['btopask'] = data['stockTopAskPrice'] -
                         data['futureTopAskPrice']
    basis_X['btopbid'] = data['stockTopBidPrice'] -
                         data['futureTopBidPrice']

    basis_X['totalaskvol'] = data['stockTotalAskVol'] -
                             data['futureTotalAskVol']
    basis_X['totalbidvol'] = data['stockTotalBidVol'] -
                             data['futureTotalBidVol']
    
    basis_X['emabasisdi7'] = basis_X['emabasis7'] -
                             basis_X['emabasis5'] + 
                             basis_X['emabasis3']
    
    basis_X = basis_X.fillna(0)
    
    basis_y = data['Y(Target)']
    basis_y.dropna(inplace=True)
    
    print("Any null data in y: %s, X: %s"
            %(basis_y.isnull().values.any(), 
             basis_X.isnull().values.any()))
    print("Length y: %s, X: %s"
            %(len(basis_y.index), len(basis_X.index)))
    
    return basis_X, basis_y
basis_X_train, basis_y_train = create_features(training_data)
basis_X_test, basis_y_test = create_features(validation_data)

5단계: 모델 선택

선택된 문제에 따라 적절한 통계/ML 모델을 선택

모델의 선택은 문제의 구성 방식에 따라 달라진다. 당신은 모니터링 문제를 해결하고 있는가 (특성 매트릭스의 각 점 X가 목표 변수 Y에 매핑된다) 또는 무감독 학습 문제를 해결하고 있는가 (제주된 매핑이 없으며 모델은 알려지지 않은 패턴을 학습하려고 하는가)? 당신은 회귀 문제를 해결하고 있는가 (미래 시간에서의 실제 가격을 예측하고 있는가) 또는 분류 문제를 해결하고 있는가 (미래 시간에서의 가격 방향을 예측하고 있는가) (증대/감소) 이다.

img

감독 또는 무감독 학습

img

회귀 or 분류

어떤 일반적인 감시 학습 알고리즘이 당신을 시작할 수 있도록 도와줍니다.

  • 선형 회귀 (변수, 회귀)

  • Logistic 회귀 (변수, 분류)

  • K 근접자 (KNN) 알고리즘 (실례 기반, 회귀)

  • SVM,SVR (변수, 분류 및 회귀)

  • 의사결정 나무

  • 결정의 숲

나는 선형 또는 논리적 회귀와 같은 간단한 모델에서 시작하여 필요에 따라 더 복잡한 모델을 구축하는 것을 제안한다. 또한 모델 뒤에 있는 수학을 읽고 맹목적으로 블랙 박스처럼 사용하지 않는 것을 추천한다.

6단계: 훈련, 검증 및 최적화 (단계 4-6을 반복)

img

훈련 및 검증 데이터 세트를 사용하여 모델을 훈련하고 최적화하십시오.

이제, 당신은 최종 모델 구축을 위해 준비되어 있습니다. 이 단계에서, 당신은 정말로 모델과 모델 파라미터를 반복합니다. 훈련 데이터에서 모델을 훈련시키고, 검증 데이터에서 성능을 측정하고, 다시 돌아와서 최적화하고, 재 훈련하고, 평가합니다. 모델의 성능에 만족하지 않으면 다른 모델을 시도하십시오. 당신이 마침내 만족하는 모델을 가질 때까지 여러 번이 반복됩니다.

이 모델은 여러분이 좋아하는 모델을 가지고 있을 때만 다음 단계로 이동합니다.

이 문제를 설명하기 위해, 간단한 선형 회귀로 시작해 봅시다.

from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score
def linear_regression(basis_X_train, basis_y_train,
                      basis_X_test,basis_y_test):
    
    regr = linear_model.LinearRegression()
    # Train the model using the training sets
    regr.fit(basis_X_train, basis_y_train)
    # Make predictions using the testing set
    basis_y_pred = regr.predict(basis_X_test)
    # The coefficients
    print('Coefficients: \n', regr.coef_)
    
    # The mean squared error
    print("Mean squared error: %.2f"
          % mean_squared_error(basis_y_test, basis_y_pred))
    
    # Explained variance score: 1 is perfect prediction
    print('Variance score: %.2f' % r2_score(basis_y_test,
                                            basis_y_pred))
    # Plot outputs
    plt.scatter(basis_y_pred, basis_y_test,  color='black')
    plt.plot(basis_y_test, basis_y_test, color='blue', linewidth=3)
    plt.xlabel('Y(actual)')
    plt.ylabel('Y(Predicted)')
    plt.show()
    
    return regr, basis_y_pred
_, basis_y_pred = linear_regression(basis_X_train, basis_y_train, 
                                    basis_X_test,basis_y_test)

img

통일되지 않은 선형 회귀

('Coefficients: \n', array([ -1.0929e+08, 4.1621e+07, 1.4755e+07, 5.6988e+06, -5.656e+01, -6.18e-04, -8.2541e-05,4.3606e-02, -3.0647e-02, 1.8826e+07, 8.3561e-02, 3.723e-03, -6.2637e-03, 1.8826e+07, 1.8826e+07, 6.4277e-02, 5.7254e-02, 3.3435e-03, 1.6376e-02, -7.3588e-03, -8.1531e-04, -3.9095e-02, 3.1418e-02, 3.3321e-03, -1.3262e-06, -1.3433e+07, 3.5821e+07, 2.6764e+07, -8.0394e+06, -2.2388e+06, -1.7096e+07]))
Mean squared error: 0.02
Variance score: 0.96

모델 계수를 보세요. 우리는 그것들을 비교하거나 어떤 것이 중요하다고 말할 수 없습니다. 왜냐하면 그것들은 모두 다른 규모에 속하기 때문입니다.

def normalize(basis_X, basis_y, period):
    basis_X_norm = (basis_X - basis_X.rolling(period).mean())/
                    basis_X.rolling(period).std()
    basis_X_norm.dropna(inplace=True)
    basis_y_norm = (basis_y - 
                    basis_X['basis'].rolling(period).mean())/
                    basis_X['basis'].rolling(period).std()
    basis_y_norm = basis_y_norm[basis_X_norm.index]
    
    return basis_X_norm, basis_y_norm
norm_period = 375
basis_X_norm_test, basis_y_norm_test = normalize(basis_X_test,basis_y_test, norm_period)
basis_X_norm_train, basis_y_norm_train = normalize(basis_X_train, basis_y_train, norm_period)
regr_norm, basis_y_pred = linear_regression(basis_X_norm_train, basis_y_norm_train, basis_X_norm_test, basis_y_norm_test)
basis_y_pred = basis_y_pred * basis_X_test['basis'].rolling(period).std()[basis_y_norm_test.index] + basis_X_test['basis'].rolling(period).mean()[basis_y_norm_test.index]

img

통합의 선형 회귀

Mean squared error: 0.05
Variance score: 0.90

이 모델은 이전 모델을 개선하지는 않았지만 더 나쁘지 않습니다. 이제 우리는 실제로 계수를 비교하여 어떤 계수가 실제로 중요하는지 볼 수 있습니다.

이 식을 더하면

for i in range(len(basis_X_train.columns)):
    print('%.4f, %s'%(regr_norm.coef_[i], basis_X_train.columns[i]))

그 결과:

19.8727, emabasis4
-9.2015, emabasis5
8.8981, emabasis7
-5.5692, emabasis10
-0.0036, rsi15
-0.0146, rsi10
0.0196, mom10
-0.0035, mom5
-7.9138, basis
0.0062, swidth
0.0117, fwidth
2.0883, btopask
2.0311, btopbid
0.0974, bavgask
0.0611, bavgbid
0.0007, topaskvolratio
0.0113, topbidvolratio
-0.0220, totalaskvolratio
0.0231, totalbidvolratio

우리는 분명히 어떤 특성이 다른 특성에 비해 더 높은 계수를 가지고 있으며 더 강력한 예측력을 가질 수 있음을 볼 수 있습니다.

다른 특징들 사이의 연관성을 살펴보자.

import seaborn

c = basis_X_train.corr()
plt.figure(figsize=(10,10))
seaborn.heatmap(c, cmap='RdYlGn_r', mask = (np.abs(c) <= 0.8))
plt.show()

img

특징들 사이의 연관성

어두운 빨간색 영역은 매우 관련된 변수를 나타냅니다. 다시 몇 가지 특징을 만들고/변경하여 우리의 모델을 개선하려고 노력하겠습니다.

例如,我可以轻松地丢弃像emabasisdi7这样的特征,这些特征只是其他特征的线性组合.

def create_features_again(data):
    basis_X = pd.DataFrame(index = data.index, columns =  [])
    basis_X['mom10'] = difference(data['basis'],11)
    basis_X['emabasis2'] = ewm(data['basis'],2)
    basis_X['emabasis5'] = ewm(data['basis'],5)
    basis_X['emabasis10'] = ewm(data['basis'],10)
    basis_X['basis'] = data['basis']
    basis_X['totalaskvolratio'] = (data['stockTotalAskVol']
                                 - data['futureTotalAskVol'])/
                                   100000
    basis_X['totalbidvolratio'] = (data['stockTotalBidVol']
                                 - data['futureTotalBidVol'])/
                                   100000
    basis_X = basis_X.fillna(0)
    
    basis_y = data['Y(Target)']
    basis_y.dropna(inplace=True)
    return basis_X, basis_y
basis_X_test, basis_y_test = create_features_again(validation_data)
basis_X_train, basis_y_train = create_features_again(training_data)
_, basis_y_pred = linear_regression(basis_X_train, basis_y_train, basis_X_test,basis_y_test)
basis_y_regr = basis_y_pred.copy()

img

('Coefficients: ', array([ 0.03246139,
0.49780982, -0.22367172,  0.20275786,  0.50758852,
-0.21510795, 0.17153884]))
Mean squared error: 0.02
Variance score: 0.96

우리의 모델의 성능은 변하지 않습니다. 우리는 단지 우리의 목표 변수를 설명하는 몇 가지 특성을 필요로 합니다.

我们还可以尝试更复杂的模型,看看模型的变化是否可以提高性能.

  • K 이웃 (KNN) 알고리즘
from sklearn import neighbors
n_neighbors = 5
model = neighbors.KNeighborsRegressor(n_neighbors, weights='distance')
model.fit(basis_X_train, basis_y_train)
basis_y_pred = model.predict(basis_X_test)
basis_y_knn = basis_y_pred.copy()

img

  • SVR
from sklearn.svm import SVR
model = SVR(kernel='rbf', C=1e3, gamma=0.1)
model.fit(basis_X_train, basis_y_train)
basis_y_pred = model.predict(basis_X_test)
basis_y_svr = basis_y_pred.copy()

img

  • 의사결정 나무
model=ensemble.ExtraTreesRegressor()
model.fit(basis_X_train, basis_y_train)
basis_y_pred = model.predict(basis_X_test)
basis_y_trees = basis_y_pred.copy()

img

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

실제 샘플 데이터의 성능을 검사합니다.

img

테스트 데이터 세트에 대한 재검토 성능 (예: 아직 만지지 않은)

이것은 중요한 순간이다. 우리는 테스트 데이터의 마지막 단계에서 우리의 최종 최적화 모델을 실행하기 시작했습니다. 우리는 처음부터 그것을 방치하고 지금까지 접촉하지 않은 데이터에 도달했습니다.

이것은 당신이 실시간 거래를 시작할 때 새롭고 보이지 않는 데이터에 대해 당신의 모델이 어떻게 실행될지에 대한 현실적인 기대를 제공합니다. 따라서 훈련 또는 검증 모델에 사용되지 않는 깨끗한 데이터 세트를 가지고 있는지 확인하는 것이 중요합니다.

테스트 데이터의 재검토 결과를 좋아하지 않으면 모델을 버리고 다시 시작하십시오. 다시 돌아와서 모델을 최적화하지 마십시오. 이것은 과잉 적합성을 초래할 것입니다! 또한 새로운 테스트 데이터 세트를 만드는 것이 좋습니다. 이 데이터 세트가 이제 오염되었기 때문에; 모델을 폐기 할 때 우리는 이미 관련 데이터 세트의 내용을 암시적으로 알고 있습니다.)

여기 우리는 Auquan의 도구 상자를 사용합니다.

import backtester
from backtester.features.feature import Feature
from backtester.trading_system import TradingSystem
from backtester.sample_scripts.fair_value_params import FairValueTradingParams
class Problem1Solver():
def getTrainingDataSet(self):
        return "trainingData1"
def getSymbolsToTrade(self):
        return ['MQK']
def getCustomFeatures(self):
        return {'my_custom_feature': MyCustomFeature}
def getFeatureConfigDicts(self):
                            
        expma5dic = {'featureKey': 'emabasis5',
                 'featureId': 'exponential_moving_average',
                 'params': {'period': 5,
                              'featureName': 'basis'}}
        expma10dic = {'featureKey': 'emabasis10',
                 'featureId': 'exponential_moving_average',
                 'params': {'period': 10,
                              'featureName': 'basis'}}                     
        expma2dic = {'featureKey': 'emabasis3',
                 'featureId': 'exponential_moving_average',
                 'params': {'period': 3,
                              'featureName': 'basis'}}
        mom10dic = {'featureKey': 'mom10',
                 'featureId': 'difference',
                 'params': {'period': 11,
                              'featureName': 'basis'}}
        
        return [expma5dic,expma2dic,expma10dic,mom10dic]    
    
    def getFairValue(self, updateNum, time, instrumentManager):
        # holder for all the instrument features
        lbInstF = instrumentManager.getlookbackInstrumentFeatures()
        mom10 = lbInstF.getFeatureDf('mom10').iloc[-1]
        emabasis2 = lbInstF.getFeatureDf('emabasis2').iloc[-1]
        emabasis5 = lbInstF.getFeatureDf('emabasis5').iloc[-1]
        emabasis10 = lbInstF.getFeatureDf('emabasis10').iloc[-1] 
        basis = lbInstF.getFeatureDf('basis').iloc[-1]
        totalaskvol = lbInstF.getFeatureDf('stockTotalAskVol').iloc[-1] - lbInstF.getFeatureDf('futureTotalAskVol').iloc[-1]
        totalbidvol = lbInstF.getFeatureDf('stockTotalBidVol').iloc[-1] - lbInstF.getFeatureDf('futureTotalBidVol').iloc[-1]
        
        coeff = [ 0.03249183, 0.49675487, -0.22289464, 0.2025182, 0.5080227, -0.21557005, 0.17128488]
        newdf['MQK'] = coeff[0] * mom10['MQK'] + coeff[1] * emabasis2['MQK'] +\
                      coeff[2] * emabasis5['MQK'] + coeff[3] * emabasis10['MQK'] +\
                      coeff[4] * basis['MQK'] + coeff[5] * totalaskvol['MQK']+\
                      coeff[6] * totalbidvol['MQK']
                    
        newdf.fillna(emabasis5,inplace=True)
        return newdf
problem1Solver = Problem1Solver()
tsParams = FairValueTradingParams(problem1Solver)
tradingSystem = TradingSystem(tsParams)
tradingSystem.startTrading(onlyAnalyze=False, 
                           shouldPlot=True,
                           makeInstrumentCsvs=False)

img

재검토 결과, Pnl는 달러로 계산됩니다 (Pnl는 거래 비용 및 기타 비용을 포함하지 않습니다)

8단계: 모델을 개선하는 다른 방법

스크롤 검증, 집단 학습, 배깅 및 부스팅

더 많은 데이터를 수집하거나 더 나은 특징을 만들거나 더 많은 모델을 시도하는 것 외에도 개선하기 위해 시도 할 수있는 몇 가지 사항이 있습니다.

1. 롤러 검증

img

롤러 검증

시장 조건은 거의 변하지 않습니다. 만약 당신이 1년 데이터를 가지고 있고, 1월부터 8월까지의 데이터를 사용하여 훈련을 하고, 9월부터 12월까지의 데이터를 사용하여 모델을 테스트한다면, 당신은 매우 구체적인 시장 조건의 집합에 대해 훈련하게 될 수도 있습니다. 아마도 상반기에는 시장 변동이 없었고, 어떤 극단적인 소식이 시장이 9월에 크게 상승하게 만들었을 수도 있습니다. 당신의 모델은 그 패턴을 배우지 못하고, 쓰레기 예측 결과를 줄 것입니다.

1월부터 2월까지의 훈련, 3월의 훈련, 4월부터 5월까지의 재교육, 6월의 훈련 등을 시도하는 것이 더 좋을 수도 있습니다.

2. 집단 학습

img

집단 학습

어떤 모델은 어떤 시나리오를 예측하는 데 잘 작동할 수 있지만 다른 시나리오를 예측하는 데 또는 어떤 경우에 모델은 극도로 과격할 수 있다. 오류와 과격을 줄이는 방법 중 하나는 다른 모델의 집합을 사용하는 것이다. 당신의 예측은 많은 모델이 예측하는 평균값이 될 것이고, 다른 모델의 오류는 완화되거나 감소될 수 있다. 일반적인 집합 방법 중 일부는 배깅과 부스팅이다.

img

포지션

img

부흥

이 방법은 간단하게 설명하기 위해 넘어가겠습니다. 하지만 더 많은 관련 정보를 온라인에서 찾을 수 있습니다.

이 문제를 풀기 위해 집합적인 방법을 시도해 봅시다.

basis_y_pred_ensemble = (basis_y_trees + basis_y_svr +
                         basis_y_knn + basis_y_regr)/4

img

Mean squared error: 0.02
Variance score: 0.95

우리는 지금까지 많은 지식과 정보를 수집했습니다.

  • 당신의 문제를 해결하세요.

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

  • 데이터를 훈련, 검증 및 테스트 세트로 분리합니다.

  • 특징을 만들고 행동 분석

  • 행동에 따라 적절한 훈련 모델을 선택합니다.

  • 훈련 데이터를 사용하여 모델을 훈련하고 예측합니다.

  • 확인집의 성능을 검사하고 다시 최적화합니다

  • 테스트 세트의 최종 성능을 확인합니다.

하지만 아직 끝나지 않았는데, 이제 믿을 수 있는 예측 모델만 있습니다.

  • 예측 모델에 기반한 신호를 개발하여 거래 방향을 식별

  • 공략을 식별하는 구체적인 전략을 개발

  • 포지션과 가격을 식별하는 실행 시스템

이 모든 것은 발명가의 정량화 플랫폼으로 사용될 것입니다.FMZ.COM), 발명자 양자 플랫폼에서, 고도로 포괄적이고 완벽한 API 인터페이스, 그리고 당신이 개별적으로 연결하고 다른 거래소를 추가하는 API 인터페이스를 사용하지 않고 전 세계적으로 호출 할 수 있는 아래와 거래 기능을 가지고, 발명자 양자 플랫폼의 전략 광장, 많은成熟하고 완벽한 대안 전략이 있습니다.https://www.fmz.com/square

거래 비용에 대한 중요한 설명:你的模型会告诉你所选资产何时是做多或做空。然而,它没有考虑费用/交易成本/可用交易量/止损等。交易成本通常会使有利可图的交易成为亏损。例如,预期价格上涨0.05美元的资产是买入,但如果你必须支付0.10美元进行此交易,你将最终获得净亏损$0.05。在你考虑经纪人佣金,交换费和点差后,我们上面看起来很棒的盈利图实际上是这样的:

img

거래 수수료와 지점 미만 후의 재검토 결과, Pnl는 달러입니다.

거래 수수료와 차이는 우리 Pnl의 90% 이상을 차지합니다.

그리고 마지막으로, 몇 가지 일반적인 함정을 살펴보겠습니다.

어떻게 해야 하고 어떻게 하지 말아야 하는지

  • 모든 힘으로 과도한 적응을 피하세요!

  • 각 데이터 포인트 후에 재훈련을 하지 마십시오: 이것은 기계 학습 개발에서 사람들이 저지르는 일반적인 실수입니다. 여러분의 모델이 각 데이터 포인트 후에 재훈련을 받아야 한다면, 그것은 매우 좋은 모델이 아닐 수 있습니다. 즉, 정기적으로 재훈련이 필요하고 합리적인 빈도로만 훈련해야 합니다. (예를 들어, 하루 내 예측을 한다면, 매주 끝에서 재훈련을 해야 합니다.)

  • 오차, 특히 전향적 오차를 피한다: 이것은 모델이 작동하지 않는 또 다른 이유이며, 당신은 미래에 대한 정보를 사용하지 않았다는 것을 확인한다. 대부분의 경우, 이것은 모델의 특징으로 목표 변수 Y를 사용하지 않는 것을 의미합니다. 레거스트 테스트 중에 사용할 수 있지만 실제 모델 실행 시에는 사용할 수 없을 것입니다. 이것은 당신의 모델을 사용할 수 없게 할 것입니다.

  • 데이터 채굴 편차에 주의: 우리는 우리의 데이터에 대한 모형의 일련의 모형을 시도하여 적합성을 확인하기 위해 노력하고 있기 때문에 특별한 이유가 없다면, 무작위 모형과 실제로 일어날 수 있는 모형을 분리하기 위해 엄격한 테스트를 실행하는 것을 확인하십시오. 예를 들어, 선형 회귀는 상승 추세 모형을 잘 설명하고 있으며, 단 하나의 작은 부분이 더 큰 무작위 이동이 될 가능성이 있습니다!

너무 잘 어울리지 않도록

이 모든 것은 매우 중요하며, 다시 한 번 언급할 필요가 있다고 생각합니다.

  • 너무 잘 어울리는 것은 거래 전략에서 가장 위험한 함정입니다.

  • 복잡한 알고리즘은 재검토에서 매우 잘 수행할 수 있지만, 눈에 보이지 않는 새로운 데이터에서 실패할 수 있습니다. 이 알고리즘은 실제로 데이터의 어떤 경향을 밝혀내지 않으며, 실제로 예측할 수 없습니다. 그것은 눈에 보이는 데이터에 매우 적합합니다.

  • 여러분의 시스템을 가능한 한 단순하게 유지하세요. 데이터를 해석하기 위해 많은 복잡한 기능이 필요하다는 것을 발견한다면, 여러분은 과도하게 적합할 수 있습니다.

  • 사용 가능한 데이터를 훈련 데이터와 테스트 데이터로 나누고, 모델을 사용하여 실시간 거래를 하기 전에 항상 실제 샘플 데이터의 성능을 검증하십시오.


관련

더 많은

한쪽 길감사합니다.

콩콩009훌륭한 기사, 아이디어, 그리고 초보자용 요약

라라데마시아!