Dobbiamo calcolare un portafoglio costantemente ribilanciato di 2 titoli. Li chiamiamo A e B. Entrambi avranno una parte uguale del portafoglio. Quindi se avessi 100 $ nel mio portafoglio 50 $ investiremo in A e 50 $ in B. Dato che entrambe le azioni hanno performance molto diverse, non manterranno i loro pesi uguali (dopo 3 mesi già A potrebbe valere 70 $ mentre B sceso a 45 $). Il problema è che devono mantenere la loro quota del portafoglio entro una certa larghezza di banda di tolleranza. Questa larghezza di banda è del 5%. Quindi ho bisogno di una funzione che: Se A> B * 1.05 o A * 1.05 < B, riequilibrare.Riequilibrio del portafoglio con il metodo della larghezza di banda in python
Questa prima parte serve solo per ottenere il modo più veloce di alcuni dati per avere una base comune di discussione e per rendere i risultati comparabili, così appena è possibile copiare e incollare tutto questo codice e funziona per voi ..
import pandas as pd
from datetime import datetime
import numpy as np
df1 = pd.io.data.get_data_yahoo("IBM",
start=datetime(1970, 1, 1),
end=datetime.today())
df1.rename(columns={'Adj Close': 'ibm'}, inplace=True)
df2 = pd.io.data.get_data_yahoo("F",
start=datetime(1970, 1, 1),
end=datetime.today())
df2.rename(columns={'Adj Close': 'ford'}, inplace=True)
df = df1.join(df2.ford, how='inner')
del df["Open"]
del df["High"]
del df["Low"]
del df["Close"]
del df["Volume"]
Ora inizia a calcolare la performance relativa di ogni stock con la formula: df.ibm/df.ibm[0]. Il problema è che non appena interrompiamo la prima larghezza di banda, dobbiamo reimpostare lo 0 nella nostra formula: df.ibm/df.ibm[0], dal momento che ribilanciamo e dobbiamo iniziare a calcolare da quel momento in poi. Quindi usiamo df.d per questa funzione segnaposto e lo impostiamo uguale a df.t non appena una larghezza di banda viene interrotta df.t fondamentalmente conta solo la lunghezza del dataframe e può dirci quindi sempre "dove siamo". Quindi, ecco il calcolo effettivo inizio:
tol = 0.05 #settintg the bandwidth tolerance
df["d"]= 0 #
df["t"]= np.arange(len(df))
tol = 0.3
def flex_relative(x):
if df.ibm/df.ibm.iloc[df.d].values < df.ford/df.ford.iloc[df.d].values * (1+tol):
return df.iloc[df.index.get_loc(x.name) - 1]['d'] == df.t
elif df.ibm/df.ibm.iloc[df.d].values > df.ford/df.ford.iloc[df.d].values * (1+tol):
return df.iloc[df.index.get_loc(x.name) - 1]['d'] == df.t
else:
return df.ibm/df.ibm.iloc[df.d].values, df.ford/df.ford.iloc[df.d].values
df["ibm_performance"], df["ford_performance"], = df.apply(flex_relative, axis =1)
Il problema è che sto ottenendo questo errore formare l'ultima riga di codice, dove cerco di applicare la funzione con df.apply(flex_relative, axis =1)
ValueError: ('The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().', u'occurred at index 1972-06-01 00:00:00')
Il problema è che nessuno delle opzioni date della dichiarazione di errore risolve il mio problema, quindi davvero non so cosa fare ...
L'unica cosa che ho trovato finora è stato il collegamento sottostante, ma chiamare una funzione R non funzionerà per me perché ho bisogno di applicarlo a dataset piuttosto grandi e posso anche implementare un'ottimizzazione in questa funzione, s o ha sicuramente bisogno di essere costruito in python. Ecco il link in ogni caso: Finance Lib with portfolio optimization method in python
manualmente (ciò che non è un buon modo per gestire dati di grandi dimensioni), ho calcolato che la prima data per un riequilibrio potrebbe essere: 03.11.1972 00:00:00
L'uscita del dataframe alla prima il ribilanciamento dovrebbe assomigliare a questo:
ibm ford d t ibm_performance ford_performance
1972-11-01 00:00:00 6,505655 0,387415 0 107 1,021009107 0,959552418
1972-11-02 00:00:00 6,530709 0,398136 0 108 1,017092172 0,933713605
1972-11-03 00:00:00 6,478513 0,411718 0 109 1,025286667 0,902911702 # this is the day, the rebalancing was detected
1972-11-06 00:00:00 6,363683 0,416007 109 110 1,043787536 0,893602752 # this is the day the day the rebalancing is implemented, therefore df.d gets set = df.t = 109
1972-11-08 00:00:00 6,310883 0,413861 109 111 1,052520384 0,898236364
1972-11-09 00:00:00 6,227073 0,422439 109 112 1,066686226 0,879996875
Grazie mille per il vostro supporto!
@Alexander: Sì, il ribilanciamento avverrà il giorno successivo.
@maxymoo: se si implementa questo codice dopo il proprio, si ottiene il peso del portafoglio di ogni stock e non si fermano tra il 45 e il 55%. È piuttosto tra il 75% e il 25%:
df["ford_weight"] = df.ford_prop*df.ford/(df.ford_prop*df.ford+df.ibm_prop*df.ibm) #calculating the actual portfolio weights
df["ibm_weight"] = df.ibm_prop*df.ibm/(df.ford_prop*df.ford+df.ibm_prop*df.ibm)
print df
print df.ibm_weight.min()
print df.ibm_weight.max()
print df.ford_weight.min()
print df.ford_weight.max()
ho provato non per un'ora o così da risolvere, ma non lo ha trovato.
Posso fare qualcosa per chiarire questa domanda?
Dato che si sta utilizzando solo il ciclo prossima, posso presumo che la regola è quella di riequilibrare il giorno successivo se i vostri pesi sono al di fuori della tolleranza (O semplicemente per scontato si può riequilibrare a distanza, se il prezzo di chiusura adj potrebbe far sì che i tuoi pesi siano al di fuori della tolleranza?). – Alexander