Herramienta de línea de comandos para graficar el historial de precios de acciones
Una herramienta de línea de comandos que grafica el historial de precios de cierre de una acción usando la Agent API de Perplexity y la herramienta sandbox.
Todo se ejecuta dentro de una única solicitud de Agent API en segundo plano:
- El modelo recibe la herramienta
sandbox— un entorno Python conurllib/pandas/matplotliby un directorio de trabajo escribible. - Dentro del sandbox, obtiene los precios de cierre diarios del ticker de una fuente de datos anclada (el endpoint JSON del gráfico v8 de Yahoo Finance), escribe
prices.csvy renderizachart.png. El sandbox expone ambos archivos como artefactos descargables.
El script sondea la solicitud hasta su finalización y descarga ambos archivos — no hay renderizado local, por lo que no tiene dependencias de terceros.

Cómo difiere de la documentación (importante)
Esta receta fue construida y verificada contra la Agent API en vivo. Algunas realidades dan forma al diseño:
- La herramienta
sandboxrequiere una tarea en segundo plano. En la ruta síncrona/de streaming, la solicitud es rechazada constreaming failed: ... unknown tool "sandbox". Debes enviarla conbackground: truey sondear la respuesta por ID. Este script siempre hace eso. - El sandbox devuelve archivos. Cualquier cosa que el sandbox escriba en su directorio de trabajo regresa como un elemento de salida
share_fileque contiene unfile_id,filenamey una URL/v1/responses/{id}/files/{file_id}/contentlista para descargar — también puedes listarlos conGET /v1/responses/{id}/files. El script descarga los artefactosprices.csvychart.pngdirectamente, en lugar de extraer nada destdout. - Ancla la fuente de datos para reducir la latencia. La parte lenta de una ejecución de sandbox sin restricciones es el modelo buscando una fuente de precios (páginas públicas
429o protegidas por captchas — fácilmente 3-7 llamadas al sandbox). Indicarle que acceda directamente al endpoint JSON del gráfico v8 de Yahoo lo convierte en una única obtención, y deja presupuesto de tokens para renderizar el gráfico en la misma sesión. Una ejecución típica ahora es una invocación de sandbox. - Dale al sandbox margen de tokens de salida. El sandbox gasta
max_output_tokensescribiendo el código que obtiene los datos y renderiza el gráfico. Un límite estricto puede agotar el paso de escritura de archivos (los datos se obtienen pero los archivos nunca se escriben). Esta receta usa8192. finance_searchno tiene historial (implementación actual). La herramienta de nivel superiorfinance_searchdevuelve solo la última cotización — una sola fila — por lo que no puede producir una serie de precios. El historial se obtiene dentro del sandbox.- La obtención de datos del sandbox es de mejor esfuerzo. Incluso una fuente anclada puede aplicar límites de tasa; el prompt recurre a una segunda fuente (Stooq), y el script reintenta toda la llamada varias veces (
--attempts).
La Agent API se llama a través de HTTP puro (stdlib urllib, sin SDK) para que el cuerpo exacto de la solicitud sea visible y el endpoint sea configurable.
Características
- Una solicitud en segundo plano orquesta el sandbox; el script la sondea hasta su finalización (resistente a 5xx transitorios)
- El sandbox obtiene los precios y renderiza el gráfico por sí mismo, escribiendo un CSV
date,closey un PNG; el script lee los artefactosshare_filede la respuesta y los descarga (recurriendo al endpoint/files) - Fuente de datos anclada (Yahoo v8 chart JSON, Stooq como respaldo) lo mantiene en ~1 llamada al sandbox
- Reintentos automáticos hasta que ambos archivos regresen y el CSV se analice correctamente
- Sin dependencias de terceros — el gráfico se renderiza en el servidor, en el sandbox
--base-url/PERPLEXITY_BASE_URLconfigurables; informa el recuento de invocaciones del sandbox y el costo de la solicitud
Requisitos previos
- Python 3.9+
- Una clave de API de Perplexity con acceso a la Agent API. La herramienta
sandboxestá en vista previa — consulta la documentación del sandbox para conocer la disponibilidad.
Instalación
cd docs/examples/finance-chart-sandbox
# No dependencies to install — the API is called over raw HTTP and the chart is
# rendered inside the sandbox. (requirements.txt is intentionally empty.)
chmod +x finance_chart_sandbox.py
Configuración de la clave de API
export PERPLEXITY_API_KEY="your-api-key-here"
También puedes pasar --api-key, colocar la clave en un archivo .pplx_api_key, o añadir una línea PERPLEXITY_API_KEY= / PPLX_API_KEY= a un .env local.
Inicio rápido
Grafica los precios de cierre de Apple de los últimos 6 meses:
./finance_chart_sandbox.py AAPL
Esto escribe AAPL_6mo.csv y AAPL_6mo.png en el directorio actual.
Uso
./finance_chart_sandbox.py TICKER [--period 6mo] [--start YYYY-MM-DD --end YYYY-MM-DD] \
[--model MODEL] [--attempts 3] [--max-steps 15] [--poll-timeout 300] \
[--out-dir DIR] [--base-url URL] [--api-key KEY] [--keep-json]
Un gráfico de un mes
./finance_chart_sandbox.py AAPL --period 1mo
Un rango de fechas explícito, más reintentos
./finance_chart_sandbox.py MSFT --start 2025-01-01 --end 2025-06-30 --attempts 5
Apuntar a un endpoint diferente
PERPLEXITY_BASE_URL=https://api.perplexity.ai ./finance_chart_sandbox.py NVDA
Ejemplo de salida
[attempt 1/3] Asking the sandbox to fetch AAPL closing prices over the past 1 month and plot them...
Data points: 21 (2026-05-08 → 2026-06-08)
CSV: AAPL_1mo.csv
Chart: AAPL_1mo.png (fetched and rendered in the sandbox)
Sandbox invocations: 1
Cost: 0.1003 USD
El CSV (AAPL_1mo.csv):
date,close
2026-05-08,293.32
2026-05-11,292.68
2026-05-12,294.80
...
…y AAPL_1mo.png es un gráfico de líneas de close sobre date.
Interfaz de usuario web (FastAPI + JS)
Una pequeña aplicación web en webapp/ pone una puerta de entrada en lenguaje natural
al ciclo del agente: pregunta "¿Cuál fue el precio de las acciones de Apple durante los últimos 6 meses?"
y el modelo resuelve el ticker y el período por sí mismo, obtiene los precios y
renderiza el gráfico en el sandbox, y la página muestra el resultado.
A diferencia de la CLI (que llama a la API a través de HTTP puro), el backend web utiliza el
SDK de Python de Perplexity y reutiliza el análisis del módulo CLI y los ayudantes de archivos compartidos. Ejecuta un flujo de dos fases, porque la herramienta sandbox solo se ejecuta como una tarea en segundo plano (no transmitible):
- Datos — una llamada en segundo plano (
client.responses.create(..., background=True)luegoclient.responses.retrieve(id)) donde el sandbox resuelve el ticker + período, obtiene los precios, escribeprices.csvy renderizachart.png(ambos descargados por el backend), e imprime un pequeño bloqueMETApara el enrutamiento (ticker + etiqueta). - Respuesta — una llamada de streaming separada (
stream=True) que escribe un breve análisis en lenguaje natural de la serie, token por token.
| Endpoint | Propósito |
|---|---|
POST /api/charts |
Envía una pregunta ({query, attempts?}) → devuelve un job_id |
GET /api/charts/{job_id}/events |
Eventos enviados por el servidor: progress → chart → tokens transmitidos → done |
GET /api/charts/{job_id}/chart.png |
El PNG del gráfico que el sandbox renderizó |
GET /api/charts/{job_id}/response.json |
La respuesta cruda de la Agent API de la fase 1 (código del sandbox, stdout, uso) |
GET /api/charts/{job_id}/csv |
Descarga el CSV date,close |
El trabajo se ejecuta en un hilo de trabajador y escribe el estado incremental en el trabajo; el
endpoint SSE simplemente sigue ese estado, por lo que las reconexiones nunca vuelven a ejecutar el trabajo. El
frontend es JS puro sin paso de compilación ni biblioteca de gráficos — en el
evento chart simplemente apunta un <img> al PNG renderizado por el sandbox, añade
el análisis transmitido en vivo y enlaza al JSON y CSV sin procesar.

