Python: Рассчитайте общий доход, добавив кумулятивные дивиденды и взяв совокупный годовой темп роста (CAGR). - PullRequest
4 голосов
/ 18 октября 2019

У меня есть данные с данными о годовых ценах и дивидендах для многих компаний. Я рассчитываю рассчитать трехлетнюю годовую доходность, сложив все дивиденды, полученные в течение трех лет, с конечной стоимостью акций, а затем взяв CAGR. Я знаю, как рассчитать CAGR, но я застреваю, добавляя дивиденды, полученные за период, к конечной цене.

Пример данных:

       RIC  Date    Price   Dividend
0   RSG.AX  2018    0.814   0.000
1   RSG.AX  2017    0.889   0.015
2   RSG.AX  2016    0.937   0.012
3   RSG.AX  2015    0.181   0.000
4   RSG.AX  2014    0.216   0.000
5   RSG.AX  2013    0.494   0.000
6   QBE.AX  2018    7.119   0.352
7   QBE.AX  2017    8.331   0.202
8   QBE.AX  2016    8.961   0.389
9   QBE.AX  2015    9.159   0.363
10  QBE.AX  2014    9.156   0.302

Используя компанию RSG.AX (RIC = балансовая единица), пример расчета с 2015 по 2018 год будет:

Доходность за 3 года = (Конечная цена + накопленные дивиденды) / Начальная цена = (0,814 + 0,015 + 0,012) / 0,182 = 4,63

Годовая прибыль = (возврат) ^ (1 / лет) -1 = (4,63) ^ (1/3) -1 = 0,66 = 66%

Как мне это сделать с Python? Возможно, .groupby() будет работать для разделения данных каждой компании. Любая помощь приветствуется!

Ответы [ 2 ]

2 голосов
/ 21 октября 2019

Использование shift() получение значений из строк выше / ниже для расчета


Метод 1: использование цикла по RIC

Я перебираю его через df.RIC.unique() с копией субкадра sub_df на каждом RIC. Предполагая, что цена года будет после деления, 3-year return будет:

sub_df['3-year Return'] = (sub_df.Price +
                           sub_df.Dividend +
                           sub_df.shift(-1).Dividend +
                           sub_df.shift(-2).Dividend) / sub_df.Price.shift(-3)

Обновите sub_df до исходного df впоследствии. Затем вычислите Annualized return на основе вашей формулы с помощью pow()

df['3-year Return'] = None
for ric in df.RIC.unique():
    sub_df = df.loc[df['RIC'] == ric].copy()
    sub_df['3-year Return'] = (sub_df.Price + 
                               sub_df.Dividend + 
                               sub_df.shift(-1).Dividend + 
                               sub_df.shift(-2).Dividend) / sub_df.Price.shift(-3)
    df.update(sub_df)
df['Annualized return'] = pow(df['3-year Return'], 1/3)  - 1
print(df)

       RIC    Date  Price  Dividend 3-year Return Annualized return
0   RSG.AX  2018.0  0.814     0.000       4.64641          0.668678
1   RSG.AX  2017.0  0.889     0.015       4.24074          0.618629
2   RSG.AX  2016.0  0.937     0.012       1.92105           0.24312
3   RSG.AX  2015.0  0.181     0.000          None               NaN
4   RSG.AX  2014.0  0.216     0.000          None               NaN
5   RSG.AX  2013.0  0.494     0.000          None               NaN
6   QBE.AX  2018.0  7.119     0.352      0.880227        -0.0416336
7   QBE.AX  2017.0  8.331     0.202       1.01409        0.00467449
8   QBE.AX  2016.0  8.961     0.389          None               NaN
9   QBE.AX  2015.0  9.159     0.363          None               NaN
10  QBE.AX  2014.0  9.156     0.302          None               NaN

Метод 2 - используйте groupby () и apply () для пользовательской функции

На основе метода 1 мы можем определить пользовательскую функцию, которая будет применяться через groupby RIC

def three_year_return(row):
    row['3-year Return'] = (row.Price + 
                            row.Dividend + 
                            row.shift(-1).Dividend + 
                            row.shift(-2).Dividend) / row.Price.shift(-3)
    return row

df = df.groupby(['RIC']).apply(three_year_return)
df['Annualized return'] = pow(df['3-year Return'], 1/3)  - 1


       RIC  Date  Price  Dividend  3-year Return  Annualized return
0   RSG.AX  2018  0.814     0.000       4.646409           0.668678
1   RSG.AX  2017  0.889     0.015       4.240741           0.618629
2   RSG.AX  2016  0.937     0.012       1.921053           0.243120
3   RSG.AX  2015  0.181     0.000            NaN                NaN
4   RSG.AX  2014  0.216     0.000            NaN                NaN
5   RSG.AX  2013  0.494     0.000            NaN                NaN
6   QBE.AX  2018  7.119     0.352       0.880227          -0.041634
7   QBE.AX  2017  8.331     0.202       1.014089           0.004674
8   QBE.AX  2016  8.961     0.389            NaN                NaN
9   QBE.AX  2015  9.159     0.363            NaN                NaN
10  QBE.AX  2014  9.156     0.302            NaN                NaN

FYI - результаты выглядят немного иначе, чем в вашем примере, потому чтоЯ обнаружил, что вы использовали 0.182 в качестве start price, в то время как оно должно быть 0.181 на основе ваших данных выборки.

0 голосов
/ 18 октября 2019

Сохраняйте его читабельным. Вместо этого вы можете использовать .apply, если действительно хотите избежать создания словаря.

result = {}
for ric, grp in df.groupby('RIC'):
    first, last = grp.iloc[-1], grp.iloc[0]
    start_price, end_price = first.Price, last.Price
    cum_div = grp.Dividend.sum()
    return_ = (end_price + cum_div) / start_price
    years = (last.Date - first.Date).days / 365
    ann_return = return_ ** (1 / years) - 1
    result[ric] = ann_return

result_df = pd.DataFrame.from_dict(result, orient='index')
print(result_df)

Это для всего периода в вашем фрейме данных - если вы хотите, чтобы три года просто изменились в последний раз на grp.iloc[3] (убедитесь, что существует много данных). Это также зависит от того факта, что ваши данные согласуются с инвариантом сортировки по дате и времени, который предлагает ваш образец.

...