→ LiquidityWise

بطاقة التجمّع وJSON الخاص بها

شبكة إيثيريوم الرئيسية

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

البطاقة

/embed/pool صفحة صغيرة مكتوبة يدويًا، لا بإطار عمل الموقع. تعرض الزوج مع بروتوكوله ورسومه وشبكته؛ والنطاق المقترح مع الأفق والاتساع اللذين رُسم لهما؛ والسعر الحالي؛ وسطرًا يقول إنها ليست نصيحة مالية؛ ورابطًا يعود إلى صفحة التجمّع هنا، يفتح في علامة تبويب جديدة. يُرسم النطاق دائمًا بالقيم الافتراضية للموقع، 30 يومًا عند 1σ، أيًّا كانت إعدادات أي شخص. وتُضاف ملاحظة ما دام السعر الحالي خارج النطاق، وأخرى لتجمّع v4 قد يغيّر خطّافه تكلفة التبادل.

لا تحتوي على أي برنامج نصي ولا استمارة، ولا تحمّل شيئًا: سياسة Content-Security-Policy الخاصة بها لا تسمح بشيء سوى أسلوبها المضمّن. ألوانها ألوان الموقع، فاتحة أو داكنة بحسب إعداد نظام القارئ. لا ترى الصفحة المحيطة بها، ولا يوجد مُعامِل لاختيار ذلك.

أعطها إطارًا بعرض 360 بكسل وارتفاع 220، أو بارتفاع 260 لتجمّع قد يغيّر خطّافه تكلفة التبادل، إذ تحمل بطاقته سطرًا إضافيًا. هذا بالضبط ما تعرضه صفحة كل تجمّع تحت «تضمين هذا التجمّع»، بالارتفاع المناسب لذلك التجمّع مسبقًا، ولا يصبح الإطار المعروض أعرض من العمود الذي يُلصق فيه أبدًا.

إنها الصفحة الوحيدة في هذا الموقع التي يجوز لموقع آخر أن يضعها في إطار. كل عنوان آخر، ومنه هذا العنوان، يُرسل مع X-Frame-Options: DENY وframe-ancestors 'none'؛ أما البطاقة فتُرسل من دون الأول ومع frame-ancestors *.

الإطار الخاص بتجمّع USDC / WETH بنسبة 0.3% على Ethereum، كما تعرضه صفحة ذلك التجمّع:
<iframe src="https://liquiditywise.com/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8" title="USDC / WETH on LiquidityWise" width="360" height="220" style="border:0;max-width:100%" loading="lazy"></iframe>
ما تُرسل معه البطاقة التي تحمل أرقامًا، إلى جانب الترويسات التي تحملها كل صفحة:
Content-Type: text/html; charset=utf-8
Cache-Control: public, max-age=300, s-maxage=300
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; frame-ancestors *

المُعامِلات

تأخذ البطاقة وJSON المُعامِلات نفسها، وتسمّيان التجمّع كما تسمّيه صفحات الموقع نفسه: تجمّع v3 بعنوانه address كما في /pool، وتجمّع v4 بمعرّفه id كما في /v4. يلزم واحد منهما بالضبط، وأيّهما وصل يحدّد البروتوكول. التجمّع أو الشبكة المذكوران مرتين يُرفضان بدل أن تُختار إحدى القيمتين، وأي مُعامِل غير مذكور هنا يُتجاهَل.

تأتي اللغة من العنوان وحده، لا من متصفح القارئ ولا من ملف تعريف ارتباط أبدًا: الموقع الذي يضع البطاقة هو من يختارها، والعنوان نفسه هو الإجابة نفسها لكل من يحمّله، وهذا ما يتيح للتخزين المؤقت الاحتفاظ بها. البطاقة مكتوبة بلغات الموقع الـ10 كلها، وبالعربية تُقرأ من اليمين إلى اليسار.

address
يقبل عنوان عقد تجمّع v3: 0x ثم 40 رقمًا ست عشريًا، بأحرف كبيرة أو صغيرة.
وإلا أي شيء آخر لا يسمّي تجمّعًا، وكذلك تجمّع v3 على شبكة لا يُقرأ فيها v3 (Unichain): 400، ولا يُقرأ شيء.
id
يقبل معرّف تجمّع v4، أي تجزئة مفتاحه: 0x ثم 64 رقمًا ست عشريًا، بأحرف كبيرة أو صغيرة.
وإلا أي شيء آخر لا يسمّي تجمّعًا: 400، ولا يُقرأ شيء. وكذلك id إلى جانب address.
chain
يقبل الاسم المختصر لشبكة من الجدول أدناه. إن غاب، فالشبكة هي Ethereum.
وإلا الاسم الذي لا يقرأ الموقع شبكته يُرفض، ولا يُقرأ على أنه Ethereum أبدًا: 400.
lang
يقبل رمز لغة من القائمة أدناه، لكلمات البطاقة ولحقل disclaimer في JSON؛ والأرقام واحدة في كل اللغات. إن غاب، فالإنجليزية.
وإلا أي قيمة أخرى، أو lang مذكورًا مرتين، يعطي الإنجليزية. لا يُرفض أبدًا.

