Volver al blog

Cómo obtener tipos de cambio en tiempo real en Google Sheets (GOOGLEFINANCE, Apps Script y una API de divisas)

V
Vlado Grigirov
August 25, 2026
Currency API Exchange Rates Google Sheets Apps Script Tutorial Finexly

Cómo obtener tipos de cambio en tiempo real en Google Sheets (GOOGLEFINANCE, Apps Script y una API de divisas)

Obtener tipos de cambio en tiempo real en Google Sheets parece un problema resuelto. Escribes =GOOGLEFINANCE("CURRENCY:USDEUR"), aparece un número y sigues con lo tuyo. Eso funciona perfectamente para el presupuesto de un viaje personal. Deja de funcionar en el momento en que la hoja de cálculo alimenta una factura, una nómina, un informe de ingresos o cualquier cosa sobre la que un compañero vaya a tomar decisiones: por una restricción de licencia, una peculiaridad documentada con las fechas y una limitación de Apps Script que casi ningún tutorial menciona.

Esta guía cubre los tres métodos prácticos —la función integrada GOOGLEFINANCE, una función personalizada de Apps Script respaldada por una API de divisas y una tabla de tipos programada que se actualiza mediante un activador temporal— con las cifras reales de las cuotas, la redacción exacta de las advertencias de la propia Google y código ejecutable. Toda afirmación sobre el comportamiento de Google que aparece más abajo está citada de la documentación oficial de Google, y toda afirmación que no está documentada se señala como tal.


Las tres formas de traer tipos de cambio a Google Sheets

GOOGLEFINANCEFunción personalizada de Apps ScriptTabla de tipos programada
Tiempo de configuraciónSegundos~10 minutos~20 minutos
¿Requiere clave de API?No
ActualizaciónAutomática, al recalcularAl recalcularCon un activador que tú controlas
Tipos históricosSí (con matices)Depende de tu plan
Funciona en Apps Script / API de SheetsHistóricos: no
Uso comercial / profesionalRestringido por los términos de GoogleRegido por los términos de tu proveedor de APIRegido por los términos de tu proveedor de API
Ideal paraConsultas rápidas, hojas personalesColumnas de conversión puntualesCualquier cosa de la que dependa otra persona
La mayoría debería empezar por el método 1 y pasar al método 3 en cuanto la hoja se vuelva crítica.


Método 1: GOOGLEFINANCE, y lo que Google dice exactamente sobre él

La fórmula básica de divisas

El patrón que enseñan todos los tutoriales es un ticker CURRENCY: formado por dos códigos de divisa ISO 4217 concatenados:

=GOOGLEFINANCE("CURRENCY:USDEUR")

Para convertir un importe de la celda A2:

=A2 * GOOGLEFINANCE("CURRENCY:USDEUR")

Para construir el par a partir de dos celdas que contienen códigos de divisa:

=GOOGLEFINANCE("CURRENCY:" & B2 & C2)

Una advertencia honesta que ningún artículo de la competencia hace: la forma de ticker CURRENCY:XXXYYY no aparece en ninguna parte de la documentación oficial de GOOGLEFINANCE. La firma documentada es GOOGLEFINANCE(ticker, [attribute], [start_date], [end_date|num_days], [interval]), y el único contenido sobre divisas de la página de ayuda es un atributo "currency" (la moneda en la que cotiza un valor) y un ejemplo de gráfico. La sintaxis de pares CURRENCY: funciona y lleva años funcionando, pero es un comportamiento establecido por la comunidad, no un contrato documentado, lo que significa que Google puede cambiarlo sin previo aviso de obsolescencia. Google tampoco publica ninguna lista de pares de divisas admitidos, así que cualquier artículo que te diga que admite "unas 50 divisas" está adivinando.

Tipos históricos: la regla de atributos que todo el mundo se salta

Pasa una fecha y obtendrás datos históricos:

=GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,15))
=GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,1), DATE(2026,1,31), "DAILY")

Fíjate en el atributo. Google lo documenta con claridad: "Si se especifica algún parámetro de fecha, la solicitud se considera histórica y solo se permiten los atributos históricos". Los atributos históricos son open, close, high, low, volume y all, y "price" no está entre ellos. "price" está documentado únicamente como atributo en tiempo real ("Cotización de precio en tiempo real, con un retraso de hasta 20 minutos").

