Kiểm tra lại chiến lược dự báo cho S & P500 trong Python với pandas

Tác giả:Tốt, Tạo: 2019-03-29 14:24:50, Cập nhật:

Các thư viện Python trưởng thành như matplotlib, pandas và scikit-learn cũng làm giảm sự cần thiết phải viết mã boilerplate hoặc đưa ra các triển khai của riêng chúng tôi của các thuật toán nổi tiếng.

Chiến lược dự báo

Chính chiến lược dự báo dựa trên một kỹ thuật học máy được gọi là phân tích phân biệt bậc hai, có liên quan chặt chẽ đến phân tích phân biệt tuyến tính.

Nhà dự báo sử dụng hai lợi nhuận hàng ngày trước đó như một tập hợp các yếu tố để dự đoán hướng thị trường chứng khoán ngày hôm nay. Nếu xác suất ngày up vượt quá 50%, chiến lược mua 500 cổ phiếu của SPY ETF và bán nó vào cuối ngày. nếu xác suất ngày giảm vượt quá 50%, chiến lược bán 500 cổ phiếu của SPY ETF và sau đó mua lại khi đóng cửa. Do đó, đây là ví dụ đầu tiên của chúng tôi về chiến lược giao dịch trong ngày.

Lưu ý rằng đây không phải là một chiến lược giao dịch đặc biệt thực tế! Chúng tôi không bao giờ có khả năng đạt được giá mở hoặc đóng do nhiều yếu tố như biến động mở quá mức, định tuyến lệnh bởi môi giới và các vấn đề thanh khoản tiềm ẩn xung quanh mở / đóng. Ngoài ra, chúng tôi không bao gồm chi phí giao dịch. Đây có thể là một tỷ lệ phần trăm đáng kể về lợi nhuận vì có một giao dịch đi lại được thực hiện mỗi ngày. Do đó, nhà dự báo của chúng tôi cần phải tương đối chính xác trong việc dự đoán lợi nhuận hàng ngày, nếu không chi phí giao dịch sẽ ăn tất cả lợi nhuận giao dịch của chúng tôi.

Thực hiện

Như với các hướng dẫn liên quan đến Python / panda khác, tôi đã sử dụng các thư viện sau:

  • Python - 2.7.3
  • Số - 1.8.0
  • panda - 0.12.0
  • matplotlib - 1.1.0
  • Sikit-learn - 0.14.1

Việc thực hiện snp_forecast.py dưới đây đòi hỏibacktest.pytừ hướng dẫn trước đây này.forecast.py(mà chủ yếu chứa hàm create_lagged_series) được tạo từ hướng dẫn trước đây.

# snp_forecast.py

import datetime
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import sklearn

from pandas.io.data import DataReader
from sklearn.qda import QDA

from backtest import Strategy, Portfolio
from forecast import create_lagged_series

Một khi tất cả các thư viện và mô-đun có liên quan đã được bao gồm, đã đến lúc phân loại lớp cơ sở trừu tượng Chiến lược, như chúng tôi đã thực hiện trong các hướng dẫn trước. SNPForecastingStrategy được thiết kế để phù hợp với Quadratic Discriminant Analyzer với chỉ số chứng khoán S & P500 như một phương tiện dự đoán giá trị tương lai của nó. Việc phù hợp với mô hình được thực hiện theo phương pháp fit_model bên dưới, trong khi các tín hiệu thực tế được tạo ra từ phương pháp generate_signals. Điều này phù hợp với giao diện của một lớp Chiến lược.

Các chi tiết về cách một phân tích phân biệt bậc hai hoạt động, cũng như việc triển khai Python bên dưới, được mô tả chi tiết trong bài viết trước về dự báo chuỗi thời gian tài chính.

# snp_forecast.py

