Một chiến lược giao dịch trong ngày sử dụng sự quay trở đồng giữa SPY và IWM

Tác giả:Tốt, Tạo: 2019-07-01 11:47:08, Cập nhật: 2023-10-26 20:07:32

img

Trong bài viết này, chúng tôi sẽ viết một chiến lược giao dịch trong ngày. Nó sẽ sử dụng khái niệm giao dịch cổ điển, đó là việc giao dịch các cặp giao dịch đồng giá trị quay trở lại. Trong ví dụ này, chúng tôi sẽ sử dụng hai quỹ chỉ số mở giao dịch (ETF), SPY và IWM, chúng được giao dịch trên sàn giao dịch chứng khoán New York (NYSE) và cố gắng đại diện cho chỉ số thị trường chứng khoán Mỹ, đó là S&P 500 và Russell 2000.

Chiến lược này tạo ra một chênh lệch lợi nhuận bằng cách làm nhiều ETF và làm trống một ETF khác. Các tỷ lệ đa không gian có thể được định nghĩa theo nhiều cách, ví dụ như bằng cách sử dụng các chuỗi thời gian thống kê phối hợp. Trong trường hợp này, chúng tôi sẽ tính tỷ lệ rủi ro giữa SPY và IWM bằng cách quay ngược tuyến tính. Điều này sẽ cho phép chúng tôi tạo ra chênh lệch lợi nhuận giữa SPY và IWM, được tiêu chuẩn hóa thành điểm số z. Khi điểm số z vượt quá một ngưỡng nào đó, sẽ có tín hiệu giao dịch, vì chúng tôi tin rằng chênh lệch lợi nhuận sẽ trở lại mức trung bình.

Nguyên tắc cơ bản của chiến lược này là SPY và IWM đại diện cho cùng một tình huống thị trường, đó là hiệu suất cổ phiếu của một nhóm các công ty lớn và nhỏ của Mỹ. Giả sử rằng nếu chấp nhận các giá chu kỳ đồng đều theo lý thuyết chu kỳ hồi quy, thì nó sẽ luôn có hồi quy, vì các sự kiện chu kỳ có thể ảnh hưởng đến S&P 500 và Russell 2000 trong thời gian rất ngắn, nhưng chênh lệch lợi nhuận giữa họ sẽ luôn quay trở lại mức trung bình bình thường, và các chuỗi giá dài hạn của cả hai đều được tích hợp hoàn toàn.

Chiến lược

Chiến lược này được thực hiện theo các bước sau:

Dữ liệu - từ tháng 4 năm 2007 đến tháng 2 năm 2014, bản đồ k phút của SPY và IWM được lấy.

xử lý - sắp xếp dữ liệu đúng cách và xóa các chuỗi k thiếu lẫn nhau. Nếu một bên bị thiếu, cả hai bên sẽ bị xóa.

Phân biệt - Tỷ lệ rủi ro giữa hai ETF được tính bằng cách sử dụng tính toán hồi quy tuyến tính lăn lăn. Được định nghĩa là hệ số regression β sử dụng cửa sổ hồi quy, mà cửa sổ hồi quy di chuyển về phía trước 1 đường k và tính lại hệ số regression. Do đó, tỷ lệ rủi ro βi, đường bi-k được tính bằng cách tính điểm băng qua từ bi-1-k đến bi-1, để sử dụng để quay lại đường k.

Z-Score - Giá trị của tỷ lệ chênh lệch tiêu chuẩn được tính theo cách thông thường. Điều này có nghĩa là trừ giá trị trung bình của tỷ lệ chênh lệch và trừ tỷ lệ chênh lệch tiêu chuẩn của tỷ lệ chênh lệch. Lý do làm như vậy là để làm cho các tham số ngưỡng dễ hiểu hơn, bởi vì Z-Score là một lượng không có kích thước.

