
SQL لمستودعات البيانات المالية
استعلام وتجميع وتحليل البيانات المالية المُهيكلة
لماذا SQL هي لغة البيانات المالية
كل صفقة، كل تكة سعرية، كل تحديث لدفتر الأوامر — الأسواق المالية تُنتج أحجامًا مذهلة من البيانات المُهيكلة. ولأكثر من أربعة عقود، كانت SQL (لغة الاستعلام المُهيكلة) الأداة المهيمنة لاستعلام تلك البيانات وتحويلها وتحليلها. لا سحر فيها. لا رواج فيها. لكن حين يسأل مدير محفظة «ما كان متوسط سعر تنفيذ صفقاتي على ETH يوم الثلاثاء الماضي بين الساعة 2 والساعة 3 مساءً بتوقيت UTC؟»، تأتي الإجابة من SQL.
البيانات المالية علائقية (relational) بطبيعتها. الصفقة تُشير إلى أمر، والأمر يُشير إلى حساب، والحساب يخص مستخدمًا. المراكز تتعلق بالأدوات؛ والأدوات تتعلق بالأسواق. النموذج العلائقي — جداول من صفوف وأعمدة، مرتبطة بمفاتيح خارجية — يتوافق طبيعيًا مع هذه العلاقات. هذا سبب أن قواعد البيانات العلائقية مثل PostgreSQL و MySQL و SQL Server تبقى العمود الفقري للبنية التحتية المالية، من Goldman Sachs إلى GaiaEx.
تنبع قوة SQL من طبيعتها التقريرية (declarative): أنت تصف ما تريده، لا كيف تحصل عليه. محرك قاعدة البيانات يجد خطة التنفيذ الأمثل. هذا مهم للغاية حين يحتوي جدول تاريخ صفقاتك على 500 مليون صف وتحتاج للنتائج في أقل من ثانية. اكتب الاستعلام الصحيح، وابنِ الفهرس الصحيح، وستُنفّذ SQL — بصرف النظر إن كنت تُشغّلها مقابل نسخة PostgreSQL محلية أو مستودع بيانات بحجم سحابي.
SELECT وJOIN وWHERE: استعلام بيانات الصفقات
لنبدأ بمخطط ملموس. تخيّل جدول trades على منصة مثل GaiaEx:
CREATE TABLE trades (
trade_id BIGINT PRIMARY KEY,
user_id INT NOT NULL,
symbol VARCHAR(20) NOT NULL,
side VARCHAR(4) NOT NULL, -- 'buy' or 'sell'
price NUMERIC(18,8) NOT NULL,
quantity NUMERIC(18,8) NOT NULL,
fee NUMERIC(18,8) DEFAULT 0,
executed_at TIMESTAMPTZ NOT NULL
);
العملية الأساسية الأولى هي جملة SELECT مع الترشيح. للعثور على كل صفقات شراء ETH-USD فوق 3,000$ في آخر 24 ساعة:
SELECT trade_id, price, quantity, executed_at
FROM trades
WHERE symbol = 'ETH-USD'
AND side = 'buy'
AND price > 3000
AND executed_at > NOW() - INTERVAL '24 hours'
ORDER BY executed_at DESC;
تربط جمل JOIN الجداول المتعلقة. لنفترض أن لديك جدول accounts وتريد رؤية حجم التداول بحسب مستوى الحساب:
SELECT a.tier, COUNT(*) AS trade_count,
SUM(t.price * t.quantity) AS total_volume
FROM trades t
JOIN accounts a ON t.user_id = a.user_id
WHERE t.executed_at > NOW() - INTERVAL '30 days'
GROUP BY a.tier
ORDER BY total_volume DESC;
هذه الاستعلامات هي الخبز اليومي للمحللين الماليين وفرق المخاطر ومسؤولي الامتثال. أتقنها وستستطيع الإجابة عن أي سؤال تحتويه بياناتك.
دوال النوافذ (Window Functions): السلاح السرّي للمحلل
دوال النوافذ (Window Functions) هي ما يُميّز مبتدئي SQL عن ممارسيها في المجال المالي. تتيح لك إجراء حسابات عبر مجموعة من الصفوف المتعلقة بالصف الحالي — دون طيّ النتيجة إلى قيمة مُجمَّعة واحدة. فكّر بها كـ«حسابات جارية» عبر بياناتك.
أكثر دوال النوافذ استخدامًا في التحليل المالي:
- ROW_NUMBER() — تُخصّص عددًا صحيحًا متتاليًا لكل صف داخل قسم (partition). مفيدة لإزالة التكرار أو اختيار الصفقة الرقم N لكل رمز.
- LAG() و LEAD() — تصل إلى قيمة الصف السابق أو التالي. أساسية لحساب العوائد من صفقة إلى صفقة أو كشف الفجوات في بيانات السلاسل الزمنية.
- SUM() OVER () — الإجماليات الجارية. حساب الحجم التراكمي، أو الربح والخسارة التراكمي، أو حجم المركز الجاري.
- AVG() OVER (ROWS BETWEEN) — المتوسطات المتحركة مباشرة في SQL. لا حاجة لـ Python.
مثال عملي — حساب تغيّر السعر من صفقة إلى صفقة ومركز جارٍ لـ BTC:
SELECT executed_at, price, quantity, side,
price - LAG(price) OVER (ORDER BY executed_at) AS price_change,
SUM(CASE WHEN side = 'buy' THEN quantity ELSE -quantity END)
OVER (ORDER BY executed_at) AS running_position
FROM trades
WHERE symbol = 'BTC-USD'
ORDER BY executed_at;
دوال النوافذ لا تُقلّل عدد صفوفك — على عكس GROUP BY، كل صف مُدخَل يُنتج صف مُخرَج. هذا يجعلها مثالية لإضافة أعمدة تحليلية إلى سجلات صفقات مفصّلة دون فقدان التفصيل. فكّر بها كأنها «تُغني» بياناتك بدلًا من «تُلخّصها».
لتجميع OHLCV — أساس شارتات الشموع اليابانية — يمكنك دمج GROUP BY مع تجميع زمني (time-bucketing) ودوال تجميع قياسية:
SELECT date_trunc('hour', executed_at) AS bucket,
(ARRAY_AGG(price ORDER BY executed_at))[1] AS open,
MAX(price) AS high,
MIN(price) AS low,
(ARRAY_AGG(price ORDER BY executed_at DESC))[1] AS close,
SUM(quantity) AS volume
FROM trades
WHERE symbol = 'ETH-USD'
GROUP BY bucket
ORDER BY bucket;CTE: تركيب استعلامات تحليلية معقّدة
التعبيرات الجدولية المشتركة (Common Table Expressions - CTEs) تتيح لك تفكيك استعلام معقّد إلى مراحل مُسمّاة وقابلة للقراءة — كالدوال في البرمجة. تُقدَّم بكلمة WITH ويمكنها الإشارة إلى بعضها بالتتابع.
لنفترض أنك تريد تحديد أفضل 10 أيام تداول من حيث الربحية، لكن الربحية تتطلب حساب الربح والخسارة الصافي لكل يوم شاملًا الرسوم. مع CTE، يمكنك بناء هذا خطوة بخطوة:
WITH daily_trades AS (
SELECT DATE(executed_at) AS trade_date,
SUM(CASE WHEN side = 'sell' THEN price * quantity
ELSE -price * quantity END) AS gross_pnl,
SUM(fee) AS total_fees
FROM trades
WHERE user_id = 42
GROUP BY DATE(executed_at)
),
daily_pnl AS (
SELECT trade_date,
gross_pnl - total_fees AS net_pnl,
SUM(gross_pnl - total_fees) OVER (ORDER BY trade_date) AS cumulative_pnl
FROM daily_trades
)
SELECT trade_date, net_pnl, cumulative_pnl
FROM daily_pnl
ORDER BY net_pnl DESC
LIMIT 10;
كل CTE يُقرأ كفقرة. daily_trades يُجمّع الصفقات الخام إلى ملخصات يومية. daily_pnl يحسب الربح والخسارة الصافي والإجمالي الجاري. جملة SELECT الأخيرة تختار أفضل 10 أيام. قارن هذا باستعلام فرعي واحد أحادي البنية — نسخة CTE قابلة للصيانة، وقابلة للاختبار، وتُوثّق نفسها بنفسها.
في الأنظمة المالية الإنتاجية، تُستخدم CTE لكل شيء من التقارير التنظيمية (تجميع متطلبات الهامش عبر الحسابات) إلى استعلامات لوحات المعلومات الفورية (حساب الحجم المتحرك على مدار 24 ساعة على GaiaEx). تتركّب بالطريقة نفسها التي يتركّب بها الكود المصمّم جيدًا — كل طبقة تبني على السابقة.
الفهرسة والتجزيء (Partitioning) لأداء السلاسل الزمنية
الاستعلام سريع بمقدار سرعة الفهرس الذي يدعمه. دون الفهرس الصحيح، حتى جملة WHERE بسيطة تُجبر على مسح تسلسلي (sequential scan) — قراءة كل صف في الجدول. عند 500 مليون صف، هذا يعني دقائق بدلًا من مللي ثوانٍ.
لبيانات السلاسل الزمنية المالية، أهم نمط فهرسة هو فهرس شجرة B مُركَّب (composite B-tree index) على (symbol, executed_at):
CREATE INDEX idx_trades_symbol_time
ON trades (symbol, executed_at DESC);
هذا الفهرس الواحد يُسرّع معظم الاستعلامات التحليلية: «كل صفقات ETH في الساعة الأخيرة»، أو «صفقات BTC بين طابعي زمن»، أو «آخر صفقة لكل رمز». ترتيب الأعمدة يهم — symbol أولًا يُفعّل الترشيح بالتساوي، ثم executed_at يُفعّل مسوحات المدى الفعّالة داخل ذلك القسم من الفهرس.
للجداول التي تنمو لتتجاوز مئات الملايين من الصفوف، تجزيء الجدول (table partitioning) أساسي. يدعم PostgreSQL التجزيء التقريري بالمدى — مثالي للسلاسل الزمنية:
CREATE TABLE trades (
trade_id BIGINT, symbol VARCHAR(20),
price NUMERIC(18,8), executed_at TIMESTAMPTZ
) PARTITION BY RANGE (executed_at);
CREATE TABLE trades_2026_q1 PARTITION OF trades
FOR VALUES FROM ('2026-01-01') TO ('2026-04-01');
CREATE TABLE trades_2026_q2 PARTITION OF trades
FOR VALUES FROM ('2026-04-01') TO ('2026-07-01');
مع التجزيء، استعلام لبيانات مارس 2026 يمسح فقط قسم الربع الأول — يتخطى المحرك الربع الثاني والثالث والرابع كليًا. هذه التقنية، المُسمّاة تقليم التجزيء (partition pruning)، تُنتج تسريعات بمقدار رتبة حجم كاملة على مجموعات البيانات التاريخية الكبيرة.
PostgreSQL مقابل ClickHouse مقابل BigQuery: اختيار المحرك الصحيح
لا تتعامل كل قواعد البيانات مع التحليلات المالية بالتساوي. الاختيار يعتمد على أنماط استعلامك، وحجم بياناتك، ومتطلبات زمن الاستجابة.
PostgreSQL هي الحصان العامل. تتفوق في أعباء العمل المُعاملاتية (تسجيل الصفقات في الزمن الفعلي)، وتدعم ضمانات ACID، وتتعامل مع عمليات JOIN المعقدة بسلاسة، وتتوسّع لمئات ملايين الصفوف مع فهرسة وتجزيء مناسبين. إنها الخيار الصحيح لقواعد البيانات التشغيلية — نظام السجل. GaiaEx، على سبيل المثال، تعتمد على بنية تحتية متوافقة مع PostgreSQL لبيانات تداولها الأساسية بضمانات الموثوقية التي تتطلبها الأنظمة المالية.
ClickHouse قاعدة بيانات عمودية (columnar) مصمّمة للاستعلامات التحليلية على مليارات الصفوف. حيث تُخزّن PostgreSQL البيانات صفًا بصف (مثالية لإدخال صفقات فردية)، تُخزّن ClickHouse البيانات عمودًا بعمود (مثالية لتجميع عمود واحد عبر ملايين الصفوف). استعلام مثل «متوسط الحجم الساعي لـ BTC عبر 3 سنوات» يستغرق 30 ثانية في PostgreSQL قد ينتهي في 200 مللي ثانية في ClickHouse. المقايضة: لا تدعم ClickHouse UPDATE أو DELETE بفعالية — إنها مُلحَقة فقط (append-only) بالتصميم.
BigQuery (Google Cloud) مستودع عمودي بلا خادم (serverless). لا بنية تحتية للإدارة، وتسعير بحسب الاستعلام، وسعة بحجم البيتابايت. مثالية للتحليلات المخصّصة، والبحث، والاستكشاف — لكن زمن استجابة الاستعلام يُقاس بالثواني، لا بالمللي ثانية، ما يجعلها غير مناسبة للتطبيقات الفورية.
- تسجيل الصفقات الفوري وإدارة الأوامر ← PostgreSQL
- التحليلات التاريخية والاختبار الرجعي (backtesting) عبر مليارات الصفوف ← ClickHouse
- الاستكشاف المخصّص ومشاركة البيانات بين الفرق ← BigQuery
كثير من شركات التداول المحترفة تستخدم الثلاثة في بنية متدرّجة: PostgreSQL كمخزن تشغيلي ساخن، وClickHouse كطبقة تحليلية دافئة، وBigQuery كأرشيف بارد. مهارة كتابة SQL جيدة تنتقل عبر كل هذه القواعد — الصيغة متطابقة بنسبة 90%، والتفكير التحليلي متطابق بنسبة 100%.