class SNPForecastingStrategy(Strategy):
    """    
    Requires:
    symbol - A stock symbol on which to form a strategy on.
    bars - A DataFrame of bars for the above symbol."""

    def __init__(self, symbol, bars):
        self.symbol = symbol
        self.bars = bars
        self.create_periods()
        self.fit_model()

    def create_periods(self):
        """Create training/test periods."""
        self.start_train = datetime.datetime(2001,1,10)
        self.start_test = datetime.datetime(2005,1,1)
        self.end_period = datetime.datetime(2005,12,31)

    def fit_model(self):
        """Fits a Quadratic Discriminant Analyser to the
        US stock market index (^GPSC in Yahoo)."""
        # Create a lagged series of the S&P500 US stock market index
        snpret = create_lagged_series(self.symbol, self.start_train, 
                                      self.end_period, lags=5) 

        # Use the prior two days of returns as 
        # predictor values, with direction as the response
        X = snpret[["Lag1","Lag2"]]
        y = snpret["Direction"]

        # Create training and test sets
        X_train = X[X.index < self.start_test]
        y_train = y[y.index < self.start_test]

        # Create the predicting factors for use 
        # in direction forecasting
        self.predictors = X[X.index >= self.start_test]

        # Create the Quadratic Discriminant Analysis model
        # and the forecasting strategy
        self.model = QDA()
        self.model.fit(X_train, y_train)

    def generate_signals(self):
        """Returns the DataFrame of symbols containing the signals
        to go long, short or hold (1, -1 or 0)."""
        signals = pd.DataFrame(index=self.bars.index)
        signals['signal'] = 0.0       

        # Predict the subsequent period with the QDA model
        signals['signal'] = self.model.predict(self.predictors)

        # Remove the first five signal entries to eliminate
        # NaN issues with the signals DataFrame
        signals['signal'][0:5] = 0.0
        signals['positions'] = signals['signal'].diff() 

        return signals

Bây giờ mà công cụ dự báo đã tạo ra các tín hiệu, chúng ta có thể tạo ra một MarketIntradayPortfolio. đối tượng danh mục đầu tư này khác với ví dụ được đưa ra trong bài viết backtest Moving Average Crossover vì nó thực hiện giao dịch trên cơ sở trong ngày.

Danh mục đầu tư được thiết kế để mua 500 cổ phiếu SPY ở mức giá mở nếu tín hiệu cho biết một ngày tăng sẽ xảy ra và sau đó bán khi đóng. Ngược lại, danh mục đầu tư được thiết kế để mua 500 cổ phiếu SPY nếu tín hiệu cho biết một ngày giảm sẽ xảy ra và sau đó đóng ở mức giá đóng.

Để đạt được điều này, sự khác biệt giá giữa giá mở thị trường và giá đóng thị trường được xác định mỗi ngày, dẫn đến việc tính toán lợi nhuận hàng ngày trên 500 cổ phiếu mua hoặc bán. Điều này sau đó dẫn đến một đường cong vốn chủ sở hữu tự nhiên bằng cách tổng hợp tổng lợi nhuận/mất cho mỗi ngày. Nó cũng có lợi thế cho phép chúng ta tính toán thống kê lợi nhuận/mất cho mỗi ngày.

Đây là danh sách cho MarketIntradayPortfolio:

# snp_forecast.py

