In früheren Beiträgen habe ich gezeigt, wie Aktienkursdaten mit pandas_datareader in Python heruntergeladen werden können – direkt aus Python.
In diesem Beitrag werde ich einen Algorithmus vorstellen mit dem Sie ein effizientes Portfolio basierend auf einer Reihe von Aktien erstellen können, die Sie möglicherweise in Betracht ziehen. Der Algorithmus ermittelt den optimalen Anteil jeder Aktie in Ihrem Portfolio auf der Grundlage des Risikos, das Sie sicher eingehen.
Genauer gesagt werde ich eine Methode zur Visualisierung der effizienten Grenze von Portfolios vorstellen, die aus einem bestimmten Satz von Aktien bestehen. In diesem Beispiel werde ich mit den folgenden 8 Aktien arbeiten, die alle Speditionen sind:
- Yamato Holdings (YATRY)
- Knight-Swift Transportation Holdings (KNX)
- BEST (BEST)
- YRC Worldwide (YRCW)
- Schneider National (SNDR)
- Old Dominion Freight Line (ODFL)
- Arc Best (ARCB)
- Werner Enterprises (WERN)
Das Risiko wird als Standardabweichung der historischen Renditen gemessen. Die Rendite wird als durchschnittliche historische tägliche Aktienrendite (unter Verwendung der Schlusskurse) gemessen.
Ich beginne mit dem Import einiger relevanter Module in Python:
# relevante Module importieren import pandas as pd import numpy as np import pandas_datareader.data as web import datetime import matplotlib.pyplot as plt import statistics as stat import random as rnd from matplotlib.ticker import StrMethodFormatter
Ich möchte historische Aktienkursdaten für die letzten 6 Monate sammeln. Im Folgenden gebe ich das Start- und Enddatum des relevanten Zeitraums an, um Daten zu sammeln von:
# Geben Sie das relevante Start- und Enddatum für den Erfassungszeitraum der Aktienkursdaten an start_date = datetime.datetime(2020,4,1) end_date = datetime.datetime(2020,9,30)
Als Nächstes definiere ich eine Hilfsfunktion die einen von Yahoo Finance über pandas_datareader gesammelten Aktienkursdatenrahmen aufnimmt und in tägliche Renditen transformiert:
# Funktion definieren, die eine Liste der täglichen Rückgaben zurückgibt
def returns(df):
prices = df["Close"]
returns = [0 if i == 0 else (prices[i]-prices[i-1])/(prices[i-1]) for i in range(0,len(prices))]
return(returns)
Jetzt definiere ich eine weitere Hilfsfunktion. Diese Funktion nimmt eine Liste von Aktien-Ticks auf und berechnet deren durchschnittliche tägliche Rendite sowie die dazugehörige Standardabweichung. Diese Funktion verwendet pandas_datareader um Aktienkursdaten von Yahoo abzufragen:
# Funktion definieren, die einen Datenrahmen mit Standardabweichungen und durchschnittlichen täglichen Erträgen erstellen kann
def analyzeStocks(tickersArr,start_date,end_date):
# Leere Datenrahmenvorlage erstellen
index = ["ticker","return","stdev"]
muArr = []
sigmaArr = []
# Durchlaufe alle Ticker
for i in range(0,len(tickersArr)):
# Ticker zur Tabelle hinzufügen
tick = tickersArr[i]
# Aktienkursdaten abrufen
data = web.DataReader(tickersArr[i],"yahoo",start_date,end_date)
# Berechne die durchschnittliche tägliche Rendite
muArr.append(stat.mean(returns(data)))
# Standardabweichung berechnen
sigmaArr.append(stat.stdev(returns(data)))
# einen Datenrahmen zurückgeben
return(pd.DataFrame(np.array([tickersArr, muArr, sigmaArr]),index=index,columns=tickersArr))
In diesem Beitrag möchte ich die folgenden Ticker-Zeichen analysieren:
tickersArr = ["YATRY","KNX","BEST","YRCW","SNDR","ODFL","ARCB","WERN"]
Mit den obigen Tickern führe ich analyseStocks aus – um Aktienkursdaten abzurufen und die durchschnittliche Rendite und Standardabweichung zu berechnen.
base_df = analyzeStocks(tickersArr,start_date,end_date) base_df
| YATRY | KNX | BEST | YRCW | SNDR | ODFL | ARCB | WERN | |
|---|---|---|---|---|---|---|---|---|
| ticker | YATRY | KNX | BEST | YRCW | SNDR | ODFL | ARCB | WERN |
| return | 0.004653743523196298 | 0.0023175179239564793 | -0.0034124339485902665 | 0.011159199755783849 | 0.002462051717055063 | 0.003349259316178459 | 0.005861686829084918 | 0.0017903742321965712 |
| stdev | 0.02358463699374274 | 0.02114091659162514 | 0.031397841155750277 | 0.09455276239906354 | 0.019372571935633416 | 0.023305461738410294 | 0.037234069177970675 | 0.02237976138155402 |
Mit Matplotlib mache ich ein einfaches Streudiagramm der historischen Rendite gegenüber der historischen Volatilität:
plt.figure(figsize=(15,8))
muArr = [float(i) for i in base_df.iloc[1,]]
sigmaArr = [float(i) for i in base_df.iloc[2,]]
sharpeArr = [muArr[i]/sigmaArr[i] for i in range(0,len(muArr))]
plt.scatter(sigmaArr,muArr,c=sharpeArr,cmap="plasma")
plt.title("Historical avg. returns vs. standard deviations [single stocks]",size=22)
plt.xlabel("Standard deviation",size=14)
plt.ylabel("Avg. daily return",size=14)
Text(0, 0.5, 'Avg. daily return')

