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 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
+