المدونة/للمطورين

كيف يعمل مخطط سعر الذهب المباشر؟

تعرّف على كيفية جمع مخطط سعر الذهب المباشر بين السعر الفوري وأشرطة OHLC والطوابع الزمنية بتوقيت UTC والاستطلاع المنضبط، مع مثال TypeScript يعمل عبر SVG.

للمطورين
اللغة:
العربية

يُبنى مخطط سعر الذهب المباشر من مجموعتي بيانات مترابطتين: سعر فوري حالي للرقم الرئيسي، وأشرطة OHLC تاريخية للسلسلة المرسومة. يحمّل العميل نافذة من الأشرطة، ويرتبها زمنياً، ويرسم القيم، ثم يحدّث أحدث مشاهدة فقط. ويجب أن يوضح أيضاً ما إذا كان أحدث شريط لا يزال قيد التكوين.

هذا الفرق مهم. قد يتغير السعر الفوري بين شريطين، بينما يظل إغلاق الشريط الجاري مؤقتاً. إذا عوملت القيمتان بالطريقة نفسها، فقد تظهر نقاط مكررة أو طوابع زمنية مضللة أو خط يبدو أحدث من البيانات التي تغذيه.

الأجزاء الأربعة للمخطط المباشر

يحتاج معظم مخططات الذهب إلى أربعة عناصر:

  • رمز وفاصل زمني، مثل XAU-USD-SPOT و1d
  • نطاق أولي من أشرطة OHLC
  • سعر فوري حالي للرقم المعروض
  • حلقة تحديث تستبدل أحدث شريط بدلاً من إضافة كل استجابة

الرسم هو الخطوة الأخيرة فقط. قبلها يجب التحقق من الأرقام وترتيب المشاهدات والاحتفاظ بالطوابع الزمنية وتحديد طريقة عرض الشريط الجاري.

السعر الفوري والشريط يجيبان عن سؤالين مختلفين

تجيب نقطة السعر الفوري عن سؤال «ما السعر المشتق الآن؟». أما الشريط اليومي فيعرض سعر الافتتاح والأعلى والأدنى والإغلاق ليوم محدد بتوقيت UTC.

GET https://api.goldprice.dev/v1/spot/XAU-USD-SPOT
GET https://api.goldprice.dev/v1/bars?symbol=XAU-USD-SPOT&interval=1d&from=2026-07-25&to=2026-08-23

تتضمن استجابة السعر الفوري الحقول price وcomputed_at وis_stale. استخدمها للرقم الرئيسي وحالة حداثته.

يتضمن كل شريط bar_start وopen وhigh وlow وclose وvolume وis_closed. يمكن أن تكون volume: null في أشرطة الذهب الفوري، لذلك لا تجعل الحجم شرطاً للرسم. ويعني is_closed: false أن الشريط لا يزال قيد التكوين وقد تتغير قيمه عند التحديث التالي.

تصل الأشرطة من الأحدث إلى الأقدم، بينما يتوقع الرسم عادةً أن يتحرك الزمن من اليسار إلى اليمين. لذلك رتّبها تصاعدياً قبل إنشاء النقاط.

تحميل البيانات وتجهيزها

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

type GoldBar = {
  bar_start: string;
  open: string | null;
  high: string | null;
  low: string | null;
  close: string | null;
  volume: string | null;
  is_closed: boolean;
};

type BarsResponse = {
  bars: GoldBar[];
  next_cursor: string | null;
};

type ChartPoint = {
  time: string;
  close: number;
  isClosed: boolean;
};

async function loadPoints(from: string, to: string): Promise<ChartPoint[]> {
  const url = new URL("https://api.goldprice.dev/v1/bars");
  url.search = new URLSearchParams({
    symbol: "XAU-USD-SPOT",
    interval: "1d",
    from,
    to,
  }).toString();

  const response = await fetch(url);
  if (!response.ok) throw new Error(`Gold bars failed: ${response.status}`);
  const page = (await response.json()) as BarsResponse;

  return page.bars
    .filter((bar) => bar.close !== null && Number.isFinite(Number(bar.close)))
    .map((bar) => ({
      time: bar.bar_start,
      close: Number(bar.close),
      isClosed: bar.is_closed,
    }))
    .sort((a, b) => Date.parse(a.time) - Date.parse(b.time));
}

يكفي طلب صفحة واحدة لمخطط يومي حديث. أما النطاق الأطول فعليه متابعة next_cursor حتى يجمع العدد المطلوب من المشاهدات أو يصبح المؤشر null.

تحويل النقاط إلى مسار SVG

يربط هذا المثال الزمن بالمحور الأفقي والسعر بالمحور العمودي. ويمكن تمرير المصفوفة نفسها لاحقاً إلى Canvas أو مكتبة رسوم دون تغيير قواعد جلب البيانات.

function linePath(points: ChartPoint[], width: number, height: number): string {
  if (points.length === 0) return "";
  const values = points.map((point) => point.close);
  const min = Math.min(...values);
  const span = Math.max(...values) - min || 1;

  return points.map((point, index) => {
    const x = points.length === 1 ? width / 2 : (index / (points.length - 1)) * width;
    const y = height - ((point.close - min) / span) * height;
    return `${index === 0 ? "M" : "L"} ${x.toFixed(2)} ${y.toFixed(2)}`;
  }).join(" ");
}

ضع القيمة الناتجة في خاصية d لعنصر <path> داخل SVG، وأضف role="img" ووصفاً واضحاً عبر aria-label.

