شروحاتجداول البيانات

كيفية جلب أسعار الذهب المباشرة في Google Sheets

اجلب أسعار الذهب المباشرة والتاريخية إلى Google Sheets دون تخزين مفتاح API، وقارنها بسعر مرجعي، وحدّثها بأمان كل 4 ساعات.

8 سبتمبر 2026 · وقت القراءة: 8 دقائق

تُرجع =GOLDPRICE() سعر XAU/USD المباشر للأونصة التروي من goldprice.dev في أي خلية بعد إضافة Apps Script. تتأخر الأسعار المجانية 15 دقيقة. لا تقرأ IMPORTDATA نقطة النهاية هذه بصيغة JSON، لذا تحتاج إلى دالة مخصصة. تُرجع GOLDHISTORY() الإغلاقات اليومية لمدة 30 يومًا، وتُرجع GOLDPRICEDELTA() فرق السعر ونسبته بإشارتيهما مقابل خلية مرجعية موحّدة العملة والوحدة. لا يُخزّن مفتاح API. شغّل installGoldRefresh() مرة لربط خلية تحديث وإنشاء مشغّل كل أربع ساعات ضمن الحصة.

ابدأ دون وضع مفتاح API في جدول البيانات

تعمل نقطة نهاية السعر الفوري لـXAU وسجل الإغلاقات اليومية لمدة 30 يومًا دون تسجيل، لذا لا يخزّن هذا الشرح بيانات اعتماد في Apps Script. يخضع الوصول المجهول لحدود Free: ‏10 طلبات في الدقيقة، و100 في الساعة، و5,000 شهريًا لكل IP. يبقى التحديث كل أربع ساعات ضمن هذه الحدود.

قد يشترك مستخدمو Sheets في عنوان خروج لدى Google، فتتفاوت السعة المجهولة. لحصة ثابتة على مستوى الحساب في مصنف مشترك أو إنتاجي، استخدم وسيطًا على خادمك واحتفظ بمفتاح goldprice.dev هناك. لا تلصق رمز bearer في سكربت مرتبط يستطيع المحررون فحصه. يمنح المفتاح المجاني الحصة الشهرية نفسها، 5,000 استدعاء، لحسابك بدل عنوان IP مشترك.

احصل على حصة طلبات خاصة بك

تعمل الخطوات أدناه دون مفتاح. يمنحك مفتاح API مجاني حصة طلبات خاصة بك. يتطلب السجل الأطول والحدود الأعلى خططًا مدفوعة.

أضف دوال أسعار الذهب الثلاث إلى Apps Script

افتح جدولك واختر الإضافات → Apps Script. احذف function myFunction() {} والصق الكود أدناه. يعرّف GOLDPRICE(metal, currency, refreshToken) للسعر الفوري، وGOLDHISTORY(fromDate, toDate, refreshToken) للإغلاقات اليومية الجاهزة للرسم، وGOLDPRICEDELTA(referencePrice, metal, currency, refreshToken) لفرق السعر ونسبته بإشارتيهما. تخزّن الدوال الطلبات المتطابقة مؤقتًا عبر CacheService، ولا ترسل ترويسة Authorization، وتُرجع الأخطاء كنصوص بدل إطلاق استثناءات.

لجمع الكميات وتكاليف الشراء والتقييمات التقريبية في مصنف واحد، استخدم قالب تتبّع محفظة الذهب.