Giao dịch - Khi giá trị điểm số z âm giảm xuống dưới ngưỡng dự định (hoặc tối ưu hóa sau đó), tín hiệu làm nhiều được tạo ra, trong khi tín hiệu làm trống là ngược lại. Khi giá trị tuyệt đối của điểm số z giảm xuống dưới ngưỡng bổ sung, tín hiệu thoả thuận sẽ được tạo ra. Đối với chiến lược này, tôi (một chút ngẫu nhiên) đã chọn z = 2 như là ngưỡng mở giao dịch và z = 1 như là ngưỡng thoả thuận. Giả sử sự trở lại đồng đều đóng vai trò trong chênh lệch lợi nhuận, những điều trên sẽ có thể nắm bắt được mối quan hệ lợi nhuận này và mang lại lợi nhuận tốt.

Có lẽ cách tốt nhất để hiểu sâu hơn về chính sách là thực hiện nó. Phần sau đây mô tả chi tiết toàn bộ mã Python để thực hiện chính sách quay trở lại giá trị đồng nhất này (một tập tin riêng lẻ). Tôi đã thêm chú thích mã chi tiết để giúp bạn hiểu rõ hơn.

Python thực hiện

Như tất cả các hướng dẫn Python / pandas, bạn phải thiết lập theo môi trường Python được mô tả trong hướng dẫn này. Sau khi thiết lập xong, nhiệm vụ đầu tiên là nhập thư viện Python cần thiết. Điều này là cần thiết để sử dụng matplotlib và pandas.

Các phiên bản cụ thể của thư viện mà tôi sử dụng là:

Python - 2.7.3 Số - 1.8.0 panda - 0.12.0 matplotlib - 1.1.0

Chúng ta hãy tiếp tục và nhập các thư viện:

# mr_spy_iwm.py

import matplotlib.pyplot as plt
import numpy as np
import os, os.path
import pandas as pd

Chức năng create_pairs_dataframe dưới đây nhập hai dòng k trong CSV chứa hai biểu tượng. Trong ví dụ của chúng tôi, đó sẽ là SPY và IWM. Sau đó nó tạo một cặp data frame riêng biệt, cặp data frame này sẽ sử dụng chỉ mục của hai tập tin nguyên bản. Thời gian của chúng có thể khác nhau do các giao dịch bị bỏ lỡ và lỗi.

# mr_spy_iwm.py
def create_pairs_dataframe(datadir, symbols):
    """Creates a pandas DataFrame containing the closing price
    of a pair of symbols based on CSV files containing a datetime
    stamp and OHLCV data."""
 
    # Open the individual CSV files and read into pandas DataFrames
    print "Importing CSV data..."
    sym1 = pd.io.parsers.read_csv(os.path.join(datadir, '%s.csv' % symbols[0]),
                                  header=0, index_col=0, 
                                  names=['datetime','open','high','low','close','volume','na'])
    sym2 = pd.io.parsers.read_csv(os.path.join(datadir, '%s.csv' % symbols[1]),
                                  header=0, index_col=0, 
                                  names=['datetime','open','high','low','close','volume','na'])
 
    # Create a pandas DataFrame with the close prices of each symbol
    # correctly aligned and dropping missing entries
    print "Constructing dual matrix for %s and %s..." % symbols    
    pairs = pd.DataFrame(index=sym1.index)
    pairs['%s_close' % symbols[0].lower()] = sym1['close']
    pairs['%s_close' % symbols[1].lower()] = sym2['close']
    pairs = pairs.dropna()
    return pairs

Bước tiếp theo là quay lượn tuyến tính giữa SPY và IWM. Trong trường hợp này, IWM là dự báo (x), SPY là phản ứng (y). Tôi đã thiết lập một cửa sổ quay lưng mặc định với 100 đường k. Như đã đề cập ở trên, đây là các tham số của chính sách. Để chính sách được coi là vững chắc, chúng ta nên mong muốn thấy một báo cáo quay trở lại biểu hiện trạng thái hàm convex (x) hoặc các phép đo hiệu suất khác trong giai đoạn quay lưng. Vì vậy, trong giai đoạn sau của mã, chúng ta sẽ phân tích độ nhạy cảm bằng cách quay lưng trong phạm vi thay đổi.