Ve ahora mismo a mirar los tutoriales de divisas para Google Sheets mejor posicionados: la mayoría te ofrecen GOOGLEFINANCE("CURRENCY:USDEUR", "price", DATE(...)). Esa combinación contradice la propia documentación de Google. Usa "close".

Dos comportamientos documentados más que conviene interiorizar:

  • "Si se especifica start_date pero no end_date|num_days, solo se devuelven los datos de ese único día".
  • "Los resultados en tiempo real se devuelven como un valor dentro de una sola celda. Los datos históricos, incluso los de un solo día, se devuelven como una matriz expandida con encabezados de columna". Por eso una fórmula histórica que parece correcta derrama dos columnas y una fila de encabezado en tu pulcro diseño, y por eso normalmente necesitas envolverla en INDEX(...,2,2).

El desplazamiento del mediodía UTC

Este corrompe informes emparejados por fecha de forma silenciosa. Textualmente, según Google:

"Google trata las fechas que se pasan a GOOGLEFINANCE como las 12:00 del mediodía en horario UTC. Los mercados que cierran antes de esa hora pueden aparecer desplazados un día".

Si estás conciliando un libro mayor en el que cada línea debe usar el tipo correspondiente a esa fecha de asiento, un desplazamiento de un día es una ruptura real de la conciliación, no un problema de redondeo. Si eso describe tu hoja, lee nuestra guía sobre tipos de cambio y declaración fiscal antes de fiarte de una matriz derramada de GOOGLEFINANCE como registro de auditoría.

El retraso es de 3 minutos, no de 20

Casi todos los artículos sobre este tema te dicen que los tipos de cambio de GOOGLEFINANCE tienen "un retraso de hasta 20 minutos". Ese número de 20 minutos procede del descargo de responsabilidad genérico sobre cotizaciones de valores del atributo "price". La propia página de descargo de responsabilidad de Google Finance publica una tabla de retrasos por tipo de activo, y la fila de Divisas —global, suministrada por Morningstar— indica 3 minutos. Las criptomonedas también tienen 3 minutos.

Así que los datos son más frescos de lo que cree internet. Lo que Google no publica es con qué frecuencia Sheets recalcula la fórmula, que es justo el dato que de verdad te importa: un tipo de hace 3 minutos alojado en una celda que no se recalcula desde el martes sigue siendo un tipo del martes. Quien cite un intervalo de recálculo concreto está citando algo que Google nunca ha documentado.

Como comparación, Finexly actualiza los tipos cada minuto y los devuelve bajo demanda, así que la frescura depende de cuándo llamas , no de cuándo decide recalcular la hoja de cálculo. Si quieres entender qué significa "en tiempo real" entre proveedores en general, consulta de dónde obtienen sus datos las API de tipos de cambio.

La restricción de uso que nadie cita

Este es el párrafo más importante de este artículo, y no aparece en ninguno de los tutoriales mejor posicionados. De la página de ayuda de GOOGLEFINANCE de Google, textualmente:

"Restricciones de uso: Los datos no están destinados al uso profesional del sector financiero ni al uso por parte de otros profesionales de empresas no financieras (incluidas entidades gubernamentales). El uso profesional puede estar sujeto a tarifas de licencia adicionales de un proveedor de datos externo".

Y del descargo de responsabilidad de Google Finance:

"Aceptas no copiar, modificar, reformatear, descargar, almacenar, reproducir, reprocesar, transmitir ni redistribuir ningún dato o información que se encuentre aquí, ni utilizar dichos datos o información en una empresa comercial sin obtener consentimiento previo por escrito".
"Google no puede garantizar la exactitud de los tipos de cambio mostrados. Deberías confirmar los tipos vigentes antes de realizar cualquier transacción que pueda verse afectada por variaciones en los tipos de cambio".

Contrasta eso con lo que hace realmente tu hoja. Fijar el precio de una factura a un cliente, convertir facturas de proveedores para el equipo contable o exportar una cifra de ingresos convertida a un informe que envías a un cliente no encaja de forma evidente en "fines informativos". Una API de tipos de cambio con licencia elimina la duda por completo y eso —no la precisión en bruto— es el verdadero motivo por el que los equipos financieros abandonan GOOGLEFINANCE.