Code.gs
// google-sheets: Apps Script Code.gsconst SPOT_CACHE_TTL = 55; // Cache successful spot responses for 55 seconds.const BARS_CACHE_TTL = 300; // Cache successful daily bars for 5 minutes.const REFRESH_RANGE_NAME = 'GOLDPRICE_REFRESH_TOKEN';const SPREADSHEET_ID_KEY = 'GOLDPRICE_SPREADSHEET_ID';const INSTALLER_EMAIL_KEY = 'GOLDPRICE_INSTALLER_EMAIL';const LAST_REFRESH_AT_KEY = 'GOLDPRICE_LAST_REFRESH_AT';const MIN_REFRESH_INTERVAL_MS = 4 * 60 * 60 * 1000;/** * Returns the current spot price for a metal/currency pair. * @customfunction */function GOLDPRICE(metal, currency, refreshToken) {  const symbol = metal + '-' + currency + '-SPOT';  const cache = CacheService.getScriptCache();  const cacheKey = 'spot_' + symbol;  const cached = cache.get(cacheKey);  if (cached) return cached;  const url = `https://api.goldprice.dev/v1/spot/${symbol}`;  const resp = UrlFetchApp.fetch(url, {    muteHttpExceptions: true,  });  const code = resp.getResponseCode();  if (code === 401) return '#ACCESS_ERROR: use a server-side proxy';  if (code === 403) return '#PLAN_GATED: symbol not on your tier';  if (code === 429) return '#RATE_LIMIT: wait a minute and retry';  if (code !== 200) return '#ERROR_' + code;  const data = JSON.parse(resp.getContentText());  if (!data || !data.price) return '#NO_DATA';  // Price stays a string, same as the API wire format: Sheets displays and  // sorts it fine. Wrap in VALUE() if you need it in arithmetic.  cache.put(cacheKey, data.price, SPOT_CACHE_TTL);  return data.price;}/** * Compares live spot with a reference cell in the same currency and unit. * Spills [signed price delta, signed percentage delta] into two cells. * @customfunction */function GOLDPRICEDELTA(referencePrice, metal, currency, refreshToken) {  const reference = Number(referencePrice);  if (!Number.isFinite(reference) || reference <= 0) {    return [['#BAD_REFERENCE: enter a positive price', '']];  }  const liveResult = GOLDPRICE(metal, currency, refreshToken);  const live = Number(liveResult);  if (!Number.isFinite(live)) return [[liveResult, '']];  const signedDelta = live - reference;  return [[Number(signedDelta.toFixed(2)), signedDelta / reference]];}/** * Returns chart-ready daily closes for a date range. * @customfunction */function GOLDHISTORY(fromDate, toDate, refreshToken) {  const now = new Date();  const rollingFrom = new Date(now.getTime() - 29 * 24 * 60 * 60 * 1000);  const from = toIsoDate_(    fromDate === '' || fromDate == null ? rollingFrom : fromDate  );  const to = toIsoDate_(toDate === '' || toDate == null ? now : toDate);  if (!from || !to) return [['#BAD_DATE: put real dates in B2/B3']];  const cache = CacheService.getScriptCache();  const cacheKey = 'bars_' + from + '_' + to;  const cached = cache.get(cacheKey);  if (cached) return JSON.parse(cached);  const url = 'https://api.goldprice.dev/v1/bars?symbol=XAU-USD-SPOT&interval=1d'    + '&from=' + from + '&to=' + to;  const resp = UrlFetchApp.fetch(url, {    muteHttpExceptions: true,  });  const code = resp.getResponseCode();  if (code === 401) return [['#ACCESS_ERROR: use a server-side proxy']];  if (code === 403) return [['#PLAN_GATED: range not on your tier']];  if (code === 429) return [['#RATE_LIMIT: wait a minute and retry']];  if (code !== 200) return [['#ERROR_' + code]];  const data = JSON.parse(resp.getContentText());  const bars = Array.isArray(data.bars) ? data.bars : [];  if (bars.length === 0) return [['#NO_DATA: empty range']];  // /v1/bars returns bars newest-first; reverse to chronological order so  // a line chart built from this range reads left-to-right in time.  const rows = bars.slice().reverse().map(function (bar) {    return [bar.bar_start.slice(0, 10), Number(bar.close)];  });  cache.put(cacheKey, JSON.stringify(rows), BARS_CACHE_TTL);  return rows;}function installGoldRefresh() {  const lock = LockService.getScriptLock();  lock.waitLock(30000);  try {    const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();    if (!spreadsheet) throw new Error('Open the bound Google Sheet and run again');    const installerEmail = Session.getEffectiveUser().getEmail();    if (!installerEmail) throw new Error('Run the installer from your Google account');    const properties = PropertiesService.getScriptProperties();    const existingInstaller = properties.getProperty(INSTALLER_EMAIL_KEY);    if (existingInstaller && existingInstaller !== installerEmail) {      throw new Error('Gold refresh is already owned by another editor');    }    const refreshRange = spreadsheet.getActiveSheet().getRange('B1');    spreadsheet.setNamedRange(REFRESH_RANGE_NAME, refreshRange);    // getProjectTriggers() only returns this user's triggers. The shared    // installer-email claim above prevents a second editor from creating a    // second schedule, while this replacement keeps owner reruns idempotent.    ScriptApp.getProjectTriggers()      .filter(function (trigger) {        return trigger.getHandlerFunction() === 'refreshGoldData';      })      .forEach(function (trigger) {        ScriptApp.deleteTrigger(trigger);      });    ScriptApp.newTrigger('refreshGoldData')      .timeBased()      .everyHours(4)      .create();    properties.setProperties({      [SPREADSHEET_ID_KEY]: spreadsheet.getId(),      [INSTALLER_EMAIL_KEY]: installerEmail,    });  } finally {    lock.releaseLock();  }  refreshGoldData();}function uninstallGoldRefresh() {  const lock = LockService.getScriptLock();  lock.waitLock(30000);  try {    const properties = PropertiesService.getScriptProperties();    const installerEmail = Session.getEffectiveUser().getEmail();    const existingInstaller = properties.getProperty(INSTALLER_EMAIL_KEY);    if (existingInstaller && existingInstaller !== installerEmail) {      throw new Error('Only the trigger owner can uninstall gold refresh');    }    ScriptApp.getProjectTriggers()      .filter(function (trigger) {        return trigger.getHandlerFunction() === 'refreshGoldData';      })      .forEach(function (trigger) {        ScriptApp.deleteTrigger(trigger);      });    properties.deleteProperty(SPREADSHEET_ID_KEY);    properties.deleteProperty(INSTALLER_EMAIL_KEY);    properties.deleteProperty(LAST_REFRESH_AT_KEY);  } finally {    lock.releaseLock();  }}function refreshGoldData(event) {  const lock = LockService.getScriptLock();  lock.waitLock(30000);  try {    // Clock triggers pass an event object, but they cannot supply the metal,    // currency, date-range, or reference arguments required by sheet formulas.    // This wrapper only changes the named token cell those formulas reference.    const properties = PropertiesService.getScriptProperties();    const spreadsheetId = properties.getProperty(SPREADSHEET_ID_KEY);    if (!spreadsheetId) throw new Error('Run installGoldRefresh first');    // Script properties and the script lock are shared across editors. This    // gate coalesces legacy triggers owned by different users into one refresh    // per four hours even though Apps Script cannot enumerate their triggers.    const now = Date.now();    const lastRefreshAt = Number(properties.getProperty(LAST_REFRESH_AT_KEY));    if (lastRefreshAt && now - lastRefreshAt < MIN_REFRESH_INTERVAL_MS) return;    const spreadsheet = SpreadsheetApp.openById(spreadsheetId);    const refreshRange = spreadsheet.getRangeByName(REFRESH_RANGE_NAME);    if (!refreshRange) throw new Error('Run installGoldRefresh to restore B1');    refreshRange.setValue(new Date(now).toISOString());    properties.setProperty(LAST_REFRESH_AT_KEY, String(now));  } finally {    lock.releaseLock();  }}function toIsoDate_(value) {  const d = value instanceof Date ? value : new Date(value);  if (isNaN(d.getTime())) return null;  return d.toISOString().slice(0, 10);}

