-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathrisk_kit.py
158 lines (111 loc) · 4.24 KB
/
risk_kit.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import pandas as pd
import numpy as np
from scipy.stats import norm
from collections import Iterable
def discount(time, discount_rate):
"""
Returns the discounted price of a dollar at the given discount rate
for the given time periods.
For a time period t, the discounted price of a dollar is given by
1/(1 + t) ^ discount_rate.
Parameters:
time (Iterable) - The time periods for which discounted price is to
be calculated.
discount_rate (scalar/pd.Series) - Discount rate(s) per period.
Return:
(pd.DataFrame) - Returns a |t| x |r| dataframe of discounted prices.
"""
if not isinstance(time, Iterable):
discounts = (1 + discount_rate) ** (-time)
else:
discounts = pd.DataFrame(
[(1 + discount_rate) ** (-t) for t in time], index=time
)
return discounts
def present_value(flows, discount_rate, periods=None):
"""
Returns the persent discounted value of future cashflows.
Parameters:
flows (pd.Series) - A series of future cash flows
discount_rate (scalar/pd.Series) - Discount rate(s) per period.
periods (pd.Series) - The time period of flows.
Considers index if as to None.
Return:
(float) - The present value of the set of future cash flows.
"""
if periods is None:
periods = flows.index
indexed_flows = flows
else:
indexed_flows = pd.Series(list(flows), index=periods)
discounts = discount(periods, discount_rate)
pv = discounts.multiply(indexed_flows, axis="index").sum()
return pv
def compound_interest(principal, rate, n_years, periods_per_year=12):
"""
Calculates the compound interest.
Total = principal * (1 + rate) ** periods
Parameters:
principal (float): Represent the principal amount
rate (float): The annual rate of interest.
n_years (float): The number of years for which amount is compounded.
periods_per_year (float): Number of periods per year.
Return:
(float): Total amount compounded at the given parameters.
"""
n_periods = n_years * periods_per_year
return principal * (1 + rate / periods_per_year) ** n_periods
def blackscholes_to_binomial(
ann_risk_free_rate, ann_volatility, n_periods, n_years, dividend=0.0
):
"""
Converts the parameters of the BlackScholesModel to those of Binomial pricing model.
The conversion to equivalent binomial model parameters is as follows:
risk_free_return = exp(ann_risk_free_rate * n_years / n_periods)
upward_drift = exp(ann_volatility * sqrt(n_years / n_periods))
downward_drift = 1 / upward_drift
dividend_per_period = dividend * n_years / n_periods
Parameters:
----------
ann_risk_free_rate: float
The discount rate of a dollar over n_years.
ann_volatility: float
The standard deviation/volatility to be considered.
n_periods: int
The number of periods for which the model is to be constructed.
n_years: float
The total time T of the derivative holding.
Returns:
-------
dict: The dictionary consists of four keys:
risk_free_return
upward_drift
downward_drift
dividend_per_period
"""
risk_free_rate = np.expm1(ann_risk_free_rate * n_years / n_periods)
upward_drift = np.exp(ann_volatility * np.sqrt(n_years / n_periods))
downward_drift = 1 / upward_drift
dividend_per_period = dividend * n_years / n_periods
binomial_params = {
"risk_free_rate": risk_free_rate,
"upward_drift": upward_drift,
"downward_drift": downward_drift,
"dividend_per_period": dividend_per_period,
}
return binomial_params
def duration(flows):
"""
Computes the effective duration of the cash flows discounted at the given rate.
Parameters:
----------
flows (np.array): The cash flows for which the effective duration is to be computed
discount_rate (scalar): The rate at which cash flows are to be discounted
Return:
------
Returns the effective duration of the cashflows in terms of the number of periods.
"""
total_flow = flows.sum()
weights = flows / total_flow
value = weights.T @ flows.index
return value