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.
model_dynare.py ADDED
@@ -0,0 +1,173 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Wed Jan 9 16:05:56 2019
4
+ Reads a list of expanded modfile (outputtet from dynare)
5
+
6
+
7
+ @author: hanseni
8
+ """
9
+
10
+ import re
11
+ import pandas as pd
12
+ import sys
13
+ from pathlib import Path
14
+
15
+
16
+ import modelclass as mc
17
+ import modelmanipulation as mp
18
+ import modelpattern as pt
19
+
20
+ class grap_modfile():
21
+
22
+
23
+ '''Accept filenames as argument. The first file is asumed to be the main model
24
+ and gives the model its name
25
+
26
+ Instead of filenames a string with a .mod file can be accepted
27
+
28
+ :savepath: (path of first file ) Where to save
29
+ :save: (True) save the frm and mod files
30
+ :modelname: (name from first model file else "testmodel" for strings), name of model
31
+
32
+ The class contains among other:
33
+
34
+ :mthismodel: The actual model
35
+ :mresmodel: A model to calculate the _res variables before the actual calculations
36
+ :mparamodel: A model to inject parameter values into a dataframe before calculation
37
+ :fthismodel: String with the model
38
+ :fresmodel: String with the model for calculating residuals
39
+ :fparamodel: String with the model for injecting parameters
40
+ :modout: String with the consolidated .mod file
41
+
42
+
43
+ creates 5 files:
44
+
45
+ :{modelname}.frm: Formulas in modelflow business language
46
+ :{modelname}_res.frm: Formulas for mresmodel
47
+ :{modelname}_para.frm: Formulas for mparamodel
48
+ :{modelname}_cons.mod: A consolidated .mod file defining the model and parameters
49
+ :{modelname}.inf: A with model information - also displayes after execution
50
+ '''
51
+ def __init__(self, files,save=False,savepath='',modelname = 'testmodel'):
52
+ ''' initialize a model'''
53
+
54
+
55
+ if type(files) == list:
56
+ modfilenames = [f for f in files if f.endswith('.mod')]
57
+ self.filenames = [f for f in modfilenames if not f.endswith('param.mod') ]
58
+ self.parafilenames = [f for f in modfilenames if f.endswith('param.mod') ]
59
+
60
+ self.alllines = ''
61
+ self.alllines= ' '.join([open(f,'rt').read() for f in self.filenames]).upper()
62
+ self.paralines= ' '.join([open(f,'rt').read() for f in self.parafilenames]).upper()
63
+ file_path = Path(self.filenames[0])
64
+ # self.path,self.modelname=self.filenames[0][:-4].rsplit('\\',1)
65
+ # self.savepath = savepath if savepath else self.path
66
+ else:
67
+ self.filenames = files
68
+ self.alllines = open(file_path := Path(files),'rt').read() # we got a string
69
+ self.paralines = ''
70
+
71
+ self.path = str(file_path.parent)
72
+ self.modelname = file_path.stem
73
+ self.savepath = savepath if savepath else Path(self.path)
74
+
75
+ #%% get rid of comments
76
+ rest = [l.split(r'//')[0].strip() for l in self.alllines.split('\n')
77
+ if 0 != len(l.split(r'//')[0].strip())]
78
+
79
+ #%% get the model and make it
80
+ restmod = ' '.join(rest)
81
+ modelpat = r'model\(no_static\);(.*?)end'
82
+ modellist = re.findall(modelpat,restmod) # extract all model segments
83
+ # breakpoint()
84
+
85
+ assert len(modellist) == len([l for l in rest if 'model' in l.lower()]),'Some model segments missing'
86
+
87
+ lthismodel = [f'frml <> {f} $' for f in ''.join(modellist).split(';')
88
+ if 0 != len(f.strip())]
89
+ self.fthismodel = '\n'.join(lthismodel).replace('^','**')
90
+
91
+ assert pt.check_syntax_model(self.fthismodel),'Syntax error in file'
92
+
93
+ self.mthismodel = mc.model(self.fthismodel,modelname = self.modelname)
94
+
95
+ #%% get the resmodel
96
+ self.fresmodel = mp.find_res_dynare_new(self.fthismodel)
97
+ self.mresmodel = mc.model(self.fresmodel,modelname=self.modelname+'_res')
98
+
99
+ modelresvar = [v for v in self.mthismodel.allvar if v.endswith('_RES')]
100
+ resmodelresvar = [v for v in self.mresmodel.endogene]
101
+ assert set(modelresvar)==set(resmodelresvar),'Residual model does not match residuals in the model'
102
+
103
+ # breakpoint()
104
+ #%% get a model for injecting parameters
105
+ parampat = r'parameters(.*?)(?:(?:model)|(?:var)|(?:exovar)|(?:$))'
106
+ paramlist = re.findall(parampat,restmod)+[self.paralines]
107
+ # assert len(paramlist)-1 == len([l for l in rest if 'parameters'.upper() in l]),'Some parameter segments missing'
108
+
109
+ #new get all the parameter settings and make a model for injecting theese
110
+ self.paravalues = sorted(set([re.sub(r'\s+','',f) for f in ''.join(paramlist).split(';') if 0 != len(f.strip()) and '=' in f ]))
111
+ self.fparamodel = '\n'.join( [f'frml <> {f} $' for f in self.paravalues ])
112
+ self.mparamodel = mc.model(self.fparamodel,modelname=self.modelname+'_para')
113
+
114
+ # now get all the parameter names:
115
+ llparavars = ' '.join([f.split('=')[0] for f in ''.join(paramlist).split(';') ])
116
+ self.paravars = sorted({re.sub(r'\s+','',p) for p in llparavars.split(' ') if 0 != len(p.strip())})
117
+
118
+ ##% Variables
119
+ varpat = r'var[^e](.*?);'
120
+ varlist = re.findall(varpat,restmod)
121
+ vars = {v for v in ' '.join(varlist).split(' ') if 0 !=len(v)}
122
+ assert len(vars)==len(self.mthismodel.endogene),'Not all endogenous variables are declared'
123
+
124
+ exovarpat = r'varexo(.*?);'
125
+ exovarlist = re.findall(exovarpat,restmod)
126
+ exovars = {v.upper() for v in ' '.join(exovarlist).split(' ') if 0 !=len(v)}
127
+
128
+
129
+
130
+ #%% Output model
131
+
132
+ self.modout = self.mthismodel.todynare(self.paravars,self.paravalues)
133
+
134
+
135
+ #%%
136
+ newline='\n'
137
+ self.inf= (
138
+ f'Model file(s) : {self.filenames} \n'
139
+ +f'Contemporaneous feedback (simultaneous) : {not self.mthismodel.istopo} \n'
140
+ +f'Var equal to left hand variables : {self.mthismodel.endogene == set(vars)} \n'
141
+ +f'Number of endogeneous : {len(self.mthismodel.endogene)} \n'
142
+ +f'Number of exogenous : {len(self.mthismodel.exogene)} \n'
143
+ +f'Parameters : {len(self.paravars)} \n'
144
+ +f'Parameters set to values : {len(self.paravalues)} \n'
145
+ # +f'Exovar not in model : { set(exovars)- self.mthismodel.exogene} \n'
146
+ +f'Model exogenous not in exovar or parameter: {len(self.mthismodel.exogene- (set(exovars)|set(self.paravars)))} \n'
147
+ +f'Parameters also in exovar : {len(set(exovars) & set(self.paravars))} \n'
148
+ # +f'Parameters not in model : \n{newline.join(sorted(set(self.paravars)- self.mthismodel.exogene))} \n'
149
+ )
150
+ print(self.inf)
151
+ if save:
152
+ with open(f'{self.savepath}/{self.modelname}.inf','wt') as inffile:
153
+ inffile.write(self.inf)
154
+ with open(f'{self.savepath}/{self.modelname}.frm','wt') as frmfile:
155
+ frmfile.write(self.fthismodel)
156
+ with open(f'{self.savepath}/{self.modelname}_para.frm','wt') as frmfile:
157
+ frmfile.write(self.fparamodel)
158
+ with open(f'{self.savepath}/{self.modelname}_res.frm','wt') as frmfile:
159
+ frmfile.write(self.fresmodel)
160
+ with open(f'{self.savepath}/{self.modelname}_cons.mod','wt') as consfile:
161
+ consfile.write(self.modout)
162
+
163
+ if __name__ == '__main__' :
164
+ if 1:
165
+ dmodel = grap_modfile(r'C:/mfmodeller_raw/beast/MA-macroexp.mod')
166
+ modmod = dmodel.modout
167
+
168
+ #%%
169
+ if 0:
170
+ #%%
171
+ dmodel.mthismodel.AT_SHOCK1.draw(down=2,up=100,pdf=1,browser=0,HR=0,endo=True)
172
+ dmodel.mthismodel.TR_13_HHCC_AT_DENLG.draw(down=2,up=3,pdf=1,HR=0,endo=False)
173
+ dmodel.mthismodel.LOANSUPPLY_HHCC_AT_ATVLK.draw(down=2,up=3,pdf=1,HR=0,endo=0)
@@ -0,0 +1,88 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Sun Feb 21 16:59:39 2021
4
+
5
+ @author: bruger
6
+ """
7
+
8
+ import pandas as pd
9
+ import numpy as np
10
+
11
+ def lifetime_credit_loss(maturity,discount_rate,lgd,PDefault,debug=False):
12
+ '''
13
+
14
+
15
+ Parameters
16
+ ----------
17
+ maturity : integer or float
18
+ maturity over which the exposure is amortised - by equal instalments.
19
+ discount_rate : float
20
+ discount rate
21
+ lgd : array of float
22
+ list of loss given default
23
+ PDefault : array of float
24
+ propability of defaults
25
+ debug : bool, optional
26
+ calculate a intermidiately dataframes . The default is False.
27
+
28
+ Returns
29
+ -------
30
+ float the long term credit loss in percent
31
+
32
+
33
+ '''
34
+ startstock = 100
35
+ _mat = float(int(maturity))
36
+ time = list(range(int(_mat)+1))
37
+ cashflow = pd.Series(float(startstock)/_mat,index=time,name='cashflow')
38
+ accumulated_cashflow = cashflow.cumsum().shift(fill_value=0.0)
39
+ accumulated_cashflow.name='accumulated_cashflow'
40
+
41
+ stock = startstock-accumulated_cashflow
42
+ stock.name = 'Outstanding'
43
+
44
+ stock_lag = stock.shift().fillna(0.0)
45
+ stock_lag.name = 'outstanding_lagged'
46
+
47
+ stock_average = stock.rolling(2).mean().fillna(0)
48
+ stock_average.name = 'Outstanding average'
49
+
50
+ assert cashflow.sum() != startstock,'Amortisation does not match outstanding '
51
+ discount_series = pd.Series([1./(discount_rate+1)**t for t in time],index=time,name='discount')
52
+
53
+ lgd_series = pd.Series(lgd[:len(cashflow)] if type(lgd) == np.ndarray else lgd,index = time,name='lgd')
54
+ pd_series = pd.Series(PDefault[:len(cashflow)] if type(PDefault) == np.ndarray else PDefault, index=time,name='pd')
55
+ pd_series[0] = 0.0
56
+ # breakpoint()
57
+
58
+ pd_survival = 1-pd_series
59
+ pd_survival.name = 'pd_survival'
60
+
61
+ pd_incremental = pd_series*pd_survival.shift().cumprod()
62
+ pd_incremental.name = 'pd_incremental'
63
+
64
+ lgd_decay = stock_average*lgd_series/100.
65
+ lgd_decay.name = 'lgd_decay '
66
+
67
+ lt_loss = pd_incremental* lgd_decay*stock_lag
68
+ lt_loss.name='Loss'
69
+
70
+ lt_loss_discounted = lt_loss*discount_series
71
+ lt_loss_discounted.name = 'Discounted Loss'
72
+
73
+ lt_loss_discounted_sum = lt_loss_discounted.sum()
74
+ # breakpoint()
75
+ if debug:
76
+ debugout = pd.concat([stock,stock_average,pd_series,pd_survival,pd_incremental,
77
+ lgd_series,lgd_decay,lt_loss,discount_series,lt_loss_discounted],axis=1)
78
+ print(f'Values:\n{debugout}')
79
+ return lt_loss_discounted_sum/startstock
80
+
81
+ if __name__ == '__main__':
82
+ pd_fut = np.append([0],np.full(20,0.006831))
83
+ lgd_fut = np.full(20,0.2)
84
+
85
+ pd_ser = pd.Series(pd_fut)
86
+ xx = lifetime_credit_loss(maturity=5,discount_rate=0.015,lgd=lgd_fut,PDefault=pd_fut,debug=1)
87
+ yy = lifetime_credit_loss(maturity=5,discount_rate=0.015,lgd=0.2, PDefault=0.006831,debug=1)
88
+ zz = lifetime_credit_loss(maturity=5,discount_rate=0.015,lgd=0.2, PDefault=pd_ser,debug=1)