Dies ist eine Zusammenfassung der Tipps zum Backtesting mit Python. Lassen Sie uns die mühsame Vorverarbeitung schnell beenden und uns auf die Erstellung eines Modells konzentrieren! Das ist der Zweck. Obwohl in diesem Artikel nicht vorgestellt, können Sie verschiedene Portfolio-Auswahlmodelle wie das Multi-Faktor-Modell ausprobieren, da Sie mit "pandas-datareader" Makrodaten abrufen können.
Overview:
Installieren Sie zuerst "pandas-datareader" in Ihrer Umgebung.
pandas-datareader
ist ein praktisches Python-Paket (mit pandas.Dataframe-freundlich), mit dem Sie Marktdaten wie Aktienkurse über die Web-API herunterladen können. IEX, Weltbank, OECD, Yahoo! Finanzen, FRED, [Stooq] Sie können die im Python-Code erfassten Daten lesen, indem Sie intern auf eine API wie (https://stooq.com/q/?s=usdkrw) klicken. Weitere Informationen zur Verwendung finden Sie in Offizielles Dokument.
# Install pandas-datareader (latest version)
pip install git+https://github.com/pydata/pandas-datareader.git
# Or install pandas-datareader (stable version)
pip install pandas-datareader
Diesmal sind die Zielprodukte Aktien, die an der Tokyo Stock Exchange (TSE) notiert sind. Die meisten im Internet veröffentlichten Daten befinden sich auf dem US-Markt, aber Polens stärkste Website stooq.com ist Tokyo Securities Trading. Die vergangenen Daten des Ortes sind öffentlich zugänglich. Verwenden Sie "pandas-datareader", um individuelle Markendaten von stooq abzurufen.
Grundsätzlich können Sie pandas_datareader.stooq.StooqDailyReader ()
ausführen. Geben Sie für die Argumente den in jedem Markt registrierten Wertpapiercode (oder das Tickersymbol) und die Website (Yahoo! Stooq, ...) der Datenoffenlegungsquelle an.
Den von der Tokioter Börse gehandhabten Aktien wird ein 4-stelliger Wertpapiercode zugewiesen, daher werden wir diesen diesmal verwenden. (Beispiel: Toyota Motor ist eine Aktie, deren Wertpapiercode an der TSE ** 7203 ** lautet. In der NYSE wird das Tickersymbol als Aktie mit ** TM ** gehandelt.)
Lassen Sie uns als Test die Aktienkursdaten der Toyota Motor Corporation (TSE: 7203) abrufen und grafisch darstellen.
import datetime
import pandas_datareader
start = datetime.datetime(2015, 1, 1)
end = datetime.datetime(2020, 11, 30)
stockcode = "7203.jp" # Toyota Motor Corporation (TM)
df = pandas_datareader.stooq.StooqDailyReader(stockcode, start, end).read()
df = df.sort_values(by='Date',ascending=True)
display(df) # Show dataframe
-----
Open High Low Close Volume
Date
2015-01-05 6756.50 6765.42 6623.43 6704.69 10653925
2015-01-06 6539.48 6601.09 6519.83 6519.83 13870266
2015-01-07 6480.52 6685.05 6479.64 6615.40 12837377
2015-01-08 6698.46 6748.46 6693.98 6746.69 11257646
2015-01-09 6814.56 6846.70 6752.92 6795.80 11672928
... ... ... ... ... ...
2020-11-04 7024.00 7054.00 6976.00 6976.00 6278100
2020-11-05 6955.00 7032.00 6923.00 6984.00 5643400
2020-11-06 7070.00 7152.00 7015.00 7019.00 11092900
2020-11-09 7159.00 7242.00 7119.00 7173.00 7838600
2020-11-10 7320.00 7360.00 7212.00 7267.00 8825700
Tägliche Aktienkursübergangsdaten wurden als pandas.Dataframe erfasst!
Lassen Sie uns den Inhalt des gerade erstellten df
zeichnen. (Grundsätzlich den Schlusskurs verwenden)
# Plot timeseries (2015/1/1 - 2020/11/30)
plt.figure(figsize=(12,8))
plt.plot(df.index, df["Close"].values)
plt.show()
Wie in der folgenden Abbildung gezeigt, kann der Übergang des Schlusskurses (Schlusskurs) leicht dargestellt werden.
Erstellen Sie zur Vorbereitung des Problems der Portfoliooptimierung Paneldaten für mehrere Assets (Aktien) und organisieren Sie diese als pandas.Dataframe-Objekt.
Dieses Mal werden wir 5 in TOPIX 500 gelistete Aktien auswählen und als Anlagezielvermögen verwenden. Zusätzlich wird als Vorverarbeitung "Schlusskurs" in "Schlusskurs-basierte Gewinnrate" umgewandelt. Bitte ändern Sie den Code in diesem Teil entsprechend der Situation.
import datetime
import numpy as np
import pandas as pd
import pandas_datareader.data as web
import pandas_datareader.stooq as stooq
def get_stockvalues_tokyo(stockcode, start, end, use_ratio=False):
"""
stockcode: market code of each target stock (ex. "NNNN") defined by the Tokyo stock market.
start, end: datetime object
"""
# Get index data from https://stooq.com/
df = stooq.StooqDailyReader(f"{stockcode}.jp", start, end).read()
df = df.sort_values(by='Date',ascending=True)
if use_ratio:
df = df.apply(lambda x: (x - x[0]) / x[0] )
return df
def get_paneldata_tokyo(stockcodes, start, end, use_ratio=False):
# Use "Close" value only
dfs = []
for sc in stockcodes:
df = get_stockvalues_tokyo(sc, start, end, use_ratio)[['Close']]
df = df.rename(columns={'Close': sc})
dfs.append(df)
df_concat = pd.concat(dfs, axis=1)
return df_concat
Erstellen Sie Paneldaten mit get_paneldata_tokyo ().
start = datetime.datetime(2015, 1, 1)
end = datetime.datetime(2020, 11, 30)
stockcodes=["1301", "1762", "1820", "1967", "2127"]
df = get_paneldata_tokyo(stockcodes, start, end, use_ratio=True)
display(df) # return ratio daily
-----
1301 1762 1820 1967 2127
Date
2015-01-05 0.000000 0.000000 0.000000 0.000000 0.000000
2015-01-06 -0.010929 -0.018385 -0.033937 -0.002265 -0.038448
2015-01-07 -0.014564 -0.020433 -0.059863 -0.013823 -0.059680
2015-01-08 -0.007302 -0.016338 -0.057883 -0.013823 -0.039787
2015-01-09 0.000000 -0.004490 -0.031938 -0.025407 -0.043770
... ... ... ... ... ...
2020-10-29 0.096138 -0.032923 -0.030777 0.858573 5.682321
2020-10-30 0.093336 -0.039657 -0.041199 0.832831 5.704266
2020-11-02 0.107748 -0.026188 -0.032198 0.845702 5.418978
2020-11-04 0.099341 -0.024392 -0.020829 0.858573 5.704266
2020-11-05 0.069315 -0.014964 -0.042147 0.904909 6.055390
Damit wurden die Paneldaten jedes zu bewertenden Vermögenswerts erfasst.
Die Festlegung einer angemessenen Investitionsquote für mehrere zu investierende Vermögenswerte wird als ** Portfoliooptimierung ** bezeichnet. Dieses Mal werden wir das von Markowitz vorgeschlagene ** Mean-Varianz-Modell ** als grundlegendste Problemeinstellung für die Portfoliooptimierung verwenden.
Im durchschnittlichen Diversifikationsmodell von Markowitz betrachten wir ein Optimierungsproblem, das "die Portfoliodiversifikation minimiert", unter der Bedingung, dass "die erwartete Rendite des Portfolios über einem bestimmten Wert liegt".
Im Allgemeinen ist für ein Portfolio, das aus $ n $ co-Vermögenswerten besteht, die Diversifikation des Portfolios eine quadratische Form der Kovarianzmatrix zwischen den $ n $ co-Vermögenswerten, sodass dieses Optimierungsproblem quadratisch ist Es wird eine Klasse der Programmierung (QP) und wird wie folgt formuliert.
Die erste Beschränkungsformel erfordert, dass die erwartete Rendite des Portfolios größer oder gleich einem bestimmten Wert ist ($ = r_e $). Die zweite und dritte Einschränkungsformel sind aus der Definition des Portfolios selbsterklärend. Wenn Sie leere Verkäufe von Assets zulassen, möchten Sie möglicherweise die dritte Einschränkung entfernen.
Dieses sekundäre Planungsproblem (QP) wird mit dem konvexen Optimierungspaket [CVXOPT] von Python (https://cvxopt.org) gelöst. Wenn Sie sekundäre Planungsprobleme mit CVXOPT behandeln, organisieren Sie die Optimierungsprobleme, die Sie lösen möchten, in das folgende allgemeine Format.
Berechnen Sie die Parameter "P", "q", "G", "h", "A" und führen Sie die Funktion "cvxopt.solvers.qp ()" aus, um die optimale Lösung und den optimalen Wert zu finden. Für Markowitz 'mittleres / verteiltes Modell
Referenz:
Berechnen Sie die erforderlichen Statistiken aus den Paneldaten "df" des Zielobjekts.
Kovarianzmatrix zwischen Vermögenswerten im Portfolio $ \ Sigma $:
df.cov() # Covariance matrix
-----
1301 1762 1820 1967 2127
1301 0.024211 0.015340 0.018243 0.037772 0.081221
1762 0.015340 0.014867 0.015562 0.023735 0.038868
1820 0.018243 0.015562 0.025023 0.029918 0.040811
1967 0.037772 0.023735 0.029918 0.109754 0.312827
2127 0.081221 0.038868 0.040811 0.312827 1.703412
Erwartete Rendite für jeden Vermögenswert im Portfolio $ {\ bf r} $:
df.mean().values # Expected returns
-----
array([0.12547322, 0.10879767, 0.07469455, 0.44782516, 1.75209493])
Lösen Sie das Optimierungsproblem mit CVXOPT.
import cvxopt
def cvxopt_qp_solver(r, r_e, cov):
# CVXOPT QP Solver for Markowitz' Mean-Variance Model
# See https://cvxopt.org/userguide/coneprog.html#quadratic-programming
# See https://cdn.hackaday.io/files/277521187341568/art-mpt.pdf
n = len(r)
r = cvxopt.matrix(r)
P = cvxopt.matrix(2.0 * np.array(cov))
q = cvxopt.matrix(np.zeros((n, 1)))
G = cvxopt.matrix(np.concatenate((-np.transpose(r), -np.identity(n)), 0))
h = cvxopt.matrix(np.concatenate((-np.ones((1,1)) * r_e, np.zeros((n,1))), 0))
A = cvxopt.matrix(1.0, (1, n))
b = cvxopt.matrix(1.0)
sol = cvxopt.solvers.qp(P, q, G, h, A, b)
return sol
r = df.mean().values # Expected returns
r_e = 1.45 * # Lower bound for portfolio's return
cov = df.cov() # Covariance matrix
# Solve QP and derive optimal portfolio
sol = cvxopt_qp_solver(r, r_e, cov)
x_opt = np.array(sol['x'])
print(x_opt)
print("Variance (x_opt) :", sol["primal objective"])
-----
pcost dcost gap pres dres
0: 4.3680e-03 -8.6883e-02 5e+00 2e+00 2e+00
1: 9.1180e-02 -2.2275e-01 5e-01 1e-01 1e-01
2: 2.1337e-02 -6.0274e-02 8e-02 2e-16 1e-16
3: 1.0483e-02 -1.7810e-03 1e-02 1e-16 3e-17
4: 4.9857e-03 1.5180e-03 3e-03 2e-16 8e-18
5: 4.0217e-03 3.6059e-03 4e-04 3e-17 1e-17
6: 3.7560e-03 3.7107e-03 5e-05 3e-17 1e-18
7: 3.7187e-03 3.7168e-03 2e-06 1e-17 4e-18
8: 3.7169e-03 3.7168e-03 2e-08 1e-16 6e-18
Optimal solution found.
[ 5.56e-05]
[ 1.00e+00]
[ 1.76e-05]
[ 3.84e-07]
[ 2.63e-07]
Variance (x_opt): 0.003716866155475511 #Optimale Portfoliodiversifikation
Die optimale Lösung (optimale Investitionsquote für jeden Vermögenswert) und der optimale Wert (Diversifizierung des Portfolios bei Anwendung der optimalen Investitionsquote) wurden erhalten. Die optimale Lösung basierend auf dem diesmal verwendeten durchschnittlichen Diversifikationsmodell wird als "minimales Diversifikationsportfolio" bezeichnet, da sie die Optimalität für das Risiko (Diversifikation) des Portfolios betont.
In vielen Fällen wird eine scharfe Quote, die die Gewinnrate (Inflationsrate) risikofreier Vermögenswerte berücksichtigt, als Bewertungsindex für die Gewinnrate verwendet. Es gibt verschiedene Möglichkeiten zum Backtest. Weitere Informationen finden Sie in den Fachbüchern und -papieren.
Vielen Dank für das Lesen bis zum Ende!