Y el bloqueo insalvable

"Los datos históricos no se pueden descargar ni consultar a través de la API de Sheets ni de Apps Script. Si lo intentas, verás un error #N/A en lugar de los valores en las celdas correspondientes de tu hoja de cálculo".

En cuanto quieras automatizar algo —una exportación nocturna, una extracción con la API de Sheets, un script que capture instantáneas de tipos—, los datos históricos de GOOGLEFINANCE quedan descartados por diseño. Ese es el muro que empuja a la gente hacia el método 2.


Método 2: una función personalizada de Apps Script respaldada por una API de divisas

Una función personalizada es una función de JavaScript en Apps Script que invocas desde una celda como cualquier función integrada. Google confirma explícitamente que esto funciona con peticiones web: las funciones personalizadas "solo pueden llamar a servicios que no tengan acceso a datos personales" y URL Fetch está en la lista de servicios permitidos.

Paso 1: consigue una clave de API y guárdala como es debido

Consigue una clave gratuita en el panel de Finexly: 1.000 solicitudes al mes, sin tarjeta de crédito. Y luego, esto importa: no la escribas directamente en el código. Dos de los tutoriales de divisas para Google Sheets más enlazados pegan la clave de API tal cual en el script, en un archivo que viaja con la hoja de cálculo a cualquiera con quien la compartas.

En el editor de Apps Script (Extensiones → Apps Script), ejecuta esto una sola vez desde el editor para guardar la clave en las propiedades del script:

function storeApiKey() {
  PropertiesService.getScriptProperties()
    .setProperty('FINEXLY_API_KEY', 'YOUR_API_KEY');
}

Elimina el literal del archivo después. Ten en cuenta los límites documentados: el valor de una propiedad está limitado a 9 KB, y un almacén de propiedades a 500 KB en total; de sobra para una clave, pero no es un sitio para cachear datos.

Paso 2: una función personalizada para un solo par

/**
 * Returns the live exchange rate for a currency pair.
 *
 * @param {string} from Base currency code, e.g. "USD".
 * @param {string} to Quote currency code, e.g. "EUR".
 * @return The exchange rate.
 * @customfunction
 */
function FX_RATE(from, to) {
  if (!from || !to) throw new Error('Both currency codes are required.');

  var pair = String(from).toUpperCase() + '_' + String(to).toUpperCase();
  var cache = CacheService.getScriptCache();
  var hit = cache.get(pair);
  if (hit !== null) return Number(hit);

  var key = PropertiesService.getScriptProperties().getProperty('FINEXLY_API_KEY');
  var res = UrlFetchApp.fetch(
    'https://api.finexly.com/v1/rate?from=' + encodeURIComponent(from) +
      '&to=' + encodeURIComponent(to),
    {
      headers: { Authorization: 'Bearer ' + key },
      muteHttpExceptions: true
    }
  );

  var code = res.getResponseCode();
  var body = JSON.parse(res.getContentText());
  if (code !== 200) {
    throw new Error(body.error ? body.error.code + ': ' + body.error.message : 'HTTP ' + code);
  }

  cache.put(pair, String(body.rate), 300); // 5 minutes
  return body.rate;
}

Úsala en una celda:

=FX_RATE("USD","EUR")
=A2 * FX_RATE($B$1, $C$1)

El endpoint /v1/rate devuelve {"pair": "USD_EUR", "rate": 0.9215}. La referencia completa de parámetros está en la documentación de la API de Finexly.

Paso 3: procesa el rango por lotes, la parte que todos los competidores pasan por alto

Aquí está el modo de fallo. Google lo documenta directamente:

"Cada vez que se usa una función personalizada en una hoja de cálculo, Sheets realiza una llamada independiente al servidor de Apps Script. Si tu hoja de cálculo contiene decenas (¡o cientos, o miles!) de llamadas a funciones personalizadas, este proceso puede ser lento".

Arrastra FX_RATE 400 filas hacia abajo y habrás hecho 400 idas y vueltas. Con un límite de 30 segundos por ejecución en las funciones personalizadas, te toparás con #ERROR! y la nota Exceeded maximum execution time (line 0). mucho antes de agotar tu cuota de API.

