Skip to content

Releases: mbk-dev/okama

v2.2.2

20 Jun 04:35

Choose a tag to compare

Adds new analytics — ex-post tracking error for Portfolio and an RMS/std
method switch for tracking error across Index, AssetList, and Portfolio,
plus inflation-adjusted and price-only drawdown views — and fixes the
maintain_balance goals of find_the_largest_withdrawals_size() together with
duplicated efficient-frontier points under a thread backend.

Added

  • Portfolio.tracking_error(benchmark, rolling_window, method) — ex-post
    tracking error of a portfolio against a benchmark (#61). The benchmark may be
    a string ticker or an asset-like object (Asset, Portfolio); the method
    delegates to AssetList.
  • method parameter for AssetList.tracking_error and the underlying
    helpers.Index.tracking_error: "rms" (default, legacy uncentered
    root-mean-square) or "std" (centered sample standard deviation with
    Bessel's correction).
  • AssetList.real_drawdowns and Portfolio.real_drawdowns — drawdowns of the
    inflation-adjusted wealth index, exposing purchasing-power losses hidden by
    nominal growth (requires inflation=True) (#51).
  • AssetList.price_drawdowns and Portfolio.price_drawdowns — drawdowns based
    on close prices not adjusted for dividends, which can differ markedly from the
    total-return drawdowns for high-dividend assets (#44).

Fixed

  • PortfolioDCF.find_the_largest_withdrawals_size() raised
    ValueError: target_survival_period must be less than Monte Carlo simulation period
    for the maintain_balance_pv and maintain_balance_fv goals on any Monte
    Carlo period ≤ 27, even though those goals never use target_survival_period
    and the caller never passed it (#90). The parameter is now validated only for
    the survival_period goal.
  • EfficientFrontier.ef_points produced duplicated right-part points under a
    thread-based joblib backend, because the right-part worker both appended its
    row to the shared list and returned it (#86). The worker now only returns the
    row, matching the left-part worker.
  • Frame.kstest_series (used by kstest_for_all_distributions and the
    distribution-fit properties of AssetList / Portfolio) raised
    TypeError: ndtr() takes from 1 to 2 positional arguments but 3 were given
    with scipy 1.18.0 on Python ≥ 3.12, which routes the named-distribution
    kstest(..., "norm", args=...) call through the ndtr ufunc. The
    Kolmogorov–Smirnov test now passes a frozen-distribution CDF, which is
    numerically equivalent and compatible with scipy 1.17 and 1.18.

Docs

  • Clarified that tracking_error values are decimal fractions, not percentages.
  • PortfolioDCF.find_the_largest_withdrawals_size() docstring now notes that
    IndexationStrategy / PercentageStrategy subclasses (e.g.
    CutWithdrawalsIfDrawdown, VanguardDynamicSpending) are supported.

v2.2.1

06 Jun 05:49

Choose a tag to compare

Fixes the multi-period Efficient Frontier around single-asset corner points — the right part of the frontier now always terminates at the corner asset (no dominated "hook", no silently missing right part, pairwise frontiers reach the asset dots) — and removes pandas 3 deprecation warnings.

Fixed

  • EfficientFrontier.ef_points drew a dominated hook near the max-CAGR corner (#84): SLSQP started exactly at the optimal vertex of the bounds fails spuriously, and the fallback start converged to an interior local maximum. EfficientFrontier._maximize_risk() now keeps the better of the optimizer result and the 100% single-asset portfolio whenever the target CAGR equals an asset's own CAGR, so the right part of the frontier ends exactly at the corner asset with monotonically increasing risk.
  • The right part of EfficientFrontier.ef_points could silently disappear together with its corner point when the right CAGR span was much narrower than the left one (the point-count formula produced an empty target range).
  • Pairwise efficient frontiers (EfficientFrontier.plot_pair_ef()) stopped short of the asset point when the best rebalanced mix beat the asset by less than 1% of CAGR (#87). An asset is now considered to be the global max-CAGR point only when both its CAGR and its risk match it, and a narrow-but-real right CAGR span is drawn instead of being treated as degenerate.
  • EfficientFrontier.plot_pair_ef() ignored the parent's rebalancing_strategy, always computing pair frontiers with the default yearly rebalancing.
  • Pandas4Warning on pandas 3 (#85): dropped the deprecated copy keyword in symbols_in_namespace() and Index.rolling_fn() (slated for removal in pandas 4.0).

Changed

  • The EfficientFrontier.ef_points target grid now samples every asset's CAGR lying inside the range (previously only the minimum-variance asset's), so the frontier polyline passes exactly through single-asset points on the boundary. The number of rows in ef_points / mdp_points can therefore slightly exceed n_points.

Docs

  • README refreshed: fixed broken images on PyPI, added a hero image, an MCP server section and a uv install option.

v2.2.0

05 Jun 04:32

Choose a tag to compare

Makes Monte Carlo cash-flow simulations dramatically faster (vectorized wealth
and cash-flow engines, a Brent-based withdrawal solver — three to four orders
of magnitude per simulation), adds money-weighted IRR (MWRR) for portfolio
cash flows — both on historical data and across Monte Carlo forecast paths —
makes the Monte Carlo return draw cached and reproducible, and fixes three
cash-flow calculation bugs.

Added

  • Portfolio.dcf.irr() (PortfolioDCF.irr) — nominal annualized money-weighted
    internal rate of return (IRR/MWRR) of the portfolio cash flow over the full
    historical period, honoring the configured CashFlow strategy
    (IndexationStrategy, PercentageStrategy, VanguardDynamicSpending,
    CutWithdrawalsIfDrawdown, TimeSeriesStrategy). With no intermediate cash
    flows it equals Portfolio.get_cagr() for the period.
  • Portfolio.dcf.monte_carlo_irr() (PortfolioDCF.monte_carlo_irr) — the
    distribution (pandas.Series) of per-path money-weighted IRRs across Monte
    Carlo forecast paths, the forward-looking counterpart of PortfolioDCF.irr.
  • irr_of_cashflow_matrix() in okama.portfolios.dcf_calculations — a
    vectorized Newton solver (analytic derivative, scipy.optimize.brentq
    fallback) computing IRR for an (n_periods, n_series) cash-flow matrix in one
    pass; shared by both PortfolioDCF.irr and PortfolioDCF.monte_carlo_irr.
  • seed parameter for reproducible Monte Carlo draws: MonteCarlo.seed and the
    new seed argument of PortfolioDCF.set_mc_parameters().

Changed

  • The Monte Carlo return draw (MonteCarlo.monte_carlo_returns_ts) is now
    generated once and cached — shared by PortfolioDCF.monte_carlo_wealth,
    monte_carlo_cash_flow, monte_carlo_survival_period, monte_carlo_irr and
    the CAGR-distribution methods — so all of them see one consistent scenario set
    (previously each access regenerated fresh randomness). The cache is invalidated
    when any Monte Carlo parameter changes (distribution,
    distribution_parameters, period, mc_number, seed). As a consequence,
    unseeded results of PortfolioDCF.find_the_largest_withdrawals_size() and of
    the CAGR-distribution methods shift versus 2.1.1: the bisection in
    find_the_largest_withdrawals_size now evaluates every candidate against the
    same scenario set (removing the sampling noise that previously broke its
    monotonicity). Use set_mc_parameters(..., seed=...) for reproducible runs.
  • Portfolio.dcf.find_the_largest_withdrawals_size() is faster: the bisection
    search is replaced with Brent's method (scipy.optimize.brentq) on a signed
    goal residual, and both ends of withdrawals_range are checked first so the
    solver exits after 1–2 Monte Carlo simulations when the solution lies outside
    the range. The public signature, the Result shape and the stopping rule
    (error_rel < tolerance_rel) are unchanged; iter_max now caps objective
    evaluations (Monte Carlo simulations), including the two range-end checks, so
    the history of intermediate attempts in Result.solutions differs from the
    former bisection midpoints. iter_max values below 1 are now rejected with a
    ValueError.
  • Monte Carlo wealth simulation is vectorized: Portfolio.dcf.monte_carlo_wealth()
    and everything built on it (monte_carlo_survival_period(),
    plot_forecast_monte_carlo(),
    find_the_largest_withdrawals_size()) now computes all
    random paths in one pass (get_wealth_indexes_fv_with_cashflow_mc in
    okama.portfolios.dcf_calculations) instead of a per-path pandas apply.
    Results are unchanged (pinned by an equivalence-test grid across strategies,
    frequencies and extra cash flows); measured speedup of one full simulation is
    three to four orders of magnitude (×1400 for yearly and ×6800 for monthly
    withdrawal frequencies on 1,000 paths × 30 years). The negative-balance
    masking and the survival-date scan are vectorized as well.
  • Monte Carlo cash-flow simulation is vectorized as well:
    Portfolio.dcf.monte_carlo_cash_flow() builds its cache with the new
    get_cash_flow_fv_mc (one pass for all paths, sharing a core with the
    wealth engine), and Portfolio.dcf.monte_carlo_irr() now consumes the
    shared monte_carlo_wealth/monte_carlo_cash_flow caches instead of two
    per-path computations (measured end-to-end speedup of monte_carlo_irr():
    ×488 on 1,000 paths × 30 years).

Fixed

  • PortfolioDCF.monte_carlo_cash_flow() with remove_if_wealth_index_negative=True
    previously masked a cash-flow draw against a wealth-index draw generated from
    different randomness; with the shared cached draw the depletion mask is now
    consistent per path.
  • In periodic-frequency simulations, the first month of a period containing
    extra cash flows (time_series) skipped its return in
    get_wealth_indexes_fv_with_cashflow (and additionally skipped the cash
    flow in get_cash_flow_fv balance tracking). The recursion is now uniform
    for every month; wealth indexes and cash flow series with extra cash flows
    at year/half-year/quarter frequencies change accordingly (#81).
  • VanguardDynamicSpending floor_ceiling limits never bound in wealth-index
    calculations (wealth_index, monte_carlo_wealth and everything built on
    them): the previous withdrawal was always reported as 0. Wealth indexes for
    VDS strategies with floor_ceiling change accordingly and are now
    consistent with cash_flow_ts (#82).
  • VanguardDynamicSpending.__init__ bypassed the validating setters for
    floor_ceiling, min_max_annual_withdrawals and adjust_min_max, so
    out-of-contract limits (e.g. a non-negative floor or min > max) were
    silently accepted at construction. The constructor now routes through the
    public setters, and both limit setters accept None (meaning "limit
    disabled") so the documented defaults remain valid (#83).

Security

Docs

  • New "IRR — money-weighted return" section in the
    04 investment portfolios with DCF
    notebook demonstrating Portfolio.dcf.irr() and
    Portfolio.dcf.monte_carlo_irr().
  • The find_the_largest_withdrawals_size() docstring example now shows a real,
    seeded solver run (range-end checks followed by Brent steps).

v2.1.1

28 May 07:08

Choose a tag to compare

Adds systematic (grid-based) enumeration of portfolio weights on the efficient frontier as a deterministic alternative to Monte-Carlo sampling, and enriches the frontier sampling outputs with per-asset weight columns.

Added

  • EfficientFrontier.get_grid_portfolios() (multi-period, rebalanced) and EfficientFrontierSingle.get_grid_portfolios() (single-period) enumerate all portfolios whose weights lie on a fixed percentage grid (step, default 0.10), respecting per-asset bounds. This complements the random get_monte_carlo() with a reproducible, exhaustive sampling of the feasible region.
  • Float.get_grid_weights() helper in okama.common.helpers — a reusable generator of all weight vectors summing to 1.0 on a given grid step, honoring per-asset bounds. The step is validated to lie in [0.01, 1.0] and to divide 1.0 evenly.
  • Per-asset weight columns in the outputs of EfficientFrontier.get_monte_carlo() and EfficientFrontier.get_grid_portfolios() (multi-period), matching the column layout already produced by EfficientFrontierSingle.get_monte_carlo().

Tooling

  • Pinned sphinx < 9 for the docs build: the Sphinx 9.x autodoc rewrite raises ValueError: The truth value of a DataFrame is ambiguous on pandas DataFrame class attributes (e.g. in okama.common.make_asset_list).
  • Bumped the pre-commit ruff hook to v0.15.14 to match the poetry/CI ruff version, so it stops re-applying fixes the project ruff already suppresses via # noqa: UP0xx comments.

Full Changelog: v2.1.0...v2.1.1

v2.1.0

11 May 08:14

Choose a tag to compare

okama 2.1.0

Feature release that switches get_cagr and get_cumulative_return to an expanding-window definition, makes the okama API endpoint configurable via environment variables, and ships a batch of correctness fixes across the helpers, frontier, DCF, macro, and plotting layers.

Changed

  • AssetList.get_cumulative_return() and Portfolio.get_cumulative_return() now return an expanding cumulative return series instead of a single end-of-period scalar. Notebook 03 investment portfolios.ipynb updated accordingly.
  • AssetList.get_cagr() and Portfolio.get_cagr() now compute CAGR on an expanding window, consistent with get_cumulative_return().

Added

  • Configurable API base URL and request timeout via environment variables (OKAMA_API_URL, OKAMA_API_TIMEOUT) in okama.settings and okama.api.api_methods.

Fixed

  • Frame.get_semideviation() (in okama.common.helpers) now uses the sample mean of returns instead of the population mean, restoring the standard semideviation definition; propagated through AssetList and Portfolio consumers.
  • AssetList.recovery_periods is robust to a last_date that is not on a month start.
  • EfficientFrontier / EfficientFrontierReb (single- and multi-period variants) now raise RuntimeError on failed SLSQP optimisation instead of silently returning invalid weights.
  • AssetList.plot_assets() / Portfolio.plot_assets() autoscale no longer passes the invalid axis="year" argument.
  • Inflation.cumulative_inflation (in okama.macro) uses .iloc[-1] instead of positional [-1], fixing a pandas FutureWarning / lookup bug.
  • PortfolioDCF discount-rate attribute renamed from the misspelled monlthly_discount_rate to monthly_discount_rate (okama.portfolios.dcf, okama.portfolios.dcf_calculations).
  • Helpers producing NaN rows now use np.nan in dict.fromkeys(...) so resulting DataFrames keep float dtype (okama.common.helpers, consumed by AssetList and Portfolio).

Removed

  • Dead Portfolio._clear_cf_cache method.

Tooling

  • Enabled ruff UP (pyupgrade) rules and applied auto-fixes across okama.common.helpers, okama.common.helpers.rebalancing, okama.portfolios.dcf, and notebook 11 rebalancing portfolio.ipynb.
  • Aligned declared supported Python versions with the pyproject.toml minimum; AGENTS.md now mandates a TDD workflow for production code changes.
  • .gitignore excludes .env.

Full Changelog: v2.0.1...v2.1.0

Okama 2.0.1

14 Apr 09:35

Choose a tag to compare

Okama 2.0.1 is a maintenance-focused release that improves compatibility with pandas 3.x and Python 3.14, refines PortfolioDCF cash flow calculations, and makes several plotting and sharing APIs easier to integrate.

New features

pandas 3.x and Python 3.14 compatibility

  • okama now supports pandas 3.x and Python 3.14.
  • Compatibility updates were applied across Asset, AssetList, Portfolio, PortfolioDCF, MacroABC, Rebalance, and related helpers to keep timestamp conversion, grouping, and resampling behavior working with the new pandas aliases.

Plotting and integration improvements

  • PortfolioDCF.plot_forecast_monte_carlo(), MonteCarlo.plot_qq(), and MonteCarlo.plot_hist_fit() now return matplotlib Axes objects, which simplifies embedding okama charts into custom figures.
  • Portfolio.plot_assets() and EfficientFrontier.plot_assets() now accept extra matplotlib.pyplot.scatter() keyword arguments for custom styling.
  • Portfolio.okamaio_link now serializes the full Rebalance configuration, including Rebalance.period, Rebalance.abs_deviation, and Rebalance.rel_deviation.

Performance and analytics improvements

  • EfficientFrontier adds caching for intermediate calculations to speed up repeated optimization runs.
  • AssetList.get_monthly_geometric_mean_return() and Portfolio.get_monthly_geometric_mean_return() add direct monthly geometric mean return calculations.
  • Asset.first_date and Asset.last_date are now used more consistently by ListMaker, which improves control over downloaded history ranges.

Bugs fixed

  • PortfolioDCF.wealth_index() and PortfolioDCF.cash_flow_ts() no longer apply reverse discounting in present-value mode.
  • PortfolioDCF.find_the_largest_withdrawals_size() was fixed for Monte Carlo period validation and now works correctly with VanguardDynamicSpending and CutWithdrawalsIfDrawdown.
  • PortfolioDCF.plot_forecast_monte_carlo() no longer mutates PortfolioDCF.cashflow_parameters while plotting.
  • MonteCarlo distribution fitting and plotting fixes improve float dtype handling and restore compatibility in QQ/histogram workflows.
  • pandas compatibility fixes also cover deprecated DataFrame.applymap(), pd.concat(..., copy=...), and updated pd.Grouper frequency aliases.

Developer experience

  • Linting and formatting migrated from flake8 + black to ruff check, including GitHub workflows, pre-commit configuration, and AGENTS.md instructions for contributors.
  • Added .pre-commit-config.yaml with ruff hooks and a top-level requirements.txt mirroring runtime dependencies from pyproject.toml.
  • Added CHANGELOG.md following the Keep a Changelog format and Semantic Versioning.
  • README now shows GitHub and pepy.tech download badges and an updated project roadmap.

Documentation and examples

Updated documentation and notebooks reflect the current API changes:

Okama 2.0.0

01 Apr 11:30

Choose a tag to compare

Unified Efficient Frontier with multi-period optimization and advanced withdrawal strategies for retirement planning.

  • Merged EfficientFrontier and EfficientFrontierReb into a single EfficientFrontier class
  • Significantly faster Efficient Frontier calculations with caching, parallel computations, and objective function optimization
  • New advanced withdrawal strategies: Vanguard Dynamic Spending (VDS) and CutWithdrawalsIfDrawdown (CWD)
image

Major Changes

Unified EfficientFrontier class with multi-period optimization

EfficientFrontier and EfficientFrontierReb have been merged into a single EfficientFrontier class. Every Efficient Frontier is now computed with rebalancing (multi-period) by default. Optimization of rebalanced portfolios now supports weight constraints (bounds), allowing users to set minimum and maximum allocation limits for each asset.

The calculation speed has been significantly improved through:

  • Caching of intermediate results
  • Parallel computations
  • Objective function optimization
  • Fast vectorized methods in Rebalance class

WARNING:
The legacy single-period class has been renamed to EfficientFrontierSingle. If you were using the old EfficientFrontier (single-period), switch to EfficientFrontierSingle.

import matplotlib.pyplot as plt

# New unified EfficientFrontier (multi-period with rebalancing)

ls = ["SPY.US", "GLD.US"]
curr = "USD"
y = ok.EfficientFrontier(
    assets=ls,
    first_date="2004-12",
    last_date="2020-10",
    ccy=curr,
    rebalancing_strategy=ok.Rebalance(period="year"),  # set rebalancing period to one year
    ticker_names=True,  # use tickers in DataFrame column names (can be set to False to show full assets names instead tickers)
    n_points=40,  # number of points in the Efficient Frontier
) 
fig, ax = plt.subplots(figsize=(12, 10))

# Plot the Efficient Frontier
ax.plot(df_reb_year.Risk, df_reb_year.CAGR, label="Annually rebalanced")
ax.plot(df_not_reb.Risk, df_not_reb.CAGR, label="Not rebalanced")

# Plot the assets
y.plot_assets(kind="cagr")

# Set axis labels
ax.set_xlabel("Risk (Standard Deviation)")
ax.set_ylabel("CAGR")
ax.legend();
image

Advanced Withdrawal Strategies

Two new cash flow strategies for retirement planning and endowment fund management:

Vanguard Dynamic Spending (VDS)

Implementation of the Vanguard Dynamic Spending rule that adjusts withdrawals based on portfolio performance with floor and ceiling guardrails.

pf = ok.Portfolio(['SPY.US', 'BND.US'], weights=[.6, .4], first_date='2010-01', last_date='2024-10', ccy='USD', inflation=True)
vds = ok.VanguardDynamicSpending(
    parent=pf,
    initial_investment=1_000_000,
    frequency="year",
    percentage=-0.05,
    floor_ceiling=(-0.05, 0.10),  # -5% floor / +10% ceiling
)
pf.dcf.cashflow_parameters = vds

CutWithdrawalsIfDrawdown (CWD)

Risk-based withdrawal strategy that reduces the withdrawal amount when portfolio drawdown exceeds defined thresholds.

cwd = ok.CutWithdrawalsIfDrawdown(
    parent=pf,
    initial_investment=1_000_000,
    frequency="year",
    amount=-60_000,
    indexation="inflation",
    crash_threshold_reduction=[(.10, .25), (.20, .50), (.35, 1)],
)
pf.dcf.cashflow_parameters = cwd

Detailed explanation of new withdrawal strategies is at 04 investment portfolios with DCF.ipynb.

New Classes and Methods

first_date & last_date parameters in Asset

  • first_date & last_date parameters are available in the Asset class. Using these parameters could significantly improve the speed of downloading historical data.

Cash flow strategies

  • IndexationStrategy, PercentageStrategy, TimeSeriesStrategy — base cash flow management classes
  • VanguardDynamicSpending — dynamic spending rule with floor/ceiling guardrails and min/max annual withdrawal adjustments
  • CutWithdrawalsIfDrawdown — drawdown-based withdrawal reduction strategy with configurable threshold/reduction pairs

EfficientFrontier improvements

  • EfficientFrontier.plot_transition_map() — visualization of asset allocation across the Efficient Frontier
  • EfficientFrontier.plot_cml() — Capital Market Line plotting
  • EfficientFrontier.get_most_diversified_portfolio() — Most Diversified Portfolio (MDP) optimization based on diversification ratio
  • EfficientFrontier.get_monte_carlo() generates random portfolios with Monte Carlo simulation respecting bounds
  • EfficientFrontier.plot_assets() now accepts **kwargs for matplotlib scatter()

AssetList

  • AssetList.get_monthly_geometric_mean_return() — new method for geometric mean return calculation

MonteCarlo

  • MonteCarlo.plot_forecast_monte_carlo() now returns matplotlib Axes object
  • MonteCarlo.get_parameters_for_distribution() — distribution fitting with parameters for normal, lognormal, and Student's t distributions
  • MonteCarlo.kstest() and MonteCarlo.kstest_for_all_distributions() — Kolmogorov-Smirnov goodness-of-fit tests
  • MonteCarlo.plot_hist_fit() — histogram with fitted distribution overlay
  • MonteCarlo.plot_qq() — QQ-plot for visual distribution fit assessment

Portfolio architecture

  • New MonteCarlo class for advanced Monte Carlo simulations and statistical distribution analysis (moved from Portfolio)
  • New PortfolioDCF class for discounted cash flow analysis, portfolio survival analysis, and withdrawal strategy testing
  • New Rebalance helper class encapsulating rebalancing logic with wealth_ts_ef and return_ror_ts_ef methods for fast optimization

Documentation and Examples

New and updated Jupyter Notebook examples in the /examples directory:

All existing notebooks have been refreshed to reflect the latest API changes in okama 2.0.0.

Bug Fixes

  • Fixed AssetList.annual_return_ts and Portfolio.annual_return_ts annual arithmetic mean return compounding calculation
  • Fixed PortfolioDCF.wealth_index(discounting="pv") calculation
  • Fixed PortfolioDCF.cashflow_parameters being modified after plot_forecast_monte_carlo()
  • Fixed PortfolioDCF.find_the_largest_withdrawals_size not preserving original CashFlow parameters
  • Fixed PortfolioDCF cash flow adjustments in first and last year for partial periods
  • Fixed Portfolio.mean_return calculation to use ror.mean() formula
  • Fixed MonteCarlo._get_params_for_lognormal parameter calculation
  • Fixed MonteCarlo.kstest() fitting to lognormal distribution to use gross returns
  • Fixed Pandas FutureWarning for concat with empty DataFrame in Rebalance class
  • Fixed MonteCarlo.mc_number setter parameter name
  • Fixed PortfolioDCF._target_cagr_range_left calculation

Other Changes

  • Python 3.10 is no longer supported
  • API connection switched to HTTPS with SSL verification
  • Updated all Jupyter Notebook examples in /examples directory
  • Significant increase in test coverage for DCF, Monte Carlo, and cash flow strategy modules

Full Changelog: v1.5.0...v2.0.0

Okama 1.5.0

25 Jun 08:00

Choose a tag to compare

Rebalancing bands - new rebalancing strategies for investment portfolios.

  • Calendar-based rebalancing
  • Rebalancing bands (threshold-based)

Mean-variance optimization with rebalancing-strategy-adjusted Efficient Frontier and asset weight bounds.

rebalancing

New features

Rebalance - new class to define rebalancing strategies

Rebalancing strategies are now defined in both Portfolio and EfficientFrontierReb with Rebalance class.

rs = ok.Rebalance(period="year", abs_deviation=0.10, rel_deviation=0.30)
pf = ok.Portfolio(['SPY.US', 'AGG.US'], rebalancing_strategy=rs)

WARNING:
The previous Portfolio class initialization method is now deprecated.
ok.Portfolio(rebalancing_period="year") will not work anymore.
However, as the default rebalancing strategy is monthly calendar-based. The simple definition without rebalancing strategy is still working:

ok.Portfolio(['SPY.US', 'AGG.US'], weights=[.6, .4])

Rebalance class

  • New Rebalance class has 3 parameters: period, abs_deviation, rel_deviation
  • Rebalance.wealth_ts() calculates wealth index time series of rebalanced portfolio (optionally with assets wealth time series)
  • Rebalance.assets_weights_ts() calculates assets weights monthly time series for rebalanced portfolio
  • Rebalance.return_ror_ts() returns monthly rate of return time series of rebalanced portfolio

New methods and properties in Portfolio class

  • new property rebalancing_strategy to configure rebalancing period, absolute and relative deviations
  • new property rebalancing_events returns time series of rebalancing events and type of rebalancing

Changes in PortoflioDCF class

  • PortfolioDCF.monte_carlo_wealth_pv calculates discounted random wealth indexes with cash flows
  • PortfolioDCF.monte_carlo_wealth_fv calculates not discounted (nominal) random wealth indexes with cash flows
  • PortfolioDCF.find_the_largest_withdrawals_size() now uses bisection method to find the largest withdrawals size.
  • PortfolioDCF.find_the_largest_withdrawals_size() has 3 possible goals: 'maintain_balance_pv', 'maintain_balance_fv' and 'survival_period'
  • PortfolioDCF.find_the_largest_withdrawals_size() new attribute withdrawals_range defines the possible range for withdrawals to speed up the calculations
  • PortfolioDCF.find_the_largest_withdrawals_size() has iter_max attribute to limit the intermediate steps when searching for resolution
  • PortfolioDCF.find_the_largest_withdrawals_size() returns Result class. If the solutions is not found it is still possible to see the intermediate steps

New methods and properties in EfficienFrontierReb class

EfficienFrontierReb class now uses rebalancing_strategy parameter for initialization (the same as Portfolio).
It supports bounds to define the weight limitations for the assets.

  • new rebalancing_strategy parameter to define the rebalancing strategy
  • new bounds parameter defines the bounds for the assets weights
  • new EfficienFrontierReb.plot_pair_ef() method plots the Efficient Frontier of every pair of assets

Changes in EfficientFrontier class

  • EfficientFrontier.get_monte_carlo method generates random rebalanced portfolios with Monte Carlo simulation according to bounds limitations.

New Jupyter Notebook with examples for Rebalancing strategies

New Jupyter Notebook with examples of investment portfolios with different rebalancing strategies:
10 rebalancing portfolio.ipynb

Okama 1.4.4

11 Oct 09:21

Choose a tag to compare

New examples for investment portfolios with cash flow in 04 investment portfolios with DCF.ipynb.

Several bugs in Portfolio and PortfolioDCF are fixed.

Fixed:

  • Portfolio.dcf.initial_investment_pv must return None if cash flow parameters are not defined
  • add use_discounted_values parameter to helpers.Frame.get_wealth_indexes_with_cashflow
  • use self.use_discounted_values = False in plot_forecast_monte_carlo for any value of backtest parameter
  • clean up Portfolio dat cache if symbol changed

Okama 1.4.3

09 Oct 04:35

Choose a tag to compare

Okama 1.4.3 is dedicated to Cash Flow strategies and Monte Carlos simulations.

New features

3 new classes to set up Cash Flow strategies

Cash flow parameters for investment portfolios are now configured in the corresponding classes.

  • IndexationStrategy for strategies with regular indexed withdrawals / contributions
  • PercentageStrategy for strategies weith regualr fixed percentage withdrawals / contributions
  • TimeSeriesStrategy for strategies with user-defined withdrawals and contributions. Withdrawals, contributions, as well as their dates, are defined in the dictionary.

All 3 classes are inhereted from parent class CashFlow.
Portfolio class does not have cash flow parameters (initial_amount, cashflow, discount_rate) anymore.

New class to set up Monte Carlo simulation parameters

MonteCarlos class has several properties:

  • distribution - the type of a distribution to generate random rate of return
  • period - forecast period in years for portfolio wealth index time series
  • number - number of random wealth indexes to generate with Monte Carlo simulation

All Monte Carlos properties are linked to PortfolioDCF instance and can be accessed by Portfolio().dcf.mc construction. For example the type of random distribution is available through Portfolio().dcf.mc.disctribution.

New methods and properties in PortfolioDCF

PortfolioDCF has a new parameter use_discounted_values (default is False). Id defines whether to use discounted values in backtesting wealth indexes (initial investments, withdrawal or contribution size). discount_rate parameter is shifted from Portfolio to PortfolioDCF.

  • find_the_largest_withdrawals_size - find the largest withdrawals size for Monte Carlo simulation according to Cashflow Strategy. This method works with IndexationStrategy and PercentageStrategy
  • initial_investment_fv property to calculate the future value (FV) of the initial investments at the end of forecast period.
  • initial_investment_pv property to calculate the discounted value (PV) of the initial investments at the historical first date
  • wealth_index_with_assets works as the same property of Portfolio but considers cash flow (contributions and withdrawals)
  • set_mc_parameters method is a shortcut to add Monte Carlo simulation parameters

Changes in methods and properties in PortfolioDCF

  • monte_carlo_survival_period, survival_date_hist and survival_period_hist methods have now new parameter threshold. The threshold defines the percentage of the initial investments when the portfolio balance considered voided
  • plot_forecast_monte_carlo number of parameters is reduced to: backtest and figsize