اربط خلايا السعر والسجل والسعر المرجعي

ضع رمز تحديث في B1 وسعرًا مرجعيًا اختياريًا بوحدة USD للأونصة التروي في C1. اترك B2 وB3 فارغتين لسجل متحرك مدته 30 يومًا تقويميًا، أو أدخل تاريخين ثابتين. تُرجع GOLDPRICEDELTA() فرق السعر المباشر ناقص المرجعي ونسبته، مع الإشارة. تصح المقارنة فقط عند تطابق العملة والوحدة في الخليتين.

توضح Google أن أسعار GOOGLEFINANCE قد تتأخر حتى 20 دقيقة، وبعض العقود الآجلة غير مدعومة، ولا يمكن الوصول للسجل عبر Apps Script. وحّد السعر المرجعي إلى USD للأونصة التروي في C1؛ يوفّر goldprice.dev السعر الفوري والسجل برمجيًا. لا تمرّر NOW() أو TODAY() للدوال المخصصة؛ تحسب GOLDHISTORY() التواريخ المتحركة داخليًا عند ترك B2/B3 فارغتين.

صيغ Sheets · ربط B1/B2/B3/C1
// B1: رمز التحديث، تكتبه refreshGoldData()// B2/B3: اتركهما فارغتين لنطاق متحرك من 30 يوما تقويميا، أو أدخل تواريخ ثابتة// C1: سعر مرجعي اختياري محول إلى USD لكل أونصة تروي// السعر الفوري الحالي بعملة USD، يعاد حسابه عند تغير B1=GOLDPRICE("XAU", "USD", $B$1)// السعر الفوري المباشر ناقص C1: يملأ الخلايا بالقيم [الفرق بعملة USD مع الإشارة، الفرق النسبي مع الإشارة]// نسق خلية النتيجة الثانية كنسبة مئوية.=GOLDPRICEDELTA($C$1, "XAU", "USD", $B$1)// السعر الفوري الحالي بعملة EUR، تستخدم الصيغتان خلية رمز التحديث نفسها=GOLDPRICE("XAU", "EUR", $B$1)// أسعار الإغلاق اليومية لمدة 30 يوما، جاهزة للرسم البياني (التاريخ، الإغلاق)=GOLDHISTORY($B$2, $B$3, $B$1)