class MarketIntradayPortfolio(Portfolio):
    """Buys or sells 500 shares of an asset at the opening price of
    every bar, depending upon the direction of the forecast, closing 
    out the trade at the close of the bar.

    Requires:
    symbol - A stock symbol which forms the basis of the portfolio.
    bars - A DataFrame of bars for a symbol set.
    signals - A pandas DataFrame of signals (1, 0, -1) for each symbol.
    initial_capital - The amount in cash at the start of the portfolio."""

    def __init__(self, symbol, bars, signals, initial_capital=100000.0):
        self.symbol = symbol        
        self.bars = bars
        self.signals = signals
        self.initial_capital = float(initial_capital)
        self.positions = self.generate_positions()
        
    def generate_positions(self):
        """Generate the positions DataFrame, based on the signals
        provided by the 'signals' DataFrame."""
        positions = pd.DataFrame(index=self.signals.index).fillna(0.0)

        # Long or short 500 shares of SPY based on 
        # directional signal every day
        positions[self.symbol] = 500*self.signals['signal']
        return positions
                    
    def backtest_portfolio(self):
        """Backtest the portfolio and return a DataFrame containing
        the equity curve and the percentage returns."""

        # Set the portfolio object to have the same time period
        # as the positions DataFrame
        portfolio = pd.DataFrame(index=self.positions.index)
        pos_diff = self.positions.diff()

        # Work out the intraday profit of the difference
        # in open and closing prices and then determine
        # the daily profit by longing if an up day is predicted
        # and shorting if a down day is predicted        
        portfolio['price_diff'] = self.bars['Close']-self.bars['Open']
        portfolio['price_diff'][0:5] = 0.0
        portfolio['profit'] = self.positions[self.symbol] * portfolio['price_diff']

        # Generate the equity curve and percentage returns
        portfolio['total'] = self.initial_capital + portfolio['profit'].cumsum()
        portfolio['returns'] = portfolio['total'].pct_change()
        return portfolio

Bước cuối cùng là liên kết các mục tiêu chiến lược và danh mục đầu tư với mộtchínhchức năng. Chức năng thu thập dữ liệu cho công cụ SPY và sau đó tạo ra chiến lược tạo tín hiệu trên chỉ số S&P500. Điều này được cung cấp bởi ticker ^GSPC. Sau đó, một MarketIntradayPortfolio được tạo ra với vốn ban đầu là 100.000 USD (như trong các hướng dẫn trước). Cuối cùng, lợi nhuận được tính toán và đường cong vốn chủ sở hữu được vẽ.

Lưu ý rằng có rất ít mã được yêu cầu ở giai đoạn này bởi vì tất cả các tính toán nặng được thực hiện trong các lớp con Chiến lược và Cổ phiếu. Điều này làm cho nó cực kỳ đơn giản để tạo ra các chiến lược giao dịch mới và thử nghiệm chúng nhanh chóng để sử dụng trong đường ống chiến lược.

if __name__ == "__main__":
    start_test = datetime.datetime(2005,1,1)
    end_period = datetime.datetime(2005,12,31)

    # Obtain the bars for SPY ETF which tracks the S&P500 index    
    bars = DataReader("SPY", "yahoo", start_test, end_period)
    
    # Create the S&P500 forecasting strategy
    snpf = SNPForecastingStrategy("^GSPC", bars)
    signals = snpf.generate_signals()

    # Create the portfolio based on the forecaster
    portfolio = MarketIntradayPortfolio("SPY", bars, signals,              
                                        initial_capital=100000.0)
    returns = portfolio.backtest_portfolio()

    # Plot results
    fig = plt.figure()
    fig.patch.set_facecolor('white')

    # Plot the price of the SPY ETF
    ax1 = fig.add_subplot(211,  ylabel='SPY ETF price in $')
    bars['Close'].plot(ax=ax1, color='r', lw=2.)

    # Plot the equity curve
    ax2 = fig.add_subplot(212, ylabel='Portfolio value in $')
    returns['total'].plot(ax=ax2, lw=2.)

    fig.show()

Trong thời gian này, thị trường chứng khoán đã trả lại 4% (giả sử một chiến lược mua và giữ hoàn toàn đầu tư), trong khi thuật toán chính nó cũng trả lại 4%. Lưu ý rằng chi phí giao dịch (như phí hoa hồng) không được thêm vào hệ thống backtesting này.

S&P500 Dự báo chiến lược hiệu suất từ 2005-01-01 đến 2006-12-31

Trong các bài viết tiếp theo, chúng tôi sẽ thêm chi phí giao dịch thực tế, sử dụng các công cụ dự báo bổ sung, xác định các chỉ số hiệu suất và cung cấp các công cụ tối ưu hóa danh mục đầu tư.


Thêm nữa