根据数量和价格调整股票投资组合的价格
Adjust prices on stock portfolio based on quantity and price
我正在尝试调整我的股票组合并尝试计算调整后的平均价格(这是加权平均的一种形式)。
这是示例数据:
import pandas as pd
import numpy as np
sample_dict = {'ticker': {1: 'ABCD',
2: 'ABCD', 3: 'ABCD', 4: 'ABCD', 5: 'ABCD', 6: 'ABCD', 8: 'EFGH',
9: 'EFGH', 10: 'EFGH', 11: 'EFGH', 12: 'EFGH', 13: 'EFGH'},
'Date': {1: "2018, 1, 10", 2: "2018, 1, 20",
3: "2018, 2, 7", 4: "2018, 4, 14",
5: "2018, 5, 25", 6: "2018, 7, 4",
8: "2018, 1, 10", 9: "2018, 1, 20",
10: "2018, 2, 7", 11: "2018, 4, 14",
12: "2018, 5, 25", 13: "2018, 7, 4"},
'Sell_buy': {1: 'buy', 2: 'buy', 3: 'sell', 4: 'buy', 5: 'sell', 6: 'buy',
8: 'buy', 9: 'buy', 10: 'buy', 11: 'buy', 12: 'sell', 13: 'sell'},
'Qtd': {1: 100.0, 2: 300.0, 3: 200.0, 4: 500.0, 5: 600.0, 6: 500.0,
8: 300.0, 9: 300.0, 10: 200.0, 11: 200.0, 12: 700.0, 13: 100.0},
'Price': {1: 8.0, 2: 10.0, 3: 12.0, 4: 9.0, 5: 13.0, 6: 14.0,
8: 8.0, 9: 10.0, 10: 12.0, 11: 9.0, 12: 13.0, 13: 14.0},
'Costs': {1: 10.93, 2: 12.52, 3: 11.39, 4: 14.5, 5: 14.68, 6: 14.96,
8: 10.93, 9: 12.52, 10: 11.39, 11: 14.5, 12: 14.68, 13: 14.96}}
sample_df = pd.DataFrame(sample_dict)
sample_df['Date']=pd.to_datetime(sample_df['Date'], dayfirst=True).dt.date
我能够毫无问题地获得更新的调整数量(基于买卖):
#to calculate adjusted quantity. this works as expected
sample_df['Adj Qtd'] = sample_df.apply(lambda x: ((x.Sell_buy == "buy") - (x.Sell_buy == "sell")) * x['Qtd'], axis = 1)
sample_df['Adj Qtd'] = sample_df.groupby('ticker')['Adj Qtd'].cumsum()
但是,我无法获得正确的调整后价格。
这里的条件是,如果我卖出一只股票,我的调整后价格不应改变,并保持与买入该股票时的最后调整价格相同。
我尝试了以下方法来实现这个目标:
#Adjust Price. Works good until I reach the row where a sell was made
sample_df['Adjusted Price'] = sample_df.apply(lambda x: ((x.Sell_buy == "buy") - (x.Sell_buy == "sell")) * (x["Price"] * x["Qtd"] + x["Costs"]), axis = 1)
sample_df['Adjusted Price'] = sample_df.groupby('ticker')['Adjusted Price'].cumsum().div(sample_df['Adj Qtd'])
我可以通过以下方式部分更正卖出行的调整价格:
# When it's a "sell", adjusted price is the same from above
sample_df.loc[sample_df['Sell_buy'] == 'sell',['Adjusted Price']] = np.NaN
sample_df.fillna(method='ffill', inplace=True)
ticker Date Sell_buy Qtd Price Costs Adj Qtd Adjusted Price
1 ABCD 2018-10-01 buy 100.0 8.0 10.93 100.0 8.109300
2 ABCD 2018-01-20 buy 300.0 10.0 12.52 400.0 9.558625
3 ABCD 2018-07-02 sell 200.0 12.0 11.39 200.0 9.558625
4 ABCD 2018-04-14 buy 500.0 9.0 14.50 700.0 8.466514
5 ABCD 2018-05-25 sell 600.0 13.0 14.68 100.0 8.466514
6 ABCD 2018-04-07 buy 500.0 14.0 14.96 600.0 8.544733
8 EFGH 2018-10-01 buy 300.0 8.0 10.93 300.0 8.036433
9 EFGH 2018-01-20 buy 300.0 10.0 12.52 600.0 9.039083
10 EFGH 2018-07-02 buy 200.0 12.0 11.39 800.0 9.793550
11 EFGH 2018-04-14 buy 200.0 9.0 14.50 1000.0 9.649340
12 EFGH 2018-05-25 sell 700.0 13.0 14.68 300.0 9.649340
13 EFGH 2018-04-07 sell 100.0 14.0 14.96 200.0 9.649340
如果“买入”之间没有“卖出”(就像本例中股票 EFGH 所做的那样),这将非常有效。
需要明确的是,当交易是“卖出”时,我们必须忽略调整价格,并使用该特定股票最后一次买入类型交易中的最后调整价格。
我在 excel 中做了所有这些微积分,输出应该如下:
为了进一步说明,所选单元格的 excel 公式为:
=IF(C3="buy";(I2*G2+D3*E3+F3)/G3;IF(G3<>0;I2;0))
我也尝试过 .groupby("ticker").apply() 使用 shift() 的函数,以便使用上面行中的先前值,但我失败了。
我想不出一个好的、简单的解决方案。问题是计算调整后价格取决于调整后价格的先前值,这阻止了向量化或 shift() 的使用。
所以,这是丑陋的解决方案。 :)
第一步是使用 groupby,通过股票代码将其分开。然后,它遍历该组中的所有行,并计算价格的加权平均值以获得当前股票和之前的价格。然后,它将该列表添加为数据框中的一列。
def weighted_average(a, b, a_weight):
"""Take an average of a and b, with a weighted by a_weight"""
assert 0 <= a_weight <= 1
return a * a_weight + b * (1 - a_weight)
def get_adjusted_price_for_ticker(single_ticker_df):
adjusted_price = 0
current_shares = 0
prices = []
for _, row in single_ticker_df.iterrows():
is_buy = row["Sell_buy"] == "buy"
qtd = row["Qtd"]
if is_buy:
current_shares += qtd
cost_per_share = (qtd * row["Price"] + row["Costs"]) / qtd
proportion_of_new_shares = qtd / current_shares
adjusted_price = weighted_average(cost_per_share, adjusted_price, proportion_of_new_shares)
else:
current_shares -= qtd
prices.append(adjusted_price)
single_ticker_df["Adjusted Price"] = prices
return single_ticker_df
def get_adjusted_price(df):
return df.groupby("ticker").apply(get_adjusted_price_for_ticker)
get_adjusted_price(sample_df)
输出:
ticker Date Sell_buy Qtd Price Costs Adjusted Price
1 ABCD 2018-10-01 buy 100.0 8.0 10.93 8.109300
2 ABCD 2018-01-20 buy 300.0 10.0 12.52 9.558625
3 ABCD 2018-07-02 sell 200.0 12.0 11.39 9.558625
4 ABCD 2018-04-14 buy 500.0 9.0 14.50 9.180321
5 ABCD 2018-05-25 sell 600.0 13.0 14.68 9.180321
6 ABCD 2018-04-07 buy 500.0 14.0 14.96 13.221654
8 EFGH 2018-10-01 buy 300.0 8.0 10.93 8.036433
9 EFGH 2018-01-20 buy 300.0 10.0 12.52 9.039083
10 EFGH 2018-07-02 buy 200.0 12.0 11.39 9.793550
11 EFGH 2018-04-14 buy 200.0 9.0 14.50 9.649340
12 EFGH 2018-05-25 sell 700.0 13.0 14.68 9.649340
13 EFGH 2018-04-07 sell 100.0 14.0 14.96 9.649340
我正在尝试调整我的股票组合并尝试计算调整后的平均价格(这是加权平均的一种形式)。
这是示例数据:
import pandas as pd
import numpy as np
sample_dict = {'ticker': {1: 'ABCD',
2: 'ABCD', 3: 'ABCD', 4: 'ABCD', 5: 'ABCD', 6: 'ABCD', 8: 'EFGH',
9: 'EFGH', 10: 'EFGH', 11: 'EFGH', 12: 'EFGH', 13: 'EFGH'},
'Date': {1: "2018, 1, 10", 2: "2018, 1, 20",
3: "2018, 2, 7", 4: "2018, 4, 14",
5: "2018, 5, 25", 6: "2018, 7, 4",
8: "2018, 1, 10", 9: "2018, 1, 20",
10: "2018, 2, 7", 11: "2018, 4, 14",
12: "2018, 5, 25", 13: "2018, 7, 4"},
'Sell_buy': {1: 'buy', 2: 'buy', 3: 'sell', 4: 'buy', 5: 'sell', 6: 'buy',
8: 'buy', 9: 'buy', 10: 'buy', 11: 'buy', 12: 'sell', 13: 'sell'},
'Qtd': {1: 100.0, 2: 300.0, 3: 200.0, 4: 500.0, 5: 600.0, 6: 500.0,
8: 300.0, 9: 300.0, 10: 200.0, 11: 200.0, 12: 700.0, 13: 100.0},
'Price': {1: 8.0, 2: 10.0, 3: 12.0, 4: 9.0, 5: 13.0, 6: 14.0,
8: 8.0, 9: 10.0, 10: 12.0, 11: 9.0, 12: 13.0, 13: 14.0},
'Costs': {1: 10.93, 2: 12.52, 3: 11.39, 4: 14.5, 5: 14.68, 6: 14.96,
8: 10.93, 9: 12.52, 10: 11.39, 11: 14.5, 12: 14.68, 13: 14.96}}
sample_df = pd.DataFrame(sample_dict)
sample_df['Date']=pd.to_datetime(sample_df['Date'], dayfirst=True).dt.date
我能够毫无问题地获得更新的调整数量(基于买卖):
#to calculate adjusted quantity. this works as expected
sample_df['Adj Qtd'] = sample_df.apply(lambda x: ((x.Sell_buy == "buy") - (x.Sell_buy == "sell")) * x['Qtd'], axis = 1)
sample_df['Adj Qtd'] = sample_df.groupby('ticker')['Adj Qtd'].cumsum()
但是,我无法获得正确的调整后价格。 这里的条件是,如果我卖出一只股票,我的调整后价格不应改变,并保持与买入该股票时的最后调整价格相同。
我尝试了以下方法来实现这个目标:
#Adjust Price. Works good until I reach the row where a sell was made
sample_df['Adjusted Price'] = sample_df.apply(lambda x: ((x.Sell_buy == "buy") - (x.Sell_buy == "sell")) * (x["Price"] * x["Qtd"] + x["Costs"]), axis = 1)
sample_df['Adjusted Price'] = sample_df.groupby('ticker')['Adjusted Price'].cumsum().div(sample_df['Adj Qtd'])
我可以通过以下方式部分更正卖出行的调整价格:
# When it's a "sell", adjusted price is the same from above
sample_df.loc[sample_df['Sell_buy'] == 'sell',['Adjusted Price']] = np.NaN
sample_df.fillna(method='ffill', inplace=True)
ticker Date Sell_buy Qtd Price Costs Adj Qtd Adjusted Price
1 ABCD 2018-10-01 buy 100.0 8.0 10.93 100.0 8.109300
2 ABCD 2018-01-20 buy 300.0 10.0 12.52 400.0 9.558625
3 ABCD 2018-07-02 sell 200.0 12.0 11.39 200.0 9.558625
4 ABCD 2018-04-14 buy 500.0 9.0 14.50 700.0 8.466514
5 ABCD 2018-05-25 sell 600.0 13.0 14.68 100.0 8.466514
6 ABCD 2018-04-07 buy 500.0 14.0 14.96 600.0 8.544733
8 EFGH 2018-10-01 buy 300.0 8.0 10.93 300.0 8.036433
9 EFGH 2018-01-20 buy 300.0 10.0 12.52 600.0 9.039083
10 EFGH 2018-07-02 buy 200.0 12.0 11.39 800.0 9.793550
11 EFGH 2018-04-14 buy 200.0 9.0 14.50 1000.0 9.649340
12 EFGH 2018-05-25 sell 700.0 13.0 14.68 300.0 9.649340
13 EFGH 2018-04-07 sell 100.0 14.0 14.96 200.0 9.649340
如果“买入”之间没有“卖出”(就像本例中股票 EFGH 所做的那样),这将非常有效。 需要明确的是,当交易是“卖出”时,我们必须忽略调整价格,并使用该特定股票最后一次买入类型交易中的最后调整价格。
我在 excel 中做了所有这些微积分,输出应该如下:
为了进一步说明,所选单元格的 excel 公式为:
=IF(C3="buy";(I2*G2+D3*E3+F3)/G3;IF(G3<>0;I2;0))
我也尝试过 .groupby("ticker").apply() 使用 shift() 的函数,以便使用上面行中的先前值,但我失败了。
我想不出一个好的、简单的解决方案。问题是计算调整后价格取决于调整后价格的先前值,这阻止了向量化或 shift() 的使用。
所以,这是丑陋的解决方案。 :)
第一步是使用 groupby,通过股票代码将其分开。然后,它遍历该组中的所有行,并计算价格的加权平均值以获得当前股票和之前的价格。然后,它将该列表添加为数据框中的一列。
def weighted_average(a, b, a_weight):
"""Take an average of a and b, with a weighted by a_weight"""
assert 0 <= a_weight <= 1
return a * a_weight + b * (1 - a_weight)
def get_adjusted_price_for_ticker(single_ticker_df):
adjusted_price = 0
current_shares = 0
prices = []
for _, row in single_ticker_df.iterrows():
is_buy = row["Sell_buy"] == "buy"
qtd = row["Qtd"]
if is_buy:
current_shares += qtd
cost_per_share = (qtd * row["Price"] + row["Costs"]) / qtd
proportion_of_new_shares = qtd / current_shares
adjusted_price = weighted_average(cost_per_share, adjusted_price, proportion_of_new_shares)
else:
current_shares -= qtd
prices.append(adjusted_price)
single_ticker_df["Adjusted Price"] = prices
return single_ticker_df
def get_adjusted_price(df):
return df.groupby("ticker").apply(get_adjusted_price_for_ticker)
get_adjusted_price(sample_df)
输出:
ticker Date Sell_buy Qtd Price Costs Adjusted Price
1 ABCD 2018-10-01 buy 100.0 8.0 10.93 8.109300
2 ABCD 2018-01-20 buy 300.0 10.0 12.52 9.558625
3 ABCD 2018-07-02 sell 200.0 12.0 11.39 9.558625
4 ABCD 2018-04-14 buy 500.0 9.0 14.50 9.180321
5 ABCD 2018-05-25 sell 600.0 13.0 14.68 9.180321
6 ABCD 2018-04-07 buy 500.0 14.0 14.96 13.221654
8 EFGH 2018-10-01 buy 300.0 8.0 10.93 8.036433
9 EFGH 2018-01-20 buy 300.0 10.0 12.52 9.039083
10 EFGH 2018-07-02 buy 200.0 12.0 11.39 9.793550
11 EFGH 2018-04-14 buy 200.0 9.0 14.50 9.649340
12 EFGH 2018-05-25 sell 700.0 13.0 14.68 9.649340
13 EFGH 2018-04-07 sell 100.0 14.0 14.96 9.649340