Equation Chapter 1 Section 1 Trabajo Fin de Grado Grado en Ingeniería de las Tecnologías de Telecomunicación Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Autor: Diego José Fernández Cotán Tutor: Francisco Javier Muñoz Calle Dpto. de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2025
Trabajo Fin de Grado Grado en Ingeniería de las Tecnologías de Telecomunicación Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Autor: Diego José Fernández Cotán Tutor: Francisco Javier Muñoz Calle Profesor Colaborador Dpto. de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2025
Trabajo Fin de Grado: Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Autor: Diego José Fernández Cotán Tutor: Francisco Javier Muñoz Calle El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2025 El Secretario del Tribunal
A mi familia.
Agradecimientos Quedan atrás unos años en el que he completado parte de aquel camino que un día elegí. Años de sinsabores y desventuras, pero también de aprendizaje y recompensa. Un recorrido que, aunque no siempre fue fácil, me ha permitido crecer y afrontar un horizonte repleto de nuevos desafíos. Quisiera agradecer a todos aquellos que, de un modo u otro, estuvieron a mi lado durante esta odisea y que con su consejo y buen hacer contribuyeron a mi crecimiento personal y académico. Agradezco profundamente el incansable apoyo de mis padres, a quienes les debo más de lo que las palabras pueden expresar. Siempre tuvieron una palabra de aliento en los momentos duros y templanza y mesura para acompañarme y guiarme a lo largo de esta vida. Han sido, son y serán para mí ejemplo de fortaleza y perseverancia. Por todo lo que habéis hecho por mí, gracias. Diego José Fernández Cotán Sevilla, 2025
6.2 Blog 121 6.2.1 Posts 121 6.2.2 Videos 121 6.2.3 Archivos 122 6.3 Chat de Consultas 122 6.3.1 Chat de consultas 122 6.3.2 Gestión de conversaciones 123 6.4 Perfil y configuración 123 6.4.1 Perfil 123 6.4.2 Configuración del semáforo 124 6.4.3 Gestión de usuarios 124 7 Conclusiones y líneas de avance 125 7.1 Conclusiones 125 7.2 Líneas de avance 127 Anexo A: Instalación y Puesta en Marcha 128 Repositorios 128 iOS 128 Android 129 Servidor 130 Anexo B: API TwelveData 132 Anexo C: Inicialización de Base de Datos 135 Anexo D: Configuración de Docker 138 Referencias 141
Índice de Tablas Tabla 1 - CU-01 Inicio de sesión 41 Tabla 2 - CU-02 Registro de usuarios 42 Tabla 3 – CU-03 Añadir valor a favoritos 43 Tabla 4 - CU-04 Consultar entrada de Blog 44 Tabla 5 - CU-05 Enviar mensaje en el chat de Consultas 45 Tabla 6 - CU-06 Modificar datos de usuario o contraseña 46 Tabla 7 - CU-07 Cerrar sesión 47 Tabla 8 - CU-08 Añadir nuevo valor a seguimiento 48 Tabla 9 - CU-09 Configurar límites para el cálculo del Estado de Inversión 49 Tabla 10 - CU-10 Eliminar acción o criptomoneda 50 Tabla 11 - CU-11 Añadir nueva entrada de Blog 51 Tabla 12 - CU-12 Modificar entrada de Blog 52 Tabla 13 - CU-13 Eliminar entrada de Blog 53 Tabla 14 - CU-14 Gestionar conversaciones en el Chat de Consultas 54 Tabla 15 - CU-15 Configurar indicador de Estado de Inversión 55 Tabla 16 - CU-16 Eliminar usuario 56 Tabla 17 - CU-17 Crear nueva cuenta de administrador 57 Tabla 18 - Rutas para Inicio de Sesión y Registro 104 Tabla 19 - Rutas de Información de Usuario 104 Tabla 20 - Rutas de Información de Acciones y Criptomonedas 106 Tabla 21 - Rutas de Blog 107 Tabla 22 - Rutas de Chat de Consultas 108 Tabla 23 - Tabla Usuarios de la base de datos 110 Tabla 24 - Tabla Valores y ValoresRef de la base de datos 111 Tabla 25 - Tabla Favoritos de la base de datos 111 Tabla 26 - Tabla Limites y LimitesRef de la base de datos 112 Tabla 27 - Tabla Blog de la base de datos 113 Tabla 28 - Tabla Chat de la base de datos 113 Tabla 29 - Tabla Semáforo de la base de datos 114
Índice de Figuras Figura 1 - Evolución histórica de Bitcoin 23 Figura 2 - Arquitectura de la aplicación 26 Figura 3 - Funcionamiento de React Native 30 Figura 4 - Funcionamiento WSGI 31 Figura 5 -Expo Push Notification API. https://docs.expo.dev/push-notifications/sending-notifications/ 32 Figura 6 - Contenedores Docker. Comparativa con MVs 33 Figura 7 - Funcionamiento SSL/TLS. https://learn.microsoft.com/es-es/azure/postgresql/flexibleserver/concepts-networking-ssl-tls 35 Figura 8 - Funcionamiento JWT 36 Figura 9 - Interfaz Webull 37 Figura 10 - CU-01 Inicio de sesión 40 Figura 11 - CU-02 Registro de usuarios 41 Figura 12 - CU-03 Añadir valor a favoritos 42 Figura 13 - CU-04 Consultar entrada de Blog 43 Figura 14 - CU-05 Enviar mensaje en el chat de Consultas 44 Figura 15 - CU-06 Modificar datos de usuario o contraseña 45 Figura 16 - CU-07 Cerrar sesión 46 Figura 17 – CU-08 Añadir nuevo valor a seguimiento 47 Figura 18 – CU-09 Configurar límites para el cálculo del Estado de Inversión 48 Figura 19 – CU-10 Eliminar acción o criptomoneda 49 Figura 20 - CU-11 Añadir nueva entrada de Blog 50 Figura 21 - CU-12 Modificar entrada de Blog 51 Figura 22 - CU-13 Eliminar entrada de Blog 52 Figura 23 - CU-14 Gestionar conversaciones en el Chat de Consultas 53 Figura 24 - CU-15 Configurar indicador de Estado de Inversión 54 Figura 25 - CU-16 Eliminar usuario 55 Figura 26 - CU-17 Crear nueva cuenta de administrador 56 Figura 27 - Estados y límites del algoritmo de cálculo de inversión 57 Figura 28 - Cambio de estados 58 Figura 29 - Comunicación entre los componentes de la aplicación 60 Figura 30 - Peticiones del frontend al servidor 61
Figura 31 - Actualización de la información de seguimiento y envío de notificaciones 62 Figura 32 - Estructura de directorios del desarrollo React Native 63 Figura 33 - Interrelación de los componentes del código frontend 64 Figura 34 - Botones como componentes personalizados 65 Figura 35 - Entrada de texto como componentes personalizados 65 Figura 36 - Entrada de texto con botón para chat de consultas 65 Figura 37 - Globo de chat de consultas 66 Figura 38 - Botón de "Favoritos" marcado 66 Figura 39 - Botón de "Favoritos" sin marcar 66 Figura 40 - Indicador de Estado de Inversión 67 Figura 41 - Selector de icono sin imagen seleccionada 67 Figura 42 - Selector de icono con imagen seleccionada 68 Figura 43 - Icono de acción o criptomoneda en el detalle de la pantalla de Seguimiento 68 Figura 44 - Bottom Tabs Navigator 71 Figura 45 - Vista general de pantallas para usuarios no autenticados 75 Figura 46 - Pantalla de inicio de sesión 75 Figura 47 - Mensajes de error en Inicio de Sesión 76 Figura 48 - Pantalla de registro 77 Figura 49 - Error en formulario de registro 77 Figura 50 - Error al crear cuenta 78 Figura 51 - Cuenta creada correctamente 78 Figura 52 - Vista general de pantallas de usuario 79 Figura 53 - Pantalla de Seguimiento 80 Figura 54 - Detalle de un valor en la pantalla de Seguimiento 80 Figura 55 - Información del código de colores 81 Figura 56 - Pantalla de Seguimiento general, filtrando por acciones o criptomonedas 82 Figura 57 - Blog, sección de Posts 83 Figura 58 - Blog, sección de vídeo 84 Figura 59 - Blog, sección de archivos 85 Figura 60 - Visualización de archivos en Android 86 Figura 61 - Visualización de archivos en iOS 86 Figura 62 - Chat de consultas 87 Figura 63 - Pantalla de Perfil 88 Figura 64 - Modificar datos de usuario 89 Figura 65 - Modificar contraseña 89 Figura 66 - Pantalla de cierre de sesión 90 Figura 67 - Vista general de las pantallas de administrador 90 Figura 68 - Pantalla de seguimiento para administrador 91 Figura 69 - Configuración de límites del Algoritmo de Estado de Inversión 92 Figura 70 - Error en el formato de datos de configuración de límites 92
Figura 71 - Añadir a seguimiento 93 Figura 72 - Añadir nuevo Post 94 Figura 73 - Añadir nuevo Vídeo 94 Figura 74 - Añadir nuevo Archivo 95 Figura 75 - Modificar Posts, Vídeos y Archivos 95 Figura 76 - Pantalla de consultas para administradores 96 Figura 77 - Clasificación de conversaciones 97 Figura 78 - Pantalla de Configuración para administradores 97 Figura 79 - Configurar referencias 98 Figura 80 - Configuración de semáforo 99 Figura 81 - Configuración de usuarios 99 Figura 82 - Modificar parámetros de usuario 100 Figura 83 - Crear nuevo perfil de administrador 100 Figura 84 - Perfil para administrador 101 Figura 85 - Interrelación de los componentes del código backend 102 Figura 86 - Componentes que intervienen durante la ejecución del servidor 103 Figura 87 - Relaciones de la base de datos 109 Figura 88 - Componentes que intervienen durante la ejecución del módulo 'Engine' 115 Figura 89 - Panel de seguimiento en Android 119 Figura 90 - Panel de seguimiento de iOS 119 Figura 91 - Configuración de referencias en Android 120 Figura 92 - Configuración de referencias en iOS 120 Figura 93 - Notificaciones en Android 120 Figura 94 - Notificaciones en iOS 120 Figura 95 - Posts en Android 121 Figura 96 - Posts en iOS 121 Figura 97 - Vídeos en Android 121 Figura 98 - Vídeos en iOS 121 Figura 99 - Archivos en Android 122 Figura 100 - Archivos en iOS 122 Figura 101 - Chat de consultas en Android 122 Figura 102 - Chat de consultas en iOS 122 Figura 103 - Gestión de conversaciones en Android 123 Figura 104 - Gestión de conversaciones en iOS 123 Figura 105 - Perfil en Android 123 Figura 106 - Perfil en iOS 123 Figura 107 - Configuración de semáforo en Android 124 Figura 108 - Configuración de semáforo en iOS 124 Figura 109 - Gestión de usuarios en Android 124 Figura 110 - Gestión de usuarios en iOS 124
Figura 111 - Ejecución de la aplicación con npm start 128 Figura 112 - Menú de Expo Go 129 Figura 113 - Pantalla de inicio de la aplicación en iOS 129
1 INTRODUCCIÓN l mercado de valores brinda un punto de encuentro entre individuos y empresas que buscan hacer crecer su capital y maximizar sus oportunidades financieras. Conocer el funcionamiento de este sistema y formar parte de él mediante la compra y venta de acciones, puede suponer un gran potencial de inversión. Sin embargo, también puede conllevar riesgos, especialmente para quienes buscan una manera rápida de generar ingresos sin estar familiarizado con su complejidad. 1.1 Contexto Desde sus orígenes, la bolsa ha estado ligada a personas con alto poder adquisitivo y conocimientos financieros avanzados. Los valores y productos financieros eran manejados por individuos o instituciones con gran capacidad económica y acceso a información privilegiada. Sin embargo, en las últimas décadas, con la aparición de numerosas webs y aplicaciones que facilitan este proceso, la inversión en bolsa se ha democratizado considerablemente atrayendo a un público mucho más amplio. Uno de los puntos de inflexión de esta tendencia se dio a finales del año 2020, cuando Bitcoin, una de las criptomonedas más populares, experimentó un notable incremento de su valor. En ese momento, personas que habían decidido apostar por esta tecnología años antes vieron cómo en muchos casos sus pequeñas inversiones se transformaban en verdaderas fortunas, convirtiéndolos en millonarios de la noche a la mañana. Figura 1 - Evolución histórica de Bitcoin Este fenómeno revolucionó la percepción que la sociedad tenía de las inversiones financieras, atrayendo a inversores de todo tipo, desde aquellos con experiencia hasta aquellos que nunca habían tenido contacto previo con el mundo de la inversión. El atractivo de estas historias de éxito no pasó desapercibido y fueron muchos los que decidieron sumarse a esta ola, motivados por la posibilidad de obtener cuantiosas ganancias al adentrarse en el mercado financiero. E
Introducción 24 La popularidad de las criptomonedas propició la aparición de numerosas plataformas de inversión y cursos de trading que, a través de agresivas campañas de marketing, consolidaron en muchos la creencia de que invertir es sencillo y que es la clave para enriquecerse rápidamente. Sin embargo, la experiencia demuestra que esta percepción suele ser incorrecta. La inversión en bolsa es un proceso complejo que exige un conocimiento profundo del funcionamiento del mercado, además de la capacidad de gestionar el riesgo y la volatilidad. Ignorar estos aspectos o subestimar su importancia puede llevar a resultado desfavorables. No existe un solo método de inversión, y cada inversor necesita plantear diferentes estrategias que se adapten a sus objetivos, nivel de riesgo y horizonte temporal. Estas pueden estar basadas en indicadores financieros, índices de referencia e incluso confianza en el mercado, lo que implica que la bolsa no solo responde a datos objetivos, lo que añade un componente adicional de complejidad. En este contexto nace este proyecto, centrado en la creación y desarrollo de una aplicación multiplataforma, accesible tanto para usuarios de Android como iOS, que sea intuitiva y eficiente, diseñada para ofrecer una alternativa accesible y confiable a los inversores con menos experiencia. Su propósito es doble: por un lado, presenta un método de inversión con el que lo usuarios podrán invertir en base a las recomendaciones generadas por un algoritmo, fundamentado en los índices RSI y STOCH, que calcula el momento de inversión en el que se encuentra un determinado valor. Por otro lado, su objetivo es fomentar el aprendizaje en el ámbito de la inversión, proporcionando a los usuarios una herramienta que les permita adquirir conocimientos sólidos sobre cómo invertir y mantenerse informado de la actualidad del mercado bursátil. Además, la integración del chat directo con los administradores permite que el usuario pueda plantear directamente sus dudas y recibir soporte en tiempo real. Este soporte humano guía en cada paso del proceso, asegurando una experiencia de inversión responsable y personalizada. 1.2 Objetivos A nivel técnico, los objetivos que persigue la aplicación son: 1. Inicio de sesión y registro de usuarios Este sistema permite la creación de perfiles de usuario, permitiendo que cada usuario pueda tener una cuenta personalizada para gestionar sus preferencias dentro de la aplicación. Recoge mediante un formulario el nombre completo, correo electrónico y contraseña, y los almacena en la base de datos. Esta información se utiliza para la autenticación del usuario, manteniendo un acceso privado a sus datos e interacciones. 2. Plataforma de formación a. Gestión de contenidos Permite a los administradores poner a disposición de los usuarios material formativo en distintos tipos de formatos, tales como: - Artículos, combinando imagen y texto. - Vídeos. - Documentos.
25 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa b. Chat de consultas Servicio de mensajería en tiempo real entre usuarios y administradores para trasladar preguntas sobre temas financieros o uso de la aplicación. 3. Seguimiento de acciones a. Panel de acciones y criptomonedas El usuario puede consultar una tabla con las acciones o criptomonedas disponibles, con precios y datos actualizados en tiempo real. b. Sistema de notificación i. Aviso telemático: Envío de notificación en tiempo real al dispositivo del usuario alertando de que uno o varios de los valores a los que está suscrito ha cambiado de estado. Puede activarse o desactivarse desde el centro de configuración de notificaciones del dispositivo. ii. Código de colores: Sistema visual disponible en el panel de seguimiento que informa al usuario del estado de inversión de la acción o criptomoneda. Puede ser configurado por los administradores para cada uno de los estados que contempla el algoritmo. c. Configuración i. Administrador o Gestiona la lista de acciones y criptomonedas soportadas en la aplicación. o Define los límites generales y específicos de cada acción o criptomoneda, que establecen los umbrales que evaluará el algoritmo de cálculo del momento óptimo de inversión. ii. Usuario o Gestiona una lista personal de acciones y criptomonedas para el seguimiento personal. Puede seleccionar estos valores de entre las que el administrador haya puesto a disposición de los usuarios. o Sistema de alerta mediante notificación al dispositivo al producirse un cambio de estado en la lista personal de seguimiento. Este proyecto, por tanto, tiene como objetivo proporcionar una plataforma accesible que, además de ofrecer una herramienta práctica de inversión, promueva el aprendizaje y compresión del mercado financiero.
Análisis de Requisitos y Recursos 32 2.2.4 Expo Push Notification API Gestionar las notificaciones push es un proceso complejo, que se maneja de manera diferente en Android e iOS. La API de Expo para notificaciones push utilizada en este proyecto facilita este desarrollo, unificando la manera en la que se envían estas notificaciones para ambos sistemas operativos. La librería expo-notification provee de toda la funcionalidad en el lado de cliente necesaria para utilizar notificaciones push en una aplicación multiplataforma. Además, el equipo y la comunidad de Expo se han encargado de crean backends que gestionen este proceso para distintos lenguajes de programación, entre ellos Python, que es el que se utiliza en este proyecto para el servidor. La manera en que gestionan las notificaciones es la siguiente: El servidor de Expo recibe el mensaje que queramos mostrar en la aplicación, acompañado de un token, ExpoPushToken, generado en el dispositivo de un usuario, que identifica dicho dispositivo. Dependiendo de su sistema operativo, Expo remite estas notificaciones a Firebase Cloud Messaging (FCM), para Android, y Apple Push Notifications (APN), para iOS, y estos servicios a su vez lo envían a los terminales. Firebase Cloud Messaging y Apple Push Notifications son servicios de envío de notificaciones push, de Google y Apple respectivamente. Para aplicaciones nativas desarrolladas específicamente para cada plataforma, es necesario configurar estos servicios específicamente. Si bien la utilización del servicio Expo Push Notifications facilita este proceso. En el siguiente esquema se muestra el funcionamiento. Figura 5 -Expo Push Notification API. https://docs.expo.dev/push-notifications/sending-notifications/
33 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 2.2.5 Docker Docker es una plataforma para desarrollar, enviar y ejecutar aplicaciones [8]. Permite empaquetar y ejecutar aplicaciones en un entorno llamado Contenedor, que tiene todo lo necesario para hacer funcionar las aplicaciones sin depender de lo que esté instalado en el host. Los contenedores son procesos aislados para cada uno de los componentes de una aplicación: - Autónomo. Cada contenedor tiene todo lo que necesita para funcionar, sin depender de ninguna dependencia preinstalada en el host. - Aislado. Lo contenedores se ejecutan de forma aislada, por lo que tiene una influencia mínima en el host y en otros contenedores. - Independiente. Cada contenedor se administra de manera independiente. Eliminar un contenedor no afecta a los otros, a menos que estén configurados para ello. - Portátil. Los contenedores pueden ejecutarse en cualquier lugar. El contenedor que se ejecuta en una máquina de desarrollo funciona de la misma manera en un centro de datos o en la nube. A diferencia de las máquinas virtuales [9], que cuentan con sistema operativo completo con su propio núcleo, controladores de hardware, programas y aplicaciones, un contenedor es simplemente un proceso con todos los archivos que necesita para ejecutarse. Si se ejecutan varios contenedores, todos ellos comparten el mismo núcleo, lo que permite ejecutar más aplicaciones en menos infraestructura. Figura 6 - Contenedores Docker. Comparativa con MVs Utilizar Docker ayuda a la escalabilidad de la aplicación y facilita el despliegue del servidor en cualquier máquina, así como la integración con la base de datos. 2.3 Red Para la comunicación entre la aplicación, como cliente, y el servidor se pueden utilizar diferentes métodos, cuya elección depende de las necesidades específicas del proyecto, como la transferencia de datos en tiempo real o la frecuencia de solicitudes. Los métodos más utilizados incluyen el uso de peticiones HTTP y WebSockets, para conexiones bidireccionales en tiempo real.
Análisis de Requisitos y Recursos 34 2.3.1 HTTP Las peticiones HTTP se utilizan especialmente para operaciones que no requieren interacciones constantes o en tiempo real. Estas solicitudes se envían a través de URLs que actúan como puntos de acceso a los recursos del servidor. En esta aplicación fundamentalmente se utilizan los métodos GET y POST. GET, para operaciones de lectura y POST, para las solicitudes que requieran enviar alguna información adicional al servidor. 2.3.2 WebSockets Este protocolo permite establecer un canal de comunicación bidireccional entre un cliente y un servidor, permitiendo el envío y recepción de mensajes en tiempo real. El objetivo de esta tecnología es proporcionar un mecanismo para aplicaciones que requieren una comunicación bidireccional con el servidor, evitando abrir múltiples conexiones HTTP. 2.3.3 Formato de datos: JSON JSON (JavaScript Object Notation) es un formato de texto para el intercambio de datos. Define un conjunto de reglas de formato para la representación de datos estructurados [10]. Es ampliamente utilizado en aplicaciones web para la comunicación entre cliente y servidor, y es el formato utilizado también en este proyecto. Ejemplos de este formato se puede encontrar en el Anexo B de este documento. 2.4 Seguridad La seguridad es un aspecto fundamental en cualquier web o aplicación móvil. Para este proyecto se implementan fundamentalmente dos tecnologías que permiten un uso más seguro de la aplicación, además del inicio de sesión y registro de usuarios: Cifrado de las comunicaciones con SSL/TLS y uso de JSON Web Token en las peticiones. 2.4.1 HTTPS y WSS La comunicación entre el servidor y la aplicación están cifradas mediante el uso de HTTPS (HyperText Transfer Protocol Secure) o WSS (Secure Web Socket), en el caso de WebSockets. • HTTPS utiliza el protocolo HTTP combinado con TLS (Transport Layer Security) o su predecesor SSL (Secure Sockets Layer). • Una ruta WSS indica que el tráfico sobre esa conexión está protegido con TLS [11]. El protocolo de cifrado SSL/TLS funciona con un mecanismo de clave pública y privada combinado con claves simétricas para cifrar los mensajes. La clave pública es proporcionada por el servidor a la aplicación, lo que permite cifrar datos que solo el servidor puede descifrar utilizando su clave privada, la cual está protegida y no se comparte. Una vez establecida una clave de sesión compartida, esta se utiliza para cifrar y descifrar los mensajes en ambas direcciones.
35 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 7 - Funcionamiento SSL/TLS. https://learn.microsoft.com/es-es/azure/postgresql/flexibleserver/concepts-networking-ssl-tls El uso de HTTPS protege la privacidad de los datos y previene de ataques Man in the Middle. Para implementar esta tecnología es necesario contar con un certificado SSL/TLS. En este proyecto se hace uso de certificados de Let’s Encrypt, que es una plataforma gratuita para la expedición de certificados digitales. 2.4.1.1 Let’s Encrypt Let’s Encrypt es una Autoridad de Certificación gratuita, automatizada y abierta, que permite obtener certificados SSL/TLS para un servidor. Para obtener un certificado para un dominio web de Let’s Encrypt es necesario demostrar control sobre ese dominio, lo cual se comprueba con el protocolo ACME (RFC 8555). Se ha utilizado en este proyecto en el servidor, como alternativa a los certificados autofirmados, para posibilitar el cifrado SSL en las comunicaciones entre este y la aplicación móvil. Los certificados autofirmados, si bien pueden ser útiles en muchas ocasiones, sobre todo en páginas web, donde los navegadores dan la opción de confiar en el certificado manualmente, la naturaleza de las aplicaciones móviles no permite su uso. Se requiere certificados de una Autoridad de Certificación como Let’s Encrypt. 2.4.2 JWT Token El otro aspecto de seguridad que implementa la aplicación son los JSON Web Token o JWT, que es una manera segura de intercambio de información entre dos o más partes utilizando formato JSON [12].
Análisis de Requisitos y Recursos 36 Su funcionamiento es el siguiente: después de haber superado con éxito la autenticación de usuario, este recibe un token de acceso y un token de refresco. El token de acceso se envía en la cabecera Authorization de cada petición que requiera autenticación. El token de acceso tiene un tiempo de vida configurable, que en general suele corto, para que un atacante no lo pueda utilizar durante mucho tiempo. Una vez que el token de acceso expira, debe solicitarse uno nuevo utilizando el token de refresco. En la siguiente figura se muestra un ejemplo de funcionamiento: Figura 8 - Funcionamiento JWT La utilización de JWT evita que alguien ajeno a la aplicación acceda a recursos protegidos del servidor, ya que requiere un token válido generado durante el proceso de autenticación. Esto contribuye a prevenir ataques de suplantación de identidad y manipulación de datos. 2.5 Obtención de datos de bolsa Uno de los objetivos fundamentales de este proyecto es poder contar con datos del mercado de valores, principalmente de la Bolsa de Nueva York, actualizados en tiempo real. 2.5.1 Web Scraping A fin de obtener información actualizada del mercado de valores, en un primer momento, se planteó la posibilidad de obtener estos datos directamente de la web “Webull”, creando una API que accediera a la página y obtuviera estos datos. Esta web permite la consulta de datos financieros y de mercado de valores a través una interfaz de usuario, mostrada en la Figura 9, que se actualiza dinámicamente en tiempo real.
37 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 9 - Interfaz Webull Para obtener estos datos es necesario emplear técnicas de Web Scraping, que consiste extraer información de una web mediante un programa que, en este caso, accedería al código HTML de la página y obtendría el precio de la acción y los índices RSI y STOCH. Los datos bolsa son bastante codiciados y en la mayoría de los casos la manera para acceder a ellos es pagando. Webull permite la consulta gratuita a través de la web, pero intenta evitar, al igual que otras webs similares, que sus datos sean extraídos directamente para procesarlos en otro programa. Si bien, y aunque durante un tiempo exploré esta opción llegando a desarrollar bastante código, consideré que extraer la información de Webull no era una buena opción para el propósito que le quería dar. No obstante, me gustaría mostrar el proceso seguido: Para automatizar el proceso estuve utilizando Selenium, que es una librería que permite automatizar pruebas en navegadores web simulando un comportamiento humano, y que a menudo se utiliza para el web scraping. La manera de acceder a los elementos de la página es haciendo referencia a identificadores o atributos HTML de estos. Sin embargo, probando diferentes maneras de poder acceder a ellos, pude comprobar que no había una manera unificada de hacerlo. En el HTML de la página los elementos no tienen un identificador invariable. La única manera de referenciarlos desde el script, por ejemplo, para hacer click en el icono de los indicadores y seleccionar RSI y Stoch, es por el atributo class, si bien el valor de este atributo varía cada vez que se accede a la página. En este caso, viendo el comportamiento de la web, llegué a pensar que el valor de class variaba sobre unos valores acotados, lo que me estaba permitiendo acceder teniendo en cuenta esta casuística. Sin embargo, tras un tiempo de pruebas, comprobé que variaba de manera aleatoria, probablemente para evitar la utilización de este tipo de técnicas, y, de este modo, el script deja de tener validez prácticamente de una ejecución a otra. Por otro lado, los valores numéricos que necesitaba extraer se encontraban dentro de un elemento Canvas, que no refleja dichos valores directamente en el HTML, probablemente una vez más para evitar el web scraping. Tras haber estado investigando, la única manera que parece que pudiera es mediante el reconocimiento de imágenes con una biblioteca de Python, aunque, además de los otros problemas, no había garantías de que funcionara de una manera fiable.
Análisis de Requisitos y Recursos 38 La utilización del software de automatización, además, hacía que la web detectara un comportamiento extraño y pudiera llegar a bloquear el acceso por IP. Este punto podría ser crítico para la aplicación si se perdiera acceso durante un tiempo. Asimismo, al utilizar el Web Scraping, en general, también se podrían estar incumpliendo los términos de servicio de los sitios de los que se extraiga la información. Por todo ello, consideré que extraer la información de Webull no era una buena opción para este propósito en concreto. Para continuar con el desarrollo estuve investigando otras opciones: - Para tener una API 'propia', el Web Scraping es prácticamente la única opción viable, pese a lo que comentaba de los términos de uso, que dependería de cada web. La otra forma para obtener los datos en tiempo real es tener acceso a fuentes primarias, que son prácticamente inaccesibles si no es a través de acuerdos comerciales con los proveedores. - La otra opción, es utilizar algunas de las API comerciales que ya existen. La mayoría ofrece planes gratuitos, con funcionalidades muy limitadas, pero suficientes para tener una demo de la aplicación. Si se quisiera utilizar la aplicación en el futuro con fines comerciales, se podría cambiar a un plan de pago adquiriendo un APIKEY. Después de esta investigación, esta última, suponía la opción más razonable, ya que permite la consulta de precios e índices, tanto de acciones como de criptomonedas en tiempo real y con la garantía de que la información estará disponible sin poner en riesgo la experiencia del usuario. Algunas opciones populares son TwelveData, AlphaVantage o Polygon. 2.5.2 TwelveData API TwelveData es una plataforma digital que ofrece datos del mercado financiero a través de consultas a una API. Dispone de datos en tiempo real e históricos, así como de información general de las acciones, precios o indicadores concretos Existen numerosas plataformas que ofrecen datos financieros para su uso en aplicaciones comerciales o simplemente para el estudio personal del mercado. El funcionamiento de todas ellas es bastante similar, si bien existen diferencias significativas en el precio y en las condiciones de uso. Para el propósito de la aplicación se eligió la API de TwelveData, que ofrece extensa documentación y un plan gratuito suficiente para poder disponer y trabajar con los datos durante el desarrollo y pruebas de la aplicación. Esta plataforma ofrece los datos en formato JSON o, alternativamente, en CSV mediante peticiones a su API. En el proyecto se utilizan datos en formato JSON. 2.5.2.1 Peticiones Los enpoints de la API empiezan por el prefijo: https://api.twelvedata.com seguido de los parámetros de consulta [13]. Para el propósito de la aplicación se consultan tanto para acciones y criptomonedas las siguientes peticiones:
39 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa - Información general: o https://api.twelvedata.com/quote?symbol=AAPL&apikey=your_api_key - Precio en tiempo real: o https://api.twelvedata.com/price?symbol=AAPL&apikey=your_api_key - Indicador RSI en intervalo de 1 minuto y 5 minutos: o https://api.twelvedata.com/rsi?symbol=AAPL&interval=1min&outputsize=1&a pikey=your_api_key - Indicador STOCH en intervalo de 1 minuto y 5 minutos: o https://api.twelvedata.com/stoch?symbol=AAPL&interval=1min&outputsize=1 &apikey=your_api_key El campo ‘symbol’ de la petición se debe ajustar dependiendo de la acción o criptomoneda requerida en cada caso. El resultado de las peticiones indicadas, siguiendo la acción de ejemplo ‘AAPL, Apple’ se puede consultar en el Anexo B.
Diseño de la Aplicación 40 3 DISEÑO DE LA APLICACIÓN n este capítulo se abordarán en detalle aspectos relacionados con el diseño de la aplicación. Se describirán los casos de uso [14], indicando las interacciones entre los usuarios y el sistema. Asimismo, se incluirán diagramas de casos de uso y diagramas de secuencia para representar el funcionamiento y estructura del sistema. 3.1 Casos de uso 3.1.1 Inicio de sesión Figura 10 - CU-01 Inicio de sesión E
41 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CU-01 Inicio de sesión Precondición El usuario debe estar registrado en la aplicación y no debe haber iniciado sesión. Descripción Este caso de uso describe el proceso de inicio de sesión de un usuario en la aplicación. Secuencia Paso Acción 1 Introduce el usuario y la contraseña en los campos del formulario. 2 Pulsa el botón ‘Iniciar sesión’ Postcondición El usuario inicia sesión en la aplicación y obtiene acceso al contenido. Excepciones Paso Acción 2 Si el usuario no está registrado en la aplicación E.1 Se mostrará un mensaje de error solicitando de nuevo los datos y permaneciendo en la pantalla de inicio de sesión. Tabla 1 - CU-01 Inicio de sesión 3.1.2 Registro de usuarios Figura 11 - CU-02 Registro de usuarios
Diseño de la Aplicación 48 CU-08 Añadir nueva acción o criptomoneda a seguimiento Precondición El administrador debe estar autenticado en la aplicación y haber seleccionado la pantalla de Seguimiento en la barra de navegación. Descripción Este caso de uso describe las acciones para añadir un nuevo valor a seguimiento. Secuencia Paso Acción 1 Pulsar botón ‘Añadir a seguimiento’ 2 Introducir símbolo y nombre del nuevo valor. 3 Pulsar el botón ‘Acción/Crypto’ para seleccionar si es acción o criptomoneda. 4 Pulsar icono para añadir una imagen representativa del valor. 5 Pulsar el botón ‘Añadir’. Postcondición Se habrá añadido un nuevo valor y estará disponible para los usuarios de la aplicación. Excepciones Paso Acción 5 Si el símbolo introducido no existe o el campo está vacío o el campo de nombre está vacío o no se ha seleccionado se es acción o criptomoneda o no se ha seleccionado una imagen. E.1 Muestra un mensaje de error indicando la información que falta. Comentarios Ninguno. Tabla 8 - CU-08 Añadir nuevo valor a seguimiento 3.1.9 Configurar límites para el algoritmo de Estado de Inversión Figura 18 – CU-09 Configurar límites para el cálculo del Estado de Inversión
49 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CU-09 Configurar límites para el cálculo del Estado de Inversión Precondición El administrador debe estar autenticado en la aplicación y haber seleccionado la pantalla de Seguimiento en la barra de navegación. Descripción Este caso de uso describe las acciones configurar los límites para el cálculo del Estado de Inversión de un valor. Secuencia Paso Acción 1 Pulsar sobre un valor de la lista de seguimiento. 2 Modificar los campos necesarios. 3 Pulsar el botón ‘Guardar cambios’ Postcondición Se habrán guardado los límites asociados al valor seleccionado. Excepciones Paso Acción 2 Si alguno de los campos está vació o contiene caracteres no numéricos. E.1 Se resalta el campo afectado en color rojo indicando un error. 3 Si se intenta guardar con campos erróneos. E.1 Se muestra un mensaje de error y se vuelve a solicitar los datos. Comentarios Este caso de uso también aplica para configurar las referencias en la pantalla de configuración. Tabla 9 - CU-09 Configurar límites para el cálculo del Estado de Inversión 3.1.10 Eliminar acción o criptomoneda Figura 19 – CU-10 Eliminar acción o criptomoneda
Diseño de la Aplicación 50 CU-10 Eliminar acción o criptomoneda Precondición El administrador debe estar autenticado en la aplicación y haber seleccionado la pantalla de Seguimiento en la barra de navegación. Descripción Este caso de uso describe las acciones eliminar un determinado valor. Secuencia Paso Acción 1 Dejar pulsado un valor de la lista de seguimiento. 2 Pulsar el botón ‘Eliminar’ Postcondición Se habrán eliminado el valor seleccionado. Excepciones Ninguna. Comentarios Ninguno. Tabla 10 - CU-10 Eliminar acción o criptomoneda 3.1.11 Añadir nueva entrada de Blog Figura 20 - CU-11 Añadir nueva entrada de Blog
51 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CU-11 Añadir nueva entrada de Blog Precondición El administrador debe estar autenticado en la aplicación y haber seleccionado la pantalla de Blog en la barra de navegación. Descripción Este caso de uso describe las acciones añadir una nueva entrada de Blog. Secuencia Paso Acción 1 El administrador pulsa uno de los apartados disponibles en el Blog: Posts, Vídeos o Archivos. 2 Pulsa el botón ‘Añadir nueva publicación’ 3 Escribe los títulos o textos requeridos. 4 Pulsa el botón ‘Añadir imagen’, ‘Añadir vídeo o ‘Añadir archivo’ según corresponda y se selecciona el archivo. 5 Pulsa el botón ‘Publicar’ Postcondición Se habrá añadido una nueva entrada al Blog. Excepciones Paso Acción 5 Si falta algún campo por rellenar o no se ha seleccionado el archivo requerido. E.1 Se muestra un mensaje de error y se vuelve a solicitar los datos. Comentarios Ninguno. Tabla 11 - CU-11 Añadir nueva entrada de Blog 3.1.12 Modificar entrada de Blog Figura 21 - CU-12 Modificar entrada de Blog
Diseño de la Aplicación 52 CU-12 Modificar entrada de Blog Precondición El administrador debe estar autenticado en la aplicación, haber seleccionado la pantalla de Blog en la barra de navegación. Descripción Este caso de uso describe las acciones para modificar una entrada de Blog ya existente. Secuencia Paso Acción 1 El administrador pulsa uno de los apartados disponibles en el Blog: Posts, Vídeos o Archivos. 2 Deja pulsado sobre una publicación que se quiera modificar. 3 Modifica los campos necesarios. 4 Pulsa el botón ‘Guardar cambios’. Postcondición Se habrá añadido modificado la entrada de Blog seleccionada. Excepciones Paso Acción 4 Si falta algún campo por rellenar o no se ha seleccionado el archivo requerido. E.1 Se muestra un mensaje de error y se vuelve a solicitar los datos. Comentarios Ninguno. Tabla 12 - CU-12 Modificar entrada de Blog 3.1.13 Eliminar entrada de Blog Figura 22 - CU-13 Eliminar entrada de Blog
53 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CU-13 Eliminar entrada de Blog Precondición El administrador debe estar autenticado en la aplicación, haber seleccionado la pantalla de Blog en la barra de navegación. Descripción Este caso de uso describe las acciones para eliminar una entrada de Blog. Secuencia Paso Acción 1 El administrador pulsa uno de los apartados disponibles en el Blog: Posts, Vídeos o Archivos. 2 Deja pulsado sobre una publicación que se quiera modificar. 3 Pulsa el botón ‘Eliminar’. Postcondición Se habrá añadido eliminado la entrada de Blog seleccionada. Excepciones Ninguna. Comentarios Ninguno. Tabla 13 - CU-13 Eliminar entrada de Blog 3.1.14 Gestionar conversaciones del Chat de Consultas Figura 23 - CU-14 Gestionar conversaciones en el Chat de Consultas
Diseño de la Aplicación 54 CU-14 Gestionar conversaciones en el chat de Consultas Precondición El administrador debe estar autenticado en la aplicación, haber seleccionado la pantalla de Consultas en la barra de navegación. Descripción Este caso de uso describe las acciones para la gestión de chats por el administrador. Secuencia Paso Acción 1 El administrador pulsa uno de los apartados disponibles en el Blog: Todos, Pendientes o Archivados. 2 Deja pulsado sobre un usuario de la lista para abrir menú desplegable. 3 Pulsar el botón ‘Marcar como respondido’, ‘Marcar como pendiente’ o ‘Eliminar’. Postcondición La conversación se habrá clasificada como respondida o pendiente o se habrá eliminado, según corresponda. Excepciones Ninguna. Comentarios Ninguno. Tabla 14 - CU-14 Gestionar conversaciones en el Chat de Consultas 3.1.15 Configurar indicar de Estado de Inversión Figura 24 - CU-15 Configurar indicador de Estado de Inversión
55 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CU-15 Configurar indicador de Estado de Inversión Precondición El administrador debe estar autenticado en la aplicación y haber seleccionado la pantalla de Configuración en la barra de navegación. Descripción Este caso de uso describe las acciones configurar el color que indica el Estado de Inversión. Secuencia Paso Acción 1 Pulsar el botón ‘Configuración de semáforo’. 2 Pulsar uno de los botones que indican los estados. 3 Configurar y seleccionar color. 4 Pulsar el botón ‘Aceptar. 5 Pulsar el botón ‘Guardar cambios’. Postcondición Se habrán guardado los colores asociados a los diferentes estados. Excepciones Ninguna. Comentarios Ninguno. Tabla 15 - CU-15 Configurar indicador de Estado de Inversión 3.1.16 Eliminar usuario Figura 25 - CU-16 Eliminar usuario
Diseño de la Aplicación 56 CU-16 Eliminar usuario Precondición El administrador debe estar autenticado en la aplicación, haber seleccionado la pantalla de Configuración en la barra de navegación. Descripción Este caso de uso describe las acciones para eliminar usuarios. Secuencia Paso Acción 1 Pulsar el botón ‘Gestión de usuarios’. 2 Pulsa sobre un usuario de la lista para abrir información. 3 Pulsar el botón ‘Eliminar’ Postcondición Se habrá eliminado el usuario seleccionado. Excepciones Ninguna. Comentarios Ninguno. Tabla 16 - CU-16 Eliminar usuario 3.1.17 Crear nueva cuenta de administrador Figura 26 - CU-17 Crear nueva cuenta de administrador
57 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CU-17 Crear nuevas cuentas de administrador Precondición El administrador debe estar autenticado en la aplicación, haber seleccionado la pantalla de Configuración en la barra de navegación. Descripción Este caso de uso describe las acciones para crear nuevas cuentas de administrador. Secuencia Paso Acción 1 Pulsar el botón ‘Crear administrador’. 2 Introduce los datos solicitados en el formulario: alias, nombre, apellidos, correo electrónico y contraseña. 3 Pulsa el botón ‘Crear cuenta’. Postcondición El usuario quedará registrado en la aplicación y será devuelto a la pantalla de Inicio de Sesión para que pueda iniciar sesión. Excepciones Paso Acción 3 Si el alias o correo electrónico especificado ya estaban registrados en la aplicación. E.1 Devolverá un mensaje de error y volverá a solicitar los datos. Tabla 17 - CU-17 Crear nueva cuenta de administrador 3.2 Algoritmo de Cálculo de Inversión Uno de los pilares de esta aplicación es el cálculo del momento óptimo de inversión. Para ello se propone un algoritmo basado en los indicadores financieros RSI y STOCH. Este algoritmo diferencia siete estados posibles en los que una determinada acción o criptomoneda puede estar, indicando el momento de inversión de ese determinado valor. En la Figura 27 se recogen estos estados: Figura 27 - Estados y límites del algoritmo de cálculo de inversión
Desarrollo Frontend 64 64 El punto de inicio de la aplicación se encuentra en el fichero App.js. Las distintas pantallas que muestra la aplicación se organizan dentro del directorio screens. Cada pantalla se desarrolla en un fichero separado, en el que se define el código necesario para su funcionamiento. Para mostrar las diferentes vistas, se utiliza la biblioteca React Navigation, que permite la transición entre pantallas y gestionar el historial de navegación [16]. La aplicación también utiliza contextos [12] para mantener los datos relativos a la sesión accesibles desde todas las pantallas y componentes. Estos datos globales se gestionan mediante un Provider, que actúa como un contenedor de datos, distribuyendo esta información a través de los distintos componentes. En la siguiente figura se muestra una vista generalizada de los componentes del código frontend y cómo estos se relacionan entre sí: Figura 33 - Interrelación de los componentes del código frontend 4.1.1 Vistas y Componentes Tanto en el desarrollo en Android como en iOS, los elementos básicos de una interfaz de usuario son las “vistas” [17]. Estas permiten mostrar texto, imágenes, o responder a las interacciones de los usuarios. Con React Native se pueden invocar estas vistas con JavaScript mediante componentes de React. React Native incluye una serie de componentes predefinidos, como View, Test, Image, ScrollView o TextInput, que se respaldan en los componentes nativos de cada plataforma y que tienen apariencia nativa al ejecutarse la aplicación Android o iOS. Además de incluir estos componentes, React Native también permite crear componentes personalizados y hacer uso de ellos en distintas partes del código. Para esta aplicación se han desarrollados varios componentes personalizados. 4.1.1.1 Botones Estos botones combinan los componentes de React Native TouchableOpacity, que permite pulsar sobre el
65 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa componente y ejecutar funciones, y Text, que permite introducir un texto en este. El diseño en cuanto a forma, colores y dimensiones se fija en la definición del propio componente, tomando como parámetros modificables el texto del botón y la función a ejecutar al ser pulsado. Esto permite mantener un estilo uniforme en toda la aplicación. Figura 34 - Botones como componentes personalizados 4.1.1.2 Entradas de texto Este componente está basado en TextInput de React Native, permitiendo como parámetros modificables el Placeholder y la variable destino del texto introducido. Al igual que con los botones, con este componente se busca mantener un estilo uniforme en toda la aplicación. Figura 35 - Entrada de texto como componentes personalizados 4.1.1.3 Entrada de texto para Chat de Consultas Este componente se utiliza en el Chat de Consultas de la aplicación y consta de una entrada de texto para escribir un mensaje y un botón para enviarlo. Por ser una combinación de los componentes anteriores, se utilizan los mismos componentes de React Native ya mencionados: TextInput, TouchableOpacity y Text. Figura 36 - Entrada de texto con botón para chat de consultas 4.1.1.4 Globos de Chat de Consultas También en la pantalla del Chat de Consultas, para visualizar los mensajes compartidos en la conversación, se utiliza este componente personalizado que consta de TouchableOpacity y Text. En este componente se ha desarrollado una lógica que dependiendo del usuario que escribió el mensaje muestra un estilo u otro. Si el mensaje ha sido escrito por un administrador, este se mostrará en alineado en lado izquierdo de la pantalla y con color gris. En caso de que el mensaje haya sido escrito por un usuario, este se mostrará alineado a la derecha y en color azul. Un ejemplo se puede ver en la siguiente figura:
Desarrollo Frontend 66 66 Figura 37 - Globo de chat de consultas 4.1.1.5 Botón de “Favoritos” Este botón con forma de estrella se ha desarrollado para permitir marcar como favoritos las acciones o criptomonedas que el usuario quiera seguir de manera específica. El componente se compone de TouchableOpacity, para permitir ejecutar una función al ser pulsado, y un componente Image. Al pulsar el botón se envía una petición al servidor indicando que el usuario ha marcado o eliminado como favorito una determinada acción o criptomoneda, almacenándolo o eliminándolo en la base de datos. Mientras el usuario tenga marcado un valor como favorito la estrella se mostrará en gris oscuro, como se puede ver en la Figura 38. En caso contrario, se mostrará en blanco con el contorno en gris oscuro, como aparece en la Figura 39. Figura 38 - Botón de "Favoritos" marcado Figura 39 - Botón de "Favoritos" sin marcar 4.1.1.6 Indicador de Estado de Inversión En la pantalla de Seguimiento, junto al precio de la acción o criptomoneda, aparece un cuadro con un color que puede ir variando en función del estado de inversión en el que esté dicho valor. Este componente está compuesto de un TouchableOpacity con las dimensiones y formas que se pueden ver en la Figura 40. Como parámetro, este componente recibe el color, que se recibe desde el servidor según corresponda y que previamente ha debido ser configurado por el administrador en la pantalla de configuración.
67 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 40 - Indicador de Estado de Inversión 4.1.1.7 Selector de icono para Acciones y Criptomonedas Al añadir el administrador una nueva acción o criptomoneda para seguimiento se requiere una imagen o icono de dicho valor para ser mostrada en el detalle de este. Este componente está compuesto de TouchableOpacity y el componente de la biblioteca Ionicons, para mostrar iconos. Para ello se ha desarrollado este componente, que muestra un símbolo rojo con icono mientras no haya ninguna imagen seleccionada, como se puede ver en la Figura 41. Figura 41 - Selector de icono sin imagen seleccionada Al pulsar sobre dicho componente se abrirá el explorador de archivos para seleccionar una imagen. Si selecciona alguna imagen el componente cambiará a color verde y esta estará cargada en el formulario para enviarla al servidor.
Desarrollo Frontend 68 68 Figura 42 - Selector de icono con imagen seleccionada 4.1.1.8 Visor de icono para Acciones y Criptomonedas Una vez se haya validado el formulario anterior y se haya añadido una nueva acción criptomoneda, al pulsar sobre el valor en la pantalla de Seguimiento se abrirá un detalle de dicho valor mostrando la imagen que previamente fue seleccionada. Este componente está formado por View, actuando de contenedor, y WebView para cargar la imagen. Figura 43 - Icono de acción o criptomoneda en el detalle de la pantalla de Seguimiento 4.1.2 Pantallas El código correspondiente a cada pantalla está definido en ficheros, los cuales comparten una estructura similar. A continuación, se muestra el código en una versión simplificada del correspondiente a la pantalla de Inicio de Sesión de esta aplicación, que permite explicar esta estructura.
69 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa En primer lugar, se importan las bibliotecas y componentes que serán utilizados en esta pantalla, tanto los proporcionados por React Native, como los componentes personalizados, que se importan desde la carpeta import React, { useState } from 'react'; import { StyleSheet, Text, View } from 'react-native'; import TextInputApp from '../components/TextInputApp'; import ButtonApp from '../components/ButtonApp'; const Login = () => { const { login } = useAuth(); const[user, setUser] = useState('') const[password, setPassword] = useState('') const handlerequest = () => { if(user!='' && password!=''){ login(user, password) } } return( <View style={styles.container}> <Text style={styles.text}>¡Bienvenido!</Text> <TextInputApp ph='Usuario' val={user} setVal={setUser}/> <TextInputApp ph='Constraseña' val={password} setVal={setPassword}/> <ButtonApp title={'Iniciar sesión'} onPress={() => handlerequest()}/> </View> ); }; export default Login; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', }, text: { marginTop: 40, alignSelf: 'center', } });
Desarrollo Frontend 70 70 components. Desde el directorio assets también es posible importar otros recursos, como las imágenes utilizadas para el logotipo de la aplicación. Cabe destacar el uso de Hooks, que es una herramienta que permite utilizar estados y otras funcionalidades de React [18]. Concretamente son funciones que permiten acceder al estado y ciclo de vida de React desde los componentes de una función. Principalmente se ha hecho uso de useState y de useEffect: • useState se llama dentro de un componente para agregarle un estado local, que se conservará en nuevas renderizaciones. Devuelve el valor del estado actual y función para actualizarlo. En el siguiente ejemplo tenemos la variable num inicializada a 0 y la función setNum, que asignará nuevos valores a num, por ejemplo con setNum(num + 1), que incrementaría la variable en 1. • useEffect permite ejecutar código durante el ciclo de vida de un componente, generalmente al renderizar por primera vez una pantalla. En esta aplicación se utiliza, por ejemplo, para hacer una petición al servidor para inicializar datos en una pantalla. Esta función es declarada dentro de los componentes, por lo que tienen acceso a las propiedades y estados de este. A continuación de las importaciones se declara el componente, que define la pantalla. Al inicio de este se declaran los Hooks, para manejar estados y ejecutar el código necesario al montar la pantalla. También se declaran en este punto funciones, que permitan manejar las interacciones del usuario con la pantalla, haciendo peticiones al servidor o cambiando estados. La interfaz se define organizando los elementos jerárquicamente dentro de un contenedor principal View. Dentro de este contenedor van otros componentes, ya sean propios de React Native o personalizados, distribuidos según el diseño que se quiera tener en esta pantalla. En el código de ejemplo se añade una línea de texto, dos campos de entrada de texto y un botón. Por último, se define una hoja de estilos, similar a cómo se hace en CSS, para dar formato a los componentes de la pantalla. Estos estilos se definen utilizando StyleSheet y se asignan a cada componente con la propiedad style. El uso de esta hoja de estilos permite modificar características de los componentes como posición, dimensiones, bordes, colores o alineación. 4.1.3 Navegación Para la navegación entre las distintas pantallas, como ya se ha indicado anteriormente, se ha utilizado la biblioteca React Navigation. En esta aplicación se hace uso de Stack Navigator y de Bottoms Tabs Navigator. • Stack Navigator es una forma de ir cambiando de pantalla, de manera que cada nueva pantalla se posiciona en la parte superior de una pila, siendo esta pantalla, la que está en la parte superior, la que es const[num, setNum] = useState(0)
71 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa visible para el usuario [19]. Al volver atrás, la última pantalla se quita de la pila, dejando visible la que estaba inmediatamente por debajo. La transición entre pantallas se hace por defecto con la configuración nativa de la plataforma, sea Android o iOS. • Bottom Tabs Navigator consiste en una barra de pestañas en la parte inferior de la pantalla que permite ir cambiando entre diferentes rutas de la aplicación [20]. En la siguiente figura se muestra el Bottom Tab Navigator implementado en este proyecto. Los componentes de las pantallas no se montan hasta que el usuario le asigna el foco, es decir, hasta que selecciona la pestaña correspondiente. Figura 44 - Bottom Tabs Navigator Este navegador se ha personalizado para incluir iconos representativos utilizando la biblioteca Ionicons, así como los colores para adaptarlo al estilo de la aplicación. Esta configuración reemplaza el formato predeterminado que proporciona React Navigation. Toda la lógica que conforma la navegación de la aplicación está implementada en el fichero index.js dentro del directorio navigators. Mientras el usuario no esté autenticado, solo tiene acceso a la ventana de Inicio de Sesión y Registro. En el momento en el que este inicia sesión podrá tener acceso al resto de pantallas. Asimismo, se hace una distinción entre usuarios y administradores, donde estos últimos tienen acceso a pantallas con funcionalidades específicas para administrar la aplicación. 4.1.4 Red La comunicación con el servidor se establece mediante peticiones HTTPS y mediante WebSockets. 4.1.4.1 HTTPS Para las realizar peticiones HTTPS se utiliza la API Fetch de React Native. Esta herramienta permite enviar solicitudes indicando la URL a la que se quiere acceder [21]. También permite indicar el método, GET o POST en el caso de esta aplicación, así como cabeceras adicionales y cuerpo del mensaje, en caso de peticiones POST. Un ejemplo de uso se puede ver a continuación con la petición para obtener los valores favoritos de seguimiento de un usuario.
Desarrollo Frontend 72 72 En este ejemplo, se especifica la ruta del servidor indicando que se trata de una petición POST. La dirección IP del servidor está definida en un archivo de configuración y se toma como parámetro. Además, se añaden las cabeceras Authorization, indicando el JWT Token para poder acceder a los recursos, y Content-Type, especificando el tipo de datos que contiene la petición. En el cuerpo de la solicitud incluye el campo ‘alias’ en formato JSON, que indica el nombre del usuario. En la pantalla de Blog, las Imágenes y Documentos son renderizados utilizando el componente WebView, de la biblioteca react-native-webview. Los videos son renderizados utilizando el componente Video de la biblioteca expo-av. En ambos casos, la URL del servidor se indica en el atributo source de estos componentes, como se puede ver a continuación. 4.1.4.2 Websockets Para la comunicación mediante WebSockets se utiliza la biblioteca socket.io-client. En el contexto de la aplicación se inician dos conexiones, una para el obtener los datos relativos al seguimiento de los valores y otro para el chat. A través del Provider se dispondrá de estas conexiones en las pantallas correspondientes. const response = await fetch('https://'+ip+'/getFavourites', { method: 'POST', headers: { 'Authorization': `Bearer ${jwtToken}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ alias: authState.username, }), }); <WebView source={{uri: 'https://'+ip+'/getBlogImage/'+item[0], headers: {'Authorization': `Bearer ${jwtToken}`} }}/> <Video source={{uri: 'https://'+ip+'/getBlogVideo/'+item[0], headers: {'Authorization': `Bearer ${jwtToken}`} }} useNativeControls resizeMode="contain" style={styles.imageblog} /> const ws = io('wss://'+ip+'/stocks') const wsChat = io('wss://'+ip+'/chat')
73 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Tanto en la pantalla de Seguimiento como en la de Chat, se definen funciones para gestionar los eventos de estas conexiones, fundamentalmente para la recepción de mensajes. Cada vez que se reciba un mensaje se ejecuta el código que haya definido dentro de la función, actualizando las variables que almacenan el precio o estado de un valor, en la pantalla de Seguimiento, o actualizando la lista de mensajes en la pantalla de Consultas. 4.1.5 Notificaciones push La gestión de las notificaciones push se hace con la librería expo-notifications, implementando las funciones necesarias para manejar las notificaciones y configurando credenciales para Android e iOS [22]. Para configurar las notificaciones en el dispositivo se utiliza la siguiente función: async function registerForPushNotificationsAsync() { let token; const{status: existingStatus} = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== 'granted') { const {status} = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== 'granted') { alert('Error al activar las notificaciones'); return; } //ProjectId obtenido de Expo al crear nuevo proyecto const projectId = Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId; if (!projectId) { console.log('Project ID not found'); } token = (await Notifications.getExpoPushTokenAsync({ projectId ws.on('message', (data) => { // Código de la función });
Desarrollo Frontend 80 80 Figura 53 - Pantalla de Seguimiento Al pulsar sobre una fila se abrirá un detalle de ese valor, como se muestra en la Figura 54, en el que se muestra información adicional: fecha de cambio, cambio 1 minuto y porcentaje de cambio 1 minuto. También se muestra un icono representativo de ese determinado valor, que el administrador configuró previamente. Figura 54 - Detalle de un valor en la pantalla de Seguimiento
81 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa En la barra superior se implementa también un botón de información que al pulsarlo despliega una pantalla, la mostrada a continuación, indicando qué estado de inversión se corresponde con cada color mostrado. Figura 55 - Información del código de colores En la parte inferior de la pantalla, haciendo referencia a la Figura 53, se muestra un botón “Mostrar todo”, que al pulsarlo muestra la totalidad de valores que la aplicación pone a disposición del usuario para seguimiento. El diseño de esta pantalla, mostrado en la Figura 56, es similar a la anterior, sin embargo, en este caso se estará mostrando tanto los valores favoritos, como los que no. Si el usuario quisiera añadir otro valor a seguimiento tan solo tendría que pulsar el botón con forma de estrella para hacerlo. En esta pantalla, previsiblemente, habrá un gran número de valores. Para facilitar la consulta de estos se incluye un botón para filtrar por acciones o criptomonedas. El botón “Mostrar todo” indica que se están mostrando todos los valores sin filtrar. Al pulsarlo una vez, únicamente se mostrarán las acciones y al pulsarlo nuevamente, se mostrarán únicamente las criptomonedas. Si se vuelve a pulsar volverá al estado inicial.
Desarrollo Frontend 82 82 Figura 56 - Pantalla de Seguimiento general, filtrando por acciones o criptomonedas Para obtener el precio y el estado de inversión en tiempo real se establece una conexión con el servidor utilizando WebSockets. Se hace uso de la biblioteca socket.io-client. 4.2.2.2 Blog A través de la barra inferior de navegación, se accede a la pantalla de Blog. En esta se distinguen tres secciones, Posts, Videos y Archivos, entre las que es posible cambiar mediante el selector que aparece en las siguientes figuras. A diferencia de la barra de navegación inferior de React Navigation, este selector está implementado de manera que renderiza una u otra vista en función de lo que se seleccione dentro de la misma pantalla, sin hacer cambios en la pila de navegación. Por defecto se abre la sección de Posts, como se muestra en la Figura 57. El diseño de esta vista está hecho con un bloque FlatList, que contiene un componente Text a modo de título y otro a modo de cuerpo de la publicación, y un componente WebView para mostrar la imagen, todo ello dentro de un TouchableOpacity como contenedor. La utilización de FlatList, en lugar de otro componente similar como ScrollView, responde a una cuestión de eficiencia. FlatList renderiza los elementos a medida que se van mostrando por pantalla, mientras que ScrollView renderiza todos los elementos al abrir la pantalla.
83 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 57 - Blog, sección de Posts Al seleccionar la sección de Vídeos, mostrada en la siguiente Figura, obtenemos una vista similar a la anterior en la que se suprimido el texto. En este caso, dentro de FlatList tenemos un componente Video de la biblioteca expo-av. Este componente renderiza el video y ofrece controles para gestionar la reproducción.
Desarrollo Frontend 84 84 Figura 58 - Blog, sección de vídeo Por último, en la sección de Archivos, mostrada en la Figura 59, dentro del FlatList se tienen contenedores TouchableOpacity compuestos a su vez por un icono de Ionicons y un componente Text indicando el nombre del archivo. Para visualizar el archivo se despliega una ventana Modal en la que se renderiza el archivo dentro de un componente WebView. Utilizar WebView es la solución más extendida para la visualización de archivos en React Native, sin embargo, su comportamiento difiere de iOS a Android. En iOS el archivo se visualiza en la propia pantalla de la aplicación, mientras que en Android el archivo se descarga en el dispositivo y se podrá visualizar con el gestor de documentos del propio dispositivo.
85 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 59 - Blog, sección de archivos Por ello, antes de abrir la pantalla, al pulsar en uno de los elementos de la lista se abre una ventana emergente indicando que se va a descargar el archivo. Si el usuario decide continuar se mostrará el archivo o se descargará dependiendo de la plataforma.
Desarrollo Frontend 86 86 Figura 60 - Visualización de archivos en Android Figura 61 - Visualización de archivos en iOS
87 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 4.2.2.3 Consultas El chat de consultas está pensado para que el usuario pueda tener un medio de comunicación con los administradores de la aplicación. Al abrir la pantalla se descargan del servidor los mensajes asociados a la conversación del usuario ordenados temporalmente y se renderizan de arriba hacia abajo, donde los mensajes que está más arriba son más antiguos. Para mostrar los mensajes se vuelve a utilizar FlatList, haciendo uso de los componentes personalizados que se mencionaron en un punto anterior. Los globos que contienen los mensajes se muestran en azul y alineados hacia la derecha si el mensaje es del usuario y se muestran en gris y alineados hacia la izquierda si el mensaje es del administrador. Para escribir y enviar mensajes se utiliza también un componente personalizado, que combina una entrada de texto y un botón de envío. Para enviar y recibir los mensajes en tiempo real se establece una conexión con el servidor utilizando WebSockets. Se hace uso de la biblioteca socket.io-client. Figura 62 - Chat de consultas
Desarrollo Frontend 88 88 4.2.2.4 Perfil Al abrir la última pantalla, la de Perfil, encontramos el logotipo de la aplicación seguido del nombre y apellidos del usuario y de su alias, como se puede ver en la siguiente figura: Figura 63 - Pantalla de Perfil Además, esta pantalla dispone de botones que al pulsarlos abrirán otra pantalla para modificar los datos de usuario, mostrado en la Figura 64, y la contraseña, mostrada en la Figura 65.
89 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 64 - Modificar datos de usuario Figura 65 - Modificar contraseña Asimismo, en esta pantalla se implementa también un botón para cerrar sesión. Este cierre de sesión se hace modificando en el estado global de la sesión el campo authenticated a false. Al estar este campo en a false el componente de navegación nos devolverá a la pantalla de inicio de sesión.
Desarrollo Frontend 96 96 4.2.3.3 Consultas En la pantalla de Consultas, los administradores deben tener la posibilidad de gestionar conversaciones con múltiples usuarios. Por ello al abrir esta pantalla se muestra una lista con todos los usuarios que tienen alguna conversación abierta, como se muestra en la siguiente figura. Al seleccionar una de las conversaciones, se abrirá un chat similar al utilizado para los usuarios. Figura 76 - Pantalla de consultas para administradores Adicionalmente, se implementa la posibilidad de filtrar los chats mediante un selector en la parte superior de la pantalla, de manera similar a como se gestionaban las distintas secciones en la pestaña de Blog. Para clasificar los chats hay que dejar pulsado una de las conversaciones. Esto desplegará una pantalla Modal, con la opción de marcar como respondido o pendiente. También se da la opción de borrar la conversación. En la Figura 77 se muestra esta funcionalidad.
97 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 77 - Clasificación de conversaciones 4.2.3.4 Configuración En la pantalla de Configuración encontramos una serie de botones que permite modificar algunos parámetros de la aplicación. Figura 78 - Pantalla de Configuración para administradores
Desarrollo Frontend 98 98 En primer lugar, está el botón de ‘Configurar referencias’, que permite modificar los límites utilizados en el algoritmo de Cálculo del Estado de Inversión para los índices de referencia, que son NASDAQ y Bitcoin. Figura 79 - Configurar referencias Debajo está el botón de ‘Configuración de Semáforo’, que permite modificar el color del indicador de Estado de Inversión para cada estado. Al pulsar el botón se abrirá una pantalla con otra serie de botones, como se muestra en la Figura 80, cada uno con un estado diferente. Al pulsar en alguno de los estados se desplegará un Modal con un selector de colores de la librería react-native-color-picker. Para seleccionar el color es necesario desplazar el selector por la circunferencia exterior. Al pulsar el botón “Aceptar” se almacenará el código del color en una variable y se volverá a la pantalla anterior. Una vez que se hayan seleccionado los nuevos colores se deben validar los cambios pulsando sobre el botón de ‘Guardar cambios’.
99 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 80 - Configuración de semáforo El siguiente botón de la configuración es para la gestión de usuarios. Al pulsarlo se abrirá un listado de los usuarios registrados en la aplicación, como se puede ver en la Figura 81. Figura 81 - Configuración de usuarios
Desarrollo Frontend 100 100 Al seleccionar alguno de los usuarios de la lista, tendremos acceso a nueva pantalla con los datos de dicho usuario, como se muestra en la Figura 82. Desde esta pantalla se pueden modificar estos datos si fuese necesario o borrar la cuenta asociada a este usuario. Figura 82 - Modificar parámetros de usuario Debajo de la gestión de usuarios, está el botón para agregar un nuevo administrador. Al pulsar el botón se abrirá un formulario similar al de registro de usuarios que hay en la pantalla inicial, como aparece en la Figura 83. Sin embargo, el usuario añadido desde aquí será almacenado en la base de datos como administrador. Figura 83 - Crear nuevo perfil de administrador
101 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Después, está el botón de Perfil, que abre una pantalla para gestionar los datos del propio administrador. Esta pantalla es similar a la utilizada para los usuarios, como se muestra en la siguiente figura. Figura 84 - Perfil para administrador Por último, está el botón de “Cerrar sesión” que tiene una funcionalidad similar a la indicada en las vistas de usuarios.
Desarrollo Backend 102 102 5 DESARROLLO BACKEND n este capítulo se abordará en detalle el desarrollo backend de la aplicación, explicando el funcionamiento de los diferentes módulos que conforman el servidor, así como de los servicios externos utilizados por estos. Asimismo, se detallará el proceso y configuración de estos módulos para su despliegue utilizando Docker. El código del backend se encuentra disponible en el repositorio https://github.com/dffdez/rodeoserver 5.1 Aspectos generales El backend de la aplicación se compone de tres módulos dockerizados: • Servidor Python Flask, que contiene las rutas. • Base de Datos PostgreSQL, para persistir información. • Módulo ‘Engine’, que gestiona el cálculo del momento de inversión y la notificación a usuarios. En la siguiente figura se muestra una vista generalizada de los componentes del código backend y cómo estos se relacionan entre sí: Figura 85 - Interrelación de los componentes del código backend E
103 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 5.1.1 database_api.py Tanto el Servidor Python Flask como el módulo ‘Engine’ deben poder acceder a la base de datos y tener la capacidad de realizar operaciones CRUD sobre ella. Para tener una manera unificada y ordenada de hacerlo se ha implementado esta API. La API se conectan a la base de datos y ejecutan sentencias SQL de lectura (SELECT), inserción (INSERT), actualización (UPDATE) o borrado (DELETE) de datos, dependiendo de la función. Para esta implementación se ha utilizado Psycopg2, que es una librería ampliamente utilizada para la conexión de aplicaciones Python y bases de datos PostgreSQL. 5.2 Servidor El código principal del servidor se encuentra en el archivo server.py. Este archivo establece las URI o rutas que define como responderá el servidor a las solicitudes HTTP. Además, define los puntos donde se conectarán los Web Sockets. Cómo se indicó en el apartado de seguridad, las solicitudes al servidor están cifradas y para acceder a los recursos del servidor se requiere un token JWT. En la siguiente figura se muestra un detalle de los componentes que intervienen en la ejecución de este módulo: Figura 86 - Componentes que intervienen durante la ejecución del servidor Las URI definidas en el servidor se pueden dividir en varios bloques en función de su finalidad.
Desarrollo Backend 104 104 5.2.1 Inicio de Sesión y Registro URI Método Descripción /login POST Recibe un nombre de usuario y una contraseña, y comprueba que existe en la base de datos y si es administrador. Si está registrado devuelve un token de acceso JWT y, si además es administrador, devolverá el parámetro admin. /signup POST Recibe alias, nombre, apellido, correo electrónico y contraseña y lo almacena en la base de datos como un nuevo usuario. Si ya existiera un usuario con el mismo alias o correo electrónico, devolvería un error. /signupAdmin POST Recibe alias, nombre, apellido, correo electrónico y contraseña y lo almacena en la base de datos como un nuevo administrador. /setPushNotificationToken POST Almacena en la base de datos el token para las notificaciones push. /getPushNotificationToken GET Recupera de la base de datos el token para las notificaciones push. Tabla 18 - Rutas para Inicio de Sesión y Registro 5.2.2 Usuarios URI Método Descripción /getAllUser GET Devuelve el alias de todos los usuarios. /getUserInfo POST Recibe el alias de un usuario y devuelve la información asociada a este alias. /deleteUser POST Recibe el alias de un usuario y elimina la información asociada a este alias. /changePassword POST Recibe un alias y una contraseña, y modifica la contraseña asociada a ese alias. /changeUserData POST Recibe un alias, nombre, apellidos y correo electrónico, y modifica los datos asociados a ese alias. Tabla 19 - Rutas de Información de Usuario
105 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 5.2.3 Acciones y criptomonedas URI Método Descripción /getStocks GET Devuelve todos los valores de la base de datos. / getStocksFav POST Recibe un alias y devuelve todos los valores de la base de datos, indicando los favoritos para ese alias. / getStocksFavStocks POST Recibe un alias y devuelve todas las acciones de la base de datos, indicando los favoritos para ese alias. / getStocksFavCrypto POST Recibe un alias y devuelve todas las criptomonedas de la base de datos, indicando las favoritas para ese alias. / getFavourites POST Recibe un alias y devuelve todos los valores favoritos para ese alias. /setFavourite POST Recibe un alias y el símbolo de un valor y almacena este par en la base de datos como favorito. /deleteFavourite POST Recibe un alias y el símbolo de un valor y elimina este par en la base de datos como favorito. /verifySymbol POST Recibe el símbolo de una acción o criptomoneda y verifica que es correcto. /newStock POST Añade una nueva acción o criptomoneda a la base de datos. /newIconStock POST Recibe un icono de una determinada acción o criptomoneda y la almacena en el sistema de ficheros del servidor nombrándola con el símbolo de este valor. /getIconStock/<name> GET Recibe el símbolo de un valor y devuelve la imagen o icono asociado a este valor para mostrarlo en el detalle de la pantalla de Seguimiento. /deleteStock POST Recibe el símbolo de un valor y elimina la información asociada a este símbolo. /getLimits POST Recibe el símbolo de un valor y devuelve los límites para el cálculo del Estado de Inversión asociado a ese símbolo. /setLimits POST Recibe el símbolo de un valor y los límites para el cálculo del Estado de Inversión asociado a ese símbolo, y los almacena en la base de datos. /getLimitsRef POST Recibe el símbolo de una de las referencias y devuelve los límites para el cálculo del Estado de Inversión asociado a ese símbolo. /setLimitsRef POST Recibe el símbolo de una de las referencias y los límites para el cálculo del Estado de Inversión asociado a ese símbolo, y los almacena en la base de datos.
Desarrollo Backend 112 112 5.3.4 Límites y LímitesRef La relación Límites almacena los límites RSI, Stoch y Precio de cada valor en seguimiento para evaluar estado de inversión. LimitesRef tiene la misma estructura que Limites, pero almacena únicamente los valores utilizados como referencia para el algoritmo de Cálculo de Inversión, NASDAQ y Bitcoin. Atributo Tipo Descripción Símbolo VARCHAR(25) Caracteres que identifican a una acción o criptomoneda e_apx_rsi_min NUMERIC Valor mínimo RSI para estado Entrada Aproximación e_apx_rsi_max NUMERIC Valor máximo RSI para estado Entrada Aproximación e_apx_stoch_min NUMERIC Valor mínimo Stoch para estado Entrada Aproximación e_apx_stoch_max NUMERIC Valor máximo Stoch para estado Entrada Aproximación e_ent_rsi_min NUMERIC Valor mínimo RSI para estado Entrada e_ent_rsi_max NUMERIC Valor máximo RSI para estado Entrada e_ent_stoch_min NUMERIC Valor mínimo Stoch para estado Entrada e_ent_stoch_max NUMERIC Valor máximo Stoch para estado Entrada stp_apx_stoch_min NUMERIC Valor mínimo Stoch para estado Salida ‘Take Profit’ Aproximación stp_apx_stoch_max NUMERIC Valor máximo Stoch para estado Salida ‘Take Profit’ Aproximación stp_sal_stoch_min NUMERIC Valor mínimo Stoch para estado Salida ‘Take Profit’ ssl_apx_value_min NUMERIC Precio mínimo para estado Salida ‘Stop Loss’ Aproximación ssl_apx_value_max NUMERIC Precio máximo para estado Salida ‘Stop Loss’ Aproximación Tabla 26 - Tabla Limites y LimitesRef de la base de datos
113 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 5.3.5 Blog Esta relación almacena información de las publicaciones del Blog. Los archivos multimedia son almacenados en el sistema de ficheros del servidor, si bien, como nombre para identificar estos archivos se utiliza el título de la publicación. Atributo Tipo Descripción Título VARCHAR(50) Título de una publicación Artículo TEXT Texto de una publicación tipo ‘Post’ Fecha TIMESTAMP Fecha de publicación para orden temporal Tipo VARCHAR(10) Indica el tipo de publicación: Post, Video o Archivo Tabla 27 - Tabla Blog de la base de datos 5.3.6 Chat En esta relación se almacenan las conversaciones del chat de consultas. Atributo Tipo Descripción Alias VARCHAR Usuario al que están asociados los mensajes de la conversación Usuario VARCHAR Identifica si el mensaje es del usuario o del administrador Mensaje TEXT Texto que conforma el mensaje Fecha TIMESTAMP Fecha de envío del mensaje para orden temporal Estado VARCHAR Indica el estado en el que se encuentra la conversación: Pendiente (0) o Respondida (1) Tabla 28 - Tabla Chat de la base de datos
Desarrollo Backend 114 114 5.3.7 Semáforo Esta relación almacena el código de los colores asociados a cada estado. Por defecto esta tabla se inicializa con todos los estados en blanco (#fff), si bien el administrados puede cambiar estos colores en el apartado de configuración de semáforo. Atributo Tipo Descripción neutral VARCHAR(15) Código de color asociado al estado Neutral ent_apx VARCHAR(15) Código de color asociado al estado Entrada Aproximación ent_ent VARCHAR(15) Código de color asociado al estado Entrada sal_tp_apx VARCHAR(15) Código de color asociado al estado Salida ‘Take Profit’ Aproximación sal_tp_sal VARCHAR(15) Código de color asociado al estado Salida ‘Take Profit’ sal_sl_apx VARCHAR(15) Código de color asociado al estado Salida ‘Stop Loss’ Aproximación sal_sl_sal VARCHAR(15) Código de color asociado al estado Salida ‘Stop Loss’ Tabla 29 - Tabla Semáforo de la base de datos 5.4 Módulo ‘Engine’ El módulo ‘Engine’ se encarga de ejecutar el algoritmo de Estado de Inversión, realizando peticiones a la API de TwelveData para obtener información del mercado bursátil en tiempo real. Además, notifica a los usuarios sobre los cambios de estado de los valores, actualizando el código de colores en el panel de seguimiento de la aplicación, así como enviando notificaciones push, mediante Expo Push Notification Service. En la siguiente figura se muestran los componentes que intervienen durante la ejecución del módulo ‘Engine’:
115 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Figura 88 - Componentes que intervienen durante la ejecución del módulo 'Engine' 5.4.1 engine.py El código principal de este módulo se encuentra en el archivo engine.py. En primer lugar, realiza una consulta a la API TwelveData para obtener los valores RSI y Stoch 1 minuto y 5 minutos de los valores de referencia NASDAQ y Bitcoin. Estos datos se pasan a la función checkRefLimits y comprueba que estos valores se encuentran dentro de los límites definidos en la base de datos. Esta función devuelve ‘ENT’ si está en estado de Entrada, ‘ENTAPX’ si está en estado de Entrada Aproximación o ‘0’ en otro caso. A continuación, se obtienen todos los valores almacenados en la base de datos y por cada valor se realiza una petición a la API de TwelveData para obtener los valores RSI y Stoch 1 minuto y 5 minutos, así como el precio, la fecha de cambio, el cambio y el porcentaje de cambio. Estos datos se pasan a la función checkLimits y comprueba que estos valores se encuentran dentro de los límites definidos en la base de datos. Esta función devuelve: • ‘0’, si está en estado Neutro. • ‘ENTAPX’, si está en estado de Entrada Aproximación. • ‘ENT’, si está en estado de Entrada. • ‘STPAPX’, si está en estado de Salida ‘Take Profit’ Aproximación • ‘STP’, si está en estado de Salida ‘Take Profit’
Desarrollo Backend 116 116 • ‘SSLAPX’, si está en estado de Salida ‘Stop Loss’ Aproximación • ‘SSL’, si está en estado de Salida ‘Stop Loss’ • ‘00’, si está en tiempo de espera para nuevo comienzo. Los valores mencionados son almacenados en la base de datos al producirse un cambio de estado y es este valor almacenado el que se envía a la interfaz periódicamente para mantener el estado actualizado. Mientras no se produzca otro cambio de estado se estará enviando el mismo, que se mostrará en el panel de seguimiento de la aplicación mediante un código de colores. Además, cuando se produce un cambio de estado, la función devuelve el nuevo estado, que se utiliza para la notificación al usuario mediante notificaciones push. Estos resultados se presentan en formato JSON mediante el uso de las funciones jsonMaker y jsonMakerFront, Los resultados obtenidos se envían por un lado a la interfaz, mediante Web Sockets, y por otro a la función que gestiona las notificaciones push. El resultado de estas funciones se va almacenando en un diccionario en el que las claves son los símbolos de cada acción o criptomoneda. def jsonMaker(price, state): response = { "price": price, "state": state } return response def jsonMakerFront(price, state, datetime, change, percent_change): response = { "price": price, "state": state, "datetime": datetime, "change": change, "percent_change": percent_change, } return response
117 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 5.4.2 notificationManager.py Este archivo contiene una función homónima que recibe como parámetro el diccionario anteriormente mencionado. Este diccionario solo contiene los valores que hayan cambiado de estado. Se comprueban qué usuarios están suscritos a los valores que contiene el diccionario y se le envía una notificación haciendo uso de la función send_push_message, de la librería exponent_server_sdk. La notificación tiene como título el estado de inversión y como cuerpo el símbolo de la acción. La función send_push_message recibe el token que identifica el dispositivo del usuario y el mensaje a enviar. También permite configurar el sonido de la notificación, que se ha indicado el que esté por defecto en el sistema. Esta función envía estos parámetros al Expo Push Notification Server que gestiona el envío de la notificación, cómo se indicó en el apartado 2.2.4 de este documento. 5.5 Docker Para el despliegue de estos módulos del backend se ha utilizado Docker, separando cada uno en un contenedor independiente. Esto permite mayor modularidad y facilita el mantenimiento del sistema. Cada componente se ejecuta de manera aislada dentro de su contenedor. La comunicación entre ellos se realiza a través de la red interna de Docker, configurada en el archivo de configuración docker-compose.yml. El contenido de este archivo se puede consultar en el Anexo D. 5.5.1 Dockerfile Un Dockerfile es un archivo de texto que contiene instrucciones para construir la imagen de un contenedor [24]. En el Anexo D de este documento se encuentran los Dockerfiles utilizados. En el caso del servidor y el módulo ‘Engine’ se utiliza como base la imagen python:3.9-slim, que proporciona un entorno inicial con Python preinstalado. Para la base de datos se utiliza la imagen postgresql:17.0-alpine3.20, una versión de PostgreSQL basada en Alpine Linux. Una vez definida la imagen base, se copian los archivos del proyecto a cada contenedor, se instalan las dependencias necesarias y se indica el comando que se ejecutará al iniciar el contenedor, con la orden CMD. En el caso del servidor, el comando utilizando inicia el servidor Flask utilizando Gunicorn como servidor WSGI. También se configura el worker eventlet para habilitar soporte de WebSockets. Además, el comando indica el archivo de certificado SSL y su clave privada utilizado para habilitar HTTPS. Para la base de datos, se incluye en el contenedor el archivo con las órdenes SQL indicado en el Anexo C, que contiene las órdenes para crear las tablas requeridas por la aplicación. Este archivo se ejecuta automáticamente la primera vez que se inicia el contenedor, configurando la base de datos. 5.5.2 Docker-compose El archivo docker-compose.yml reúne la configuración necesaria para iniciar los contenedores, asignando a cada uno un nombre e indicando la imagen asociada.
Desarrollo Backend 118 118 En el caso del servidor es importante destacar que se mapea el puerto 5000 del contenedor, que es donde está el servidor, al puerto 443 del host que es a dónde irán dirigidas las peticiones externas. También se configuran los volúmenes asociados a la base de datos y al guardado de archivos multimedia del servidor. El uso de volúmenes permite persistir la información incluso si el contenedor se borra o se detiene. 5.5.3 Red La comunicación entre los diferentes módulos se hace a través de la red de Docker [25], facilitando la que los servicios se conecten entre sí utilizando nombres de servicios en lugar de direcciones IP. Los nombres de los servicios definidos en el archivo docker-compose, se convierten en el nombre de los hosts accesibles dentro de la red. Docker incluye un sistema DNS que resuelve los nombres de los servicios a sus direcciones IP. En cuanto a la configuración de puertos, cada contenedor puede exponer los puertos necesarios para tener visibilidad dentro de la red interna de Docker. En el caso del servidor, se expondría el puerto 5000, mientras que la base de datos expondría el puerto 5432.
119 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 6 PRUEBAS DE FUNCIONAMIENTO i bien gran parte de las funcionalidades de la aplicación se han mostrado en el apartado de ‘Desarrollo Frontend’, en este punto se hará un repaso de las principales funcionalidades para el usuario y administrador, mostrando la disponibilidad en Android y iOS. 6.1 Seguimiento 6.1.1 Panel de seguimiento Figura 89 - Panel de seguimiento en Android Figura 90 - Panel de seguimiento de iOS S
Pruebas de Funcionamiento 120 120 6.1.2 Configuración de referencias Figura 91 - Configuración de referencias en Android Figura 92 - Configuración de referencias en iOS 6.1.3 Notificación de cambio de Estado de Inversión Figura 93 - Notificaciones en Android Figura 94 - Notificaciones en iOS
121 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa 6.2 Blog 6.2.1 Posts Figura 95 - Posts en Android Figura 96 - Posts en iOS 6.2.2 Videos Figura 97 - Vídeos en Android Figura 98 - Vídeos en iOS
Anexo A: Instalación y Puesta en Marcha 128 128 ANEXO A: INSTALACIÓN Y PUESTA EN MARCHA En este punto se explican los pasos para la instalación y pruebas de la aplicación, tanto en dispositivos Android como iOS. También se explicarán los pasos para el despliegue del servidor. Repositorios El código de este proyecto se encuentra disponible en los siguientes repositorios: • Frontend: https://github.com/dffdez/rodeo • Backend: https://github.com/dffdez/rodeoserver iOS Durante el desarrollo del proyecto, para la instalación y pruebas de la aplicación, se ha estado utilizando la aplicación Expo Go en un dispositivo Apple iPhone con sistema operativo iOS 17. El primer paso para probar la aplicación es abrir el directorio donde está el código de la aplicación y arrancar el servidor de desarrollo de Expo con el comando npm start. Esto muestra la siguiente salida: Figura 111 - Ejecución de la aplicación con npm start
129 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa Escaneando el código QR con el dispositivo, se abrirá la aplicación Expo Go, que previamente ha debido ser instalada, mostrando la aplicación desarrollada en el proyecto y pudiendo acceder a toda su funcionalidad. Figura 112 - Menú de Expo Go Figura 113 - Pantalla de inicio de la aplicación en iOS Expo Go puede requerir adicionalmente, para su utilización en dispositivos físicos, tener actualizada la última versión del SDK en el proyecto. Si la versión del SDK del proyecto es más antigua, para utilizar la aplicación con Expo Go será necesario utilizar un emulador de dispositivo iOS y la versión de Expo Go compatible con el SDK. Android Para las pruebas se ha estado utilizando el Emulador de Android con un dispositivo Pixel 5, haciendo uso igualmente de la aplicación Expo Go. Si bien, también se ha generado un APK de la aplicación para poder compartirla. Para generar el APK se hace uso de EAS Build, un servicio de Expo para generar binarios de los proyectos Expo y React Native, permitiendo enviar la aplicación a Google Play o a la App Store, o como es el caso de este proyecto, instalar la aplicación directamente en un dispositivo físico o emulador Android. Para ello, en el directorio del proyecto hay que instalar la última versión de EAS CLI con el comando npm install -g eas-cli. Una vez hecho esto, con el comando eas login hay que iniciar sesión en la cuenta de Expo, que ha debido ser previamente creada. Para configurar el proyecto se ejecuta el comando eas build:configure. Esto crea el fichero eas.json que debe indicar que la compilación creará un apk, dentro de build > preview > Android > buildType.
Anexo A: Instalación y Puesta en Marcha 130 130 { "cli": { "version": ">= 12.6.2", "appVersionSource": "remote" }, "build": { "development": { "developmentClient": true, "distribution": "internal" }, "preview": { "android": { "buildType": "apk" } }, "production": {} }, "submit": { "production": {} } } Una vez configurado el anterior archivo, se debe ejecutar el comando eas build -p android --profile preview, que iniciará la compilación en el servidor de Expo. Cuando la compilación finaliza, el archivo .APK está disponible para su descarga e instalación. El archivo está disponible desde un enlace facilitado al terminar la compilación o bien desde la web de Expo autenticándose con el usuario. Servidor Durante el desarrollo del proyecto las pruebas del servidor se han hecho en un entorno de desarrollo en local. Una vez finalizado el desarrollo se ha desplegado utilizando Docker en un equipo del Laboratorio de Telemática, con un sistema operativo Ubuntu 18.04. Para la compilación del servidor se utilizan el script make.sh, cuyo contenido es el mostrado a continuación. #! /bin/bash rm -rf ../exports mkdir -p ../exports/ mkdir -p ../exports/dockerImages docker build -t "rodeo_server" -f "Docker/Server/Dockerfile" ../ docker build -t "rodeo_engine" -f "Docker/Engine/Dockerfile" ../ docker save -o "../exports/dockerImages/server" "rodeo_server" docker save -o "../exports/dockerImages/engine" "rodeo_engine"
131 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa cp -r ../code/Database ../exports cp install.sh ../exports/ cp docker-compose.yml ../exports/ mkdir -p ../install/ tar -cvzf ../install/rodeoserver.tar.gz ../exports/* Este script crea las imágenes utilizando los Dockerfile y las guarda en la carpeta exports, donde además se guardan todos los archivos necesarios para la instalación. Dentro de la carpeta exports se encuentra el script install.sh, que carga las imágenes e inicia los servicios con docker compose up -d. Tan solo hay que ejecutar este script para poner en marcha el servidor. #! /bin/bash docker image load -i dockerImages/engine docker image load -i dockerImages/server docker compose up -d Para poder desplegar el servidor es necesario tener instalado Docker en el equipo, tanto en el que se realice la compilación como en el que se realice el despliegue. Para ello se sigue los pasos indicados en la web de Docker.
Anexo B: API TwelveData 132 132 ANEXO B: API TWELVEDATA El resultado de las peticiones realizadas a la API TwelveData, siguiendo la acción de ejemplo ‘AAPL, Apple’ son: - Indicador RSI en intervalo de 1 minuto y 5 minutos: { "meta":{ "symbol": "AAPL", "interval": "1min", "currency": "USD", "exchange_timezone": "America/New_York", "exchange": "NYSE", "mic_code": "XNYS", "type": "Common Stock", "indicator": { "name": "RSI - Relative Strength Index", "series_type": "close", "time_period": 14 } }, "values":[ { "datetime":"2019-08-09 15:59:00", "rsi":"16.57887" } ], "status":"ok" }
133 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa - Indicador STOCH en intervalo de 1 minuto y 5 minutos: - Precio en tiempo real: { "meta":{ "symbol": "AAPL", "interval": "1min", "currency": "USD", "exchange_timezone": "America/New_York", "exchange": "NYSE", "mic_code": "XNYS", "type": "Common Stock", "indicator": { "name": "STOCH - Stochastic Oscillator", "fast_k_period": 14, "slow_d_period": 3, "slow_dma_type": "SMA", "slow_k_period": 1, "slow_kma_type": "SMA" } }, "values":[ { "datetime":"2019-08-09 15:59:00", "slow_k":"11.35168", "slow_d":"7.5293" } ], "status":"ok" } { "price": "200.99001" }
Anexo B: API TwelveData 134 134 - Información general: { "symbol": "AAPL", "name": "Apple Inc", "exchange": "NASDAQ", "mic_code": "XNAS", "currency": "USD", "datetime": "2021-09-16", "timestamp": 1631772000, "open": "148.44000", "high": "148.96840", "low": "147.22099", "close": "148.85001", "volume": "67903927", "previous_close": "149.09000", "change": "-0.23999", "percent_change": "-0.16097", "average_volume": "83571571", "rolling_1d_change": "123.123", "rolling_7d_change": "123.123", "rolling_period_change": "123.123" "is_market_open": false, "fifty_two_week": { "low": "103.10000", "high": "157.25999", "low_change": "45.75001", "high_change": "-8.40999", "low_change_percent": "44.37440", "high_change_percent": "-5.34782", "range": "103.099998 - 157.259995" }, "extended_change": "0.09", "extended_percent_change": "0.05", "extended_price": "125.22", "extended_timestamp": 1649845281 }
135 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa ANEXO C: INICIALIZACIÓN DE BASE DE DATOS CREATE TABLE USUARIOS ( Alias VARCHAR(20) NOT NULL UNIQUE, Contrasenia VARCHAR(20) NOT NULL, Nombre VARCHAR(20) NOT NULL, Apellido VARCHAR(20) NOT NULL, Email VARCHAR(25) NOT NULL UNIQUE, Admin BOOLEAN DEFAULT FALSE, NotificationToken TEXT, PRIMARY KEY(Alias) ); CREATE TABLE VALORES ( Simbolo VARCHAR(25) NOT NULL, Nombre VARCHAR(25) NOT NULL, AC VARCHAR(5) NOT NULL, Estado VARCHAR(10) NOT NULL DEFAULT '0', ValorEntrada NUMERIC NOT NULL DEFAULT 0, TiempoSalida NUMERIC NOT NULL DEFAULT 0, PRIMARY KEY(Simbolo) ); CREATE TABLE VALORESREF ( Simbolo VARCHAR(25) NOT NULL, Nombre VARCHAR(25) NOT NULL, AC VARCHAR(5) NOT NULL, Estado VARCHAR(10) NOT NULL DEFAULT '0', ValorEntrada NUMERIC NOT NULL DEFAULT 0, TiempoSalida NUMERIC NOT NULL DEFAULT 0, PRIMARY KEY(Simbolo) ); CREATE TABLE FAVORITOS ( Simbolo VARCHAR(25) NOT NULL, Alias VARCHAR(20) NOT NULL );
Anexo C: Inicialización de Base de Datos 136 136 CREATE TABLE LIMITES ( Simbolo VARCHAR(25) NOT NULL, e_apx_rsi_min NUMERIC NOT NULL DEFAULT 0, e_apx_rsi_max NUMERIC NOT NULL DEFAULT 0, e_apx_stoch_min NUMERIC NOT NULL DEFAULT 0, e_apx_stoch_max NUMERIC NOT NULL DEFAULT 0, e_ent_rsi_min NUMERIC NOT NULL DEFAULT 0, e_ent_rsi_max NUMERIC NOT NULL DEFAULT 0, e_ent_stoch_min NUMERIC NOT NULL DEFAULT 0, e_ent_stoch_max NUMERIC NOT NULL DEFAULT 0, stp_apx_stoch_min NUMERIC NOT NULL DEFAULT 0, stp_apx_stoch_max NUMERIC NOT NULL DEFAULT 0, stp_sal_stoch_min NUMERIC NOT NULL DEFAULT 0, ssl_apx_value_min NUMERIC NOT NULL DEFAULT 0, ssl_apx_value_max NUMERIC NOT NULL DEFAULT 0, ssl_sal_value_min NUMERIC NOT NULL DEFAULT 0, PRIMARY KEY(Simbolo) ); CREATE TABLE LIMITESREF ( Simbolo VARCHAR(25) NOT NULL, e_apx_rsi_min NUMERIC NOT NULL DEFAULT 0, e_apx_rsi_max NUMERIC NOT NULL DEFAULT 0, e_apx_stoch_min NUMERIC NOT NULL DEFAULT 0, e_apx_stoch_max NUMERIC NOT NULL DEFAULT 0, e_ent_rsi_min NUMERIC NOT NULL DEFAULT 0, e_ent_rsi_max NUMERIC NOT NULL DEFAULT 0, e_ent_stoch_min NUMERIC NOT NULL DEFAULT 0, e_ent_stoch_max NUMERIC NOT NULL DEFAULT 0, stp_apx_stoch_min NUMERIC NOT NULL DEFAULT 0, stp_apx_stoch_max NUMERIC NOT NULL DEFAULT 0, stp_sal_stoch_min NUMERIC NOT NULL DEFAULT 0, ssl_apx_value_min NUMERIC NOT NULL DEFAULT 0, ssl_apx_value_max NUMERIC NOT NULL DEFAULT 0, ssl_sal_value_min NUMERIC NOT NULL DEFAULT 0, PRIMARY KEY(Simbolo) ); CREATE TABLE BLOG ( Titulo VARCHAR(50) NOT NULL, Articulo TEXT, Fecha TIMESTAMP, Tipo VARCHAR(10) NOT NULL DEFAULT 'post', PRIMARY KEY(Titulo) );
137 Desarrollo de una aplicación móvil para el seguimiento eficiente de movimientos en bolsa CREATE TABLE CHAT ( Alias VARCHAR(15) NOT NULL, Usuario VARCHAR(10) NOT NULL, Mensaje TEXT NOT NULL, Fecha TIMESTAMP, Estado VARCHAR(10) NOT NULL DEFAULT '0' ); CREATE TABLE SEMAFORO ( neutral VARCHAR(15) NOT NULL, ent_apx VARCHAR(15) NOT NULL, ent_ent VARCHAR(15) NOT NULL, sal_tp_apx VARCHAR(15) NOT NULL, sal_tp_sal VARCHAR(15) NOT NULL, sal_sl_apx VARCHAR(15) NOT NULL, sal_sl_sal VARCHAR(15) NOT NULL ); INSERT INTO SEMAFORO (neutral, ent_apx, ent_ent, sal_tp_apx, sal_tp_sal, sal_sl_apx, sal_sl_sal) VALUES ('#fff', '#fff', '#fff', '#fff', '#fff', '#fff', '#fff'); INSERT INTO USUARIOS (Alias, Contrasenia, Nombre, Apellido, Email, Admin) VALUES ('admin', 'admin', 'admin', 'admin', '
[email protected]', TRUE); INSERT INTO VALORESREF (Simbolo, Nombre, Estado, AC) VALUES ('NDAQ', 'NASDAQ', DEFAULT, 'A'); INSERT INTO VALORESREF (Simbolo, Nombre, Estado, AC) VALUES ('BTC', 'Bitcoin', DEFAULT, 'C'); INSERT INTO LIMITESREF (Simbolo) VALUES ('NDAQ'); INSERT INTO LIMITESREF (Simbolo) VALUES ('BTC');