Cara menggunakan error javascript tradingview

penyangkalan. Artikel ini tidak dimaksudkan sebagai saran investasi atau keuangan - ini dimaksudkan murni sebagai tutorial teknis untuk pengembangan dan penelitian perangkat lunak. Kode yang diberikan hanya untuk tujuan pendidikan, apa adanya, tanpa jaminan

Lihat Pengantar seri tutorial ini, jika Anda belum melakukannya. Menyiapkan grafik TradingView bisa menjadi proses yang berbelit-belit, jadi mohon maaf atas penafian dan catatan

Penafian. Pustaka charting TradingView adalah proyek pribadi gratis di Github yang harus Anda ajukan untuk aksesnya. Perjanjian lisensi yang saya yakini melarang saya untuk mendistribusikannya kepada Anda, jadi untuk menyelesaikan panduan ini sepenuhnya, Anda perlu mengajukan permohonan akses untuk mengunduh pustaka pembuatan bagan

Untuk menjalankan bagian tutorial ini secara lokal (dengan asumsi Anda memiliki akses ke library charting) clone repo yang tersedia di bawah ini, lalu salin folder library charting ke direktori /public/ di folder part1. Jalankan npm install lalu npm start untuk menjalankan server pengembangan

Tutorial repo. https. //github. com/jonchurch/tradingview-js-api-tutorial. git

Pratinjau yang Diterapkan. https. //tv-tut-part1. kesalahan. Saya/

TradingView memungkinkan Anda untuk menggunakan Charting Library mereka di situs Anda sendiri, dengan sumber data Anda sendiri

Ada dua cara untuk memasukkan data Anda ke TradingView, UDF API dan JS API. JS API memberi Anda kendali paling besar atas data Anda, dan menurut saya jauh lebih fleksibel. Ditambah itu Javascript

Anda dapat mengimplementasikan koneksi data hampir seperti yang Anda inginkan, tetapi detail implementasi sebenarnya cukup kabur. Tujuan dari tutorial ini adalah untuk menunjukkan kepada Anda contoh kerja penggunaan sumber data Anda sendiri dengan grafik TradingView untuk membuat grafik statis dasar

CATATAN. TradingView TIDAK memberi Anda sumber data ini, dan menganggap Anda telah mengimplementasikan sumber Anda sendiri. Tutorial ini mengandalkan API harga historis CryptoCompare sebagai sumber data untuk kenyamanan

Panduan ini dibuat dari React Javascript TradingView Contoh yang tersedia di sini

Ringkasan

