初识tradingview

前言

tradingview,以下简称tv
公司最近决定使用tv作为交易图表,过去我们使用过echartshigtcharts作为交易的图表,过去工作中没有接触过货币交易的领域,所以从来没有听说过tv,但是现在需要使用了,便开始tv的学习。

tradingview是一个怎样的图表库?

这是一个专业的图表库,很多行业的大厂都使用了这个图标库,专门做K线图,虽然ECharts等也支持基本的k线图,但长期发展肯定还是使用专业的图表更利于后期的拓展。
tv官网上有三种版本:

  • 轻量图表可以直接前往github下载。
  • 技术分析图表需向官方提交一些必要的信息,然后可以获取到访问权限。
  • 图表&交易平台版本我没有试过,估计需要购买才可以使用。

从名字上也可以看出来它们是越来越强大的,因为目前我只使用了k线,感觉到第二种与第三种的区别在于第三种有交易终端可以使用,是tv自带的一套交易。

虽然tv非常强大,但是文档的质量非常一般,看上去方方面面都覆盖到了,但字里行间充斥着大量晦涩难懂的概念,对参数的注解也是残缺不齐,很多操作上的细节都没有提到,阅读体验非常糟糕,加上百度上关于这方面的实例非常少,没有对应的社区,各种群里也都是些新手,大佬们平时很少发话。

我看了文档后,还是一脸懵逼,完全不知道是怎么回事,到github上寻找别人的实例,加群看别人的demo,捣鼓了一番,终于把基础的图表功能弄出来了。

基础概念

一般情况下,图表库包含:图例(Legend)价格刻度(PriceSeries)时间刻度(TmeScale)头部工具(Header Tools)绘图工具(Drawing Tools)版权(Credits)等。

tv中有很多专业词汇,这里简单说明一下。

k线

大佬们肯定熟悉不过了,但是对于从来没有接触过这行的人来说,还是有些陌生,以1分钟k线来说,其实每秒钟传过来的数据里时间都是一样的,直到下一分钟,有以及交易量这几个,具体的展示tv都帮我们做了,我们只需要安装它规定的格式给它就好,每一条数据的格式如下:

{
    time: xxx,
    open: xxx,
    high: xxx,
    low: xxx,
    close: xxx,
    volume: xxx,
}

Symbol

Symbol直译过来叫象征、符号,这里引申为商品K线表现的是价格的变化趋势,至于是什么东西的价格,可以是股票,可以是货币,也可以是任何一样商品,TradingView为了通用,提供了这么一个抽象的概念。

一个Symbol就是一个JS对象,描述了商品的一些属性(名称、价格小数位、支持的时间分辨率、交易开放时间等,具体请参考官方文档),图表库会根据Symbol的定义,来决定改获取怎样的数据。

商品名称的固定格式为EXCHANGE:SYMBOLSYMBOL代表商品,例如一支股票、一个交易对;EXCHANGE是交易所的名称,同一商品在不同交易所可能会有不同的价格,因此需要进行区分。

Resolution

Resolution直译过来叫分辨率,这里指K线图中相邻两条柱子之间的时间间隔

Study

Study直译过来叫学习、研究,这里解释为指标,例如成交量、均线,以及其他各种分析指标。

Chart

图表本体,特指K线图及相关的各项指标,不包含工具栏。一个图表实例可以包含多个指标

Widget

小部件,和Android上的Widget类似。Widget可以看做是一个容器,主要是一些工具栏,以及留给绘制真正图表的一块区域,不含图表本体。一个Widget可以包含多个图表实例

FeatureSet

功能集,Widget配置选项中的一部分,用于定制图表库的一些功能(包括显示与否、样式)。

Overrides

覆盖,Widget配置选项中的一部分,用于定制图表库的样式(主要是图表各部分的颜色)。整个图表库由外层DOM结构和内部多个canvas组成,因此样式相关的设置也分为两部分,这里是用于canvas部分的设置,另外还有一个custom_css_url属性用于指定一个css文件,其中可以覆盖DOM部分的样式。

DataFeed

数据源,也就是接下来要讲的东西。它是TradingView获取、处理数据的方法集合,也是TradingView数据接入的核心所在,需要用户自己实现。它可以是一个Class的实例,也可以就是一个简单的对象。

开始使用

有2种方式传给tv数据,一个是udf,一个是jsApi,这个一般看过一遍文档的都能了解到,没看过文档的可以先去了解下:传送门

  • udftv已经帮你封装好的一种方式,如果需要修改可以去udf文件夹下的文件,是ts写的,因为我也没用过,就不过多说了。
  • jsApi主要使用的是onReadyresolveSymbolgetBarssubscribeBarsunsubscribeBars这5个方法。

