• No results found

Numerosas son las líneas de trabajo futuro que admite el problema que aquí hemos tratado. A continuación se sugieren algunas propuestas, siguiendo

CAPÍTULO 9. CONCLUSIONES Y TRABAJO FUTURO la distribución por partes que componen el trabajo:

Parte I:

• Estudio de la literatura: la gestión del cŕedito comercial es un tema poco tratado en la literatura científica, por tanto los eventuales nuevos estudios adquieren una mayor relevancia.

• Estudio de cómo elegir el periodo que contenga los clientes del portafolio: en el trabajo se han tomado, como componentes del portafolio, los clientes que vendrán a la PYME en un determi- nado periodo. La elección de ese periodo podría estar basada en los periodos de crédito comercial concedidos habitualmente a los clientes. También hay que tomar en cuenta en qué medida empeo- ran nuestras predicciones de crédito comercial frente al tiempo. Si el periodo es tomado demasiado largo las funciones de probabili- dad que determinan la exposición en impago de nuestros clientes podrían provocar que el modelo no funcione correctamente. • Estudio de la creación de un portafolio dinámico en dos vertientes:

en lo referente a las condiciones de TC de cada cliente del portafo- lio y a los clientes que configura dicho portafolio. De este modo se usaría un único portafolio en lugar un portafolio para cada peri- odo. Esto es así ya que los clientes del portafolio se modificarían según se van cumpliendo los periodos de TC concedidos. Por una parte se eliminarían del portafolio los clientes que han cumplido sus obligaciones, por otra parte se añadirían futuros clientes según nuevas predicciones que se suceden en el tiempo.

Parte II: • Modelo:

◦ Existen discrepancias en la literatura de la gestión de crédi- to sobre si utilizar el RAROC como paŕametro a optimizar. Se propone estudiar la optimización de otros parámetros e incluso un planteamiento multiobjetivo del problema.

CAPÍTULO 9. CONCLUSIONES Y TRABAJO FUTURO ◦ Integrar el periodo del TC en el modelo: en el trabajo se ha considerado que mantiene una relación discreta y lineal con la cantidad de crédito comercial. No obstante la inserción del periodo de TC supone un gran reto y no está clara si su aportación será relevante. La integración de periodos de de- scuento también aumentaría el realismo del modelo pero la complejidad aumentaría exponencialmente.

◦ Extensión del modelo: integrar otros parámetros estocásticos como el número de clientes que harán pedidos o el beneficio neto por cada pedido.

◦ Elaboración de modelos alternativos: el cálculo de las pérdidas inesperadas es complejo y se podría realizar mediante otras técnicas como la simulación.

◦ Eliminar simplificaciones del modelo: integrar la restricción de cantidad máxima de TC que se puede ofrecer a un cliente y cantidad máxima de TC que se puede conceder en todo el portafolio. Esto a su vez exigiría una modificación del algorit- mo de resolución.

◦ En el modelo se ha empleado el paradigma Default Mode (el prestatario incurre en impago o no), también existe la posi- bilidad de usar el paradigma Mark-to-Market donde tambińe se considera que el crédito del prestatario se puede deteriorar. • Algoritmo:

◦ Análisis del orden de complejidad del algoritmo: para deter- minar la eficiencia y recursos necesarios del algoritmo.

◦ Modificación del algoritmo simheurístico: la combinación de simulación y metaheurística se podría realizar de forma dis- tinta.

◦ Uso de otras metaheurísticas: se han usado en este trabajo los algoritmos genéticos, que suelen ser buenos para resolver todo tipo de problemas. Se podría estudiar el uso de otras metaheurísticas que estuvieran más adaptadas a este tipo de

CAPÍTULO 9. CONCLUSIONES Y TRABAJO FUTURO problemas.

Parte III:

• Optimización del código: el algoritmo simheurístico desarrollado es altamente paralelizable. Tanto la parte de simulación como la metaheurística son idóneos para emplear computación paralela. Con esto se conseguiría reducir significativamente el coste com- putacional del DSS.

• Creación de una GUI: con el lenguaje de programación empleado se puede elaborar una GUI o interfaz de usuario que incremente la facilidad de uso del programa.

Parte IV:

• Implementar pruebas para determinar qué valores deben tomar los parámetros de entrada del test para resolver eficazmente el proble- ma: tanto los referentes al algoritmo genético (tasa de mutaciones, tasa de cruces, tamaño de la población, número en la élite) como los referentes a la simulación (número de simulaciones).