Sau khi tính toán các hệ số xoay β trong mô hình hồi quy tuyến tính SPY-IWM, chúng tôi thêm vào DataFrame và loại bỏ các đường trống. Điều này đã xây dựng một tập K đầu tiên, tương đương với thước đo cắt giảm chiều dài ngược. Sau đó, chúng tôi tạo ra hai ETF, đơn vị SPY và đơn vị -βi của IWM.

Cuối cùng, chúng ta tạo ra điểm số z của chênh lệch lãi suất, tính bằng cách trừ giá trị trung bình của chênh lệch lãi suất và tính bằng giá trị tiêu chuẩn của chênh lệch lãi suất tiêu chuẩn. Lưu ý rằng có một chi tiết khá tinh tế về chênh lệch lãi suất lãi suất. Tôi cố tình để lại nó trong mã bởi vì tôi muốn nhấn mạnh việc mắc sai lầm như vậy dễ dàng như thế nào trong nghiên cứu. Tính toán giá trị trung bình và chênh lệch lãi suất toàn bộ chuỗi thời gian.

# mr_spy_iwm.py
 
def calculate_spread_zscore(pairs, symbols, lookback=100):
    """Creates a hedge ratio between the two symbols by calculating
    a rolling linear regression with a defined lookback period. This
    is then used to create a z-score of the 'spread' between the two
    symbols based on a linear combination of the two."""
     
    # Use the pandas Ordinary Least Squares method to fit a rolling
    # linear regression between the two closing price time series
    print "Fitting the rolling Linear Regression..."
    model = pd.ols(y=pairs['%s_close' % symbols[0].lower()], 
                   x=pairs['%s_close' % symbols[1].lower()],
                   window=lookback)
 
    # Construct the hedge ratio and eliminate the first 
    # lookback-length empty/NaN period
    pairs['hedge_ratio'] = model.beta['x']
    pairs = pairs.dropna()
 
    # Create the spread and then a z-score of the spread
    print "Creating the spread/zscore columns..."
    pairs['spread'] = pairs['spy_close'] - pairs['hedge_ratio']*pairs['iwm_close']
    pairs['zscore'] = (pairs['spread'] - np.mean(pairs['spread']))/np.std(pairs['spread'])
    return pairs

Trong create_long_short_market_signals, tạo tín hiệu giao dịch. Chúng được tính bằng cách giá trị của z-score vượt quá ngưỡng. Khi giá trị tuyệt đối của z-score nhỏ hơn hoặc bằng một ngưỡng khác (thời gian nhỏ hơn), báo hiệu ngang hàng được đưa ra.

Để thực hiện điều này, cần thiết phải thiết lập một chiến lược giao dịch cho mỗi đường k là mở khoang hoặc mở khoang. Long_market và short_market là hai biến định nghĩa để theo dõi các vị trí đa đầu và không đầu. Thật không may, lập trình theo cách lặp đi lặp lại dễ dàng hơn so với phương pháp định lượng và do đó tính toán chậm. Mặc dù mỗi tập tin CSV cần khoảng 700.000 điểm dữ liệu cho một biểu đồ đường k 1 phút, nhưng tính toán trên máy tính để bàn cũ của tôi vẫn tương đối nhanh!

Để lặp lại một Pandas DataFrame (đây chắc chắn là một hoạt động không phổ biến), cần phải sử dụng phương pháp iterrows, nó cung cấp một trình tạo lặp:

# mr_spy_iwm.py
 
