需要帮助计算每项投资在不同日期的不同投资的 IRR,在 python

问题描述

我需要帮助计算不同投资的 IRR,以及这些投资在不同时间的 IRR。

所以有一个看起来像这样的数据框:

日期 投资 流程
2012-05-12 1 -50
2013-09-04 1 100
2014-05-05 1 300
2013-09-04 2 -700
2015-05-12 2 1000
2012-04-04 3 100
2013-05-12 3 -50
2013-09-04 4 -60

一个看起来像这样

日期 投资 股票
2012-09-05 1 400
2014-05-05 1 600
2014-05-05 2 300
2013-09-04 2 800
2012-09-14 3 1000
2013-09-05 4 6000

因此,我想创建多个数据框,其中包含在我获得股票信息之日之前每项投资的流向,最后一行包含该日期的股票。例如,我对投资 1 的股票有 2 个观察结果,因此我应该为投资 1 创建 2 个数据框,如下所示:

日期 投资 流量+库存(最后一行)
2012-05-12 1 -50
2012-09-05 1 400
日期 投资 流量+库存(最后一行)
2012-05-12 1 -50
2013-09-04 1 100
2014-05-05 1 300
2014-05-05 1 600

对于投资 3,假设我对股票只有一个观察结果,那么应该只有 1 个如下所示的数据框:

日期 投资 流量+库存(最后一行)
2012-04-04 3 100
2012-09-14 3 1000

鉴于我有很多数据,手动创建每个数据框很麻烦,而且我希望这段代码我有新信息时更新 IRR。我想这样做是因为我想看到 IRR 在每个日期的演变,我有每项投资的股票信息。有点像投资的内部收益率时间序列。我将使用创建的数据框计算 IRR。

我曾尝试对每项投资有股票信息的日期进行排序,但在循环中遇到问题。

非常感谢

编辑: 根据 Henry Ecker 的要求,这是合并数据库的示例。

         DATE_x       Investment         Flow     DATE_y         Stock
355  2018-08-29            1            1371300 2020-09-30    2904678,03
3076 2016-03-31            2           -4535569 2015-06-30             0
1564 2017-11-28            3            1142227 2014-09-30   10378007,31
3666 2018-02-22            2            1622857 2020-03-31  122203846,09
1394 2017-05-16            3            3116642 2017-12-31             0
472  2013-11-09            3           -4364500 2015-12-31   45789217,93
446  2021-02-23            1             325117 2020-03-31   13176648,97
1641 2018-01-31            3             623695 2015-09-30             0
1297 2017-03-21            3            1146193 2015-09-30    32103654,6
2080 2020-09-15            3             461123 2017-09-30   47763628,79

解决方法

解决此问题的一种方法是加入流和观察以获取关联,然后按观察日期和投资 ID 分组以获取我们感兴趣的每个组。

函数 process_df 用于仅过滤掉观察日期 (DATE_y) 之前的天数。

从第一行获取值 Investment、Observation Date (DATE_y) 和 Stock 值,因为它们在组中都相同,并将其附加到表的末尾。然后只需清理所有内容,删除额外的列(Stock 和 DATE_y),重置索引,并重命名列以反映您想要的输出。

import pandas as pd

flows = pd.DataFrame({'DATE': {0: '2012-05-12',1: '2013-09-04',2: '2014-05-05',3: '2013-09-04',4: '2015-05-12',5: '2012-04-04',6: '2013-05-12',7: '2013-09-04',8: '2020-05-12',9: '2016-07-12'},'Investment': {0: 1,1: 1,2: 1,3: 2,4: 2,5: 3,6: 3,7: 4,8: 5,9: 7},'Flow': {0: -50,1: 100,2: 300,3: -700,4: 1000,5: 100,6: -50,7: -60,8: 100,9: 800}})
flows['DATE'] = flows['DATE'].astype('datetime64[ns]')

observations = pd.DataFrame({'DATE': {0: '2012-09-05',1: '2014-05-05',4: '2012-09-14',5: '2013-09-05',6: '2014-05-14',7: '2015-12-14'},2: 2,4: 3,5: 4,6: 5,7: 6},'Stock': {0: 400,1: 600,3: 800,5: 6000,6: 0,7: 15}})
observations['DATE'] = observations['DATE'].astype('datetime64[ns]')


def process_df(df):
    out = df[df['DATE_x'] <= df['DATE_y']]  # Filter Out Out of Bound Dates
    if out.empty:
        # Handle Case Where Observation but No flows
        return df[['DATE_y','Investment','Stock']] \
            .reset_index(drop=True) \
            .rename(columns={'DATE_y': 'DATE','Stock': 'Flow + Stock(last row)'})
    return out.drop(['DATE_y','Stock'],axis=1) \
        .append(out[['Investment','DATE_y','Stock']]
                .iloc[0]
                .rename({'DATE_y': 'DATE_x','Stock': 'Flow'})) \
        .reset_index(drop=True) \
        .rename(columns={'DATE_x': 'DATE','Flow': 'Flow + Stock(last row)'})


merged = pd.merge(flows,observations,on='Investment',how='right')

dfs = [process_df(group) for _,group in merged.groupby(['Investment','DATE_y'])]

# For Display
for i,new_df in enumerate(dfs):
    print(f'DataFrame {i+1}')
    print(new_df)
    print()

dfs 是包含单个 DataFrame 的列表。

输出:

DataFrame 1
        DATE  Investment  Flow + Stock(last row)
0 2012-05-12           1                   -50.0
1 2012-09-05           1                   400.0

DataFrame 2
        DATE  Investment  Flow + Stock(last row)
0 2012-05-12           1                   -50.0
1 2013-09-04           1                   100.0
2 2014-05-05           1                   300.0
3 2014-05-05           1                   600.0

DataFrame 3
        DATE  Investment  Flow + Stock(last row)
0 2013-09-04           2                  -700.0
1 2013-09-04           2                   800.0

DataFrame 4
        DATE  Investment  Flow + Stock(last row)
0 2013-09-04           2                  -700.0
1 2014-05-05           2                   300.0

DataFrame 5
        DATE  Investment  Flow + Stock(last row)
0 2012-04-04           3                   100.0
1 2012-09-14           3                  1000.0

DataFrame 6
        DATE  Investment  Flow + Stock(last row)
0 2013-09-04           4                   -60.0
1 2013-09-05           4                  6000.0

DataFrame 7
        DATE  Investment  Flow + Stock(last row)
0 2014-05-14           5                       0

DataFrame 8
        DATE  Investment  Flow + Stock(last row)
0 2015-12-14           6                      15

编辑备注:

  • 我最初的实现做了一个错误的假设,即所有观察都至少有一个流。我猜测您希望如何接收有关没有流关联的观察的信息,并选择返回一个 DataFrame,该 DataFrame 仍然具有包含库存信息但没有流的最后一行。如果您更喜欢空的 DataFrame,请直接返回。
    if out.empty:
        # Handle Case Where Observation but No flows
        return out
  • 我在示例数据中添加了 3 个额外的测试用例。
    1. 有流量,但发生在观察之后
    2. 给定投资 ID 没有流量
    3. 有流动但没有观察。
      • 鉴于您生成的 DataFrame 基于观察,我选择使用“正确”连接排除观察中不匹配的流。