Jetzt definiere ich eine Portfolioaufbaufunktion. Die Funktion erstellt eine definierte Anzahl von Portfolios mit zufällig zugewiesenen Aktiengewichtungen. Die daraus resultierende erwartete Rendite und Standardabweichung wird in Form eines Pandas-Datenrahmens zurückgegeben:
# Funktion zum Erstellen einer definierten Anzahl von Portfolios definieren
def portfolioBuilder(n,tickersArr,start_date,end_date):
muArr = []
sigmaArr = []
dailyreturnsArr = []
weightedreturnsArr = []
portfoliodailyreturnsArr = []
# tägliche Renditen ausfüllen
for i in range(0,len(tickersArr)):
data = web.DataReader(tickersArr[i],"yahoo",start_date,end_date)
dailyreturnsArr.append(returns(data))
# n verschiedene Portfolios erstellen
for i in range(0,n):
# tägliche Portfolio-Liste zurücksetzen
portfoliodailyreturnsArr = []
# Portfoliogewicht erstellen
weightsArr = [rnd.uniform(0,1) for i in range(0,len(tickersArr))]
nweightsArr = [i/sum(weightsArr) for i in weightsArr]
# Gewicht die täglichen Renditen
for j in range(0,len(dailyreturnsArr[0])):
temp = 0
for k in range(0,len(tickersArr)):
temp = temp + float(dailyreturnsArr[k][j])*float(nweightsArr[k])
portfoliodailyreturnsArr.append(temp)
# Berechnen und Anhängen der täglichen gewichteten Portfoliorenditen
muArr.append(stat.mean(portfoliodailyreturnsArr))
# Berechnen und Anhängen der Standardabweichung der täglichen Renditen des gewichteten Portfolios
sigmaArr.append(stat.stdev(portfoliodailyreturnsArr))
# erwartete Renditen und Standardabweichung für die erstellten Portfolios zurückgeben
return([sigmaArr,muArr])
Ich wende die Funktion an um 500000 zufällige Portfolios basierend auf den angegebenen Ticker-Symbolen zu erzeugen. Die Visualisierung erfolgt mittels Matplotlib.pyplot:
portfoliosArr = portfolioBuilder(500000,tickersArr,start_date,end_date)
plt.figure(figsize=(15,8))
muArr = [float(portfoliosArr[1][i]) for i in range(0,len(portfoliosArr[1]))]
sigmaArr = [float(portfoliosArr[0][i]) for i in range(0,len(portfoliosArr[0]))]
sharpeArr = [muArr[i]/sigmaArr[i] for i in range(0,len(muArr))]
plt.scatter(sigmaArr,muArr,c=sharpeArr,cmap="plasma")
plt.title("Historical avg. returns vs. standard deviations [single stocks]",size=22)
plt.colorbar(label="Sharpe ratio")
plt.xlabel("Standard deviation",size=14)
plt.ylabel("Avg. daily returns",size=14)
Text(0, 0.5, 'Avg. daily returns')

Mit dieser Graphik kann ein Analyst überprüfen ob dessen aktuelle Auswahl an Aktiengewichtungen für die ausgewählten Aktien derzeit effizient ist. Effiziente Portfolios befinden sich entlang der oberen Linie in dem Streudiagramm.

Wirtschaftsingenieur mit Interesse an Optimierung, Simulation und mathematischer Modellierung in R, SQL, VBA und Python

Leave a Reply