Este tutorial adapta pedagógicamente el Día 36. Las secciones 📝 Ejercicio original del curso provienen de los archivos del curso. Los retos 🟢🟡🟠🔴, el proyecto extra y el proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
Nota sobre las verificaciones: con Python 3.14,
requests2.34 yrequests-cachese comprobó, el 26 de septiembre de 2026: la estructura de Alpha Vantage con su clave de demostración (demo, solo para el símbolo IBM), la respuesta de News API sin clave (error 401) y la API abierta de la TRM en datos.gov.co. No se usaron claves personales de Alpha Vantage, News API ni Twilio. Los proyectos iniciales (normal, difícil y muy difícil) no están en la carpeta.
💰 Nota ética y financiera (adaptación para el aula): este proyecto es un ejercicio de programación con datos, no una recomendación para invertir. Operar en la bolsa exige, en general, ser mayor de edad y entender que se puede perder dinero. Además, que una noticia aparezca el mismo día que una subida no demuestra que la noticia la haya causado (correlación no es causalidad).
Tabla de contenidos
- Antes de empezar: una "terminal Bloomberg" casera
- Elige tu destino y cuida tu cuota de peticiones
- Paso 1: detectar un movimiento grande del precio
- Paso 2: traer las noticias
- Paso 3: armar y enviar los mensajes
- 🚀 Proyecto del día: la Alerta de Noticias de Acciones
- 🌟 Proyecto extra: la Alerta de la TRM
- 🏆 Proyecto integrador de los Días 33 a 36: el Boletín Matutino Automático
- 🧩 Comprueba lo aprendido
- 🤖 Programar con apoyo de IA
- 🛠️ Correcciones técnicas al material original
- 📋 Matriz de trazabilidad
- 📦 Evidencias de aprendizaje del Día 36
0. Antes de empezar: una "terminal Bloomberg" casera
(Fuente: 277 - Day 36 Goals- what you will make by the end of the day.md)
Los operadores profesionales de bolsa usan pantallas como la terminal Bloomberg: precios en vivo, noticias de las empresas y alertas. Según la profesora, cuesta unos 24 000 dólares al año. Hoy construiremos una versión muy sencilla con Python.
Conceptos de bolsa que necesitas (del curso):
- Una acción es una pequeña parte de una empresa. Su precio cambia durante el día.
- El mercado NASDAQ abre a las 9:30 a. m. y cierra a las 4:00 p. m., hora de Nueva York. El precio de cierre es el precio al final del día.
- Las acciones se identifican con un símbolo corto:
TSLA(Tesla),SNAP(Snapchat),IBM.
Cómo funcionará el programa (el plan del curso):
Precio de cierre de AYER ──┐
├─► ¿cambió más de X %? ── no ──► fin
Precio de cierre de │ │
ANTEAYER ──────────────────┘ sí
▼
Traer 3 noticias sobre la empresa
▼
Enviar un mensaje por noticia (SMS)El ejemplo del curso: si ayer una acción cerró en 1000 dólares y anteayer en 900, subió 100 dólares. Si el cambio supera el umbral que tú eliges (por ejemplo, 5 % o 10 %), quieres saber por qué, y por eso buscas noticias.
Este proyecto usa tres APIs: Alpha Vantage (precios), News API (noticias) y Twilio (mensajes). La profesora pide dedicarle al menos 30 a 45 minutos antes de ver la solución, y sobre todo leer la documentación por tu cuenta: "Hay millones de APIs; para tus propios proyectos tendrás que hacer este proceso".
Prerequisito general: APIs, parámetros y claves (Días 33 a 35); comprensión de listas (Día 26); slicing de listas (Día 21); diccionarios y el método
items();abs()yround(); Twilio o correo (Días 32 y 35); variables de entorno (Día 35).
1. Elige tu destino y cuida tu cuota de peticiones
(Fuente: 278-choose-your-destiny.md)
📝 Contenido original del curso
Como en el Día 32, hay tres proyectos iniciales: Normal (muchas pistas en comentarios TODO), Difícil y Muy difícil. Los videos de solución siguen el nivel Normal. Anota qué nivel elegiste.
Consejo de la lección: usar la biblioteca requests-cache para no gastar las peticiones permitidas mientras pruebas.
📖 ¿Qué es una caché y por qué la necesitas hoy?
Las APIs gratuitas limitan cuántas peticiones puedes hacer (por día o por minuto). Mientras desarrollas, ejecutas el programa decenas de veces, y cada ejecución gasta peticiones aunque los datos no hayan cambiado.
Una caché guarda la respuesta la primera vez; las siguientes veces la devuelve guardada sin ir a internet:
import requests_cache
session = requests_cache.CachedSession("cache_bolsa", expire_after=3600) # 1 hora
response = session.get(STOCK_ENDPOINT, params=stock_params)
print(response.from_cache) # False la primera vez, True las siguientesPrueba de esta adaptación (verificada): la primera petición tardó 0,735 s (from_cache=False) y la segunda, 0,004 s (from_cache=True), con los mismos datos.
⚠️ Mientras la caché esté activa, no verás datos nuevos hasta que expire. Úsala durante el desarrollo y desactívala (o reduce
expire_after) en la versión final.
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: instala
requests-cachey repite el experimento de tiempos con cualquier API del Día 33. - 🟡 Reto 2: ¿dónde guarda
requests-cachelas respuestas? Busca el archivo que se creó en tu proyecto. - 🟠 Reto 3: ¿qué valor de
expire_aftertiene sentido para precios de cierre diarios? ¿Y para la posición de la ISS? Justifica. - 🔴 Reto 4: consulta en la documentación de Alpha Vantage y de News API cuántas peticiones permite su plan gratuito. Calcula cuántas veces al día podrías ejecutar tu programa sin caché.
2. Paso 1: detectar un movimiento grande del precio
(Fuente: 279 - Solution & Walkthrough for Step 1 - Check for Stock Price Movements.md)
🎯 Objetivo de aprendizaje
- Leer una API con claves de JSON poco comunes.
- Convertir un diccionario en lista con una comprensión de listas.
- Calcular una diferencia porcentual.
📝 Ejercicio original del curso (tareas TODO 1 a 5)
- Obtener el precio de cierre de ayer con Alpha Vantage.
- Obtener el precio de cierre de anteayer.
- Calcular la diferencia positiva entre ambos (pista:
abs). - Calcular la diferencia porcentual.
- Si es mayor que 5 %, imprimir "Get News".
La clave de API: se obtiene gratis en alphavantage.co (se puede elegir "estudiante"). El curso aconseja copiarla de inmediato en el proyecto, porque es difícil volver a esa página.
🔍 Antes de programar
- Busca en la documentación la función de datos diarios. ¿Qué parámetros son obligatorios?
- Si los datos llegan como un diccionario cuyas claves son fechas, ¿cómo obtienes "el más reciente" sin escribir la fecha a mano?
🔎 La solución del curso, paso a paso
Parámetros y petición:
STOCK_NAME = "TSLA"
STOCK_ENDPOINT = "https://www.alphavantage.co/query"
stock_params = {
"function": "TIME_SERIES_DAILY",
"symbol": STOCK_NAME,
"apikey": STOCK_API_KEY,
}
response = requests.get(STOCK_ENDPOINT, params=stock_params)
data = response.json()["Time Series (Daily)"]La forma de los datos (respuesta real con la clave demo para IBM, 26/09/2026):
{
"Meta Data": {...},
"Time Series (Daily)": {
"2026-09-25": {"1. open": "226.1500", "2. high": "228.9900", "3. low": "225.1900",
"4. close": "225.5100", "5. volume": "4147449"},
"2026-09-24": {...},
...
}
}- Las claves tienen espacios, paréntesis, números y puntos:
"Time Series (Daily)","4. close". La profesora dice que no es común y recomienda copiarlas de la respuesta para no equivocarse. "Time Series (Daily)"no es una lista: es un diccionario cuyas claves son fechas, de la más reciente a la más antigua (verificado).
De diccionario a lista. Escribir data["2026-09-25"] funcionaría solo hoy: mañana la fecha cambia. Por eso el curso convierte los valores en una lista:
data_list = [value for (key, value) in data.items()]
yesterday_data = data_list[0]
yesterday_closing_price = yesterday_data["4. close"]
day_before_yesterday_data = data_list[1]
day_before_yesterday_closing_price = day_before_yesterday_data["4. close"]Diferencia y porcentaje:
difference = abs(float(yesterday_closing_price) - float(day_before_yesterday_closing_price))
diff_percent = (difference / float(yesterday_closing_price)) * 100
if diff_percent > 5:
print("Get News")- Los precios llegan como texto (
"225.5100"): restarlos directamente produceTypeError: unsupported operand type(s) for -: 'str' and 'str'. Se convierten confloat. abs()quita el signo: interesa el tamaño del cambio, suba o baje.- Para probar: Tesla rara vez cambia más de 5 % en un día. El curso baja el umbral temporalmente (a 4 en su caso) para que la condición se cumpla y poder seguir.
🛠️ Nota técnica (el porcentaje): el curso divide la diferencia entre el precio de ayer. La forma habitual de expresar "cuánto cambió" es dividir entre el valor anterior (anteayer). Con los números del video (1568 y 1643, diferencia de 75): el curso obtiene 4,78 %; con el precio anterior, 4,56 % (ambos verificados). Con umbrales como 5 %, esa diferencia puede decidir si llega la alerta. Elige una fórmula y documenta cuál usas.
💡 Análisis (fines de semana): usar posiciones (
[0]y[1]) en lugar de restar días al calendario es una ventaja: el lunes, "ayer" en la lista es el viernes, el último día en que hubo mercado. Si calcularas "hoy menos un día" condatetime, el lunes buscarías el domingo, que no existe en los datos.
⚠️ Errores frecuentes
| Error | Qué ocurre | Solución |
|---|---|---|
Código con sangría debajo de un TODO sangrado |
IndentationError: unexpected indent (le pasó al curso) |
Quita la sangría y empieza en el margen |
"4.close" o "Time Series(Daily)" |
KeyError |
Copia la clave exacta, con espacios |
Usar la clave demo con TSLA |
Un mensaje "Information" en vez de datos (verificado) |
demo solo funciona con IBM; usa tu clave |
Restar sin float |
TypeError entre str y str |
Convierte los precios |
| Superar el límite de peticiones | Mensaje de límite en lugar de datos | Usa la caché (sección 1) |
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: imprime la fecha de ayer y la de anteayer junto a sus precios. (Pista: haz la comprensión con
(key, value)y guarda también las claves.) - 🟡 Reto 2: calcula el porcentaje con las dos fórmulas y muéstralas lado a lado para 5 días seguidos.
- 🟠 Reto 3: calcula el promedio de cierre de los últimos 5 días y compara el cierre de ayer con ese promedio.
- 🔴 Reto 4: en lugar de confiar en el orden del diccionario, ordena las fechas con
sorted(data.keys(), reverse=True). ¿Por qué es más seguro?
3. Paso 2: traer las noticias
(Fuente: 280 - Solution & Walkthrough for Step 2 - Get the News Articles.md)
📝 Ejercicio original del curso (tareas TODO 6 y 7)
- En lugar de imprimir "Get News", usar News API para obtener artículos con el nombre de la empresa.
- Usar el operador de slicing para quedarse con los 3 primeros artículos.
📖 Leer la documentación de News API
News API (newsapi.org) tiene dos endpoints principales:
| Endpoint | Para qué sirve |
|---|---|
| Top headlines | Los titulares del día (pocos) |
| Everything | Buscar artículos en general |
La profesora probó ambos: Everything encuentra más noticias sobre una empresa, porque muchas no llegan a los titulares del día.
Parámetros que usa el curso:
apiKey: la clave (obligatoria). Atención a las mayúsculas:apiKey, con K mayúscula. Sin clave, la API responde 401apiKeyMissing(verificado).qInTitle: busca la palabra solo en el título, para evitar artículos de análisis que mencionan muchas empresas a la vez. La profesora lo copia de la documentación porque no está segura de si es una "I" mayúscula o una "l" minúscula.
¿Nombre de la empresa o símbolo? Se busca "Tesla Inc" y no "TSLA": los periodistas escriben el nombre, no el símbolo.
🔎 La solución del curso
news_params = {
"apiKey": NEWS_API_KEY,
"qInTitle": COMPANY_NAME,
}
news_response = requests.get(NEWS_ENDPOINT, params=news_params)
articles = news_response.json()["articles"]
three_articles = articles[:3]- La respuesta tiene
status,totalResultsyarticles, una lista de diccionarios consource,author,title,description, etc. articles[:3]toma los elementos 0, 1 y 2: el3es el límite no incluido (Día 21).
🛠️ Nota técnica: los parámetros y las condiciones del plan gratuito de News API pueden haber cambiado desde que se grabó el curso. Revisa en la documentación actual si
qInTitlesigue disponible o si la búsqueda solo en títulos se hace de otra forma (por ejemplo, con un parámetro que indique en qué campos buscar). Esa es precisamente la habilidad que pide la profesora: leer la documentación.
⚠️ Errores frecuentes
| Error | Qué ocurre | Solución |
|---|---|---|
"apikey" en minúsculas |
401 | apiKey, como dice la documentación |
Buscar el símbolo TSLA |
Pocos o ningún resultado | Busca el nombre de la empresa |
articles[0:2] para "los 3 primeros" |
Solo 2 artículos | [:3] |
| Suponer que siempre hay 3 artículos | Menos mensajes de lo esperado, o ninguno | Revisa len(articles) |
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: imprime solo los títulos de los 3 artículos, numerados.
- 🟡 Reto 2: busca noticias solo en español (revisa el parámetro de idioma en la documentación) sobre una empresa colombiana.
- 🟠 Reto 3: limita la búsqueda a noticias de los últimos 2 días (parámetro de fecha).
- 🔴 Reto 4: compara los resultados de "Everything" y "Top headlines" para la misma empresa. Presenta en una tabla cuántos artículos devuelve cada uno y explica la diferencia.
4. Paso 3: armar y enviar los mensajes
(Fuente: 281 - Solution & Walkthrough for Step 3 - Send the SMS Messages.md)
📝 Ejercicio original del curso (tareas TODO 8 y 9)
- Con una comprensión de listas, crear una lista con el titular y el resumen de cada artículo, con este formato:
Headline: {título del artículo}
Brief: {descripción del artículo}- Enviar cada artículo como un mensaje separado con Twilio.
🔎 La solución del curso
formatted_articles = [
f"Headline: {article['title']}. \nBrief: {article['description']}"
for article in three_articles
]
client = Client(TWILIO_SID, TWILIO_AUTH_TOKEN)
for article in formatted_articles:
message = client.messages.create(
body=article,
from_=VIRTUAL_TWILIO_NUMBER,
to=VERIFIED_NUMBER
)Detalle de comillas: la cadena f usa comillas dobles por fuera, así que las claves de adentro usan simples: article['title']. Si usas dobles adentro, Python confunde dónde termina la cadena. (Desde Python 3.12 esto ya se permite, pero mezclar tipos de comillas sigue siendo lo más claro y compatible.)
📖 Mejora del curso: ¿subió o bajó?
Para que el mensaje diga la dirección del cambio, el curso quita el abs() del cálculo de la diferencia y lo usa solo al comparar con el umbral:
difference = float(yesterday_closing_price) - float(day_before_yesterday_closing_price)
up_down = None
if difference > 0:
up_down = "🔺"
else:
up_down = "🔻"
diff_percent = round((difference / float(yesterday_closing_price)) * 100)
if abs(diff_percent) > 5:
...
formatted_articles = [
f"{STOCK_NAME}: {up_down}{diff_percent}%\nHeadline: {article['title']}. \nBrief: {article['description']}"
for article in three_articles
]Resultado: TSLA: 🔺5% seguido del titular y el resumen. Los emojis son simplemente texto para Python.
🔍 Análisis: el texto extraño de la transcripción. En el archivo de la lección, los emojis aparecen como
ðŸ"º. No es un error de la profesora: es un ejemplo real de error de codificación (mojibake). El emoji 🔺 se guardó en UTF-8 (4 bytes) y alguien leyó esos bytes como Windows-1252, donde cada byte es un carácter distinto. Verificado:"🔺".encode("utf-8").decode("cp1252")produce exactamente🔺. Por eso conviene abrir siempre los archivos conencoding="utf-8".
⚠️ Errores frecuentes
| Error | Qué ocurre | Solución |
|---|---|---|
| Comillas dobles dentro de la cadena f (antes de Python 3.12) | SyntaxError |
Usa comillas simples adentro |
Crear el Client dentro del for |
Funciona, pero crea un cliente por mensaje sin necesidad | Créalo una vez, antes del bucle |
Quitar abs y comparar diff_percent > 5 |
Las bajadas grandes nunca generan alerta | abs(diff_percent) > 5 |
Retos adicionales (creados para esta adaptación)
- 🟢 Reto 1: en vez de tres mensajes, arma uno solo con los tres artículos separados por líneas. ¿Qué ventajas tiene (costo) y qué desventajas (longitud)?
- 🟡 Reto 2: agrega al mensaje el enlace del artículo (
url). - 🟠 Reto 3: envía la alerta por correo al servidor local del Día 32 en lugar de Twilio.
- 🔴 Reto 4: escribe la función
formatear_alerta(simbolo, porcentaje, articulo) -> stry pruébala con 3 diccionarios de artículo inventados, incluido uno condescriptionigual aNone.
5. 🚀 Proyecto del día: la Alerta de Noticias de Acciones
(Fuentes: 277 a 281)
Problema
Recibir una alerta con noticias cuando una acción cambie mucho de un día para otro.
Requisitos funcionales
- Obtener los dos últimos precios de cierre de una acción (Alpha Vantage).
- Calcular el cambio porcentual y su dirección.
- Si supera el umbral, obtener hasta 3 noticias de la empresa (News API).
- Enviar un mensaje por noticia con el símbolo, la flecha, el porcentaje, el titular y el resumen.
Restricciones técnicas
Tres claves en variables de entorno (Día 35); requests-cache durante el desarrollo; umbral como constante.
Planificación
| Paso | Pregunta | Herramienta |
|---|---|---|
| 1 | ¿Cuánto cambió el precio? | Alpha Vantage, comprensión de listas, float, abs |
| 2 | ¿Por qué pudo cambiar? | News API, slicing |
| 3 | ¿Cómo me entero? | Comprensión de listas con cadenas f, Twilio o correo |
Pruebas
| Caso | Cómo simularlo | Esperado |
|---|---|---|
| Cambio pequeño | Umbral normal | No se envía nada |
| Cambio grande | Umbral temporalmente bajo | Hasta 3 mensajes |
| Bajada grande | Precios simulados: ayer 90, anteayer 100 | Mensaje con 🔻 |
| Menos de 3 noticias | Una empresa poco conocida | ⚠️ (ver 🧪) |
| Artículo sin descripción | Diccionario simulado con description: None |
⚠️ (ver 🧪) |
🧪 Prueba y depuración
- Pocas noticias. Si News API devuelve 1 o 0 artículos, ¿el programa falla o envía menos mensajes? Si no hay noticias, ¿envías de todos modos la alerta del precio? Decide e impleméntalo.
Noneen la descripción. Algunos artículos no tienen descripción: el mensaje diceBrief: None. Reemplázalo por "(sin resumen)".- Probar sin gastar cuota. Guarda en archivos JSON una respuesta real de cada API y crea una opción
MODO_PRUEBA = Trueque lea esos archivos en lugar de hacer peticiones. Así puedes probar los casos anteriores sin internet y sin gastar peticiones. - La fórmula del porcentaje. Con ayer = 1568 y anteayer = 1643, calcula a mano el porcentaje con las dos fórmulas (sección 2). Con un umbral de 4,6 %, ¿se envía la alerta en cada caso?
⭐ Extensión del proyecto
- Vigilar varias acciones desde una lista.
- Guardar en un CSV el historial de alertas (fecha, símbolo, cambio, titulares).
- Programarlo con GitHub Actions al terminar el día de mercado (4:00 p. m. de Nueva York; calcula la hora UTC).
6. 🌟 Proyecto extra: la Alerta de la TRM
Situación
En Colombia, la TRM (tasa representativa del mercado) es el valor oficial del dólar en pesos para cada día. Afecta los precios de productos importados, los viajes y muchas empresas. La tienda escolar compra algunos productos importados y quiere saber cuándo el dólar cambia mucho.
La fuente de datos (sin clave)
El portal de datos abiertos del Estado colombiano publica la TRM como API. Petición verificada el 26/09/2026:
params = {"$order": "vigenciadesde DESC", "$limit": 3}
response = requests.get("https://www.datos.gov.co/resource/32sa-8pi3.json", params=params)[{"valor":"3306.86","unidad":"COP","vigenciadesde":"2026-09-26T00:00:00.000","vigenciahasta":"2026-09-28T00:00:00.000"},
{"valor":"3329.61","unidad":"COP","vigenciadesde":"2026-09-25T00:00:00.000","vigenciahasta":"2026-09-25T00:00:00.000"},
...]Observa: el valor llega como texto, igual que en Alpha Vantage, y una TRM puede estar vigente varios días (por ejemplo, un fin de semana).
Requisitos
- Obtener las dos TRM más recientes y calcular el cambio en pesos y en porcentaje (usa la fórmula con el valor anterior y explica por qué).
- Si el cambio supera un umbral (constante, por ejemplo 1 %), enviar un correo al servidor local con 🔺 o 🔻, los dos valores y sus fechas.
- Una tabla con la TRM de los últimos 30 registros, guardada en
trm.csvcon pandas, con el valor como número. - El valor máximo, el mínimo y el promedio del período.
- Opcional con clave: buscar en News API noticias en español sobre "dólar Colombia" y agregarlas al correo.
- Manejo de errores de red y de respuestas vacías.
Decisiones que debes tomar
- Si la TRM de hoy tiene vigencia de varios días, ¿con cuál la comparas?
- ¿Qué umbral tiene sentido para la tienda escolar? Justifícalo con los datos de los últimos 30 registros.
Casos de prueba
| Caso | Esperado |
|---|---|
| Datos simulados: 3300 → 3400 | Alerta 🔺 de 3,03 % |
| Datos simulados: 3400 → 3380 | Sin alerta (0,59 %) |
| Respuesta vacía de la API | Mensaje claro, sin error |
7. 🏆 Proyecto integrador de los Días 33 a 36: el Boletín Matutino Automático
Proyecto integrador creado para esta adaptación. Reúne APIs abiertas y con parámetros (Día 33), limpieza de datos de APIs y clases (Día 34), autenticación y variables de entorno (Día 35), y la combinación de varias APIs con umbrales y caché (Día 36), además del correo y la programación de tareas (Día 32).
Situación problema
El grupo de comunicaciones del colegio quiere enviar cada mañana a los docentes (ficticios en el ejercicio) un boletín breve con información útil del día.
Pregunta orientadora
¿Cómo diseñar un programa que combine varias APIs distintas de forma modular, de modo que agregar o quitar una sección no obligue a reescribir todo?
Objetivo
Construir el Boletín Matutino Automático: un correo diario con varias secciones, cada una alimentada por una API.
Requerimientos
- Mínimo 4 secciones, por ejemplo: clima y probabilidad de lluvia (Día 35), hora del amanecer y del atardecer (Día 33), TRM y su cambio (sección 6) y la pregunta de trivia del día (Día 34, con la respuesta al final del correo).
- Cada sección es una clase con la misma interfaz, por ejemplo un método
generar() -> strque devuelve el texto de la sección, o un mensaje "Sección no disponible hoy" si falla. - Una clase
Boletinque recibe la lista de secciones, arma el correo (EmailMessage) y lo envía. - Las secciones activas y su orden se configuran en
config.json. - Las claves (si alguna sección las usa) en variables de entorno.
requests-cacheen modo de desarrollo, activado por una opción deconfig.json.- Un resaltado automático: si la probabilidad de lluvia supera el 70 % o la TRM cambia más del 1 %, esa información aparece al principio del correo.
- Registro en
boletines.csvde cada envío (fecha, secciones enviadas, secciones fallidas).
Restricciones
- Una sección que falla nunca impide enviar las demás.
- Todas las peticiones con
timeout. - Datos personales ficticios; envío al servidor local.
Etapas de desarrollo
| Etapa | Entregable parcial |
|---|---|
| 1. Diseño | Diagrama de clases con la interfaz común de las secciones |
| 2. Secciones | Cada sección probada por separado en la consola |
| 3. Boletín | Correo completo en el servidor local |
| 4. Configuración | config.json con secciones activas y modo de desarrollo |
| 5. Robustez | Prueba con una API simulada caída |
| 6. Automatización | Expresión cron para las 6:00 a. m. de Colombia |
Entregables
- Código en varios archivos (una sección por archivo) y
config.json. - Diagrama de clases.
- 10 casos de prueba con resultados.
- Registro de errores con al menos 5 errores reales.
- Un ejemplo del correo recibido.
Casos de prueba mínimos
| Caso | Esperado |
|---|---|
| Todas las APIs responden | Correo con todas las secciones |
| Una API no responde | Correo con esa sección como "no disponible" |
| Probabilidad de lluvia simulada de 90 % | Aparece resaltada al inicio |
Quitar una sección de config.json |
Desaparece del correo sin tocar el código |
| Agregar una sección nueva | Solo se crea una clase y se agrega a config.json |
Criterios técnicos de funcionamiento
- La clase
Boletinno sabe nada de APIs concretas: solo llamagenerar(). - No hay código repetido para hacer peticiones y manejar errores.
- El programa termina en menos de 30 segundos aunque una API no responda.
Posibles extensiones
Versión Tkinter de vista previa del boletín; una sección con noticias (News API); estadística semanal de secciones fallidas.
8. 🧩 Comprueba lo aprendido
Conceptuales
- ¿Qué es el precio de cierre? ¿Por qué el curso compara el de ayer con el de anteayer?
- ¿Para qué sirve
requests-cachedurante el desarrollo? ¿Qué riesgo tiene dejarlo activo? - ¿Por qué el curso busca las noticias por el nombre de la empresa y no por el símbolo?
- ¿Qué es el mojibake? Explica con el ejemplo de 🔺.
Análisis de código
data_list = [value for (key, value) in data.items()]¿Qué contiene data? ¿Qué contiene data_list? ¿Qué se pierde en la conversión?
Predicción
- Ayer = 110, anteayer = 100. ¿Cuánto vale
diff_percentcon la fórmula del curso? ¿Y dividiendo entre el valor anterior? - ¿Qué devuelve
["a", "b", "c", "d"][:3]? ¿Y["a"][:3]? - ¿Qué imprime
f"{'TSLA'}: {'🔻'}{round(-4.6)}%"?
Depuración
difference = yesterday_closing_price - day_before_yesterday_closing_price
diff_percent = difference / yesterday_closing_price * 100
if diff_percent > 5:
print("Get News")Encuentra dos errores: uno produce una excepción y el otro hace que nunca se detecten las bajadas.
Modificación
Cambia el programa para vigilar tres acciones, con umbrales distintos para cada una, guardados en un diccionario.
Creación
Escribe cambio_porcentual(anterior: float, actual: float) -> float y pruébala con: (100, 110), (110, 100), (100, 100). ¿Qué debería pasar si anterior es 0?
9. 🤖 Programar con apoyo de IA
Actividad 1: pedir ayuda sin pedir la solución. La profesora insiste: "Tienes que escribir código para ser bueno escribiendo código". Antes de ver el video de la solución, si te atascas, pide a una IA solo una pista. Por ejemplo: "No me des código. ¿Cómo puedo obtener el primer valor de un diccionario de Python sin saber su clave?". Registra la pista que recibiste y cómo la aplicaste.
Actividad 2: la IA y el análisis financiero. Pregunta a una IA: "¿Por qué subió la acción de [empresa] ayer?". Luego:
- Revisa si cita fuentes y si su información corresponde a ayer o a fechas antiguas.
- Compara con las noticias que trajo tu programa.
- Discute en clase: ¿se puede confiar en esa explicación para tomar una decisión con dinero real?
Actividad 3: revisar el porcentaje. Pide a una IA que explique cómo se calcula el "cambio porcentual" entre dos precios. Compárala con la fórmula del curso (sección 2). ¿Cuál usa la IA? Comprueba con un ejemplo numérico.
10. 🛠️ Correcciones técnicas al material original
| Archivo | Afirmación o comportamiento del curso | Observación | Tratamiento |
|---|---|---|---|
279 |
diff_percent = difference / yesterday * 100 |
Lo habitual es dividir entre el valor anterior; con los datos del video: 4,78 % frente a 4,56 % (verificado) | Nota técnica de la sección 2 |
279 |
El orden del diccionario define "ayer" y "anteayer" | Funciona porque la API entrega las fechas en orden descendente (verificado); ordenar las fechas es más seguro | Reto 4 de la sección 2 |
280 |
Parámetro qInTitle de News API |
Los parámetros y el plan gratuito pueden haber cambiado; verificar en la documentación actual | Nota técnica de la sección 3 |
281 |
Emojis mostrados como ðŸ"º en la transcripción |
Es mojibake: UTF-8 leído como Windows-1252 (verificado) | Análisis de la sección 4 |
281 |
Mensajes con article['description'] |
Puede ser None y aparece "Brief: None" |
🧪 del proyecto |
281 |
Siempre 3 mensajes | Puede haber menos de 3 artículos | 🧪 del proyecto |
11. 📋 Matriz de trazabilidad
| Contenido original | Archivo de origen | Concepto desarrollado | Ejercicio original | Reto adicional | Proyecto relacionado |
|---|---|---|---|---|---|
| Terminal Bloomberg, precios de cierre, plan del programa, niveles de dificultad | 277 |
Sección 0 | — | Nota ética y financiera | Sección 5 |
Proyectos iniciales, APIs del proyecto, requests-cache |
278 |
Sección 1 | Elegir nivel | Retos 1–4 de la sección 1 | Secciones 5 y 7 |
Alpha Vantage, TIME_SERIES_DAILY, comprensión con items(), abs, porcentaje, umbral |
279 |
Sección 2 | TODO 1 a 5 |
Retos 1–4 de la sección 2 | Secciones 5, 6 y 7 |
News API, Everything, qInTitle, apiKey, slicing |
280 |
Sección 3 | TODO 6 y 7 |
Retos 1–4 de la sección 3 | Secciones 5 y 6 |
Comprensión de listas con cadenas f, Twilio, 🔺/🔻, round |
281 |
Sección 4 | TODO 8 y 9 |
Retos 1–4 de la sección 4 | Secciones 5, 6 y 7 |
| (No existe en el curso original) | — | — | — | Alerta de la TRM | Sección 6 |
| (No existe en el curso original) | — | — | — | Boletín Matutino Automático (Días 33–36) | Sección 7 |
12. 📦 Evidencias de aprendizaje del Día 36
- El nivel de dificultad elegido y los
TODOresueltos. - La prueba de tiempos con
requests-cache(from_cacheenFalseyTrue). - Los precios de ayer y anteayer impresos con sus fechas, y el porcentaje calculado con las dos fórmulas.
- Los mensajes de alerta (SMS en la demostración del docente, o correos en el servidor local) con 🔺 o 🔻.
- Las correcciones de la sección 🧪 y el
MODO_PRUEBAcon respuestas guardadas. - La Alerta de la TRM (proyecto extra) o el Boletín Matutino Automático (proyecto integrador).
- Cuaderno de errores:
IndentationErrordebajo de unTODO,KeyErrorcon claves como"4. close", restar textos, clavedemocon otro símbolo,apiKeymal escrito, comillas dentro de la cadena f,absmal ubicado, descripcionesNoney mojibake.