أنشئ مخططًا خطيًا من النتائج التاريخية

حدّد الصفوف التي ملأتها GOLDHISTORY()، ثم اختر إدراج → رسم بياني واختر مخطط خطي. يعتمد عدد الصفوف على الفترة المطلوبة والبيانات اليومية المتاحة. تعكس الدالة ترتيب بيانات API من الأحدث أولًا إلى الترتيب الزمني، فيمتد المحور الأفقي من الأقدم إلى الأحدث دون فرز إضافي.

أضف مشغّل تحديث كل 4 ساعات

اختر حساب Google واحدًا لامتلاك الجدول الزمني. إذا اتبع محررون الشرح القديم، فعلى كل منهم أولًا حذف مشغّل refreshGoldData الخاص به من Apps Script → المشغّلات. شغّل installGoldRefresh مرة وامنحه الإذن. يربط المثبّت B1 وينشئ مشغّلًا كل أربع ساعات. يدمج قفل وطابع زمني مشتركان المشغّلات القديمة التي يتعذر الوصول إليها في تحديث واحد كل أربع ساعات.

لنقل المسؤولية، يشغّل المالك uninstallGoldRefresh ثم يثبّت المالك الجديد المشغّل. عند تعذر الوصول للمالك، احذف إدخالات GOLDPRICE_* الثلاثة من إعدادات المشروع → خصائص السكربت ثم أعد التثبيت؛ يمنع الفاصل الزمني المشترك بين الصيغ تكرار الاستدعاءات. أربع صيغ × ستة تحديثات تعني بحد أقصى 24 استدعاءً يوميًا، ونحو 720 شهريًا، ضمن حدود Free المجهولة: 100 طلب/ساعة و5,000 شهريًا لكل IP.

النتيجة المتوقعة

JSON
{  "symbol": "XAU",  "quote_currency": "USD",  "unit": "troy_ounce",  "contract_type": "spot",  "price": "4012.75",  "is_stale": false,  "computed_at": "2026-10-23T07:00:18Z"}

تعرض GOLDPRICE حقل price أعلاه كنص، مثل "4012.75". تملأ GOLDPRICEDELTA خليتين بفرق السعر ونسبته العشرية مع الإشارة؛ نسّق الثانية كنسبة مئوية. تملأ GOLDHISTORY صفوف [date, close] المتاحة للفترة المطلوبة.

