Eksperimen VonmoTrade. Bagian 4: Grafik Perdagangan


Dalam artikel sebelumnya, kami menemukan cara pembuatan dan pemrosesan pesanan perdagangan. Topik artikel ini adalah masalah pemrosesan dan penyimpanan informasi yang diperlukan untuk alat grafis analisis pasar - grafik saham.


Sebelum memulai, saya ingin melakukan penyimpangan kecil. Untuk proyek Vonmo internal, skema penamaan kata V + biasa digunakan, yang paling ringkas menggambarkan fungsi proyek. Hari ini saya menemukan bahwa VTrade adalah perusahaan yang sudah ada. Untuk menghindari kebingungan, saya mengganti nama eksperimen menjadi VonmoTrade.


Untuk menilai keadaan pasar, satu buku pesanan dan riwayat transaksi tidak cukup. Kami membutuhkan alat yang memungkinkan kami untuk mengidentifikasi dengan jelas dan cepat tren harga pasar. Grafik perdagangan dapat dibagi menjadi dua jenis:


  1. Linier;
  2. Interval

Grafik garis


Jadwal paling sederhana dan paling mudah dipahami tanpa persiapan. Menampilkan ketergantungan harga instrumen keuangan tepat waktu.



Keuntungan utama dari jenis grafik ini adalah kesederhanaan. Kelemahan utama mengikutinya - konten informasi rendah.


Jika grafik didasarkan pada data mentah, maka harga penutupan terakhir diambil. Tetapi biasanya, grafik dibangun berdasarkan data yang dikumpulkan. Dalam hal ini, harga penutupan setiap interval diambil. Karena kami membuang semua yang terjadi dalam interval dan hanya mengambil harga penutupan interval, karena itu, konten informasi hilang.


Resolusi Grafik


Jika kita mulai membangun grafik berdasarkan semua perubahan harga, yaitu, setiap transaksi yang ditutup akan jatuh pada grafik, maka akan sulit bagi seseorang untuk melihatnya. Dan daya yang dihabiskan untuk pemrosesan dan pengiriman jadwal seperti itu akan dihabiskan secara tidak efisien.


Oleh karena itu, data diperkecil dengan membagi sumbu waktu menjadi interval dan menjumlahkan harga dalam interval ini.
Resolusi - ukuran interval dasar untuk membagi sumbu waktu: detik, menit, jam, hari, dan sebagainya.


Bar


Berhubungan dengan grafik interval. Untuk meningkatkan konten informasi, perlu setiap interval waktu untuk menampilkan informasi harga di awal dan akhir interval, serta harga maksimum dan minimum. Tampilan grafis dari set ini disebut bilah. Pertimbangkan skema satu batang:



Urutan bilah membentuk bagan:



Lilin jepang


Seperti bar, lihat diagram interval. Mereka adalah jenis grafik yang paling populer dalam analisis teknis. Lilin terdiri dari tubuh hitam dan putih dan bayangan: atas dan bawah. Terkadang bayangan disebut sumbu. Batas atas dan bawah bayangan menampilkan harga maksimum dan minimum untuk periode yang sesuai. Batas-batas tubuh menampilkan harga pembukaan dan penutupan. Mari kita menggambar lilin:



Urutan lilin membentuk grafik:



Notasi OHLCV


Pada artikel terakhir, kami menemukan skema penyimpanan data untuk grafik di postgresql dan membuat tabel untuk sumber data yang akan menyimpan data agregat:


CREATE TABLE df ( t timestamp without time zone NOT NULL, r df_resolution NOT NULL DEFAULT '1m'::df_resolution, o numeric(64,32), h numeric(64,32), l numeric(64,32), c numeric(64,32), v numeric(64,32), CONSTRAINT df_pk PRIMARY KEY (t, r) ) 

Fields tidak memerlukan penjelasan, kecuali field r adalah resolusi seri. Ada enumerasi di postgresql, mereka nyaman digunakan ketika satu set nilai untuk bidang diketahui sebelumnya. Melalui enumerasi, kami mendefinisikan tipe baru untuk resolusi grafik yang diizinkan. Jadikan seri dari satu menit menjadi satu bulan:


 CREATE TYPE df_resolution AS ENUM ('1m', '3m', '5m', '15m', '30m', '45m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w', '1M'); 

