强大的金融类图表库 TradingView 使用分享

这段时间刚好做币圈交易所,运用到了现在最火的金融类图表库 -- TradingView ,就是强大,基本上现在的火币网(https://www.huobi.com),币安网(https://www.binance.com/)等大型交易所都在使用。

简介:

带有开放API的可下载图表库。这是一个独立的解决方案,可以将其下载,托管在自己的服务器上,连接自己的数据,在自己的网站/应用程序免费使用。

适用于手机和桌面应用程序、 门户网站、博客和新闻网站。 当您想要完全控制图表并希望显示您所控制的数据时,此为最佳选择。

使用教程:

本教程使用的是nodejs 提供的接口,所有的数据都本地mock出来的,这样大家可以更加方便理解数据使用的问题。

步骤:

1.注册TradingView账号,然后申请TradingView的图表库(申请地址:https://cn.tradingview.com/how-it-works/),(注意,必须是以公司名义申请,不允许个人名义申请,如果以个人名义申请或者你所在行业经过中国区经销商了解后不需要用到tradingview将无法给你提供github的开源代码下载。源码结构如下图:)

  • /charting\_library 包含全部的图表库文件。
  • /charting\_library/charting\_library.min.js 包含外部图表库widget接口。此文件不应该被修改。
  • /charting_library/charting_library.min.d.ts 包含TypeScript定义的widget接口
  • /charting_library/datafeed-api.d.ts 包含TypeScript定义的datafeed接口。
  • /charting_library/datafeeds/udf/ 包含UDF-compatible 的datafeed包装类(用于实现JS API通过UDF传输数据给图表库)。例子中的datafeed包装器类实现了脉冲实时仿真数据。您可以自由编辑此文件。
  • /charting\_library/static 文件夹中存储图表库内部资源,不适用于其他目的。
  • /index.html 为使用Charting Library widget 的html例子。
  • /test.html 为不同的图表库自定义功能使用的示例。
  • /mobile\*.html 也是Widget自定义的示例。

然后把整个项目clone 下来到本地。

2.安装nodejs  (安装教程:https://www.cnblogs.com/zhouyu2017/p/6485265.html)

3.安装koa  (Koa -- 基于 Node.js 平台的下一代 web 开发框架)

$ npm i koa

4.安装koa-generator  (Koa 脚手架)

$ npm i -g koa-generator

5.使用koa-generator 快速创建项目

$ koa2 TrandingPiewProject && cd TrandingPiewProject && npm install

koa-generator创建的项目已经集成了nodemon,所以大家可以直接使用nodemon启动项目

$ nodemon run start

 打开浏览器: http://localhost:3001

就可以看到nodejs项目已经启动了

6.在nodejs创建3个接口

地址1:http://localhost:3001/api/config (存放trandingview的 datafeed配置数据)

地址2:http://localhost:3001/api/symbols (trandingview的 商品解析数据)

地址3:http://localhost:3001/api/history (trandingview的 K线数据)

7.nodejs项目文件修改如下

app.js (修改部分黄色标出)

const Koa = require(‘koa‘)
const views = require(‘koa-views‘)
const json = require(‘koa-json‘)
const onerror = require(‘koa-onerror‘)
const bodyparser = require(‘koa-bodyparser‘)
const logger = require(‘koa-logger‘)
// 引入koa2-cors "允许跨域"
const cors = require(‘koa2-cors‘)

const index = require(‘./routes/index‘)
const api = require(‘./routes/api‘)

const app = new Koa()
app.use(cors())
// error handler
onerror(app)

// middlewares
app.use(bodyparser({
  enableTypes:[‘json‘, ‘form‘, ‘text‘]
}))
app.use(json())
app.use(logger())
app.use(require(‘koa-static‘)(__dirname + ‘/public‘))

app.use(views(__dirname + ‘/views‘, {
  extension: ‘pug‘
}))

// logger
app.use(async (ctx, next) => {
  const start = new Date()
  await next()
  const ms = new Date() - start
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})

// routes
app.use(index.routes(), index.allowedMethods())
app.use(api.routes(), api.allowedMethods())

// error-handling
app.on(‘error‘, (err, ctx) => {
  console.error(‘server error‘, err, ctx)
});

module.exports = app

  

把原来的routes下面的users.js改成api.js,

贴上我的api.js

api.js (修改部分黄色标出)

const router = require(‘koa-router‘)()

router.prefix(‘/api‘)

// 产生随机数的方法
function random(lower, upper) {
    return Math.floor(Math.random() * (upper - lower)) + lower;
}
// 获取两数中一数的方法
function rd(n, m) {
    var c = m - n + 1;
    return Math.floor(Math.random() * c + n);
}

// config接口
router.get(‘/config‘, async (ctx, next) => {
    ctx.body = {
        "supports_search": true, //是否支持搜索
        "supports_group_request": false, //是否支持搜索或品种解析
        "supported_resolutions": ["30", "60", "240", "D"], //中的值D代表天day,W代表周week,M代表月;2D是两天;3W是三周;6M是6个月,表示支持显示的哪几种图日线图、2日线
        "supports_marks": false,
        "supports_timescale_marks": false,
    }
})
// symbols接口
router.get(‘/symbols‘, async (ctx, next) => {
    ctx.body = {
        "name": "CDCC/ETH", //品种名称
        "session": "24x7", //开盘时间
        "has_intraday": true, //显示符号是否具有历史盘中数据
        "timezone": "Asia/Shanghai", //时区
        "data_status": "delayed_streaming",
        "supported_resolutions": ["5", "10", "15", "30", "60", "120", "240", "D", "W"],
        "intraday_multipliers": ["5", "60", "D"],
        "minmov": 20, //用于格式化用途
        "pricescale": 100000000, //数据显示的小数位数(例如:100显示0.01)
        "type": "bitcoin" //类型
    }
})
// history接口
router.get(‘/history‘, async (ctx, next) => {
    let resolution = ctx.query.resolution // 商品名称或者代码
    let from = new Date(ctx.query.from * 1000) //获取数据的开始时间戳
    let to = new Date(ctx.query.to * 1000) //获取数据的结束时间戳

    if (resolution == ‘1‘ || resolution == ‘5‘ || resolution == ‘10‘ || resolution == ‘15‘ || resolution == ‘30‘) {
        from.setMilliseconds(0)
        to.setMilliseconds(0)
        from.setSeconds(0)
        to.setSeconds(0)
    } else if (resolution == ‘60‘) {
        from.setMilliseconds(0)
        to.setMilliseconds(0)
        from.setSeconds(0)
        to.setSeconds(0)
        from.setMinutes(0)
        to.setMinutes(0)
    } else if (resolution == ‘D‘) {
        from.setMilliseconds(0)
        to.setMilliseconds(0)
        from.setSeconds(0)
        to.setSeconds(0)
        from.setMinutes(0)
        to.setMinutes(0)
        from.setHours(0)
        to.setHours(0)
    }
    let text = from
    const time = Math.floor((to.getTime() - from.getTime()) / 60 / 1000)
    let num
    if (resolution == ‘D‘) {
        num = time / (60 * 24)
    } else {
        num = time / resolution
    }
    let o = []
    let c = []
    let h = []
    let l = []
    let v = []
    let t = []
    let newnum = 3000;
    for (var i = 0; i < num; i++) {
        t.push(text.getTime() / 1000)
        if (resolution == ‘D‘) {
            text.setMinutes(text.getMinutes() + Number(24 * 60))
        } else {
            text.setMinutes(text.getMinutes() + Number(resolution))
        }
        if (rd(1, 2) == 1) {
            newnum += random(1, 10)
            o.push(newnum)
            let h1 = 0;
            let l1 = 0;
            if (rd(1, 2) == 1) {
                h1 = newnum + random(1, 10)
                h.push(h1)
                l1 = h1 - random(1, 10)
                l.push(l1)
                c.push(rd(l1, h1))
            } else {
                h1 = newnum - random(1, 10)
                h.push(h1)
                l1 = h1 - random(1, 10)
                l.push(l1)
                c.push(rd(l1, h1))
            }
        } else {
            newnum -= random(1, 10)
            if (newnum < 0) {
                newnum = 0
            }
            o.push(newnum)
            if (rd(1, 2) == 1) {
                h.push(newnum + random(1, 10))
                l.push(newnum + random(1, 10))
                c.push(newnum + random(1, 10))
            } else {
                if ((newnum - random(1, 10)) < 0) {
                    newnum = 0
                    h.push(0)
                } else {
                    h.push(newnum - random(1, 10))
                }
                if ((newnum - random(1, 10)) < 0) {
                    newnum = 0
                    l.push(0)
                } else {
                    l.push(newnum - random(1, 10))
                }
                if ((newnum - random(1, 10)) < 0) {
                    newnum = 0
                    c.push(0)
                } else {
                    c.push(newnum - random(1, 10))
                }
            }
        }

        v.push(random(1, 1000))
    }
    ctx.body = {
        t: t, //表示时间,将t的数值补000后就代表毫秒数,比如js的(new Date).getTime()
        o: o, //表示open开盘价
        c: c, //表示close收盘价
        h: h, //表示high最高价
        l: l, //表示low最低价
        v: v, //表示volume成交量
        s: "ok" //表示状态,返回数据是否成功,ok表示成功
    }
})

module.exports = router

修改完之后,其实上面创建的3个就可以访问了。mock 数据也完成了。

8.把github上clone下来的项目启动在自己本地的服务器,我个人用了代理服务器nginx,nginx 具体的安装流程请大家自己去搜索,以及为什么用nginx,这个就是因为接口跨域问题,大家自己私下了解下就可以了,我在这里就不多做解释了。

接着把克隆下来的charting_library文件移动到nginx的html文件下就可以了。

这里我贴出我的nginx.conf 文件

注意:修改下里面charting_library文件夹根目录下的 test.html 文件,把名字改成 index3.html。因为nginx跟恶心,对test这个词有bug。

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  ‘$remote_addr - $remote_user [$time_local] "$request" ‘
    #                  ‘$status $body_bytes_sent "$http_referer" ‘
    #                  ‘"$http_user_agent" "$http_x_forwarded_for"‘;

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       8083;
        server_name  localhost;
        location / {
            root  ./html/charting_library;
            index  index3.html index3.htm;
        }
    }

    server {
       listen       8084;
       server_name  localhost;

       location / {
            proxy_pass http://localhost:8083;
            proxy_redirect default;
       }
       location /apis {
            rewrite  ^/apis/(.*)$ /$1 break;
            proxy_pass   http://localhost:3001;
       }

    }

    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

好了,这个时候项目就已经启动了。

9.然后修改Tradingview的配置就可以连接自己的nodesj mock出来的数据了。

tradingview 目录结构

然后只需要修改里里面的index.html(其实就是原来的test.html,只是我这里把它改成index3.html)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>TradingView Charting Library demo -- testing mess</title>
    <!-- Fix for iOS Safari zooming bug -->
    <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <script src="http://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
    <script type="text/javascript" src="charting_library/charting_library.min.js"></script>
    <script type="text/javascript" src="datafeeds/udf/dist/polyfills.js"></script>
    <script type="text/javascript" src="datafeeds/udf/dist/bundle.js"></script>
    <script type="text/javascript">
    function getParameterByName(name) {
        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
        var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
            results = regex.exec(location.search);
        return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
    }

    TradingView.onready(function() {
        var widget = window.tvWidget = new TradingView.widget({
            debug: false,
            // 是否全屏
            fullscreen: true,
            // 初始商品
            symbol: ‘CDCC/ETH‘,
            // 周期
            interval: 60,
            // 时区
            timezone: "Asia/Shanghai",
            // id属性为指定要包含widget的DOM元素id
            container_id: "tv_chart_container",
            // 语言
            locale: "zh",
            // static文件夹的路径
            library_path: "charting_library/",
            // JavaScript对象的实现接口 JS API 以反馈图表及数据
            datafeed: new Datafeeds.UDFCompatibleDatafeed("http://localhost:3001/api"),
            // 自动调节大小
            autosize: true,
            // 主题颜色(dark,light)
            theme: ‘dark‘,
            time_frames: false,
            style: "1",
            overrides: {
                "timeScale.rightOffset": 1,
                "timeScale.barSpacing": 12.709329141645004,
                "headerToolbarIndicators.backgroundColor": "#dc1a5a",
                "headerToolbarIndicators.backgroundColor": "#dc1a5a",
                "mainSeriesProperties.candleStyle.borderColor": "#212c3f",
                "mainSeriesProperties.candleStyle.borderDownColor": "#dc1a5a",
                "mainSeriesProperties.candleStyle.borderUpColor": "#0fbb89",
                "mainSeriesProperties.candleStyle.downColor": "#dc1a5a",
                "mainSeriesProperties.candleStyle.upColor": "#0fbb89",
                "mainSeriesProperties.candleStyle.wickDownColor": "#dc1a5a",
                "mainSeriesProperties.candleStyle.wickUpColor": "#0fbb89",
                "mainSeriesProperties.hollowCandleStyle.borderColor": "#212c3f",
                "mainSeriesProperties.hollowCandleStyle.borderDownColor": "#dc1a5a",
                "mainSeriesProperties.hollowCandleStyle.borderUpColor": "#0fbb89",
                "mainSeriesProperties.hollowCandleStyle.downColor": "#dc1a5a",
                "mainSeriesProperties.hollowCandleStyle.upColor": "#0fbb89",
                "mainSeriesProperties.showCountdown": false,
                "mainSeriesProperties.style": 1,
                "paneProperties.background": "#131722",
                "paneProperties.crossHairProperties.color": "#999",
                "paneProperties.horzGridProperties.color": "#252c40",
                "paneProperties.horzGridProperties.style": 2,
                "paneProperties.legendProperties.showLegend": true,
                "paneProperties.vertGridProperties.color": "#131722",
                "paneProperties.vertGridProperties.style": 2,
                "symbolWatermarkProperties.color": "#0e192b",
                "volumePaneSize": "small",
            },
            studies_overrides: {
                "volume.volume.color.0": "#0fbb89",
                "volume.volume.color.1": "#dc1a5a",
                "volume.options.showStudyArguments": false,
                "bollinger bands.median.color": "#33FF88",
                "bollinger bands.upper.linewidth": 0
            },
            disabled_features: [
                "header_symbol_search",
                "header_saveload",
                "header_screenshot",
                "header_chart_type",
                "header_compare",
                "header_undo_redo",
                "timeframes_toolbar",
                "volume_force_overlay",
                "header_resolutions",
                "display_market_status",
                "timezone_menu",
                "countdown",
                "symbol_info"
            ],
            enabled_features: [
                "legend_context_menu"
            ],

            // 指标模板
            charts_storage_api_version: ‘1.1‘,
            // 定制加载进度条
            loading_screen: { backgroundColor: "#000000" },
            ‘scalesProperties.fontSize‘: 14, // 设置坐标轴字体大小

        });

        // 参考线、 按钮、 时间切换:
        var thats = widget;
        var buttons = [
            { title: ‘5分‘, resolution: ‘5‘, chartType: 1 },
            { title: ‘10分‘, resolution: ‘10‘, chartType: 1 },
            { title: ‘15分‘, resolution: ‘15‘, chartType: 1 },
            { title: ‘30分‘, resolution: ‘30‘, chartType: 1 },
            { title: ‘1小时‘, resolution: ‘60‘, chartType: 1 },
            { title: ‘2小时‘, resolution: ‘120‘, chartType: 1 },
            { title: ‘4小时‘, resolution: ‘240‘, chartType: 1 },
            { title: ‘1天‘, resolution: ‘D‘, chartType: 1 },
            { title: ‘1周‘, resolution: ‘W‘, chartType: 1 },
        ];

        var studies = [];

        function createButton(buttons) {
            for (var i = 0; i < buttons.length; i++) {
                thats.createButton()
                    .attr(‘title‘, buttons[i].title)
                    .attr(‘data-interval‘, buttons[i].resolution)
                    .addClass(‘btn-m‘)
                    .text(buttons[i].title)
                    .on(‘click‘, function(e) {
                        tvWidget.setSymbol("CDCC/ETH",$(this).attr(‘data-interval‘),function(){});
                    })
            }
        }

        function createStudy() {
            var id = widget.chart().createStudy(‘Moving Average‘, false, false, [5], null, { ‘Plot.color‘: ‘rgb(150, 95, 196)‘ });
            studies.push(id);
            id = widget.chart().createStudy(‘Moving Average‘, false, false, [10], null, { ‘Plot.color‘: ‘rgb(116,149,187)‘ });
            studies.push(id);
            id = widget.chart().createStudy(‘Moving Average‘, false, false, [20], null, { "plot.color": "rgb(58,113,74)" });
            studies.push(id);
            id = widget.chart().createStudy(‘Moving Average‘, false, false, [30], null, { "plot.color": "rgb(118,32,99)" });
            studies.push(id);
        }

        widget.onChartReady(function() {
            //设置均线种类 均线样式
            createStudy();
            //生成时间按钮
            createButton(buttons);
        });
    });
    </script>
</head>

<body style="margin:0;">
    <div id="tv_chart_container"></div>
</body>

</html>

上面是我的index3.html文件

修改完之后大家打开http://localhost:8083/ 就可以看到自己的TradingView 项目连接着自己的nodejs服务器mock出来的数据运行了,是不是很有成就感啦!!!

这个给大家介绍个好东西,图表功能展示

地址: https://tradingview.gitee.io/featuresets/

这里,我就是介绍了简单的ajax请求方法的,要WS的后面我再慢慢更新哈。

以上只是一部分,后续会继续更新完善。

期待!期待!期待!

原文地址:https://www.cnblogs.com/it-xiong/p/10082295.html

时间: 2024-11-08 22:45:32

强大的金融类图表库 TradingView 使用分享的相关文章

推荐三款强大的Js图表库

1.百度的Echart ECharts,缩写来自Enterprise Charts,是百度推出的一款开源的,商业级数据图表,它最初是为了满足百度公司商业体系里各种业务系统(如凤巢.广告管家等等)的报表需求. 2.Highcharts 中文网站:http://www.hcharts.cn/ Highcharts是国外的一款功能强大.开源.美观.图表丰富.兼容绝大多数浏览器的纯js图表库.Highcharts针对个人用户及非商业用途免费,商业用途需要购买授权. 3.阿里的G2 G2(The Gram

Swift 很强大的图表库-Charts使用

前言: 今天分享一个很漂亮的功能强大的图表库,希望对有需要的同学, 有帮助, 喜欢请点个赞,支持一下.谢谢~ 在项目中如何加入Swift库请看我的上一篇文章 http://www.jianshu.com/p/fd91c10c9f55 编译环境: Xcode7.3 添加Charts图表库 // 在Podfile中 use_frameworks! pod 'Charts' import Charts 创建柱状图 func createLineChartView() { chartView = Bar

Android开源图表库XCL-Charts版本号公布及展示页

XCL-Charts V2.1 Android开源图表库(XCL-Charts is a free charting library for Android platform.) XCL-Charts基于原生的Canvas来绘制各种图表,在设计时,尽量在保证开发效率的同一时候,给使用者提供足够多的定制化能力. 因此使用简便,同一时候具有相当灵活的定制能力. 眼下支持(3D/非3D,背向式)柱形图(Bar Chart).3D/非3D饼图(Pie Chart).堆叠图(Stacked Bar Cha

双11不再孤单,结识ECharts---强大的常用图表库

又是一年双十一,广大单身狗们有没有很寂寞(好把,其实我也是)!但是这次的双十一,我不再孤单,因为结识了一个js的强大的图表库---ECharts. 最近做软件工程项目的时候,由于设计图中有柱状图和饼图的设计,第一反应用原生js写肯定很麻烦,于是我请求能否不做,但我们的PM铁了心要做,最终逼迫我找到了这个强大的图表库,哈哈,在这里感谢一下PM李佳玮.(当我发现它还兼容IE6-8时,真的炒鸡感动!)  ECharts提供商业产品常用图表,底层基于ZRender(一个全新的轻量级canvas类库),创

Android图表库MPAndroidChart(一)——了解他的本质,方能得心应手

Android图表库MPAndroidChart(一)--了解他的本质,方能得心应手 我们项目中经常会遇到一些统计图,比如折线图,线形图等,在一些运动健康类的App中尤其的常见,这画起来要命,我以前就是自己手撸了这么多,但是撸完却并没有很深的感悟i,感觉,自己白撸了一样,懊恼,经常去搜索,Google也好,百度也罢,都是些标题党,什么最简单的,一招怎么怎么的,我看了半天愣是连文笔的逻辑的没看明白,主要还是排版实在是感人,本来以为现在转站系统之后接触的,应该是一大堆源码和终端,谁知道又临时调到Ap

21 个最棒最有用的 JavaScript 图表库

每个企业在做重要决定时都倾向于做数据分析.实际上他们很多时候都是沉沦在数据里头,不知道如何跳出其中.随着大数据的到来,曾经好用的表格和图表只是不再削减它了. 企业一直寻求更好的方式来可视化数据,更好的互动和使图表多角度.毕竟,只有从数据中抽出的见解才是有用的. JavaScript 图表库出现了,作为漂亮的,容易理解的,交互式的可视化图表最有力的工具.它能更容易提取和传达关键的模式和见解,而静态图表往往不明显. 为了使事情更加简单,我努力挖掘了很多选项,找到了你需要的最好的 JavaScript

个人永久性免费-Excel催化剂功能第69波-专业图表库新增图表-刘万祥老师中国地图

Excel催化剂的[专业图表库],仅提供一个工具的输出,让用户可以在制作专业图表过程中更低的门槛,更快速的完成所想要实现的图表.具体参考:第69波-打造最专业易用的商务图表库https://www.jianshu.com/p/914d075418cf 专业的图表,仍需要广大图表爱好者乐于分享的精神多多贡献自己的作品才能有真正的实质性的内容丰富度. 感谢国内图表大师-刘万祥老师的带头作用,愿意将其精心打造的中国数据地图模板无偿贡献出来,供广大Excel催化剂用户们使用. 中国数据地图入口 具体的制

Android图表库MPAndroidChart(十四)——在ListView种使用相同的图表

Android图表库MPAndroidChart(十四)--在ListView种使用相同的图表 各位好久不见,最近挺忙的,所有博客更新的比较少,这里今天说个比较简单的图表,那就是在ListView中使用相同的图标,因为我们在下篇会讲解使用不同的图表,相同的图表还是比较简单的,我们来看下效果图 具体怎么去实现呢,这里我们先写点铺垫,比如我们需要一个基类的Activity ViewPagerBaseActivity package com.liuguilin.mpandroidchartsample

Android图表库XCL-Charts

首先,这个是国人开发的,支持下必须顶!github项目地址:点击打开,由于项目的基本功能已经实现,所以项目作者也说以后基本不会在有更新了. 项目简介: Android图表库(XCL-Charts is a free charting library for Android platform.),基于Android Canvas来绘制各种图表,使用简便,定制灵活.目前支持3D/非3D/背向式/横向/竖向柱形图(Bar Chart).3D/非3D饼图(Pie Chart).堆叠图(Stacked B