أخطاء شائعة

الرمزما يظهر لكالحل
401تعرض الخلية #ACCESS_ERROR: use a server-side proxyلم يُقبل الطلب المجهول. افحص Apps Script → عمليات التنفيذ أولًا. إذا احتاج المصنف إلى سعة موثّقة، فأرسل الطلب عبر وسيط على الخادم؛ لا تلصق مفتاحًا في السكربت المرتبط.
403تعرض الخلية #PLAN_GATED: symbol not on your tierتشمل Free الأسعار الفورية للذهب (XAU) والفضة (XAG) والنحاس (HG). تحقّق من الرمز؛ البلاتين والبلاديوم غير متاحين. راجع الأسعار.
429تعرض الخلية #RATE_LIMIT: wait a minute and retryبلغ عنوان IP المشترك أحد حدود Free: ‏10 طلبات/دقيقة، أو 100/ساعة، أو 5,000/شهر. يمنع التخزين المؤقت ذلك عادةً؛ ارفع ثوابت TTL، أو قلّل الصيغ المختلفة، أو أرسل الطلبات الموثّقة عبر وسيط على الخادم.
N/Aتعرض GOLDHISTORY الرسالة #BAD_DATE: put real dates in B2/B3تحتوي B2 أو B3 على نص لا يستطيع Apps Script تفسيره كتاريخ، مثل تسمية بدل قيمة. أدخل تواريخ فعلية، أو ارجع إلى خلايا منسّقة كتاريخ عبر تنسيق → رقم → تاريخ.
N/Aتعرض GOLDPRICEDELTA الرسالة #BAD_REFERENCE: enter a positive priceالخلية C1 فارغة، أو تحتوي نصًا، أو صفرًا، أو قيمة سالبة. أدخل سعرًا مرجعيًا موجبًا بالعملة نفسها وبوحدة الأونصة التروي المستخدمة في صيغة السعر الفوري.
N/Aتظل الخلية تعرض Loading…يحتاج Apps Script إلى إذن لجلب البيانات الخارجية. اختر اسم دالة من شريط أدوات المحرر وشغّلها يدويًا مرة لإظهار طلب الإذن، ثم وافق عليه.

خطوات إضافية

  • أنشئ صيغة تنبيه للسعر: =IF(GOLDPRICE("XAU","USD",$B$1) > 4800, "ALERT", "OK")
  • للسجل اليومي الأقدم، استخدم وسيطًا على الخادم بمفتاح: تشمل Basic سنة واحدة، وتشمل Plus وPro السجل الكامل
  • تتبّع الفضة إلى جانب الذهب في Free، باستخدام خلية رمز التحديث نفسها لكليهما
  • استخدم صفوف GOLDHISTORY الجاهزة للرسم في اختبار تاريخي، راجع اختبار استراتيجية ذهب على بيانات OHLC
  • اربط =GOLDPRICE(...) بنموذج تقييم أو تكلفة ليتحدّث بالبيانات المباشرة بدل قيمة ثابتة

أسئلة

كم مرة يتحدّث السعر؟

تتحدّث نقطة نهاية السعر الفوري كل 60 ثانية ببيانات مباشرة مرخّصة؛ تتأخر أسعار Free والوصول دون مفتاح 15 دقيقة، والمدفوعة مباشرة. تراعي ذاكرة GOLDPRICE هذه الوتيرة، فتُرجع الاستدعاءات المتكررة خلال TTL القيمة نفسها دون استهلاك استدعاء API جديد.

هل يناسب التحديث كل 4 ساعات الخطة المجانية؟

نعم. ترتبط أربع صيغ بخلية $B$1: استدعاءا GOLDPRICE واستدعاء لكل من GOLDPRICEDELTA وGOLDHISTORY. كل 4 ساعات يعني 6 مرات يوميًا × 4 استدعاءات = 24 يوميًا، ونحو 720 شهريًا. يقلّل التخزين المؤقت الإجمالي عادةً لأن GOLDPRICEDELTA يعيد استخدام طلب USD الفوري. يبقى ذلك دون الحدود المجهولة: 10 طلبات/دقيقة، و100/ساعة، و5,000/شهر لكل IP.

