modelflowib 2.73__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelBLfunk.py +180 -0
- model_Excel.py +332 -0
- model_cvx.py +139 -0
- model_dynare.py +173 -0
- model_financial_stability.py +88 -0
- model_latex.py +497 -0
- model_latex_class.py +808 -0
- model_parquet_mixin.py +424 -0
- modelclass.py +9828 -0
- modelconstruct.py +1496 -0
- modelconstruct_estimation.py +2872 -0
- modeldash.py +265 -0
- modeldashboot.py +202 -0
- modeldashsidebar.py +456 -0
- modeldekom.py +651 -0
- modeldiff.py +561 -0
- modeldisplay.py +550 -0
- modelestimation.py +1776 -0
- modelestimator_new.py +2613 -0
- modelflowib-2.73.dist-info/METADATA +156 -0
- modelflowib-2.73.dist-info/RECORD +44 -0
- modelflowib-2.73.dist-info/WHEEL +5 -0
- modelflowib-2.73.dist-info/licenses/license.md +10 -0
- modelflowib-2.73.dist-info/top_level.txt +39 -0
- modelgrab.py +318 -0
- modelgrabgdx.py +584 -0
- modelgrabwf2.py +1107 -0
- modelhelp.py +543 -0
- modelhtml.py +606 -0
- modelinvert.py +250 -0
- modeljupyter.py +824 -0
- modeljupytermagic.py +813 -0
- modelmacrograb.py +98 -0
- modelmanipulation.py +1461 -0
- modelmf.py +349 -0
- modelnet.py +114 -0
- modelnewton.py +2178 -0
- modelnormalize.py +430 -0
- modelpattern.py +428 -0
- modelreport.py +2187 -0
- modeluserfunk.py +97 -0
- modelvis.py +1038 -0
- modelwidget.py +718 -0
- modelwidget_input.py +1933 -0
modelBLfunk.py
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Fri Mar 2 17:01:49 2018
|
|
4
|
+
|
|
5
|
+
@author: hanseni
|
|
6
|
+
|
|
7
|
+
Functions placed here are included in the Pyfs business language
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
from math import exp, log, sqrt, tanh, erf,isclose
|
|
11
|
+
from numpy import transpose , array
|
|
12
|
+
from scipy.stats import norm,lognorm
|
|
13
|
+
from scipy.stats import gamma
|
|
14
|
+
import inspect
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
# raise ImportError("Simulating ImportError for numba.")
|
|
18
|
+
|
|
19
|
+
from numba import jit
|
|
20
|
+
except ImportError:
|
|
21
|
+
print("Numba is not available. No worry")
|
|
22
|
+
|
|
23
|
+
def jit(*args, **kwargs):
|
|
24
|
+
def wrapper(func):
|
|
25
|
+
# print('jit called')
|
|
26
|
+
return func
|
|
27
|
+
return wrapper
|
|
28
|
+
|
|
29
|
+
@jit("f8(f8)",nopython=True)
|
|
30
|
+
def logit_inverse(number):
|
|
31
|
+
''' A function which returns the logit of a number
|
|
32
|
+
|
|
33
|
+
takes care of extreme values
|
|
34
|
+
'''
|
|
35
|
+
if number > 100:
|
|
36
|
+
return 1.0
|
|
37
|
+
elif number < -100:
|
|
38
|
+
return 0.0
|
|
39
|
+
else:
|
|
40
|
+
return 1/(1+exp(-number))
|
|
41
|
+
|
|
42
|
+
classfunk = []
|
|
43
|
+
try:
|
|
44
|
+
from cvxopt import matrix
|
|
45
|
+
from model_cvx import mv_opt, mv_opt_prop
|
|
46
|
+
classfunk = ['TRANS'] # names a classfunk which can be called
|
|
47
|
+
except:
|
|
48
|
+
print('ModelFlow info: CVXopt not installed. Only matters if you are incorporating optimization')
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
from numpy import array
|
|
52
|
+
|
|
53
|
+
from model_financial_stability import lifetime_credit_loss
|
|
54
|
+
|
|
55
|
+
def sum_excel(*arg):
|
|
56
|
+
''' a functions which sums the arguments used in models franslated from excel
|
|
57
|
+
'''
|
|
58
|
+
return sum(arg)
|
|
59
|
+
|
|
60
|
+
def logit(number):
|
|
61
|
+
''' A function which returns the logit of a number
|
|
62
|
+
'''
|
|
63
|
+
return(-log(1.0/number-1.0))
|
|
64
|
+
|
|
65
|
+
# @jit("f8(f8)")
|
|
66
|
+
# def logit_inverse(number):
|
|
67
|
+
# ''' A function which returns the logit of a number
|
|
68
|
+
|
|
69
|
+
# takes care of extreme values
|
|
70
|
+
# '''
|
|
71
|
+
# if number > 100:
|
|
72
|
+
# return 1.0
|
|
73
|
+
# elif number < -100:
|
|
74
|
+
# return 0.0
|
|
75
|
+
# else:
|
|
76
|
+
# return 1/(1+exp(-number))
|
|
77
|
+
|
|
78
|
+
def normcdf(input,mu=0.0,sigma=1.0):
|
|
79
|
+
return norm.cdf(input,mu,sigma)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def qgamma(q,a,loc):
|
|
83
|
+
res = gamma.ppf(q,a,loc,scale=1)
|
|
84
|
+
return res
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def cdf_lognorm_econ(x, mu, sigma, eps=1e-12):
|
|
88
|
+
"""
|
|
89
|
+
Econ / GAMS-style log-normal cumulative distribution function (Newton-safe).
|
|
90
|
+
|
|
91
|
+
Computes the CDF of a log-normal distribution using the mean-parameterized
|
|
92
|
+
(econ / GAMS) formulation, where `mu` is the mean of the level variable X,
|
|
93
|
+
not the mean of log(X).
|
|
94
|
+
|
|
95
|
+
Mathematically:
|
|
96
|
+
F(x) = Φ((ln(x / mu) + 0.5 * sigma**2) / sigma)
|
|
97
|
+
|
|
98
|
+
where Φ(·) is the standard normal CDF.
|
|
99
|
+
|
|
100
|
+
This implementation is numerically safe for use in Newton solvers and
|
|
101
|
+
numerical differentiation by applying a soft lower bound to x and using
|
|
102
|
+
a stable normal CDF.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
x : float
|
|
107
|
+
Evaluation point. May be zero or negative during numerical
|
|
108
|
+
differentiation.
|
|
109
|
+
mu : float
|
|
110
|
+
Mean of the level variable X (E[X] = mu).
|
|
111
|
+
sigma : float
|
|
112
|
+
Standard deviation of ln(X).
|
|
113
|
+
eps : float, optional
|
|
114
|
+
Small positive floor used to ensure log(x) is well-defined.
|
|
115
|
+
Default is 1e-12.
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
119
|
+
float
|
|
120
|
+
Value of the log-normal CDF in the interval [0, 1].
|
|
121
|
+
|
|
122
|
+
Notes
|
|
123
|
+
-----
|
|
124
|
+
- The median of the distribution is mu * exp(-0.5 * sigma**2),
|
|
125
|
+
not mu.
|
|
126
|
+
- As x → 0, the function smoothly approaches 0 with a vanishing
|
|
127
|
+
derivative, which is critical for Newton stability.
|
|
128
|
+
- Equivalent to the standard log-mean parameterization with:
|
|
129
|
+
mu_log = ln(mu) - 0.5 * sigma**2
|
|
130
|
+
"""
|
|
131
|
+
from scipy.special import ndtr
|
|
132
|
+
|
|
133
|
+
x_safe = x if x > eps else eps
|
|
134
|
+
z = (log(x_safe / mu) + 0.5 * sigma**2) / sigma
|
|
135
|
+
return float(ndtr(z))
|
|
136
|
+
|
|
137
|
+
def part_exp_lognorm(k, mu, std, eps=1e-12):
|
|
138
|
+
"""
|
|
139
|
+
Safe scalar equivalent of the GAMS PartExpLogNorm function.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
k : float
|
|
144
|
+
Marginal input
|
|
145
|
+
mu : float
|
|
146
|
+
Average input (scale)
|
|
147
|
+
std : float
|
|
148
|
+
Dispersion / smoothing parameter
|
|
149
|
+
eps : float, optional
|
|
150
|
+
Small positive number to avoid log/division errors
|
|
151
|
+
|
|
152
|
+
Returns
|
|
153
|
+
-------
|
|
154
|
+
float
|
|
155
|
+
Smoothed, bounded transformation
|
|
156
|
+
"""
|
|
157
|
+
# protect against division by zero
|
|
158
|
+
mu_safe = mu if abs(mu) > eps else eps
|
|
159
|
+
|
|
160
|
+
# protect against log(0)
|
|
161
|
+
ratio = abs(k / mu_safe)
|
|
162
|
+
ratio_safe = ratio if ratio > eps else eps
|
|
163
|
+
|
|
164
|
+
# protect against std = 0
|
|
165
|
+
std_safe = std if abs(std) > eps else eps
|
|
166
|
+
|
|
167
|
+
return mu_safe * erf((log(ratio_safe) - 0.5 * std_safe**2) / std_safe)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def clognorm(input,mu=0.0,sigma=1.0):
|
|
172
|
+
res = lognorm.cdf(input,mu,sigma)
|
|
173
|
+
return res
|
|
174
|
+
|
|
175
|
+
if __name__ == '__main__' and 1:
|
|
176
|
+
xx = logit_inverse(-3*10
|
|
177
|
+
)
|
|
178
|
+
print(xx)
|
|
179
|
+
|
|
180
|
+
|
model_Excel.py
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Fri Feb 12 07:04:02 2016
|
|
4
|
+
|
|
5
|
+
@author: ibh
|
|
6
|
+
|
|
7
|
+
Takes all formula's from a excel work book and translates each to the equivalent expression.
|
|
8
|
+
Openpyxl is the fastest library but it can not deal all values. Therefor xlwings is also used.
|
|
9
|
+
But only to read repeated formula's which inly will show as '='
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
Also defines function used when using xlwings to automate excel.
|
|
14
|
+
|
|
15
|
+
These are used in :any:`modeldump_excel` and :any:`modelload_excel`
|
|
16
|
+
|
|
17
|
+
Some of the docstring are not very informative, to be improved.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
import pandas as pd
|
|
23
|
+
import networkx as nx
|
|
24
|
+
import openpyxl
|
|
25
|
+
from openpyxl import load_workbook
|
|
26
|
+
from openpyxl.formula import Tokenizer
|
|
27
|
+
from openpyxl.utils import get_column_letter
|
|
28
|
+
from openpyxl.utils import cols_from_range,rows_from_range
|
|
29
|
+
# try:
|
|
30
|
+
# import xlwings as xw
|
|
31
|
+
# except:
|
|
32
|
+
# ...
|
|
33
|
+
# import networkx as nx
|
|
34
|
+
|
|
35
|
+
import matplotlib.pylab as plt
|
|
36
|
+
import seaborn as sns
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
|
|
39
|
+
import modelclass as mc
|
|
40
|
+
|
|
41
|
+
DEBUG = 0
|
|
42
|
+
|
|
43
|
+
def findequations(name):
|
|
44
|
+
'''Takes all formula's from a excel work book and translates each to the equivalent expression.
|
|
45
|
+
|
|
46
|
+
Multicell ranges are expanded to a comma separated list. \n
|
|
47
|
+
The ordinary operators and the SUM function can be handled. If you need more functions. You have to impelent them in the modelclass.
|
|
48
|
+
|
|
49
|
+
In the model each cell reference is prefixed by <sheet name>_
|
|
50
|
+
|
|
51
|
+
Openpyxl is the fastest library and it has a tokenizer
|
|
52
|
+
but it can not read all values.
|
|
53
|
+
|
|
54
|
+
Therefor xlwings is used to read repeated formula's which Openpyxl will show as '='
|
|
55
|
+
|
|
56
|
+
input:
|
|
57
|
+
:name: Location of a excel sheeet
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
:modeldic: A dictionary with formulars keyed by cell reference
|
|
62
|
+
|
|
63
|
+
'''
|
|
64
|
+
outdic={}
|
|
65
|
+
wb = load_workbook(name, read_only=True,data_only=False) # to read the spresdsheet first save as xml then write it again
|
|
66
|
+
try:
|
|
67
|
+
wb2 = xw.Book(name) # the same worksheet in xlwings
|
|
68
|
+
except:
|
|
69
|
+
...
|
|
70
|
+
# breakpoint()
|
|
71
|
+
|
|
72
|
+
allsheets = wb.sheetnames
|
|
73
|
+
for wsname in allsheets:
|
|
74
|
+
ws=wb[wsname]
|
|
75
|
+
try:
|
|
76
|
+
ws2=wb2.sheets(wsname) # the same sheet but in xlwings
|
|
77
|
+
except:
|
|
78
|
+
...
|
|
79
|
+
|
|
80
|
+
formulacell = [c for row in ws.rows for c in row if c.value != None and c.data_type == 'f']
|
|
81
|
+
for cell in formulacell:
|
|
82
|
+
cellref=get_column_letter(cell.column)+str(cell.row)
|
|
83
|
+
if DEBUG : print('This cell:',cellref,cell.data_type,cell.value)
|
|
84
|
+
if cell.value == '=' :
|
|
85
|
+
print(f'Repeat cell = so xlwings has to be imported {cell=}')
|
|
86
|
+
frml = cell.value if cell.value != '=' else ws2.range(cellref).formula # To avoid emty repeating formula'rs
|
|
87
|
+
else:
|
|
88
|
+
frml = cell.value
|
|
89
|
+
tok=Tokenizer(frml)
|
|
90
|
+
if DEBUG and False : print("\n".join("%19s%15s%9s" % (t.value, t.type, t.subtype) for t in tok.items))
|
|
91
|
+
# left hand term is <worksheet>!<column><row>=
|
|
92
|
+
lhs=wstrans(wsname) + get_column_letter(cell.column)+str(cell.row)
|
|
93
|
+
out=[lhs+'=']
|
|
94
|
+
for t in tok.items:
|
|
95
|
+
if t.subtype == "RANGE":
|
|
96
|
+
#Find or create the sheetname
|
|
97
|
+
sheet0 = t.value.split('!')[0] if '!' in t.value else wsname
|
|
98
|
+
sheet = wstrans(sheet0)
|
|
99
|
+
# print(t.value,'---->')
|
|
100
|
+
# Get all the cells in the range columwize
|
|
101
|
+
# the nested list comprehension makes the list works for square ranges.
|
|
102
|
+
# the split construct drops the sheet name from the range name if any
|
|
103
|
+
thisrange=[sheet+i for subtupler in cols_from_range((t.value.split('!')[-1])) for i in subtupler]
|
|
104
|
+
|
|
105
|
+
# put a ',' between each element i the list
|
|
106
|
+
thistext=','.join(thisrange)
|
|
107
|
+
#print(thisrange)
|
|
108
|
+
out=out + [thistext]
|
|
109
|
+
else:
|
|
110
|
+
out.append(t.value)
|
|
111
|
+
#create the equation and get rid of the !
|
|
112
|
+
equation=''.join(out).replace('!','_')
|
|
113
|
+
outdic[lhs]=equation
|
|
114
|
+
#print(equation)
|
|
115
|
+
try:
|
|
116
|
+
wb2.close()
|
|
117
|
+
except:
|
|
118
|
+
...
|
|
119
|
+
return outdic
|
|
120
|
+
|
|
121
|
+
def showcells(name):
|
|
122
|
+
'''Finds values in a excel workbook with a value different from 0
|
|
123
|
+
'''
|
|
124
|
+
wb = load_workbook(name, read_only=True,data_only=False) # to read the spresdsheet first save as xml then write it again
|
|
125
|
+
allsheets = wb.sheetnames
|
|
126
|
+
for wsname in allsheets:
|
|
127
|
+
ws=wb[wsname]
|
|
128
|
+
for row in ws.rows:
|
|
129
|
+
for c in row:
|
|
130
|
+
if c.value != None:
|
|
131
|
+
print(wsname,get_column_letter(c.column ),c.row,c.data_type,c.value)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def findvalues(name):
|
|
135
|
+
'''Finds numerical values in a excel workbook with a value different from 0
|
|
136
|
+
'''
|
|
137
|
+
wb = load_workbook(name, read_only=True,data_only=True) # to read the spresdsheet first save as xml then write it again
|
|
138
|
+
allsheets = wb.sheetnames
|
|
139
|
+
values=[]
|
|
140
|
+
for wsname in allsheets:
|
|
141
|
+
ws=wb[wsname]
|
|
142
|
+
twsname = wstrans(wsname)
|
|
143
|
+
values+=[(twsname+get_column_letter(c.column )+str(c.row),c.value)
|
|
144
|
+
for row in ws.rows for c in row
|
|
145
|
+
if c.value != None and c.data_type == 'n' ]
|
|
146
|
+
return values
|
|
147
|
+
|
|
148
|
+
def wstrans(wsname):
|
|
149
|
+
'Translates workspace names'
|
|
150
|
+
res = '_'+wsname.replace("'","").replace(' - ','_').replace(' ','_').replace('-','_')+'_'
|
|
151
|
+
return res.upper()
|
|
152
|
+
|
|
153
|
+
def findcoordinates(name):
|
|
154
|
+
'''Finds the cell references matching the codes in a LCR workbook from EBA
|
|
155
|
+
|
|
156
|
+
This is needed for the mapping of the raw data to the excel cell refereces.
|
|
157
|
+
|
|
158
|
+
input:
|
|
159
|
+
:name: Location of a excel sheeet
|
|
160
|
+
|
|
161
|
+
returns:
|
|
162
|
+
:coldf: Dataframe with mapping between excel column and EBA columns_code
|
|
163
|
+
:rowdf: Dataframe with row with mapping between excel row and EBS data row_code
|
|
164
|
+
'''
|
|
165
|
+
wb = load_workbook(name, read_only=True,data_only=True) # to read the spresdsheet first save as xml then write it again
|
|
166
|
+
allsheets = wb.sheetnames
|
|
167
|
+
|
|
168
|
+
colcodes=[]
|
|
169
|
+
rowcodes=[]
|
|
170
|
+
|
|
171
|
+
for wsname in allsheets:
|
|
172
|
+
ws=wb[wsname]
|
|
173
|
+
try:
|
|
174
|
+
#find the anchor for the row and columns id, the first
|
|
175
|
+
cell = [c for row in ws.rows for c in row if c.value and c.data_type == 's' and 'Row'== c.value][0]
|
|
176
|
+
# find the numeric values in the column below the anchor, only the digits and remenber python index starts with 0 while excels index starts with 1
|
|
177
|
+
|
|
178
|
+
rowcodes += [(wsname , c.value , c.row ) for r in ws.rows for c in r
|
|
179
|
+
if c.value and c.column == cell.column and c.row > cell.row and
|
|
180
|
+
( c.data_type == 'n' or (c.data_type == 's' and c.value.isdigit()) )]
|
|
181
|
+
|
|
182
|
+
# finds the numeric values in the row at the right of the anchor.
|
|
183
|
+
# c.rows returns a generator (probably because te potential for a huge number) therefor the list(c.rows)
|
|
184
|
+
colcodes += [(wsname , c.value , get_column_letter(c.column ) ) for c in list(ws.rows)[cell.row-1]
|
|
185
|
+
if c.value and c.column > cell.column and (c.data_type == 'n' or (c.data_type == 's' and c.value.isdigit()))]
|
|
186
|
+
except: # Ok this ws did not have an ancor cell
|
|
187
|
+
pass
|
|
188
|
+
coldf = pd.DataFrame(colcodes,columns=['sheet','colcode','col'])
|
|
189
|
+
rowdf = pd.DataFrame(rowcodes,columns=['sheet','rowcode','row'])
|
|
190
|
+
return coldf,rowdf
|
|
191
|
+
|
|
192
|
+
def getexcelmodel(name):
|
|
193
|
+
''' Creates a model instance from a excel sheet
|
|
194
|
+
SUM is replaced by SUM_EXCEL which is a function in the modelclass
|
|
195
|
+
|
|
196
|
+
In the excel formulars this function accepts ordinary operators and SUM in excel sheets
|
|
197
|
+
|
|
198
|
+
input:
|
|
199
|
+
:name: Location of a excel sheeet
|
|
200
|
+
|
|
201
|
+
returns:
|
|
202
|
+
:model: A model instance with the formulars of the excel sheet
|
|
203
|
+
:para: A list of values in the sheet which matches exogeneous variables in the model
|
|
204
|
+
|
|
205
|
+
'''
|
|
206
|
+
modelname = Path(name).stem
|
|
207
|
+
eqdic = findequations(name)
|
|
208
|
+
eqdic2 = {i : eq.replace('SUM(','SUM_EXCEL(') for i,eq in eqdic.items()}
|
|
209
|
+
fdic = {i : 'Frml xx '+eqdic2[i] + r' $ ' for i,eq in eqdic2.items()}
|
|
210
|
+
f = '\n'.join([eq for i,eq in fdic.items()])
|
|
211
|
+
_mmodel=mc.model(f,modelname=modelname)
|
|
212
|
+
zz = findvalues(name)
|
|
213
|
+
para = [z for z in zz if z[0] in _mmodel.exogene] # find all values which match a exogeneous variable in model
|
|
214
|
+
return _mmodel,para
|
|
215
|
+
|
|
216
|
+
#%% now functions related to running xlsheets
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def indextrans(index):
|
|
220
|
+
'''
|
|
221
|
+
Transforms a period index to excel acceptable datatype
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
'''
|
|
225
|
+
out = [i.year if type(index) == pd.core.indexes.period.PeriodIndex
|
|
226
|
+
else int(i) for i in index]
|
|
227
|
+
return out
|
|
228
|
+
|
|
229
|
+
def df_to_sheet(name,df,wb,after=None):
|
|
230
|
+
'''
|
|
231
|
+
Dataframe to sheet
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
name (TYPE): DESCRIPTION.
|
|
235
|
+
df (TYPE): DESCRIPTION.
|
|
236
|
+
wb (TYPE): DESCRIPTION.
|
|
237
|
+
after (TYPE, optional): DESCRIPTION. Defaults to None.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
sht (TYPE): DESCRIPTION.
|
|
241
|
+
|
|
242
|
+
'''
|
|
243
|
+
try:
|
|
244
|
+
wb.sheets[name].delete()
|
|
245
|
+
except:
|
|
246
|
+
pass
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
sht = wb.sheets.add(name,after=after)
|
|
250
|
+
except Exception as e :
|
|
251
|
+
print('no sheet added',str(e))
|
|
252
|
+
df_ = df.copy()
|
|
253
|
+
df_.index = indextrans(df.index)
|
|
254
|
+
sht.range('A1').value = df_.T
|
|
255
|
+
active_window = wb.app.api.ActiveWindow
|
|
256
|
+
active_window.FreezePanes = False
|
|
257
|
+
active_window.SplitColumn = 1
|
|
258
|
+
active_window.SplitRow = 1
|
|
259
|
+
active_window.FreezePanes = True
|
|
260
|
+
sht.autofit(axis="columns")
|
|
261
|
+
sht[(2,25)].select()
|
|
262
|
+
return sht
|
|
263
|
+
|
|
264
|
+
def obj_to_sheet(name,obj,wb,after=None):
|
|
265
|
+
'''
|
|
266
|
+
An python object to sheet
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
name (TYPE): DESCRIPTION.
|
|
270
|
+
obj (TYPE): DESCRIPTION.
|
|
271
|
+
wb (TYPE): DESCRIPTION.
|
|
272
|
+
after (TYPE, optional): DESCRIPTION. Defaults to None.
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
None.
|
|
276
|
+
|
|
277
|
+
'''
|
|
278
|
+
# breakpoint()
|
|
279
|
+
try:
|
|
280
|
+
wb.sheets[name].delete()
|
|
281
|
+
except:
|
|
282
|
+
pass
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
sht = wb.sheets.add(name,after=after)
|
|
286
|
+
except Exception as e:
|
|
287
|
+
print(str(e))
|
|
288
|
+
print('no sheet added ')
|
|
289
|
+
sht.range('A1').value=obj
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def sheet_to_df(wb,name):
|
|
293
|
+
'''
|
|
294
|
+
Sheet to df
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
wb (TYPE): DESCRIPTION.
|
|
298
|
+
name (TYPE): DESCRIPTION.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
df (TYPE): DESCRIPTION.
|
|
302
|
+
|
|
303
|
+
'''
|
|
304
|
+
df = wb.sheets[name].range('A1').options(pd.DataFrame, expand='table').value.T
|
|
305
|
+
df.index = indextrans(df.index)
|
|
306
|
+
return df
|
|
307
|
+
|
|
308
|
+
def sheet_to_dict(wb,name,integers=None):
|
|
309
|
+
''' transform the named sheet to a python dict. If we need a integer it has to be in the integer set'''
|
|
310
|
+
|
|
311
|
+
integers_ = {'max_iterations'} if isinstance(None,type(None)) else integers
|
|
312
|
+
try:
|
|
313
|
+
out = wb.sheets[name].range('A1').options(dict,expand='table').value
|
|
314
|
+
out2 = {k : int(v) if k in integers_ else v for k,v in out.items()}
|
|
315
|
+
except:
|
|
316
|
+
out2={}
|
|
317
|
+
return out2
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
if __name__ == '__main__':
|
|
324
|
+
testxls=Path('exceltest/lcrberegning2.xlsx')
|
|
325
|
+
mmodel,para = getexcelmodel(testxls)
|
|
326
|
+
eq=mmodel.equations
|
|
327
|
+
mmodel.draw('_LCR_C62',up=10,down=1,HR=0,pdf=1) # The LCR
|
|
328
|
+
mmodel.draw('_LCR_C25',up=4,down=1,pdf=1) # liquid assets
|
|
329
|
+
mmodel.draw('_LCR_C10',up=2,pdf=1) # Leel 1 covered bonds
|
|
330
|
+
|
|
331
|
+
c,r = findcoordinates(testxls)
|
|
332
|
+
xx = findequations(testxls)
|
model_cvx.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Mon May 26 21:11:18 2014
|
|
4
|
+
|
|
5
|
+
@author: Ib Hansen
|
|
6
|
+
|
|
7
|
+
A good explanation of quadradic programming in cvxopt is in
|
|
8
|
+
http://courses.csail.mit.edu/6.867/wiki/images/a/a7/Qp-cvxopt.pdf
|
|
9
|
+
|
|
10
|
+
This exampel calculates the efficient forntier in a small example
|
|
11
|
+
the example is based on a mean variance model for Indonesian Rupia running in Excel
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
import pandas as pd
|
|
17
|
+
from cvxopt import matrix, spdiag
|
|
18
|
+
from cvxopt.solvers import qp , options
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def MV_test(lprint=True):
|
|
22
|
+
''' Test a mean variance model for Indonesian Rupia
|
|
23
|
+
'''
|
|
24
|
+
P= matrix([
|
|
25
|
+
[0.01573635, 0.01436816, 0.01045556],
|
|
26
|
+
[0.01436816, 0.02289016, 0.01172995],
|
|
27
|
+
[0.01045556, 0.01172995, 0.01748076]]) # the covariance matrix
|
|
28
|
+
|
|
29
|
+
q = matrix([0.048,0.040,0.035]) # return vector
|
|
30
|
+
bsum=1.0
|
|
31
|
+
|
|
32
|
+
wsum1=20. # weighted sum should be less than:
|
|
33
|
+
weights1=matrix([2.5 , 1 , 1 ] ,(3,1))
|
|
34
|
+
|
|
35
|
+
wsum2= 1 # weightet sum should be greater than:
|
|
36
|
+
weights2=matrix([0.2 , 2.4 , 1 ] ,(3,1))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
hmin = -matrix([0. , 0 , 0])
|
|
40
|
+
|
|
41
|
+
hmax = matrix([1. ,1. , 1.])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
options['show_progress'] = False
|
|
45
|
+
|
|
46
|
+
riskaversions = [r/100. for r in range(101)] # compute 100 points on the efficient frontier
|
|
47
|
+
portefolios = [mv_opt(P,q,riskaversion,bsum,[[weights1],[-weights2]],[wsum1,-wsum2],hmin,hmax) for riskaversion in riskaversions] # minimize risk and maximize return
|
|
48
|
+
p_return = [100 * x.T * q for x in portefolios]
|
|
49
|
+
risk = [100 *( x.T * P *x)**0.5 for x in portefolios]
|
|
50
|
+
res = [list(r)+list(p)+list(x) for r,p,x in zip(risk,p_return,portefolios) ] # a row in the Dataframe
|
|
51
|
+
|
|
52
|
+
columns=['risk','return']+['Asset'+str(i) for i,temp in enumerate(q)] # to handle a number of assets
|
|
53
|
+
results=pd.DataFrame(res,columns=columns) # create an empty pandas.Dataframe
|
|
54
|
+
return results
|
|
55
|
+
|
|
56
|
+
def mv_opt(PP,qq,riskaversion,bsum,weights,weigthtedsum,boundsmin,boundsmax,maximize=True,lprint=False,solget=None):
|
|
57
|
+
''' Performs mean variance optimization by calling a
|
|
58
|
+
quadratic optimization function from the cvxopt
|
|
59
|
+
library
|
|
60
|
+
|
|
61
|
+
'''
|
|
62
|
+
yield_multiplier = -1 if maximize else 1
|
|
63
|
+
|
|
64
|
+
q_size = len(qq)
|
|
65
|
+
P = matrix(2.0*(1.0-riskaversion)*PP) # to
|
|
66
|
+
q = matrix(yield_multiplier*riskaversion*qq)
|
|
67
|
+
Gmin = -matrix(np.eye(q_size))
|
|
68
|
+
hmin = -matrix(boundsmin)
|
|
69
|
+
Gmax = matrix(np.eye(q_size))
|
|
70
|
+
hmax = matrix(boundsmax)
|
|
71
|
+
if weights:
|
|
72
|
+
Gweights = matrix(weights)
|
|
73
|
+
hweights = matrix(weigthtedsum)
|
|
74
|
+
G = matrix([Gmin,Gmax,Gweights.T]) # creates the combined inequalities
|
|
75
|
+
h = matrix([hmin,hmax,hweights])
|
|
76
|
+
else:
|
|
77
|
+
G = matrix([Gmin,Gmax]) # creates the combined inequalities
|
|
78
|
+
h = matrix([hmin,hmax])
|
|
79
|
+
|
|
80
|
+
A = matrix(1.,(1,q_size)) if bsum else None # sum of shares equal to bsum
|
|
81
|
+
b = matrix([bsum]) if bsum else None
|
|
82
|
+
options['show_progress'] = False
|
|
83
|
+
options['refinement']=10
|
|
84
|
+
sol = qp(P,q,G,h,A,b)
|
|
85
|
+
if solget:
|
|
86
|
+
return sol
|
|
87
|
+
else: # minimize risk and maximize return
|
|
88
|
+
x = sol['x']
|
|
89
|
+
res = x
|
|
90
|
+
return res # get the solution
|
|
91
|
+
|
|
92
|
+
def mv_opt_bs(msigma,vreturn,riskaversion,budget,risk_weights,capital,lcr_weights,lcr,leverage_weights,equity,boundsmin,boundsmax,lprint=False,solget=None):
|
|
93
|
+
'''
|
|
94
|
+
Performs balance sheet optimization using mean variance optimization
|
|
95
|
+
'''
|
|
96
|
+
res = mv_opt(msigma,vreturn,riskaversion,budget,[risk_weights,-lcr_weights,leverage_weights],[capital,-lcr,equity],boundsmin,boundsmax,lprint=False,solget=None)
|
|
97
|
+
return res
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def mv_opt_prop(PP,qq,riskaversion,bsum,weights,weigthtedsum,boundsmin,boundsmax,probability=None,lprint=False):
|
|
101
|
+
''' select a numner of assets/liabilities which. when the selection is feasible an Mean variance optimazation is performed\n
|
|
102
|
+
the selection is based on probabilities '''
|
|
103
|
+
q_size = len(qq)
|
|
104
|
+
selectsize = 2
|
|
105
|
+
newboundsmax = matrix(0.,(q_size,1))
|
|
106
|
+
prop = list(probability/sum(probability)) if probability else [1./q_size for i in range(q_size)]
|
|
107
|
+
# Find a feasible set of banks
|
|
108
|
+
while selectsize < q_size :
|
|
109
|
+
selected = [ int(i) for i in np.random.choice(q_size,selectsize,replace=False,p=prop)] # select banks
|
|
110
|
+
selectvector = matrix(0.,(q_size,1))
|
|
111
|
+
selectvector[selected] = 1.0 # the selected banks is marked by 1.1
|
|
112
|
+
newboundsmax = matrix([s*bm for s,bm in zip(selectvector,boundsmax)]) # elementwise multiplication, so max=0 if the bank is not selected
|
|
113
|
+
# print(sum(newboundsmax))
|
|
114
|
+
if sum(newboundsmax) >= bsum and [weigthtedsum] > list(newboundsmax.T*weights):
|
|
115
|
+
break
|
|
116
|
+
selectsize=selectsize+1
|
|
117
|
+
else:
|
|
118
|
+
print('*** Constraints to do not allow a solution')
|
|
119
|
+
raise
|
|
120
|
+
# now optimize
|
|
121
|
+
try:
|
|
122
|
+
sol= mv_opt(PP,qq,riskaversion,bsum,weights,weigthtedsum,boundsmin,newboundsmax,lprint=False,solget=True)
|
|
123
|
+
shares= sol['x']
|
|
124
|
+
except:
|
|
125
|
+
print('** The Mean variance problem can not be solved')
|
|
126
|
+
raise
|
|
127
|
+
return shares
|
|
128
|
+
|
|
129
|
+
if __name__ == '__main__':
|
|
130
|
+
ib=MV_test()
|
|
131
|
+
import matplotlib.pyplot as plt
|
|
132
|
+
# pd.DataFrame.plot(ib,x='risk',y='return')
|
|
133
|
+
fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(9, 12))
|
|
134
|
+
ib.plot(x='risk',y=['return'],kind='area' ,ax=axes[0])
|
|
135
|
+
ib.plot(x='risk',y=['Asset0','Asset1','Asset2'],ax=axes[1],kind='line')
|
|
136
|
+
ib.plot(x='risk',y=['Asset0','Asset1','Asset2'],ax=axes[2],kind='area')
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|