因为我也是从零开始的tv,深知新手在刚开始tv时的困境,我尽量说说我的思路,然后下面会将每一个函数主要是做什么事情,如果看不懂,可以先看了下面的,再回头看下这个思路。

  1. 首先,使用new TradingView.widget(xx)创建tv,其中xx为一个对象,里面包含了tv的很多属性。
  2. 其中,有一个datafeed属性,我们需要创建一个class或者简单对象传给它。
  3. 新建一个class,或者简单对象,里面放入几个方法,就是jsapi里面的方法,这些方法不需要我们手动去调用,tv自己会在它的创建过程中去调用它(这点是比较迷惑初学者的,以为要调用,其实只需要写了这样的一个方法就行了。)。
    • 添加一个onReady方法,在里面异步返回图表的一些配置。
    • 添加一个resolveSymbol方法,异步返回商品的一些配置。
    • 添加一个getBars方法,这个方法主要是用来传递历史数据的,将历史数据丢给它的第5个回调参数onHistoryCallback
    • 添加一个subscribeBars方法,将实时数据丢给它的第3个回调参数onRealtimeCallback
    • 添加一个unsubscribeBars方法,主要是取消订阅,应该是使用tv自带的币种切换用来取消币种的订阅,因为我们设计图切换产品是在图表外面,所以我实际只是用这个方法停止websocket连接。

getBars

这个接口专门用于获取历史数据,即当前时刻之前的数据。TradingView 会根据 Resolution 从当前时刻开始往前划定一个时间范围,尝试获取这个时间范围内,指定Symbol指定Resolution的数据。出于性能考虑,TradingView只获取可见范围内的数据,超出可见范围的数据会随着图表的拖拽、缩放而分段延迟加载。这个接口中的fromto就是这次需要的历史数据时间范围,可以自行根据时间去请求后台的数据,一般一分钟的第一次的请求是一天,即1440条数据,如果数据不足tv会一直去调用这个getbars直到图表铺满,你也可以传入noData停止请求。

getBars (symbolInfo, resolution, from, to, onHistoryCallback, onErrorCallback, firstDataRequest) {
  function _send (data) {
    // 按时间筛选
    const dataInRange = data.length ? data.filter(n => n.time >= from && n.time <= to) : []

    // 没有数据就返回 noData
    const meta = {
        noData: !dataInRange.length
    }

    // 有数据,则整理成图表库要求的格式
    const bar = [...dataInRange]

    // 触发回调
    onHistoryCallback(bar, meta)
  }
}

subscribeBars

这个函数对每个Symbol + Resolution的组合都会调用一次,所以我们可以维护一个数组对象,用于保存每一个订阅者的信息和回调函数,当推送数据到达时,遍历订阅列表,找到符合条件的订阅者,调用其回调函数传递数据。如果你没有多个订阅的话,其实可以不用理会,直接有数据就处理好,丢给它的第三个参数onRealtimeCallback
事实上,这个函数只是增加一个订阅者,你可以在任意你实时获取到数据的地方将数据丢入回调函数onRealtimeCallback里。

subscribeBars (symbolInfo, resolution, onRealtimeCallback, subscriberUID, onResetCacheNeededCallback) {
  // 限制单例
  window.kChartSubscriberList = window.kChartSubscriberList || []

  // 避免重复订阅
  const found = window.kChartSubscriberList.some(n => n.uid === subscriberUID)
  if (found) return

  // 添加订阅
  window.kChartSubscriberList.push({
    symbol: symbolInfo,
    resolution: resolution,
    uid: subscriberUID,
    callback: onRealtimeCallback
  })
}

unsubscribeBars

这个就好理解了,当触发这个方法的时候,说明这个不订阅了,所以应该将它从我们维护的数组对象里面删除。

unsubscribeBars (subscriberUID) {
  window.kChartSubscriberList = window.kChartSubscriberList || []

  const idx = window.kChartSubscriberList.findIndex(n => n.uid === subscriberUID)
  if (idx < 0) return

  window.kChartSubscriberList.splice(idx, 1)
}

附录

tv功能集图
中文文档

后记

我接触tv时间也不是很长,很多都只是自己的一些理解,不一定正确,大家互相交流。
有不理解的也可以在下面评论,我会尽能力解答的。
我没有直接大段代码的丢上来,把一些概念放上去,希望授人以渔。
如果有需要demo的,大家可以加一些群,里面有很多大佬分享的demo

posted @ 2020-07-15 16:50  来亦何哀  阅读(4797)  评论(8编辑  收藏  举报