Saat widget bagan pertama kali dimuat, widget ini akan memanggil metode JS API resolveSymbol dengan symbolName untuk pasangan default. Dalam contoh kita

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
0 adalah pasangan default. Anda diharapkan untuk meneruskan objek
{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
1 ke panggilan balik
{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
2 yang diteruskan ke fungsi resolveSymbol oleh pustaka charting

Seluruh integrasi terdiri dari beberapa bagian

  • TV Widget Constructor — mengambil objek opsi widget, mengirimkan umpan data, pasangan simbol default untuk ditampilkan, opsi pengguna, opsi memuat/menyimpan bagan
  • Datafeed — Antarmuka antara JS API dan backend Anda
  • JS API — Tanda tangan fungsi yang diperlukan oleh TV untuk menampilkan data Anda
  • Penyedia Riwayat — OHLCV bar API
  • Penyedia Realtime — Perbarui candle terbaru secara realtime, mulai candle baru
  • Penyimpanan Simbol — Daftar simbol yang tersedia

Bagian 1 membahas Konstruktor Widget TV, Datafeed, JS API, dan Penyedia Riwayat untuk membuat bagan statis tunggal, dengan pasangan simbol yang di-hardcode

Pembuat Widget

Opsi konstruktor widget mengonfigurasi widget TradingView Chart, dan memengaruhi fitur mana yang diaktifkan saat grafik dimuat pertama kali, serta opsi apa yang dapat diatur oleh pengguna

Di sini kami menetapkan opsi seperti ID Pengguna, pengaturan gaya, bahasa, pasangan simbol yang akan dimuat, jalur publik ke pustaka pembuatan bagan, dan meneruskan implementasi JS API Datafeed kami

Dokumen untuk opsi konstruktor widget tersedia di sini, ini akan 404 jika Anda belum mengajukan akses ke Charting Library

Berikut adalah opsi konstruktor yang kami mulai

const widgetOptions = {
debug: false,
symbol: 'Coinbase:BTC/USD',
datafeed: Datafeed, // our datafeed object
interval: '15',
container_id: 'tv_chart_container',
library_path: '/charting_library/',
locale: getLanguageFromURL() || 'en',
disabled_features: ['use_localstorage_for_settings'],
enabled_features: [],
client_id: 'test',
user_id: 'public_user_id',
fullscreen: false,
autosize: true,
overrides: {
"paneProperties.background": "#131722",
"paneProperties.vertGridProperties.color": "#363c4e",
"paneProperties.horzGridProperties.color": "#363c4e",
"symbolWatermarkProperties.transparency": 90,
"scalesProperties.textColor" : "#AAA",
"mainSeriesProperties.candleStyle.wickUpColor": '#336854',
"mainSeriesProperties.candleStyle.wickDownColor": '#7f323f',
}
};

Ini mengonfigurasi widget untuk menunjukkan kepada kami

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
0 dengan interval lilin 15 menit, dan menetapkan beberapa penyesuaian lainnya (fitur yang dinonaktifkan, pengaturan default untuk diganti, bahasa apa yang digunakan, dll)

Setelah dimuat, Anda tidak perlu mengubah salah satu opsi ini, tetapi widget menampilkan metode yang dapat digunakan untuk mengubah beberapa setelan secara dinamis. (mengganti simbol dapat dilakukan melalui pencarian simbol yang akan kita implementasikan pada tutorial bagian 3)

Saya telah menyetel bagan saya ke default ke mode gelap dengan menyetel

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
5

Integrasi Umpan Data JS API

Sekarang setelah widget dikonfigurasi dan ditata sesuka kita, mari kita lihat bagaimana kita menghubungkan data grafik kita ke JS API TradingView Charting Library

JS API benar-benar sebuah Objek yang Anda berikan ke Widget TradingView, yang memaparkan fungsi-fungsi yang akan dipanggil oleh TradingView, dan dalam kebanyakan kasus Anda diharapkan untuk meneruskan data ke Callback dalam fungsi-fungsi tersebut agar data Anda bekerja dengan tradingview

Sebagai contoh, kami menggunakan data bagan historis CryptoCompare*, dan di bagian 2, API websocket mereka untuk mendapatkan pembaruan harga waktu nyata

Tradingview akan memanggil metode yang Anda berikan sesuai kebutuhan untuk mengisi grafik saat ini dengan data, serta metode siklus hidup lainnya yang harus Anda implementasikan

Di bawah ini adalah seluruh tanda tangan objek JS API yang diharapkan Tradingview untuk Anda teruskan ke widget. Beberapa metode bersifat opsional, lihat dokumen untuk info lebih lanjut

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}

Saat bagan pertama kali dimuat, alur JS API berjalan seperti ini

1.

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
6 dipanggil, diteruskan ke
{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
7

2.

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
8 dipanggil, berikan objek symbolInfo ke
{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
9

3.

const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
_0 dipanggil, berikan array objek ohlcv dengan waktu UTC dalam milidetik ke
const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
1

Mari kita lihat implementasi kita untuk masing-masing ini

onReady

const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
6 dipanggil segera setelah widget bagan diinisialisasi, dan kita harus meneruskan opsi konfigurasi datafeed ke fungsi
const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
3
{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
7. Pustaka charting menginginkan ini dieksekusi secara asinkron, dan menyarankan pembungkusan dalam setTimeout dengan penundaan 0 untuk memaksa perilaku ini

Saat ini kami hanya menentukan kemungkinan,

const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
5 yang memberi tahu perpustakaan bagan mana pilihan interval yang didukung umpan data kami untuk bilah. Ini akan ditampilkan kepada pengguna, dan dapat diganti per pasangan simbol nanti di resolveSymbol. Daftar yang kami sediakan diterjemahkan

const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
_7

Nanti di tutorial kita akan menambahkan opsi ke konfigurasi Datafeed kita, saat kita mengimplementasikan grafik pencarian dan realtime

solveSymbol

Setelah umpan data dikonfigurasi, pustaka pembuatan bagan akan memanggil

{
/* mandatory methods for realtime chart */
onReady: cb => {},
// only need searchSymbols when search is enabled
searchSymbols: (userInput, exchange, symbolType, onResultReadyCallback) => {},
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {},getBars: (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) => {},subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {},unsubscribeBars: subscriberUID => {},
/* optional methods */
getServerTime: cb => {},calculateHistoryDepth: (resolution, resolutionBack, intervalBack) => {},getMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {},getTimeScaleMarks: (symbolInfo, startDate, endDate, onDataCallback, resolution) => {}
}
8 dengan properti
const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
9 dari objek konfigurasi widget. Kami hanya diberi nilai string, dan harus mengembalikan objek symbolInfo yang mewakili simbol yang sesuai

resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}

Di sinilah Anda mengonfigurasi pasangan individu, mengatur jumlah tempat desimal untuk ditampilkan, berapa banyak pergerakannya per tick (untuk crypto hampir selalu 1), dan sangat penting dan mudah untuk dikacaukan,

resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
0. Karena crypto diperdagangkan tanpa henti, kami menyetel sesi ke
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
1. Zona waktu seharusnya menjadi zona waktu pertukaran simbol ini diperdagangkan, tidak terlalu penting dengan sesi 24 jam

Semua dokumentasi untuk symbolInfo ada di sini, pastikan Anda membiasakan diri dengannya

resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
2 dan
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
3 kontrol menunjukkan bar interval di bawah 1 hari. Sekarang di sinilah saya membuat banyak kesalahan. Tradingview dapat membangun beberapa bar untuk Anda. Sebagai contoh, anggaplah API data historis kita hanya dapat memberi kita data untuk interval 1 menit, artinya jika kita meminta data 24 jam terakhir, kita akan mendapatkan 1440 poin data, jumlah menit dalam 24 jam. Tetapi bagaimana jika kita ingin menampilkan bar 15 menit? . Pustaka charting akan membuat bar 15 menit untuk Anda, dan menampilkannya di chart

Kami melakukan hal yang sama untuk bar jam, memberi tahu tradingview bahwa kami dapat menyediakan bar 60 menit, dan itu harus membangun bar 2 jam dan 4 jam kami sendiri dari bar 60 menit kami

Ticker juga sangat penting. Jika disetel, pustaka bagan akan menggunakan ticker secara internal untuk merujuk ke pasangan unik ini (nilai ticker akan dikirim ke resolveSymbol sebagai ganti bidang nama). Bidang nama inilah yang akan ditampilkan kepada pengguna. Saya menyetel

resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
6 dan
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
7 ke nilai yang sama untuk membuat hidup saya lebih mudah, dan karena nama yang saya gunakan menyertakan semua informasi yang saya perlukan untuk mengidentifikasi simbol. pertukaran, ke simbol, dan dari simbol (mis. g. Coinbase. BTC/USD)

Skala harga sedikit menarik, karena pasangan yang berbeda dapat menggunakan presisi desimal yang berbeda. Misalnya, BTC/USD diukur hingga dua tempat desimal, jadi

resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
8 tetapi misalnya TRX/BTC (0. 00000771 BTC pada saat penulisan), kami mengukurnya ke satoshi, 8 desimal. Jadi untuk TRX/BTC
resolveSymbol: (symbolName, onSymbolResolvedCallback, onResolveErrorCallback) => {
var split_data = symbolName.split(/[:/]/)

var symbol_stub = {
name: symbolName,
description: '',
type: 'crypto',
session: '24x7',
timezone: 'America/New_York',
ticker: symbolName,
minmov: 1,
pricescale: 100000000,
has_intraday: true,
intraday_multipliers: ['1', '60'],
supported_resolution: ["1", "3", "5", "15", "30", "60", "120", "240", "D"],
volume_precision: 8,
data_status: 'streaming',
}
if (split_data[2].match(/USD|EUR|JPY|AUD|GBP|KRW|CNY/)) {
symbol_stub.pricescale = 100
}

setTimeout(function() {
onSymbolResolvedCallback(symbol_stub)
}, 0)
}
9 tetapi untuk TRX/USD ($0. 059432 pada saat penulisan), kita akan menggunakan 6 angka desimal dan
getBars: function(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {

historyProvider.getBars(symbolInfo, resolution, from, to, firstDataRequest)
.then(bars => {
if (bars.length) {
onHistoryCallback(bars, {noData: false})
} else {
onHistoryCallback(bars, {noData: true})
}
}).catch(err => {
console.log({err})
onErrorCallback(err)
})
}
.../* historyProvider.js */
var rp = require('request-promise').defaults({json: true})
getBars: function(symbolInfo, resolution, from, to, first, limit) {
var split_symbol = symbolInfo.name.split(/[:/]/)

const url = resolution === 'D' ? '/data/histoday' : resolution >= 60 ? '/data/histohour' : '/data/histominute'
const qs = {
e: split_symbol[0], // Coinbase
fsym: split_symbol[1], // BTC
tsym: split_symbol[2], // USD
toTs: to ? to : '',
limit: 2000,
}
return rp({
url: `${api_root}${url}`,
qs,
})
.then(data => {
if (data.Response && data.Response === 'Error') {
console.log('CryptoCompare API error:',data.Message)
return []
}
if (data.Data.length) {
var bars = data.Data.map(el => {
return {
time: el.time * 1000, //TradingView requires bar time in ms
low: el.low,
high: el.high,
open: el.open,
close: el.close,
volume: el.volumefrom
}
})
return bars
} else {
return []
}
})
}
0

Penting untuk memahami bagaimana symbolInfo memengaruhi bagan Anda, jadi periksalah dokumennya

getBars

Sekarang ke bagian yang menyenangkan. Mendapatkan data grafik dari sumber API kami dan menyerahkannya ke TradingView

getBars: function(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {

historyProvider.getBars(symbolInfo, resolution, from, to, firstDataRequest)
.then(bars => {
if (bars.length) {
onHistoryCallback(bars, {noData: false})
} else {
onHistoryCallback(bars, {noData: true})
}
}).catch(err => {
console.log({err})
onErrorCallback(err)
})
}
.../* historyProvider.js */
var rp = require('request-promise').defaults({json: true})
getBars: function(symbolInfo, resolution, from, to, first, limit) {
var split_symbol = symbolInfo.name.split(/[:/]/)

const url = resolution === 'D' ? '/data/histoday' : resolution >= 60 ? '/data/histohour' : '/data/histominute'
const qs = {
e: split_symbol[0], // Coinbase
fsym: split_symbol[1], // BTC
tsym: split_symbol[2], // USD
toTs: to ? to : '',
limit: 2000,
}
return rp({
url: `${api_root}${url}`,
qs,
})
.then(data => {
if (data.Response && data.Response === 'Error') {
console.log('CryptoCompare API error:',data.Message)
return []
}
if (data.Data.length) {
var bars = data.Data.map(el => {
return {
time: el.time * 1000, //TradingView requires bar time in ms
low: el.low,
high: el.high,
open: el.open,
close: el.close,
volume: el.volumefrom
}
})
return bars
} else {
return []
}
})
}

Oke, mari kita hancurkan semua kode itu

Tradingview memanggil

getBars: function(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {

historyProvider.getBars(symbolInfo, resolution, from, to, firstDataRequest)
.then(bars => {
if (bars.length) {
onHistoryCallback(bars, {noData: false})
} else {
onHistoryCallback(bars, {noData: true})
}
}).catch(err => {
console.log({err})
onErrorCallback(err)
})
}
.../* historyProvider.js */
var rp = require('request-promise').defaults({json: true})
getBars: function(symbolInfo, resolution, from, to, first, limit) {
var split_symbol = symbolInfo.name.split(/[:/]/)

const url = resolution === 'D' ? '/data/histoday' : resolution >= 60 ? '/data/histohour' : '/data/histominute'
const qs = {
e: split_symbol[0], // Coinbase
fsym: split_symbol[1], // BTC
tsym: split_symbol[2], // USD
toTs: to ? to : '',
limit: 2000,
}
return rp({
url: `${api_root}${url}`,
qs,
})
.then(data => {
if (data.Response && data.Response === 'Error') {
console.log('CryptoCompare API error:',data.Message)
return []
}
if (data.Data.length) {
var bars = data.Data.map(el => {
return {
time: el.time * 1000, //TradingView requires bar time in ms
low: el.low,
high: el.high,
open: el.open,
close: el.close,
volume: el.volumefrom
}
})
return bars
} else {
return []
}
})
}
1 dan meneruskan objek symbolInfo yang kami berikan ke panggilan balik resolveSymbol resolusi, resolusi (apakah kita memerlukan bilah 1 menit? Batang 60 menit? 1 hari?), ke dan dari stempel waktu, dan tanda boolean jika ini adalah data pertama permintaan untuk simbol ini

Dari sana, kami memanggil

getBars: function(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {

historyProvider.getBars(symbolInfo, resolution, from, to, firstDataRequest)
.then(bars => {
if (bars.length) {
onHistoryCallback(bars, {noData: false})
} else {
onHistoryCallback(bars, {noData: true})
}
}).catch(err => {
console.log({err})
onErrorCallback(err)
})
}
.../* historyProvider.js */
var rp = require('request-promise').defaults({json: true})
getBars: function(symbolInfo, resolution, from, to, first, limit) {
var split_symbol = symbolInfo.name.split(/[:/]/)

const url = resolution === 'D' ? '/data/histoday' : resolution >= 60 ? '/data/histohour' : '/data/histominute'
const qs = {
e: split_symbol[0], // Coinbase
fsym: split_symbol[1], // BTC
tsym: split_symbol[2], // USD
toTs: to ? to : '',
limit: 2000,
}
return rp({
url: `${api_root}${url}`,
qs,
})
.then(data => {
if (data.Response && data.Response === 'Error') {
console.log('CryptoCompare API error:',data.Message)
return []
}
if (data.Data.length) {
var bars = data.Data.map(el => {
return {
time: el.time * 1000, //TradingView requires bar time in ms
low: el.low,
high: el.high,
open: el.open,
close: el.close,
volume: el.volumefrom
}
})
return bars
} else {
return []
}
})
}
_3 yang merupakan kode yang telah kami tulis untuk mengambil data ohlcv historis dari API harga historis Cryptocompare. Kita harus meneruskan larik data batang ke getBar's
const config = {
supported_resolutions: ["1", "3", "5", "15", "30", "60", "120", "240", "D"]
}
onReady: cb => {
console.log('=====onReady running')
setTimeout(() => cb(config), 0)
}
1 , larik itu bisa terlihat seperti ini untuk data batang 1 menit

[
...{
time: 1528322340000, //bar time must be in milliseconds
open: 7678.85,
high: 7702.55,
low: 7656.98,
close: 7658.25,
volume: 0.9834
},
...
]

Jadi file historyProvider kami bertanggung jawab untuk benar-benar membuat permintaan ke CryptoCompare untuk mendapatkan data yang sesuai. Untuk membuat permintaan dengan CrytoCompare kita perlu mengetahui simbol ke, dari simbol, dan pertukaran spesifik yang kita inginkan dari data

Karena kami telah memilih untuk memasukkan semua informasi yang relevan ke dalam nama simbol (Coinbase. BTC/USD), kami dapat mengekstrak parameter tersebut dari string

getBars: function(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {

historyProvider.getBars(symbolInfo, resolution, from, to, firstDataRequest)
.then(bars => {
if (bars.length) {
onHistoryCallback(bars, {noData: false})
} else {
onHistoryCallback(bars, {noData: true})
}
}).catch(err => {
console.log({err})
onErrorCallback(err)
})
}
.../* historyProvider.js */
var rp = require('request-promise').defaults({json: true})
getBars: function(symbolInfo, resolution, from, to, first, limit) {
var split_symbol = symbolInfo.name.split(/[:/]/)

const url = resolution === 'D' ? '/data/histoday' : resolution >= 60 ? '/data/histohour' : '/data/histominute'
const qs = {
e: split_symbol[0], // Coinbase
fsym: split_symbol[1], // BTC
tsym: split_symbol[2], // USD
toTs: to ? to : '',
limit: 2000,
}
return rp({
url: `${api_root}${url}`,
qs,
})
.then(data => {
if (data.Response && data.Response === 'Error') {
console.log('CryptoCompare API error:',data.Message)
return []
}
if (data.Data.length) {
var bars = data.Data.map(el => {
return {
time: el.time * 1000, //TradingView requires bar time in ms
low: el.low,
high: el.high,
open: el.open,
close: el.close,
volume: el.volumefrom
}
})
return bars
} else {
return []
}
})
}
5

TradingView juga meneruskan

getBars: function(symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {

historyProvider.getBars(symbolInfo, resolution, from, to, firstDataRequest)
.then(bars => {
if (bars.length) {
onHistoryCallback(bars, {noData: false})
} else {
onHistoryCallback(bars, {noData: true})
}
}).catch(err => {
console.log({err})
onErrorCallback(err)
})
}
.../* historyProvider.js */
var rp = require('request-promise').defaults({json: true})
getBars: function(symbolInfo, resolution, from, to, first, limit) {
var split_symbol = symbolInfo.name.split(/[:/]/)

const url = resolution === 'D' ? '/data/histoday' : resolution >= 60 ? '/data/histohour' : '/data/histominute'
const qs = {
e: split_symbol[0], // Coinbase
fsym: split_symbol[1], // BTC
tsym: split_symbol[2], // USD
toTs: to ? to : '',
limit: 2000,
}
return rp({
url: `${api_root}${url}`,
qs,
})
.then(data => {
if (data.Response && data.Response === 'Error') {
console.log('CryptoCompare API error:',data.Message)
return []
}
if (data.Data.length) {
var bars = data.Data.map(el => {
return {
time: el.time * 1000, //TradingView requires bar time in ms
low: el.low,
high: el.high,
open: el.open,
close: el.close,
volume: el.volumefrom
}
})
return bars
} else {
return []
}
})
}
_6 ke getBars, yang akan menginformasikan titik akhir API apa yang kami minta dari CryptoCompare, titik akhir data historis menit, jam, atau hari

Karena keterbatasan API CryptoCompare (kami hanya bisa mendapatkan 2000 catatan sekaligus) kami mungkin mengirimkan kumpulan data yang tidak lengkap yang diminta oleh TradingView. Jangan khawatir. getBars akan dipanggil lagi, dengan stempel waktu baru ke dan dari, hingga semua data yang diperlukan untuk mengisi bagian bagan yang terlihat diperoleh

Hore untuk Grafik Statis

Saya harap ini telah membantu Anda. Proses ini membuat saya kewalahan pada awalnya, itulah sebabnya saya mencoba berbagi pembelajaran dengan Anda, ini adalah proses yang membingungkan

Anda mungkin berpikir "Oke, Jon, tapi bagan statis tidak banyak membantu saya". Di bagian 2 dari rangkaian tutorial ini, kami mengimplementasikan pembaruan waktu nyata pada bagan. Penting untuk memahami konsep yang diuraikan di sini terlebih dahulu, dan membiasakan diri dengan dokumentasi TradingView

Berikut adalah pratinjau yang diterapkan dari bagian 1. https. //tv-tut-part1. kesalahan. Saya/

Saya yakin banyak dari Anda yang masih bingung, atau menemukan kesalahan yang mungkin saya buat. Jangan ragu untuk berkomentar di sini, atau hubungi melalui email di bawah ini 👇👇

Kode

Lihat kode untuk semua bagian dari seri tutorial ini di sini

jonchurch/tradingview-js-api-tutorial

Berkontribusi pada pengembangan tradingview-js-api-tutorial dengan membuat akun di GitHub

github. com

*Mengandalkan layanan pihak ketiga untuk menyediakan data bagan Anda dalam produksi kurang optimal. Misalnya, Cryptocompare membatasi data menit hanya 7 hari di masa lalu. Baik untuk tutorial kami, tetapi ini mencegah kami memetakan data menit lebih dari 7 hari ke masa lalu. Selain itu, Anda dibatasi oleh batas laju API CryptoCompare dan semua waktu henti yang mungkin mereka alami

Berapa biaya TradingView?

Untuk akun Pro, Anda harus membayar biaya berlangganan sebesar USD 14. 95 per bulan, Pro+ adalah USD 29. 95 per bulan, sedangkan preminya USD 59. 95 per bulan . Setiap akun memiliki versi Uji Coba Gratis yang dapat dicoba secara gratis selama 30 hari.

Apa itu TradingView?

Apa itu Tradingview? . Sebagai pemula, Anda juga dapat menggunakan platform ini untuk mendengarkan strategi perdagangan pengguna lain atau membagikan analisis Anda sendiri melalui streaming langsung. platform berbasis peramban yang menampilkan grafik dan tren harga beragam instrumen investasi. Sebagai pemula, kamu juga bisa menggunakan platform ini untuk menyimak strategi trading pengguna lain atau membagikan analisis kamu sendiri lewat livestream.

Apa itu skrip Pine?

Pine Script ™ adalah bahasa pemrograman TradingView. Dengan Pine Script , trader dapat membuat alat trading sendiri dan menjalankannya di Server Trading View. Pine Script didesain ringan, namun kuat. Dengan Pine Script , kita bisa membuat indikator dan strategi yang bisa di-backtest.

Apa gunanya TradingView?

TradingView adalah platform perdagangan satu atap yang menyajikan informasi dalam bentuk grafik harga aset kripto yang diperoleh melalui berbagai pasar perdagangan aset kripto . TradingView menggabungkan grafik real-time, indikator teknis, peringatan lintas platform, dan jejaring sosial.