Giao dịch ghép nối là một ví dụ điển hình về việc xây dựng chiến lược giao dịch dựa trên phân tích toán học. Trong bài viết này, chúng tôi sẽ trình bày cách sử dụng dữ liệu để tạo và tự động hóa các chiến lược giao dịch ghép nối.
假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.
Khi có sự khác biệt giá tạm thời, giao dịch sẽ bán các đầu tư hiệu suất cao (đối với các đầu tư tăng) và mua các đầu tư hiệu suất thấp (đối với các đầu tư giảm). Bạn có thể chắc chắn rằng sự chênh lệch lợi nhuận giữa hai đầu tư cuối cùng sẽ xảy ra thông qua sự suy giảm của các đầu tư hiệu suất cao hoặc sự phục hồi của các đầu tư hiệu suất thấp hoặc cả hai.
Do đó, giao dịch ghép đôi là một chiến lược giao dịch trung lập thị trường, cho phép các nhà giao dịch lợi nhuận từ hầu hết các điều kiện thị trường: xu hướng tăng, xu hướng giảm hoặc thanh toán ngang.
Trước tiên, để công việc diễn ra suôn sẻ, chúng tôi cần xây dựng môi trường nghiên cứu của mình, trong bài viết này chúng tôi sử dụng nền tảng định lượng của nhà phát minh.FMZ.COMCác nhà nghiên cứu đã xây dựng một môi trường nghiên cứu, chủ yếu là để sử dụng nền tảng này một giao diện API dễ dàng và nhanh chóng và gói một hệ thống Docker hoàn hảo.
Trong cái tên chính thức của nền tảng định lượng của nhà phát minh, hệ thống Docker này được gọi là hệ thống quản lý.
Để biết cách triển khai người quản lý và robot, hãy tham khảo bài viết trước của tôi:https://www.fmz.com/bbs-topic/4140
Người đọc muốn mua một nhà quản lý triển khai máy chủ điện toán đám mây của riêng họ có thể tham khảo bài viết này:https://www.fmz.com/bbs-topic/2848
Sau khi triển khai thành công các dịch vụ và hệ thống quản trị đám mây tốt, tiếp theo chúng tôi sẽ cài đặt Python lớn nhất hiện nay: Anaconda.
Để thực hiện tất cả các môi trường ứng dụng liên quan cần thiết cho bài viết này (tài liệu phụ thuộc, quản lý phiên bản, v.v.), cách đơn giản nhất là sử dụng Anaconda. Nó là một hệ sinh thái khoa học dữ liệu Python được đóng gói và quản lý thư viện phụ thuộc.
Để biết cách cài đặt Anaconda, hãy xem hướng dẫn chính thức của Anaconda:https://www.anaconda.com/distribution/
本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.
Các công việc cơ bản trên cũng có thể tham khảo bài viết trước của tôi về cách thiết lập môi trường Anaconda và hai thư viện numpy và pandas.https://www.fmz.com/digest-topic/4169
Tiếp theo, chúng ta hãy sử dụng mã để thực hiện một "các tiêu chuẩn đầu tư hai giả định".
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
Chúng ta sẽ sử dụng matplotlib, một thư viện biểu đồ rất nổi tiếng trong Python.
Hãy tạo ra một X của một chỉ số đầu tư giả định và mô phỏng lợi nhuận hàng ngày của nó bằng cách phân bố bình thường. Sau đó, chúng ta thực hiện tích lũy để có được giá trị X hàng ngày.
# 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()
X của một chỉ số đầu tư, mô phỏng bản đồ lợi nhuận hàng ngày của nó bằng cách phân bố bình thường
Bây giờ chúng ta tạo ra Y và X có mối liên hệ mạnh mẽ với nhau, vì vậy giá của Y nên rất giống với sự thay đổi của X. Chúng ta mô hình hóa điều này bằng cách lấy X, di chuyển nó lên và thêm một số tiếng ồn ngẫu nhiên được lấy từ phân bố bình thường.
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()
X và Y của các chỉ số đầu tư hợp tác
协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:
Y =
Trong đó,
Đối với các cặp giao dịch giữa hai chuỗi thời gian, tỷ lệ này chắc chắn sẽ hội tụ với các giá trị dự kiến theo thời gian, nghĩa là chúng nên hợp nhất. Các chuỗi thời gian mà chúng ta xây dựng ở trên là hợp nhất. Bây giờ chúng ta sẽ vẽ tỷ lệ giữa hai thứ để chúng ta có thể thấy vẻ ngoài của nó.
(Y/X).plot(figsize=(15,7))
plt.axhline((Y/X).mean(), color='red', linestyle='--')
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()
Tỷ lệ và giá trung bình giữa hai chỉ số đầu tư hợp nhất
Một cách dễ dàng để kiểm tra là sử dụng statsmodels.tsa.stattools. Chúng ta sẽ thấy một p-value rất thấp vì chúng ta đã tạo ra hai chuỗi dữ liệu có thể kết hợp với nhau nhất.
# 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
Kết quả là: 1.81864477307e-17
Có liên quan và hợp nhất nhưng không giống nhau. Hãy xem ví dụ về các chuỗi dữ liệu có liên quan nhưng không hợp nhất, và ngược lại. Trước tiên, hãy kiểm tra mối liên quan của chuỗi mà chúng ta vừa tạo.
X.corr(Y)
Kết quả là: 0.951.
Một ví dụ đơn giản là hai chuỗi dữ liệu sai lệch. Một ví dụ đơn giản là hai chuỗi dữ liệu sai lệch.
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)
Hai series liên quan (không hợp nhất)
Các hệ số liên quan: 0.998 Giá trị p của kiểm tra hợp nhất: 0.258
Một ví dụ đơn giản về sự hợp nhất không có liên quan là chuỗi phân bố chính xác và sóng vuông.
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)
Liên quan: 0.007546 Phân tích kiểm tra p: 0.0
Sự tương quan rất thấp, nhưng p-value cho thấy sự hợp tác hoàn hảo!
Bởi vì hai chuỗi thời gian hợp nhất (ví dụ như X và Y ở trên) đối diện và lệch lẫn nhau, đôi khi có những trường hợp có giới hạn cao và thấp. Chúng ta giao dịch bằng cách mua một chứng chỉ đầu tư và bán một chứng chỉ đầu tư khác. Vì vậy, nếu hai chứng chỉ đầu tư giảm hoặc tăng cùng một lúc, chúng ta không kiếm được tiền hoặc mất tiền, nghĩa là chúng ta là trung lập trong thị trường.
Trở lại trên Y = x + e trong X và y, để tỷ lệ (Y / X) di chuyển xung quanh giá trị trung bình của nó, chúng ta kiếm tiền bằng tỷ lệ quay về giá trị trung bình. Để làm điều này, chúng ta sẽ chú ý đến trường hợp khi X và Y cách xa nhau, tức là ngưỡng quá cao hoặc quá thấp:
Làm nhiều tỷ lệ: Đây là khi tỷ lệ tăng rất nhỏ và chúng ta mong đợi nó sẽ lớn hơn. Trong ví dụ trên, chúng ta mở lệnh bằng cách làm nhiều Y và làm trống X.
Tỷ lệ làm trống: Đây là khi tỷ lệ tăng rất lớn và chúng tôi mong đợi nó sẽ thay đổi theo giờ. Trong ví dụ trên, chúng tôi mở lệnh bằng cách làm trống Y và làm nhiều X.
Lưu ý rằng, chúng ta luôn có một vị trí được bảo hiểm: nếu giá trị mua mất giá trị của chỉ số giao dịch, vị trí trống sẽ kiếm tiền, và ngược lại, do đó chúng ta miễn dịch với xu hướng thị trường tổng thể.
Khi các chỉ số X và Y di chuyển so với nhau, chúng ta sẽ kiếm tiền hoặc mất tiền.
Cách tốt nhất để làm điều này là bắt đầu từ các chỉ số giao dịch mà bạn nghi ngờ có thể là hợp nhất và thực hiện kiểm tra thống kê.Sự sai lệch đa so sánhNhững nạn nhân của cuộc tấn công.
Sự sai lệch đa so sánhlà một trường hợp tăng cơ hội sai tạo p quan trọng khi chạy nhiều bài kiểm tra vì chúng ta cần chạy nhiều bài kiểm tra. Nếu thử nghiệm 100 lần dữ liệu ngẫu nhiên, chúng ta sẽ thấy 5 p dưới 0.05. Nếu bạn so sánh n giao dịch để thực hiện tổng hợp, bạn sẽ thực hiện n n − 1 / 2 so sánh và bạn sẽ thấy nhiều giá trị p không chính xác, điều này sẽ tăng khi số lượng mẫu kiểm tra của bạn tăng. Để tránh tình huống này, hãy chọn một số ít các cặp giao dịch mà bạn có lý do để xác định có thể là hợp tác và thử nghiệm chúng một cách riêng biệt.Sự sai lệch đa so sánh。
Vì vậy, hãy thử tìm một số chỉ số giao dịch cho thấy sự hợp tác. Hãy lấy ví dụ một giỏ các cổ phiếu công nghệ lớn của Mỹ trong chỉ số S&P 500, những chỉ số này hoạt động trong các thị trường phân khúc tương tự và có giá hợp tác. Chúng tôi quét danh sách các chỉ số giao dịch và kiểm tra sự hợp tác giữa tất cả các cặp.
Trả về tất cả các cặp của ma trận kiểm tra phân số, ma trận giá trị p và giá trị p nhỏ hơn 0.05.Phương pháp này có thể gây ra nhiều sai lệch so sánh, vì vậy họ thực sự cần phải kiểm tra lại.Trong bài viết này, chúng tôi chọn bỏ qua điều này trong ví dụ để dễ dàng giải thích.
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
Lưu ý: Chúng tôi đã bao gồm trong dữ liệu các chỉ số thị trường (SPX) - thị trường thúc đẩy sự lưu thông của nhiều chỉ số giao dịch, thường bạn có thể tìm thấy hai chỉ số giao dịch có vẻ hợp tác; nhưng thực tế chúng không hợp tác với nhau mà hợp tác với thị trường. Điều này được gọi là biến hỗn hợp.
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)
Bây giờ chúng ta hãy thử sử dụng phương pháp của chúng tôi để tìm các giao dịch phối hợp.
# 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')]
Có vẻ như ADBE và MSFT đều hợp tác với nhau. Hãy xem giá để chắc chắn nó thực sự có ý nghĩa.
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()
Biểu đồ tỷ lệ giá giữa MSFT và ADBE 2008 - 2017
Tỷ lệ này thực sự trông giống như một mức trung bình ổn định. Tỷ lệ tuyệt đối không hữu ích về mặt thống kê.
Điểm số Z (giá trị) = (giá trị
Trong thực tế, chúng ta thường cố gắng mở rộng dữ liệu một chút, nhưng chỉ với điều kiện rằng dữ liệu đó là phân bố bình thường. Tuy nhiên, nhiều dữ liệu tài chính không phải là phân bố bình thường, vì vậy chúng ta phải rất cẩn thận để không chỉ đơn giản giả định sự bình thường hoặc bất kỳ phân bố cụ thể nào khi tạo ra dữ liệu thống kê. Sự phân bố thực của tỷ lệ có thể có hiệu ứng mỡ, và những dữ liệu có xu hướng cực đoan sẽ làm cho mô hình của chúng ta trở nên lộn xộn và dẫn đến tổn thất lớn.
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()
Tỷ lệ giá Z giữa MSFT và ADBE từ 2008 đến 2017
Bây giờ có thể dễ dàng hơn để quan sát tỷ lệ di chuyển gần mức trung bình, nhưng đôi khi có thể xảy ra sự khác biệt lớn với mức trung bình, chúng ta có thể tận dụng điều này.
Bây giờ chúng ta đã thảo luận về các nguyên tắc cơ bản của chiến lược giao dịch phối hợp và xác định các chỉ số giao dịch hợp nhất dựa trên giá lịch sử, hãy thử phát triển một tín hiệu giao dịch. Trước tiên, hãy xem lại các bước để phát triển tín hiệu giao dịch bằng công nghệ dữ liệu:
Thu thập dữ liệu đáng tin cậy và làm sạch dữ liệu
Tạo chức năng từ dữ liệu để nhận ra tín hiệu giao dịch / logic
Các tính năng có thể là các giá trị động trung bình hoặc dữ liệu giá, tỷ lệ liên quan hoặc các tín hiệu phức tạp hơn - kết hợp chúng để tạo ra các tính năng mới
Sử dụng các chức năng này để tạo ra các tín hiệu giao dịch, tức là những tín hiệu mua, bán hoặc nhìn vào không
May mắn thay, chúng tôi có một nền tảng định lượng cho các nhà phát minh.fmz.comNhững gì chúng tôi đã làm cho 4 khía cạnh trên là một phúc âm to lớn cho các nhà phát triển chiến lược, chúng tôi có thể sử dụng năng lượng và thời gian của mình để thiết kế logic chiến lược và mở rộng chức năng.
Trong nền tảng định lượng của nhà phát minh, có các giao diện của các sàn giao dịch chính thống được đóng gói sẵn, tất cả những gì chúng ta cần làm là gọi các API này, và phần còn lại là thực hiện logic dưới cùng, và đã có một nhóm chuyên gia tinh chỉnh nó.
Trong bài viết này, chúng tôi sẽ trình bày các logic dưới cùng như một việc giải quyết lợn, nhưng trong các hoạt động thực tế, người đọc có thể trực tiếp gọi các giao diện API được định lượng của nhà phát minh để thực hiện bốn khía cạnh trên.
Chúng ta hãy bắt đầu:
Ở đây, chúng ta cố gắng tạo ra một tín hiệu cho chúng ta biết tỷ lệ mua hay bán vào thời điểm tiếp theo, đó là biến số dự đoán của chúng ta Y:
Y = Tỷ lệ là mua (1) hoặc bán (-1)
Y ((t) = Sign ((Ratio ((t+1)
Lưu ý rằng chúng ta không cần dự đoán giá của chỉ số giao dịch thực, thậm chí không cần dự đoán giá trị thực của tỷ lệ (mặc dù chúng ta có thể), chỉ cần dự đoán hướng của tỷ lệ tiếp theo
Các nhà phát minh định lượng là bạn của bạn! Bạn chỉ cần chỉ định các chỉ số giao dịch và các nguồn dữ liệu để sử dụng, nó sẽ trích xuất dữ liệu cần thiết và xóa nó để phân chia cổ tức và chỉ số giao dịch. Vì vậy, chúng ta đã có dữ liệu sạch sẽ ở đây.
Chúng tôi đã sử dụng dữ liệu sau đây từ tài chính của Yahoo cho các ngày giao dịch trong 10 năm qua (khoảng 2500 điểm dữ liệu): giá mở, giá đóng, giá cao nhất, giá thấp nhất và khối lượng giao dịch.
Đừng quên bước rất quan trọng này để kiểm tra độ chính xác mô hình. Chúng tôi đang sử dụng dữ liệu sau đây để đào tạo / xác minh / phân tích thử nghiệm
Đào tạo 7 năm ~ 70%
Thử nghiệm ~ 3 năm 30%
ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]
Trong trường hợp lý tưởng, chúng ta cũng nên tạo bộ xác thực, nhưng chúng ta sẽ không làm điều đó trong thời gian tới.
Chúng ta muốn dự đoán hướng thay đổi tỷ lệ. Chúng ta đã thấy rằng hai dấu hiệu giao dịch của chúng ta là tích hợp, vì vậy tỷ lệ này thường di chuyển và quay trở lại mức trung bình. Dường như đặc điểm của chúng ta nên là một số thước đo của mức trung bình, sự khác biệt giữa giá trị hiện tại và mức trung bình có thể tạo ra tín hiệu giao dịch của chúng ta.
Chúng tôi sử dụng các tính năng sau:
Tỷ lệ trung bình di chuyển 60 ngày: đo lường trung bình di chuyển
Tỷ lệ trung bình di chuyển 5 ngày: đo giá trị hiện tại của trung bình
60 ngày sai tiêu chuẩn
Điểm số 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()
Tỷ lệ giá của 60d và 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()
Tỷ lệ giá 60-5 điểm Z
Điểm số Z của đường trung bình lăn thực sự mang lại tính năng quay ngược đường trung bình của tỷ lệ!
Hãy bắt đầu với một mô hình rất đơn giản. Hãy xem biểu đồ điểm số z và chúng ta có thể thấy rằng nó sẽ quay trở lại bất cứ khi nào điểm số z quá cao hoặc quá thấp. Hãy sử dụng + 1 / -1 như là ngưỡng của chúng ta để xác định quá cao và quá thấp, sau đó chúng ta có thể sử dụng mô hình sau đây để tạo tín hiệu giao dịch:
Khi z thấp hơn -1, tỷ lệ là buy (−1) bởi vì chúng ta mong đợi z trở lại 0, tỷ lệ tăng
Khi z lớn hơn 1, tỷ lệ là bán (−1) vì chúng ta mong đợi z quay trở lại 0, tỷ lệ giảm
Và cuối cùng, hãy xem mô hình của chúng tôi có ảnh hưởng thực tế đến dữ liệu thực tế?
# 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()
Nhập và bán tín hiệu tỷ lệ giá
Dấu hiệu này có vẻ hợp lý, chúng ta dường như bán tỷ lệ (điểm đỏ) khi nó cao hoặc tăng và mua lại khi nó thấp (điểm xanh) và giảm. Điều này có ý nghĩa gì đối với chỉ số giao dịch thực tế mà chúng ta giao dịch?
# 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()
Các tín hiệu mua và bán cổ phiếu MSFT và ADBE
Hãy chú ý cách chúng ta đôi khi kiếm tiền bằng chân ngắn, đôi khi kiếm tiền bằng chân dài, và đôi khi cả hai.
Chúng tôi rất hài lòng với tín hiệu của dữ liệu huấn luyện. Hãy xem tín hiệu này có thể tạo ra lợi nhuận như thế nào. Khi tỷ lệ thấp, chúng tôi có thể tạo một bộ nhớ đơn giản, mua 1 tỷ lệ (mua 1 cổ phiếu ADBE và bán tỷ lệ x cổ phiếu MSFT), bán 1 tỷ lệ khi nó cao (bán 1 cổ phiếu ADBE và mua tỷ lệ x cổ phiếu MSFT) và tính toán giao dịch PnL của tỷ lệ này.
# 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)
Kết quả là: 1783.375
Vì vậy, chiến lược này có vẻ có lợi! Bây giờ, chúng ta có thể tối ưu hóa thêm bằng cách thay đổi cửa sổ thời gian trung bình di chuyển, thay đổi ngưỡng mua / bán yên và kiểm tra cải thiện hiệu suất của dữ liệu xác minh.
Chúng ta có thể thử các mô hình phức tạp hơn như Logistic regression, SVM, v.v. để thực hiện dự đoán 1/-1.
Bây giờ, chúng ta hãy tiến lại mô hình này, và điều này đưa chúng ta đến
Một nền tảng định lượng của nhà phát minh sử dụng công cụ định lượng QPS / TPS hiệu suất cao, tái tạo thực tế các môi trường lịch sử, loại bỏ những cạm bẫy định lượng thông thường, phát hiện kịp thời những thiếu sót trong chiến lược, giúp giúp đầu tư thực tế tốt hơn.
Trong bài viết này, chúng tôi sẽ giải thích các nguyên tắc, hoặc chọn để hiển thị logic cơ bản, trong ứng dụng thực tế, hoặc khuyến cáo cho độc giả sử dụng nền tảng định lượng của nhà phát minh, ngoài việc tiết kiệm thời gian, điều quan trọng là tăng tỷ lệ lỗi.
Phân tích lại rất đơn giản, chúng ta có thể sử dụng hàm trên để xem PnL của dữ liệu thử nghiệm.
trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)
Kết quả là: 5262.868
Mô hình đã làm tốt! Nó trở thành mô hình giao dịch cặp đơn giản đầu tiên của chúng tôi.
Trước khi kết thúc cuộc thảo luận, tôi muốn đặc biệt thảo luận về quá phù hợp; quá phù hợp là một trong những cạm bẫy nguy hiểm nhất trong chiến lược giao dịch; quá phù hợp với thuật toán có thể hoạt động rất tốt trong đánh giá lại nhưng thất bại trên dữ liệu mới không thể nhìn thấy - điều này có nghĩa là nó không thực sự tiết lộ bất kỳ xu hướng nào của dữ liệu và không có khả năng dự đoán thực sự. Chúng tôi đưa ra một ví dụ đơn giản.
Trong mô hình của chúng tôi, chúng tôi đã sử dụng dự đoán tham số cuộn và mong muốn tối ưu hóa chiều dài cửa sổ thời gian của nó. Chúng tôi có thể quyết định đơn giản là lặp lại tất cả các khả năng, chiều dài cửa sổ thời gian hợp lý và chọn chiều dài thời gian tốt nhất theo cách hoạt động của mô hình của chúng tôi. Dưới đây chúng tôi đã viết một vòng lặp đơn giản để pNL đánh giá chiều dài cửa sổ thời gian dựa trên dữ liệu đào tạo và tìm ra vòng lặp tốt nhất.
# 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)
Bây giờ chúng tôi kiểm tra hiệu suất mô hình trên dữ liệu thử nghiệm, chúng tôi thấy rằng chiều dài của cửa sổ thời gian này không phải là tối ưu!
# 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)
Rõ ràng là dữ liệu mẫu phù hợp với chúng tôi không phải lúc nào cũng mang lại kết quả tốt trong tương lai. Chỉ để kiểm tra, hãy vẽ phần tử chiều dài tính toán từ hai bộ dữ liệu.
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()
Chúng ta có thể thấy rằng bất cứ thứ gì trong khoảng 20-50 là một lựa chọn tốt cho cửa sổ thời gian.
Để tránh quá phù hợp, chúng ta có thể sử dụng tính chất của suy luận kinh tế hoặc các thuật toán để chọn chiều dài của cửa sổ thời gian. Chúng ta cũng có thể sử dụng bộ lọc Karman, nó không yêu cầu chúng ta chỉ định chiều dài; phương pháp này sẽ được trình bày sau trong một bài viết khác.
Trong bài viết này, chúng tôi đưa ra một số phương pháp giới thiệu đơn giản để chứng minh quá trình phát triển chiến lược giao dịch. Trong thực tế, nên sử dụng số liệu thống kê phức tạp hơn, bạn có thể xem xét các tùy chọn sau:
Chỉ số Hearst
Thời gian phân hủy của sự quay trở lại của giá trị trung bình được suy luận từ quá trình Ornstein-Uhlenbeck
Máy lọc Kalman
bk_fundKhông tìm thấy gói này
bk_fundBạn có thể cài đặt backtester.dataSource.yahoo_data_source ở đâu?