def create_long_short_market_signals(pairs, symbols, 
                                     z_entry_threshold=2.0, 
                                     z_exit_threshold=1.0):
    """Create the entry/exit signals based on the exceeding of 
    z_enter_threshold for entering a position and falling below
    z_exit_threshold for exiting a position."""
 
    # Calculate when to be long, short and when to exit
    pairs['longs'] = (pairs['zscore'] <= -z_entry_threshold)*1.0
    pairs['shorts'] = (pairs['zscore'] >= z_entry_threshold)*1.0
    pairs['exits'] = (np.abs(pairs['zscore']) <= z_exit_threshold)*1.0
 
    # These signals are needed because we need to propagate a
    # position forward, i.e. we need to stay long if the zscore
    # threshold is less than z_entry_threshold by still greater
    # than z_exit_threshold, and vice versa for shorts.
    pairs['long_market'] = 0.0
    pairs['short_market'] = 0.0
 
    # These variables track whether to be long or short while
    # iterating through the bars
    long_market = 0
    short_market = 0
 
    # Calculates when to actually be "in" the market, i.e. to have a
    # long or short position, as well as when not to be.
    # Since this is using iterrows to loop over a dataframe, it will
    # be significantly less efficient than a vectorised operation,
    # i.e. slow!
    print "Calculating when to be in the market (long and short)..."
    for i, b in enumerate(pairs.iterrows()):
        # Calculate longs
        if b[1]['longs'] == 1.0:
            long_market = 1            
        # Calculate shorts
        if b[1]['shorts'] == 1.0:
            short_market = 1
        # Calculate exists
        if b[1]['exits'] == 1.0:
            long_market = 0
            short_market = 0
        # This directly assigns a 1 or 0 to the long_market/short_market
        # columns, such that the strategy knows when to actually stay in!
        pairs.ix[i]['long_market'] = long_market
        pairs.ix[i]['short_market'] = short_market
    return pairs

Ở giai đoạn này, chúng tôi đã cập nhật các cặp để chứa nhiều, tín hiệu trống thực tế, điều này cho phép chúng tôi xác định xem chúng tôi có cần mở lệnh hay không. Bây giờ chúng tôi cần tạo một danh mục đầu tư để theo dõi giá trị thị trường của vị trí. Nhiệm vụ đầu tiên là tạo một hàng vị trí kết hợp nhiều tín hiệu và tín hiệu trống.