الشبكات، بالاسم المختصر الذي يأخذه chain:

chainالشبكةتجمّعات v3تجمّعات v4
ethereumEthereumتُقرأتُقرأ
baseBaseتُقرأتُقرأ
arbitrumArbitrum Oneتُقرأتُقرأ
unichainUnichainلا تُقرأتُقرأ
optimismOP Mainnetتُقرأتُقرأ
polygonPolygonتُقرأتُقرأ

اللغات، بالرمز الذي يأخذه lang:

  • enEnglish
  • trTürkçe
  • deDeutsch
  • esEspañol
  • arالعربية
  • hiहिन्दी
  • zh中文
  • ruРусский
  • ptPortuguês
  • zh-Hant繁體中文

صيغة JSON

يجيب GET /api/embed/pool، بالمُعامِلات نفسها، بأرقام البطاقة بصيغة JSON، لموقع يفضّل أن يرسمها بنفسه: القراءة نفسها، محفوظة المدة نفسها. كل رقم فيها رقم JSON، وكل سعر مكتوب بالاتجاه الذي تكتبه به صفحة التجمّع: كم price.quote يساوي price.base واحد.

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

يجوز لبرنامج أي موقع أن يقرأها. كل إجابة، ومنها الأخطاء والرفض، تُرسل مع Access-Control-Allow-Origin: *. لا تضع ملف تعريف ارتباط ولا تحتاج إلى بيانات اعتماد. طلب GET بسيط لا يحتاج إلى فحص مسبق (preflight)، ولا يُجاب عن أي فحص مسبق، فأرسله من دون ترويسات خاصة بك.

ما تُرسل معه الإجابة التي تحمل أرقامًا، إلى جانب الترويسات التي تحملها كل صفحة:
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=300, s-maxage=300
Access-Control-Allow-Origin: *

كل حقل في إجابة 200، مع نوعه في JSON:

protocol"v3" | "v4"
v3 لتجمّع سُمّي بـaddress، وv4 لتجمّع سُمّي بـid.
chain.idinteger > 0
معرّف السلسلة (chain id) للشبكة.
chain.slugstring
الاسم المختصر للشبكة، كما يأخذه chain.
chain.namestring
اسم الشبكة.
poolstring
عنوان التجمّع (v3) أو معرّفه (v4)، بأحرف صغيرة.
pair.token0string
اسم الرمز الأول في التجمّع كما يعلنه عقده: نصٌّ من عقد يستطيع أي أحد نشره، فاحرص على تهريبه (escape) قبل أن تضعه في صفحة.
pair.token1string
اسم الرمز الثاني، بالطريقة نفسها.
lpFeePpminteger ≥ 0 | null
الرسوم التي يدفعها التجمّع لمزوّدي السيولة عن كل تبادل، بأجزاء من المليون: 3000 تعني 0.3%. وتكون null حين يحدّد خطّاف تجمّع v4 الرسوم تبادلًا بتبادل.
price.basestring
الرمز الذي يُعطى كل سعر لوحدة واحدة منه.
price.quotestring
الرمز الذي يُحسب به كل سعر.
price.currentnumber > 0
سعر التجمّع لحظة قراءته.
range.lowernumber > 0
الحد الأدنى للنطاق المقترح، كسعر.
range.uppernumber > 0
حدّه الأعلى.
range.currentInRangeboolean
هل السعر الحالي داخل النطاق. إن لم يكن، تضيف البطاقة ملاحظة.
range.lowerTruncatedboolean
true حين لا تبلغ شبكة الـ tick في التجمّع الحدَّ الأدنى للحزمة، فيتوقف النطاق قبله.
range.upperTruncatedboolean
الشيء نفسه، للحد الأعلى.
parameters.horizonDaysinteger > 0
الأفق الذي رُسم له النطاق، بالأيام: دائمًا القيمة الافتراضية، 30.
parameters.standardDeviationMultipliernumber > 0
الاتساع الذي رُسم له، بالانحرافات المعيارية: دائمًا القيمة الافتراضية، 1σ.
hookMayAlterSwapsboolean
true لتجمّع v4 قد يغيّر خطّافه تكلفة التبادل، مقروءًا من عنوان الخطّاف؛ وfalse لـ v3، ولتجمّع v4 بلا خطّاف، ولخطّاف لا تمسّ أذوناته التبادل. وحيث تكون true تحمل البطاقة ملاحظة.
analysedAtstring (ISO 8601)
متى قُرئ السعر، بتوقيت UTC وحتى الجزء من الألف من الثانية — لا متى أُرسلت هذه الإجابة، وقد يكون ذلك بعد دقائق.
poolUrlstring
صفحة التجمّع على هذا الموقع، بالأفق والاتساع نفسيهما.
disclaimerstring
ما هي الأرقام وما ليست هي، باللغة التي يحدّدها lang.
إجابة للتجمّع الوارد في الأمثلة. أرقامها مثال: حسبتها شيفرة الموقع نفسها من شهر نموذجي من الأسعار، لا من قراءة التجمّع، ويتحقق اختبار من أن الشيفرة ما زالت تجيب بهذا بالضبط لذلك الشهر:
{
  "protocol": "v3",
  "chain": {
    "id": 1,
    "slug": "ethereum",
    "name": "Ethereum"
  },
  "pool": "0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
  "pair": {
    "token0": "USDC",
    "token1": "WETH"
  },
  "lpFeePpm": 3000,
  "price": {
    "base": "WETH",
    "quote": "USDC",
    "current": 3000
  },
  "range": {
    "lower": 2824.2704157479307,
    "upper": 3184.336896959513,
    "currentInRange": true,
    "lowerTruncated": false,
    "upperTruncated": false
  },
  "parameters": {
    "horizonDays": 30,
    "standardDeviationMultiplier": 1
  },
  "hookMayAlterSwaps": false,
  "analysedAt": "2026-08-21T09:15:00.000Z",
  "poolUrl": "https://liquiditywise.com/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8&days=30&sigma=1",
  "disclaimer": "For information only, not financial advice. The range is worked out from how far this pool's price moved over the last 30 days: it is not a forecast and not a recommendation."
}

