Portfolio rebalancing with bandwidth method in python

后端 未结 4 1823
走了就别回头了
走了就别回头了 2020-12-16 03:03

We need to calculate a continuously rebalanced portfolio of 2 stocks. Lets call them A and B. They shall both have an equal part of the portfolio. So if I have 100$ in my po

相关标签:
4条回答
  • 2020-12-16 03:28

    just a mathematical improvement on maxymoo's answer:

    i = df.index[0]
    df['ibm_prop'] = df.ibm.ix[i]/(df.ibm.ix[i]+df.ford.ix[i])
    df['ford_prop'] = df.ford.ix[i]/(df.ibm.ix[i]+df.ford.ix[i])
    
    while i:
       try:
          i =  df[abs((df.ibm_prop*df.ibm - df.ford_prop*df.ford)) > tol].index[0]
       except IndexError:
          break
       df['ibm_prop'].ix[i:] = df.ibm.ix[i]/(df.ibm.ix[i]+df.ford.ix[i])
       df['ford_prop'].ix[i:] = df.ford.ix[i]/(df.ibm.ix[i]+df.ford.ix[i])
    
    0 讨论(0)
  • 2020-12-16 03:31

    The main idea here is to work in terms of dollars instead of ratios. If you keep track of the number of shares and the relative dollar values of the ibm and ford shares, then you can express the criterion for rebalancing as

    mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
    

    where the ratio equals

        df['ratio'] = df['ibm value'] / df['ford value']
    

    and df['ibm value'], and df['ford value'] represent actual dollar values.


    import datetime as DT
    import numpy as np
    import pandas as pd
    import pandas.io.data as PID
    
    def setup_df():
        df1 = PID.get_data_yahoo("IBM", 
                                 start=DT.datetime(1970, 1, 1), 
                                 end=DT.datetime.today())
        df1.rename(columns={'Adj Close': 'ibm'}, inplace=True)
    
        df2 = PID.get_data_yahoo("F", 
                                 start=DT.datetime(1970, 1, 1), 
                                 end=DT.datetime.today())
        df2.rename(columns={'Adj Close': 'ford'}, inplace=True)
    
        df = df1.join(df2.ford, how='inner')
        df = df[['ibm', 'ford']]
        df['sh ibm'] = 0
        df['sh ford'] = 0
        df['ibm value'] = 0
        df['ford value'] = 0
        df['ratio'] = 0
        return df
    
    def invest(df, i, amount):
        """
        Invest amount dollars evenly between ibm and ford
        starting at ordinal index i.
        This modifies df.
        """
        c = dict([(col, j) for j, col in enumerate(df.columns)])
        halfvalue = amount/2
        df.iloc[i:, c['sh ibm']] = halfvalue / df.iloc[i, c['ibm']]
        df.iloc[i:, c['sh ford']] = halfvalue / df.iloc[i, c['ford']]
    
        df.iloc[i:, c['ibm value']] = (
            df.iloc[i:, c['ibm']] * df.iloc[i:, c['sh ibm']])
        df.iloc[i:, c['ford value']] = (
            df.iloc[i:, c['ford']] * df.iloc[i:, c['sh ford']])
        df.iloc[i:, c['ratio']] = (
            df.iloc[i:, c['ibm value']] / df.iloc[i:, c['ford value']])
    
    def rebalance(df, tol, i=0):
        """
        Rebalance df whenever the ratio falls outside the tolerance range.
        This modifies df.
        """
        c = dict([(col, j) for j, col in enumerate(df.columns)])
        while True:
            mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
            # ignore prior locations where the ratio falls outside tol range
            mask[:i] = False
            try:
                # Move i one index past the first index where mask is True
                # Note that this means the ratio at i will remain outside tol range
                i = np.where(mask)[0][0] + 1
            except IndexError:
                break
            amount = (df.iloc[i, c['ibm value']] + df.iloc[i, c['ford value']])
            invest(df, i, amount)
        return df
    
    df = setup_df()
    tol = 0.05
    invest(df, i=0, amount=100)
    rebalance(df, tol)
    
    df['portfolio value'] = df['ibm value'] + df['ford value']
    df['ibm weight'] = df['ibm value'] / df['portfolio value']
    df['ford weight'] = df['ford value'] / df['portfolio value']
    
    print df['ibm weight'].min()
    print df['ibm weight'].max()
    print df['ford weight'].min()
    print df['ford weight'].max()
    
    # This shows the rows which trigger rebalancing
    mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
    print(df.loc[mask])
    
    0 讨论(0)
  • 2020-12-16 03:34

    What about this:

    df["d"]= [0,0,0,0,0,0,0,0,0,0]
    df["t"]= np.arange(len(df))
    tol = 0.05
    
    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
    
    0 讨论(0)
  • 2020-12-16 03:45

    You can use this code to calulate your portfolio at each point in time.

    i = df.index[0]
    df['ibm_prop'] = 0.5/df.ibm.ix[i]
    df['ford_prop'] = 0.5/df.ford.ix[i]
    
    while i:
       try:
          i =  df[abs(1-(df.ibm_prop*df.ibm + df.ford_prop*df.ford)) > tol].index[0]
       except IndexError:
          break
       df['ibm_prop'].ix[i:] = 0.5/df.ibm.ix[i]
       df['ford_prop'].ix[i:] = 0.5/df.ford.ix[i]
    
    0 讨论(0)
提交回复
热议问题