Penting untuk mencapai keseimbangan antara kinerja sistem disk, prosesor, dan total biaya kepemilikan. Sistem saat ini menetapkan 16 resolusi. Dua solusi sudah jelas:


  • Kami dapat menghitung dan menyimpan semua resolusi dalam database. Opsi ini nyaman karena ketika pengambilan sampel kami tidak menghabiskan daya pada agregasi interval, semua data segera siap untuk output. Dalam sebulan, sedikit lebih dari 72 ribu catatan akan dibuat untuk satu instrumen. Ini terlihat sederhana dan nyaman, bagaimanapun, tabel seperti itu akan berubah terlalu sering, karena untuk setiap pembaruan harga perlu untuk membuat atau memperbarui 16 entri dalam tabel dan membangun kembali indeks. Dalam postgresql, mungkin ada masalah dengan pengumpulan sampah.
  • Pilihan lain adalah menyimpan satu resolusi dasar. Ketika memilih dari resolusi dasar, resolusi yang diperlukan harus dibangun. Misalnya, ketika menyimpan resolusi menit sebagai basis per bulan, 43 ribu catatan akan dibuat untuk setiap instrumen. Jadi, dibandingkan dengan versi sebelumnya, volume perekaman dan overhead berkurang sebesar 40%. Akan tetapi, beban prosesor meningkat.

Seperti disebutkan di atas, penting untuk menemukan keseimbangan. Oleh karena itu, opsi kompromi bukan untuk menyimpan satu resolusi dasar, tetapi beberapa: 1 menit, 1 jam, 1 hari. Dengan skema ini, 44,6 ribu catatan akan dibuat untuk setiap instrumen per bulan. Optimalisasi volume rekaman akan menjadi 36%, tetapi beban pada prosesor akan dapat diterima. Misalnya, untuk membuat interval mingguan alih-alih membaca dan mengumpulkan 10.080 catatan dalam kasus resolusi dasar satu menit, kita perlu membaca dari disk dan menggabungkan data hanya dengan resolusi 7 hari.


Penyimpanan OHLCV


Secara alami, OHLCV adalah deret waktu. Seperti yang Anda ketahui, basis data relasional sangat tidak cocok untuk menyimpan dan memproses data tersebut. Untuk mengatasi masalah ini, proyek menggunakan ekstensi Timescale .


Timescale meningkatkan kinerja operasi penyisipan dan pembaruan, memungkinkan Anda untuk mengkonfigurasi partisi, dan menyediakan fungsi analitis yang dioptimalkan secara khusus untuk bekerja dengan deret waktu.


Untuk membuat dan memperbarui bilah, kita hanya perlu fungsi standar:


  • date_trunc('minute' | 'hour' | 'day', transaction_ts) - untuk menemukan masing-masing interval awal resolusi menit, jam, dan hari.
  • greatest dan least untuk menentukan harga maksimum dan minimum.

Berkat api upert, hanya satu permintaan pembaruan dieksekusi per transaksi.
Saya mendapatkan SQL semacam ini untuk memperbaiki perubahan pasar dalam resolusi dasar:


 FOR i IN 1 .. array_upper(storage_resolutions, 1) LOOP resolution = storage_resolutions[i]; IF resolution = '1m' THEN SELECT DATE_TRUNC('minute', ts) INTO bar_start; ELSIF resolution = '1h' THEN SELECT DATE_TRUNC('hour', ts) INTO bar_start; ELSIF resolution = '1d' THEN SELECT DATE_TRUNC('day', ts) INTO bar_start; END IF; EXECUTE format( 'INSERT INTO %I (t,r,o,h,l,c,v) VALUES (%L,%L,%L::numeric,%L::numeric,%L::numeric,%L::numeric,%L::numeric) ON CONFLICT (t,r) DO UPDATE SET h = GREATEST(%Ih, %L::numeric), l = LEAST(%Il, %L::numeric), c = %L::numeric, v = %Iv + %L::numeric;', df_table, bar_start, resolution, price, price, price, price, volume, df_table, price, df_table, price, price, df_table, volume ); END LOOP; 

