Kiểm tra ngược dựa trên sự kiện với Python - Phần VII

Tác giả:Tốt, Tạo: 2019-03-26 10:52:49, Cập nhật:

Trong bài viết trước đây về loạt backtester Event-Driven, chúng tôi đã xem xét một hệ thống phân cấp ExecutionHandler cơ bản.

Các chỉ số hiệu suất

Chúng ta đã xem xét tỷ lệ Sharpe trong một bài viết trước đó.img

Trong đó Ra là dòng lợi nhuận của đường cong vốn chủ sở hữu và Rb là một chỉ số chuẩn, chẳng hạn như một lãi suất thích hợp hoặc chỉ số vốn chủ sở hữu.

Số lượng rút vốn tối đa và thời gian rút vốn là hai biện pháp bổ sung mà các nhà đầu tư thường sử dụng để đánh giá rủi ro trong danh mục đầu tư.

Trong bài viết này, chúng tôi sẽ thực hiện tỷ lệ Sharpe, kéo dài tối đa và kéo dài kéo dài như các biện pháp đo lường hiệu suất danh mục đầu tư để sử dụng trong bộ thử nghiệm ngược dựa trên Python.

Thực hiện Python

Nhiệm vụ đầu tiên là tạo một tệp mớiperformance.pyNhư với hầu hết các lớp tính toán nặng của chúng tôi, chúng tôi cần nhập NumPy và panda:

# performance.py

import numpy as np
import pandas as pd

Lưu ý rằng tỷ lệ Sharpe là một thước đo rủi ro để thưởng (thực tế nó là một trong nhiều!).

Thông thường, giá trị này được thiết lập là 252, đó là số ngày giao dịch ở Mỹ mỗi năm. Tuy nhiên, nếu chiến lược của bạn giao dịch trong vòng một giờ, bạn cần điều chỉnh Sharpe để định kỳ đúng. Do đó, bạn cần thiết lập các khoảng thời gian là 2526.5=1638, đó là số giờ giao dịch của Mỹ trong một năm. Nếu bạn giao dịch theo từng phút, thì yếu tố này phải được thiết lập là 2526.560=98280.

Chức năng create_sharpe_ratio hoạt động trên một đối tượng chuỗi pandas gọi là lợi nhuận và đơn giản là tính toán tỷ lệ của trung bình của thời gian phần trăm lợi nhuận và thời gian phần trăm lợi nhuận lệch chuẩn quy mô bởi các yếu tố thời gian:

# performance.py

def create_sharpe_ratio(returns, periods=252):
    """
    Create the Sharpe ratio for the strategy, based on a 
    benchmark of zero (i.e. no risk-free rate information).

    Parameters:
    returns - A pandas Series representing period percentage returns.
    periods - Daily (252), Hourly (252*6.5), Minutely(252*6.5*60) etc.
    """
    return np.sqrt(periods) * (np.mean(returns)) / np.std(returns)

Trong khi tỷ lệ Sharpe mô tả mức độ rủi ro (được xác định bởi độ lệch chuẩn đường dẫn tài sản) được thực hiện trên mỗi đơn vị lợi nhuận, drawdown được xác định là mức giảm lớn nhất từ đỉnh đến đáy dọc theo đường cong vốn chủ sở hữu.

Chức năng create_drawdowns bên dưới thực sự cung cấp cả mức rút tối đa và thời gian rút tối đa.

Có một số tinh tế cần thiết trong việc giải thích thời gian rút vốn vì nó đếm các giai đoạn giao dịch và do đó không thể dịch trực tiếp thành đơn vị thời gian như ngày.

Chức năng này bắt đầu bằng cách tạo ra hai đối tượng panda Series đại diện cho mức rút và thời gian tại mỗi giao dịch bar. Sau đó, dấu nước cao hiện tại (HWM) được thiết lập bằng cách xác định xem đường cong vốn chủ sở hữu vượt quá tất cả các đỉnh trước đó hay không.