Một khi giá trị thị trường của ETF đã được tạo ra, chúng tôi sẽ phân chia chúng để tạo ra tổng giá trị thị trường ở cuối mỗi dòng k. Sau đó chuyển đổi nó thành giá trị trả về bằng phương pháp pct_change của đối tượng. Các dòng mã tiếp theo sẽ xóa các mục sai ((NaN và các yếu tố inf) và cuối cùng tính toán đường cong lợi ích hoàn chỉnh.

# mr_spy_iwm.py
 
def create_portfolio_returns(pairs, symbols):
    """Creates a portfolio pandas DataFrame which keeps track of
    the account equity and ultimately generates an equity curve.
    This can be used to generate drawdown and risk/reward ratios."""
     
    # Convenience variables for symbols
    sym1 = symbols[0].lower()
    sym2 = symbols[1].lower()
 
    # Construct the portfolio object with positions information
    # Note that minuses to keep track of shorts!
    print "Constructing a portfolio..."
    portfolio = pd.DataFrame(index=pairs.index)
    portfolio['positions'] = pairs['long_market'] - pairs['short_market']
    portfolio[sym1] = -1.0 * pairs['%s_close' % sym1] * portfolio['positions']
    portfolio[sym2] = pairs['%s_close' % sym2] * portfolio['positions']
    portfolio['total'] = portfolio[sym1] + portfolio[sym2]
 
    # Construct a percentage returns stream and eliminate all 
    # of the NaN and -inf/+inf cells
    print "Constructing the equity curve..."
    portfolio['returns'] = portfolio['total'].pct_change()
    portfolio['returns'].fillna(0.0, inplace=True)
    portfolio['returns'].replace([np.inf, -np.inf], 0.0, inplace=True)
    portfolio['returns'].replace(-1.0, 0.0, inplace=True)
 
    # Calculate the full equity curve
    portfolio['returns'] = (portfolio['returns'] + 1.0).cumprod()
    return portfolio

Chức năng chủ kết hợp chúng với nhau. Các tập tin CSV trong ngày nằm trong đường dẫn datadir.

Để xác định mức độ nhạy cảm của chiến lược đối với chu kỳ lookback, cần phải tính toán một loạt các chỉ số hiệu suất của lookback. Tôi đã chọn phần trăm tổng lợi nhuận cuối cùng của danh mục đầu tư làm chỉ số hiệu suất và phạm vi lookback[50,200], tăng là 10. Bạn có thể thấy trong mã dưới đây, các hàm trước được bao gồm trong chu kỳ for trong phạm vi này, các ngưỡng khác vẫn không thay đổi. Nhiệm vụ cuối cùng là sử dụng matplotlib để tạo biểu đồ đường cong của lookbacks so với lợi nhuận:

# mr_spy_iwm.py
 
if __name__ == "__main__":
    datadir = '/your/path/to/data/'  # Change this to reflect your data path!
    symbols = ('SPY', 'IWM')
 
    lookbacks = range(50, 210, 10)
    returns = []
 
    # Adjust lookback period from 50 to 200 in increments
    # of 10 in order to produce sensitivities
    for lb in lookbacks: 
        print "Calculating lookback=%s..." % lb
        pairs = create_pairs_dataframe(datadir, symbols)
        pairs = calculate_spread_zscore(pairs, symbols, lookback=lb)
        pairs = create_long_short_market_signals(pairs, symbols, 
                                                z_entry_threshold=2.0, 
                                                z_exit_threshold=1.0)
 
        portfolio = create_portfolio_returns(pairs, symbols)
        returns.append(portfolio.ix[-1]['returns'])
 
    print "Plot the lookback-performance scatterchart..."
    plt.plot(lookbacks, returns, '-o')
    plt.show()

img

Bây giờ bạn có thể thấy biểu đồ lookbacks và returns. Lưu ý rằng lookback có giá trị tối đa của một hàm toàn cầu, tương đương với 110 đường k. Nếu chúng ta thấy lookbacks không liên quan đến return, đó là vì:

SPY-IWM phân tích độ nhạy trong thời gian trục trặc so với sự bảo hiểm hồi quy tuyến tính

Không có đường cong lợi nhuận nghiêng lên, bất kỳ bài viết xem lại nào cũng không hoàn chỉnh! Vì vậy, nếu bạn muốn vẽ đường cong lợi nhuận tích lũy và thời gian, bạn có thể sử dụng mã sau đây. Nó sẽ vẽ danh mục đầu tư cuối cùng được tạo ra từ nghiên cứu tham số lookback. Do đó, cần phải chọn lookback dựa trên biểu đồ bạn muốn hình dung.

# mr_spy_iwm.py
 
    # This is still within the main function
    print "Plotting the performance charts..."
    fig = plt.figure()
    fig.patch.set_facecolor('white')
 
    ax1 = fig.add_subplot(211,  ylabel='%s growth (%%)' % symbols[0])
    (pairs['%s_close' % symbols[0].lower()].pct_change()+1.0).cumprod().plot(ax=ax1, color='r', lw=2.)
 
    ax2 = fig.add_subplot(212, ylabel='Portfolio value growth (%%)')
    portfolio['returns'].plot(ax=ax2, lw=2.)
 
    fig.show()

Trong khi đó, các nhà nghiên cứu cũng cho biết:

img

SPY-IWM phân tích độ nhạy trong thời gian trục trặc so với sự bảo hiểm hồi quy tuyến tính

Xin lưu ý rằng SPY đã giảm đáng kể trong năm 2009 trong thời gian khủng hoảng tài chính. Chiến lược này cũng đang trong giai đoạn biến động tại thời điểm này. Xin lưu ý rằng kết quả năm ngoái đã xấu đi do SPY có tính xu hướng mạnh trong thời gian này, phản ánh chỉ số S&P 500.

Lưu ý rằng, khi tính lãi suất của điểm số z, chúng ta vẫn cần phải xem xét tỷ lệ lệ chênh lệch nhìn về phía trước. Ngoài ra, tất cả các tính toán này được thực hiện trong trường hợp không có chi phí giao dịch. Một khi đã tính đến các yếu tố này, chiến lược này chắc chắn sẽ hoạt động rất kém. Chi phí thủ tục và điểm trượt hiện tại chưa được xác định.

Trong các bài viết sau, chúng tôi sẽ tạo ra một backtester chạy sự kiện phức tạp hơn sẽ tính đến các yếu tố trên, cho phép chúng tôi thể hiện sự tự tin hơn về đường cong vốn và các chỉ số hiệu suất.


Có liên quan

Thêm nữa