تحليل مجموعة المنافسين
متوسط
ابنِ مجموعة منافسين حول عقارك من جميع العقارات المجمّعة، واعرف موقع سعرك بينها.
الإعداد
يستخدم هذا الدرس الأداة المساعدة jokerprice.py من درس البدء السريع. احفظها بجوار نصك البرمجي واضبط JOKERPRICE_API_KEY.
عرّف عقارك
mine = {"latitude": 24.8094, "longitude": 46.6112, "bedrooms": 2, "typeId": "6", "nightly": 450}
CITY, RADIUS_KM = "riyadh", 2.0اجلب عقارات المدينة
تتبع الدالة all_listings قيمة nextCursor بواقع 500 عقار لكل طلب. احفظ النتيجة لتعيد التحليل دون استهلاك طلبات.
import json, os
from jokerprice import all_listings
cache = f"{CITY}-listings.json"
if os.path.exists(cache):
listings = json.load(open(cache))
else:
listings = all_listings(CITY)
json.dump(listings, open(cache, "w"))
print(len(listings), "listings")صفِّ المنافسين الفعليين
from math import radians, sin, cos, asin, sqrt
def km(a_lat, a_lng, b_lat, b_lng):
d_lat, d_lng = radians(b_lat - a_lat), radians(b_lng - a_lng)
h = sin(d_lat / 2) ** 2 + cos(radians(a_lat)) * cos(radians(b_lat)) * sin(d_lng / 2) ** 2
return 6371 * 2 * asin(sqrt(h))
comps = []
for l in listings:
if l.get("latitude") is None or not l.get("nightly"):
continue
if l.get("bedrooms") != mine["bedrooms"] or str(l.get("typeId")) != mine["typeId"]:
continue
d = km(mine["latitude"], mine["longitude"], l["latitude"], l["longitude"])
if d <= RADIUS_KM:
comps.append({**l, "km": d})
print(len(comps), "comparables")اعرف موقعك
from statistics import quantiles, median
rates = sorted(c["nightly"] for c in comps)
p25, p50, p75 = quantiles(rates, n=4)
below = sum(r < mine["nightly"] for r in rates)
print(f"Comp set: 25th SAR {p25:.0f} | median SAR {p50:.0f} | 75th SAR {p75:.0f}")
print(f"Your SAR {mine['nightly']} is above {below / len(rates):.0%} of comparables")
rated = [c for c in comps if c.get("rating")]
top = [c["nightly"] for c in rated if c["rating"] >= 9.5]
if top:
print(f"Median rate of comps rated 9.5+: SAR {median(top):.0f} ({len(top)} listings)")تحتاج quantiles إلى عقارين مماثلين على الأقل؛ وسّع نصف القطر إن كان العدد أقل.
راجع أقرب المنافسين
for c in sorted(comps, key=lambda c: c["km"])[:15]:
print(f"{c['km']:.2f} km SAR {c['nightly']:>5} rating {c.get('rating') or '-':>4} reviews {c.get('reviews') or 0:>4} {c['source']:<7} {c.get('district') or ''}")أضف أداء الحجوزات
لا تكشف الأسعار المعروضة ما يُحجز فعلًا. وتقبل /api/v1/metrics النطاق نفسه على هيئة مستطيل على الخريطة، فتستطيع قراءة الإشغال ومتوسط السعر اليومي للمنطقة المحيطة بعقارك.
from jokerprice import api
d = 0.02 # about 2 km
m = api("GET", "/api/v1/metrics", params={"north": mine["latitude"] + d, "south": mine["latitude"] - d,
"east": mine["longitude"] + d, "west": mine["longitude"] - d, "past_days": 60})["metrics"]
print(m["maturity"], "occupancy", m["past"]["occupancy"], "ADR", m["past"]["adr"], "tracked", m["listings"]["tracked"])