Search code examples
pythonpandasdataframerolling-computation

Python: Dynamically calculate rolling returns over different frequencies


Consider a DataFrame with multiple columns as follows:

data = [[99330,12,122],[1123,1230,1287],[123,101,812739],[1143,1230123,252],[234,342,4546],[2445,3453,3457],[7897,8657,5675],[46,5675,453],[76,484,3735],[363,93,4568],[385,568,367],[458,846,4847],[574,45747,658468],[57457,46534,4675]]
df1 = pd.DataFrame(data, index=['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04',
                       '2022-01-05', '2022-01-06', '2022-01-07', '2022-01-08',
                       '2022-01-09', '2022-01-10', '2022-01-11', '2022-01-12',
                       '2022-01-13', '2022-01-14'], 
          columns=['col_A', 'col_B', 'col_C'])
df1.index = pd.to_datetime(df1.index)
df1: 
            col_A   col_B   col_C
2022-01-01  99330   12      122
2022-01-02  1123    1230    1287
2022-01-03  123     101     812739
2022-01-04  1143    1230123 252
2022-01-05  234     342     4546
2022-01-06  2445    3453    3457
2022-01-07  7897    8657    5675
2022-01-08  46      5675    453
2022-01-09  76      484     3735
2022-01-10  363     93      4568
2022-01-11  385     568     367
2022-01-12  458     846     4847
2022-01-13  574     45747   658468
2022-01-14  57457   46534   4675

Is there a way to write a loop so I can calculate the rolling returns on a daily ('1D'), weekly ('1W'), monthly ('1M') and six monthly ('6M') basis?

EDIT: Here is my attempt at calculating the rolling return on a daily and weekly basis:

periodicity_dict = {'1D':'daily', '1W':'weekly'}
df_columns = df1.columns
for key in periodicity_dict:
    for col in df_columns:
        df1[col+'_rolling']= np.nan
        for i in pd.date_range(start=df1[col].first_valid_index(), end=df1[col].last_valid_index(), freq=key):
                df1[col+'_rolling'].iloc[i] = (df1[col].iloc[i] - df[col].iloc[i-'1W'])/df[col].iloc[i-'1W']

Solution

  • pct_change does the shifting math for you, but you would have to do it one window at a time.

    windows = ["1D", "7D"]
    for window in windows:
        df1 = pd.merge(
            df1,
            (
                df1[["col_A", "col_B", "col_C"]]
                .pct_change(freq=window)
                .add_suffix(f"_rolling_{window}")
            ),
            left_index=True,
            right_index=True,
        )