رموز الحالة والأخطاء

تجيب البطاقة وJSON برموز الحالة نفسها. ولا يجيب أيّ منهما أبدًا بصفحة الخطأ الخاصة بالموقع أو بما تعطّل في الداخل: تعرض البطاقة جملة واحدة ورابطها للعودة، ويجيب JSON بحقل error يستطيع البرنامج فحصه، ومعه disclaimer — عدا الرفض، الذي يحمل مدة الانتظار بدلًا منه.

إجابة JSON، ومدة جواز الاحتفاظ بها:

200

الأرقام: بطاقة تحملها، أو JSON الموصوف أعلاه.

Cache-Control: public, max-age=300, s-maxage=300

400 not-a-pool

العنوان لا يسمّي تجمّعًا يقرؤه الموقع: لا address ولا id، أو كلاهما، أو أحدهما مشوّه أو مكرّر، أو شبكة لا يقرؤها الموقع، أو تجمّع v3 حيث لا يُقرأ إلا v4 (Unichain). لم يُقرأ شيء، وإعادة السؤال لن تغيّر الإجابة.

Cache-Control: public, max-age=3600, s-maxage=3600

{
  "error": "not-a-pool",
  "disclaimer": "For information only, not financial advice. The range is worked out from how far this pool's price moved over the last 30 days: it is not a forecast and not a recommendation."
}

503 unreadable

تجمّع سُمّي تسمية صحيحة وتعذّرت قراءته الآن: مصدرٌ لم يُجب في الوقت المحدد، أو لا يوجد تجمّع كهذا على تلك الشبكة. يبقى poolUrl موصلًا إلى صفحته. وقد تجده إعادة السؤال بعد دقيقة.

Cache-Control: public, max-age=60, s-maxage=60

{
  "error": "unreadable",
  "poolUrl": "https://liquiditywise.com/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8&days=30&sigma=1",
  "disclaimer": "For information only, not financial advice. The range is worked out from how far this pool's price moved over the last 30 days: it is not a forecast and not a recommendation."
}

429 rate-limited

طلبات كثيرة جدًا من عميل واحد: انظر حدّ الطلبات أدناه. يقول كلٌّ من Retry-After وretryAfterSeconds كم ثانية يجب الانتظار. وتجيب البطاقة بصفحة قصيرة تقول ذلك، بلغتها.

Cache-Control: no-store
Retry-After: 42

{
  "error": "rate-limited",
  "retryAfterSeconds": 42
}

التخزين المؤقت وحدّ الطلبات

