diff --git a/examples/03 investment portfolios.ipynb b/examples/03 investment portfolios.ipynb index 1a9e4b3..bbf1867 100644 --- a/examples/03 investment portfolios.ipynb +++ b/examples/03 investment portfolios.ipynb @@ -54,7 +54,7 @@ "import matplotlib.pyplot as plt\n", "\n", "plt.rcParams[\"figure.figsize\"] = [12.0, 6.0]\n", - "warnings.simplefilter(action='ignore', category=FutureWarning)\n", + "warnings.simplefilter(action=\"ignore\", category=FutureWarning)\n", "\n", "import okama as ok" ] diff --git a/examples/04 investment portfolios with DCF.ipynb b/examples/04 investment portfolios with DCF.ipynb index 1f47ff8..980cf53 100644 --- a/examples/04 investment portfolios with DCF.ipynb +++ b/examples/04 investment portfolios with DCF.ipynb @@ -59,7 +59,7 @@ "import okama as ok\n", "\n", "plt.rcParams[\"figure.figsize\"] = [12.0, 6.0]\n", - "warnings.simplefilter(action='ignore', category=FutureWarning)" + "warnings.simplefilter(action=\"ignore\", category=FutureWarning)" ], "metadata": { "collapsed": false @@ -92,12 +92,12 @@ ], "source": [ "pf = ok.Portfolio(\n", - " ['SPY.US', 'AGG.US', 'GLD.US'],\n", - " weights=[.60, .35, .05],\n", - " ccy='USD',\n", + " [\"SPY.US\", \"AGG.US\", \"GLD.US\"],\n", + " weights=[0.60, 0.35, 0.05],\n", + " ccy=\"USD\",\n", " inflation=False,\n", - " last_date='2024-01',\n", - " rebalancing_period='year',\n", + " last_date=\"2024-01\",\n", + " rebalancing_period=\"year\",\n", " initial_amount=300_000, # portfolio initial investments\n", " cashflow=-2_000, # portfolio monthly withdrawals\n", ")\n", @@ -228,7 +228,7 @@ } ], "source": [ - "pf.dcf.survival_date # the date when portfolio has zero value after withdrawals" + "pf.dcf.survival_date # the date when portfolio has zero value after withdrawals" ], "metadata": { "collapsed": false @@ -335,7 +335,7 @@ } ], "source": [ - "pf.dcf.initial_amount_pv # the value of initial investments PV changes" + "pf.dcf.initial_amount_pv # the value of initial investments PV changes" ], "metadata": { "collapsed": false @@ -365,12 +365,12 @@ "outputs": [], "source": [ "pf2 = ok.Portfolio(\n", - " ['MCFTR.INDX', 'RGBITR.INDX', 'GC.COMM'],\n", - " weights=[.40, .40, .20],\n", - " ccy='RUB',\n", + " [\"MCFTR.INDX\", \"RGBITR.INDX\", \"GC.COMM\"],\n", + " weights=[0.40, 0.40, 0.20],\n", + " ccy=\"RUB\",\n", " inflation=True,\n", - " last_date='2024-01',\n", - " rebalancing_period='year',\n", + " last_date=\"2024-01\",\n", + " rebalancing_period=\"year\",\n", " initial_amount=600_000, # portfolio initial investments\n", " cashflow=-4_000, # portfolio monthly withdrawals\n", ")" @@ -403,10 +403,10 @@ ], "source": [ "pf2.dcf.plot_forecast_monte_carlo(\n", - " distr='norm', # the rate of return distribution. Can be set to `norm` for normal distribution or `lognorm` for lognormal\n", + " distr=\"norm\", # the rate of return distribution. Can be set to `norm` for normal distribution or `lognorm` for lognormal\n", " years=30, # future period\n", " backtest=True, # chose whether to plot backtest portfolio (True) or start from the future time series (False)\n", - " n=50 # Number of random time series generated by Monte Carlo\n", + " n=50, # Number of random time series generated by Monte Carlo\n", ")" ], "metadata": { @@ -446,9 +446,9 @@ "outputs": [], "source": [ "s = pf2.monte_carlo_survival_period(\n", - " distr='norm', # the rate of return distribution. Can be set to `norm` for normal distribution, `lognorm` for lognormal or 't' for Student's\n", + " distr=\"norm\", # the rate of return distribution. Can be set to `norm` for normal distribution, `lognorm` for lognormal or 't' for Student's\n", " years=30, # future period\n", - " n=100 # Number of random time series generated by Monte Carlo\n", + " n=100, # Number of random time series generated by Monte Carlo\n", ")" ], "metadata": { diff --git a/examples/05 macroeconomics - inflation rates.ipynb b/examples/05 macroeconomics - inflation rates.ipynb index c829da1..2e06337 100644 --- a/examples/05 macroeconomics - inflation rates.ipynb +++ b/examples/05 macroeconomics - inflation rates.ipynb @@ -59,7 +59,7 @@ "import okama as ok\n", "\n", "plt.rcParams[\"figure.figsize\"] = [12.0, 6.0]\n", - "warnings.simplefilter(action='ignore', category=FutureWarning)" + "warnings.simplefilter(action=\"ignore\", category=FutureWarning)" ], "metadata": { "collapsed": false @@ -107,7 +107,7 @@ } ], "source": [ - "ok.symbols_in_namespace('INFL') # the list of available inflation data series" + "ok.symbols_in_namespace(\"INFL\") # the list of available inflation data series" ], "metadata": { "collapsed": false @@ -127,7 +127,7 @@ } ], "source": [ - "us_inf = ok.Inflation('USD.INFL', first_date='1913-01', last_date='2024-01') # US dollar inflation\n", + "us_inf = ok.Inflation(\"USD.INFL\", first_date=\"1913-01\", last_date=\"2024-01\") # US dollar inflation\n", "us_inf" ], "metadata": { @@ -166,7 +166,7 @@ } ], "source": [ - "us_inf.rolling_inflation['1980':].plot(); # plot US 12-months inflation (CPI)" + "us_inf.rolling_inflation[\"1980\":].plot(); # plot US 12-months inflation (CPI)" ], "metadata": { "collapsed": false @@ -224,7 +224,7 @@ } ], "source": [ - "us_inf.annual_inflation_ts['2000': '2020'].plot(kind='bar');" + "us_inf.annual_inflation_ts[\"2000\":\"2020\"].plot(kind=\"bar\");" ], "metadata": { "collapsed": false @@ -249,6 +249,7 @@ " Plot 12-month rolling inflation for several countries.\n", " \"\"\"\n", " import pandas as pd\n", + "\n", " fig, ax = plt.subplots(figsize=[12.0, 8.0])\n", " date1 = pd.to_datetime(first_date)\n", " date2 = pd.to_datetime(last_date)\n", @@ -256,17 +257,19 @@ " for i, ccy in enumerate(ccy_list):\n", " infl_obj = ok.Inflation(ccy)\n", " if i == 0:\n", - " infl_df = infl_obj.rolling_inflation[str(date1):] * 100\n", + " infl_df = infl_obj.rolling_inflation[str(date1) :] * 100\n", " else:\n", - " infl = infl_obj.rolling_inflation[str(date1):] * 100\n", - " infl_df = pd.concat([infl_df, infl], axis=1, join='inner').dropna()\n", + " infl = infl_obj.rolling_inflation[str(date1) :] * 100\n", + " infl_df = pd.concat([infl_df, infl], axis=1, join=\"inner\").dropna()\n", "\n", " for infl_symbol in infl_df.columns:\n", - " ticker = infl_symbol.split('.', 1)[0]\n", - " ax.plot(infl_df[infl_symbol].index.to_timestamp(), infl_df[infl_symbol], linewidth=2, label=f'Inflation {ticker}')\n", + " ticker = infl_symbol.split(\".\", 1)[0]\n", + " ax.plot(\n", + " infl_df[infl_symbol].index.to_timestamp(), infl_df[infl_symbol], linewidth=2, label=f\"Inflation {ticker}\"\n", + " )\n", "\n", " ax.set_xlim(date1, date2 + pd.Timedelta(30, unit=\"d\"))\n", - " ax.legend(loc='upper right')" + " ax.legend(loc=\"upper right\")" ], "metadata": { "collapsed": false @@ -286,7 +289,7 @@ } ], "source": [ - "infl_symbols = list(ok.symbols_in_namespace('INFL').loc[:, 'symbol'])\n", + "infl_symbols = list(ok.symbols_in_namespace(\"INFL\").loc[:, \"symbol\"])\n", "infl_symbols" ], "metadata": { @@ -307,7 +310,7 @@ } ], "source": [ - "plot_inflation_list(ccy_list=infl_symbols, first_date='2000-01', last_date='2020-01')" + "plot_inflation_list(ccy_list=infl_symbols, first_date=\"2000-01\", last_date=\"2020-01\")" ], "metadata": { "collapsed": false @@ -355,7 +358,7 @@ } ], "source": [ - "ok.Inflation('EUR.INFL', first_date='2000-01', last_date='2020-01').purchasing_power_1000" + "ok.Inflation(\"EUR.INFL\", first_date=\"2000-01\", last_date=\"2020-01\").purchasing_power_1000" ], "metadata": { "collapsed": false @@ -384,7 +387,7 @@ } ], "source": [ - "ok.Inflation('GBP.INFL', first_date='2000-01', last_date='2020-01').purchasing_power_1000" + "ok.Inflation(\"GBP.INFL\", first_date=\"2000-01\", last_date=\"2020-01\").purchasing_power_1000" ], "metadata": { "collapsed": false @@ -413,7 +416,7 @@ } ], "source": [ - "ok.Inflation('CNY.INFL', first_date='2000-01', last_date='2020-01').purchasing_power_1000" + "ok.Inflation(\"CNY.INFL\", first_date=\"2000-01\", last_date=\"2020-01\").purchasing_power_1000" ], "metadata": { "collapsed": false @@ -442,7 +445,7 @@ "execution_count": 38, "outputs": [], "source": [ - "ru_inf = ok.Inflation('RUB.INFL', first_date='2000-01', last_date='2020-01') # Russian rubl inflation" + "ru_inf = ok.Inflation(\"RUB.INFL\", first_date=\"2000-01\", last_date=\"2020-01\") # Russian rubl inflation" ], "metadata": { "collapsed": false @@ -482,7 +485,7 @@ "execution_count": 43, "outputs": [], "source": [ - "ru_inf.set_values_monthly(date='2020-02', value=0.006)" + "ru_inf.set_values_monthly(date=\"2020-02\", value=0.006)" ], "metadata": { "collapsed": false @@ -545,7 +548,7 @@ } ], "source": [ - "isr_inf = ok.Inflation('ILS.INFL') # Israeli shekel inflation\n", + "isr_inf = ok.Inflation(\"ILS.INFL\") # Israeli shekel inflation\n", "isr_inf" ], "metadata": { @@ -567,7 +570,7 @@ } ], "source": [ - "isr_inf.describe([5, 10, 20]) # statistics for 5, 10 and 20 years and full period" + "isr_inf.describe([5, 10, 20]) # statistics for 5, 10 and 20 years and full period" ], "metadata": { "collapsed": false @@ -615,7 +618,7 @@ } ], "source": [ - "ok.symbols_in_namespace('RATE') # the list of available rates data series" + "ok.symbols_in_namespace(\"RATE\") # the list of available rates data series" ], "metadata": { "collapsed": false @@ -644,7 +647,7 @@ } ], "source": [ - "us_rate = ok.Rate('US_EFFR.RATE')\n", + "us_rate = ok.Rate(\"US_EFFR.RATE\")\n", "us_rate" ], "metadata": { @@ -674,7 +677,7 @@ } ], "source": [ - "us_rate.values_monthly['2020':].plot();" + "us_rate.values_monthly[\"2020\":].plot();" ], "metadata": { "collapsed": false @@ -760,32 +763,34 @@ "import matplotlib.dates as mdates\n", "import pandas as pd\n", "\n", - "def plot_infl_and_keyrate(infl: pd.DataFrame,\n", - " rate: pd.DataFrame,\n", - " first_date: str,\n", - " last_date: str,\n", - " figsize: list = [12, 6],\n", - " ):\n", + "\n", + "def plot_infl_and_keyrate(\n", + " infl: pd.DataFrame,\n", + " rate: pd.DataFrame,\n", + " first_date: str,\n", + " last_date: str,\n", + " figsize: list = [12, 6],\n", + "):\n", "\n", " fig, ax = plt.subplots(figsize=figsize)\n", " first_date_dt = pd.to_datetime(first_date)\n", " last_date_dt = pd.to_datetime(last_date)\n", - " rate = rate.loc[first_date: last_date]\n", + " rate = rate.loc[first_date:last_date]\n", " if infl is not None:\n", - " infl = infl.loc[first_date: last_date]\n", - " ax.plot(infl.index.to_timestamp(), infl * 100, color ='blue', linewidth = 2, label='12-month inflation')\n", - " ax.plot(rate.index.to_timestamp(), rate * 100, color ='green', linewidth = 2, label='Key rate')\n", + " infl = infl.loc[first_date:last_date]\n", + " ax.plot(infl.index.to_timestamp(), infl * 100, color=\"blue\", linewidth=2, label=\"12-month inflation\")\n", + " ax.plot(rate.index.to_timestamp(), rate * 100, color=\"green\", linewidth=2, label=\"Key rate\")\n", "\n", " ax.set_xlim(first_date_dt, last_date_dt + pd.DateOffset(months=1))\n", "\n", " # set tickers format\n", " years = mdates.YearLocator()\n", - " years_fmt = mdates.DateFormatter('%Y')\n", + " years_fmt = mdates.DateFormatter(\"%Y\")\n", " ax.xaxis.set_major_locator(years)\n", " ax.xaxis.set_major_formatter(years_fmt)\n", "\n", - " ax.legend(loc='upper left')\n", - " ax.set_ylabel('rate, %')" + " ax.legend(loc=\"upper left\")\n", + " ax.set_ylabel(\"rate, %\")" ], "metadata": { "collapsed": false @@ -796,8 +801,8 @@ "execution_count": 76, "outputs": [], "source": [ - "infl = ok.Inflation('USD.INFL').rolling_inflation\n", - "rates = ok.Rate('US_EFFR.RATE').values_monthly # US Federal Reserve Effective Federal Funds Rate" + "infl = ok.Inflation(\"USD.INFL\").rolling_inflation\n", + "rates = ok.Rate(\"US_EFFR.RATE\").values_monthly # US Federal Reserve Effective Federal Funds Rate" ], "metadata": { "collapsed": false @@ -817,7 +822,7 @@ } ], "source": [ - "plot_infl_and_keyrate(infl=infl, rate=rates, first_date='2000-01', last_date='2020-01')" + "plot_infl_and_keyrate(infl=infl, rate=rates, first_date=\"2000-01\", last_date=\"2020-01\")" ], "metadata": { "collapsed": false @@ -856,7 +861,7 @@ } ], "source": [ - "ok.symbols_in_namespace('RATIO')" + "ok.symbols_in_namespace(\"RATIO\")" ], "metadata": { "collapsed": false @@ -899,7 +904,7 @@ } ], "source": [ - "cape = ok.Indicator('GBR_CAPE10.RATIO') # CAPE 10 for UK market\n", + "cape = ok.Indicator(\"GBR_CAPE10.RATIO\") # CAPE 10 for UK market\n", "cape" ], "metadata": { @@ -973,7 +978,7 @@ } ], "source": [ - "cape_symbols = ok.symbols_in_namespace('RATIO')['symbol']\n", + "cape_symbols = ok.symbols_in_namespace(\"RATIO\")[\"symbol\"]\n", "cape_objects = [ok.Indicator(cape) for cape in cape_symbols]\n", "cape_df = pd.DataFrame({cape.country: cape.values_monthly for cape in cape_objects})\n", "cape_df.plot();" diff --git a/main.py b/main.py index d515da6..582669b 100644 --- a/main.py +++ b/main.py @@ -1,19 +1,17 @@ import warnings -import matplotlib.pyplot as plt import okama as ok warnings.filterwarnings("ignore") pf = ok.Portfolio( - assets=['MCFTR.INDX', 'AGG.US', 'GLD.US'], - weights=[.60, .35, .05], - ccy='RUB', - rebalancing_period='year', + assets=["MCFTR.INDX", "AGG.US", "GLD.US"], + weights=[0.60, 0.35, 0.05], + ccy="RUB", + rebalancing_period="year", initial_amount=300_000, - cashflow=-2_000 + cashflow=-2_000, ) -print(pf.percentile_inverse_cagr(distr='t', score=0, years=1, n=5000)) - +print(pf.percentile_inverse_cagr(distr="t", score=0, years=1, n=5000)) diff --git a/main_notebook.ipynb b/main_notebook.ipynb index 3f85e0a..0fd9f24 100644 --- a/main_notebook.ipynb +++ b/main_notebook.ipynb @@ -204,7 +204,7 @@ } ], "source": [ - "al = ok.AssetList(['SPY.US', 'BND.US'])\n", + "al = ok.AssetList([\"SPY.US\", \"BND.US\"])\n", "al" ] }, @@ -256,7 +256,7 @@ } ], "source": [ - "al.get_rolling_risk_annual(window=12*5).plot()" + "al.get_rolling_risk_annual(window=12 * 5).plot()" ], "metadata": { "collapsed": false diff --git a/okama/__init__.py b/okama/__init__.py index 8d0a767..42e6cdd 100644 --- a/okama/__init__.py +++ b/okama/__init__.py @@ -19,6 +19,7 @@ - Matplotlib visualization scripts for the Efficient Frontier, Transition map and assets risk / return performance """ + from importlib.metadata import version from okama.asset import Asset diff --git a/okama/common/error.py b/okama/common/error.py index 2563124..19676bd 100644 --- a/okama/common/error.py +++ b/okama/common/error.py @@ -1,9 +1,8 @@ - - class ShortPeriodLengthError(Exception): """ Raised when available period length is too short for the asset. """ + pass @@ -11,6 +10,7 @@ class RollingWindowLengthBelowOneYearError(Exception): """ Raised when rolling window size is below one year. """ + pass @@ -18,5 +18,5 @@ class LongRollingWindowLengthError(Exception): """ Raised when rolling window size is more than data history depth. """ - pass + pass diff --git a/okama/common/helpers/helpers.py b/okama/common/helpers/helpers.py index 3c4e9d1..8a12e77 100644 --- a/okama/common/helpers/helpers.py +++ b/okama/common/helpers/helpers.py @@ -7,7 +7,11 @@ import scipy.stats from okama.common.validators import validate_integer -from okama.common.error import LongRollingWindowLengthError, RollingWindowLengthBelowOneYearError, ShortPeriodLengthError +from okama.common.error import ( + LongRollingWindowLengthError, + RollingWindowLengthBelowOneYearError, + ShortPeriodLengthError, +) from okama import settings @@ -16,7 +20,7 @@ def check_rolling_window(window: int, ror: Union[pd.Series, pd.DataFrame], windo if not window_below_year and window < settings._MONTHS_PER_YEAR: raise RollingWindowLengthBelowOneYearError("window size must be at least 1 year") if window > ror.shape[0]: - raise LongRollingWindowLengthError(f"window size is more than data history depth: 13 months") + raise LongRollingWindowLengthError("window size is more than data history depth: 13 months") class Float: @@ -240,7 +244,7 @@ def _(wealth_series: pd.Series) -> pd.Timestamp: survival_date = wealth_series[condition].index[0] except IndexError: survival_date = wealth_series.index[-1] - return survival_date.to_timestamp(freq='M') + return survival_date.to_timestamp(freq="M") @get_survival_date.register def _(wealth: pd.DataFrame) -> pd.Timestamp: diff --git a/okama/common/make_asset_list.py b/okama/common/make_asset_list.py index 295304b..f5d9e01 100644 --- a/okama/common/make_asset_list.py +++ b/okama/common/make_asset_list.py @@ -323,7 +323,7 @@ def _assets_dividend_yield(self) -> pd.DataFrame: div_monthly.index = div_monthly.index.to_timestamp() for date in price_monthly_ts.index.to_timestamp(how="End"): date0 = date - pd.DateOffset(months=12) # last 12 months - ltm_div = div_monthly[date0: date].sum() + ltm_div = div_monthly[date0:date].sum() last_price = price_monthly_ts.loc[:date].iloc[-1] value = ltm_div / last_price div_yield.at[date] = value diff --git a/okama/common/validators.py b/okama/common/validators.py index f8405ea..53b5d00 100644 --- a/okama/common/validators.py +++ b/okama/common/validators.py @@ -1,4 +1,5 @@ """Various validators""" + import numbers import operator from typing import Optional, Any diff --git a/okama/portfolio.py b/okama/portfolio.py index 9cdb17a..9544720 100644 --- a/okama/portfolio.py +++ b/okama/portfolio.py @@ -2349,6 +2349,7 @@ class PortfolioDCF: pf.dсf.cashflow_pv ``` """ + def __init__(self, parent: Portfolio): self.parent = parent self._wealth_index = pd.DataFrame(dtype=float) diff --git a/tests/test_asset_list.py b/tests/test_asset_list.py index d839d4e..254ed48 100644 --- a/tests/test_asset_list.py +++ b/tests/test_asset_list.py @@ -7,7 +7,11 @@ from pytest import mark import okama as ok -from okama.common.error import ShortPeriodLengthError, LongRollingWindowLengthError, RollingWindowLengthBelowOneYearError +from okama.common.error import ( + ShortPeriodLengthError, + LongRollingWindowLengthError, + RollingWindowLengthBelowOneYearError, +) from tests import conftest @@ -387,7 +391,9 @@ def test_skewness(self): assert self.asset_list.skewness["MCFTR.INDX"].iloc[-1] == approx(0.24876, abs=1e-2) def test_rolling_skewness_failing(self): - with pytest.raises(LongRollingWindowLengthError, match=r"window size is more than data history depth: 13 months"): + with pytest.raises( + LongRollingWindowLengthError, match=r"window size is more than data history depth: 13 months" + ): self.asset_list.skewness_rolling(window=24) with pytest.raises(RollingWindowLengthBelowOneYearError, match=r"window size must be at least 1 year"): self.asset_list.skewness_rolling(window=5) diff --git a/tests/test_macro.py b/tests/test_macro.py index 42cdaaf..23c5322 100644 --- a/tests/test_macro.py +++ b/tests/test_macro.py @@ -52,8 +52,7 @@ def test_purchasing_power_1000(self): def test_rolling_inflation_fails(self): with pytest.raises( - LongRollingWindowLengthError, - match=r"data history depth is less than rolling window size \(12 months\)" + LongRollingWindowLengthError, match=r"data history depth is less than rolling window size \(12 months\)" ): self.infl_usd_less_year.rolling_inflation diff --git a/tests/test_portfolio.py b/tests/test_portfolio.py index d390701..9c7cdec 100644 --- a/tests/test_portfolio.py +++ b/tests/test_portfolio.py @@ -414,10 +414,7 @@ def test_dcf_survival_period(portfolio_cashflows_inflation): ) def test_dcf_monte_carlo_wealth(portfolio_cashflows_inflation_large_cf, distribution, expected): result = portfolio_cashflows_inflation_large_cf.dcf.monte_carlo_wealth( - first_value=100_000, - distr=distribution, - years=1, - n=100 + first_value=100_000, distr=distribution, years=1, n=100 ) assert result.iloc[-1].mean() == approx(expected, rel=1e-1) @@ -427,15 +424,5 @@ def test_dcf_monte_carlo_wealth(portfolio_cashflows_inflation_large_cf, distribu [("norm", 6.2), ("lognorm", 6.2), ("t", 5.9)], ) def test_dcf_monte_carlo_survival_period(portfolio_cashflows_inflation_large_cf, distribution, expected): - result = portfolio_cashflows_inflation_large_cf.dcf.monte_carlo_survival_period( - distr=distribution, - years=25, - n=100 - ) + result = portfolio_cashflows_inflation_large_cf.dcf.monte_carlo_survival_period(distr=distribution, years=25, n=100) assert result.mean() == approx(expected, rel=1e-1) - - - - - - diff --git a/tests/test_search.py b/tests/test_search.py index b2df7ae..0af59ec 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -1,6 +1,7 @@ """ Tests the search """ + import json import pytest