Saat pengambilan sampel, untuk agregasi interval, kita memerlukan fungsi berikut:


  • time_bucket - untuk masuk ke interval
  • first - untuk menemukan harga pembukaan - O
  • max - harga tertinggi untuk interval - H
  • min - harga terendah per interval - L
  • last - untuk menemukan harga penutupan - C
  • sum - untuk menemukan volume perdagangan - V

Satu-satunya masalah yang ditemukan saat menggunakan Timescale adalah keterbatasan fungsi time_bucket . Ini memungkinkan Anda untuk beroperasi hanya dengan interval kurang dari sebulan. Untuk membangun resolusi bulanan, Anda harus menggunakan fungsi date_trunc standar.


API


Untuk menampilkan grafik pada klien, kami akan menggunakan grafik ringan dari Tradingview. Perpustakaan memungkinkan Anda untuk sepenuhnya menyesuaikan tampilan grafik dan nyaman digunakan. Saya mendapat grafik berikut:



Karena bagian utama dari interaksi antara browser dan platform adalah melalui websocket, tidak ada masalah dengan interaktivitas.


Sumber data


Sumber data untuk grafik (umpan data) harus mengembalikan bagian yang diperlukan dari rangkaian waktu dalam resolusi yang diperlukan. Pada saat yang sama, untuk menghemat lalu lintas dan mengurangi waktu pemrosesan pada klien, server harus mengemas poin.


API umpan data pada awalnya perlu dirancang agar Anda dapat meminta beberapa grafik dalam satu permintaan dan berlangganan pembaruan mereka. Ini akan mengurangi jumlah perintah dan respons di saluran.


Pertimbangkan contoh permintaan 50 menit terakhir untuk USDGBP, dengan berlangganan otomatis ke pembaruan grafik:


 { "m":"market", "c":"get_chart", "v":{ "charts":[ { "ticker":"USDGBP", "resolution":"1h", "from":0, "cnt":50, "send_updates":true } ] } } 

Anda bisa, tentu saja, meminta rentang tanggal (dari, ke), tetapi karena interval setiap bilah diketahui, API deklaratif yang menunjukkan momen dan jumlah bilah tampaknya lebih nyaman bagi saya.
Umpan data untuk permintaan ini akan merespons dengan cara yang sama:


 { "m":"market", "c":"chart", "v":{ "bar_fields":[ "t","uts","o","h","l","c","v" ], "items":[ { "ticker":"USDGBP", "resolution":"1h", "bars":[ [ "2019-12-13 13:00:00",1576242000,"0.75236800", "0.76926400","0.75236800","0.76926400","138.10000000" ], .... ] } ] } } 

Bidang bar_fields berisi informasi tentang posisi elemen. Pengoptimalan lebih lanjut adalah menempatkan bidang ini dalam konfigurasi klien yang diterima dari server pada saat boot.


Dengan demikian, klien menerima bagian yang diperlukan dari data historis dan membangun keadaan awal grafik. Jika keadaan berubah, ia menerima pembaruan yang hanya memengaruhi bilah terakhir.


 { "m":"market", "c":"chart_tick", "v":{ "ticker":"USDGBP", "resolution":"1h", "items":{ "v":"140.600", "ut":1576242000, "t":"2019-12-13T13:00:00", "o":"0.752368", "l":"0.752368", "h":"0.770531", "c":"0.770531" } } } 

Hasil awal


Sepanjang serangkaian artikel, kami telah menganalisis teori dan praktik membangun pertukaran. Saatnya untuk menyatukan sistem.


Pada artikel selanjutnya, kami akan membahas pengembangan antarmuka pengguna grafis: UI layanan untuk manajemen platform dan UI untuk pengguna akhir. Versi demo Vonmo Trade juga akan disajikan.

Source: https://habr.com/ru/post/id483308/


All Articles