La solución que recomienda Google es el procesamiento por lotes con matrices: acepta un rango, devuelve una matriz. El endpoint /v1/convert de Finexly admite pares separados por comas, así que toda la columna se convierte en una sola petición HTTP:

/**
 * Converts a column of amounts from one currency to another in a single API call.
 *
 * @param {A2:A400} amounts Range of amounts.
 * @param {string} from Base currency code.
 * @param {string} to Quote currency code.
 * @return {Array} Converted amounts.
 * @customfunction
 */
function FX_CONVERT_RANGE(amounts, from, to) {
  var rate = FX_RATE(from, to);           // one fetch, then cached
  var rows = Array.isArray(amounts) ? amounts : [[amounts]];
  return rows.map(function (row) {
    return row.map(function (v) {
      return (v === '' || v === null) ? '' : Number(v) * rate;
    });
  });
}
=FX_CONVERT_RANGE(A2:A400, "USD", "EUR")

Una fórmula, una llamada de red, 399 idas y vueltas menos. Si necesitas varios pares a la vez, llama a /v1/convert?q=USD_EUR,USD_GBP,USD_JPY y lee body["USD_EUR"].rate.

Lo que Google dice realmente sobre la caché en las funciones personalizadas

Arriba se usa CacheService, pero seamos precisos sobre el motivo. La guía de funciones personalizadas de Google califica el servicio Cache como "Funciona, pero no resulta especialmente útil en las funciones personalizadas". La ventaja del cacheo solo es real entre ejecuciones distintas —recálculos repetidos del mismo par—, no dentro de una única matriz derramada. El procesamiento por lotes con matrices es la optimización documentada; el cacheo es un complemento útil.

Los límites documentados de la caché: claves de hasta 250 caracteres, valores de hasta 100 KB, un tope de 1.000 elementos y una caducidad de entre 1 segundo y 21.600 segundos (6 horas), con 600 segundos por defecto. No hay ninguna cuota diaria publicada para las llamadas a la caché.

Otra trampa documentada más, porque el apaño circula ampliamente: añadir NOW() como argumento para forzar una actualización rompe la función. Google: "Los argumentos de las funciones personalizadas deben ser deterministas… Si una función personalizada intenta devolver un valor basado en una de estas funciones integradas volátiles, mostrará Loading... indefinidamente".


Método 3: una tabla de tipos programada (el patrón de producción)

Las funciones personalizadas se recalculan cuando a Sheets le apetece, que es exactamente la propiedad equivocada para una hoja que lee otra persona. El patrón robusto consiste en dejar de hacer peticiones desde las celdas por completo: escribe los tipos en una tabla siguiendo una programación y luego consúltalos con fórmulas normales.

El script de actualización

var PAIRS = ['USD_EUR', 'USD_GBP', 'USD_JPY', 'USD_CAD', 'USD_AUD', 'USD_CHF'];

function refreshRates() {
  var key = PropertiesService.getScriptProperties().getProperty('FINEXLY_API_KEY');
  var res = UrlFetchApp.fetch(
    'https://api.finexly.com/v1/convert?q=' + PAIRS.join(','),
    { headers: { Authorization: 'Bearer ' + key }, muteHttpExceptions: true }
  );

  if (res.getResponseCode() !== 200) {
    console.error('Finexly refresh failed: ' + res.getContentText());
    return; // keep yesterday's rates rather than blanking the sheet
  }

  var data = JSON.parse(res.getContentText());
  var stamp = new Date();
  var rows = PAIRS.map(function (p) {
    return [p, p.split('_')[0], p.split('_')[1], data[p].rate, stamp];
  });

  var sheet = SpreadsheetApp.getActive().getSheetByName('Rates') ||
              SpreadsheetApp.getActive().insertSheet('Rates');
  sheet.clear();
  sheet.getRange(1, 1, 1, 5)
       .setValues([['Pair', 'From', 'To', 'Rate', 'Updated (UTC)']])
       .setFontWeight('bold');
  sheet.getRange(2, 1, rows.length, 5).setValues(rows);
}

Dos detalles que diferencian esto de los scripts que encontrarás en otros sitios. Primero, una sola llamada a setValues(), no una por celda: las escrituras de rango por lotes son muchísimo más rápidas. Segundo, una petición fallida sale de la función en lugar de vaciar la tabla, de modo que un tropiezo del proveedor deja tipos antiguos pero etiquetados como tales, en vez de una hoja llena de blancos que convierte en silencio todos los totales posteriores en cero.

