ระบบเก็บข้อมูล CME/QuikStrike/Yahoo สำหรับ GoldQuant โดยใช้ Postgres-backed queue, TimescaleDB เป็น canonical store, latest files เป็น compatibility contract และ Parquet เป็น training history แบบถาวร
flowchart LR
Scheduler["cme-scheduler"] --> Queue[("Postgres queue")]
Dashboard["dashboard"] --> API["cme-api"]
API --> Queue
Queue --> Worker["cme-fetcher worker"]
Worker --> Sources["CME / QuikStrike / Yahoo"]
Worker --> DB[("TimescaleDB")]
Worker --> Latest["GoldQuant latest files"]
DB --> Exporter["training-exporter"]
Exporter --> Parquet["Partitioned Parquet"]
- Scheduler และ API enqueue งานเท่านั้น ไม่มี browser/scrape ใน process
- Worker เริ่มที่ logical concurrency 3 โดยงาน CME/Camoufox ทำทีละงาน ส่วน Yahoo intraday ยังทำงานขนานได้
- Queue รองรับ idempotency, dependencies, attempt history, heartbeat, retry และ stale-job recovery
- API deduplicate request ค่าเดียวกันใน UTC-minute slot โดยอัตโนมัติจาก job type, symbol, timeframe และ trade date; ยังรองรับ explicit
idempotencyKey - Latest files เขียนด้วย temporary file +
fsync+ atomic rename - DB และ Parquet ไม่มี automatic retention;
intraday_barsใช้ TimescaleDB 2.27 Hypercore columnstore หลัง 7 วัน และ disk guard หยุดรับงานเขียนที่ 95% - System Health แสดง worker circuit states, INTRADAY/Vol2Vol freshness ที่ 10/45 นาที, Vol2Vol Tenor daily freshness ที่ 24 ชั่วโมง และ EOD completeness ของ Options/OI/OI Summary/Settlement
- Intraday ทำงานทุก 1 นาทีที่วินาที 10; recovery job เก่าถูกจำกัดให้อยู่ใน UTC date ของงาน และ exporter ปฏิเสธ bar ที่ไม่ตรงวันที่ในชื่อไฟล์
- GC 24×7 มีผลตั้งแต่
2026-07-26; ก่อนหน้านั้นยังใช้ weekday calendar
รายละเอียด architecture, job/source/output inventory, API contract, SLO, failure modes, rollout และ acceptance status อยู่ที่ docs/cme-fetcher-system-analysis.md ส่วนขั้นตอน incident/maintenance อยู่ที่ RUNBOOK.md
Prerequisites: Docker Desktop, Compose v2, PowerShell และพื้นที่ว่างบนไดรฟ์ D:
Copy-Item .env.example .env
$env:BUILD_SHA = (git rev-parse --short HEAD)
$env:BUILD_VERSION = 'local'
docker compose config --quiet
docker compose up -d --build --wait
docker compose ps
Invoke-RestMethod 'http://127.0.0.1:3000/api/system-health'Compose services:
db: TimescaleDB ที่ bind เฉพาะ127.0.0.1:5433โดย defaultmigrate: one-shot additive migration; service อื่นรอจนสำเร็จscheduler: queue producerfetcher: browser worker และ execution authorityapi: internal API; ไม่ publish host port โดย defaultdashboard:http://127.0.0.1:3000training-exporter: export เวลา 19:30America/Chicagotrading-bot: paper-trading consumer; ต้องมี localscripts/bot/model.joblibและรับ webhook ผ่านDISCORD_WEBHOOK_URLเท่านั้น
Host persistence:
./output-> GoldQuant latest/current files และ legacy archives./errors-> scrape diagnostics./config-> worker read-only configuration/cookies./training-data-> immutable Parquet partitions- Docker volume
pgdata-> TimescaleDB
ห้ามใช้ docker compose down -v กับข้อมูลจริง
Legacy output/ สามารถ import เข้า Parquet ด้วย one-shot training-exporter โดย mount source แบบ read-only; ดูคำสั่งและข้อจำกัดใน RUNBOOK.md archive จริงถูก reconcile แล้วใน training-data/reconciliation/; การ cleanup ยังต้องได้รับอนุมัติแยกต่างหาก
Consumer ควรอ่าน top-level current files เดิม เช่น:
output/options/GC_options_YYYYMMDD.csvoutput/oi/GC_options_oi_by_strike_YYYYMMDD.csvoutput/oi/GC_oi_summary_YYYYMMDD.csvoutput/oi/GC_futures_oi_YYYYMMDD.csvoutput/intraday/GC_1m_YYYYMMDD.csvoutput/settlement/GC_settlement_YYYYMMDD.csvoutput/vol2vol/vol2vol_summary_latest.jsonoutput/Data-prediction/gc_prediction_latest.jsonoutput/Data-prediction/prediction_latest.json(legacy GC)
สำหรับ GoldQuant ใน Docker ให้ mount D:/GetDataCMEBoy/output แบบ read-only แล้วตั้ง CME_OUTPUT_DIR ให้ตรง mount path
Intraday filenames partition ตาม UTC bar_time ไม่ใช่ queue run_date แบบบังคับ หาก recovery คืน bars หลายวัน ระบบ export แยกไฟล์ตามวันจริง ห้าม copy/rename ข้อมูลวันเก่าให้เป็นวันใหม่เพื่อหลอก freshness check
เรียกผ่าน dashboard proxy ซึ่งเป็นผู้ใส่ API token ให้ backend:
$body = @{
jobType = 'INTRADAY'
symbol = 'GC'
timeframe = '1m'
idempotencyKey = 'manual-intraday-gc-1m-20260713-slot1'
} | ConvertTo-Json
$accepted = Invoke-RestMethod `
-Method Post `
-Uri 'http://127.0.0.1:3000/api/pipeline/run' `
-ContentType 'application/json' `
-Body $body
Invoke-RestMethod "http://127.0.0.1:3000$($accepted.statusUrl)"POST ตอบ 202 Accepted; poll statusUrl จน terminal=true. GET /api/pipeline/run ตอบ 405 และไม่เริ่มงาน
npm ci
npm run lint
npm run build
npm test
pytest -q
docker compose config --quietconfig/cme-cookies.json ถูกกันออกจาก build context และ mount แบบ read-only ให้ worker เมื่อ cookie หมดอายุ:
npm run script:cme-login
docker compose restart fetcherแก้ MFA ใน browser บน host แล้วตรวจว่าไฟล์ cookie ถูกอัปเดต ห้าม commit หรือ bake cookie เข้า image