TradingView es la plataforma de gráficos preferida por la mayoría de los operadores minoristas de FX, y Pine Script es el lenguaje que da vida a indicadores personalizados y señales de estrategia en esos gráficos. El desafío es que Pine Script se ejecuta completamente dentro de la caja de arena de TradingVIEW no puede hacer llamadas HTTP salientes a API externas en tiempo de ejecución. Esta guía cubre esa brecha con un flujo de trabajo de dos partes: un pequeño script de Python recupera datos de anuncio macro de FXMacroData, genera código Pine Script listo para pegar, y el indicador resultante superpone esos puntos de datos directamente en su gráfico de Trading VIEW con marcadores de eventos, una línea de señal y una tabla de datos macro en vivo.
Lo que construirás
- Un script de Python que recupera los anuncios de tasas de interés, CPI y PMI para cualquier moneda de FXMacroData y genera código fuente Pine Script automáticamente
- Indicador de la secuencia de comandos de Pine Script v5 que marca las fechas de los eventos macro en su gráfico con diamantes etiquetados, dibuja una línea de superposición de valores macro y muestra una tabla de datos que resume las últimas impresiones
- Una alerta de TradingView → puente de webhook que pings un pequeño punto final de Flask cada vez que su condición de Pine Script dispara, lo que le permite cruzar referencia de la señal con el contexto fresco FXMacroData automáticamente
Los requisitos previos
- Python 3.10+ con
requestsinstalado - La clave de la API de FXMacroData inscribirse en / suscribirse; los datos del indicador USD son gratuitos y no requieren una clave
- Una cuenta de TradingView el nivel gratuito admite Pine Script v5 e indicadores personalizados
- Familiaridad básica con el guión Pine el Pine Script v5 Docs cubrir los conceptos básicos en menos de una hora
- ¿ Qué pasa ?
Paso 1 Comprender el punto final del anuncio de FXMacroData
Cada indicador en FXMacroData sigue la misma forma REST. Una solicitud de tasa de política para el EUR se ve así use su clave API como parámetro de consulta:
curl "https://fxmacrodata.com/api/v1/announcements/eur/policy_rate?api_key=YOUR_API_KEY&start=2023-01-01"
La respuesta JSON es un objeto plano con un data - ¿ Qué es eso ?
{
"currency": "eur",
"indicator": "policy_rate",
"data": [
{
"date": "2025-03-06",
"val": 2.65,
"announcement_datetime": "2025-03-06T13:15:00Z"
},
{
"date": "2025-01-30",
"val": 2.90,
"announcement_datetime": "2025-01-30T13:15:00Z"
},
{
"date": "2024-12-12",
"val": 3.15,
"announcement_datetime": "2024-12-12T13:15:00Z"
}
]
}
Cada disco lleva un date (Año Año A-MM-DD fecha local de publicación), un número val, y un segundo nivel UTC announcement_datetimeLa forma uniforme de todas las monedas e indicadores es lo que hace que el generador de códigos sea sencillo de construir. Documento sobre las tasas de interés de política monetaria en euros y explore el catálogo de indicadores para su moneda de destino.
- ¿ Qué pasa ?
Paso 2 Obtener datos de macros con Python
Crear un archivo llamado generate_pine.pyEste script recupera datos de anuncio para una moneda y indicador elegido, luego serializa los resultados en matrices de Pine Script que se pegan en el archivo del indicador.
"""
generate_pine.py — fetch FXMacroData announcements and output Pine Script arrays.
Usage:
python generate_pine.py --currency eur --indicator policy_rate --start 2023-01-01
"""
import argparse
import json
import os
from datetime import datetime, timezone
import requests
BASE_URL = "https://fxmacrodata.com/api/v1"
API_KEY = os.environ.get("FXMD_API_KEY", "")
def fetch_announcements(currency: str, indicator: str, start: str) -> list[dict]:
url = f"{BASE_URL}/announcements/{currency}/{indicator}"
params: dict = {"start": start}
if API_KEY:
params["api_key"] = API_KEY
resp = requests.get(url, params=params, timeout=15)
resp.raise_for_status()
return resp.json().get("data", [])
def ts_to_pine_timestamp(iso_str: str) -> int:
"""Convert an ISO-8601 UTC string to a Unix timestamp (milliseconds for Pine)."""
dt = datetime.fromisoformat(iso_str.replace("Z", "+00:00"))
return int(dt.timestamp() * 1000)
def build_pine_arrays(records: list[dict]) -> str:
"""Render the data as Pine Script array literals."""
ts_list = []
val_list = []
for r in records:
ann = r.get("announcement_datetime") or f"{r['date']}T00:00:00Z"
ts_list.append(str(ts_to_pine_timestamp(ann)))
val_list.append(str(r["val"]))
ts_str = ", ".join(ts_list)
val_str = ", ".join(val_list)
n = len(records)
return f"""
// ── Auto-generated by generate_pine.py — do not edit manually ──
// Currency: {records[0].get('currency', '?').upper() if records else '?'}
// Indicator: {records[0].get('indicator', '?') if records else '?'}
// Records: {n}
var int[] _ann_ts = array.from({ts_str})
var float[] _ann_val = array.from({val_str})
"""
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--currency", required=True)
parser.add_argument("--indicator", required=True)
parser.add_argument("--start", default="2023-01-01")
args = parser.parse_args()
print(f"Fetching {args.indicator} for {args.currency.upper()} from {args.start} …")
records = fetch_announcements(args.currency, args.indicator, args.start)
print(f" {len(records)} records returned.")
pine = build_pine_arrays(records)
print(pine)
output_file = f"pine_data_{args.currency}_{args.indicator}.txt"
with open(output_file, "w") as f:
f.write(pine)
print(f"Arrays written to {output_file}")
if __name__ == "__main__":
main()
Guarde su clave de API y ejecute el script:
export FXMD_API_KEY="YOUR_API_KEY"
python generate_pine.py --currency eur --indicator policy_rate --start 2023-01-01
El archivo de salida pine_data_eur_policy_rate.txt Puede ejecutar el mismo script para CPI (--indicator inflation), el PMI (--indicator pmi), o cualquier otro indicador de la
Catálogo de FXMacroData- ¿ Qué ?
- ¿ Qué pasa ?
Paso 3 Construye el indicador de Pine Script
Abrir TradingView, navegar a la Pine Script editor (la pestaña "Pine Editor" en la parte inferior del gráfico), y pegar el siguiente indicador. _ann_ts ¿ Qué ? _ann_val las matrices en la parte superior con la salida del paso 2.
// @version=5
// FXMacroData Overlay — policy rate event markers + value line
// Replace the arrays below with output from generate_pine.py
indicator("FXMacroData Macro Overlay", overlay=true, max_labels_count=50, max_lines_count=50)
// ── User inputs ──
i_show_labels = input.bool(true, "Show event labels")
i_show_line = input.bool(true, "Show macro value line")
i_show_table = input.bool(true, "Show data table")
i_label_color = input.color(color.new(color.orange, 0), "Label colour")
i_line_color = input.color(color.new(color.orange, 30), "Line colour")
// ── Paste generated arrays here ──
// ---- BEGIN GENERATED SECTION ----
var int[] _ann_ts = array.from(1672531200000, 1675209600000, 1677628800000)
var float[] _ann_val = array.from(2.50, 2.65, 3.00)
// ---- END GENERATED SECTION ----
// ── Helper: find the most recent announcement value at or before this bar ──
f_current_val() =>
float result = na
int bar_t = time
for i = 0 to array.size(_ann_ts) - 1
if array.get(_ann_ts, i) <= bar_t
result := array.get(_ann_val, i)
break
result
// ── Macro overlay line ──
float macro_val = f_current_val()
plot(i_show_line ? macro_val : na, title="Macro value", color=i_line_color,
linewidth=2, style=plot.style_stepline)
// ── Event marker labels ──
if i_show_labels
for i = 0 to array.size(_ann_ts) - 1
int ts = array.get(_ann_ts, i)
float val = array.get(_ann_val, i)
if ts >= chart.left_visible_bar_time and ts <= chart.right_visible_bar_time
label.new(
x = ts,
y = high * 1.002,
text = str.tostring(val, "#.##"),
style = label.style_diamond,
color = i_label_color,
textcolor = color.white,
size = size.small,
xloc = xloc.bar_time
)
// ── Summary table (top-right corner) ──
var table t = table.new(position.top_right, 2, 6,
bgcolor = color.new(color.navy, 85),
border_width = 1,
border_color = color.new(color.gray, 60))
if i_show_table and barstate.islast
table.cell(t, 0, 0, "Date", text_color=color.silver, text_size=size.small)
table.cell(t, 1, 0, "Value", text_color=color.silver, text_size=size.small)
int rows = math.min(5, array.size(_ann_ts))
for i = 0 to rows - 1
int ts = array.get(_ann_ts, i)
float val = array.get(_ann_val, i)
string date_str = str.format("{0,date,yyyy-MM-dd}", ts)
table.cell(t, 0, i + 1, date_str, text_color=color.white, text_size=size.tiny)
table.cell(t, 1, i + 1, str.tostring(val, "#.##"), text_color=color.orange, text_size=size.tiny)
¿ Por qué ? stepline¿ Qué es eso ?
Los valores de los indicadores macro son funciones de paso el tipo de interés de referencia no interpola sin problemas entre las reuniones; salta. plot.style_stepline mantiene la superposición honesta: la línea mantiene su nivel hasta que se imprima un nuevo anuncio, que coincide exactamente con los datos publicados.
Haga clic Añadir a la tablaEl indicador superpondrá una línea de pasos que coincide con la progresión del valor macro y dejará caer un marcador de diamante etiquetado en cada fecha de anuncio. Desplácese por el historial para ver cómo cada impresión de tasa de política se alineó con la acción del precio en el par de divisas elegido.
- ¿ Qué pasa ?
Paso 4 Capas en múltiples indicadores
Un solo indicador cuenta parte de la historia. El borde real proviene de la capas de tasa de política, IPC y PMI juntos. Repita el paso 2 para cada indicador y agregue una sección adicional al guión de pino, o cree tres indicadores separados y apile en el mismo panel de gráfico.
Para una búsqueda de tres indicadores de una sola vez, extienda el script de Python:
INDICATORS = ["policy_rate", "inflation", "pmi"]
CURRENCY = "eur"
START = "2023-01-01"
for ind in INDICATORS:
records = fetch_announcements(CURRENCY, ind, START)
pine = build_pine_arrays(records)
with open(f"pine_data_{CURRENCY}_{ind}.txt", "w") as f:
f.write(pine)
print(f"Written pine_data_{CURRENCY}_{ind}.txt ({len(records)} records)")
Cada archivo de salida le proporciona una sección de acceso directo para un indicador Pine Script separado. Añadir cada uno a su gráfico y asignar un color distinto por indicador por ejemplo, naranja para la tasa de interés, azul para el IPC y verde para el PMI para que pueda ver de un vistazo qué régimen macro está en vigor. Documento de las PMI en EUR y el catálogo más amplio de indicadores.
- ¿ Qué pasa ?
Paso 5 Automatizar las actualizaciones con una verificación del calendario de lanzamiento
Los datos de macro en las matriz de Pine Script se vuelven obsoletos en el momento en que se imprime un nuevo anuncio. Automatice la actualización llamando al punto final del calendario de lanzamiento de FXMacroData antes de cada sesión de negociación para verificar si se imprimió algo desde su última regeneración. Si lo hizo, vuelva a ejecutar el generador y actualice su Pine Script.
"""
check_and_refresh.py — Re-generate Pine arrays if new announcements have printed.
Run this before each session, e.g. via cron or GitHub Actions.
"""
import subprocess
import requests
import os
from datetime import date, timedelta
BASE_URL = "https://fxmacrodata.com/api/v1"
API_KEY = os.environ.get("FXMD_API_KEY", "")
PAIRS = [
("eur", "policy_rate"),
("eur", "inflation"),
("eur", "pmi"),
]
def latest_release_date(currency: str, indicator: str) -> str | None:
"""Return the most recent announcement date for this indicator."""
params: dict = {"start": str(date.today() - timedelta(days=7))}
if API_KEY:
params["api_key"] = API_KEY
r = requests.get(
f"{BASE_URL}/announcements/{currency}/{indicator}",
params=params, timeout=10
)
r.raise_for_status()
data = r.json().get("data", [])
return data[0]["date"] if data else None
def refresh_all() -> None:
for currency, indicator in PAIRS:
latest = latest_release_date(currency, indicator)
if latest and latest >= str(date.today() - timedelta(days=1)):
print(f"New print detected: {currency.upper()} {indicator} on {latest}. Regenerating …")
subprocess.run(
["python", "generate_pine.py",
"--currency", currency,
"--indicator", indicator,
"--start", "2023-01-01"],
check=True,
)
else:
print(f"{currency.upper()} {indicator}: no new prints since yesterday.")
if __name__ == "__main__":
refresh_all()
Programe este script para que se ejecute de lunes a viernes a las 08:00 UTC, antes de la apertura de Londres, usando un trabajo cron, un flujo de trabajo de GitHub Actions o cualquier programador de tareas.
pine_data_*.txt contenido en el Editor de Pinar de TradingView y haga clic SalvarSus marcadores de gráficos reflejarán inmediatamente los últimos datos del anuncio.
- ¿ Qué pasa ?
Paso 6 Enviar alertas de TradingView de nuevo al contexto de FXMacroData
El flujo de trabajo hasta ahora empuja los datos macro En el TradingView. Paso 6 cierra el bucle en la otra dirección: cuando su Pine Script dispara una señal de negociación (por ejemplo, una ruptura por encima de la resistencia después de una impresión del IPC), el sistema de alerta webhook de TradingVIEW reenvía ese evento a un pequeño punto final de Flask, que consulta inmediatamente FXMacroData para obtener un contexto nuevo la última tendencia del IPc, las próximas versiones y el posicionamiento actual del COT y registra o le notifica con la imagen macro completa.
Crear . webhook_server.pyEl artículo 2
"""
webhook_server.py — Receive TradingView alert webhooks and enrich with FXMacroData context.
Run with: python webhook_server.py
Expose to the internet via ngrok or deploy to a cloud function / VPS.
"""
import os
import json
from datetime import date, timedelta
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
BASE_URL = "https://fxmacrodata.com/api/v1"
API_KEY = os.environ.get("FXMD_API_KEY", "")
def get_macro_context(currency: str) -> dict:
"""Fetch latest policy rate + CPI for the given currency."""
params: dict = {"start": str(date.today() - timedelta(days=90))}
if API_KEY:
params["api_key"] = API_KEY
ctx: dict = {}
for indicator in ("policy_rate", "inflation"):
try:
r = requests.get(
f"{BASE_URL}/announcements/{currency}/{indicator}",
params=params, timeout=10
)
r.raise_for_status()
data = r.json().get("data", [])
ctx[indicator] = data[0] if data else {}
except Exception as exc:
ctx[indicator] = {"error": str(exc)}
return ctx
@app.route("/tradingview/alert", methods=["POST"])
def receive_alert():
payload = request.get_json(force=True, silent=True) or {}
currency = payload.get("currency", "usd").lower()
signal = payload.get("signal", "unknown")
ctx = get_macro_context(currency)
result = {
"received_signal": signal,
"currency": currency.upper(),
"macro_context": ctx,
}
print(json.dumps(result, indent=2))
return jsonify(result), 200
if __name__ == "__main__":
app.run(port=5050, debug=False)
Instale Flask y ejecute el servidor:
pip install flask
python webhook_server.py
Expone el puerto local a Internet con el¿ Qué ?
ngrok http 5050
En TradingView, abierto Alertas → Crear una alertaSeleccione su condición de Pine Script, habilite
URL de la conexión, y pegar la URL de HTTPS ngrok que termina con /tradingview/alert. Configure el mensaje de alerta en una carga útil JSON:
{
"currency": "eur",
"signal": "breakout_long",
"ticker": "{{ticker}}",
"price": {{close}}
}
Cada vez que se activa la condición de Pine Script, TradingView publica ese JSON a su punto final. El manejador de webhook obtiene la última tasa de política de EUR y el CPI de FXMacroData y registra el contexto macro completo junto con la señal. Puede extender esto para enviar una notificación de Telegram o Slack utilizando los datos enriquecidos.
Consejo de producción
Para un despliegue permanente, anfitrión webhook_server.py En una nube VM, Railway, o Render. FXMD_API_KEY TradingView no firma las cargas útiles webhook de forma nativa, por lo que su propio secreto compartido en la ruta de URL (por ejemplo /tradingview/alert/SECRET_TOKENEs el guardia más sencillo.
- ¿ Qué pasa ?
Paso 7 Extensión con posicionamiento de COT y contexto spot de divisas
Los datos de anuncio macro son una capa de la imagen. Para una señal más completa, añada el posicionamiento del Compromiso de los Traders de la CFTC y el contexto de la tendencia spot de FX de FXMacroData.
Posicionamiento de la COT de la compra de futuros en euros:
curl "https://fxmacrodata.com/api/v1/cot/eur?api_key=YOUR_API_KEY&start=2024-01-01"
{
"currency": "eur",
"data": [
{
"date": "2025-03-18",
"net_noncommercial": 48320,
"long_noncommercial": 182500,
"short_noncommercial": 134180
}
]
}
Añadir una serie de colocación de red COT a su generador de Pine Script utilizando el mismo patrón que el paso 2.
net_noncommercial El valor de los valores de los futuros de EUR indica que los operadores especulativos son netos de futuros largos en EUR un contexto de sentimiento que añade convicción cuando se combina con una señal de política del BCE.
Tablero de instrumentos de la COT antes de incrustarlo en su indicador.
Extensión del generador de Python para incluir una sección COT:
def fetch_cot(currency: str, start: str) -> list[dict]:
url = f"{BASE_URL}/cot/{currency}"
params: dict = {"start": start}
if API_KEY:
params["api_key"] = API_KEY
resp = requests.get(url, params=params, timeout=15)
resp.raise_for_status()
return resp.json().get("data", [])
def build_cot_pine_arrays(records: list[dict]) -> str:
ts_list = [str(int(datetime.fromisoformat(r["date"] + "T00:00:00+00:00").timestamp() * 1000)) for r in records]
net_list = [str(r.get("net_noncommercial", 0)) for r in records]
ts_str = ", ".join(ts_list)
net_str = ", ".join(net_list)
return f"""
var int[] _cot_ts = array.from({ts_str})
var float[] _cot_net = array.from({net_str})
"""
En el guión de Pine, trama _cot_net en un panel separado (conjunto overlay=false Para este indicador) para que pueda ver la tendencia de posicionamiento especulativo junto con los anuncios de precios y macro.
- ¿ Qué es lo que está pasando ?
Lo que construiste
- ✅ Un script Python que recupera anuncios de FXMacroData y genera literales de array de Pine Script
- ✅ Un indicador de Pine Script v5 que marca las fechas de eventos macro en su gráfico TradingView con etiquetas, una superposición de línea de paso y una tabla de datos
- ✅ Un script de actualización automático que comprueba si hay nuevas impresiones antes de cada sesión y regenera las matrices Pine cuando sea necesario
- ✅ Un punto final de webhook Flask que recibe alertas de TradingView y las enriquece con contexto macro en vivo de FXMacroData
- ✅ Una extensión de posicionamiento de COT que agrega sentimiento especulativo a la imagen
Los siguientes pasos: Extendiendo el manejador de webhook para publicar en Telegram o Slack, añadir una verificación de calendario de lanzamiento para que el indicador resalta el próximo En el caso de los tipos de cambio de tipo de cambio, el índice de variación de los precios de cambio se basa en el valor de los valores de cambio en el mercado de la moneda de referencia. /api-datos-doc Para encontrar la serie macro que mejor se adapte a su estrategia.