Crear el activador

function installTrigger() {
  ScriptApp.getProjectTriggers().forEach(function (t) {
    if (t.getHandlerFunction() === 'refreshRates') ScriptApp.deleteTrigger(t);
  });
  ScriptApp.newTrigger('refreshRates').timeBased().everyHours(1).create();
}

Google documenta que los activadores temporales se ejecutan "con una frecuencia de hasta cada minuto o tan espaciada como una vez al mes", y que la hora de disparo se difumina deliberadamente: "si creas un activador recurrente a las 9:00, Apps Script elige una hora entre las 9:00 y las 10:00". Si usas everyMinutes(n), n debe ser 1, 5, 10, 15 o 30; no se acepta ningún otro valor.

Leer los tipos

=XLOOKUP("USD_EUR", Rates!A:A, Rates!D:D)
=A2 * XLOOKUP($B$1 & "_" & $C$1, Rates!A:A, Rates!D:D)

Ahora todas las conversiones del libro se resuelven al instante desde celdas locales, usan un mismo tipo coherente y llevan una marca de tiempo visible. Ese último punto es el que preguntan los auditores.


Cuotas y límites con los que realmente te vas a topar

Estas son las cifras publicadas por Google para Apps Script; conviene conocerlas antes de diseñar en torno a ellas:

LímiteCuenta de consumidor (gmail.com)Cuenta de Google Workspace
Llamadas de URL Fetch20.000 / día100.000 / día
Tiempo total de ejecución de activadores90 min / día6 h / día
Lecturas/escrituras de propiedades50.000 / día500.000 / día
Tiempo de ejecución de funciones personalizadas30 s / ejecución30 s / ejecución
Tiempo de ejecución del script6 min / ejecución6 min / ejecución
Activadores por usuario y script2020
Longitud de URL en URL Fetch2 KB / llamada2 KB / llamada
Ese tope de 2 KB en la URL es el techo práctico para la cantidad de pares que puedes meter en un único lote ?q=: bastante más de cien, pero no ilimitados.

Del lado de la API, el plan gratuito de Finexly permite 1.000 solicitudes al mes a 10 solicitudes por minuto. Un activador horario consume alrededor de 730 solicitudes al mes, dentro del nivel gratuito y con margen de sobra. Añade un puñado de llamadas puntuales a funciones personalizadas y puede que te interese el plan Starter; los niveles actuales están en la página de precios. Ten en cuenta que los tipos históricos requieren un plan de pago, así que si necesitas tipos con fecha retroactiva y presupuesto cero, GOOGLEFINANCE sigue siendo la respuesta honesta para uso personal y no profesional.

Todas las respuestas incluyen las cabeceras X-RateLimit-Limit, X-RateLimit-Used y X-RateLimit-Units, así que puedes registrar el consumo desde res.getAllHeaders() y ver venir un límite.


Errores habituales y cómo solucionarlos

Lo que vesCausaSolución
#N/A de GOOGLEFINANCEPar no admitido o mal escrito, o datos históricos solicitados a través de Apps Script / la API de SheetsComprueba ambos códigos ISO; para automatizar, usa una API en su lugar
#ERROR! con "Exceeded maximum execution time (line 0)."Demasiadas llamadas individuales a funciones personalizadasCambia al patrón por lotes FX_CONVERT_RANGE
Loading... para siempreNOW(), RAND() u otra función volátil pasada como argumento de una función personalizadaQuítala: Google documenta que no está admitida
401 UNAUTHORIZED / invalid tokenClave de API ausente o incorrectaConfirma que la propiedad del script está definida y que la cabecera dice Bearer <key>
429 RATE_LIMIT_EXCEEDEDSe ha alcanzado el tope por minuto o mensualAlarga el TTL de la caché, agrupa más pares por llamada o amplía el plan
You do not have permission to call X service.Una función personalizada llamó a un servicio que requiere autorizaciónTraslada esa lógica a una función ejecutada por un activador
La fórmula histórica derrama columnas de másComportamiento documentado: los resultados históricos se devuelven como matriz con encabezadosEnvuélvela en INDEX(..., 2, 2)
Para patrones más avanzados sobre reintentos, backoff e invalidación de caché en producción, consulta nuestra guía sobre cacheo y gestión de errores en las API de divisas.


