這段時間恰好作幣圈交易所,運用到了如今最火的金融類圖表庫 -- TradingView ,就是強大,基本上如今的火幣網(https://www.huobi.com),幣安網(https://www.binance.com/ )等大型交易所都在使用。javascript
簡介:css
帶有開放API的可下載圖表庫。這是一個獨立的解決方案,能夠將其下載,託管在本身的服務器上,鏈接本身的數據,在本身的網站/應用程序無償使用。html
適用於手機和桌面應用程序、 門戶網站、博客和新聞網站。 當您想要徹底控制圖表並但願顯示您所控制的數據時,此爲最佳選擇。java
使用教程:node
本教程使用的是nodejs 提供的接口,全部的數據都本地mock出來的,這樣你們能夠更加方便理解數據使用的問題。jquery
步驟:nginx
1.註冊TradingView帳號,而後申請TradingView的圖表庫(申請地址:https://cn.tradingview.com/how-it-works/),(注意,必須是以公司名義申請,不容許我的名義申請,若是以我的名義申請或者你所在行業通過中國區經銷商瞭解後不須要用到tradingview將沒法給你提供github的開源代碼下載。源碼結構以下圖:)git
/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 下來到本地。github
2.安裝nodejs (安裝教程:http://www.javashuo.com/article/p-mpdcimfc-hw.html)web
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