σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academyالمسارات
Ctrl K
AO
+1.2k متعلّم
تسجيل الدخولانضم ↗
المسارات
AO
+1.2k متعلّم
تسجيل الدخول
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
مسار Python›الوحدة 10 · هندسة Python عالية الأداء›الموضوع 10.13·~50 دمتقدم

قواعد بيانات السلاسل الزمنية

الموضع في المسارالوحدة 10 من 11 · الموضوع 13 من 13
10.13 قواعد بيانات السلاسل الزمنية
—درجة المختبر— / 100إجمالي XP—التتابع—

بيانات تصل ومعها ساعة

التيكات والأسعار وأرقام المخاطر ومقاييس الخوادم لها شكل واحد: طابع زمني وبعض الوسوم وبعض القيم المقيسة وسيل لا ينتهي منها. وقاعدة السلاسل الزمنية (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
راقب عدد القيم المختلفة في وسومكالوسوم مفهرسة، فكل تركيبة متمايزة من قيم الوسوم تنشئ سلسلة منفصلة. والرمز أو المنصة مقبول (مئات القيم)؛ أما وضع معرّف أمر أو طابع زمني في وسم فينشئ ملايين السلاسل وقد يركع القاعدة. ضع المعرفات التي تتغير في كل نقطة في الحقول لا في الوسوم. وخزّن الطوابع الزمنية بتوقيت UTC بدقة واحدة (ثوانٍ أو ميلي ثوانٍ أو نانو ثوانٍ) في النظام كله، فخلطها ينتج ربطًا لا يطابق شيئًا بصمت.
  • نقطة السلسلة الزمنية قياس ووسوم مفهرسة وحقول مقيسة وطابع زمني؛ والكتابات إضافات وتُخزَّن البيانات بالترتيب الزمني.
  • أعد تجميع التيكات في شرائط OHLCV (ts - ts % bucket) واقرأ الشرائط؛ واحتفظ بالتيكات الخام زمنًا قصيرًا فقط.
  • اربط السلاسل بربط as-of ينظر إلى الخلف فقط (بحث ثنائي) وطبّق سياسة احتفاظ وتحكّم في عدد قيم الوسوم ووحدات الزمن.

التالي: تغليف مكتبة بايثون، تحويل شيفرتك إلى شيء يستطيع الآخرون تثبيته.

المختبر: ما الذي يُقيَّم

  • حوّل التيكات إلى شرائط باستخدام ohlcv_bars25 نقطة
  • اعثر على السعر عند كل صفقة باستخدام asof_join25 نقطة
  • اكتب نقطة باستخدام line_protocol25 نقطة
  • احذف البيانات المنتهية باستخدام apply_retention25 نقطة
المستكشف · lab-129-1
▾ lab-129-1
…
bash · داخل المتصفح
learner@quantcraft:~/lab-129-1$
لم يتم تحميل Python بعدPythonLn 1, Col 1Spaces: 4UTF-8

هل تريد إعادة ضبط هذا الموضوع؟

سيعود كل ما في lab-129-1 إلى الملفات الابتدائية وستُمسح الطرفية. ستفقد حلّك الحالي ولا يمكن التراجع عن ذلك.

سيُعاد ضبطه
  • main.py ← الشيفرة الابتدائية
  • سجل الطرفية ومخرجات الاختبارات
  • التغييرات غير المُرسلة
سيُحتفظ به
  • أفضل درجة في المختبر
  • نقاط XP والتتابع
  • تقدّم المحاضرة والملاحظات

سجّل الدخول لتشغيل الكود الخاص بك.

قراءة كل المحاضرات مجانية. أنشئ حسابًا أو سجّل الدخول لتشغيل الكود وتنفيذ الاختبارات وتسليم هذا المختبر.

  • بيئة تطوير داخل المتصفح مع طرفية bash — لا حاجة لتثبيت أي شيء
  • تصحيح فوري ونقاط خبرة ومكانك في المسار
إنشاء حسابتسجيل الدخول
أو
المتابعة عبر GitHub