The functions need the package scipy (for the delta normal approach)
pip install scipy
To test the function run you need pytest and then just run pytest
from the folder with then functions.py and the test_functions.py
from dataclasses import dataclass, field | |
from math import sqrt, log, exp | |
from enum import Enum | |
from scipy.stats import norm | |
def to_perc(num, digits=4): | |
return round(num * 100, digits) | |
def calc_sr(p_minus_1, old, new, ip=0.0, div=0.0, dividend_new_shares=1.0): | |
"""calculates the subscription right price""" | |
if ip != 0.0: # for SEO | |
return p_minus_1 - ( | |
(p_minus_1 * old + (ip + div * dividend_new_shares) * new) / (old + new) | |
) | |
else: # for stocksplit | |
return p_minus_1 - (p_minus_1 * old) / (old + new - 1) | |
def correction_factor(p_minus_1, sr): | |
"""returns the correction factor f given the subscription right sr""" | |
return (p_minus_1 - sr) / p_minus_1 | |
def compound_interest(periods, rate): | |
"""calculates the compound interest rate given the periods and rate""" | |
return (1 + rate) ** periods | |
def discrete_to_cont_subperiods(rate, subperiods): | |
"""calculates the continous interest rate given the subperiods and discrete rate""" | |
return (1 + rate / subperiods) ** subperiods - 1 | |
def disc_to_cont(rate): | |
"""discrete rate to continous""" | |
return log(1 + rate) | |
def cont_to_disc(rate): | |
"""continous rate to discrete rate""" | |
return exp(rate) - 1 | |
def geometric_return(buy_and_hold_return, n): | |
return (1 + buy_and_hold_return) ** (1 / n) - 1 | |
def var_delta_normal(market_value, expected_return, volatility, alpha): | |
return -market_value * (expected_return + volatility * norm.ppf(alpha)) | |
def utility(expected_return, a, variance, **kwargs): | |
return expected_return - 0.5 * a * variance | |
@dataclass | |
class Day: | |
priceBefore: float | |
priceToday: float | |
sr: float = 0.0 | |
div: float = 0.0 | |
old: int = 0 | |
new: int = 0 | |
ip: float = 0 | |
name: str = "" | |
dividend_new_shares: float = 1 # how many % new shares get dividend | |
@property | |
def f(self): | |
if self.old and self.new: | |
self.sr = calc_sr( | |
self.priceBefore, | |
self.old, | |
self.new, | |
ip=self.ip, | |
div=self.div, | |
dividend_new_shares=self.dividend_new_shares, | |
) | |
if self.sr: | |
return correction_factor(self.priceBefore, self.sr) | |
return 1 | |
@property | |
def corrected_price_minus_one(self): | |
return self.f * self.priceBefore | |
@property | |
def return_today(self): | |
return (self.priceToday - self.f * self.priceBefore + self.div) / ( | |
self.f * self.priceBefore | |
) | |
class ReturnCalculator: | |
def __init__(self): | |
self.first_closing_price = 0.0 | |
self.days = [] | |
def add_day(self, closing_price: float, **kwargs): | |
""" adds a day to the returncalculator """ | |
if self.first_closing_price == 0.0: | |
self.first_closing_price = closing_price | |
else: | |
try: | |
last_closing_price = self.days[-1].priceToday | |
except IndexError: | |
last_closing_price = self.first_closing_price | |
self.days.append(Day(last_closing_price, closing_price, **kwargs)) | |
@property | |
def returns(self): | |
""" calculated returns for all given days """ | |
return list(map(lambda x: x.return_today, self.days)) | |
@property | |
def buy_and_hold_return(self): | |
""" Buy and Hold returns """ | |
bhr = 1 | |
for ret in self.returns: | |
bhr *= 1 + ret | |
return bhr - 1 | |
@property | |
def geometric_return(self): | |
return geometric_return(self.buy_and_hold_return, len(self.days)) | |
@dataclass | |
class SeoPortfolio: | |
seo_day: Day | |
shares: float | |
cash_value: float | |
stock_value: float = field(init=False) | |
def __post_init__(self): | |
# calculate stock value with price of today, this case is when she ignores the SEO | |
self.stock_value = self.seo_day.priceBefore * self.shares | |
def exercise_sr(self, before_trading=False): | |
new_shares = self.shares / self.seo_day.old * self.seo_day.new | |
buy_price = self.seo_day.ip * new_shares | |
self.cash_value -= buy_price | |
self.shares += new_shares | |
if before_trading: | |
self.stock_value = self.shares * self.seo_day.corrected_price_minus_one | |
else: | |
self.stock_value = self.shares * self.seo_day.priceToday | |
def sell_sr(self, before_trading=False): | |
new_cash = self.shares * self.seo_day.sr | |
self.cash_value += new_cash | |
if before_trading: | |
self.stock_value = self.shares * self.seo_day.corrected_price_minus_one | |
else: | |
self.stock_value = self.shares * self.seo_day.priceToday | |
@property | |
def total_value(self): | |
return self.cash_value + self.stock_value | |
@dataclass | |
class Portfolio: | |
era: float # expected return a | |
erb: float # expected return b | |
stda: float # standard deviation a | |
stdb: float # standard deviation b | |
corr: float # correlation a and b | |
xa: float = 0.0 # amount of a (in percent) | |
xb: float = field(init=False) # amount of b (in percent) | |
def __post_init__(self): | |
if self.xa == 0.0: | |
self.xa = (self.stdb ** 2 - self.corr * self.stda * self.stdb) / ( | |
self.stda ** 2 + self.stdb ** 2 - 2 * self.corr * self.stda * self.stdb | |
) | |
self.xb = 1 - self.xa | |
@property | |
def volatility(self): | |
return sqrt( | |
self.xa ** 2 * self.stda ** 2 | |
+ self.xb ** 2 * self.stdb ** 2 | |
+ 2 * self.xa * self.xb * self.corr * self.stda * self.stdb | |
) | |
@property | |
def expected_return(self): | |
return self.xa * self.era + self.xb * self.erb | |
@dataclass | |
class CAPMPortfolio: | |
market_return: float # market expected return | |
market_vol: float # market volatility | |
risk_free: float # risk free expected return | |
@property | |
def capm_equation(self): | |
"""CAPM/CML equation given the parameters of the CAPM/CML""" | |
return ( | |
f"E[R_P] = " | |
f"{self.risk_free * 100}% " | |
f"+ {round((self.market_return - self.risk_free) / self.market_vol, 4)} " | |
f"* sigma_P" | |
) | |
@property | |
def sml_equation(self): | |
"""SML equation given the parameters of the market portfolio""" | |
return ( | |
f"E[R_P] = " | |
f"{self.risk_free * 100}% + " | |
f"beta_P * " | |
f"{(self.market_return - self.risk_free) * 100}%" | |
) | |
def risk(self, expected_return): | |
"""risk of the given portfolio with expected return""" | |
return ( | |
(expected_return - self.risk_free) | |
/ (self.market_return - self.risk_free) | |
* self.market_vol | |
) | |
def xm(self, expected_return): | |
"""amount of risky assets to be bought to achieve given expected return""" | |
return (expected_return - self.risk_free) / ( | |
-self.risk_free + self.market_return | |
) | |
def xf(self, expected_return): | |
"""amount of risk free assets to be bought to achieve given expected return""" | |
return 1 - self.xm(expected_return) | |
def market_investment(self, expected_return, investment): | |
"""amount of risky assets invested to achieve given expected return""" | |
return self.xm(expected_return) * investment | |
def risk_free_investment(self, expected_return, investment): | |
"""amount of risk free assets invested to achieve given expected return""" | |
return self.xf(expected_return) * investment | |
def return_on_investment(self, investment_risk_free, investment_market): | |
""" | |
calculates the amount of expected cash at the end of the year | |
it is the initial investment + returns | |
""" | |
return ( | |
investment_market | |
+ investment_risk_free | |
+ self.risk_free * investment_risk_free | |
+ self.market_return * investment_market | |
) | |
def expected_return(self, xf, xm): | |
"""expected return given amount of risk free assets (xf) and market assets (xm) in percent""" | |
return xf * self.risk_free + xm * self.market_return | |
def volatility(self, xm): | |
"""volatility of the portfolio and amount of percent of market assets""" | |
return xm * self.market_vol | |
def beta(self, xm): | |
return xm | |
def beta_of_stock(self, volatility, correlation, **kwargs): | |
"""calculates the beta of a stock in relation to the market""" | |
return volatility / self.market_vol * correlation | |
def sml_return(self, volatility, correlation, **kwargs): | |
"""returns the expected return based on the security market line (according to the stocks beta)""" | |
return self.risk_free * ( | |
1 + self.beta_of_stock(volatility, correlation, **kwargs) | |
) | |
def evaluate(self, expected_return, volatility, correlation, **kwargs): | |
"""return whether a stock is overvalued/undervalued or just right on the SML""" | |
sml_return = self.sml_return(volatility, correlation, **kwargs) | |
if sml_return > expected_return: | |
return Valuation.OVERVALUED | |
elif sml_return < expected_return: | |
return Valuation.UNDERVALUED | |
return Valuation.JUST_RIGHT | |
def utility(self, expected_return, a, **kwargs): | |
if "xm" in kwargs: | |
return utility(expected_return, a, self.volatility(kwargs.get("xm")) ** 2) | |
elif "volatility" in kwargs: | |
return utility(expected_return, a, kwargs.get("volatility") ** 2) | |
class Valuation(Enum): | |
JUST_RIGHT = 0 | |
OVERVALUED = 1 | |
UNDERVALUED = 2 |
from functions import * | |
# all exercises from https://tuwel.tuwien.ac.at/mod/assign/view.php?id=1073839 | |
def test_returns_ex6_abs_inc(): | |
"""THE2 Ex6""" | |
r = ReturnCalculator() | |
# ABS Inc. | |
r.add_day(50.0) | |
r.add_day(51.50) | |
r.add_day(49.7) | |
r.add_day(10.8, new=5, old=1) | |
r.add_day(11.5) | |
r.add_day(10.9) | |
assert list(map(lambda x: to_perc(x), r.returns)) == [ | |
3.0, | |
-3.4951, | |
8.6519, | |
6.4815, | |
-5.2174, | |
] | |
assert to_perc(r.buy_and_hold_return) == 9.0 | |
def test_returns_ex6_hp_inc(): | |
r = ReturnCalculator() | |
# HP Inc. | |
r.add_day(22.1) | |
r.add_day(23.05) | |
r.add_day(23.4) | |
r.add_day(23.2, div=0.6) | |
r.add_day(22.7) | |
r.add_day(24.03) | |
assert list(map(lambda x: to_perc(x), r.returns)) == [ | |
4.2986, | |
1.5184, | |
1.7094, | |
-2.1552, | |
5.859, | |
] | |
assert to_perc(r.buy_and_hold_return) == 11.5451 | |
def test_ex7_sr(): | |
assert round(calc_sr(p_minus_1=5.44, old=29, new=25, ip=1.07), 2) == 2.02 | |
def test_ex7_expected_share_price(): | |
p_minus_1 = 5.44 | |
assert ( | |
round( | |
p_minus_1 - round(calc_sr(p_minus_1=p_minus_1, old=29, new=25, ip=1.07), 2), | |
2, | |
) | |
== 3.42 | |
) | |
# most exercises from | |
# https://tuwel.tuwien.ac.at/pluginfile.php/2400775/mod_folder/content/0/PEF_Additional%20exercises%20to%20prepare%20for%20test%202.pdf?forcedownload=1 | |
def test_additional_ex_1a(): | |
years = 2019 - 1800 | |
rate = 2.3 / 100 | |
assert round(compound_interest(years, rate), 2) == 145.47 | |
def test_additional_ex_1b(): | |
years = 2019 - 1800 | |
rate = 4.5 / 100 | |
assert round(compound_interest(years, rate), 2) == 15362.7 | |
def test_additional_ex_3a(): | |
rate = 4.5 | |
assert to_perc(discrete_to_cont_subperiods(rate / 100, 12), 2) == 4.59 | |
def test_additional_ex_3b(): | |
rate = 12 | |
assert to_perc(discrete_to_cont_subperiods(rate / 100, 12), 2) == 12.68 | |
def test_additional_ex_4a1i(): | |
seo_day = Day(96, 78, old=2, new=1, sr=22, ip=30) | |
portfolio = SeoPortfolio(seo_day, 1000, 25000) | |
portfolio.exercise_sr(before_trading=True) | |
assert portfolio.stock_value == 111000 | |
assert portfolio.cash_value == 10000 | |
assert portfolio.total_value == 121000 | |
def test_additional_ex_4a1ii(): | |
seo_day = Day(96, 78, old=2, new=1, sr=22, ip=30) | |
portfolio = SeoPortfolio(seo_day, 1000, 25000) | |
portfolio.sell_sr(before_trading=True) | |
assert portfolio.stock_value == 74000 | |
assert portfolio.cash_value == 47000 | |
assert portfolio.total_value == 121000 | |
def test_additional_ex_4a2i(): | |
seo_day = Day(96, 78, old=2, new=1, sr=22, ip=30) | |
portfolio = SeoPortfolio(seo_day, 1000, 25000) | |
portfolio.exercise_sr(before_trading=False) | |
assert portfolio.stock_value == 117000 | |
assert portfolio.cash_value == 10000 | |
assert portfolio.total_value == 127000 | |
def test_additional_ex_4a2ii(): | |
seo_day = Day(96, 78, old=2, new=1, sr=22, ip=30) | |
portfolio = SeoPortfolio(seo_day, 1000, 25000) | |
portfolio.sell_sr(before_trading=False) | |
assert portfolio.stock_value == 78000 | |
assert portfolio.cash_value == 47000 | |
assert portfolio.total_value == 125000 | |
def test_additional_ex_4b(): | |
r = ReturnCalculator() | |
r.add_day(95) | |
r.add_day(96) | |
r.add_day(78, sr=22) | |
# alternatively: | |
# r.add_day(78, old=2, new=1, ip=30) | |
r.add_day(77.5) | |
r.add_day(76, div=4) | |
r.add_day(75) | |
assert list(map(lambda x: to_perc(x, 3), r.returns)) == [ | |
1.053, | |
5.405, | |
-0.641, | |
3.226, | |
-1.316, | |
] | |
def test_additional_ex_5a(): | |
p = Portfolio(era=10 / 100, erb=18 / 100, stda=15 / 100, stdb=30 / 100, corr=0.1) | |
assert to_perc(p.xa, 2) == 82.61 | |
assert to_perc(p.xb, 2) == 17.39 | |
def test_additional_ex_5b(): | |
p = Portfolio(era=10 / 100, erb=18 / 100, stda=15 / 100, stdb=30 / 100, corr=0.1) | |
assert to_perc(p.volatility, 2) == 13.92 | |
def test_additional_ex_5c(): | |
p = Portfolio(era=10 / 100, erb=18 / 100, stda=15 / 100, stdb=30 / 100, corr=0.1) | |
assert to_perc(p.expected_return, 2) == 11.39 | |
def test_additional_ex_6a(): | |
p = Portfolio( | |
era=15 / 100, erb=20 / 100, stda=20 / 100, stdb=22 / 100, corr=0.5, xa=0.6 | |
) | |
assert to_perc(p.expected_return, 3) == 17.0 | |
assert to_perc(p.volatility, 3) == 18.084 | |
def test_additional_ex_6b(): | |
# correlation = 0 | |
p = Portfolio( | |
era=15 / 100, erb=20 / 100, stda=20 / 100, stdb=22 / 100, corr=0.0, xa=0.6 | |
) | |
assert to_perc(p.expected_return, 3) == 17.0 | |
assert to_perc(p.volatility, 3) == 14.881 | |
# correlation = -0.5 | |
p = Portfolio( | |
era=15 / 100, erb=20 / 100, stda=20 / 100, stdb=22 / 100, corr=-0.5, xa=0.6 | |
) | |
assert to_perc(p.expected_return, 3) == 17.0 | |
assert to_perc(p.volatility, 3) == 10.763 | |
def test_additional_ex_6c(): | |
p = Portfolio(era=15 / 100, erb=20 / 100, stda=20 / 100, stdb=22 / 100, corr=0.5) | |
assert to_perc(p.xa, 2) == 59.46 | |
assert to_perc(p.xb, 2) == 40.54 | |
def test_additional_ex_7a(): | |
p = Portfolio(era=18 / 100, erb=12 / 100, stda=40 / 100, stdb=25 / 100, corr=0.3) | |
assert to_perc(p.xa, 0) == 20 | |
assert to_perc(p.xb, 0) == 80 | |
assert to_perc(p.expected_return, 1) == 13.2 | |
assert to_perc(p.volatility, 1) == 23.7 | |
def test_additional_ex_7b(): | |
p = Portfolio(era=18 / 100, erb=12 / 100, stda=40 / 100, stdb=25 / 100, corr=-1) | |
assert to_perc(p.xa, 2) == 38.46 | |
assert to_perc(p.xb, 2) == 61.54 | |
assert to_perc(p.expected_return, 2) == 14.31 | |
assert to_perc(p.volatility, 0) == 0 | |
def test_additional_ex_8a(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=18 / 100, risk_free=1 / 100 | |
) | |
assert capm_p.capm_equation == "E[R_P] = 1.0% + 0.5 * sigma_P" | |
def test_additional_ex_8b(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=18 / 100, risk_free=1 / 100 | |
) | |
assert to_perc(capm_p.risk(expected_return=4 / 100), 0) == 6 | |
def test_additional_ex_8c(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=18 / 100, risk_free=1 / 100 | |
) | |
assert to_perc(capm_p.xm(expected_return=4 / 100), 4) == 33.3333 | |
assert to_perc(capm_p.xf(expected_return=4 / 100), 4) == 66.6667 | |
assert ( | |
round(capm_p.market_investment(expected_return=4 / 100, investment=1000), 2) | |
== 333.33 | |
) | |
assert ( | |
round(capm_p.risk_free_investment(expected_return=4 / 100, investment=1000), 2) | |
== 666.67 | |
) | |
def test_additional_ex_8d(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=18 / 100, risk_free=1 / 100 | |
) | |
assert capm_p.return_on_investment(300, 700) == 1073 | |
def test_additional_ex_9a(): | |
capm_p = CAPMPortfolio( | |
market_return=8 / 100, market_vol=15 / 100, risk_free=4 / 100 | |
) | |
stock_a = {"expected_return": 5 / 100, "volatility": 20 / 100, "correlation": 0.7} | |
stock_b = {"expected_return": 15 / 100, "volatility": 30 / 100, "correlation": 0.5} | |
stock_c = {"expected_return": 10 / 100, "volatility": 40 / 100, "correlation": 0.8} | |
assert capm_p.sml_equation == "E[R_P] = 4.0% + beta_P * 4.0%" | |
assert round(capm_p.beta_of_stock(**stock_a), 3) == 0.933 | |
assert round(capm_p.beta_of_stock(**stock_b), 3) == 1.000 | |
assert round(capm_p.beta_of_stock(**stock_c), 3) == 2.133 | |
assert capm_p.evaluate(**stock_a) == Valuation.OVERVALUED | |
assert capm_p.evaluate(**stock_b) == Valuation.UNDERVALUED | |
assert capm_p.evaluate(**stock_c) == Valuation.OVERVALUED | |
def test_additional_ex_10a(): | |
capm_p = CAPMPortfolio( | |
market_return=11 / 100, market_vol=25 / 100, risk_free=3 / 100 | |
) | |
er = 9 / 100 | |
assert to_perc(capm_p.xm(expected_return=er), 0) == 75 | |
assert to_perc(capm_p.xf(expected_return=er), 0) == 25 | |
def test_additional_ex_10b(): | |
capm_p = CAPMPortfolio( | |
market_return=11 / 100, market_vol=25 / 100, risk_free=3 / 100 | |
) | |
assert to_perc(capm_p.volatility(0.75), 2) == 18.75 | |
def test_additional_ex_10c(): | |
capm_p = CAPMPortfolio( | |
market_return=11 / 100, market_vol=25 / 100, risk_free=3 / 100 | |
) | |
assert capm_p.beta(0.75) == 0.75 | |
def test_additional_ex_10d(): | |
capm_p = CAPMPortfolio( | |
market_return=-10 / 100, market_vol=25 / 100, risk_free=3 / 100 | |
) | |
assert to_perc(capm_p.expected_return(0.25, 0.75), 2) == -6.75 | |
# Some more exercises from VOWI | |
# https://vowi.fsinf.at/wiki/TU_Wien:Project_and_Enterprise_Financing_VU_(Aussenegg)/Exam_2_-_26.03.2019 | |
def test_seo_a(): | |
assert round(calc_sr(30, 10, 1, 20), 5) == 0.90909 | |
def test_seo_bi(): | |
seo_day = Day( | |
30, 0, old=10, new=1, ip=20 | |
) # second parameter doesn't matter, because its before trading | |
seo_portfolio = SeoPortfolio(seo_day, 100, 2000) | |
assert seo_portfolio.stock_value == 3000 | |
assert seo_portfolio.cash_value == 2000 | |
assert seo_portfolio.total_value == 5000 | |
def test_seo_bii(): | |
seo_day = Day( | |
30, 0, old=10, new=1, ip=20 | |
) # second parameter doesn't matter, because its before trading | |
seo_portfolio = SeoPortfolio(seo_day, 100, 2000) | |
seo_portfolio.exercise_sr(before_trading=True) | |
assert seo_portfolio.stock_value == 3200 | |
assert seo_portfolio.cash_value == 1800 | |
assert seo_portfolio.total_value == 5000 | |
def test_returns_table1(): | |
r = ReturnCalculator() | |
r.add_day(199.01) | |
r.add_day(204.09, div=0.5) | |
r.add_day(214.1) | |
assert to_perc(r.buy_and_hold_return, 3) == 7.846 | |
def test_returns_table2(): | |
r = ReturnCalculator() | |
r.add_day(189.45) | |
r.add_day(194.1) | |
r.add_day(47.75, new=4, old=1) | |
r.add_day(45.13) | |
assert to_perc(r.buy_and_hold_return, 3) == -4.714 | |
def test_portfolio_a(): | |
p = Portfolio( | |
era=15 / 100, erb=10 / 100, stda=20 / 100, stdb=15 / 100, corr=0.1, xa=0.9 | |
) | |
assert to_perc(p.expected_return, 1) == 14.5 | |
assert to_perc(p.volatility, 2) == 18.21 | |
def test_portfolio_b(): | |
p = Portfolio(era=15 / 100, erb=10 / 100, stda=20 / 100, stdb=15 / 100, corr=0.1) | |
assert to_perc(p.xa, 4) == 34.5133 | |
assert to_perc(p.xb, 4) == 65.4867 | |
assert to_perc(p.expected_return, 4) == 11.7257 | |
assert to_perc(p.volatility, 4) == 12.5578 | |
def test_capm_a(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=30 / 100, risk_free=1 / 100 | |
) | |
assert to_perc(capm_p.xm(7 / 100), 2) == 66.67 | |
assert to_perc(capm_p.xf(7 / 100), 2) == 33.33 | |
def test_capm_b(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=30 / 100, risk_free=1 / 100 | |
) | |
assert to_perc(capm_p.volatility(2 / 3), 2) == 20 | |
def test_capm_c(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=30 / 100, risk_free=1 / 100 | |
) | |
assert capm_p.beta(2 / 3) == 2 / 3 | |
def test_capm_d(): | |
capm_p = CAPMPortfolio( | |
market_return=10 / 100, market_vol=30 / 100, risk_free=1 / 100 | |
) | |
assert round(capm_p.utility(expected_return=7 / 100, a=2, xm=2 / 3), 2) == 0.03 | |
# exercises from the slides | |
def test_returns_slides_11(): | |
r = ReturnCalculator() | |
r.add_day(98.52) | |
r.add_day(98.73) | |
r.add_day(101.35) | |
r.add_day(100.00) | |
r.add_day(100.55) | |
assert list(map(lambda x: to_perc(x, 5), r.returns)), [ | |
0.21315, | |
2.65370, | |
-1.33202, | |
0.55000, | |
] | |
def test_returns_slides_14(): | |
r = ReturnCalculator() | |
r.add_day(97.41) | |
r.add_day(98.94) | |
r.add_day(94.87, div=3.0) | |
r.add_day(94.14) | |
r.add_day(93.96) | |
assert list(map(lambda x: to_perc(x, 3), r.returns)), [ | |
1.571, | |
-1.081, | |
-0.769, | |
-0.191, | |
] | |
def test_cont_returns_slides_30(): | |
assert to_perc(discrete_to_cont_subperiods(10 / 100, 2), 2) == 10.25 | |
def test_cont_to_discrete_32(): | |
assert to_perc(cont_to_disc(10 / 100), 4) == 10.5171 | |
def test_discrete_to_cont_32(): | |
assert to_perc(disc_to_cont(10.5171 / 100), 4) == 10 | |
def test_returns_cont_34(): | |
r = ReturnCalculator() | |
r.add_day(98.52) | |
r.add_day(98.73) | |
r.add_day(101.35) | |
r.add_day(100.00) | |
r.add_day(100.55) | |
cont = list(map(lambda x: to_perc(disc_to_cont(x), 5), r.returns)) | |
assert cont == [0.21293, 2.61910, -1.34097, 0.54849] | |
def test_geometric_return_42(): | |
assert to_perc(geometric_return(1.1162 * 1.3749 * 1.4361 - 1, 3), 3) == 30.137 | |
def test_var_delta_normal_82(): | |
assert round(var_delta_normal(279500, 0.048 / 100, 2.921 / 100, 0.01), 2) == 18858.6 | |
assert ( | |
round(var_delta_normal(279500, 0.048 / 100, 2.921 / 100, 0.05), 2) == 13294.75 | |
) |