On the wire · 14:56:59 UTC Live 119 · Prematch 8,510 · Markets 34,179 Vol. I · No. 1 · Monday 9 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Guía · Google Sheets · Apps Script

Cuotas de Pinnacle en Google Sheets

Actualizado el · PinnFeed · 5 min de lectura

Esta guía escribe los 1X2 de fútbol de Pinnacle en una hoja de Google Sheets: una fila por partido, con cuotas decimales, cuotas justas sin margen y el margen del mercado. Un activador por tiempo actualiza la pestaña cada 15 minutos. El script usa la API REST de PinnFeed, así que funciona en el plan Free (0 €, 30 segundos de retraso, 1.000 peticiones/día).

Paso 1 — Consigue una clave Free#

  1. Crea una cuenta en pinnfeed.io y abre el panel.
  2. Crea una clave y cópiala. Las claves tienen la forma pf_live_….
  3. En Free, elige hasta dos deportes en el panel. El script usa fútbol (soccer) por defecto; cambia SPORT si elegiste otro.

No necesitas Builder para Sheets. Builder (99 €/mes, el plan WebSocket) es para clientes push en tiempo real como los de la guía de Python y Node.

Paso 2 — Crea la hoja de cálculo#

  1. Crea una hoja nueva de Google Sheets.
  2. Renombra la primera pestaña a Odds (nombre exacto; el script la busca así).
  3. Abre Extensiones → Apps Script. Borra la función de ejemplo myFunction y deja el proyecto vacío para el siguiente paso.

Paso 3 — Pega el script y define las propiedades#

Pega esto en Code.gs:

// Google Apps Script: Extensiones → Apps Script, pega este archivo.
// Propiedades del script (Configuración del proyecto → Propiedades del script):
//   PINNFEED_BASE = https://pinnfeed.io
//   PINNFEED_KEY  = pf_live_...
// Crea una pestaña llamada "Odds", ejecuta refreshOdds una vez y añade un activador cada 15 minutos.

const PROPS = PropertiesService.getScriptProperties();
const BASE = PROPS.getProperty('PINNFEED_BASE') || 'https://pinnfeed.io';
const KEY = PROPS.getProperty('PINNFEED_KEY');
const SPORT = 'soccer'; // cámbialo a basketball, tennis, … (tiene que estar en tu plan)

function refreshOdds() {
  if (!KEY) {
    console.error('Set script property PINNFEED_KEY first');
    return;
  }
  const url = BASE + '/v1/odds'
    + '?sport=' + encodeURIComponent(SPORT)
    + '&market=moneyline&main=true&live=false&limit=500';
  const res = UrlFetchApp.fetch(url, {
    headers: { 'x-api-key': KEY },
    muteHttpExceptions: true,
  });
  const code = res.getResponseCode();
  if (code !== 200) {
    console.warn('PinnFeed HTTP ' + code + ': ' + res.getContentText().slice(0, 300));
    return; // si falla la llamada, no toca la pestaña
  }
  const data = JSON.parse(res.getContentText());
  const rows = [];
  for (const ev of data.events || []) {
    const ml = (ev.markets || []).find((m) => m.type === 'moneyline' && m.main);
    if (!ml) continue;
    const byName = {};
    for (const o of ml.outcomes || []) byName[o.name] = o;
    const home = byName.home || {};
    const draw = byName.draw || {};
    const away = byName.away || {};
    rows.push([
      ev.startTime ? new Date(ev.startTime) : '',
      (ev.league && ev.league.name) || '',
      ev.home || '',
      ev.away || '',
      home.decimal || '',
      draw.decimal || '',
      away.decimal || '',
      home.fair || '',
      draw.fair || '',
      away.fair || '',
      ml.margin != null ? ml.margin : '',
      ev.id,
    ]);
  }
  const sheet = SpreadsheetApp.getActive().getSheetByName('Odds');
  if (!sheet) {
    console.error('Create a tab named Odds first');
    return;
  }
  sheet.clearContents();
  sheet.appendRow([
    'Starts', 'League', 'Home', 'Away',
    '1', 'X', '2',
    'Fair 1', 'Fair X', 'Fair 2',
    'Margin', 'Event id',
  ]);
  if (rows.length) {
    sheet.getRange(2, 1, rows.length, 12).setValues(rows);
  }
  console.log('Wrote ' + rows.length + ' moneyline rows for ' + SPORT);
}