لماذا لا أستخدم GOOGLEFINANCE لسعر الذهب؟

يدعم GOOGLEFINANCE أوراقًا مالية وعملات محددة، ولا يوفّر API موثّقًا لسعر XAU/USD الفوري. تذكر Google أن الأسعار قد تتأخر حتى 20 دقيقة، وبعض العقود الآجلة غير مدعومة، والسجل غير متاح عبر Apps Script. استخدم GOLDPRICE() للفوري، وGOLDHISTORY() للسجل البرمجي، وGOLDPRICEDELTA() لمقارنة سعر مرجعي موحّد العملة والوحدة، دون افتراض تكافؤ الأداتين.

لماذا يستهدف المشغّل refreshGoldData بدل GOLDPRICE؟

يمرّر Apps Script كائن حدث زمني إلى المعالج المختار، لكنه لا يمرّر معاملات المعدن أو العملة أو الفترة أو السعر المرجعي اللازمة للصيغ. لذلك ينشئ installGoldRefresh() مشغّلًا للدالة refreshGoldData(event)، التي تكتب طابعًا زمنيًا جديدًا فقط في نطاق B1 المسمّى، فتُعيد الصيغ الأربع حساب نتائجها.

هل يمكنني مشاركة جدول البيانات مع محررين آخرين؟

نعم. يستخدم المثال وصولًا مجهولًا ولا يخزّن مفتاح API، فيستطيع المحررون فحص السكربت المرتبط أو نسخه دون الحصول على بيانات اعتماد. إذا احتاج المصنف لاحقًا إلى سعة موثّقة، فاحتفظ برمز bearer في وسيط على الخادم واجعل الجدول يستدعيه.

هل يمكنني استخدامه تجاريًا؟

نعم، يُسمح بالاستخدام التجاري في جميع الخطط. لا تتطلب الخطط المدفوعة رابط إسناد، بينما تتطلب Free وضع رابط ظاهر إلى goldprice.dev بالقرب من الأسعار المعروضة للمستخدم.

ما المعادن المدعومة؟

تتوفر الأسعار الفورية للذهب (XAU) والفضة (XAG) والنحاس (HG) في جميع الخطط، بما فيها Free. لا يتوفر البلاتين والبلاديوم في أي خطة. التفاصيل في مرجع API ضمن التوثيق.

هل الخطة المجانية مجانية فعلًا؟

نعم. يعمل سعر XAU الفوري وسجل يومي لمدة 30 يومًا دون مفتاح ضمن حدود Free: ‏10 طلبات/دقيقة، و100/ساعة، و5,000/شهر لكل IP. يمنح المفتاح المجاني الحصة الشهرية نفسها لحسابك، دون بطاقة أو انتهاء صلاحية، للتكاملات على الخادم.

هل يستطيع مساعد ذكاء اصطناعي مثل Claude كتابة هذا لي؟

نعم. وجّه Claude أو Cursor أو ChatGPT إلى خادم MCP لدى goldprice.dev أو llms.txt، واطلب: اكتب دوال Google Sheets مخصصة تستخدم api.goldprice.dev، ومثبّتًا لا يكرر الإعداد عند إعادة تشغيله، يربط خلية تحديث مسمّاة وينشئ مشغّلًا كل أربع ساعات. يقرأ المخطط الحالي، فيستخدم الكود أسماء الحقول ورموز الأخطاء الصحيحة من المحاولة الأولى.

هل يعمل Apps Script مع Excel؟

لا. لإعداد أسعار الذهب في Excel، راجع شرح Excel. يستخدم Excel لغة Power Query M، وتختلف خطوات إعداد الاتصال فيه عن الخطوات الخاصة بـApps Script.

تابع القراءة

ابدأ بمفتاح API مجاني

5,000 طلب شهريًا في الخطة المجانية. دون بطاقة ائتمان.

احصل على مفتاح مجاني