Продукт Pandas dot с мультииндексом
Моя проблема довольно распространена в финансах.
Учитывая массив весов w (1xN) и ковариационную матрицу Q (NxN) активов, можно рассчитать ковариацию портфеля, используя квадратное выражение w' * Q * w, где * - это точечный продукт.
Я хочу понять, как лучше всего выполнить эту операцию, когда у меня есть история весов W (T x N) и трехмерная структура для ковариационной матрицы (T, N, N).
import numpy as np
import pandas as pd
returns = pd.DataFrame(0.1 * np.random.randn(100, 4), columns=['A', 'B', 'C', 'D'])
covariance = returns.rolling(20).cov()
weights = pd.DataFrame(np.random.randn(100, 4), columns=['A', 'B', 'C', 'D'])
Мое решение до сих пор заключалось в том, чтобы преобразовать панды DataFrames в numpy, выполнить вычисления, выполнив цикл, а затем преобразовать обратно в панд. Обратите внимание, что мне нужно явно проверить выравнивание меток, поскольку в действительности ковариация и веса могут быть рассчитаны различными процессами.
cov_dict = {key: covariance.xs(key, axis=0, level=0) for key in covariance.index.get_level_values(0)}
def naive_numpy(weights, cov_dict):
expected_risk = {}
# Extract columns, index before passing to numpy arrays
# Columns
cov_assets = cov_dict[next(iter(cov_dict))].columns
avail_assets = [el for el in cov_assets if el in weights]
# Indexes
cov_dates = list(cov_dict.keys())
avail_dates = weights.index.intersection(cov_dates)
sel_weights = weights.loc[avail_dates, avail_assets]
# Main loop and calculation
for t, value in zip(sel_weights.index, sel_weights.values):
expected_risk[t] = np.sqrt(np.dot(value, np.dot(cov_dict[t].values, value)))
# Back to pandas DataFrame
expected_risk = pd.Series(expected_risk).reindex(weights.index).sort_index()
return expected_risk
Есть ли способ чистой панды для достижения того же результата? Или есть ли улучшения в коде, чтобы сделать его более эффективным? (несмотря на использование NumPy, это все еще довольно медленно).
0 ответов
Я думаю, что NumPy определенно лучший вариант. Хотя вы теряете эту эффективность, если зацикливаетесь на значениях / датах.
Мое предложение для расчета скользящей волатильности портфеля (без зацикливания):
returns = pd.DataFrame(0.1 * np.random.randn(100, 4), columns=['A', 'B', 'C', 'D'])
covariance = returns.rolling(20).cov()
weights = pd.DataFrame(np.random.randn(100, 4), columns=['A', 'B', 'C', 'D'])
rows, columns = weights.shape
# Go to numpy:
w = weights.values
cov = covariance.values.reshape(rows, columns, columns)
A = np.matmul(w.reshape(rows, 1, columns), cov)
var = np.matmul(A, w.reshape(rows, columns, 1)).reshape(rows)
std_dev = np.sqrt(var)
# Back to pandas (in case you want that):
pd.Series(std_dev, index = weights.index)