• Identificar, para el algoritmo simple de límite de probabilidad de impago, cual es el límite que más rendimiento ofrece.

• Comparar los resultados del test con otros algoritmos simples: que combinen indicadores como la probabilidad de impago y la exposición al impago, y que permitan el ofrecimiento de porciones del crédito comercial demandado.

Bibliografía

[1] S Christian Albright, Christopher James Zappe, and Wayne L Winston. Data Analysis, Optimization, and Simulation Modeling. South-Western, 2011.

[2] J. Baggott. Origins: The Scientific Story of Creation. OUP Oxford, 2015.

[3] Peter Checkland. Systems thinking, systems practice. 1981.

[4] Ian Iscoe, Alexander Kreinin, Helmut Mausser, and Oleksandr Ro- manko. Portfolio credit-risk optimization. Journal of Banking & Fi- nance, 36(6):1604–1615, 2012.

[5] Lee Jacobson and Burak Kanber. Genetic Algorithms in Java Basics. Springer, 2015.

[6] Angel A. Juan, Javier Faulin, Scott E. Grasman, Markus Rabe, and Gonçalo Figueira. A review of simheuristics: Extending metaheuristics to deal with stochastic combinatorial optimization problems. Operations Research Perspectives, 2:62 – 72, 2015.

[7] Sean Luke. 1 essentials of metaheuristicsl. 1.

[8] M. Lutz. Programming Python. O’Reilly Media, 2006.

[9] Harry Markowitz. Portfolio selection. The Journal of Finance, 7(1):77– 91, 1952.

BIBLIOGRAFÍA [10] Anna Nagurney. Network economics. Handbook of Computational

Econometrics, pages 429–486, 2009.

[11] F. Nelli. Python Data Analytics: Data Analysis and Science using pan- das, matplotlib and the Python Programming Language. Apress, 2015. [12] M. Pidd. Tools for Thinking: Modelling in Management Science. Wiley,

2009.

[13] Michael Pidd. Just modeling through: A rough guide to modeling. In- terfaces, 29(2):118–132, 1999.

[14] C.T. Reviews. e-Study Guide for: Fundamentals of Corporate Finance and Standard and Poors Educational Version of Market Insight by Breasley, ISBN 9780077263348. Cram101, 2012.

[15] Stewart Robinson. Simulation: the practice of model development and use. Palgrave Macmillan, 2014.

[16] C. Smithson. Credit Portfolio Management. Wiley Finance. Wiley, 2003. [17] John D Sterman. Business dynamics: systems thinking and modeling for

a complex world, volume 19. Irwin/McGraw-Hill Boston, 2000.

[18] El-Ghazali Talbi. Metaheuristics: from design to implementation, vol- ume 74. John Wiley & Sons, 2009.

[19] Manuel Terrádez Gurrea. Análisis del riesgo de crédito comercial en pymes mediante técnicas de minería de datos. 2014.

[20] Gregory Turnbull-Schwartz. The limits to diversification. Credit, 2010. [21] Víctor García Vaquero and Francisco Alonso. El crédito comercial en

españa: importancia relativa y evolución reciente. Boletín económico- Banco de España, (2):67–77, 2011.

[22] Rosemary H Wild, Kenneth A Griggs, and Tanya Downing. A frame- work for e-learning as a tool for knowledge management. Industrial Management & Data Systems, 102(7):371–380, 2002.

BIBLIOGRAFÍA [23] Benjamin S Wilner. The exploitation of relationships in financial dis- tress: The case of trade credit. The Journal of Finance, 55(1):153–178, 2000.

Apéndices

A.

Código del DSS (DSS.py)

1 #!/usr/bin/python

2 # -*- coding: utf-8 -*- 3