Después abre el engranaje del proyecto (Configuración del proyecto) y, en Propiedades del script, añade:

PropiedadValor
PINNFEED_KEYtu clave (pf_live_…)
PINNFEED_BASEhttps://pinnfeed.io (opcional; es el valor por defecto)

Nunca pegues la clave en las celdas de la hoja ni compartas públicamente el proyecto de Apps Script.

Paso 4 — Ejecútalo una vez y autorízalo#

  1. Elige refreshOdds en el desplegable de funciones y pulsa Ejecutar.
  2. Google te pedirá permiso para conectarse a un servicio externo y editar la hoja. Acéptalo para tu cuenta.
  3. Recarga la hoja. La pestaña Odds debería mostrar las columnas Starts, League, Home, Away, 1, X, 2, las tres cuotas justas, Margin y Event id.

Si una llamada falla (clave incorrecta, límite de peticiones, deporte fuera de tu plan), el script registra un aviso y deja las filas anteriores como estaban, así que un mal minuto nunca vacía el tablero.

Paso 5 — Añade un activador cada 15 minutos#

  1. En Apps Script, abre Activadores (icono del reloj) → Añadir activador.
  2. Función: refreshOdds. Fuente del evento: Según tiempo. Tipo: Temporizador por minutos. Intervalo: Cada 15 minutos.
  3. Guarda.

Son 96 llamadas al día para un deporte, muy por debajo de las 1.000 peticiones/día y 1 req/s del plan Free. Dos deportes cada 30 minutos también son 96. Consulta planes y límites (en inglés).

ActivadorLlamadas / día¿Cabe en Free?
Cada 15 min, 1 deporte96sí
Cada 30 min, 2 deportes96sí
Cada 15 min, 2 deportes192sí
Cada 1 min, 1 deporte1.440no — necesita Hobby o superior (sin cuota diaria)

Apps Script tiene además sus propias cuotas; el activador por tiempo más corto es de un minuto.

Paso 6 — Lee las cuotas justas y los márgenes#

Cada fila de 1X2 lleva los campos sin margen de PinnFeed descritos en el esquema:

  • Fair 1 / Fair X / Fair 2 — la cuota decimal fair de cada resultado (margen eliminado, método multiplicativo).
  • Margin — el margin del mercado (sobrerredondeo = suma de probabilidades implícitas − 1).

Usa esas columnas cuando compares una cuota de una casa blanda en otra pestaña: el valor esperado es soft × (1 / fair) − 1, la misma cuenta de la guía de value betting. Para los movimientos steam en vivo, Sheets no es la herramienta: usa el WebSocket de Builder y la guía de detección de steam.

Preguntas frecuentes#

¿Qué plan de PinnFeed necesito?#

Free basta para un tablero con retraso que se actualiza cada pocos minutos. Hobby (29 €/mes) quita la cuota diaria y los 30 segundos de retraso, pero sigue siendo solo REST. El push en tiempo real necesita Builder (99 €/mes).

¿Por qué el script usa x-api-key en vez de un parámetro en la URL?#

Es la cabecera de autenticación recomendada en la documentación. UrlFetchApp de Apps Script puede enviar cabeceras, así que no hay motivo para poner la clave en la URL (donde puede acabar en los logs).

¿Puedo hacer un gráfico del histórico de precios?#

Sí. Deja la pestaña Odds como tablero en vivo (se borra y reescribe en cada ejecución). Añade una segunda pestaña que solo agregue filas tras cada actualización e inserta un gráfico de líneas. No borres la pestaña del histórico.

¿Es contenido educativo para mayores de edad?#

Sí. Los datos de cuotas y las herramientas de hoja de cálculo son material educativo para mayores de 18 años. Nada de esto es un pronóstico, una apuesta segura ni una promesa de beneficios.

Relacionado#

El plan WebSocket: Builder, 99 €/mes.

Cuotas de Pinnacle en tiempo real por un único WebSocket: los 13 deportes, todos los mercados, cuotas justas sin margen y cuotas de cierre. 3 días gratis y cancelas con un clic.

Form K-1 · Free API key

Get your free API key.

No password. We email you a link; click it and your key is on screen.

One free key per email. Link valid for 20 minutes.