قائمة وثائق المطورين

قارن الأسواق جنبًا إلى جنب

متوسط

أنشئ جدول مقارنة بين مدن الخليج ومصر واحفظه بصيغة CSV.

الإعداد

يستخدم هذا الدرس الأداة المساعدة jokerprice.mjs من درس البدء السريع.

jokerprice.mjs
// jokerprice.mjs: a small client for the JokerPrice API (Node 18+).
const BASE = "https://jokerprice.com";
const KEY = process.env.JOKERPRICE_API_KEY;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

export async function api(path, { method = "GET", query = {}, body } = {}) {
  const url = new URL(BASE + path);
  for (const [name, value] of Object.entries(query)) url.searchParams.set(name, String(value));
  for (;;) {
    const res = await fetch(url, {
      method,
      headers: { Authorization: "Bearer " + KEY, ...(body ? { "Content-Type": "application/json" } : {}) },
      body: body ? JSON.stringify(body) : undefined,
    });
    const data = await res.json();
    if (res.status === 429 && data.error.code === "RATE_LIMIT") { await sleep(Number(res.headers.get("Retry-After") || 60) * 1000); continue; }
    if (!res.ok) throw new Error(res.status + " " + data.error.code + ": " + data.error.message);
    return data;
  }
}

اختر الأسواق

يغطي طلب واحد إلى /api/v1/markets العرض والأسعار وملخص التتبّع لآخر 90 ليلة لكل وجهة. اجلب التقرير الكامل فقط للمدن التي تريد تفاصيل غرف النوم فيها.

JavaScript (Node 18+)
import { api } from "./jokerprice.mjs";

const SLUGS = ["riyadh", "jeddah", "dubai", "doha", "cairo"];
const { markets } = await api("/api/v1/markets");
const known = new Set(markets.map(m => m.slug));
const chosen = SLUGS.filter(slug => known.has(slug));
console.log("Comparing", chosen.join(", "));

اجلب التقارير

JavaScript (Node 18+)
const reports = [];
for (const slug of chosen) reports.push((await api("/api/v1/markets/" + slug)).market);

const twoBed = m => m.bedrooms.find(b => b.bedrooms === 2)?.median ?? null;
const live = m => m.tracker && m.tracker.maturity === "estimating" ? m.tracker : null;
const rows = reports.map(m => ({
  market: m.name,
  listings: m.listings,
  median: Math.round(m.nightly.median ?? 0),
  spread: m.nightly.p75 && m.nightly.p25 ? +(m.nightly.p75 / m.nightly.p25).toFixed(2) : null,
  twoBedMedian: twoBed(m),
  topType: m.types[0]?.type ?? null,
  occupancy: live(m) ? +(live(m).occupancy * 100).toFixed(1) : null,
  adr: live(m) ? Math.round(live(m).adr) : null,
  revenuePerListing: live(m) ? Math.round(live(m).monthlyRevenuePerListing) : null,
}));
console.table(rows);

يمثل spread سعر المئين الخامس والسبعين مقسومًا على سعر المئين الخامس والعشرين، والقيمة المرتفعة تعني سوقًا بفئات أسعار متباينة جدًا.

احفظها بصيغة CSV

JavaScript (Node 18+)
import { writeFileSync } from "node:fs";

const cols = Object.keys(rows[0]);
const cell = v => (v === null || v === undefined ? "" : '"' + String(v).replace(/"/g, '""') + '"');
writeFileSync("markets.csv", [cols.join(","), ...rows.map(r => cols.map(c => cell(r[c])).join(","))].join("\n"));

قارن بإنصاف

  • لا تقارن الإشغال إلا بين الأسواق التي تكون قيمة tracker فيها estimating.
  • تُطلب جميع الأسعار من المنصات بالريال السعودي، لذا تُقارن المدن في الدول المختلفة مباشرة؛ لكنها تبقى أسعارًا معروضة لا أسعارًا محققة.
  • توزيع أنواع العقارات مهم: فالمدينة التي تغلب عليها الشاليهات سيختلف وسيطها عن مدينة تغلب عليها الاستوديوهات. استخدم الوسيط حسب غرف النوم أو types لمقارنة المتشابه بالمتشابه.