Ejecútalo
cd docs/examples/finance-chart-sandbox/webapp
pip install -r requirements.txt # perplexityai + fastapi + uvicorn
export PERPLEXITY_API_KEY="your-api-key-here" # or a .env in this dir
python app.py # serves http://127.0.0.1:8000
# PORT=8060 python app.py # if 8000 is taken
Abre la página, escribe una pregunta (o haz clic en un ejemplo) y pulsa Preguntar. La línea de estado se actualiza por intento mientras el sandbox en segundo plano se ejecuta (~20–40s).
Recorrido del código
1. Envía una solicitud en segundo plano con la herramienta sandbox (HTTP puro).
payload = {
"model": "openai/gpt-5.5",
"instructions": SYSTEM_PROMPT, # "fetch from Yahoo v8, write CSV + render PNG"
"input": "Fetch this exact URL ... Write prices.csv and render chart.png for AAPL ...",
"tools": [{"type": "sandbox"}],
"background": True, # required for the sandbox tool
"max_output_tokens": 8192, # headroom for the in-sandbox code
"max_steps": 15,
}
# POST https://api.perplexity.ai/v1/responses (Authorization: Bearer <key>)
El prompt ancla la fuente de datos (https://query1.finance.yahoo.com/v8/finance/chart/<TICKER>?range=<RANGE>&interval=1d, Stooq como respaldo) para que el sandbox obtenga los datos de una sola vez en lugar de buscar en páginas con límites de tasa.
2. Sondea la respuesta por ID hasta que se complete.
# GET https://api.perplexity.ai/v1/responses/{id}
while body["status"] in ("queued", "in_progress"):
time.sleep(3)
body = get(f"/v1/responses/{body['id']}") # tolerate transient 5xx
3. Encuentra los archivos compartidos por el sandbox y descárgalos.
for item in body["output"]:
if item["type"] == "share_file":
url = item["url"] # /v1/responses/{id}/files/{file_id}/content
# item["filename"] is "prices.csv" or "chart.png"
data = get_raw(url) # Authorization: Bearer <key>
El script lee los elementos share_file de la respuesta (recurriendo a GET /v1/responses/{id}/files si no hay ninguno en línea), descarga tanto el .csv como el .png, valida que el CSV se analice en ≥2 filas date,close, y reintenta toda la llamada si no es así.
4. Guarda los archivos. El CSV y el PNG renderizado por el sandbox se escriben en el disco — no hay nada que renderizar en el cliente, por lo que la CLI no tiene dependencias de terceros. (El CSV se analiza solo para informar la longitud de la serie).
Guía de prompting
- Haz que los archivos sean el entregable. Indica claramente que la tarea solo se completa una vez que
prices.csvychart.pngexisten en el directorio de trabajo — de lo contrario, el modelo puede responder con los precios en prosa y nunca escribir los archivos. - Ancla la fuente de datos. Entregar al sandbox la URL de obtención exacta (JSON del gráfico v8 de Yahoo) colapsa una búsqueda de fuente de múltiples llamadas en una sola obtención — la mayor ganancia de latencia — y libera presupuesto para renderizar el gráfico en la misma sesión.
- Dale margen de tokens de salida. El sandbox gasta
max_output_tokensescribiendo el código que obtiene los datos y renderiza el gráfico; con un límite demasiado pequeño, se agota antes del paso de escritura.8192es cómodo. - Nombra una fuente de respaldo. Incluso un endpoint anclado puede
429; indicarle al modelo que recurra a una segunda fuente (Stooq) mejora la tasa de aciertos. - Prohíbe la fabricación. El prompt del sistema instruye al modelo a usar solo los precios que realmente recuperó — nunca a interpolar o estimar.
Precios
sandbox:$0.03por sesión de contenedor- Tokens del modelo: se facturan por separado según los precios de los tokens de la Agent API
Las invocaciones al sandbox se cuentan bajo usage.tool_calls_details.sandbox.invocation, y el intercambio de archivos bajo usage.tool_calls_details.share_file.invocation. Con una fuente de datos anclada, una ejecución típica es una invocación al sandbox (sin búsquedas web dentro del contenedor), lo que mantiene el costo bajo (~$0.10 en nuestras ejecuciones). Consulta Precios de Perplexity para conocer las tarifas actuales.
Limitaciones
sandboxestá en vista previa y debe ejecutarse como una tarea en segundo plano- El historial de precios proviene de fuentes de terceros (JSON del gráfico v8 de Yahoo, Stooq como respaldo) obtenidas dentro del sandbox, por lo que la precisión y disponibilidad de los datos dependen de esas fuentes — los valores deben ser verificados, y los tickers oscuros/no estadounidenses pueden fallar (Stooq espera un sufijo
.us) - La obtención es de mejor esfuerzo: los límites de tasa pueden hacer que un intento no devuelva archivos; el script reintenta, pero una ejecución aún puede fallar (lanzar
--attempts) - Cada intento es una sesión de sandbox facturada por separado
- Esto no es asesoramiento de inversión