kline.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. var myChart;
  2. // import $store from "./../../../store"
  3. // post请求封装
  4. function post(url, data) {
  5. let baseUrl = 'https://biking.okenx.com';
  6. return new Promise((resolve, reject) => {
  7. axios({
  8. headers: {
  9. "Content-Type": "application/x-www-form-urlencoded",
  10. },
  11. method: 'get',
  12. url: baseUrl +
  13. '/api/currency/new_timeshar?from=1685422833&to=1685520093&symbol=LTC/USDT&period=1min',
  14. })
  15. .then(res => {
  16. console.log('res ======', res)
  17. if (res.data.code == 1) {
  18. resolve(res.data.data)
  19. } else {
  20. reject()
  21. alertError('请求超时')
  22. }
  23. })
  24. .catch(err => {
  25. alertError('请求超时')
  26. })
  27. })
  28. }
  29. // 弹窗
  30. function alertError(title) {
  31. document.addEventListener('plusready', function() {
  32. console.log('......')
  33. })
  34. try {
  35. plus.nativeUI.toast(title, {
  36. icon: '/static/common/toast-error.png',
  37. style: 'inline',
  38. verticalAlign: 'top'
  39. });
  40. } catch (e) {
  41. //TODO handle the exception
  42. }
  43. }
  44. var app = new Vue({
  45. el: '#app',
  46. data: {
  47. MA5: '',
  48. MA10: '',
  49. MA30: '',
  50. volMA5: '',
  51. volMA10: '',
  52. current: 1,
  53. tabs: [{
  54. 'label': '1分钟',
  55. 'value': 1
  56. },
  57. {
  58. 'label': '15分钟',
  59. 'value': 2
  60. },
  61. {
  62. 'label': '30分钟',
  63. 'value': 3
  64. },
  65. {
  66. 'label': '1小时',
  67. 'value': 4
  68. },
  69. {
  70. 'label': '4小时',
  71. 'value': 5
  72. },
  73. {
  74. 'label': '1天',
  75. 'value': 6
  76. },
  77. ],
  78. category: 1,
  79. categoryList: [{
  80. 'label': '深度',
  81. 'value': 1
  82. },
  83. {
  84. 'label': '成交',
  85. 'value': 2
  86. },
  87. {
  88. 'label': '简介',
  89. 'value': 3
  90. },
  91. ],
  92. txData: {}, //交易数据统计
  93. buyList: [],
  94. sellList: [],
  95. dealHis: [],
  96. tokenInfo: {},
  97. page: 1,
  98. },
  99. created() {
  100. console.log('00')
  101. this.getTxData()
  102. this.getDepth()
  103. },
  104. mounted() {
  105. myChart = echarts.init(document.getElementById('main'));
  106. this.draw()
  107. this.getKline()
  108. },
  109. methods: {
  110. // 返回上一页
  111. back() {
  112. uni.navigateBack()
  113. },
  114. // 获取24小时交易数据统计
  115. getTxData() {
  116. this.txData = txData;
  117. },
  118. // 获取k线数据,生成k线
  119. getKline() {
  120. post().then(res => {
  121. const dataX = []
  122. res.forEach(el => {
  123. dataX.push(el.time)
  124. rawData.push([new Date(el.time).getTime() , el.open , el.high , el.low, el.close , el.volume ])
  125. // var data = rawData.map(function(item) {
  126. // return [+item[1], +item[2], +item[3], +item[4], +item[5]];
  127. // });
  128. // var volumes = rawData.map(function(item, index) {
  129. // return [index, item[5], item[1] > item[2] ? 1 : -1];
  130. // });
  131. })
  132. // var dataList = res.map(data => {
  133. // // ["2004-01-05", 10411.85, 10544.07, 10411.85, 10575.92, 221290000],
  134. // // return [new Date(data.time).getTime() , data.open , data.high , data.low, data.close , data.volume ]
  135. // return{
  136. // timestamp: new Date(data.time).getTime(),
  137. // open: +data.open,
  138. // high: +data.high,
  139. // low: +data.low,
  140. // close: +data.close,
  141. // volume: +data.volume
  142. // }
  143. // })
  144. var dates = rawData.map(function(item) {
  145. console.log('dates--------' , item)
  146. return item[0];
  147. });
  148. var data = rawData.map(function(item) {
  149. return [+item[1], +item[2], +item[3], +item[4], +item[5]];
  150. });
  151. var volumes = rawData.map(function(item, index) {
  152. return [index, item[5], item[1] > item[2] ? 1 : -1];
  153. });
  154. // this.buyList=this.addItem(res.buyList || []);
  155. // this.sellList=this.addItem(res.sellList || []);
  156. console.log('rawData 1= ', rawData)
  157. var dataMA5 = this.calculateMA(5, data);
  158. var dataMA10 = this.calculateMA(10, data);
  159. var dataMA30 = this.calculateMA(30, data);
  160. var volumeMA5 = this.calculateMA(5, volumes);
  161. var volumeMA10 = this.calculateMA(10, volumes);
  162. myChart.setOption({
  163. xAxis: [{
  164. // data: dates
  165. data: dataX
  166. },
  167. {
  168. data: dataX
  169. // data: dates
  170. },
  171. ],
  172. series: [{
  173. name: '日K',
  174. data: data
  175. },
  176. {
  177. name: 'MA5',
  178. data: dataMA5
  179. },
  180. {
  181. name: 'MA10',
  182. data: dataMA10
  183. },
  184. {
  185. name: 'MA30',
  186. data: dataMA30
  187. },
  188. {
  189. name: 'Volume',
  190. data: volumes
  191. },
  192. {
  193. name: 'VolumeMA5',
  194. data: volumeMA5
  195. },
  196. {
  197. name: 'VolumeMA10',
  198. data: volumeMA10
  199. },
  200. ]
  201. })
  202. })
  203. },
  204. // 列表条数不足补全
  205. addItem(list, type) {
  206. // type: 1开头加,2末尾加
  207. list = list || [];
  208. let len = 20 - list.length;
  209. if (len > 0) {
  210. for (let i = 0; i < len; i++) {
  211. if (type == 1) {
  212. list.unshift({})
  213. } else {
  214. list.push({})
  215. }
  216. }
  217. }
  218. return list;
  219. },
  220. // 获取深度数据
  221. getDepth() {
  222. this.buyList = this.addItem(depthList().buyList || []);
  223. this.sellList = this.addItem(depthList().sellList || []);
  224. // console.log('000' , data)
  225. },
  226. // 获取成交记录
  227. getDealHis() {
  228. this.dealHis = dealHis();
  229. },
  230. // 获取项目简介信息
  231. getTokenInfo() {
  232. this.tokenInfo = tokenInfo;
  233. },
  234. // 切换tab
  235. switchTab(val) {
  236. if (this.current == val) return;
  237. this.current = val;
  238. this.getKline()
  239. },
  240. // 切换类目
  241. switchCategory(val) {
  242. if (this.category == val) return;
  243. this.category = val;
  244. if (this.category == 1) {
  245. this.getDepth()
  246. } else if (this.category == 2) {
  247. this.getDealHis()
  248. } else {
  249. this.getTokenInfo()
  250. }
  251. },
  252. // 截取数字字符串 保留precision小数
  253. formatterNum(value, precision) {
  254. // console.log(value)
  255. let reg = new RegExp('^\\d+(?:\\.\\d{0,' + precision + '})?')
  256. return value.toString().match(reg)
  257. },
  258. // 计算MA
  259. calculateMA(dayCount, data) {
  260. var result = [];
  261. for (var i = 0, len = data.length; i < len; i++) {
  262. if (i < dayCount) {
  263. result.push('-');
  264. continue;
  265. }
  266. var sum = 0;
  267. for (var j = 0; j < dayCount; j++) {
  268. sum += data[i - j][1];
  269. }
  270. // console.log(sum, dayCount)
  271. result.push((sum / dayCount).toFixed(2));
  272. }
  273. return result;
  274. },
  275. // 绘制(配置项)
  276. draw() {
  277. let that = this;
  278. var upColor = '#03ad91';
  279. var downColor = '#dd345b';
  280. var colorList = ['#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83', '#ca8622',
  281. '#bda29a', '#6e7074',
  282. '#546570', '#c4ccd3'
  283. ];
  284. var labelFont = 'bold 12px Sans-serif';
  285. var option = {
  286. // backgroundColor: '#0d1723',
  287. title: {
  288. show: false
  289. },
  290. legend: {
  291. show: false
  292. },
  293. visualMap: {
  294. show: false,
  295. seriesIndex: 4,
  296. dimension: 2,
  297. pieces: [{
  298. value: 1,
  299. color: downColor
  300. }, {
  301. value: -1,
  302. color: upColor
  303. }]
  304. },
  305. grid: [{
  306. top: '5%',
  307. left: 20,
  308. right: 20,
  309. height: '70%'
  310. },
  311. {
  312. top: '80%',
  313. left: 20,
  314. right: 20,
  315. height: '16%'
  316. },
  317. ],
  318. axisPointer: { //坐标轴指示器配置项
  319. link: {
  320. xAxisIndex: 'all'
  321. },
  322. label: {
  323. backgroundColor: '#0d1723',
  324. color: '#fff',
  325. // borderColor: 'rgb(99, 117, 139)',
  326. borderWidth: 1,
  327. borderRadius: 2,
  328. fontSize: 10
  329. }
  330. },
  331. xAxis: [{
  332. type: 'category', //坐标轴类型。(value:数值轴,适用于连续数据。,category:类目轴,适用于离散的类目数据,time: 时间轴,适用于连续的时序数据,log:对数轴。适用于对数数据)
  333. data: [], //类目数据,在类目轴(type: 'category')中有效。
  334. scale: true,
  335. boundaryGap: false, //坐标轴两边留白策略,类目轴和非类目轴的设置和表现不一样。
  336. axisLine: {
  337. show: false
  338. }, //坐标轴轴线相关设置
  339. axisTick: {
  340. show: false
  341. }, //坐标轴刻度相关设置。
  342. axisLabel: {
  343. show: false,
  344. }, //坐标轴刻度标签的相关设置。
  345. splitLine: {
  346. show: false,
  347. lineStyle: {
  348. color: 'rgba(255,255,255, 0.1)'
  349. }
  350. }, //坐标轴在 grid 区域中的分隔线。
  351. min: 'dataMin', //坐标轴刻度最小值。可以设置成特殊值 'dataMin',此时取数据在该轴上的最小值作为最小刻度。
  352. max: 'dataMax', //坐标轴刻度最大值。可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
  353. axisPointer: {
  354. label: {
  355. margin: 200
  356. }
  357. },
  358. }, {
  359. type: 'category',
  360. gridIndex: 1, //x 轴所在的 grid 的索引,默认位于第一个 grid。
  361. data: [], //类目数据,在类目轴(type: 'category')中有效。
  362. scale: true,
  363. boundaryGap: false, //坐标轴两边留白策略,类目轴和非类目轴的设置和表现不一样。
  364. axisLine: {
  365. show: false,
  366. lineStyle: {
  367. color: 'rgba(255,255,255,1)',
  368. width: 1
  369. }
  370. }, //坐标轴轴线相关设置
  371. axisTick: {
  372. show: false
  373. }, //坐标轴刻度相关设置。
  374. axisLabel: { //坐标轴刻度标签的相关设置。
  375. show: true,
  376. margin: 6,
  377. fontSize: 10,
  378. // color: 'rgba(99, 117, 139, 1.0)',
  379. formatter: function(value) {
  380. return echarts.format.formatTime('MM-dd', value);
  381. }
  382. },
  383. splitNumber: 20,
  384. splitLine: {
  385. show: false,
  386. lineStyle: {
  387. color: 'rgba(255,255,255, 0.1)'
  388. }
  389. }, //坐标轴在 grid 区域中的分隔线。
  390. min: 'dataMin', //坐标轴刻度最小值。可以设置成特殊值 'dataMin',此时取数据在该轴上的最小值作为最小刻度。
  391. max: 'dataMax', //坐标轴刻度最大值。可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
  392. // axisPointer: { show: true, type: 'none', label: { show: false }},
  393. }],
  394. yAxis: [{
  395. type: 'value', //坐标轴类型。(value:数值轴,适用于连续数据。,category:类目轴,适用于离散的类目数据,time: 时间轴,适用于连续的时序数据,log:对数轴。适用于对数数据)
  396. position: 'right', //y 轴的位置。'left','right'
  397. scale: true, //是否是脱离 0 值比例。设置成 true 后坐标刻度不会强制包含零刻度。在双数值轴的散点图中比较有用。(在设置 min 和 max 之后该配置项无效。)
  398. axisLine: {
  399. show: true
  400. }, //坐标轴轴线相关设置。
  401. axisTick: {
  402. show: true,
  403. inside: true
  404. }, //坐标轴刻度相关设置。
  405. axisLabel: { //坐标轴刻度标签的相关设置。
  406. show: true,
  407. color: 'rgba(99, 117, 139, 1.0)',
  408. inside: true,
  409. fontSize: 10,
  410. formatter: function(value) {
  411. return Number(value).toFixed(2)
  412. }
  413. },
  414. splitLine: {
  415. show: false,
  416. lineStyle: {
  417. color: 'rgba(255,255,255, 0.1)'
  418. }
  419. }, //坐标轴在 grid 区域中的分隔线。
  420. }, {
  421. type: 'value',
  422. position: 'right',
  423. scale: true,
  424. gridIndex: 1,
  425. axisLine: {
  426. show: false
  427. },
  428. axisTick: {
  429. show: false
  430. },
  431. axisLabel: {
  432. show: false
  433. },
  434. splitLine: {
  435. show: false
  436. }
  437. }],
  438. animation: false, //是否开启动画。
  439. color: colorList,
  440. tooltip: {
  441. show: true, //是否显示提示框组件,包括提示框浮层和 axisPointer。
  442. trigger: 'axis', //触发类型。item,axis,none
  443. formatter(params) {
  444. let tooltip = '';
  445. let time = '',
  446. open = 0,
  447. high = 0,
  448. low = 0,
  449. close = 0,
  450. amount = 0;
  451. for (var i = 0; i < params.length; i++) {
  452. if (params[i].seriesName === '日K') {
  453. time = params[i].name;
  454. open = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  455. 1], 2)) : 0;
  456. close = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  457. 2], 2)) : 0;
  458. low = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  459. 3], 2)) : 0;
  460. high = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
  461. 4], 2)) : 0;
  462. amount = params[i].data.length > 1 ? Number(that.formatterNum(params[i]
  463. .data[5], 2)) : 0;
  464. // console.log(time,open,close,low,high,amount)
  465. tooltip = '<div class="charts-tooltip">' +
  466. '<div class="charts-tooltip-row"><div class="ctr-label">' + '时间' +
  467. '</div><div class="ctr-value">' + time + '</div></div>' +
  468. '<div class="charts-tooltip-row"><div class="ctr-label">' + '开' +
  469. '</div><div class="ctr-value">' + open + '</div></div>' +
  470. '<div class="charts-tooltip-row"><div class="ctr-label">' + '高' +
  471. '</div><div class="ctr-value">' + high + '</div></div>' +
  472. '<div class="charts-tooltip-row"><div class="ctr-label">' + '低' +
  473. '</div><div class="ctr-value">' + low + '</div></div>' +
  474. '<div class="charts-tooltip-row"><div class="ctr-label">' + '收' +
  475. '</div><div class="ctr-value">' + close + '</div></div>' +
  476. '<div class="charts-tooltip-row"><div class="ctr-label">' + '数量' +
  477. '</div><div class="ctr-value">' + amount + '</div></div></div>';
  478. }
  479. if (params[i].seriesName === 'MA5') {
  480. that.MA5 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  481. .data, 2)) : 0
  482. }
  483. if (params[i].seriesName === 'MA10') {
  484. that.MA10 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  485. .data, 2)) : 0
  486. }
  487. if (params[i].seriesName === 'MA30') {
  488. that.MA30 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  489. .data, 2)) : 0
  490. }
  491. if (params[i].seriesName === 'VolumeMA5') {
  492. that.volMA5 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  493. .data, 2)) : 0
  494. }
  495. if (params[i].seriesName === 'VolumeMA10') {
  496. that.volMA10 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
  497. .data, 2)) : 0
  498. }
  499. }
  500. return tooltip;
  501. },
  502. triggerOn: 'click', //提示框触发的条件 'mousemove','click','mousemove|click','none'
  503. textStyle: {
  504. fontSize: 10
  505. }, //提示框浮层的文本样式
  506. backgroundColor: 'rgba(30,42,66,0.8);', //提示框浮层的背景颜色。
  507. borderColor: '#2f3a56', //提示框浮层的边框颜色。
  508. borderWidth: 2,
  509. position: function(pos, params, el, elRect, size) { //提示框浮层的位置,默认不设置时位置会跟随鼠标的位置。
  510. var obj = {
  511. top: 20
  512. };
  513. obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 10;
  514. return obj;
  515. },
  516. axisPointer: { //坐标轴指示器配置项。
  517. label: {
  518. color: 'rgba(255,255,255,.87)',
  519. fontSize: 9,
  520. backgroundColor: '#020204',
  521. borderColor: "#9c9fa4",
  522. shadowBlur: 0,
  523. borderWidth: 0.5,
  524. padding: [4, 2, 3, 2],
  525. },
  526. animation: false,
  527. type: 'cross',
  528. lineStyle: {
  529. color: {
  530. type: 'linear',
  531. x: 0,
  532. y: 0,
  533. x2: 0,
  534. y2: 1,
  535. colorStops: [{
  536. offset: 0,
  537. color: 'rgba(30, 42, 66, 0.1)' // 0% 处的颜色
  538. }, {
  539. offset: 0.7,
  540. color: 'rgba(30, 42, 66,0.9)' // 100% 处的颜色
  541. }, {
  542. offset: 1,
  543. color: 'rgba(30, 42, 66,0.2)' // 100% 处的颜色
  544. }]
  545. },
  546. width: 10,
  547. shadowColor: 'rgba(30, 42, 66,0.7)',
  548. shadowBlur: 0,
  549. shadowOffsetY: 68,
  550. }
  551. }
  552. },
  553. dataZoom: [{ //用于区域缩放
  554. type: 'inside',
  555. xAxisIndex: [0, 1],
  556. realtime: false,
  557. start: 50,
  558. end: 100,
  559. }],
  560. series: [{
  561. type: 'candlestick',
  562. name: '日K',
  563. data: [],
  564. itemStyle: {
  565. color: upColor,
  566. color0: downColor,
  567. borderColor: upColor,
  568. borderColor0: downColor
  569. },
  570. markPoint: {
  571. symbol: 'rect',
  572. symbolSize: [-10, 0.5],
  573. symbolOffset: [5, 0],
  574. itemStyle: {
  575. color: 'rgba(255,255,255,.87)'
  576. },
  577. label: {
  578. color: 'rgba(255,255,255,.87)',
  579. offset: [10, 0],
  580. fontSize: 10,
  581. align: 'left',
  582. formatter: function(params) {
  583. return Number(params.value).toFixed(2)
  584. }
  585. },
  586. data: [{
  587. name: 'max',
  588. type: 'max',
  589. valueDim: 'highest'
  590. },
  591. {
  592. name: 'min',
  593. type: 'min',
  594. valueDim: 'lowest'
  595. }
  596. ]
  597. },
  598. },
  599. {
  600. name: 'MA5',
  601. type: 'line',
  602. data: [],
  603. symbol: 'none', //去除圆点
  604. smooth: true,
  605. lineStyle: {
  606. normal: {
  607. opacity: 1,
  608. width: 1,
  609. color: "#eef4ba"
  610. }
  611. },
  612. z: 5
  613. },
  614. {
  615. name: 'MA10',
  616. type: 'line',
  617. data: [],
  618. symbol: 'none', //去除圆点
  619. smooth: true,
  620. lineStyle: {
  621. normal: {
  622. opacity: 1,
  623. width: 1,
  624. color: '#83c1c5'
  625. }
  626. },
  627. z: 4
  628. },
  629. {
  630. name: 'MA30',
  631. type: 'line',
  632. data: [],
  633. symbol: 'none', //去除圆点
  634. smooth: true,
  635. lineStyle: {
  636. normal: {
  637. opacity: 1,
  638. width: 1,
  639. color: '#b39cd8'
  640. }
  641. },
  642. z: 3
  643. },
  644. {
  645. name: 'Volume',
  646. type: 'bar',
  647. xAxisIndex: 1,
  648. yAxisIndex: 1,
  649. data: []
  650. },
  651. {
  652. name: 'VolumeMA5',
  653. type: 'line',
  654. xAxisIndex: 1,
  655. yAxisIndex: 1,
  656. data: [],
  657. symbol: 'none', //去除圆点
  658. smooth: true,
  659. lineStyle: {
  660. normal: {
  661. opacity: 1,
  662. width: 1,
  663. color: "#eef4ba"
  664. }
  665. },
  666. z: 5
  667. },
  668. {
  669. name: 'VolumeMA10',
  670. type: 'line',
  671. xAxisIndex: 1,
  672. yAxisIndex: 1,
  673. data: [],
  674. symbol: 'none', //去除圆点
  675. smooth: true,
  676. lineStyle: {
  677. normal: {
  678. opacity: 1,
  679. width: 1,
  680. color: '#83c1c5'
  681. }
  682. },
  683. z: 4
  684. },
  685. ]
  686. };
  687. myChart.setOption(option);
  688. // 加载上一页数据
  689. myChart.on('datazoom', function(params) {
  690. let num = params.batch[0]['start'];
  691. if (num == 0) {
  692. console.log('到最左边了')
  693. }
  694. })
  695. window.addEventListener('resize', () => {
  696. myChart.resize()
  697. })
  698. }
  699. }
  700. })