这里的主要思想是根据美元而不是比率来工作。如果您跟踪ibm和福特股票的数量以及相对美元价值,则可以将重新平衡的标准表示为
mask = (df['ratio'] >= 1+tol) | (df['ratio'] <= 1-tol)
比率等于
df['ratio'] = df['ibm value'] / df['ford value']
和df['ibm value']
,df['ford value']
代表实际美元价值。
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])