-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinversor.clp
1098 lines (1027 loc) · 41.8 KB
/
inversor.clp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;; ASESOR PARA INVERTIR EN BOLSA ;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Sistema experto para invertir en bolsa, basado en reglas.
; Hecho por Marta Gómez Macías
; Mayo 2016
; Universidad de Granada
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;; DATOS EMPRESA IBEX35 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftemplate ValorEmpresaIbex
(field Nombre) ; nombre de la empresa
(field Precio (type FLOAT)) ; precio en euros
(field PerVarDia (type FLOAT)) ; % de variación del precio respecto al día anterior
(field Capitalizacion (type INTEGER)) ; valor total de la empresa: precioAccion * n_acciones
(field PER (type FLOAT)) ; capitalizacion / beneficio anual
(field RPD (type FLOAT)) ; repartido a los accionistas por dividendos
(field Tamanio) ; puede ser pequenio, mediano o grande
(field PerIbex (type FLOAT)) ; % de capitalización respecto a la capitalización total del ibex
(field EtiqPER) ; puede ser alto, medio o bajo
(field EtiqRPD) ; puede ser alto, medio o bajo
(field Sector) ; sector de la empresa
(field PerVar5Dias (type FLOAT)) ; % de variación del precio respecto al de hace 5 días
(field Perd3consec) ; Verdadero o Falso -> "bajando en los 3 últimos días"
(field Perd5consec) ; Verdadero o Falso -> "bajando los 5 últimos días"
(field PerVarRespSector5 (type FLOAT)) ; % de variación respecto del sector en los últimos 5 días
(field VRS5) ; Verdadero o falso -> "% varación con respecto a sector últimos 5 días < -5"
(field PerVarMen (type FLOAT)) ; % de variación del precio respecto al de hace un mes
(field PerVarTri (type FLOAT)) ; % de variación del precio respecto al de hace 3 meses
(field PerVarSem (type FLOAT)) ; % de variación del precio respecto al de hace 6 meses
(field PerVarAn (type FLOAT)) ; % de variación del precio respecto al de hace 1 año
)
;;;;;;;;;;;;;;;;;;;;;;;;;; DATOS SECTOR IBEX35 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftemplate ValorSector
(field Nombre) ; Nombre del sector
(field PerVarDia (type FLOAT)) ; Media % variación dia en las empresas del sector
(field Capitalizacion (type INTEGER)) ; Suma capitalización empresas del sector
(field PER (type FLOAT)) ; Media del PER en las empresas del sector
(field RPD (type FLOAT)) ; % repartido por dividendos en el último año
(field PerIbex (type FLOAT)) ; % capitalización con respecto a la capitalización total del ibex
(field PerVar5Dias (type FLOAT)) ; Media % variación en los últimos 5 días de las empresas del sector
(field Perd3consec) ; Verdadero o falso -> "bajando 3 últimos días"
(field Perd5consec) ; Verdadero o falso -> "bajando 5 últimos días"
(field PerVarMen (type FLOAT)) ; Media % variación último mes en las empresas del sector
(field PerVarTri (type FLOAT)) ; Media % variación último trimestre en las empresas del sector
(field PerVarSem (type FLOAT)) ; Media % variación último semestre en las empresas del sector
(field PerVarAn (type FLOAT)) ; Media % variación último año
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CARTERA ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftemplate ValorCartera
(field Empresa)
(field Acciones (type FLOAT))
(field ValorActual (type FLOAT))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Noticia ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(deftemplate Noticia
(field Sobre) ; Empresa o sector afectado
(field Tipo) ; Buena o mala
(field Antiguedad (type INTEGER)) ; Días de antigüedad
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;; Módulo de lectura de datos ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;; BLOQUE PARA LEER DATOS DE EMPRESAS DEL IBEX ;;;;;;;;;;;;;;;;;;
(defrule leer_analisis
=>
(open "Analisis.txt" analisis)
(assert (SeguirLeyendoAnalisis))
)
(defrule leer_analisis_from_file
?f <- (SeguirLeyendoAnalisis)
=>
(bind ?Leido (read analisis))
(retract ?f)
(if (neq ?Leido EOF) then
(assert (ValorEmpresaIbex
(Nombre ?Leido)
(Precio (read analisis))
(PerVarDia (read analisis))
(Capitalizacion (read analisis))
(PER (read analisis))
(RPD (read analisis))
(Tamanio (read analisis))
(PerIbex (read analisis))
(EtiqPER (read analisis))
(EtiqRPD (read analisis))
(Sector (read analisis))
(PerVar5Dias (read analisis))
(Perd3consec (read analisis))
(Perd5consec (read analisis))
(PerVarRespSector5 (read analisis))
(VRS5 (read analisis))
(PerVarMen (read analisis))
(PerVarTri (read analisis))
(PerVarSem (read analisis))
(PerVarAn (read analisis))
)
)
(assert (SeguirLeyendoAnalisis))
)
)
(defrule close_analisis
=>
(close analisis)
; (assert (finLeerFicheros))
)
;;;;;;;;;;;;;;; FIN BLOQUE PARA LEER DATOS DE EMPRESAS DEL IBEX ;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;; BLOQUE PARA LEER DATOS SECTORES ;;;;;;;;;;;;;;;;;;;;;;;;;;
(defrule leer_sectores
=>
(open "AnalisisSectores.txt" sectores)
(assert (SeguirLeyendoSectores))
)
(defrule leer_sectores_from_file
?f <- (SeguirLeyendoSectores)
=>
(bind ?Leido (read sectores))
(retract ?f)
(if (neq ?Leido EOF) then
; cada valor de sectores tiene la forma:
(assert (ValorSector
(Nombre ?Leido)
(PerVarDia (read sectores))
(Capitalizacion (read sectores))
(PER (read sectores))
(RPD (read sectores))
(PerIbex (read sectores))
(PerVar5Dias (read sectores))
(Perd3consec (read sectores))
(Perd5consec (read sectores))
(PerVarMen (read sectores))
(PerVarTri (read sectores))
(PerVarSem (read sectores))
(PerVarAn (read sectores))
)
)
(assert (SeguirLeyendoSectores))
)
)
(defrule close_sectores
=>
(close sectores)
; (assert (finLeerFicheros))
)
;;;;;;;;;;;;;;;;;; FIN BLOQUE PARA LEER DATOS SECTORES ;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; BLOQUE PARA LEER LA CARTERA DEL USUARIO ;;;;;;;;;;;;;;;;;;;;
(defrule leer_cartera
=>
(open "Cartera.txt" cartera)
(assert (SeguirLeyendoCartera))
)
(defrule leer_cartera_from_file
?f <- (SeguirLeyendoCartera)
=>
(bind ?Leido (read cartera))
(retract ?f)
(if (neq ?Leido EOF) then
(assert (ValorCartera
(Empresa ?Leido)
(Acciones (read cartera))
(ValorActual (read cartera))
)
)
(assert (SeguirLeyendoCartera))
)
)
(defrule close_cartera
=>
(close cartera)
; (assert (finLeerFicheros))
)
;;;;;;;;;;;;;;;;;; FIN BLOQUE PARA LEER CARTERA DEL USUARIO ;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; BLOQUE PARA LEER EL FICHERO DE NOTICIAS ;;;;;;;;;;;;;;;;;;;;
(defrule leer_noticias
=>
(open "Noticias.txt" noticias)
(assert (SeguirLeyendonoticias))
)
(defrule leer_noticias_from_file
?f <- (SeguirLeyendonoticias)
=>
(bind ?Leido (read noticias))
(retract ?f)
(if (neq ?Leido EOF) then
(assert (Noticia
(Sobre ?Leido)
(Tipo (read noticias))
(Antiguedad (read noticias))
)
)
(assert (SeguirLeyendonoticias))
)
)
(defrule close_noticias
=>
(close noticias)
(assert (finLeerFicheros))
)
;;;;;;;;;;;;;;; FIN BLOQUE PARA LEER EL FICHERO DE NOTICIAS ;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; regla de transición entre el módulo de lectura de ficheros y el de deducciones
;-------------------------------------------------------------------------------
(defrule transicionLectura
(declare (salience -10)) ; esta debe ser la última regla del módulo en ejecutarse
?f <- (finLeerFicheros)
=>
(retract ?f)
(assert (deducirValores))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;; Módulo de deducir valores ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;; BLOQUE PARA DEDUCIR VALORES INESTABLES ;;;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Los valores del sector de la construcción son inestables por defecto
;-------------------------------------------------------------------------------
(defrule deducir_valores_inestables_construccion
(deducirValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(Sector Construccion)
)
=>
(assert (ValorInestable ?nombre (str-cat "La empresa " ?nombre " es inestable "
"porque su sector es la construcción")))
)
;-------------------------------------------------------------------------------
; Si la economía está bajando, los valores del sector servicios son inestables
; por defecto. Para saber si la economía está bajando, nos fijamos en el sector
; Ibex y sus pérdidas en los últimos 5 días.
;-------------------------------------------------------------------------------
(defrule deducir_valores_inestables_servicios
(deducirValores)
(ValorSector
(Nombre Ibex)
(Perd5consec true)
)
(ValorEmpresaIbex
(Nombre ?nombre)
(Sector Servicios)
)
=>
(assert (ValorInestable ?nombre (str-cat "La empresa " ?nombre " es inestable "
"porque la economía está bajando y su sector es el servicios")))
)
;-------------------------------------------------------------------------------
; Si hay una noticia negativa sobre un valor, éste pasa a ser inestable durante
; dos días
;-------------------------------------------------------------------------------
(defrule deducir_valores_estables_noticias_negativas_empresa
(deducirValores)
(Noticia
(Sobre ?nombre)
(Tipo Mala)
(Antiguedad ?ant)
)
(ValorEmpresaIbex
(Nombre ?nombre)
)
(test (<= ?ant 2)) ; la noticia debe tener dos o menos días de antigüedad
=>
(assert (ValorInestable ?nombre (str-cat "La empresa " ?nombre " es inestable "
"durante dos días porque ha surgido una noticia negativa donde está implicada")))
)
;-------------------------------------------------------------------------------
; Si hay una noticia negativa sobre un sector, éste pasa a ser inestable durante
; dos días
;-------------------------------------------------------------------------------
(defrule deducir_valores_inestables_notcias_negativas_sector
(deducirValores)
(Noticia
(Sobre ?sector)
(Tipo Mala)
(Antiguedad ?ant)
)
(ValorEmpresaIbex
(Nombre ?nombre)
(Sector ?sector)
)
(test (<= ?ant 2)) ; la noticia debe tener menos de dos días de antigüedad
=>
(assert (ValorInestable ?nombre (str-cat "La empresa " ?nombre " es inestable "
"durante dos días porque ha surgido una noticia negativa donde su "
"sector, " ?sector ", está implicado")))
)
;-------------------------------------------------------------------------------
; Si hay una noticia negativa sobre la econoía, todos los valores pasan a ser
; inestables durante dos días
;-------------------------------------------------------------------------------
(defrule deducir_valores_inestables_economia
(deducirValores)
(Noticia
(Sobre Ibex)
(Tipo Mala)
(Antiguedad ?ant)
)
(test (<= ?ant 2))
=>
(assert (ValorInestable Todos (str-cat "Al surgir una noticia negativa sobre "
"la economía, todos los valores pasan a ser inestables durante dos días")))
)
;;;;;;;;;;;;;;;; FIN BLOQUE PARA DEDUCIR VALORES INESTABLES ;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; BLOQUE PARA DEDUCIR VALORES ESTABLES ;;;;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; si hay una noticia positiva sobre un valor o su sector, un valor inestable deja
; de serlo durante dos días
;-------------------------------------------------------------------------------
; Versión noticia positiva sobre un valor
(defrule deducir_valores_estables_noticias_positivas_valor
(deducirValores)
(Noticia
(Sobre ?nombre)
(Tipo Buena)
(Antiguedad ?ant)
)
(ValorInestable ?nombre $?)
?v <- (ValorInestable ?nombre $?)
(test (< ?ant 2))
=>
(retract ?v)
; (printout t "Al surgir una noticia positiva sobre la empresa " ?nombre
; ", su valor ha dejado de ser inestable durante dos días" crlf)
)
; Versión noticia positiva sobre un sector
(defrule deducir_valores_estables_noticias_positivas_sector
(deducirValores)
(Noticia
(Sobre ?sector)
(Tipo Buena)
(Antiguedad ?ant)
)
(ValorEmpresaIbex
(Nombre ?nombre)
(Sector ?sector)
)
(ValorInestable ?nombre $?)
?v <- (ValorInestable ?nombre $?)
(test (< ?ant 2))
=>
(retract ?v)
; (printout t "Al surgir una noticia positiva sobre el sector " ?sector
; ", el valor de la empresa " ?nombre " es estable durante dos días" crlf)
)
;;;;;;;;;;;;;;;;; FIN BLOQUE PARA DEDUCIR VALORES ESTABLES ;;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; regla de transición entre el bloque de deducir valores y el de detectar
; valores peligrosos
;-------------------------------------------------------------------------------
(defrule transicionDeducir
(declare (salience -10)) ; esta debe ser la última regla del módulo en ejecutarse
?d <- (deducirValores)
=>
(retract ?d)
(assert (detectarValores))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;; Módulo de detectar valores ;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;; peligrosos, sobrevalorados e infravalorados ;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;; BLOQUE PARA DETECTAR VALORES PELIGROSOS ;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Si un valor, de la cartera del usuario, es inestable y está perdiendo de forma
; continua duante los últimos 3 días es peligroso
;-------------------------------------------------------------------------------
(defrule detectar_valores_peligrosos_perd3
(detectarValores)
(ValorCartera (Empresa ?nombre))
(or (ValorInestable ?nombre $?) (ValorInestable Todos $?))
(ValorEmpresaIbex
(Nombre ?nombre)
(Perd3consec true)
)
=>
(assert (ValorPeligroso ?nombre (str-cat "El valor " ?nombre " es peligroso "
"porque es inestable y lleva tres días perdiendo")))
)
;-------------------------------------------------------------------------------
; Si un valor, de la cartera del usuario, está perdiendo durante los últimos 5 días
; y la variación en esos días con respecto a la variación del sector es mayor de
; un 5%, ese valor es peligroso
;-------------------------------------------------------------------------------
(defrule detectar_valores_peligrosos_perd5
(detectarValores)
(ValorCartera (Empresa ?nombre))
(ValorEmpresaIbex
(Nombre ?nombre)
(Perd5consec true)
(VRS5 true)
)
=>
(assert (ValorPeligroso ?nombre (str-cat "El valor " ?nombre " es peligroso "
"porque está perdiendo durante los últimos 5 días y la variación con "
"respecto al sector es mayor al -5%")))
)
;;;;;;;;;;;;;;;;;; FIN BLOQUE PARA DETECTAR VALORES PELIGROSOS ;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;; BLOQUE PARA DETECTAR VALORES SOBREVALORADOS ;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Si el PER es Alto y el RPD bajo, la empresa está sobrevalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_sobrevalorados_general
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(EtiqPER Alto)
(EtiqRPD Bajo)
)
=>
(assert (ValorSobrevalorado ?nombre (str-cat "El valor " ?nombre " está "
"sobrevalorado ya que su PER es alto y su RPD es bajo")))
)
;-------------------------------------------------------------------------------
; Caso empresa pequeña: si el PER es alto entonces la empresa está sobrevalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_sobrevalorados_empresa_peque1
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(EtiqPER Alto)
(Tamanio PEQUENIA)
)
=>
(assert (ValorSobrevalorado ?nombre (str-cat "El valor " ?nombre " está "
"sobrevalorado porque es una empresa pequeña y tiene un PER alto")))
)
;-------------------------------------------------------------------------------
; Caso empresa pequeña: Si el PER es mediano y el RPD es bajo la empresa está
; sobrevalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_sobrevalorados_empresa_peque2
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(EtiqPER Medio)
(EtiqRPD Bajo)
(Tamanio PEQUENIA)
)
=>
(assert (ValorSobrevalorado ?nombre (str-cat "El valor " ?nombre " está "
"sobrevalorado porque es una empresa pequeña, tiene un PER mediano y un "
"RPD bajo")))
)
;-------------------------------------------------------------------------------
; Caso empresa grande: Si el RPD es bajo y el PER es mediano o alto la empresa
; está sobrevalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_sobrevalorados_empresa_grande1
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(EtiqRPD Bajo)
(Tamanio GRANDE)
(EtiqPER ?per)
)
(test (or (eq ?per Medio) (eq ?per Alto)))
=>
(assert (ValorSobrevalorado ?nombre (str-cat "El valor " ?nombre " está "
"sobrevalorado porque es una empresa grande, tiene un PER mediano o "
"alto y un RPD bajo")))
)
;-------------------------------------------------------------------------------
; Caso empresa grande: Si el RPD es mediano y el PER es alto la empresa está
; sobrevalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_sobrevalorados_empresa_grande2
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(EtiqPER Alto)
(EtiqRPD Medio)
(Tamanio GRANDE)
)
=>
(assert (ValorSobrevalorado ?nombre (str-cat "El valor " ?nombre " está "
"sobrevalorado porque es una empresa grande, tiene un PER alto o alto "
"y un RPD mediano")))
)
;;;;;;;;;;;;;;; FIN BLOQUE PARA DETECTAR VALORES SOBREVALORADOS ;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;; BLOQUE PARA DETECTAR VALORES INFRAVALORADOS ;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Si el PER es bajo y el RPD alto, la empresa está infravalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_infravalorados1
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(EtiqPER Bajo)
(EtiqRPD Alto)
)
=>
(assert (ValorInfravalorado ?nombre (str-cat "El valor " ?nombre " está "
"infravalorado porque tiene un PER bajo y un RPD alto")))
)
;-------------------------------------------------------------------------------
; Si la empresa ha caído bastante (más de un 30%) en los últimos 3, 6 o 12 meses,
; ha subido pero no mucho en el último mes, y el PER es bajo, la empresa está
; infravalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_infravalorados2
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(PerVarTri ?tri)
(PerVarSem ?sem)
(PerVarAn ?an)
(PerVarMen ?men)
(EtiqPER Bajo)
)
; La empresa ha caído más de un 30% en los últimos 3, 6 o 12 meses
(test (or (<= ?tri -30) (<= ?sem -30) (<= ?an -30)))
; La empresa ha subido, pero no mucho, en el último mes
(test (< ?men 10)) ;consideramos que no ha subido si ha subido menos de un 10%
(test (> ?men 0))
=>
(assert (ValorInfravalorado ?nombre (str-cat "El valor " ?nombre " está "
"infravalorado porque tiene un PER bajo, ha caído bastante en los "
"últimos 3, 6 o 12 meses pero este último mes ha subido un poco")))
)
;-------------------------------------------------------------------------------
; Si la empresa es grande, el RPD es alto y el PER mediano, además no está bajando
; y se comporta mejor que su sector, la empresa está infravalorada
;-------------------------------------------------------------------------------
(defrule detectar_valores_infravalorados3
(detectarValores)
(ValorEmpresaIbex
(Nombre ?nombre)
(Tamanio GRANDE)
(EtiqRPD Alto)
(EtiqPER Medio)
(Perd5consec false) ; se considera que no está bajando si lleva 5 días sin pérdidas
(VRS5 false) ; si la variación con respecto al sector es mayor al -5,
; la empresa va mejor que su sector
)
=>
(assert (ValorInfravalorado ?nombre (str-cat "El valor " ?nombre " está "
"infravalorado porque tiene un PER mediano, un RPD alto, no está bajando "
"y se comporta mejor que su sector")))
)
;;;;;;;;;;;;;;; FIN BLOQUE PARA DETECTAR VALORES INFRAVALORADOS ;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Regla transición entre el módulo de detectar valores y el de obtener propuestas
;-------------------------------------------------------------------------------
(defrule transicionDetectar
(declare (salience -10)) ; esta debe ser la última regla del módulo en ejecutarse
?d <- (detectarValores)
=>
(retract ?d)
(assert (buscarPropuestas))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;; Módulo de realización de propuestas ;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;; BLOQUE DE BÚSQUEDA DE PROPUESTAS ;;;;;;;;;;;;;;;;;;;;;
; RE = rendimiento esperado = revalorización anual esperada + dividendos anuales esperados
; Proponer vender valores peligrosos ;
;-------------------------------------------------------------------------------
; Si una empresa es peligrosa, ha bajado el último mes y ha bajado más de un 3%
; con respecto a su sector en el último mes, proponer vender las acciones de la
; empresa. RE = 20-rpd.
; EXPLICACIÓN: la empresa es peligrosa por...; además está entrando en tendencia
; bajista con respecto a su sector. Según mi estimación, existe una probabilidad
; no despreciable de que pueda caer al cabo del año un 20%, aunque produzca rpd%
; por dividendos perderíamos un 20-rpd%.
;-------------------------------------------------------------------------------
(defrule proponer_vender_valor_peligroso
(buscarPropuestas)
(ValorEmpresaIbex
(Nombre ?nombre)
(PerVarMen ?men)
(Sector ?sector)
(RPD ?rpd)
)
(ValorSector
(Nombre ?sector)
(PerVarMen ?mensector)
)
(ValorPeligroso ?nombre ?comentario)
(test (< ?men 0)) ; si la empresa ha bajado en el último mes, este valor será negativo
(test (<= (- (abs ?men) (abs ?mensector)) -3)) ; si la empresa ha bajado más de un 3% con
;respecto al sector, este valor será menor a -3
=>
(assert (VenderPeligroso ?nombre (- 20 (* ?rpd 100)) (str-cat ?comentario ", además, "
"está entrando en tendencia bajista con respecto a su sector. Según mi "
"estimación, existe una probabilidad no despreciable de que pueda caer "
"al cabo del año un 20%, aunque produzca rpd% por dividendos, "
"perderíamos " (- 20 (* ?rpd 100)) "%")))
)
; Proponer invertir en empresas infravaloradas ;
;-------------------------------------------------------------------------------
; Si una empresa está infravalorada y el usuario tiene dinero para invertir,
; proponer invertir el dinero en las acciones de la empresa:
; RE = (PERMedio - PER)*100 / (5 * PER) + RDP
; EXPLICACIÓN: esta empresa está infravalorada y seguramente el PER tienda al
; PER medio en 5 años, con lo que se debería revalorizar un (PERMedio - PER)*100/(5*PER)
; anual a lo que habría que sumar el RPD% de beneficios por dividendos.
;-------------------------------------------------------------------------------
(defrule proponer_comprar_valor_infravalorado
(buscarPropuestas)
(ValorEmpresaIbex
(Nombre ?nombre)
(PER ?per)
(RPD ?rpd)
(Sector ?sector)
)
(ValorSector
(Nombre ?sector)
(PER ?persector)
)
(ValorInfravalorado ?nombre ?comentario)
(ValorCartera
(Empresa DISPONIBLE)
(Acciones ?acciones)
)
(not
(ValorCartera
(Empresa ?nombre)
)
)
(test (> ?acciones 0)) ; comprobamos que el usuario tiene dinero
=>
(if (not (eq ?per 0)) then
(assert (ComprarInfravalorado ?nombre (+ (/ (* 100 (- ?persector ?per)) (* 5 ?per)) (* ?rpd 100))
(str-cat ?comentario " y seguramente el PER tienda al PER medio en 5 años, "
"con lo que se debería revalorizar un " (/ (* 100 (- ?persector ?per)) (* 5 ?per)) "% anual "
"a lo que habría que sumar el " (* ?rpd 100) "% de beneficios por dividendos")))
)
)
; Proponer vender valores de empresas sobrevaloradas ;
;-------------------------------------------------------------------------------
; Si una empresa de mi cartera está sobrevalorada y el rendimiento por año < 5 + precio dinero,
; proponer vender las acciones de la empresa; RE = -RPD + (PER - PERMedioSector)/(5*PER)
; EXPLICACIÓN: Esta empresa está sobrevalorada, es mejor amortizar lo invertido, ya
; que seguramente el PER tan alto deberá bajar al PER medio del sector en unos 5
; años, con lo que se debería devaluar un (PER - PERMedioSector)*100/(5*PER)
; anual, así que aunque se pieda el RPD% de beneficios por dividendos saldría rentable.
;-------------------------------------------------------------------------------
(defrule proponer_vender_valor_sobrevalorado
(buscarPropuestas)
(ValorCartera (Empresa ?nombre))
(ValorEmpresaIbex
(Nombre ?nombre)
(PER ?per)
(RPD ?rpd)
(PerVarAn ?an)
(Precio ?precio)
(Sector ?sector)
)
(ValorSector
(Nombre ?sector)
(PER ?persector)
)
(ValorSobrevalorado ?nombre ?comentario)
(test (< (+ (* ?rpd 100) ?an) (+ ?precio 5))) ; rendimiento al año < precio + 5
=>
(if (not (eq ?per 0)) then
(assert (VenderSobrevalorado ?nombre (* (- (/ (* (- ?per ?persector) 100) (* 5 ?per)) (* ?rpd 100)) 100)
(str-cat ?comentario ", es mejor amortizar lo invertido, ya que seguramente "
"el PER tan alto deberá bajar al PER medio del sector en unos 5 años, "
"con lo que se debería devaluar un " (/ (* (- ?per ?persector) 100) (* 5 ?per))
"% anual, así que aunque se pierda el " (* ?rpd 100) "% de beneficios por "
"dividendos saldría rentable.")))
)
)
; Proponer cambiar una inversión a valores más rentables ;
;-------------------------------------------------------------------------------
; Si una empresa (empresa1) no está sobrevalorada y su RPD es mayor que el
; (revalorización por semestre + RPD + 1) de una empresa de mi cartera (empresa2)
; que no está infravalorada, proponer cambiar las acciones de una empresa por las
; de la otra, RE = (RPD empresa1 - (revalorización por semestre empresa2 + RPD empresa2 +1))
; EXPLICACIÓN: empresa1 debe tener una revalorización acorde con la evolución de
; la bolsa. Por dividendos se espera un RPD%, que es más de lo que te está dando
; empresa2, por eso te propongo cambiar los valores por los de esta otra
; (rendimiento por año obtenido de revalorización + RPD de beneficios). Aunque se
; pague el 1% del coste del cambio te saldría rentable.
;-------------------------------------------------------------------------------
(defrule proponer_cambiar_rentable
(buscarPropuestas)
(ValorEmpresaIbex
(Nombre ?empresa1)
(RPD ?rpd1)
(PerVarSem ?sem1)
)
(ValorEmpresaIbex
(Nombre ?empresa2)
(RPD ?rpd2)
(PerVarSem ?sem2)
)
(ValorCartera (Empresa ?empresa2))
(not (ValorCartera (Empresa ?empresa1)))
(not (ValorInfravalorado ?empresa2 $?))
(not (ValorSobrevalorado ?empresa1 $?))
(test (< (+ (* ?rpd2 100) ?sem2 1) (* ?rpd1 100))) ; el 1 viene del coste de vender y comprar (0.5% por cada acción)
=>
(assert (Cambiar ?empresa1 ?empresa2 (- (* ?rpd1 100) (+ (* ?rpd2 100) ?sem2 1))
(str-cat ?empresa1 " debe tener una revalorización acorde con la evolución "
"de la bolsa. Por dividendos se espera un " (* ?rpd1 100) "%, que es "
"más de lo que te está dando " ?empresa2 ", por eso te propongo cambiar "
"los valores por los de esta otra, donde obtendrás un " (+ ?sem2 (* ?rpd2 100)) "% de beneficios. "
"Aunque se pague el 1% del coste del cambio te saldría rentable.")))
)
;;;;;;;;;;;;;;;;;;; FIN BLOQUE DE BÚSQUEDA DE PROPUESTAS ;;;;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Transición entre el bloque de buscar propuestas y el de mostrarlas al usuario
;-------------------------------------------------------------------------------
(defrule transicion
(declare (salience -10))
?b <- (buscarPropuestas)
?m <- (maximo ?max)
?n <- (numpropuestas ?nump)
=>
(retract ?b)
(retract ?m)
(retract ?n)
(assert (maximo 0))
(assert (numpropuestas 0))
(assert (proponerCosas))
)
;;;;;;;;;;;;;;;;;;; BLOQUE DE REALIZACIÓN DE PROPUESTAS ;;;;;;;;;;;;;;;;;;;;;;;;
;-------------------------------------------------------------------------------
; Hechos iniciales: máximo RE encontrado y el número de propuestas realizadas
;-------------------------------------------------------------------------------
(deffacts max
(maximo 0)
(numpropuestas 0)
)
;-------------------------------------------------------------------------------
; regla para detectar el primer máximo RE de todas las propuestas de cambio
;-------------------------------------------------------------------------------
(defrule maximoREInicial
(proponerCosas)
(or (Cambiar ?e1 ?e2 ?RE ?com)
(VenderSobrevalorado ?e ?RE ?com)
(ComprarInfravalorado ?e ?RE ?com)
(VenderPeligroso ?e ?RE ?com)
)
(maximo ?n)
(numpropuestas ?np)
?m <- (maximo ?n)
(test (> ?RE ?n))
(test (< ?np 5))
=>
(assert (Propuesta ?RE ?com))
(retract ?m)
(assert (maximo ?RE))
)
;-------------------------------------------------------------------------------
; Regla para ir limpiando propuestas inútiles.
; Esta regla tiene mayor salience porque debe ejecutarse antes que la anterior.
; La anterior sólo sirve para encontrar una primera propuesta y ya después,
; la que debe ejecutarse es esta.
;-------------------------------------------------------------------------------
(defrule maximoRE
(declare (salience 1))
(proponerCosas)
(or (Cambiar ?e1 ?e2 ?RE ?com)
(VenderSobrevalorado ?e ?RE ?com)
(ComprarInfravalorado ?e ?RE ?com)
(VenderPeligroso ?e ?RE ?com)
)
(maximo ?n)
?m <- (maximo ?n)
(numpropuestas ?np)
(test (> ?RE ?n))
(test (< ?np 5))
?p <- (Propuesta ?n ?c)
=>
(retract ?p)
(retract ?m)
(assert (maximo ?RE))
(assert (Propuesta ?RE ?com))
)
;-------------------------------------------------------------------------------
; Una vez obtenida una propuesta, reiniciamos el máximo y borramos ese hecho.
; Para ello, según la propuesta sea de cambiar, de vender (sobrevalorado o
; peligroso) o de comprar, se lanzará un hecho u otro.
; Versión para cambiar.
;-------------------------------------------------------------------------------
(defrule imprimirPropuestaCambiar
(proponerCosas)
?p <- (Propuesta ?RE ?explicacion)
?n <- (numpropuestas ?np)
?m <- (maximo ?RE)
?c <- (Cambiar ?e1 ?e2 ?RE ?com)
(test (< ?np 5))
=>
(printout t (+ ?np 1) " Te propongo cambiar tus acciones de " ?e2 " por las de "
?e1 " ya que " ?explicacion " RENDIMIENTO ESPERADO = " ?RE crlf)
(retract ?c)
(retract ?p)
(retract ?n)
(retract ?m)
(assert (maximo 0))
(assert (numpropuestas (+ ?np 1)))
(assert (PropuestaCambiar ?e1 ?e2 ?RE (+ ?np 1)))
)
;-------------------------------------------------------------------------------
; Una vez obtenida una propuesta, reiniciamos el máximo y borramos ese hecho.
; Para ello, según la propuesta sea de cambiar, de vender (sobrevalorado o
; peligroso) o de comprar, se lanzará un hecho u otro.
; Versión para vender.
;-------------------------------------------------------------------------------
(defrule imprimirPropuestaVender
(proponerCosas)
?p <- (Propuesta ?RE ?explicacion)
?n <- (numpropuestas ?np)
?m <- (maximo ?RE)
(or ?v <- (VenderSobrevalorado ?e ?RE ?com)
?v <- (VenderPeligroso ?e ?RE ?com)
)
(test (< ?np 5))
=>
(printout t (+ ?np 1) " Te propongo vender tus acciones de " ?e
", ya que" ?explicacion " RENDIMIENTO ESPERADO = " ?RE crlf)
(retract ?v)
(retract ?p)
(retract ?n)
(retract ?m)
(assert (maximo 0))
(assert (numpropuestas (+ ?np 1)))
(assert (PropuestaVender ?e ?RE (+ ?np 1)))
)
;-------------------------------------------------------------------------------
; Una vez obtenida una propuesta, reiniciamos el máximo y borramos ese hecho.
; Para ello, según la propuesta sea de cambiar, de vender (sobrevalorado o
; peligroso) o de comprar infravalorado se lanzará un hecho u otro.
; Versión para comprar.
;-------------------------------------------------------------------------------
(defrule imprimirPropuestaComprar
(proponerCosas)
?p <- (Propuesta ?RE ?explicacion)
?n <- (numpropuestas ?np)
?m <- (maximo ?RE)
?c <- (ComprarInfravalorado ?e ?RE ?com)
(test (< ?np 5))
=>
(printout t (+ ?np 1) " Te propongo comprar acciones de " ?e
", ya que " ?explicacion " RENDIMIENTO ESPERADO = " ?RE crlf)
(retract ?c)
(retract ?p)
(retract ?n)
(retract ?m)
(assert (maximo 0))
(assert (numpropuestas (+ ?np 1)))
(assert (PropuestaComprar ?e ?RE (+ ?np 1)))
(assert (numpropuestas (+ ?np 1)))
)
;-------------------------------------------------------------------------------
; Regla para leer la elección del usuario
;-------------------------------------------------------------------------------
(defrule preguntarPorPropuestas
(proponerCosas)
?n <- (numpropuestas ?np)
(test (<= ?np 5))
=>
(printout t (+ ?np 1) " No, he acabado" crlf)
(printout t "¿Quieres aplicar alguno de estos consejos? Selecciona el número" crlf)
(bind ?consejo (read))
(retract ?n)
(assert (Consejo ?consejo))
(if (< ?np ?consejo) then
(assert (salir))
)
)
;-------------------------------------------------------------------------------
; Regla para salir del programa
;-------------------------------------------------------------------------------
(defrule AplicarConsejoDespedida
(proponerCosas)
(salir)
?m <- (maximo ?max)
=>
(retract ?m)
(printout t "¡Hasta pronto!" crlf)
)
;-------------------------------------------------------------------------------
; Si el consejo seleccionado es uno de cambiar un valor, se disparará esta regla.
; Elimina de la cartera el antiguo valor y guarda el nuevo, con el 5% de las
; acciones que tenía el otro
;-------------------------------------------------------------------------------
(defrule AplicarConsejoCambiar
(proponerCosas)
?c <- (Consejo ?consejo)
?prob <- (PropuestaCambiar ?e1 ?e2 ?RE ?consejo)
?car <- (ValorCartera
(Empresa ?e2)
(Acciones ?accs)
(ValorActual ?dineroempresa)
)
?disp <- (ValorCartera
(Empresa DISPONIBLE)
(ValorActual ?dinero)
)
(ValorEmpresaIbex
(Nombre ?e1)
(Precio ?precio)
)
=>
(retract ?car)
(retract ?c)
(retract ?disp)
(retract ?prob)
(assert (ValorCartera
(Empresa ?e1)
(Acciones ?accs)
(ValorActual (* ?accs ?precio))
)
)
(printout t "Actualizada tu cartera. Añadida la empresa " ?e1 " con " ?accs " acciones" crlf)
(printout t "Ahora tienes " (- (+ ?dinero ?dineroempresa) (* ?accs ?precio))
" euros en tu cartera." crlf)
; Al vender las acciones de la empresa2, en la cartera obtendremos:
; (DineroDisponible + ValorAccionEmpresa2)
; Al comprar las acciones de la empresa1, en la cartera obtendremos:
; (DineroDisponible + ValorAccionEmpresa2) - (numAccionesEmpresa2 * PrecioAccionesEmpresa1)
(assert (ValorCartera
(Empresa DISPONIBLE)
(Acciones (- (+ ?dinero ?dineroempresa) (* ?accs ?precio)))
(ValorActual (- (+ ?dinero ?dineroempresa) (* ?accs ?precio)))
)
)
(assert (borrarPropuestas))
)
;-------------------------------------------------------------------------------
; Si el consejo seleccionado es uno de vender un valor, se disparará esta regla.
; Elimina de la cartera el valor y suma a la cantidad disponible su valor actual
;-------------------------------------------------------------------------------
(defrule AplicarConsejoVender
(proponerCosas)
?c <- (Consejo ?consejo)
?prob <- (PropuestaVender ?e ?RE ?consejo)
?car <- (ValorCartera
(Empresa ?e)
(ValorActual ?valor)
)