كيف تحصل على أسعار صرف حيّة في Google Sheets (GOOGLEFINANCE وApps Script وواجهة برمجية للعملات)
الحصول على أسعار صرف حيّة في Google Sheets يبدو مشكلة محلولة سلفًا. تكتب =GOOGLEFINANCE("CURRENCY:USDEUR")، فيظهر رقم، وتمضي في طريقك. هذا كافٍ تمامًا لميزانية سفر شخصية، لكنه يتوقف عن العمل في اللحظة التي يغذّي فيها الجدول فاتورةً، أو دورة رواتب، أو تقرير إيرادات، أو أي شيء سيبني عليه زميل قرارًا — بسبب قيد ترخيصي، وسلوك موثّق غريب في التعامل مع التواريخ، وقيد في Apps Script لا يكاد يذكره أي شرح.
يغطي هذا الدليل الطرق العملية الثلاث جميعها — الدالة المدمجة GOOGLEFINANCE، ودالة مخصّصة في Apps Script تعتمد على واجهة برمجية للعملات، وجدول أسعار مجدول يُحدَّث عبر مُشغّل زمني — مع أرقام الحصص الحقيقية، والصياغة الحرفية لتحفّظات Google نفسها، وشيفرة قابلة للتشغيل. كل ما يرد أدناه عن سلوك Google مقتبس من وثائق Google الرسمية، وكل ما ليس موثّقًا يُشار إليه صراحةً على هذا الأساس.
الطرق الثلاث لجلب أسعار الصرف إلى Google Sheets
GOOGLEFINANCE | دالة مخصّصة في Apps Script | جدول أسعار مجدول | |
|---|---|---|---|
| وقت الإعداد | ثوانٍ | ~10 دقائق | ~20 دقيقة |
| هل يلزم مفتاح API | لا | نعم | نعم |
| التحديث | تلقائي، عند إعادة الحساب | عند إعادة الحساب | عبر مُشغّل تتحكم فيه أنت |
| الأسعار التاريخية | نعم (بتحفّظات) | حسب خطتك | نعم |
| يعمل في Apps Script / Sheets API | التاريخية: لا | نعم | نعم |
| الاستخدام التجاري / المهني | مقيّد بشروط Google | يخضع لشروط مزوّد الواجهة البرمجية لديك | يخضع لشروط مزوّد الواجهة البرمجية لديك |
| الأنسب لـ | عمليات بحث سريعة، جداول شخصية | أعمدة تحويل عابرة | أي شيء يعتمد عليه شخص آخر |
الطريقة 1: GOOGLEFINANCE — وماذا تقول Google عنها بالضبط
صيغة العملات الأساسية
النمط الذي تعلّمه كل الشروحات هو رمز CURRENCY: مكوَّن من رمزَي عملة ISO 4217 متلاصقين:
=GOOGLEFINANCE("CURRENCY:USDEUR")لتحويل مبلغ في الخلية A2:
=A2 * GOOGLEFINANCE("CURRENCY:USDEUR")لتكوين الزوج من خليتين تحتويان رمزَي العملة:
=GOOGLEFINANCE("CURRENCY:" & B2 & C2)تحفّظ صريح لا يذكره أي مقال منافس: صيغة الرمز CURRENCY:XXXYYY لا ترد في أي موضع من وثائق GOOGLEFINANCE الرسمية. التوقيع الموثّق هو GOOGLEFINANCE(ticker, [attribute], [start_date], [end_date|num_days], [interval])، والمحتوى الوحيد المتعلق بالعملات في صفحة المساعدة هو سمة "currency" (العملة التي تُسعَّر بها ورقة مالية) ومثال على رسم بياني. صيغة زوج CURRENCY: تعمل، وتعمل منذ سنوات، لكنها سلوك أرسته المجتمعات التقنية، لا عقد موثّق — أي أن Google حرة في تغييرها دون إشعار إيقاف مسبق. كما أن Google لا تنشر أي قائمة بأزواج العملات المدعومة، لذا فأي مقال يخبرك بأنها تدعم "نحو 50 عملة" إنما يخمّن.
الأسعار التاريخية: قاعدة السمات التي يخطئ فيها الجميع
مرِّر تاريخًا فتحصل على بيانات تاريخية:
=GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,15))=GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,1), DATE(2026,1,31), "DAILY")انتبه إلى السمة. توثّقها Google بوضوح: "إذا حُدِّد أي من معاملات التاريخ، فإن الطلب يُعدّ تاريخيًا ولا يُسمح إلا بالسمات التاريخية." والسمات التاريخية هي open وclose وhigh وlow وvolume وall — و"price" ليست منها. فـ"price" موثّقة بوصفها سمة لحظية فقط ("عرض سعر لحظي، بتأخير يصل إلى 20 دقيقة").
اذهب الآن وتفحّص أعلى الشروحات ترتيبًا عن العملات في Google Sheets: معظمها يقدّم لك GOOGLEFINANCE("CURRENCY:USDEUR", "price", DATE(...)). هذا المزيج يناقض وثائق Google نفسها. استخدم "close".
وثمة سلوكان موثّقان آخران يستحقان أن يترسّخا في ذهنك:
- "إذا حُدِّد
start_dateولم يُحدَّدend_date|num_days، تُعاد بيانات ذلك اليوم الواحد فقط." - "تُعاد النتائج اللحظية كقيمة داخل خلية واحدة. أما البيانات التاريخية، ولو ليوم واحد، فتُعاد كمصفوفة موسَّعة مع عناوين أعمدة." ولهذا فإن صيغة تاريخية تبدو صحيحة تسكب عمودين وصف عناوين في تخطيطك المرتّب، ولهذا تحتاج عادةً إلى تغليفها بـ
INDEX(...,2,2).
إزاحة منتصف النهار بتوقيت UTC
هذه تُفسد بصمت التقارير المطابَقة بالتاريخ. حرفيًا من Google:
"تتعامل Google مع التواريخ المُمرَّرة إلى GOOGLEFINANCE على أنها منتصف النهار بتوقيت UTC. أما البورصات التي تُغلق قبل ذلك الوقت فقد تُزاح بمقدار يوم."
إذا كنت تسوّي دفترًا محاسبيًا يجب أن يستخدم فيه كل سطر سعر الصرف الخاص بتاريخ القيد، فإن إزاحة يوم واحد هي كسر تسوية حقيقي، لا مسألة تقريب. إن كان هذا وصفًا لجدولك، فاقرأ دليلنا عن أسعار الصرف والإقرار الضريبي قبل أن تعتمد مصفوفة GOOGLEFINANCE المسكوبة سجلًا تدقيقيًا.
التأخير 3 دقائق، لا 20
يكاد كل مقال في هذا الموضوع يخبرك بأن أسعار العملات في GOOGLEFINANCE "متأخرة حتى 20 دقيقة". هذا الرقم مصدره إخلاء المسؤولية العام الخاص بعروض أسعار الأوراق المالية المرتبط بالسمة "price". أما صفحة إخلاء المسؤولية في Google Finance فتنشر جدول تأخير لكل نوع أصل، والسطر الخاص بـالعملات — عالميًا، بتزويد من Morningstar — يذكر 3 دقائق. والعملات المشفّرة كذلك 3 دقائق.
إذن البيانات أطزج مما يظن الإنترنت. لكن ما لا تنشره Google هو عدد المرات التي يعيد فيها Sheets حساب الصيغة، وهو الرقم الذي يهمّك فعلًا — فسعر عمره 3 دقائق قابع في خلية لم يُعَد حسابها منذ الثلاثاء يبقى سعرَ يوم الثلاثاء. ومن يستشهد بفاصل زمني محدد لإعادة الحساب إنما يستشهد بشيء لم توثّقه Google قط.
للمقارنة، تُحدّث Finexly الأسعار كل دقيقة وتعيدها عند الطلب، فتكون الطزاجة دالةً على متى تطلب أنت، لا على متى يقرر الجدول إعادة الحساب. وإذا أردت فهم ما تعنيه كلمة "حيّ" لدى المزوّدين عمومًا، فراجع من أين تحصل واجهات أسعار الصرف على بياناتها.
قيد الاستخدام الذي لا يقتبسه أحد
هذه أهم فقرة في المقال، ولا ترد في أي من الشروحات المتصدّرة. من صفحة مساعدة GOOGLEFINANCE لدى Google، حرفيًا:
"قيود الاستخدام: البيانات ليست مخصّصة للاستخدام المهني في قطاع المال، ولا للاستخدام من قِبل مهنيين آخرين في شركات غير مالية (بما في ذلك الجهات الحكومية). وقد يخضع الاستخدام المهني لرسوم ترخيص إضافية من مزوّد بيانات خارجي."
ومن إخلاء مسؤولية Google Finance:
"أنت توافق على عدم نسخ أي بيانات أو معلومات واردة هنا أو تعديلها أو إعادة تنسيقها أو تنزيلها أو تخزينها أو إعادة إنتاجها أو إعادة معالجتها أو بثّها أو إعادة توزيعها، وعلى عدم استخدام أي من تلك البيانات أو المعلومات في مشروع تجاري دون الحصول على موافقة خطية مسبقة."
"لا تستطيع Google ضمان دقة أسعار الصرف المعروضة. وينبغي لك التأكد من الأسعار الحالية قبل إجراء أي معاملات قد تتأثر بتغيّرات أسعار الصرف."
اقرأ ذلك في ضوء ما يفعله جدولك فعليًا. تسعير فاتورة عميل، أو تحويل فواتير المورّدين لفريق الحسابات، أو تصدير رقم إيراد محوَّل إلى تقرير ترسله إلى عميل — ليس أيٌّ من ذلك "أغراضًا معلوماتية" بالبداهة. واجهة برمجية مرخّصة لأسعار الصرف تُنهي السؤال من أصله، وهذا — لا الدقة في ذاتها — هو السبب الحقيقي وراء هجرة فرق المالية من GOOGLEFINANCE.
والعائق القاطع
"لا يمكن تنزيل البيانات التاريخية أو الوصول إليها عبر Sheets API أو Apps Script. وإذا حاولت ذلك، فسترى خطأ #N/A بدل القيم في الخلايا المقابلة في جدول بياناتك."
في اللحظة التي تريد فيها أتمتة أي شيء — تصدير ليلي، أو سحب عبر Sheets API، أو سكربت يلتقط لقطة من الأسعار — تصبح بيانات GOOGLEFINANCE التاريخية خارج الحسبان بحكم التصميم. هذا هو الجدار الذي يدفع الناس إلى الطريقة الثانية.
الطريقة 2: دالة مخصّصة في Apps Script تعتمد على واجهة برمجية للعملات
الدالة المخصّصة هي دالة JavaScript في Apps Script تستدعيها من خلية كأي دالة مدمجة. وتؤكد Google صراحةً أن هذا يعمل مع طلبات الويب: فالدوال المخصّصة "لا يمكنها استدعاء سوى الخدمات التي لا تصل إلى بيانات شخصية"، وURL Fetch ضمن القائمة المسموح بها.
الخطوة 1: احصل على مفتاح API وخزّنه كما يجب
احصل على مفتاح مجاني من لوحة تحكم Finexly — 1,000 طلب شهريًا، دون بطاقة ائتمان. ثم، وهذا مهم: لا تكتبه مباشرة داخل الشيفرة. اثنان من أكثر شروحات العملات في Google Sheets ارتباطًا بروابط خارجية يلصقان مفتاح API مباشرة في السكربت، داخل ملف يسافر مع جدول البيانات إلى كل من تشاركه معه.
في محرّر Apps Script (الإضافات ← Apps Script)، شغّل هذا مرة واحدة من المحرّر لتخزين المفتاح في خصائص السكربت:
function storeApiKey() {
PropertiesService.getScriptProperties()
.setProperty('FINEXLY_API_KEY', 'YOUR_API_KEY');
}ثم احذف القيمة الحرفية من الملف بعد ذلك. لاحظ الحدود الموثّقة: قيمة الخاصية الواحدة محدودة بـ9 كيلوبايت، ومخزن الخصائص بـ500 كيلوبايت إجمالًا — وهو متّسع لمفتاح، لا مكان لتخزين البيانات مؤقتًا.
الخطوة 2: دالة مخصّصة لزوج واحد
/**
* 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;
}استخدمها في خلية:
=FX_RATE("USD","EUR")
=A2 * FX_RATE($B$1, $C$1)تعيد نقطة النهاية /v1/rate الاستجابة {"pair": "USD_EUR", "rate": 0.9215}. ومرجع المعاملات الكامل موجود في وثائق واجهة Finexly البرمجية.
الخطوة 3: عالج النطاق دفعةً واحدة — الجزء الذي يفوّته كل منافس
إليك وضع الفشل. توثّقه Google مباشرة:
"في كل مرة تُستخدم فيها دالة مخصّصة في جدول بيانات، يُجري Sheets استدعاءً منفصلًا لخادم Apps Script. وإذا احتوى جدول بياناتك على عشرات (أو مئات، أو آلاف!) من استدعاءات الدوال المخصّصة، فقد تصبح هذه العملية بطيئة."
اسحب FX_RATE عبر 400 صف وستكون قد أجريت 400 رحلة ذهاب وإياب. ومع حدّ 30 ثانية لكل تنفيذ على الدوال المخصّصة، ستصطدم بـ#ERROR! مصحوبًا بالملاحظة Exceeded maximum execution time (line 0). قبل وقت طويل من استنفاد حصتك في الواجهة البرمجية.
الحل الذي توصي به Google هو التجميع في مصفوفات: اقبل نطاقًا، وأعِد مصفوفة. ونقطة النهاية /v1/convert لدى Finexly تقبل أزواجًا مفصولة بفواصل، فيصير العمود بأكمله طلب 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")صيغة واحدة، واستدعاء شبكي واحد، و399 رحلة ذهاب وإياب أقل. وإذا احتجت عدة أزواج دفعةً واحدة، فاستدعِ /v1/convert?q=USD_EUR,USD_GBP,USD_JPY واقرأ body["USD_EUR"].rate.
ماذا تقول Google فعلًا عن التخزين المؤقت في الدوال المخصّصة
استُخدم CacheService أعلاه، لكن لنكن دقيقين في السبب. دليل Google للدوال المخصّصة يصنّف خدمة Cache بأنها "تعمل، لكنها ليست مفيدة بشكل خاص في الدوال المخصّصة." فميزة التخزين المؤقت حقيقية فقط عبر عمليات تنفيذ منفصلة — أي عمليات إعادة الحساب المتكررة للزوج نفسه — لا داخل مصفوفة مسكوبة واحدة. التجميع في مصفوفات هو التحسين الموثّق؛ والتخزين المؤقت مكمّل مفيد.
حدود التخزين المؤقت الموثّقة: مفاتيح حتى 250 حرفًا، وقيم حتى 100 كيلوبايت، وسقف قدره 1,000 عنصر، ومدة صلاحية بين ثانية واحدة و21,600 ثانية (6 ساعات)، بقيمة افتراضية 600 ثانية. ولا توجد حصة يومية منشورة لاستدعاءات التخزين المؤقت.
ومصيدة موثّقة أخرى، لأن الحل الالتفافي منتشر على نطاق واسع: إضافة NOW() كوسيط لإجبار التحديث تُعطّل الدالة. تقول Google: "يجب أن تكون وسائط الدوال المخصّصة حتمية … وإذا حاولت دالة مخصّصة إعادة قيمة مبنية على إحدى هذه الدوال المدمجة المتقلّبة، فستعرض Loading... إلى ما لا نهاية."
الطريقة 3: جدول أسعار مجدول (نمط بيئة الإنتاج)
الدوال المخصّصة تعيد الحساب متى شاء Sheets، وهذه بالضبط الخاصية الخاطئة لجدول يقرأه شخص آخر. النمط المتين هو أن تتوقف عن الجلب من الخلايا كليًا: اكتب الأسعار في جدول وفق جدولة زمنية، ثم استخرجها بصيغ عادية.
سكربت التحديث
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);
}تفصيلان يميّزان هذا عن السكربتات التي ستجدها في أماكن أخرى. أولًا، استدعاء واحد لـsetValues()، لا استدعاء لكل خلية — فالكتابة المجمّعة على نطاق أسرع بفارق هائل. ثانيًا، الطلب الفاشل يخرج مبكرًا بدل أن يمسح الجدول، فتعثّرٌ لدى المزوّد يترك أسعارًا قديمة لكنها موسومة بذلك، بدل جدول مليء بالفراغات يحوّل بصمت كل مجموع لاحق إلى صفر.
إنشاء المُشغّل
function installTrigger() {
ScriptApp.getProjectTriggers().forEach(function (t) {
if (t.getHandlerFunction() === 'refreshRates') ScriptApp.deleteTrigger(t);
});
ScriptApp.newTrigger('refreshRates').timeBased().everyHours(1).create();
}توثّق Google أن المُشغّلات الزمنية تعمل "بتواتر يصل إلى كل دقيقة أو يقلّ إلى مرة واحدة شهريًا"، وأن وقت الإطلاق يُموَّه عمدًا: "إذا أنشأت مُشغّلًا متكررًا في الساعة 9 صباحًا، فسيختار Apps Script وقتًا بين 9 و10 صباحًا." وإذا استخدمت everyMinutes(n)، فإن n يجب أن تكون 1 أو 5 أو 10 أو 15 أو 30 — ولا تُقبل أي قيمة أخرى.
قراءة الأسعار
=XLOOKUP("USD_EUR", Rates!A:A, Rates!D:D)
=A2 * XLOOKUP($B$1 & "_" & $C$1, Rates!A:A, Rates!D:D)الآن كل تحويل في المصنّف يُحسم فورًا من خلايا محلية، ويستخدم سعرًا واحدًا متسقًا، ويحمل ختمًا زمنيًا ظاهرًا. وهذه النقطة الأخيرة تحديدًا هي ما يسأل عنه المدقّقون.
الحصص والحدود التي ستصطدم بها فعلًا
هذه أرقام Apps Script التي تنشرها Google — يجدر معرفتها قبل أن تصمّم نظامك حولها:
| الحد | حساب استهلاكي (gmail.com) | حساب Google Workspace |
|---|---|---|
| استدعاءات URL Fetch | 20,000 / يوم | 100,000 / يوم |
| إجمالي زمن تشغيل المُشغّلات | 90 دقيقة / يوم | 6 ساعات / يوم |
| قراءة/كتابة الخصائص | 50,000 / يوم | 500,000 / يوم |
| زمن تشغيل الدالة المخصّصة | 30 ثانية / تنفيذ | 30 ثانية / تنفيذ |
| زمن تشغيل السكربت | 6 دقائق / تنفيذ | 6 دقائق / تنفيذ |
| المُشغّلات لكل مستخدم لكل سكربت | 20 | 20 |
| طول عنوان URL في URL Fetch | 2 كيلوبايت / استدعاء | 2 كيلوبايت / استدعاء |
?q= واحدة — أكثر من مئة بارتياح، لكن ليس بلا حدود.على جانب الواجهة البرمجية، تتيح الخطة المجانية من Finexly 1,000 طلب شهريًا بمعدل 10 طلبات في الدقيقة. ومُشغّل يعمل كل ساعة يستهلك نحو 730 طلبًا شهريًا — داخل الطبقة المجانية مع فائض مريح. أضف حفنة من استدعاءات الدوال المخصّصة العابرة وقد ترغب في خطة Starter؛ والطبقات الحالية موجودة في صفحة الأسعار. ولاحظ أن الأسعار التاريخية تتطلب خطة مدفوعة، فإن كنت تحتاج أسعارًا بأثر رجعي وميزانيتك صفر، تبقى GOOGLEFINANCE الإجابة الصادقة للاستخدام الشخصي غير المهني.
كل استجابة تحمل الترويسات X-RateLimit-Limit وX-RateLimit-Used وX-RateLimit-Units، فيمكنك تسجيل الاستهلاك من res.getAllHeaders() ورؤية الحد قادمًا قبل أن يصلك.
الأخطاء الشائعة وكيفية إصلاحها
| ما تراه | السبب | الحل |
|---|---|---|
#N/A من GOOGLEFINANCE | زوج غير مدعوم أو مكتوب خطأً، أو بيانات تاريخية مطلوبة عبر Apps Script / Sheets API | تحقّق من رمزَي ISO كليهما؛ وللأتمتة، استخدم واجهة برمجية بدلًا من ذلك |
#ERROR! مع "Exceeded maximum execution time (line 0)." | عدد مفرط من استدعاءات الدوال المخصّصة الفردية | انتقل إلى نمط FX_CONVERT_RANGE المجمَّع |
Loading... إلى ما لا نهاية | تمرير NOW() أو RAND() أو دالة متقلّبة أخرى كوسيط لدالة مخصّصة | احذفها — توثّق Google ذلك بوصفه غير مدعوم |
401 UNAUTHORIZED / invalid token | مفتاح API مفقود أو خاطئ | تأكّد من ضبط خاصية السكربت وأن الترويسة تنص على Bearer <key> |
429 RATE_LIMIT_EXCEEDED | بلوغ السقف الدقيقي أو الشهري | أطِل مدة صلاحية التخزين المؤقت، أو اجمع أزواجًا أكثر في الاستدعاء الواحد، أو ارتقِ بخطتك |
You do not have permission to call X service. | دالة مخصّصة استدعت خدمة تتطلب تفويضًا | انقل ذلك المنطق إلى دالة تعمل عبر مُشغّل |
| الصيغة التاريخية تسكب أعمدة إضافية | سلوك موثّق — النتائج التاريخية تُعاد كمصفوفة مع عناوين | غلّفها بـINDEX(..., 2, 2) |
أي طريقة ينبغي أن تستخدم؟
- جدول شخصي، بحث سريع، ولا مال على المحك:
GOOGLEFINANCE. مجانية وفورية، وقيد الترخيص لا يمسّك. - عمود تحويل داخل جدول عمل فعلي: الدالة المخصّصة المجمَّعة في Apps Script. مصدر بيانات يمكن التنبؤ به، ولا لبس ترخيصي، واستدعاء واحد لكل نطاق.
- أي شيء يقرأه زميل أو عميل أو مدقّق: جدول الأسعار المجدول. سعر واحد لكل دورة تحديث، وختم زمني ظاهر، ولا اعتماد على متى يقرر Sheets إعادة الحساب.
تعمل في Excel بدلًا من ذلك؟ الطرق المكافئة — Power Query وWEBSERVICE ونوع بيانات العملات — مشروحة في كيف تحصل على أسعار صرف حيّة في Excel. وإن كنت لا تزال توازن بين المزوّدين، فإن مقارنة واجهات العملات البرمجية لدينا تعرض الفروق، ويمكنك التحقق من صحة أي سعر عبر محوّل العملات من Finexly.
الأسئلة الشائعة
كيف أحصل على أسعار صرف حيّة في Google Sheets مجانًا؟
=GOOGLEFINANCE("CURRENCY:USDEUR") لا تكلّف شيئًا ولا تحتاج أي إعداد. لكن انتبه إلى قيد الاستخدام الذي تنص عليه Google — فالبيانات "ليست مخصّصة للاستخدام المهني في قطاع المال، ولا للاستخدام من قِبل مهنيين آخرين في شركات غير مالية" — وإلى أن القيم التاريخية لا يمكن قراءتها عبر Apps Script أو Sheets API. وللحصول على بديل مرخّص بتكلفة صفرية، فإن طبقة API مجانية بحدّ 1,000 طلب شهريًا تغطّي تحديثًا كل ساعة (نحو 730 استدعاءً) بارتياح.
كل كم تحدّث GOOGLEFINANCE أسعار العملات؟
يذكر جدول إخلاء المسؤولية في Google Finance تأخيرًا قدره 3 دقائق لبيانات العملات، مصدرها Morningstar — لا الـ20 دقيقة الشائع تكرارها على الإنترنت، وهي الرقم العام الخاص بعروض أسعار الأوراق المالية والمرتبط بالسمة "price". وبمعزل عن ذلك، لم تنشر Google قط عدد المرات التي يعيد فيها Sheets حساب الصيغة، لذا فإن عمر الرقم في خليتك ليس أمرًا يمكنك الاعتماد عليه.
هل يمكنني استخدام GOOGLEFINANCE داخل Apps Script؟
ليس للبيانات التاريخية. تقول Google: "لا يمكن تنزيل البيانات التاريخية أو الوصول إليها عبر Sheets API أو Apps Script. وإذا حاولت ذلك، فسترى خطأ #N/A." كما لا توجد أي دالة GOOGLEFINANCE في أي خدمة من خدمات Apps Script — فالسكربت لا يمكنه إلا قراءة قيمة حسبتها الخلية سلفًا. وإذا احتجت الأسعار داخل الشيفرة، فاستدعِ واجهة برمجية للعملات باستخدام UrlFetchApp.
لماذا صيغة العملات لديّ في Google Sheets بطيئة أو تعرض #ERROR!؟
كل استدعاء لدالة مخصّصة هو رحلة ذهاب وإياب منفصلة إلى خادم Apps Script، وكل تنفيذ محدود بـ30 ثانية. ومئات الاستدعاءات الفردية ستنتهي مهلتها. اقبل نطاقًا وأعِد مصفوفة ليغطي استدعاء واحد العمود بأكمله، وخزّن السعر مؤقتًا، وفي أي شيء مجدول انقل الجلب إلى مُشغّل زمني بدل خلية.
هل يمكنني الحصول على أسعار صرف تاريخية في Google Sheets؟
نعم، بطريقتين. GOOGLEFINANCE("CURRENCY:USDEUR", "close", DATE(2026,1,1), DATE(2026,1,31), "DAILY") تعيد سلسلة يومية — استخدم "close"، لأن "price" ليست سمة تاريخية صالحة، وتذكّر أن Google تتعامل مع التواريخ على أنها منتصف النهار بتوقيت UTC، وهو ما قد يزيح قيمةً بمقدار يوم. أو اسحب الأسعار التاريخية من واجهة برمجية بخطة مدفوعة واكتبها في جدول عبر مُشغّل، وهذا هو المسار الوحيد الذي يصمد أمام الأتمتة.
هل أنت مستعد لوضع أسعار صرف مرخّصة ومحدّثة كل دقيقة في جدول بياناتك؟ احصل على مفتاح Finexly API المجاني — دون بطاقة ائتمان. ابدأ بـ1,000 طلب شهريًا عبر أكثر من 170 عملة، وارتقِ بخطتك حين تضيق جداولك بها.
Explore More
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 →