4 5 """

6 - Title: Trade Credit Portfolio Optimization Problem 7

8 - Summary: The Trade Credit Portfolio Optimization Problem

(TCPOP) consists in

,→

9 finding efficient solutions for optimize the

risk-return profile

,→

10 of a trade credit portfolio. This solutions can be

defined as a

,→

11 vector of tuples where each tuple consists of the

trade credit

,→

12 amount and the trade credit period for any given

customer.

,→

13 In this script is implemented a framework to solve

the TCPOP using

,→

14 a method based on simheuristics. The framework can

be summarised

,→

A. CÓDIGO DEL DSS

16

17 1. Data acquisition and processing.

18 2. Create a population of possible solutions. 19 3. Calculate the portfolio performance metrics. 20 4. Solve the TCPOP usign simheuristics.

21 5. Create a report. 22

23 The algorithm proposed herein combines Monte-Carlo

Simulaton with

,→

24 Genetic Algorithms. While the Monte-Carlo

Simulation deals with the

,→

25 stochasticity of the problem, the Genetic

Algorithm metaheuristic

,→

26 deals with the non-linearity, non-convexity nature

of the problem.

,→

27 The Genetic Algorithm is a method for exploring the

space of

,→

28 solutions efficiently without getting stuck in a

local optimum.

,→

29

30 - Example: python DSS.py -d TCPOP_data.csv -t 2 31 python DSS.py -d TCPOP_data.csv 32 python DSS.py -s STCPOP_data.csv 33 python DSS.py --ds STCPOP_data.csv

34 python DSS.py --test /home/user/Documents/Test 35 python DSS.py --test Test

36

37 - Author: Juan Felici <[email protected]> 38

39 - Date: May 17, 2017 40

41 - Tested on Fedora 25 42 """

A. CÓDIGO DEL DSS

43 44

45 #%% Import modules, packages and libraries. 46 """

47 One of the features of Python language is the huge set of

modules, packages and

,→

48 libraries we can import. These are well formated Python code

we can reuse in

,→

49 our proyect to extend its capabilities. We can differentiate

between system

,→

50 imports (wich are contained in the Python Standard Library)

and third party

,→

51 imports (that we must install externally). More information

about Python

,→

52 modules cand be find in

<https://docs.python.org/2/install/index.html>

,→

53

54 In this proyect are used the following packages: 55 1. System imports:

56 - sys: This module provides access to some variables

used or maintained

,→

57 by the interpreter and to functions that

interact strongly with

,→

