Skip to content

Commit 1b71cd7

Browse files
committed
fix: cash flow in last and first year must be adjusted to the length of period
1 parent c000efd commit 1b71cd7

File tree

3 files changed

+4372
-630
lines changed

3 files changed

+4372
-630
lines changed

main.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,20 @@
3030
symbol="My_portfolio.PF",
3131
)
3232
pf.dcf.discount_rate = 0.09
33-
# # Percentage CF strategy
34-
# cf_strategy = ok.PercentageStrategy(pf) # create PercentageStrategy linked to the portfolio
35-
#
36-
# cf_strategy.initial_investment = 83_000_000 # initial investments size
37-
# cf_strategy.frequency = "year" # withdrawals frequency
38-
# cf_strategy.percentage = -0.40
33+
# Percentage CF strategy
34+
cf_strategy = ok.PercentageStrategy(pf) # create PercentageStrategy linked to the portfolio
3935

40-
# Indexation CF strategy
41-
cf_strategy = ok.IndexationStrategy(pf)
36+
cf_strategy.initial_investment = 83_000_000 # initial investments size
37+
cf_strategy.frequency = "year" # withdrawals frequency
38+
cf_strategy.percentage = -0.09
4239

43-
cf_strategy.initial_investment = 10_000_000
44-
cf_strategy.frequency = "year"
45-
cf_strategy.amount = 10_000_000 * 0.05
46-
cf_strategy.indexation = 0.09
40+
# # Indexation CF strategy
41+
# cf_strategy = ok.IndexationStrategy(pf)
42+
#
43+
# cf_strategy.initial_investment = 10_000_000
44+
# cf_strategy.frequency = "year"
45+
# cf_strategy.amount = 10_000_000 * 0.05
46+
# cf_strategy.indexation = 0.09
4747

4848
# d = {
4949
# "2015-06": -35_000_000,
@@ -78,11 +78,10 @@
7878
number=100
7979
)
8080

81-
wi = pf.dcf.wealth_index(discounting="pv", include_negative_values=False)
82-
cf = pf.dcf.cash_flow_ts(discounting="pv", remove_if_wealth_index_negative=True)
83-
# wi = pf.dcf.monte_carlo_wealth(discounting="fv", include_negative_values=False)
84-
# cf = pf.dcf.monte_carlo_cash_flow(discounting="pv", remove_if_wealth_index_negative=True)
85-
# print(cf)
81+
# wi = pf.dcf.wealth_index(discounting="pv", include_negative_values=False)
82+
# cf = pf.dcf.cash_flow_ts(discounting="pv", remove_if_wealth_index_negative=True)
83+
wi = pf.dcf.monte_carlo_wealth(discounting="fv", include_negative_values=False)
84+
cf = pf.dcf.monte_carlo_cash_flow(discounting="pv", remove_if_wealth_index_negative=True)
8685

8786
wi.plot(
8887
# kind="bar",
@@ -91,7 +90,7 @@
9190
plt.yscale('linear') # linear or log
9291
plt.show()
9392

94-
df = cf
93+
df = cf[0]
9594
df[df != 0].plot(
9695
kind="bar",
9796
legend=False

main_notebook.ipynb

Lines changed: 4347 additions & 612 deletions
Large diffs are not rendered by default.

okama/portfolios/dcf_calculations.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,12 @@ def get_wealth_indexes_fv_with_cashflow(
8181
else:
8282
# Slow Calculation
8383
pandas_frequency = cashflow_parameters._pandas_frequency
84+
months_in_full_period = settings._MONTHS_PER_YEAR / cashflow_parameters.periods_per_year
8485
wealth_df = pd.DataFrame(dtype=float, columns=[portfolio_symbol])
8586
for n, x in enumerate(ror_cashflow_df.resample(rule=pandas_frequency, convention="start")):
8687
ror_ts = x[1].iloc[:, portfolio_position] # select ror part of the grouped data
88+
months_local = ror_ts.shape[0]
89+
period_fraction = months_local / months_in_full_period # 1 for a full period
8790
cashflow_ts_local = x[1].loc[:, "cashflow_ts"].copy()
8891
# CashFlow inside period (Extra withdrawals/contributions)
8992
if (cashflow_ts_local != 0).any():
@@ -109,6 +112,7 @@ def get_wealth_indexes_fv_with_cashflow(
109112
)
110113
else:
111114
raise ValueError("Wrong cashflow_method value.")
115+
cashflow_value *= period_fraction # adjust cash flow to the period length (months)
112116
period_final_balance = period_wealth_index.iloc[-1] + cashflow_value
113117
period_wealth_index.iloc[-1] = period_final_balance
114118
period_initial_amount = period_final_balance
@@ -199,8 +203,11 @@ def get_cash_flow_fv(
199203
else:
200204
# Slow Calculation
201205
pandas_frequency = settings.frequency_mapping[cashflow_parameters.frequency]
206+
months_in_full_period = settings._MONTHS_PER_YEAR / cashflow_parameters.periods_per_year
202207
for n, x in enumerate(ror_cashflow_df.resample(rule=pandas_frequency, convention="start")):
203208
ror_ts = x[1].iloc[:, portfolio_position] # select ror part of the grouped data
209+
months_local = ror_ts.shape[0]
210+
period_fraction = months_local / months_in_full_period # 1 for a full period
204211
cashflow_ts_local = x[1].loc[:, "cashflow_ts"].copy()
205212
# CashFlow inside period (Extra cash flow)
206213
if (cashflow_ts_local != 0).any():
@@ -226,6 +233,7 @@ def get_cash_flow_fv(
226233
)
227234
else:
228235
raise ValueError("Wrong cashflow_method value.")
236+
cashflow_value *= period_fraction # adjust cash flow to the period length (months)
229237
period_final_balance = period_wealth_index.iloc[-1] + cashflow_value
230238
period_wealth_index.iloc[-1] = period_final_balance
231239
period_initial_amount = period_final_balance

0 commit comments

Comments
 (0)