在本篇中,我们将在图表上实现实时价格更新。请务必阅读简介,以及第1部分第
在本篇中,我们将在图表上实现实时价格更新。在此之前请务必阅读简介,以及第1部分
为了让图表可以实时更新数据,我们将继续改造第1部分的示例。
此示例将使用CryptoCompare的websocket来获取价格更新。
你可以看到示例部署在glitch上,并查看第2部分的代码
第1部分重点介绍如何设置TradingView图表库Widget,以及设置JS API以从我们自己的数据源获取历史K线数据。
让我们可以实时更新图表的JS API方法是:
subscribeBars - 订阅商品的实时数据unsubscribeBars - 取消订阅商品的实时数据基本上我们需要做的就是更新我们图表上最新的K线,无论是1分钟的K线,还是1天的K线,这个过程几乎是一样的。
我们必须保持图表上最后一条K线的变量记录,用最新价格数据更新它(该周期的开盘价,最高价,最低价,收盘价或成交量是否发生了变化?),如果时间进入了新的周期,则提供一个新的K线数据而不是更新最后一条K线数据。
注意:如果你提供1分钟的TradingView,并让它建立5分钟,15分钟等等,那么你实际只需更新1分钟。不用担心,TradingView将在调用
subscribeBars时指定所需的分辨率!
首先,让我们来看看我们将要使用的这些新的JS API方法。
resolveSymbol 假设我们能够成功解析商品,则在之后,图表库将调用此方法。如果您不熟悉resolveSymbol请查看本指南的第1部分。
subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {
},
图表库将这些参数传递给subscribeBars:
symbolInfo- ObjectsymbolInfo对象resolution- StringK线周期onRealtimeCallback- Function将我们更新的K线传递给此回调以更新图表subscribeUID- String此交易对的唯一ID和表示订阅的分辨率,生成规则:ticker+'_'+周期onResetCacheNeededCallback- Function调用次回调让图表再次请求历史K线数据在实现方面,当图表商品或周期发生变化时,或者图表需要订阅新商品时,图表库会调用subscribeBars。
当订阅K线实时数据时,我们需要创建一个ws订阅记录,里面需要包含onRealtimeCallback函数(可以将onRealtimeCallback公开到window对象中),这样您就可以使用从实时数据源接收的新数据调用onRealtimeCallback函数。
JS API是一个传递给图表库的JS对象,它必须包含TradingView定义的函数。这些函数由图表库根据需要调用,您不能自己调用它们,只能调用它们的回调函数。
你应该做的是保持对订阅的引用,然后将更新的K线传递给subscribeBars函数的回调realtimeUpdateCallback。
假设我们有两个文件,api/index.jsJS API所在的文件,以及api/stream.js我们的实时更新代码:
// api/index.js
import stream from './stream'
...
subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {
stream.subscribeBars(symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback)
},
...
请记住,上面的很多内容涉及我正在使用的数据源的细节,CryptoCompare的Socket.io websocket频道。
我们需要了解图表库中没有提供的东西,我们需要知道图表上的lastBar。我们需要拥有一个对指定图表的onRealtimeUpdateCB引用。
TradingView特有的部分如下:
updateCB的引用并将数据传递到右侧图表lastBar通过我们数据源的更新或创建新K线subscribeBars时,将更新/创建的K线数据传递给updateCB
从TradingView图表库的角度来看,就这么简单。但是,使用您自己的数据源来实现这个流程可以是简单或复杂的。
通过更新图表上最新K线(当前的K线)来实现K线的实时更新。当实时价格数据进入时,您需要为图表库提供该K线数据的更新版本。
JS API提供了两个管理它的功能。susbcribeBars和unsubscribeBars。
当图表加载商品,或者当前图表的周期发生变化时,TV将通过使用想要订阅的商品和周期调用subscribeBars来请求订阅该K线的实时更新。
subscribeBars: (symbolInfo, resolution, onRealtimeCallback, subscribeUID, onResetCacheNeededCallback) => {
console.log('=====subscribeBars runnning')
}
unsubscribeBars
TV将调用subscribeBars函数以开启商品的实时订阅。为了将更新数据传递给图表,您需要调用onRealtimeCallback。
请注意,TV只调用一次
subscribeBars,当您需要更新该订阅的图表时,您需要保留对onRealtimeCallback函数的引用。
所以您要负责:
subscribeBars和unsubscribeBars方法通知您。TV的K线格式是一个如下所示的对象:
{
time: 1528322340000,//K线时间必须以毫秒为单位
open: 7678.85,
high: 7702.55,
low: 7656.98,
close: 7658.25,//收盘价是开盘后最新的价格
volume: 0.9834
}
了解TV的需求与您自己的数据实现之间的区别非常重要。您可以使用任何数据,只要您以正确的格式将其提供给TV图表库即可。
下面是我自己实现CryptoCompare的 socket.io交易数据websocket 的例子。
这只是完整JS API实现的一部分,我们从这个文件中导出两个方法,这些方法将从我们传递给TV的JS API对象中调用。有关JS API的更多信息,请参阅本教程的第1部分
// api/stream.js
import historyProvider from './historyProvider.js';
// 我们使用Socket.io客户端连接cryptocompare的socket.io数据流
var io = require('socket.io-client');
var socket_url = 'wss://streamer.cryptocompare.com';
var socket = io(socket_url);
// 正在订阅的对象数组
var _subs = [];
export default {
subscribeBars: function(symbolInfo, resolution, updateCb, uid, resetCache) {
const channelString = createChannelString(symbolInfo);
socket.emit('SubAdd', { subs: [channelString] });
var newSub = {
channelString,
uid,
resolution,
symbolInfo,
lastBar: historyProvider.history[symbolInfo.name].lastBar,
listener: updateCb,
};
_subs.push(newSub);
},
unsubscribeBars: function(uid) {
var subIndex = _subs.findIndex((e) => e.uid === uid);
if (subIndex === -1) {
//console.log("No subscription found for ",uid)
return;
}
var sub = _subs[subIndex];
socket.emit('SubRemove', { subs: [sub.channelString] });
_subs.splice(subIndex, 1);
},
};
socket.on('connect', () => {
console.log('===Socket connected');
});
socket.on('disconnect', (e) => {
console.log('===Socket disconnected:', e);
});
socket.on('error', (err) => {
console.log('====socket error', err);
});
socket.on('m', (e) => {
//这里我们得到CryptoCompare连接订阅的所有事件
//我们需要将这些新数据发送到我们订阅的图表上
const _data = e.split('~');
if (_data[0] === '3') {
// console.log('Websocket Snapshot load event complete')
return;
}
const data = {
sub_type: parseInt(_data[0], 10),
exchange: _data[1],
to_sym: _data[2],
from_sym: _data[3],
trade_id: _data[5],
ts: parseInt(_data[6], 10),
volume: parseFloat(_data[7]),
price: parseFloat(_data[8]),
};
const channelString = `${data.sub_type}~${data.exchange}~${data.to_sym}~${data.from_sym}`;
const sub = _subs.find((e) => e.channelString === channelString);
if (sub) {
// 如果是历史K线数据,则跳过
if (data.ts < sub.lastBar.time / 1000) {
return;
}
var _lastBar = updateBar(data, sub);
// 将最新的K线发送给TV的realtimeUpdate回调
sub.listener(_lastBar);
// 更新我们自己的lastBar记录
sub.lastBar = _lastBar;
}
});
// 取得交易数据和订阅记录, 返回更新后的最新K线
function updateBar(data, sub) {
var lastBar = sub.lastBar;
let resolution = sub.resolution;
if (resolution.includes('D')) {
// 一天的分钟数 === 1440
resolution = 1440;
} else if (resolution.includes('W')) {
// 一周的分钟数 === 10080
resolution = 10080;
}
var coeff = resolution * 60;
// console.log({coeff})
var rounded = Math.floor(data.ts / coeff) * coeff;
var lastBarSec = lastBar.time / 1000;
var _lastBar;
if (rounded > lastBarSec) {
// 创建一个新的K线,使用最后的收盘价作为开盘价**个人选择**
_lastBar = {
time: rounded * 1000,
open: lastBar.close,
high: lastBar.close,
low: lastBar.close,
close: data.price,
volume: data.volume,
};
} else {
// 更新最新的K线
if (data.price < lastBar.low) {
lastBar.low = data.price;
} else if (data.price > lastBar.high) {
lastBar.high = data.price;
}
lastBar.volume += data.volume;
lastBar.close = data.price;
_lastBar = lastBar;
}
return _lastBar;
}
// 将symbolInfo对象作为输入参数,并创建要发送到CryptoCompare的订阅字符串
function createChannelString(symbolInfo) {
var channel = symbolInfo.name.split(/[:/]/);
const exchange = channel[0] === 'GDAX' ? 'Coinbase' : channel[0];
const to = channel[2];
const from = channel[1];
// 订阅指定交易所和交易对的CryptoCompare交易频道
return `0~${exchange}~${from}~${to}`;
}
不过,您的数据源实现可能与我的不同,除非您也使用CryptoCompare!
一般步骤是:
realtimeUpdateCallback 、subscriberUID和resolution。您还需要图表上的最新K线,我的historyProvider负责提供最新K线。让我们分析一下我正在做些什么来实现CryptoCompare的特定实时数据来处理这个问题。 这仅限于TV,因为我正在按照他们指定的格式,格式化我可用的数据。
Coinbase:BTC/USD为我提供了使用CryptoCompare订阅正确频道所需的信息你可以看到部署在演示在Glitch,并查看第2部分的代码
希望这有助于回答有关Trading View 图表库实时更新的一些问题!
这是我在图表库中系列中最受欢迎的部分,我打算随着时间的推移更新它,因此我简化了这个过程。
本系列的第3部分将介绍更多TradingView功能(有非常多!),并将很快推出。我计划创建一些更好的起始项目,以加快开发tradingview的过程。