Chế độ rút vốn sau đó chỉ đơn giản là sự khác biệt giữa HWM hiện tại và đường cong vốn chủ sở hữu. Nếu giá trị này là âm thì thời gian tăng lên cho mỗi thanh xảy ra cho đến khi đạt đến HWM tiếp theo. Chức năng sau đó chỉ đơn giản trả về tối đa của mỗi hai chuỗi:

# performance.py

def create_drawdowns(equity_curve):
    """
    Calculate the largest peak-to-trough drawdown of the PnL curve
    as well as the duration of the drawdown. Requires that the 
    pnl_returns is a pandas Series.

    Parameters:
    pnl - A pandas Series representing period percentage returns.

    Returns:
    drawdown, duration - Highest peak-to-trough drawdown and duration.
    """

    # Calculate the cumulative returns curve 
    # and set up the High Water Mark
    # Then create the drawdown and duration series
    hwm = [0]
    eq_idx = equity_curve.index
    drawdown = pd.Series(index = eq_idx)
    duration = pd.Series(index = eq_idx)

    # Loop over the index range
    for t in range(1, len(eq_idx)):
        cur_hwm = max(hwm[t-1], equity_curve[t])
        hwm.append(cur_hwm)
        drawdown[t]= hwm[t] - equity_curve[t]
        duration[t]= 0 if drawdown[t] == 0 else duration[t-1] + 1
    return drawdown.max(), duration.max()

Để sử dụng các thước đo hiệu suất này, chúng ta cần một phương tiện để tính toán chúng sau khi đã thực hiện backtest, tức là khi có đường cong vốn chủ sở hữu phù hợp!

Chúng ta cũng cần liên kết tính toán với một hệ thống phân cấp đối tượng cụ thể.

Nhiệm vụ đầu tiên là mở raportfolio.pynhư đã được thảo luận trong bài viết trước và nhập các chức năng hiệu suất:

# portfolio.py

..  # Other imports

from performance import create_sharpe_ratio, create_drawdowns

Vì Portfolio là một lớp cơ sở trừu tượng, chúng ta muốn gắn một phương thức vào một trong những lớp phái sinh của nó, trong trường hợp này sẽ là NaivePortfolio. Do đó, chúng ta sẽ tạo một phương thức gọi là output_summary_stats sẽ hoạt động trên đường cong vốn chủ sở hữu danh mục đầu tư để tạo ra thông tin Sharpe và rút tiền.

Phương pháp này rất đơn giản. Nó chỉ đơn giản là sử dụng hai thước đo hiệu suất và áp dụng chúng trực tiếp vào đường cong vốn chủ sở hữu của DataFrame, xuất dữ liệu thống kê dưới dạng một danh sách các tuples theo cách thân thiện với định dạng:

# portfolio.py

..
..

class NaivePortfolio(object):

    ..
    ..

    def output_summary_stats(self):
        """
        Creates a list of summary statistics for the portfolio such
        as Sharpe Ratio and drawdown information.
        """
        total_return = self.equity_curve['equity_curve'][-1]
        returns = self.equity_curve['returns']
        pnl = self.equity_curve['equity_curve']

        sharpe_ratio = create_sharpe_ratio(returns)
        max_dd, dd_duration = create_drawdowns(pnl)

        stats = [("Total Return", "%0.2f%%" % ((total_return - 1.0) * 100.0)),
                 ("Sharpe Ratio", "%0.2f" % sharpe_ratio),
                 ("Max Drawdown", "%0.2f%%" % (max_dd * 100.0)),
                 ("Drawdown Duration", "%d" % dd_duration)]
        return stats

Rõ ràng đây là một phân tích hiệu suất rất đơn giản cho một danh mục đầu tư. Nó không xem xét phân tích cấp giao dịch hoặc các biện pháp rủi ro / phần thưởng khác. Tuy nhiên, nó rất đơn giản để mở rộng bằng cách thêm nhiều phương pháp vàoperformance.pyvà sau đó kết hợp chúng vào output_summary_stat theo yêu cầu.


Thêm nữa