تقول كل إجابة كم يجوز الاحتفاظ بها، للمتصفح وللتخزين المؤقت المشترك على السواء: 300 ثانية للأرقام؛ و60 ثانية لتجمّع تعذّرت قراءته، كي لا يظهر تجمّع عاد للعمل متعذّرًا طويلًا؛ و3,600 ثانية لعنوان لا يسمّي تجمّعًا، فلن تغيّر ذلك أي لحظة لاحقة. أما الرفض فلا يُحتفظ به أبدًا. وكل إجابة واحدة لكل من يسأل بالعنوان نفسه، وهذا ما يجعل الاحتفاظ بها آمنًا.

ووراء ذلك يحتفظ الخادم بأرقام كل تجمّع 300 ثانية من لحظة قراءتها، للبطاقة ولـ JSON على السواء وبكل اللغات: كل بطاقة لتجمّع واحد، في كل صفحة توضع فيها، هي قراءة واحدة حتى تنتهي مدتها. والتجمّع الذي تعذّرت قراءته لا يُحتفظ به، ويُسأل عنه من جديد في الطلب التالي. لذلك قد يكون السعر في الإجابة أقدم من الإجابة نفسها: يقول analysedAt متى قُرئ.

الطلب الذي يسمّي تجمّعًا صحيح الصيغة يقرأ ذلك التجمّع، ولذلك يُحسب من الحصة نفسها التي تُحسب منها صفحات التجمّعات في الموقع: 10 طلبات لكل عميل في نافذة مدتها 60 ثانية تبدأ مع أول طلب للعميل، والعميل هو عنوان IP الذي يصل منه الطلب إلى الموقع. وبعد تجاوز الحد تكون الإجابة 429 مع Retry-After. ويُحسب كل طلب كهذا يصل إلى الموقع، ومنه ما يُجاب عنه مما يحتفظ به الخادم؛ أما الطلب الذي لا يسمّي تجمّعًا فلا يُحسب.

من المتصفح، تُحسب البطاقة أو fetch على القارئ الذي يحمّلها، لا على الموقع الذي توضع فيه — فالصفحة التي تضع أكثر من 10 بطاقات تُرفض فيها البطاقات الزائدة لكل قارئ. ومن الخادم، تتقاسم كل طلباتك حصة ذلك الخادم الواحدة: احتفظ بكل إجابة طوال الـ300 ثانية التي تسمح بها، وهذا لا يكلّف كثيرًا، لأن الخادم كان سيجيب في معظم تلك المدة بالقراءة التي لديك أصلًا. وُضع الحد لإبقاء كلفة قراءة التجمّعات منخفضة، ولا شيء هنا يَعِد بأنه سيبقى كما هو.

أمثلة

الأرقام، من الطرفية:
curl -s "https://liquiditywise.com/api/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8"
من برنامج الصفحة نفسها، أو من خادم، مع معالجة كل إجابة:
const response = await fetch(
  "https://liquiditywise.com/api/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8",
);
const body = await response.json();

if (response.ok) {
  // The range, in body.price.quote per one body.price.base
  console.log(body.range.lower, body.range.upper, body.price.quote, body.price.base);
  console.log(body.disclaimer);
} else if (response.status === 429) {
  console.log(`Asked too often: wait ${body.retryAfterSeconds} seconds`);
} else {
  console.log(body.error); // "not-a-pool" or "unreadable"
}
البطاقة، في صفحة:
<iframe src="https://liquiditywise.com/embed/pool?address=0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8" title="USDC / WETH on LiquidityWise" width="360" height="220" style="border:0;max-width:100%" loading="lazy"></iframe>

نقرة واحدة تحدّد الكتلة كلها، جاهزة للنسخ.

الشروط بكلمات بسيطة

الأرقام قياسات، لا نصيحة. يُحسب النطاق من مقدار تحرّك سعر التجمّع خلال آخر 30 يومًا: ليس تنبؤًا وليس توصية، وكل إجابة تقول ذلك بنفسها، البطاقة على واجهتها وJSON في disclaimer. وكيف يُحسب كل رقم وما الذي يتركه خارجه، تجده في صفحة «كيف يعمل».

تحمل البطاقة رابطها الخاص للعودة، «تحليل LiquidityWise». أما JSON فليس فيه حقل لنسبة المصدر، ولا شيء في الشيفرة يطلب ذلك؛ ما يحمله هو poolUrl، صفحة التجمّع هنا، وdisclaimer. وإذا عُرض هذان بجانب الأرقام، أخبرا القارئ من أين جاءت وما هي.

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

الشيفرة مفتوحة المصدر، بموجب رخصة MIT.

كيف يعملالشيفرة على GitHubرخصة MIT