Dalam artikel terakhir tentang seri Backtester Event-Driven kami mempertimbangkan hierarki ExecutionHandler dasar. Dalam artikel ini kita akan membahas bagaimana menilai kinerja strategi pasca backtest menggunakan kurva ekuitas DataFrame yang dibangun sebelumnya dalam objek Portfolio.
Kami telah membahas rasio Sharpe dalam artikel sebelumnya.Di artikel itu saya menguraikan bahwa rasio Sharpe (taunan) dihitung melalui:
Di mana Ra adalah aliran pengembalian kurva ekuitas dan Rb adalah patokan, seperti suku bunga atau indeks ekuitas yang sesuai.
Pendapatan maksimum dan durasi penarikan adalah dua ukuran tambahan yang sering digunakan investor untuk menilai risiko dalam portofolio.
Dalam artikel ini kita akan menerapkan rasio Sharpe, penarikan maksimum dan durasi penarikan sebagai ukuran kinerja portofolio untuk digunakan dalam Suite Backtesting Event-Driven berbasis Python.
Tugas pertama adalah untuk membuat file baruperformance.py, yang menyimpan fungsi untuk menghitung rasio Sharpe dan informasi drawdown.
# performance.py
import numpy as np
import pandas as pd
Perhatikan bahwa rasio Sharpe adalah ukuran risiko untuk imbalan (pada kenyataannya ini adalah salah satu dari banyak!)
Biasanya nilai ini ditetapkan menjadi 252, yang merupakan jumlah hari perdagangan di AS per tahun. Namun, jika strategi Anda diperdagangkan dalam satu jam, Anda perlu menyesuaikan Sharpe untuk mempertahunikannya dengan benar. Dengan demikian, Anda perlu menetapkan periode menjadi 252
Fungsi create_sharpe_ratio beroperasi pada obyek Pandas Series yang disebut pengembalian dan hanya menghitung rasio rata-rata pengembalian persentase periode dan deviasi standar pengembalian persentase periode yang diskalakan oleh faktor periode:
# 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)
Sementara rasio Sharpe mencirikan berapa banyak risiko (seperti yang didefinisikan oleh deviasi standar jalur aset) yang diambil per unit pengembalian,
Fungsi create_drawdowns di bawah ini sebenarnya memberikan kedua penarikan maksimum dan durasi penarikan maksimum. Yang pertama adalah penurunan puncak-ke-rendah terbesar yang disebutkan di atas, sementara yang terakhir didefinisikan sebagai jumlah periode di mana penurunan ini terjadi.
Ada beberapa kehalusan yang diperlukan dalam interpretasi durasi penarikan karena menghitung periode perdagangan dan karenanya tidak dapat diterjemahkan langsung ke dalam satuan waktu seperti
Fungsi ini dimulai dengan membuat dua objek seri panda yang mewakili penurunan dan durasi pada setiap perdagangan
Penarikan kemudian hanya perbedaan antara HWM saat ini dan kurva ekuitas. Jika nilai ini negatif maka durasi ditingkatkan untuk setiap bar yang terjadi sampai HWM berikutnya tercapai. Fungsi kemudian hanya mengembalikan maksimum masing-masing dari dua seri:
# 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()
Untuk menggunakan ukuran kinerja ini, kita membutuhkan cara untuk menghitungnya setelah backtest dilakukan, yaitu ketika kurva ekuitas yang sesuai tersedia!
Kita juga perlu menghubungkan perhitungan dengan hierarki objek tertentu. Mengingat bahwa ukuran kinerja dihitung berdasarkan portofolio, masuk akal untuk melampirkan perhitungan kinerja ke metode pada hierarki kelas portofolio yang kita bahas dalam artikel ini.
Tugas pertama adalah membukaportfolio.pyseperti yang dibahas dalam artikel sebelumnya dan mengimpor fungsi kinerja:
# portfolio.py
.. # Other imports
from performance import create_sharpe_ratio, create_drawdowns
Karena Portfolio adalah kelas dasar abstrak kita ingin melampirkan metode ke salah satu kelas turunan, yang dalam hal ini akan NaivePortfolio. Oleh karena itu kita akan membuat metode yang disebut output_summary_stats yang akan bertindak pada kurva ekuitas portofolio untuk menghasilkan informasi Sharpe dan penarikan.
Metode ini sederhana. hanya menggunakan dua ukuran kinerja dan menerapkannya langsung ke kurva ekuitas panda DataFrame, output statistik sebagai daftar tuples dengan cara yang ramah format:
# 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
Jelas ini adalah analisis kinerja yang sangat sederhana untuk portofolio. tidak mempertimbangkan analisis tingkat perdagangan atau ukuran risiko / imbalan lainnya.performance.pydan kemudian menggabungkannya ke output_summary_stat seperti yang diperlukan.