okama.PortfolioDCF
- class PortfolioDCF(parent, discount_rate=None, use_discounted_values=False)
Bases:
object
Class to access discounted cash flow (DCF) methods of Portfolio. All methods can be used in Portfolio instances trough construction:
` pf = Portfolio() pf.dcf.weatlh_index pf.dсf.cashflow_pv `
- Parameters:
- discount_rate: float or None, default None
Cash flow discount rate required to calculate Present value (PV) or Future (FV) of cashflow. If not provided geometric mean of inflation is taken. For portfolios without inflation the default value from settings is used.
- use_discounted_values: bool, default False
Defines whether to use discounted values in backtesting wealth indexes. If True the initial investments and cashflow size are discounted.
Methods & Attributes
The discounted value (PV) of the cash flow amount (contributions/withdrawals) at the historical first date.
Portfolio cash flow discount rate.
find_the_largest_withdrawals_size
(...[, ...])Find the largest withdrawals size for Monte Carlo simulation according to Cashflow Strategy.
The future value (FV) of the initial investments at the end of forecast period.
The discounted value (PV) of the initial investments at the historical first date.
monte_carlo_survival_period
([threshold])Generate a survival period distribution for a portfolio with cash flows by Monte Carlo simulation.
Portfolio random wealth indexes with cash flows (withdrawals/contributions) by Monte Carlo simulation.
Portfolio discounted random wealth indexes with cash flows (withdrawals/contributions) by Monte Carlo simulation.
plot_forecast_monte_carlo
([backtest, figsize])Plot Monte Carlo simulation for portfolio future wealth indexes optionally together with historical wealth index.
set_mc_parameters
(distribution, period, number)Add Monte Carlo simulation parameters to PortfolioDCF.
survival_date_hist
([threshold])Get the date when the portfolio balance become negative considering withdrawals on the historical data.
survival_period_hist
([threshold])Calculate the period when the portfolio has positive balance considering withdrawals on the historical data.
The value of attribute to define weather to use discounted values in backtesting wealth indexes.
Wealth index time series for the portfolio with cash flow (contributions and withdrawals).
Wealth index time series for the portfolio and all assets considering cash flow (contributions and withdrawals).
- property discount_rate
Portfolio cash flow discount rate.
- Returns:
- float
Cash flow discount rate.
- property use_discounted_values
The value of attribute to define weather to use discounted values in backtesting wealth indexes. If True the initial investments and cashflow size are discounted.
- Returns:
- bool
Weather to use discounted values in backtesting wealth indexes
- set_mc_parameters(distribution, period, number)
Add Monte Carlo simulation parameters to PortfolioDCF.
- Parameters:
- distribution: str
The type of a distribution to generate random rate of return. Allowed values for distribution: -‘norm’ for normal distribution -‘lognorm’ for lognormal distribution -‘t’ for Student’s (t-distribution)
- period: int
Forecast period for portfolio wealth index time series (in years).
- number: int
Number of random wealth indexes to generate with Monte Carlo simulation.
Examples
>>> import matplotlib.pyplot as plt >>> pf = ok.Portfolio(first_date="2015-01", last_date="2024-10") # create Portfolio with default parameters >>> # Set Monte Carlo parameters >>> pf.dcf.set_mc_parameters(distribution="lognorm", period=10, number=100) >>> # Set the cash flow strategy. It's required to generate random wealth indexes. >>> ind = ok.IndexationStrategy(pf) # create IndexationStrategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investments size >>> ind.frequency = "year" # set cash flow frequency >>> ind.amount = -1_500 # set withdrawal size >>> ind.indexation = "inflation" >>> # Assign the strategy to Portfolio >>> pf.dcf.cashflow_parameters = ind >>> pf.dcf.use_discounted_values = False # do not discount initial investment value >>> # Plot wealth index with cash flow >>> pf.dcf.wealth_index.plot() >>> plt.show()
- property wealth_index
Wealth index time series for the portfolio with cash flow (contributions and withdrawals).
Wealth index (Cumulative Wealth Index) is a time series that presents the value of portfolio over historical time period considering cash flows.
Accumulated inflation time series is added if inflation=True in the Portfolio.
If there is no cash flow, Wealth index is obtained from the accumulated return multiplicated by the initial investments. That is: initial_amount_pv * (Acc_Return + 1)
- Returns:
- Time series of wealth index values for portfolio and accumulated inflation.
Examples
>>> import matplotlib.pyplot as plt >>> pf = ok.Portfolio(['VOO.US', 'GLD.US'], weights=[0.8, 0.2]) >>> ind = ok.IndexationStrategy(pf) # Set Cash Flow Strategy parameters >>> ind.initial_investment = 100 # initial investments value >>> ind.frequency = "year" # withdrawals frequency >>> ind.amount = -0.5 * 12 # initial withdrawals amount >>> ind.indexation = "inflation" # the indexation is equal to inflation >>> pf.dcf.cashflow_parameters = ind # assign the strategy to Portfolio >>> pf.dcf.wealth_index.plot() >>> plt.show()
- property wealth_index_with_assets
Wealth index time series for the portfolio and all assets considering cash flow (contributions and withdrawals).
Wealth index (Cumulative Wealth Index) is a time series that presents the value of portfolio over historical time period. Accumulated inflation time series is added if inflation=True in the Portfolio.
Wealth index is obtained from the accumulated return multiplicated by the initial investments. initial_amount_pv * (Acc_Return + 1)
If there is no cash flow, Wealth index is obtained from the accumulated return multiplicated by the initial investments. That is: initial_amount_pv * (Acc_Return + 1)
- Returns:
- DataFrame
Time series of wealth index values for portfolio, each asset and accumulated inflation.
Examples
>>> import matplotlib.pyplot as plt >>> pf = ok.Portfolio(['VOO.US', 'GLD.US'], weights=[0.8, 0.2]) >>> ind = ok.IndexationStrategy(pf) # Set Cash Flow Strategy parameters >>> ind.initial_investment = 100 # initial investments value >>> ind.frequency = "year" # withdrawals frequency >>> ind.amount = -0.5 * 12 # initial withdrawals amount >>> ind.indexation = "inflation" # the indexation is equal to inflation >>> pf.dcf.cashflow_parameters = ind # assign the strategy to Portfolio >>> pf.dcf.wealth_index_with_assets.plot() >>> plt.show()
- survival_period_hist(threshold=0)
Calculate the period when the portfolio has positive balance considering withdrawals on the historical data.
The portfolio survival period (longevity period) depends on the investment strategy: asset allocation, rebalancing, withdrawals rate etc.
- Parameters:
- thresholdfloat, default 0
The percentage of the initial investments when the portfolio balance considered voided. This parameter is important to use in cash flow strategies with a fixed whtdrawal percentage (PercentageStrategy).
- Returns:
- float
The portfolio survival period (longevity period) in years.
Examples
>>> pf = ok.Portfolio( ['SPY.US', 'AGG.US'], ccy='USD', first_date='2010-01', last_date='2024-10' ) >>> # set cash flow strategy >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> ind.amount = -2_500 # set annual withdrawal size >>> ind.frequency = "year" # set withdrawal frequency to year >>> pf.dcf.cashflow_parameters = ind >>> # Calculate the historical survival period for the cash flow strategy. >>> # The balance is considered voided when it's equal to 0 (threshold=0) >>> pf.dcf.survival_period_hist(threshold=0) 5.1
- survival_date_hist(threshold=0)
Get the date when the portfolio balance become negative considering withdrawals on the historical data.
The portfolio survival date (longevity date) depends on the investment strategy: asset allocation, rebalancing, withdrawals rate etc.
- Parameters:
- thresholdfloat, default 0
The percentage of the initial investments when the portfolio balance considered voided. This parameter is important to use in cash flow strategies with a fixed whtdrawal percentage (PercentageStrategy).
- Returns:
- pd.Timestamp
The portfolio survival date (longevity period) in years.
Examples
>>> pf = ok.Portfolio( ['SPY.US', 'AGG.US'], ccy='USD', first_date='2010-01', last_date='2024-10' ) >>> # set cash flow strategy >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> ind.amount = -2_500 # set annual withdrawal size >>> ind.frequency = "year" # set withdrawal frequency to year >>> pf.dcf.cashflow_parameters = ind >>> # Calculate the historical survival period for the cash flow strategy >>> pf.dcf.survival_date_hist(threshold=0) Timestamp('2015-01-31 00:00:00')
- property initial_investment_pv
The discounted value (PV) of the initial investments at the historical first date.
The future value (FV) is defined by initial_amount parameter.
- Returns:
- float, None
The discounted value (PV) of the initial investments at the historical first date.
Examples
>>> # Get discounted PV value of `initial_investment` for a portfolio with 4 years of history (at 2020-04). >>> pf = ok.Portfolio(['EQMX.MOEX', 'SBGB.MOEX'], ccy='RUB', last_date="2024-10") >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> pf.dcf.cashflow_parameters = ind # assign cash flow strategy to portfolio >>> pf.dcf.discount_rate = 0.10 # define discount rate as 10% >>> pf.dcf.initial_investment_pv 6574.643143611553
- property initial_investment_fv
The future value (FV) of the initial investments at the end of forecast period.
The forecast period is defined in Monte Carlo parameters (‘period’).
FV is defined by the discount rate and the initial investments: initial_investment_fv = initial_investment * (1 + discount_rate) ** period
When ‘initial_investment’ parameter is not defined, initial_investment_fv set to None.
- Returns:
- float, None
The future value (FV) of the initial investments.
Examples
>>> # Get discounted FV of initial_investment value for a period of 10 years. >>> pf = ok.Portfolio(['EQMX.MOEX', 'SBGB.MOEX'], ccy='RUB') >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> pf.dcf.cashflow_parameters = ind # assign cash flow strategy to portfolio >>> pf.dcf.mc.period = 10 # define forecast period >>> pf.dcf.discount_rate = 0.10 # define discount rate as 10% >>> pf.dcf.initial_investment_fv 25937.424601000024
- property cashflow_pv
The discounted value (PV) of the cash flow amount (contributions/withdrawals) at the historical first date.
PV is defined by the discount rate and the cash flow amount: cashflow_pv = amount / (1 + discount_rate) ** period_length
When cash flow ‘amount’ is not defined, cashflow_pv set to None.
- Returns:
- float, None
The discounted value (PV) of the cash flow amount at the historical first date.
Examples
>>> # Get discounted PV value of of the cash flow amount for a portfolio with 20 years of history (at 2003-10). >>> pf = ok.Portfolio(['SPY.US', 'AGG.US'], ccy='USD', last_date="2024-10") >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> ind.amount = -500 # set withdrawal size >>> ind.frequency = "year" # set withdrawal frequency >>> pf.dcf.cashflow_parameters = ind # assign cash flow strategy to portfolio >>> pf.dcf.discount_rate = 0.10 # define discount rate >>> pf.dcf.cashflow_pv -68.86557103941368
- property monte_carlo_wealth
Portfolio random wealth indexes with cash flows (withdrawals/contributions) by Monte Carlo simulation.
Monte Carlo simulation generates n random monthly time series. Each wealth index is calculated with rate of return time series of a given distribution.
First date of forecasted returns is portfolio last_date. First value for the forecasted wealth indexes is the last historical portfolio index value. It is useful for a chart with historical wealth index and forecasted values.
- Returns:
- DataFrame
Table with n random wealth indexes monthly time series.
Examples
>>> import matplotlib.pyplot as plt >>> pf = ok.Portfolio(['SPY.US', 'AGG.US', 'GLD.US'], weights=[.60, .35, .05], rebalancing_period='month') >>> pf.dcf.set_mc_parameters(distribution="t", period=10, number=100) # Set Monte Carlo parameters >>> # set cash flow parameters >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> ind.amount = -500 # set withdrawal size >>> ind.frequency = "year" # set withdrawal frequency >>> pf.dcf.cashflow_parameters = ind # assign cash flow strategy to portfolio >>> pf.dcf.monte_carlo_wealth.plot() >>> plt.legend("") # don't show legend for each line >>> plt.show()
- property monte_carlo_wealth_pv
Portfolio discounted random wealth indexes with cash flows (withdrawals/contributions) by Monte Carlo simulation.
Random Monte Carlo simulation monthly time series are discounted using discount_rate parameter. Each wealth index is calculated with rate of return time series of a given distribution.
discount_rate parameter can be set in Portfolio.dcf.discount_rate.
Monte Carlo parameters are defined by Portfolio.dcf.set_mc_parameters() method.
- Returns:
- DataFrame
Table with random discounted wealth indexes monthly time series.
Examples
>>> import matplotlib.pyplot as plt >>> pf = ok.Portfolio(['SPY.US', 'AGG.US', 'GLD.US'], weights=[.60, .35, .05], rebalancing_period='month') >>> pc = ok.PercentageStrategy(pf) # Define withdrawals strategy with fixed percentage >>> pc.frequency = "year" # set withdrawals frequency >>> pc.percentage = -0.08 # investor would take 8% every year >>> pf.dcf.cashflow_parameters = pc # Assign the strategy to Portfolio >>> pf.dcf.discount_rate = 0.05 # set dicount rate value to 5% >>> pf.dcf.set_mc_parameters(distribution="t", period=10, number=100) # Set Monte Carlo parameters >>> df = pf.dcf.monte_carlo_wealth_pv # calculate discounted random wealth indexes >>> df.plot() # create a chart >>> plt.legend("") # no legend is required >>> plt.show()
- plot_forecast_monte_carlo(backtest=True, figsize=None)
Plot Monte Carlo simulation for portfolio future wealth indexes optionally together with historical wealth index.
Wealth index (Cumulative Wealth Index) is a time series that presents the value of portfolio over time period considering cash flows (portfolio withdrawals/contributions).
Random wealth indexes are generated according to a given distribution.
- Parameters:
- backtestbool, default ‘True’
Include historical wealth index if ‘True’.
- figsize(float, float), optional
Width, height in inches. If None default matplotlib figsize value is used.
- Returns:
- None
Examples
>>> import matplotlib.pyplot as plt >>> pf = ok.Portfolio(assets=['SPY.US', 'AGG.US', 'GLD.US'], weights=[.60, .35, .05], rebalancing_period='year') >>> # Set Monte Carlo parameters >>> pf.dcf.set_mc_parameters(distribution="norm", period=50, number=200) >>> # set cash flow parameters >>> ind = ok.IndexationStrategy(pf) # create cash flow strategy linked to the portfolio >>> ind.initial_investment = 10_000 # add initial investment to cash flow strategy >>> ind.amount = -500 # set withdrawal size >>> ind.frequency = "year" # set withdrawal frequency >>> pf.dcf.cashflow_parameters = ind # assign cash flow strategy to portfolio >>> pf.dcf.plot_forecast_monte_carlo(backtest=True) >>> plt.yscale("log") # Y-axis has logarithmic scale >>> plt.show()
- monte_carlo_survival_period(threshold=0)
Generate a survival period distribution for a portfolio with cash flows by Monte Carlo simulation.
Analyzing the result, finding “min”, “max” and percentiles it’s possible to see for how long will last the investment strategy - possible longevity period.
- Parameters:
- thresholdfloat, default 0
The percentage of the initial investments when the portfolio balance considered voided. This parameter is important to use in cash flow strategies with a fixed whtdrawal percentage (PercentageStrategy).
- Returns:
- Series
Survival period distribution for a portfolio with cash flows.
Examples
>>> pf = ok.Portfolio(['SPY.US', 'AGG.US', 'GLD.US'], weights=[.60, .35, .05]) >>> # set Monte Carlos parameters >>> pf.dcf.set_mc_parameters( ... distribution="t", # use Student's distribution (t-distribution) ... period=50, # make forecast for 50 years ... number=200 # create 200 randow wealth indexes ... ) >>> # Set Cash Flow parameters >>> pc = ok.PercentageStrategy(pf) # create PercentageStrategy linked to the portfolio >>> pc.initial_investment = 10_000 # add initial investments size >>> pc.frequency = "year" # set cash flow frequency >>> pc.percentage = -0.20 # set withdrawal percentage >>> # Assign the strategy to Portfolio >>> pf.dcf.cashflow_parameters = pc >>> s = pf.dcf.monte_carlo_survival_period(threshold=0.10) # the balance is considered voided at 10% >>> s.min() np.float64(10.5) >>> s.max() np.float64(33.5) >>> s.mean() np.float64(17.9055) >>> s.quantile(50 / 100) np.float64(17.5)
- find_the_largest_withdrawals_size(withdrawal_steps, confidence_level, goal, threshold=0, target_survival_period=25)
Find the largest withdrawals size for Monte Carlo simulation according to Cashflow Strategy.
It’s possible to find the largest withdrawl with 2 kind of goals:
- — ‘maintain_balance’ to keep the purchasing power of the invesments after inflation
for the whole period defined in Monte Carlo parameteres.
- — ‘survival_period’ to keep positive balance for a period defined by ‘target_survival_period’.
The method works with IndexationStrategy and PercentageStrategy only.
The withdrawal size defined in cash flow strategy must be negative.
- Parameters:
- withdrawal_stepsint
The number of intermediate steps during the iteration of values fom maximum to minimum of the withdrawal size. The withdrawal size varies from 100% of the initial investment to zero.
- confidence_levelfloat
Confidence level must be form 0 to 1. Confidence level defines the percentile of Monte Carlo time series. 0.01 or 0.05 are the examples of “bad” scenarios. 0.50 is mediane (50% percentile). 0.95 or 0.99 are optimiststic scenarios.
- goal{‘maintain_balance’, ‘survival_period’}
‘maintain_balance’ - the goal is to keep the purchasing power of the invesments after inflation for the whole period defined in Monte Carlo parameteres. ‘survival_period’ - the goal is to keep positive balance for a period defined by ‘target_survival_period’.
- thresholdfloat, default 0
The percentage of initial investments when the portfolio balance is considered voided. Important for the “fixed_percentage” Cash flow strategy.
- target_survival_period: int, default 25
The smallest acceptable survival period. It wokrs with the ‘survival_period’ goal only.
- Returns:
- float
the largest withdrawals size according to Cashflow Strategy.
Examples
>>> pf = ok.Portfolio( ... assets=["MCFTR.INDX", "RUCBTRNS.INDX"], ... weights=[.3, .7], ... inflation=True, ... ccy="RUB", ... rebalancing_period="year", ... ) >>> # Fixed Percentage strategy >>> pc = ok.PercentageStrategy(pf) >>> pc.initial_investment = 10_000 >>> pc.frequency = "year" >>> # Assign a strategy >>> pf.dcf.cashflow_parameters = pc >>> # Set Monte Carlo parameters >>> pf.dcf.set_mc_parameters( ... distribution="norm", ... period=50, ... number=200 ...) >>> pf.dcf.find_the_largest_withdrawals_size( ... withdrawal_steps=30, ... confidence_level=0.50, ... goal="survival_period", ... threshold=0.05, ... target_survival_period=25 ...) np.float64(-0.10344827586206895)