Package daredare :: Package model :: Module model
[hide private]
[frames] | no frames]

Source Code for Module daredare.model.model

  1  #from xml.etree import ElementTree as ET 
  2  import copy 
  3  from sympy import __version__ as sympy_version 
  4  print("Sympy version is : " + sympy_version) 
  5  from sympy import * 
  6  #from sympy.printing.latex import LatexPrinter  
  7   
  8  import misc.calculus 
  9  import re 
 10   
11 -class Variable(Symbol):
12 ''' 13 Define a new variable with : x = Variable('x') 14 Then x(k) returns the value with lag k 15 Internally x(-k) is a symbol with name x_bk 16 ''' 17 # question : should this class be a singleton ? 18 19 # other question : should variables be injected ? (import inspect ...) 20 21 basename = None 22 name = None #Name of the variable 23 init_value = None 24 end_value = None 25
26 - def __init__(self, name):
27 28 super(Variable,self).__init__() 29 self.basename = name 30 self.lag = 0 31 32 return(None)
33
34 - def __call__(self,lag):
35 newlag = self.lag + lag 36 if newlag < 0: 37 newname = self.basename + "_b" + str(- newlag) 38 #newname = self.basename + "(" + str( newlag) + ")" 39 elif newlag > 0: 40 newname = self.basename + "_f" + str( newlag ) 41 #newname = self.basename + "(" + str( newlag ) + ")" 42 else: 43 newname = self.basename 44 v = Variable(newname) 45 v.lag = newlag 46 v.basename = self.basename 47 return v
48
49 - def tostr(self, level=0):
50 precedence = self.precedence 51 if self.lag != 0: 52 result = self.basename + "(" + str(self.lag) + ")" 53 else: 54 result = self.basename 55 if precedence<=level: 56 return('(%s)' % (result)) 57 return result
58
59 -class Parameter(Symbol):
60 61 name = None 62 value = None 63
64 - def __init__(self, name, value):
65 super(Parameter,self).__init__() 66 self.name = name 67 self.value = value 68 # Should this be kept her or not ? 69 # If not is it useful to subclass Symbol ? 70 return(None)
71
72 - def __repr__(self):
73 return(self.name)
74
75 -class Equation(Equality):
76 77 name = None 78
79 - def __init__(self, lhs, rhs, name=None,is_endogenous=True):
80 super(Equality,self).__init__() 81 self.name = name 82 self.is_endogenous=is_endogenous 83 return(None)
84
85 - def gap(self):
86 return( -self.lhs + self.rhs)
87
88 -class Model:
89 90 fname = None # Model basename 91 variables = [] 92 exovariables = [] 93 shocks = [] 94 covariances = [] 95 parameters = [] 96 equations = [] 97 init_values = dict() 98 variables_order = dict() 99 commands = None # keep some instructions to treat the model, not sure how to do it 100
101 - def __init__(self, fname):
102 self.fname = fname 103 return(None)
104
105 - def copy(self):
106 c = Model(self.fname) 107 c.variables = copy.copy(self.variables) 108 c.exovariables = copy.copy(self.exovariables) 109 c.covariances = copy.copy(self.covariances) 110 c.parameters = copy.copy(self.parameters) 111 c.equations = copy.copy(self.equations) 112 c.init_values = copy.copy(self.init_values) 113 c.commands = copy.copy(self.commands) 114 return(c)
115
116 - def check_all(self):
117 print("There are :") 118 print("- %s variables") % len(self.variables) 119 print("- %s exovariables") % len(self.exovariables) 120 print("- %s shocks") % len(self.shocks) 121 print("- %s equations") % len(self.equations)
122
123 - def map_function_to_expression(self,f,expr):
124 if len(expr._args)==0 : 125 return( f(expr) ) 126 else: 127 l = list(expr._args) 128 args = [] 129 for a in l: 130 args.append(self.map_function_to_expression(f,a)) 131 return( expr.__class__(* args) )
132
133 - def current_equations(self):
134 c_eqs = [] 135 def f(x): 136 if x in self.shocks: 137 return(0) 138 elif x.__class__ == Variable: 139 return(x(-x.lag)) 140 else: 141 return(x)
142 for eq in self.equations: 143 n_eq = self.map_function_to_expression(f,eq) 144 n_eq.is_endogenous = eq.is_endogenous 145 c_eqs.append(n_eq) 146 return(c_eqs)
147
148 - def future_variables(self):
149 # returns [f_vars, f_eq, f_eq_n] 150 # f_vars : list of variables with lag > 1 151 # f_eq : list of equations containing future variables 152 # f_eq_n : list of indices of equations containing future variables 153 154 f_eq_n = [] # indices of future equations 155 f_eq = [] # future equations (same order) 156 f_vars = set([]) # future variables 157 for i in range(len(self.equations)): 158 eq = self.equations[i] 159 all_atoms = eq.atoms() 160 f_var = [] 161 for a in all_atoms: 162 if (a.__class__ == Variable) and (a(-a.lag) in self.variables): 163 if a.lag > 0: 164 f_var.append(a) 165 if len(f_var)>0: 166 f_eq_n.append(i) 167 f_eq.append(eq) 168 f_vars = f_vars.union(f_var) 169 f_vars = list(f_vars) 170 return([f_vars,f_eq,f_eq_n])
171
172 - def get_jacobian(self):
173 ''' 174 returns the jacobian of the equations with respect to 175 all_variables_f,all_variables,all_variables_b 176 where all_variables == variables + exovariables 177 ''' 178 #print(self.variables) 179 all_variables = self.variables + self.exovariables 180 vec = map(lambda v: v(1), all_variables) + all_variables + map(lambda v: v(-1), all_variables) 181 vec = Matrix([vec]) 182 #print vec 183 f = Matrix( map(lambda eq: eq.gap(),self.equations) ) 184 return f.T.jacobian(vec)
185
186 - def process_portfolio_model(self):
187 188 pf_model = self.copy() # I should work on a copy on the model not on itself ! 189 pf_model.fname = pf_model.fname + "_pf" 190 191 [f_vars,f_eq,f_eq_n] = pf_model.future_variables() 192 193 f_vars_c = map(lambda v: v(-v.lag), f_vars) # this returns current dates of future variables 194 195 nf_eq_n = list(set(range(len(self.equations))).difference(f_eq_n)) # indices of non forward equations 196 nf_eq = map(lambda (n): self.equations[n], nf_eq_n) # non forward equations (differences) 197 198 nf_eq = map(lambda eq: eq.gap(), nf_eq) # we remove equal signs before we can calculate jacobian 199 f_eq = map(lambda eq: eq.gap(), f_eq) 200 201 A = Matrix(len(nf_eq),len(self.exovariables), lambda i,j : Variable("A_"+str(i+1)+str(j+1))) 202 for a in A: 203 pf_model.variables.append(a) 204 205 # Thanks to non forward equations, forward variables variations are 206 # approximated by A * shocks (first order approximation) 207 f = Matrix(nf_eq) 208 f_X = f.jacobian(f_vars_c) 209 for v in pf_model.exovariables: 210 f_X = f_X.subs(v,0) 211 f_E = f.jacobian(Matrix(self.exovariables)) 212 for v in pf_model.exovariables: 213 f_E = f_E.subs(v,0) 214 f_ = f_X * A + f_E 215 216 # Then future variables are substituted in forward equations 217 # which are taylorized twice with respect to shocks 218 # Cross products of shocks are replaced by covariances 219 s_f_eq = [] # will contain future equations with substitutions 220 for i in range(len(f_eq)): 221 eq = f_eq[i] 222 for k in range(len(f_vars)): 223 v = f_vars[k] 224 dv = (A[k,:] * Matrix(self.exovariables))[0,0] 225 eq = eq.subs(v,v+dv) 226 seq = Calculus.second_order_taylorisation(eq, self.exovariables, self.covariances) 227 s_f_eq.append(Equality(0,seq)) 228 229 for eq in f_: 230 pf_model.equations.append(Equation(0,eq,"Another moment condition") ) 231 232 for i in range(len(f_eq)): 233 pf_model.equations[f_eq_n[i]] = s_f_eq[i] 234 235 return(pf_model)
236