¿Qué método deberías usar?

  • Hoja personal, consulta rápida, sin dinero en juego: GOOGLEFINANCE. Es gratis, instantáneo y la restricción de licencia no te afecta.
  • Una columna de conversión en una hoja de cálculo de trabajo: la función personalizada de Apps Script con procesamiento por lotes. Fuente de datos predecible, sin ambigüedad de licencia, una llamada por rango.
  • Cualquier cosa que lea un compañero, un cliente o un auditor: la tabla de tipos programada. Un tipo por ciclo de actualización, una marca de tiempo visible y ninguna dependencia de cuándo decida recalcular Sheets.

¿Trabajas en Excel en su lugar? Los métodos equivalentes —Power Query, WEBSERVICE y el tipo de datos Monedas— se cubren en cómo obtener tipos de cambio en tiempo real en Excel. Si todavía estás evaluando proveedores, nuestra comparativa de API de divisas expone las diferencias, y puedes contrastar cualquier tipo con el conversor de divisas de Finexly.


Preguntas frecuentes

¿Cómo obtengo tipos de cambio en tiempo real en Google Sheets gratis?

=GOOGLEFINANCE("CURRENCY:USDEUR") no cuesta nada y no requiere configuración. Ten presente la restricción de uso que declara Google —los datos "no están destinados al uso profesional del sector financiero ni al uso por parte de otros profesionales de empresas no financieras"— y que los valores históricos no se pueden leer mediante Apps Script ni la API de Sheets. Como alternativa con licencia y coste cero, un nivel gratuito de API de 1.000 solicitudes al mes cubre holgadamente una actualización horaria (unas 730 llamadas).

¿Con qué frecuencia actualiza GOOGLEFINANCE los tipos de cambio?

La tabla del descargo de responsabilidad de Google Finance indica un retraso de 3 minutos para los datos de divisas, suministrados por Morningstar; no los 20 minutos que suelen repetirse en internet, que son la cifra genérica de cotización de valores asociada al atributo "price". Por otro lado, Google nunca ha publicado con qué frecuencia recalcula Sheets la fórmula, así que la antigüedad del número de tu celda no es algo en lo que puedas confiar.

¿Puedo usar GOOGLEFINANCE dentro de Apps Script?

Para datos históricos, no. Google afirma: "Los datos históricos no se pueden descargar ni consultar a través de la API de Sheets ni de Apps Script. Si lo intentas, verás un error #N/A". Tampoco existe ningún método GOOGLEFINANCE en ningún servicio de Apps Script: un script solo puede leer un valor que una celda ya haya calculado. Si necesitas los tipos en código, llama a una API de divisas con UrlFetchApp.

¿Por qué mi fórmula de divisas en Google Sheets va lenta o muestra #ERROR!?

Cada llamada a una función personalizada es una ida y vuelta independiente al servidor de Apps Script, y cada ejecución está limitada a 30 segundos. Cientos de llamadas individuales acabarán en tiempo de espera agotado. Acepta un rango y devuelve una matriz para que una sola llamada cubra toda la columna, cachea el tipo y, para cualquier cosa programada, mueve la petición a un activador temporal en lugar de a una celda.

¿Puedo obtener tipos de cambio históricos en Google Sheets?

Sí, de dos formas. GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,1), DATE(2026,1,31), "DAILY") devuelve una serie diaria: usa "close", ya que "price" no es un atributo histórico válido, y recuerda que Google trata las fechas como mediodía UTC, lo que puede desplazar un valor un día. O bien extrae tipos históricos de una API con un plan de pago y escríbelos en una hoja mediante un activador, que es la única vía que sobrevive a la automatización.


¿Listo para poner tipos de cambio con licencia y actualizados al minuto en tu hoja de cálculo? Consigue tu clave gratuita de la API de Finexly: sin tarjeta de crédito. Empieza con 1.000 solicitudes al mes en más de 170 divisas y amplía cuando tus hojas se te queden pequeñas.

Vlado Grigirov

Senior Currency Markets Analyst & Financial Strategist

Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...

View full profile →