<svg viewBox="0 0 720 280" role="img" aria-label="Gold price in US dollars">
  <path
    d={linePath(points, 720, 280)}
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
  />
</svg>

استبدال أحدث شريط بحسب الطابع الزمني

أشرطة OHLC متاحة عبر REST. استطلع /v1/bars/latest للحصول على أحدث شريط، سواء كان مستقراً أو جارياً. إذا كان bar_start مطابقاً لنقطة موجودة، استبدلها. أضف نقطة جديدة فقط عندما يتغير وقت البداية.

async function refreshLatest(current: ChartPoint[]): Promise<ChartPoint[]> {
  const response = await fetch(
    "https://api.goldprice.dev/v1/bars/latest?symbol=XAU-USD-SPOT&interval=1d",
    { cache: "no-store" },
  );
  if (!response.ok) throw new Error(`Latest bar failed: ${response.status}`);

  const { bar } = await response.json() as { bar: GoldBar | null };
  if (!bar || bar.close === null || !Number.isFinite(Number(bar.close))) return current;

  const next = { time: bar.bar_start, close: Number(bar.close), isClosed: bar.is_closed };
  const index = current.findIndex((point) => point.time === next.time);
  if (index === -1) return [...current, next].sort((a, b) => Date.parse(a.time) - Date.parse(b.time));

  const copy = current.slice();
  copy[index] = next;
  return copy;
}

شغّل التحديث بمؤقت منضبط، وأوقفه عندما تكون الصفحة مخفية، ولا تسمح بأكثر من طلب نشط. زيادة وتيرة الاستطلاع لا تجعل مشاهدة المصدر أحدث.

افصل السعر الرئيسي عن خط الرسم

يمكن تحديث السعر الرئيسي وخط الرسم بوتيرتين مختلفتين. اجلب /v1/spot/XAU-USD-SPOT بصورة مستقلة، واعرض computed_at الخاص به، واستخدم is_stale لإظهار حالة واضحة عند تقادم السعر. لا تستبدل وقت المشاهدة بوقت وصول الاستجابة إلى المتصفح.

type SpotQuote = {
  symbol: string;
  price: string;
  computed_at: string;
  is_stale: boolean;
};

async function loadSpot(): Promise<SpotQuote> {
  const response = await fetch(
    "https://api.goldprice.dev/v1/spot/XAU-USD-SPOT",
    { cache: "no-store" },
  );
  if (!response.ok) throw new Error(`Gold spot failed: ${response.status}`);
  return response.json() as Promise<SpotQuote>;
}

ماذا يحدث عند إغلاق السوق؟

من الطبيعي أن يبقى المخطط بلا تغيير. غياب مشاهدة جديدة ليس خطأ رسم. احتفظ بآخر سعر صالح مع computed_at الأصلي، وبآخر شريط مع bar_start وis_closed الحقيقيين. إذا احتاج التصميم إلى فترات تقويم فارغة، اعرضها كمساحة أو فجوات، لا كأسعار منسوخة تبدو كمشاهدات جديدة.

تنطبق القاعدة نفسها عند فشل الشبكة. اعرض آخر بيانات صالحة مع وقتها أو رسالة خطأ إذا لم تُحمّل أي بيانات. لا تخزّن استجابة HTTP فاشلة على أنها سعر يساوي صفراً.

قائمة فحص قبل الإطلاق

  • استخدم الرمز القياسي XAU-USD-SPOT
  • رتّب الأشرطة من الأقدم إلى الأحدث قبل الرسم
  • استبدل الشريط عند تطابق bar_start ولا تضف نقطة إلا عند وصول شريط جديد
  • وضّح أن is_closed: false يعني قيمة مؤقتة
  • اسمح بأن تكون volume فارغة
  • احتفظ بـcomputed_at وis_stale للسعر الفوري
  • امنع تداخل طلبات التحديث وتراجع بعد أخطاء HTTP
  • أبق مفاتيح API في الخادم عند استخدام طلبات موثقة

يصبح المخطط جديراً بالثقة عندما يمكن ربط كل نقطة بوقت مشاهدتها وحالتها. راجع دليل الأشرطة التاريخية لمعاملات الطلب والتقسيم إلى صفحات، ودليل WebSocket للفرق بين تدفق الأسعار وأشرطة OHLC.

مقالات ذات صلة

للمطورين

اختبار الذهب بالعملة المحلية رجعياً دون تحيز استباقي في أسعار الصرف

دمج أشرطة XAU/USD اليومية المستقرة مع أرصاد أسعار الصرف التاريخية لاختبار استراتيجية ذهب بعملة محلية رجعياً، دون استخدام أسعار لم تكن متاحة فعلياً في ذلك الوقت عن طريق الخطأ.

← اقرأ
للمطورين

إضافة أداة سعر ذهب مباشر إلى WordPress

أضف أداة سعر ذهب مباشر مجانية وقابلة للتخصيص إلى WordPress بإطار iframe واحد. تعمل في Gutenberg و Elementor — بلا مفتاح API وبلا إضافة.

← اقرأ
للمطورين

بناء حاسبة أسعار مجوهرات الذهب باستخدام JavaScript

بناء حاسبة أسعار مجوهرات الذهب من أسعار القيراط الحية لكل غرام، بحساب عشري دقيق، وتخزين مؤقت، وهوامش ربح، وحدود تقييم واضحة.

← اقرأ

goldprice.dev

أسعار الذهب اللحظية، بيانات OHLC التاريخية، وتجميع متعدد المصادر — متاحة عبر REST و SSE.