بيانات تصل ومعها ساعة
التيكات والأسعار وأرقام المخاطر ومقاييس الخوادم لها شكل واحد: طابع زمني وبعض الوسوم وبعض القيم المقيسة وسيل لا ينتهي منها. وقاعدة السلاسل الزمنية (InfluxDB وTimescaleDB وQuestDB وkdb+) مبنية لهذا بالضبط. فالكتابات إضافات في أحدث وقت تقريبًا دائمًا فهي سريعة؛ وتُخزَّن البيانات في كتل مرتبة زمنيًا فتلمس «الساعة الأخيرة» القليل؛ ويمكن تلخيص التفاصيل القديمة في بيانات أخشن ثم حذفها في النهاية. ونموذج بيانات InfluxDB نموذجي: قياس (كجدول) ووسوم (علامات مفهرسة كالرمز أو المنصة) وحقول (القيم المقيسة) وطابع زمني.
# One point in InfluxDB line protocol: measurement,tags fields timestamp
point = "trades,symbol=AAPL,venue=XNAS price=184.25,qty=100i 1700000000000000000"
head, fields, ts = point.split(" ")
measurement, *tag_pairs = head.split(",")
tags = dict(pair.split("=") for pair in tag_pairs)
print(measurement, tags) # trades {'symbol': 'AAPL', 'venue': 'XNAS'}
print(fields, int(ts)) # price=184.25,qty=100i 1700000000000000000إعادة التجميع: من التيكات إلى شرائط
الاحتفاظ بكل تيك إلى الأبد مكلف ونادرًا ما يلزم. وإعادة التجميع (downsampling) تضع النقاط في دلاء زمنية ثابتة وتحتفظ بملخص لكل دلو. وملخص الأسعار المعتاد هو OHLCV: الافتتاح (أول سعر في الدلو) والأعلى والأدنى والإغلاق (آخر سعر) والحجم. ينتمي تيك عند الزمن ts إلى الدلو الذي يبدأ عند ts - ts % bucket. وتفعل القواعد ذلك باستمرار وتكتب الناتج في جدول منفصل أصغر بكثير (تجميع مستمر) تقرؤه الرسوم ومعظم الاختبارات الرجعية، بينما تُحفظ التيكات الخام زمنًا قصيرًا فقط.
# Rolling ticks (ts, price, size) into 60-second OHLCV bars
def ohlcv_bars(ticks, bucket):
bars = []
for ts, price, size in ticks:
start = ts - ts % bucket
if bars and bars[-1]["start"] == start:
bar = bars[-1]
bar["high"], bar["low"] = max(bar["high"], price), min(bar["low"], price)
bar["close"] = price
bar["volume"] += size
else:
bars.append({"start": start, "open": price, "high": price, "low": price, "close": price, "volume": size})
return bars
ticks = [(0, 100.0, 10), (30, 101.0, 5), (61, 99.5, 20), (65, 100.5, 1)]
for bar in ohlcv_bars(ticks, 60):
print(bar)
# {'start': 0, 'open': 100.0, 'high': 101.0, 'low': 100.0, 'close': 101.0, 'volume': 15}
# {'start': 60, 'open': 99.5, 'high': 100.5, 'low': 99.5, 'close': 100.5, 'volume': 21}الربط as-of والاحتفاظ
نادرًا ما تتحرك السلاسل في اللحظات نفسها فربطها بطوابع متساوية لا يجد شيئًا تقريبًا. والسؤال الفعلي هو «ما السعر المعلن عند حدوث هذه الصفقة؟»: لكل صفقة خذ آخر سعر عند وقتها أو قبله. وهذا الربط as-of (pandas.merge_asof وASOF JOIN في kdb+ وDuckDB) يجب أن ينظر إلى الخلف فقط؛ فاستعمال سعر بعد الصفقة يسرّب المستقبل إلى التحليل. ولأن الأسعار مرتبة زمنيًا يجد البحث الثنائي (bisect_right) الصحيح منها في زمن لوغاريتمي. وأخيرًا سياسة احتفاظ تُسقط النقاط الأقدم من حد معين ليبقى التخزين محدودًا: احتفظ بـ 30 يومًا من التيكات وسنة من شرائط الدقيقة وشرائط يومية إلى الأبد.
# For each trade, the latest quote at or before it, found by binary search
from bisect import bisect_right
def asof_join(trades, quotes):
times = [quote[0] for quote in quotes]
joined = []
for ts, price in trades:
position = bisect_right(times, ts)
joined.append((ts, price, *quotes[position - 1][1:]) if position else (ts, price, None, None))
return joined
quotes = [(10, 99.9, 100.1), (40, 100.5, 100.7)]
print(asof_join([(5, 100.0), (10, 100.0), (50, 101.0)], quotes))
# [(5, 100.0, None, None), (10, 100.0, 99.9, 100.1), (50, 101.0, 100.5, 100.7)]# Retention: keep only the points younger than the limit
def apply_retention(points, now, ttl):
return [(ts, value) for ts, value in points if ts > now - ttl]
points = [(10, 1.0), (40, 2.0), (50, 3.0), (90, 4.0)]
print(apply_retention(points, 100, 60)) # [(50, 3.0), (90, 4.0)] the point at 40 is exactly 60 s old: dropped
print(apply_retention(points, 100, 1000)) # everything is younger than the limit- نقطة السلسلة الزمنية قياس ووسوم مفهرسة وحقول مقيسة وطابع زمني؛ والكتابات إضافات وتُخزَّن البيانات بالترتيب الزمني.
- أعد تجميع التيكات في شرائط OHLCV (
ts - ts % bucket) واقرأ الشرائط؛ واحتفظ بالتيكات الخام زمنًا قصيرًا فقط. - اربط السلاسل بربط as-of ينظر إلى الخلف فقط (بحث ثنائي) وطبّق سياسة احتفاظ وتحكّم في عدد قيم الوسوم ووحدات الزمن.
التالي: تغليف مكتبة بايثون، تحويل شيفرتك إلى شيء يستطيع الآخرون تثبيته.
المختبر: ما الذي يُقيَّم
- حوّل التيكات إلى شرائط باستخدام
ohlcv_bars25 نقطة - اعثر على السعر عند كل صفقة باستخدام
asof_join25 نقطة - اكتب نقطة باستخدام
line_protocol25 نقطة - احذف البيانات المنتهية باستخدام
apply_retention25 نقطة