- eurofxref-hist.zip milik ECB hanyalah kumpulan CSV kurs tukar yang sederhana, tetapi dengan
curl, gunzip, dan sqlite3 saja kita bisa langsung menemukan tanggal saat dolar paling kuat terhadap euro, yaitu 2000-10-26
- Format asli berupa wide format dengan kolom mata uang mengikuti
Date, sehingga kurang nyaman untuk analisis dan perlu dirapikan menjadi long format berbentuk Date,Currency,Rate
- Karena ada trailing comma di akhir setiap baris, parser CSV membaca kolom kosong, sehingga di Pandas perlu menghapus kolom terakhir dengan
.iloc[:,:-1] agar hasil melt bersih
- CSV yang sudah dirapikan dapat diunggah ke csvbase lewat HTTP PUT lalu disambungkan dengan alat seperti
gnuplot, DuckDB, dan sqlite3 untuk membuat grafik, menghitung moving average, dan memuat CSV lewat HTTP
- Data publik yang bisa diambil tanpa negosiasi akses, autentikasi, kuota, atau dokumentasi API yang rumit dapat berfungsi seperti open API, dan file zip sederhana pun bisa menjadi dasar pertukaran data untuk aplikasi finansial
Mengueri kurs tukar hanya dengan satu file zip
- ECB mempublikasikan data historis kurs euro terhadap mata uang lain dalam bentuk file zip resmi
- Pipeline di bawah ini mengunduh data, mengekstrak isinya, membaca CSV ke SQLite in-memory DB, lalu mengurutkan berdasarkan nilai USD untuk mengambil tanggal pertama
curl -s https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip \
| gunzip \
| sqlite3 ':memory:' '.import /dev/stdin stdin' \
"select Date from stdin order by USD asc limit 1;"
- Output-nya adalah
2000-10-26
curl -s mengurangi noise di standard error, dan gunzip mengekstrak file zip
- Di Mac OS atau BSD,
gunzip keluarga BSD tidak mendukung file zip, jadi perlu memakai bsdtar -xOf - sebagai gantinya
sqlite3 ':memory:' memakai DB in-memory, dan .import /dev/stdin stdin memuat standard input ke tabel stdin
Merapikan bentuk CSV dan Pandas melt
- Header CSV asli berbentuk wide format seperti
Date,USD,JPY,BGN,CYP,CZK,DKK,..., dengan kolom tanggal diikuti kolom per mata uang
- Untuk filter dan agregasi, long format berbentuk
Date,Currency,Rate lebih mudah digunakan
- Proses mengubah wide format menjadi long format biasa disebut melt
- Kebanyakan database SQL tidak punya operasi yang setara dengan melt, sehingga Pandas berguna untuk perapian data
curl -s https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip | \
gunzip | \
python3 -c 'import sys, pandas as pd
pd.read_csv(sys.stdin).melt("Date").to_csv(sys.stdout, index=False)'
- File ECB memiliki trailing comma di akhir setiap baris, sehingga parser CSV menambahkan kolom kosong di bagian akhir
- Kolom kosong ini membuat baris tak berguna di akhir hasil
melt, jadi perlu dihapus
curl -s https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip | \
gunzip | \
python3 -c 'import sys, pandas as pd
pd.read_csv(sys.stdin).iloc[:, :-1].melt("Date")\
.to_csv(sys.stdout, index=False)'
.iloc[:, :-1] memilih semua baris dan semua kolom kecuali kolom terakhir
- Data valas ECB memang perlu sedikit perapian format, tetapi bisa langsung dipakai tanpa negosiasi akses, pembayaran, bicara dengan sales, mengirim email·nama perusahaan·jabatan, kuota, autentikasi, atau membaca dokumentasi API
- Karena hanya perlu menangani masalah format dan bentuk dasar, ini termasuk rilis data publik yang relatif bagus
Mengunggah data yang sudah dirapikan ke csvbase
- CSV yang sudah dirapikan bisa diunggah ke csvbase table agar tidak perlu mengulangi proses perapian
- Cukup tambahkan satu
curl lagi di akhir pipeline yang ada untuk mengunggah CSV lewat HTTP PUT
curl -s https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip | \
gunzip | \
python3 -c 'import sys, pandas as pd
pd.read_csv(sys.stdin).iloc[:, :-1].melt("Date")\
.to_csv(sys.stdout, index=False)' | \
curl -n --upload-file - \
'https://csvbase.com/calpaterson/eurofxref-hist?public=yes'
--upload-file - mengunggah data yang diterima dari standard input ke URL yang ditentukan
- Jika tabel belum ada di csvbase, tabel baru akan dibuat; jika sudah ada, data dimasukkan ke tabel tersebut
-n memakai informasi autentikasi dari ~/.netrc
Menggambar grafik kurs dengan gnuplot
- Tabel csvbase yang sudah dirapikan bisa diambil sebagai CSV dengan
curl, lalu disambungkan ke grep, cut, dan gnuplot
curl -s https://csvbase.com/calpaterson/eurofxref-hist | \
grep USD | \
cut -d, -f 2,4 | \
gnuplot -e "set datafile separator ','; set term dumb; \
plot '-' using 1:2 with lines title 'usd'"
- Perintah ini menggambar lebih dari 6.000 titik data sebagai ASCII art yang masih cukup bisa dibaca di terminal karakter 80x25
- Konfigurasi
gnuplot diatur agar menerima input CSV dan menggambar tanggal serta kurs sebagai grafik garis
set datafile separator ',': menyatakan bahwa input adalah CSV
set term dumb: menggambar sebagai ASCII art
plot -: menerima data dari standard input
using 1:2 with lines: menggambar garis dari kolom 1 dan 2, yaitu tanggal dan kurs
title 'usd': menetapkan nama garis menjadi usd
- Output juga bisa dibuat sebagai gambar SVG, dan agar terlihat seperti data deret waktu, sumbu x perlu ditandai sebagai waktu serta format waktu dan rotasi tick sumbu x perlu diatur
- Untuk pemakaian berulang, ini bisa dibungkus dalam fungsi Bash
plot_timeseries_to_svg
Menghitung moving average dengan DuckDB
- Untuk melihat garis tren kurs USD, kita bisa menghitung moving average dengan DuckDB
curl -s https://csvbase.com/calpaterson/eurofxref-hist | \
duckdb -csv -c "select Date, avg(value) over \
(order by date rows between 100 preceding and current row) \
as rolling from read_csv_auto('/dev/stdin')
where variable = 'USD';" | \
plot_timeseries_to_svg rolling
- Jika tidak ada
duckdb, tidak sulit mengubah kueri yang sama untuk sqlite3
- DuckDB mirip SQLite, tetapi berorientasi kolom alih-alih berorientasi baris
- DuckDB dapat membaca CSV langsung dari HTTP dan membuatnya menjadi file tabel
CREATE TABLE eurofxref_hist AS SELECT * FROM
read_csv_auto("https://csvbase.com/calpaterson/eurofxref-hist");
- DuckDB cukup bagus dalam inferensi tipe, dan secara default mendeteksi ukuran terminal lalu menyingkat hasil besar saat ditampilkan
- Untuk kueri besar, DuckDB bisa menampilkan progress bar dan juga dapat mengeluarkan tabel Markdown
Cara data publik bekerja seperti open API
- Hanya dengan CSV di dalam file zip dan alat yang mudah dipasang lewat
brew install atau apt install, kita sudah bisa melakukan banyak hal
eurofxref-hist.zip adalah bentuk yang sangat sederhana dari protokol pertukaran data antarorganisasi
- File zip ini terlihat kecil, tetapi banyak aplikasi finansial memakainya setiap hari
- Alasan ECB membiarkan trailing comma apa adanya kemungkinan karena menghapusnya sekarang akan merusak banyak kode yang sudah ada
- Jika data publik disediakan dengan sangat mudah, itu juga dapat berperan sebagai open API
- Jika banyak API pada dasarnya lebih mirip pertukaran data daripada pemanggilan fungsi jarak jauh, maka secara fungsional tidak jauh berbeda dari data publik yang mudah diambil
URL sederhana dan kata kerja HTTP di csvbase
- csvbase memberi satu URL untuk setiap tabel
https://csvbase.com/<username>/<table_name>
- Contohnya sebagai berikut
https://csvbase.com/calpaterson/eurofxref-hist
- Setiap URL memiliki empat kata kerja HTTP utama
GET: mengambil CSV; di browser juga bisa mendapatkan halaman web
PUT: membuat tabel baru dengan CSV baru atau menimpa tabel yang ada
POST: menambahkan baris CSV dalam jumlah besar ke tabel yang sudah ada
DELETE: menghapus tabel tersebut
- Autentikasi memakai HTTP Basic Auth
Catatan tentang perapian data dan pipeline
- Di antara database SQL, fitur yang setara dengan melt tersedia misalnya pada UNPIVOT milik Snowflake dan PIVOT/UNPIVOT milik MS SQL Server
- Salah satu alasan penting R dan Pandas banyak dipakai adalah kuatnya kemampuan perapian data
- Pipeline Bash bekerja secara multiproses, sehingga tiap program berjalan paralel dalam proses yang terpisah
- Pada Oktober 2000, kurs dolar terhadap euro adalah
0.8252, yang berarti 1 dolar bisa membeli 1,21 euro
- Euro diluncurkan pada Januari 1999 tanpa uang kertas dan koin; pada awalnya hanya ada di dalam sistem perbankan, dan uang kertas serta koin menyusul kemudian
1 komentar
Komentar Hacker News
Saya ingat file ini saat bekerja di ECB sekitar 15 tahun lalu
File ini sejauh ini adalah file yang paling banyak diunduh dari situs web ECB, dan banyak orang serta lembaga keuangan mengunduhnya setiap hari untuk memperbarui sistem mereka
Selama beberapa menit tepat setelah waktu rilis harian yang sudah ditentukan, trafik melonjak tajam, dan keputusan untuk membuatnya menjadi file CSV sederhana setelah diekstrak memang disengaja
Berkat itu, file bisa disajikan dengan stabil dan cepat, memakai sedikit sumber daya, dan tim kecil yang saat itu mengelola situs web publik ECB memang layak sangat bangga atas keputusan teknis untuk menyajikan data ini sebagai satu file statis
Tidak mencolok dan tidak memakai framework
Sekitar 15 tahun lalu, saya menangani pertukaran data di sebuah perusahaan besar lama yang produknya mungkin pernah dibeli siapa saja, antara sistem pencatatan produk dan sub-sistem/sistem paralel yang tersisa dari merger dan akuisisi; kebanyakan berupa impor/ekspor massal file fixed-width atau file ber-delimiter melalui server SFTP
Saat itu produknya sendiri sudah berumur 15 tahun, dan ada sekitar 20–30 sumber data atau ekspor semacam itu yang berjalan bolak-balik, tetapi semuanya berjalan sangat baik
Kemungkinan besar masih dipakai sekarang tanpa banyak perubahan, dan saat itu frontend-nya sedang ditulis ulang dari versi lama berbasis Smalltalk
Dari semua sumber data yang kami gunakan, ini yang paling mudah ditangani
Arsitek akan bilang ZIP bukan format yang sesuai spesifikasi untuk tujuan ini, compliance akan bilang perlu pemeriksaan kebocoran data pribadi, dan pihak risk akan bilang harus mencegah aktor jahat mengunduh file tersebut
Tim web mungkin akan bilang bahwa menambahkan sesuatu ke situs memerlukan prosedur perubahan yang disetujui
Unduhan file sederhana dan file CSV itu bagus
Saya berharap lebih banyak pihak memublikasikan data dalam format sederhana seperti ini, dan setiap kali harus mengisi “keranjang belanja” untuk mengunduh data pemerintah AS, rasanya sedikit mati di dalam
Ada banyak tool wrapper yang memudahkan pipeline khusus ini, dan jika perlu tampilan web serta fitur yang sedikit lebih canggih, sesuatu seperti Datasette juga bagus
Anda bisa membaca file ZIP sebagai stream, memproses CSV baris demi baris untuk melakukan transformasi, lalu memuatnya ke database dengan COPY FROM stdin pada Postgres
Kedengarannya begitu logis dan berguna, tetapi saya belum pernah menemukannya sampai sekarang
Karena ada banyak laporan dalam bentuk CSV, saya ingin segera mencobanya untuk menjalankan kueri dengan cepat
Misalnya, cara menangani tanda kutip bisa bercabang seperti
"Look, this contains \"quotes\"!",012345dan"Look, this contains ""quotes""!",012345, dan contoh yang lebih rusak seperti"Look, this contains "quotes"!",012345atauLook, this contains "quotes"!,012345juga bisa munculJejak spreadsheet juga bisa memotong nol di depan, seperti
"Look, this contains ""quotes""!",12345Secara teori, JSON juga bisa diedit manual hingga menjadi file yang setengah rusak, tetapi dalam praktiknya saya hampir tidak pernah melihat orang melakukan itu pada file JSON, dan nilai seperti nomor seri pun dalam JSON cenderung tetap berupa string, bukan integer yang nol depannya dipotong oleh aplikasi yang “membantu”
Sebenarnya mengapa begitu, apakah ada alasan yang sah?
Bahkan jika CSV diganti menjadi dokumen JSON yang dibungkus ZIP, keuntungannya tetap sama
Masalah sebenarnya adalah terlalu banyak hambatan untuk sekadar mengunduh satu file yang disajikan secara statis
Saya pernah membuat API untuk lembaga pemerintah, dan datanya hanya berubah setahun sekali atau direvisi sangat jarang
Seluruh dataset bisa dibungkus menjadi satu file ZIP kurang dari 1MB, tetapi urusannya membesar ketika solution architect menetapkan requirement
Karena data bisa saja berubah tepat pada saat request dilakukan, cache tidak boleh dipakai, sehingga API menjadi lambat, dan bahkan muncul sistem webhook yang terlalu rumit untuk memberi tahu pelanggan tentang perubahan data
Satu file ZIP mungkin terlalu sederhana, tetapi sebenarnya tidak jauh berbeda dari yang benar-benar dibutuhkan
Jika ingin dibuat lebih keren, tambahkan webhook yang dipicu ketika file berubah, sehingga klien tahu kapan harus mengunduh ulang tanpa melakukan polling sekali sehari
Atau cukup buat skrip yang mengirim email yang sudah ditentukan ke mailing list saat ada perubahan
Jika tidak ada yang berubah dari sebelumnya, Anda mendapat respons HTTP 304 kosong; jika berubah, Anda menerima lagi file ZIP kurang dari 1MB bersama ETag baru. Saya tidak tahu apa yang kurang dari ini
Cache menambah kompleksitas dan juga menciptakan risiko harus memvalidasi ulang cache secara manual, jadi mungkin saja solution architect itu benar
Jika harus mengunduh file 565 KB hanya untuk mendapatkan satu nilai hasil
2000-10-26, itu API yang mengerikan.Kalau tujuannya mengambil data dalam jumlah besar lalu menyajikannya kembali ke pengguna, CSV yang dibundel dalam ZIP itu bagus, dan jauh lebih saya sukai daripada protobuf untuk jadwal kereta real-time transportasi publik yang dukungan multibahasanya kurang baik.
Namun kalau diperlakukan seperti API untuk mendapatkan satu nilai, itu pemborosan besar, dan saya harap tidak ada orang yang memasukkannya ke aplikasi dengan cara seperti ini.
Tulisannya sendiri keren, tetapi judulnya terasa terlalu seperti klaim yang provokatif.
Sama sekali tidak ada alasan untuk memintanya lebih dari sekali sehari, dan orang yang menggunakan data seperti ini kemungkinan menginginkan filter atau agregasi yang sangat berbeda satu sama lain.
Kalau dipakai untuk mendapatkan nilai tukar saat ini, memang desainnya buruk, tetapi ada layanan lain untuk tujuan itu, dan file ini cocok dengan kasus penggunaan yang umum.
Tidak terkait langsung dengan API, tetapi dulu saat mendukung aplikasi pengelolaan lahan, sebelum versi baru keluar aplikasi itu berjalan baik bahkan di kantor satelit lambat yang koneksinya mungkin setara ISDN, tetapi versi barunya sama sekali tidak bisa.
Vendor menyuruh menjalankannya di server RDP, tetapi saya merasa itu tidak masuk akal, jadi saya selidiki. Ternyata satu panggilan tertentu tanpa alasan melakukan
SELECT * FROM sometable, sementara panggilan lain dalam eksekusi yang sama memakai klausa SQL select yang benar.Saat kami memberi tahu vendor soal ini, awalnya mereka sangat bingung bagaimana kami bisa mengetahuinya, dan akhirnya mereka merilis versi baru yang diperbaiki agar bisa dipakai juga di koneksi lambat.
Sulit dipahami kenapa pengujian internal mereka tidak menangkap itu dan malah mendorong solusi mahal ke pelanggan.
Kalau belakangan ini Anda pernah melihat JavaScript sedikit saja, 565 KB beserta logika untuk mencari nilai terbesar di dalamnya tergolong sangat kecil menurut standar wajar apa pun.
Sebagian orang menganggap “cara mendapatkan data, meskipun menerima seluruh data tanpa pemfilteran” sebagai API, tetapi secara pribadi saya melihat unduhan seluruh tabel sebagai unduhan model data yang logikanya tidak berjalan pada model tersebut, sedangkan API adalah logika yang memfilter sebagian model dan mengembalikannya dengan cara yang saya minati.
Saya cukup banyak membuat software finansial di sisi backend maupun frontend, dan di frontend sayangnya cukup umum mengirim “data” sebanyak itu bahkan sebelum sampai ke data sebenarnya.
Di backend, ini hanya keputusan desain, dan tidak ada yang lebih cepat daripada cron job malam hari yang mem-parse nilai tukar, membuat
todays-rates.jsonyang disesuaikan untuk tujuan tertentu, lalu menyajikannya sebagai file statis ke aplikasi mobile, web, dan microservice.Tidak ada satu pun yang berarti aplikasi mobile harus mengonsumsi ZIP-CSV-over-HTTP ini secara langsung.
Ada optimasi yang sangat sederhana untuk orang yang mengeluh harus mengambil file besar setiap kali membutuhkan satu data kecil.
Jika file dijamin append-only dan menggunakan kompresi seperti HTTP gzip/brotli alih-alih file ZIP, maka dengan range request kita bisa hanya mengambil data baru sejak pembaruan terakhir.
Tambahkan satu header checksum untuk ketenangan, dan itu menjadi API inkremental yang cukup efisien sekaligus sangat sederhana.
Tentu saja Anda harus menyimpan state dan menanggung biaya unduhan pertama serta pemeliharaan state, dan ini tidak efisien jika Anda hanya butuh tepat satu nilai tukar EUR/JPY pada 2007-08-22 untuk sekali saja.
Masih sangat dalam pengerjaan, tetapi kode “kualitas riset” saat ini ada di sini: https://pypi.org/project/csvbase-client/
https://github.com/gtsystem/python-remotezip
Dengan satu patch harian saja, bandwidth yang saya perlukan untuk menjaga file tetap mutakhir bisa berkurang drastis.
Ini kalau mengunduh beberapa ratus KB ekstra per hari memang berarti; kemungkinan besar biasanya tidak.
Ada typo pada contoh
sqlite.Tidak terlihat di tangkapan layar, tetapi argumen -csv harus ditambahkan ke
sqlite.Saya akan menambahkannya kembali dan menginvalidasi cache. Nanti setelah menidurkan anak-anak saya akan memeriksa apa yang salah.
Edit: alasan itu berjalan di lingkungan saya adalah karena ada pengaturan
.separator ','di~/.sqliterc.Sepertinya dulu saya menyadari bahwa saya terutama memasukkan file CSV dan menjadikannya default.
Sedikit menyimpang: meskipun euro pada awalnya hanya ada secara elektronik, ia memiliki nilai tukar tetap terhadap mata uang lama negara-negara anggota zona euro.
Khususnya, ia dipatok ke Deutsche Mark Jerman yang sudah mapan dan tepercaya.
Jadi untuk menjelaskan “mengapa euro awalnya lemah”, perlu juga dijelaskan mengapa DEM saat itu lemah, dan penjelasan di paragraf tersebut sepertinya tidak lolos uji itu.
Untuk masalah kecil di mana Anda bisa mengunduh seluruh database setiap kali dan memperlakukannya sebagai read-only, nilai kesederhanaan tidak boleh diremehkan.
Saya suka SQLite karena portabel seperti file
.jsonatau.csv, tetapi lebih siap untuk berinteraksi seperti database.clickhouse-local, file CSV lama pun bisa diperlakukan seperti database.Intinya ada di sini.
Hal-hal yang dalam kasus ini tidak perlu dilakukan: negosiasi hak akses, misalnya membayar atau berbicara dengan sales, memasukkan alamat email, nama perusahaan, dan jabatan ke database prospek seseorang, mematuhi kuota, autentikasi, membaca dokumentasi API, atau menangani masalah yang lebih serius daripada format dan struktur dasar.
Bandwidth tidak gratis.
SQLite bisa membaca dan menulis file ZIP.
https://sqlite.org/zipfile.html
Saya penasaran apakah dekompresi bisa dilakukan dengan
sqlite3alih-alihgunzip.Jika file boleh disimpan ke disk, bisa dilakukan seperti ini:
sqlite3 -newline '' ':memory:' "SELECT data FROM zipfile('eurofxref-hist.zip')" \| sqlite3 -csv ':memory:' '.import /dev/stdin stdin' \"select ...;"