Portfoliooptimierung mit Python (Markovitz-Durchschnittsverteilungsmodell)

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:

Erfassung von Aktienkursdaten

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. hoge.png

Erstellen Sie Paneldaten für das Zielobjekt

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.

Markovitz 'mittleres Varianzmodell und seine Lösung

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.

Markowitz-Durchschnittsdispersionsmodell

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.

\begin{align} \underset{\bf x}{\rm minimize} ~~~ &{\bf x}^T \Sigma {\bf x} \\\ {\rm subject~to} ~~~ &{\bf r}^T {\bf x} = \sum_{i=1}^{n} r_i x_i \geq r_e \\\ &{\|\| {\bf x} \|\|}\_{1} = \sum_{i=1}^{n} x_i = 1 \\\ &x_i \geq 0 ~~ (i = 1, \cdots, n) \end{align}

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.

Verwendung von CVXOPT

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.

\begin{align} \underset{\bf x}{\rm minimize} ~~~ &\frac{1}{2} {\bf x}^{T} P {\bf x} + {\bf q}^{T} {\bf x} \\\ {\rm subject~to} ~~~ & G {\bf x} \leq {\bf h} \\\ &A {\bf x} = {\bf b} \end{align}

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 $ P = 2 \cdot \Sigma, ~~~ q = {\bf 0}, ~~~ G = - {\bf I}\_n, ~~~ h = - r_e, ~~~ A = {\bf 1}\_n^T, ~~~ b = 1 $ Es wird.

Referenz:

In Python berechnet

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!

Recommended Posts

Portfoliooptimierung mit Python (Markovitz-Durchschnittsverteilungsmodell)
Harmonischer Mittelwert von Python (mit SciPy)
Bayesianische Optimierung, die mit Python sehr einfach ist
[Python] Gemischtes Gaußsches Modell mit Pyro
Erklärung des Produktionsoptimierungsmodells durch Python
Lösen wir das Portfolio mit kontinuierlicher Optimierung
Mit OR-Tools erlernte Optimierung [Lineare Planung: Mehrstufiges Modell]
[Python] Clustering mit einem unendlich gemischten Gaußschen Modell
Lösen des Lorenz 96-Modells mit Julia und Python
Python in der Optimierung
FizzBuzz in Python3
Scraping mit Python
Statistik mit Python
Scraping mit Python
Python mit Go
Twilio mit Python
In Python integrieren
Spielen Sie mit 2016-Python
AES256 mit Python
Getestet mit Python
Python beginnt mit ()
mit Syntax (Python)
Bingo mit Python
Zundokokiyoshi mit Python
Excel mit Python
Mikrocomputer mit Python
Mit Python besetzen
Simulieren Sie ein gutes Weihnachtsdatum mit einem Python-optimierten Modell
Ich möchte die Optimierung mit Python und CPlex behandeln
Höchstwahrscheinlich Schätzung des Mittelwerts und der Varianz mit TensorFlow
[# 2] Mach Minecraft mit Python. ~ Modellzeichnung und Player-Implementierung ~
Berechnen Sie den Mittelwert, den Median, die häufigste Varianz und die Standardabweichung in Python
COVID-19-Simulation mit Python (SIR-Modell) ~~ mit Präfektur-Wärmekarte ~~
Lernen Sie Wasserstein GAN mit Keras-Modell und TensorFlow-Optimierung