58 the interpreter. 59 (link:

https://docs.python.org/2/library/sys.html)

,→

60 - time: This module provides various time-related

functions.

,→

61 (link:

https://docs.python.org/2/library/time.html)

,→

62 - optparse: Enable command-line option parsing. 63 (link:

https://docs.python.org/2/library/optparse.html)

A. CÓDIGO DEL DSS

64 - os: This module provides a portable way of using

operating system

,→

65 dependent functionaly.

66 (link: https://docs.python.org/2/library/os.html) 67 2. Third-pary imports:

68 - pandas: Python Data Analisys Library. 69 (link: http://pandas.pydata.org/)

70 - numpy: Fundamental package for scientific computing

with Python. ,→ 71 (link: http://www.numpy.org/) 72 """ 73 74 # 1-System imports:

75 import time, os, optparse, sys 76 # 2-Third-party imports:

77 import pandas as pd, numpy as np 78

79

80 #%% Load data. 81 """

82 The first step in the framework is to load the data. The

pandas package is used

,→

83 to create a data frame, then a set of attributes are created

and stored in a

,→

84 Data object.

85 The data is load from a CSV file where are stored the client

specific ,→ 86 parameters: 87 - Clients. 88 - Exposure At Default. 89 - Probability of Default. 90 - Default Volatility 91 - Sector_{n}

A. CÓDIGO DEL DSS

92 - Loss Given Default. 93 - Net Income.

94 """ 95

96 class Data(object): 97 """

98 Data class allows to extrat sensitive data of the file. 99 """

100

101 def __init__(self, data_file): 102 """

103 Initialize Data module. 104

105 Parameters 106 ---

107 data_file : str (CSV file)

108 Contains the required information of the

clients. ,→ 109 110 Returns 111 --- 112 Data object 113 114 Notes 115 --- 116 Abbreviations used:

117 - Exposure At Default: EAD 118 - Probability of Default: PD 119 - Default Volatility: DV 120 - Loss Given Default: LGD 121 - Net Income: NI 122 - Default Event: DE 123

A. CÓDIGO DEL DSS 124 Examples 125 --- 126 >>> data = Data('clients.csv') 127 128 >>> data = Data('~/Documetns/clients.csv') 129 """ 130

131 # Create a data frame using pandas package:

132 mydata = pd.read_csv(data_file) 133

134 # Data class attributes:

135 """

136 Client specific parameters: 137 """

138 self.EAD = mydata['Exposure At Default'] 139 self.PD = mydata['Probability of Default'] 140 self.DV = mydata['Default Volatility'] 141 self.LGD = mydata['Loss Given Default'] 142 self.NI = mydata['Net Income']

143 try:

144 self.DE = mydata['Default Event'] 145 except KeyError:

146 pass

147 """

148 General parameters: 149 """

150 self.clientNames = mydata['Clients'] 151 self.numberSectors =

int(str(mydata.keys()).count('Sector'))

,→

152 self.numberClients = len(self.clientNames) 153 self.matrixSectors = [self.numberSectors*[0] \

154 for i in range(self.numberClients)]

A. CÓDIGO DEL DSS

156 for i in range(self.numberClients)]

157 """

158 Sector specific parameters: 159 """

160 self.variationCoefficient = range(self.numberSectors) 161 self.meanDefaultRate = range(self.numberSectors)

162 self.defaultRateVolatility = range(self.numberSectors) 163

164 # Number of simulations:

165 """

166 Specifying the number of simulations we want to run in

the MCS.

,→

167 """

168 self.numberSimulations = 100 169

170 # Recalculating Data class attributes initialized

before:

,→

171 """

172 Recalculating self.matrixSectors: 173 """

174 for i in range(self.numberSectors):

175 for j in range(self.numberClients):

176 self.matrixSectors[j][i]=mydata['Sector_'+str(i +1)][j]

,→

177 """

178 Recalculating self.meanDefaultRate: 179 """

180 for sector in range(self.numberSectors): 181 self.meanDefaultRate[sector] =

sum([self.matrixSectors[i][sector] \

,→

182 *self.PD[i] for i in range(self.numberClients)]) 183 """

A. CÓDIGO DEL DSS

185 """

186 for sector in range(self.numberSectors): 187 self.defaultRateVolatility[sector] = \

188 sum([self.matrixSectors[i][sector]*self.DV[i] \

189 for i in range(self.numberClients)])

190 self.defaultRateVolatility[0]=0 191 """

192 Recalculating self.variationCoefficient: 193 """

194 for sector in range(self.numberSectors): 195 if self.meanDefaultRate[sector] == 0: 196 self.variationCoefficient[sector] = 0

197 else:

198 self.variationCoefficient[sector] = \

199 self.defaultRateVolatility[sector]/self.meanDef aultRate[sector]

,→

200 """

201 Recalculating self.correlations: 202 """

203 for i in range(self.numberClients):

204 for j in range(self.numberClients):

205 self.correlations[i][j]=np.sqrt(self.PD[i]*self .PD[j])*\

,→

206 sum([self.matrixSectors[i][k]*self.matrixSector s[j][k]\

,→

207 *self.variationCoefficient[k]**2 for k in \

208 range(self.numberSectors)])

209 """

210 Another way to calculate correlations using numpy

library:

,→

211 """

212 self.correlations = np.corrcoef(self.matrixSectors) 213

A. CÓDIGO DEL DSS

214 # Functions for data processing in stochastic portfolios: 215 """

216 The method extractDistributions extracts the distribution 217 information of the data file. It returns a well formated

matrix of

,→

218 distributions. 219 """

220 def extractDistributions(self): 221 for i in range(len(self.EAD)): 222 self.EAD[i] =

[self.EAD[i][0:self.EAD[i].index('(')],\

,→

223 self.EAD[i][self.EAD[i].index('(')+1:self.EAD[i].i ndex(',')],\

,→

224 self.EAD[i][self.EAD[i].index(',')+1:self.EAD[i].i ndex(')')]]

,→

225 self.EAD[i][1] = int(self.EAD[i][1]) 226 self.EAD[i][2] = int(self.EAD[i][2]) 227 disMatrix = self.EAD[:]

228 return disMatrix 229 """

230 Once we have the distribution matrix we can pass it to the

generateEAD

,→

231 method in order to create a matrix with feasible Exposure

at Default

,→

232 values. This method takes the distribution matrix and

creates a set of EADs

,→

233 for the number of simulations selected. 234 """

235 def generateEAD(self, disMatrix):

236 eadMatrix = [len(disMatrix)*[0] for i in

range(self.numberSimulations)]

,→

237 for k in range(self.numberSimulations):

A. CÓDIGO DEL DSS 239 if disMatrix[i][0] == 'Uniform': 240 eadMatrix[k][i] = np.random.uniform(disMatrix[i][1],\ ,→ 241 disMatrix[i][2])

242 elif disMatrix[i][0] == 'Normal':

243 eadMatrix[k][i] = np.random.normal(disMatrix[i][1],\ ,→ 244 disMatrix[i][2]) 245 return eadMatrix 246

247 # Functions for data processing in test mode: 248 """

249 The files generated for testing pupusoses contain three

EADs:

,→

250 - EAD deterministic. 251 - EAD stochastic. 252 - EAD real.

253 In order to manipulate this three types a specific funtion

is created.

,→

254 """

255 def extractEADs(self):

256 l = []

257 for i in range(len(self.EAD)):

258 EAD_deterministic =

int(self.EAD[i][1:self.EAD[i].index(',')])

,→

259 EAD_actual =

int(self.EAD[i][-self.EAD[i].index(','):-1])

,→

260 EAD_stochastic =

self.EAD[i][self.EAD[i].index(',')+3:-self.\

,→ 261 EAD[i].index(',')-3] 262 l.append([EAD_deterministic, EAD_stochastic, EAD_actual]) ,→ 263 return l

A. CÓDIGO DEL DSS

264

265 # Functions for data processing in dynamic portfolio: 266 """

267 A static matrix of EADs are created in order to represent

the credit

,→

268 amount already delivered. 269 """

270 def staticEAD(self, matrixEAD, EAD): 271 return [matrixEAD[k]+[EAD] for k in

range(self.numberSimulations)]

,→

272 """

273 This function determine the final matrix as the

conjunction of a static

,→

274 matrix and a dynamic matrix. 275 """

276 def determineEAD(self, static, dynamic): 277 return [static[k]+dynamic[k] for k in

range(self.numberSimulations)]

,→

278 279

280 #%% Portfolio performance metrics. 281 """

282 The performance metrics that characterize the porfolio are: 283 1. Expected Return.

284 2. Expected Loss. 285 3. Unexpected Loss. 286 4. Economic Capital.

287 5. Risk-Adjusted Return on Capital (RAROC). 288 """

289

290 class Portfolio(Data): 291 """

A. CÓDIGO DEL DSS

292 Portfolio class allows to create a Portfolio object and

calculate its

,→

293 performance metrics. The Portfolio class inherit the

attributes of the

,→

294 Data class. 295 """

296

297 # Methods for calculating portfolio performance metrics: 298 """

299 The expeted return is the amount of money we expect to

profit beforehand.

,→

300 """

301 def expectedReturn(self, individual):

302 return sum([x*e*(1+n)*(1-p) for x,e,n,p in \

303 zip(individual.getChromosome(), \

304 self.EAD, self.NI,

self.PD)])-self.expectedLoss(individual)

,→

305 """

306 The expected loss is the amount of money we expect to loss

beforehand.

,→

307 """

308 def expectedLoss(self, individual): 309 return sum([x*e*l*p for x,e,l,p in

zip(individual.getChromosome(), \

,→

310 self.EAD, self.LGD, self.PD)]) 311 """

312 The unexpected loss is related to the variation of the

expected loss.

,→

313 """

314 def unexpectedLoss(self, individual):

315 individual_UL = [x*self.EAD[i]*self.LGD[i]*self.DV[i] for x,i in \

A. CÓDIGO DEL DSS

316 zip(individual.getChromosome(),

range(self.numberClients))]

,→

317 UL_p = 0

318 for i in range(self.numberClients):

319 for j in range(self.numberClients):

320 UL_p += individual_UL[i]*individual_UL[j]\ 321 *self.correlations[i][j]

322 return np.sqrt(UL_p) 323 """

324 The economic capital is usually the amount of money needed

to ensure that

,→

325 the company stays solvent. 326 """

327 def economicCapital(self, individual):

328 return self.unexpectedLoss(individual)-self.expectedLo ss(individual)

,→

329 """

330 The Risk-Adjusted Return on Capital (RAROC) combines the

expected return

,→

331 and the economic capital, it is used as the objective

function.

,→

332 """

333 def RAROC(self, individual):

334 return self.expectedReturn(individual)/self.economicCa pital(individual)

,→

335 """

336 The clacBenefit method is used for testing purposes as a

mesure of per-

,→

337 formance. The calcBenefit method returns the net amount of

money earned

,→

338 given the default event, the actual EAD and the portfolio

weights.

,→

A. CÓDIGO DEL DSS

340 def calcBenefit(self, actualEAD, individual): 341 return sum([x*e*(n*(1-p)-p) for x,e,n,p in

zip(actualEAD, individual,\

,→

342 self.NI, self.DE)]) 343

344

345 #%% Individual. 346 """

347 An individual is a possible solution of the problem. An

individual

,→

348 is represented by its chromosome. Each gene of the chromosome

is

,→

349 the portion of TC the clients requests.

350 The chromosome is in the form [0.23, 0.43, 0, ...], where the

nth

,→

351 location of the list correspond to the client number n. 352 """

353

354 class Individual(object): 355

356 def __init__(self, chromosome): 357 """

358 Initialize Individual module. 359

360 Parameters 361 ---

362 chromosome : int, list

363 Contains the chromosome (list) or its length

(int). ,→ 364 365 Returns 366 --- 367 nothing

A. CÓDIGO DEL DSS

368

369 Notes 370 ---

371 This class is written using setters and getters for

the sake

,→

372 of redability. Since the Python language does not

support

,→

373 encapsulation in the way Java does. 374

375 Two attributes are created:

376 1. Chromosome : weights in the portfolio. 377 2. Fitness : metric of the objective function. 378 379 Examples 380 --- 381 >>> individual_1 = Individual(3) 382 383 >>> individual_2 = Individual([0.43, 0, 0.84]) 384 """ 385

386 self.chromosome = chromosome 387 self.fitness = -1

388 if type(self.chromosome) is int:

389 self.chromosome = range(self.chromosome) 390 for gene in self.chromosome:

391 self.setGene(gene , round(np.random.random(),2)) 392

393 # Setters and getters for Individual class: 394 """

395 Gene level: 396 """

397 def setGene(self, offset, gene): 398 self.chromosome[offset] = gene

A. CÓDIGO DEL DSS

399

400 def getGene(self, offset):

401 return self.chromosome[offset] 402 """

403 Chromosome level: 404 """

405 def getChromosomeLength(self): 406 return len(self.chromosome) 407

408 def getChromosome(self): 409 return self.chromosome 410 """

411 Fitness parameter: 412 """

413 def setFitness(self, fitness): 414 self.fitness = fitness 415

416 def getFitness(self): 417 return self.fitness 418

419

420 #%% Population. 421 """

422 A population is a set of individuals. In a genetic algorithm

the populations

,→

423 are replaced dynamically as they are evolving, generation to

generation.

,→

424 """ 425

426 class Population(object): 427

428 _populationFitness = -1 429

A. CÓDIGO DEL DSS

430 def __init__(self, populationSize, chromosomeLength): 431 """

432 Initialize Population module. 433

434 Parameters 435 ---

436 populationSize : int

437 Contains the number of individuals in the

population.

,→

438 chromosomeLength : int

439 Contains the chromosome length of each

individual. ,→ 440 441 Returns 442 --- 443 nothing 444 445 Notes 446 ---

447 As in the Individual class the Population class makes

use of getters

,→

448 and setters in spite of this is unnecessary. 449 450 Examples 451 --- 452 >>> population = Population(1000, 5) 453 """ 454

455 self.population = range(populationSize)

456 for ind in range(populationSize):

457 individual = Individual(chromosomeLength) 458 self.population[ind] = individual

A. CÓDIGO DEL DSS

460 # Individual level: 461 """

462 Some methods to manage the individuals in the population: 463 """

464 def getFittest(self, offset):

465 self.population.sort(key=lambda x: x.getFitness(), reverse=True)

,→

466 return self.population[offset] 467

468 def getIndividuals(self): 469 return self.population 470

471 def setIndividual(self, offset, individual): 472 self.population[offset] = individual 473

474 def getIndividual(self, offset): 475 return self.population[offset] 476

477 # Population level; 478 """

479 Methods to calculate parameters associated with the

population:

,→

480 """

481 def size(self):

482 return len(self.population) 483

484 def setPopulationFitness(self, fitness): 485 self.populationFitness = fitness 486

487 def getPopulationFitness(self): 488 return self.populationFitness 489

A. CÓDIGO DEL DSS

491 #%% Genetic algorithm. 492 """

493 The genetic algorithm is the method used in this framework to

explore the

,→

494 space of solutions. The GeneticAlgorithm class is defined in

order to manage

,→

495 the individuals relations and the dynamic change of the

populations. ,→ 496 """ 497 498 populationSize = 1000 499 mutationRate = 0.01 500 crossoverRate = 0.90 501 elitismCount = 100 502

503 class GeneticAlgorithm(object): 504

505 def __init__(self, chromosomeLength): 506 """

507 Initialize Population module. 508

509 Parameters 510 ---

511 populationSize : int

512 Contains the number of individuals in the

population.

,→

513 chromosomeLength : int

514 Contains the chromosome length of each

individual.

,→

515 mutationRate : float

516 Contains the probability of mutation. 517 crossoverRate : float

A. CÓDIGO DEL DSS

518 Frequency of chromosomal crossover between

individuals.

,→

519 elitismCount : int

520 Number of fittest individuals that survive

in a generation. ,→ 521 522 Returns 523 --- 524 nothing 525 526 Examples 527 --- 528 >>> ga = GeneticAlgorithm(1000, 5, 0.01, 0.90, 100) 529 """ 530

531 self.populationSize = populationSize 532 self.chromosomeLength = chromosomeLength 533 self.mutationRate = mutationRate

534 self.crossoverRate = crossoverRate 535 self.elitismCount = elitismCount 536

537 # Methods implemented in the GengeticAlgorithm class: 538 """

539 This method creates an initial population (zero

generation). It calls the

,→

540 Population class. 541 """

542 def initializePopulation(self):

543 population = Population(self.populationSize,

self.chromosomeLength)

,→

544 return population 545 """

A. CÓDIGO DEL DSS

546 This method calculates the fitness of each individual. The

fitness function

,→

547 or objective function is the Portfolio.RAROC() method. 548 """

549 def calculateFitness(self, individual, portfolio): 550 fitness = portfolio.RAROC(individual)

551 individual.setFitness(fitness) 552 return fitness

553 """

554 In order to evaluate a population this method calls the

calculateFitness

,→

555 method for each individual, setting each fitness. Then is

setted the

,→

556 population fitness, that is a metric to evaluate how good

the individuals

,→

557 are in each population. 558 """

559 def evaluatePopulation(self, population, portfolio): 560 populationFitness = 0

561 for individual in population.getIndividuals():

562 populationFitness +=

self.calculateFitness(individual, portfolio)

,→

563 population.setPopulationFitness(populationFitness) 564 """

565 This method creates a new population resulted from the

crossover of its

,→

566 individuals.

567 Some crossover procedures: 568 - Single point.

569 - Two points. 570 - Arithmetic. 571 """

A. CÓDIGO DEL DSS

573 newPopulation =

Population(population.size(),self.chromosomeLength)

,→

574 for populationIndex in range(population.size()): 575 parent1 = population.getFittest(populationIndex) 576 if self.crossoverRate > np.random.random() and

populationIndex >= \ ,→ 577 self.elitismCount: 578 offspring = Individual(parent1.getChromosomeLength()) ,→

579 parent2 = self.selectParent(population)

580 for geneIndex in range(parent1.getChromosomeLength()): ,→ 581 if 0.5 > np.random.random(): 582 offspring.setGene(geneIndex, parent1.\ 583 getGene(geneIndex)) 584 else: 585 offspring.setGene(geneIndex, parent2.\ 586 getGene(geneIndex)) 587 newPopulation.setIndividual(populationIndex, offspring) ,→ 588 else: 589 newPopulation.setIndividual(populationIndex, parent1) ,→ 590 return newPopulation 591 """

592 This method, called in crossoverPopulation(population),

selects an

,→

593 individual randomly. 594 """

595 def selectParent(self, population):

596 individuals = population.getIndividuals()

A. CÓDIGO DEL DSS

598 rouletteWheelPosition =

np.random.random()*populationFitness

,→

599 spinWheel = 0

600 for individual in individuals:

601 spinWheel += individual.getFitness() 602 if spinWheel >= rouletteWheelPosition:

603 return individual

604 return individuals[population.size()-1] 605 """

606 Given the mutation rate some genes are modified for an

individual.

,→

607 """

608 def mutatePopulation(self, population):

609 newPopulation = Population(self.populationSize,self.ch romosomeLength)

,→

610 for populationIndex in range(population.size()):

611 individual = population.getFittest(populationIndex)

612 for geneIndex in

range(individual.getChromosomeLength()):

,→

613 if populationIndex > self.elitismCount:

Related documents