var myChart;
var ws; // WebSocket 实例
// 弹窗
function alertError(title) {
document.addEventListener('plusready', function() {
console.log('......')
})
try {
plus.nativeUI.toast(title, {
icon: '/static/common/toast-error.png',
style: 'inline',
verticalAlign: 'top'
});
} catch (e) {
//TODO handle the exception
}
}
var app = new Vue({
el: '#app',
data: {
MA5: '',
MA10: '',
MA30: '',
MA60: '',
volMA5: '',
volMA10: '',
current: '1min',
tabs: [{
'label': '1分钟',
'value': '1min'
},
{
'label': '5分钟',
'value': '5min'
},
{
'label': '15分钟',
'value': '15min'
},
{
'label': '30分钟',
'value': '30min'
},
{
'label': '1小时',
'value': '60min'
},
{
'label': '4小时',
'value': '4hour'
},
{
'label': '1天',
'value': '1day'
},
{
'label': '1个月',
'value': '1mon'
},
],
category: 1,
categoryList: [{
'label': '深度',
'value': 1
},
{
'label': '实时成交',
'value': 2
},
{
'label': '简介',
'value': 3
},
],
txData: {}, //交易数据统计
buyList: [],
sellList: [],
dealHis: [],
tokenInfo: {},
page: 1,
klineData: [], // 存储K线数据
volumesData: [],
depthList: {},
dates: [],
period: '1min',
currency_name:'',
pair:'btcusdt',
rid:null,
},
created() {
//this.getDepth()
},
mounted() {
const params = new URLSearchParams(window.location.search);
const symbol = params.get('symbol');
const pair = params.get('pair');
this.currency_name=symbol;
this.pair=pair
myChart = echarts.init(document.getElementById('main'));
this.draw()
//this.getKline()
// 连接 WebSocket 服务
this.connectWebSocket();
},
methods: {
// 返回上一页
back() {
uni.navigateBack()
},
// 获取k线数据,生成k线
getKline() {
var dataMA5 = this.calculateMA(5, this.klineData);
var dataMA10 = this.calculateMA(10, this.klineData);
var dataMA30 = this.calculateMA(30, this.klineData);
//var dataMA60 = this.calculateMA(60, this.klineData);
var volumeMA5 = this.calculateMA(5, this.volumesData);
var volumeMA10 = this.calculateMA(10, this.volumesData);
myChart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
xAxis: [{
data: this.dates
},
{
data: this.dates
},
],
series: [{
name: '日K',
data: this.klineData
},
{
name: 'MA5',
data: dataMA5
},
{
name: 'MA10',
data: dataMA10
},
{
name: 'MA30',
data: dataMA30
},
// {
// name: 'MA60',
// data: dataMA60
// },
{
name: 'Volume',
data: this.volumesData
},
{
name: 'VolumeMA5',
data: volumeMA5
},
{
name: 'VolumeMA10',
data: volumeMA10
},
]
})
},
// 列表条数不足补全
addItem(list, type) {
// type: 1开头加,2末尾加
list = list || [];
let len = 20 - list.length;
if (len > 0) {
for (let i = 0; i < len; i++) {
if (type == 1) {
list.unshift({})
} else {
list.push({})
}
}
}
return list;
},
// 获取深度数据
getDepth() {
this.buyList = this.addItem(this.depthList.buyList || []);
this.sellList = this.addItem(this.depthList.sellList || []);
},
// 获取成交记录
getDealHis() {
//this.dealHis=dealHis();
},
// 获取项目简介信息
getTokenInfo() {
this.tokenInfo = tokenInfo;
},
// 切换tab
switchTab(val) {
let _self=this
//console.log(val)
if (this.current == val) return;
console.log("--------------------------------",this.period)
this.current = val;
let curPeriod = this.period;
let klineUnsubUrl="market."+_self.pair+".kline."+this.period;
// 取消订阅数据
let unsubKline = {
event: "un_sub",
channel: [klineUnsubUrl],
id: _self.rid,
type: "kline"
};
ws.send(JSON.stringify(unsubKline));
this.period = val;
//market.kline.btcusdt.1min.page
let klineReqUrl = "market.kline." +_self.pair+"."+ _self.period + '.init';
// 请求对应信息的数据
//market.kline.btcusdt.1min
let requestKline = {
event: "req",
channel: [klineReqUrl],
//id: _self.rid
};
//market.btcusdt.kline.1min
// 订阅数据
let klineUrlPrefix = "market."+_self.pair+".kline."+this.period;
let subKline = {
event: "sub",
channel: [klineUrlPrefix],
id: _self.rid,
type: "kline"
};
//请求历史 K线数据
ws.send(JSON.stringify(requestKline));
//重新订阅数据
ws.send(JSON.stringify(subKline));
this.getKline()
},
// 切换类目
switchCategory(val) {
if (this.category == val) return;
this.category = val;
if (this.category == 1) {
this.getDepth()
} else if (this.category == 2) {
this.getDealHis()
} else {
this.getTokenInfo()
}
},
// 截取数字字符串 保留precision小数
formatterNum(value, precision) {
let reg = new RegExp('^\\d+(?:\\.\\d{0,' + precision + '})?')
return value.toString().match(reg)
},
// 计算MA
calculateMA(dayCount, data) {
var result = [];
for (var i = 0, len = data.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++) {
sum += data[i - j][1];
}
result.push((sum / dayCount).toFixed(2));
}
return result;
},
// 绘制(配置项)
draw() {
let that = this;
var upColor = '#03ad91';
var downColor = '#dd345b';
var colorList = ['#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83', '#ca8622',
'#bda29a', '#6e7074',
'#546570', '#c4ccd3'
];
var labelFont = 'bold 12px Sans-serif';
var option = {
backgroundColor: '#0d1723',
title: {
show: false
},
legend: {
show: false
},
visualMap: {
show: false,
seriesIndex: 4,
dimension: 2,
pieces: [{
value: 1,
color: downColor
}, {
value: -1,
color: upColor
}]
},
grid: [{
top: '5%',
left: 20,
right: 30,
height: '70%'
},
{
top: '80%',
left: 20,
right: 30,
height: '16%'
},
],
axisPointer: { //坐标轴指示器配置项
link: {
xAxisIndex: 'all'
},
label: {
backgroundColor: '#0d1723',
color: '#fff',
borderColor: 'rgb(99, 117, 139)',
borderWidth: 1,
borderRadius: 2,
fontSize: 10
}
},
xAxis: [{
type: 'category', //坐标轴类型。(value:数值轴,适用于连续数据。,category:类目轴,适用于离散的类目数据,time: 时间轴,适用于连续的时序数据,log:对数轴。适用于对数数据)
data: [], //类目数据,在类目轴(type: 'category')中有效。
scale: true,
boundaryGap: false, //坐标轴两边留白策略,类目轴和非类目轴的设置和表现不一样。
axisLine: {
show: false
}, //坐标轴轴线相关设置
axisTick: {
show: false
}, //坐标轴刻度相关设置。
axisLabel: {
show: false,
}, //坐标轴刻度标签的相关设置。
splitLine: {
show: false,
lineStyle: {
color: 'rgba(255,255,255, 0.1)'
}
}, //坐标轴在 grid 区域中的分隔线。
min: 'dataMin', //坐标轴刻度最小值。可以设置成特殊值 'dataMin',此时取数据在该轴上的最小值作为最小刻度。
max: 'dataMax', //坐标轴刻度最大值。可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
axisPointer: {
//snap: true,
label: {
margin: 200
}
},
}, {
type: 'category',
gridIndex: 1, //x 轴所在的 grid 的索引,默认位于第一个 grid。
data: [], //类目数据,在类目轴(type: 'category')中有效。
scale: true,
boundaryGap: false, //坐标轴两边留白策略,类目轴和非类目轴的设置和表现不一样。
axisLine: {
show: false,
lineStyle: {
color: 'rgba(255,255,255,1)',
width: 1
}
}, //坐标轴轴线相关设置
axisTick: {
show: false
}, //坐标轴刻度相关设置。
axisLabel: { //坐标轴刻度标签的相关设置。
show: true,
margin: 6,
fontSize: 10,
color: 'rgba(99, 117, 139, 1.0)',
formatter: function(value) {
return echarts.format.formatTime('MM-dd', value);
}
},
splitNumber: 20,
splitLine: {
show: false,
lineStyle: {
color: 'rgba(255,255,255, 0.1)'
}
}, //坐标轴在 grid 区域中的分隔线。
min: 'dataMin', //坐标轴刻度最小值。可以设置成特殊值 'dataMin',此时取数据在该轴上的最小值作为最小刻度。
max: 'dataMax', //坐标轴刻度最大值。可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
// axisPointer: { show: true, type: 'none', label: { show: false }},
}],
yAxis: [{
type: 'value', //坐标轴类型。(value:数值轴,适用于连续数据。,category:类目轴,适用于离散的类目数据,time: 时间轴,适用于连续的时序数据,log:对数轴。适用于对数数据)
position: 'right', //y 轴的位置。'left','right'
scale: true, //是否是脱离 0 值比例。设置成 true 后坐标刻度不会强制包含零刻度。在双数值轴的散点图中比较有用。(在设置 min 和 max 之后该配置项无效。)
axisLine: {
show: true
}, //坐标轴轴线相关设置。
axisTick: {
show: true,
inside: true
}, //坐标轴刻度相关设置。
axisLabel: { //坐标轴刻度标签的相关设置。
show: true,
color: 'rgba(99, 117, 139, 1.0)',
inside: true,
fontSize: 10,
formatter: function(value) {
return Number(value).toFixed(2)
}
},
splitLine: {
show: false,
lineStyle: {
color: 'rgba(255,255,255, 0.1)'
}
}, //坐标轴在 grid 区域中的分隔线。
}, {
type: 'value',
position: 'right',
scale: true,
gridIndex: 1,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
show: false
},
splitLine: {
show: false
}
}],
animation: false, //是否开启动画。
color: colorList,
tooltip: {
show: true, //是否显示提示框组件,包括提示框浮层和 axisPointer。
trigger: 'axis', //触发类型。item,axis,none
formatter(params) {
let tooltip = '';
let time = '',
open = 0,
high = 0,
low = 0,
close = 0,
amount = 0;
for (var i = 0; i < params.length; i++) {
if (params[i].seriesName === '日K') {
time = params[i].name;
open = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
1], 2)) : 0;
close = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
2], 2)) : 0;
low = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
3], 2)) : 0;
high = params[i].data.length > 1 ? Number(that.formatterNum(params[i].data[
4], 2)) : 0;
amount = params[i].data.length > 1 ? Number(that.formatterNum(params[i]
.data[5], 2)) : 0;
// console.log(time,open,close,low,high,amount)
tooltip = '
';
}
if (params[i].seriesName === 'MA5') {
that.MA5 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
.data, 2)) : 0
}
if (params[i].seriesName === 'MA10') {
that.MA10 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
.data, 2)) : 0
}
if (params[i].seriesName === 'MA30') {
that.MA30 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
.data, 2)) : 0
}
// if (params[i].seriesName === 'MA60') {
// that.MA60 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i].data, 2)) : 0
// }
if (params[i].seriesName === 'VolumeMA5') {
that.volMA5 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
.data, 2)) : 0
}
if (params[i].seriesName === 'VolumeMA10') {
that.volMA10 = params[i].data !== 'NAN' ? Number(that.formatterNum(params[i]
.data, 2)) : 0
}
}
return tooltip;
},
triggerOn: 'click', //提示框触发的条件 'mousemove','click','mousemove|click','none'
textStyle: {
fontSize: 10
}, //提示框浮层的文本样式
backgroundColor: 'rgba(30,42,66,0.8);', //提示框浮层的背景颜色。
borderColor: '#2f3a56', //提示框浮层的边框颜色。
borderWidth: 2,
position: function(pos, params, el, elRect, size) { //提示框浮层的位置,默认不设置时位置会跟随鼠标的位置。
var obj = {
top: 20
};
obj[['left', 'right'][+(pos[0] < size.viewSize[0] / 2)]] = 10;
return obj;
},
axisPointer: { //坐标轴指示器配置项。
label: {
color: 'rgba(255,255,255,.87)',
fontSize: 9,
backgroundColor: '#020204',
borderColor: "#9c9fa4",
shadowBlur: 0,
borderWidth: 0.5,
padding: [4, 2, 3, 2],
},
animation: false,
type: 'cross',
lineStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [{
offset: 0,
color: 'rgba(30, 42, 66, 0.1)' // 0% 处的颜色
}, {
offset: 0.7,
color: 'rgba(30, 42, 66,0.9)' // 100% 处的颜色
}, {
offset: 1,
color: 'rgba(30, 42, 66,0.2)' // 100% 处的颜色
}]
},
width: 10,
shadowColor: 'rgba(30, 42, 66,0.7)',
shadowBlur: 0,
shadowOffsetY: 68,
}
}
},
dataZoom: [{ //用于区域缩放
type: 'inside',
xAxisIndex: [0, 1],
realtime: false,
start: 50,
end: 100,
}],
series: [{
type: 'candlestick',
name: '日K',
data: [],
itemStyle: {
color: upColor,
color0: downColor,
borderColor: upColor,
borderColor0: downColor
},
markPoint: {
symbol: 'rect',
symbolSize: [-10, 0.5],
symbolOffset: [5, 0],
itemStyle: {
color: 'rgba(255,255,255,.87)'
},
label: {
color: 'rgba(255,255,255,.87)',
offset: [10, 0],
fontSize: 10,
align: 'left',
formatter: function(params) {
return Number(params.value).toFixed(2)
}
},
data: [{
name: 'max',
type: 'max',
valueDim: 'highest'
},
{
name: 'min',
type: 'min',
valueDim: 'lowest'
}
]
},
},
{
name: 'MA5',
type: 'line',
data: [],
symbol: 'none', //去除圆点
smooth: true,
lineStyle: {
normal: {
opacity: 1,
width: 1,
color: "#eef4ba"
}
},
z: 5
},
{
name: 'MA10',
type: 'line',
data: [],
symbol: 'none', //去除圆点
smooth: true,
lineStyle: {
normal: {
opacity: 1,
width: 1,
color: '#83c1c5'
}
},
z: 4
},
{
name: 'MA30',
type: 'line',
data: [],
symbol: 'none', //去除圆点
smooth: true,
lineStyle: {
normal: {
opacity: 1,
width: 1,
color: '#b39cd8'
}
},
z: 3
},
// {
// name: 'MA60',
// type: 'line',
// data: [],
// symbol: 'none',//去除圆点
// smooth: true,
// lineStyle: { normal: { opacity: 1, width: 1, color: '#b39cd8' } },
// z: 1
// },
{
name: 'Volume',
type: 'bar',
xAxisIndex: 1,
yAxisIndex: 1,
data: []
},
{
name: 'VolumeMA5',
type: 'line',
xAxisIndex: 1,
yAxisIndex: 1,
data: [],
symbol: 'none', //去除圆点
smooth: true,
lineStyle: {
normal: {
opacity: 1,
width: 1,
color: "#eef4ba"
}
},
z: 5
},
{
name: 'VolumeMA10',
type: 'line',
xAxisIndex: 1,
yAxisIndex: 1,
data: [],
symbol: 'none', //去除圆点
smooth: true,
lineStyle: {
normal: {
opacity: 1,
width: 1,
color: '#83c1c5'
}
},
z: 4
},
]
};
myChart.setOption(option);
// 加载上一页数据
myChart.on('datazoom', function(params) {
let num = params.batch[0]['start'];
if (num == 0) {
console.log('到最左边了')
}
})
window.addEventListener('resize', () => {
myChart.resize()
})
},
// 连接到 WebSocket
connectWebSocket() {
let _self=this;
ws = new WebSocket('wss://jacqueshuang-cion.hf.space'); // 连接 WebSocket 服务端
// 动态生成频道名称
const klineReqChannel = `market.kline.${this.pair}.${this.period}.init`;
const klineSubChannel = `market.${this.pair}.kline.${this.period}`;
const depthChannel = `market.${this.pair}.depth.step1`;
const tradeChannel = `market.${this.pair}.trade.detail`;
const detailChannel = `market.${this.pair}.detail`;
//请求对应信息的数据
let requestKline = {
"event": "req",
"channel": [klineReqChannel] //req 数组只能一个
};
//订阅k线数据
let subKline = {
"event": "sub",
"id": "723c9150-e143-4d80-84fc-6d0acdcba8f5",
"channel": [klineSubChannel], //1min 5min 15min 30min 60min 1day 1mon..
"type": "kline"
};
//订阅深度数据
let subDepth = {
"event": "sub",
"id": "723c9150-e143-4d80-84fc-6d0acdcba8f5",
"channel": [depthChannel],
"type": "depth"
};
//订阅成交量
let subDetail = {
"event": "sub",
"id": "723c9150-e143-4d80-84fc-6d0acdcba8f5",
"channel": [tradeChannel],
"type": "trade"
};
let subTicker = {
"event": "sub",
"id": "723c9150-e143-4d80-84fc-6d0acdcba8f5",
"channel": [detailChannel],
"type": "detail"
}
// WebSocket 打开时的回调
ws.onopen = () => {
};
// WebSocket 收到消息时的回调
ws.onmessage = (event) => {
var blob = event.data;
let result = JSON.parse(blob)
if (result.event == 'conn') {
let id = result.data;
_self.rid=id;
subKline.id = id;
subTicker.id = id;
subDepth.id = id;
subDetail.id=id;
//订阅实时 K线数据
ws.send(JSON.stringify(requestKline))
// //请求历史 K线数据
ws.send(JSON.stringify(subKline))
//详细
ws.send(JSON.stringify(subTicker))
// //订阅成交量
ws.send(JSON.stringify(subDetail));
// //请求深度数据
ws.send(JSON.stringify(subDepth));
}
if (result.event == 'req'&&result.channel.includes("kline")) {
this.handleData(result);
}
if (result.event == 'kline') {
this.handleData(result);
}
if (result.event == 'ticker') {
this.handleData(result);
}
if (result.event == 'depth') {
this.handleData(result);
}
if (result.event == 'detail') {
this.handleData(result);
}
if (result.event == 'trade') {
this.handleData(result);
}
};
// WebSocket 错误时的回调
ws.onerror = (error) => {
console.error('WebSocket 错误:', error);
};
// WebSocket 关闭时的回调
ws.onclose = () => {
console.log('WebSocket 已关闭');
};
},
// 处理接收到的信息
async handleData(msg) {
//console.log(msg);
// 判断数据类型
if (msg.event && msg.channel.includes('kline')) {
// K线数据
this.updateKlineData(msg.data);
} else if (msg.event && msg.event.includes('depth')) {
// 深度数据
this.updateDepthData(msg.data);
//聚合数据
} else if (msg.event && msg.event.includes('detail')) {
this.updateTickerData(msg.data);
} else if (msg.event && msg.event.includes('trade')) {
this.updateDetailData(msg.data);
}
if (msg.event && msg.event.includes('req')) {
//K线数据
this.initKlineData(msg.data);
}
// 处理ping-pong
if (msg.ping) {
// 如果是 ping 消息
this.sendHeartMessage(msg.ping);
}
},
// 初始化K-line 图表数据
async initKlineData(res) {
// 假设服务器发送的数据格式为:[时间, 开盘价, 收盘价, 最低价, 最高价, 成交量]
this.klineData = res; // 提取 K-line 数据
// 转换数据
const {
rawData,
dates,
klineData,
volumesData
} = this.transformData(this.klineData);
//console.log("Raw Data:", rawData);
this.dates = dates;
this.klineData = rawData.map(function(item) {
return [+item[1], +item[2], +item[3], +item[4], +item[5]];
});
this.volumesData = rawData.map(function(item, index) {
return [index, item[5], item[1] > item[2] ? 1 : -1];
});
this.getKline();
},
//实时处理订阅k线数据
async updateKlineData(newKline) {
console.log(newKline);
const date = this.timestampToDate(newKline.KTime);
// 检查时间戳是否已经存在
if (this.dates.includes(date)) {
// 更新最后一条 K 线数据
const lastIndex = this.dates.length - 1;
this.klineData[lastIndex] = [
newKline['open'],
newKline['close'],
newKline['low'],
newKline['high'],
Math.round(newKline['vol'])
];
this.volumesData[lastIndex] = [
lastIndex + 1,
Math.round(newKline['vol']),
newKline['open'] > newKline['close'] ? 1 : -1
];
} else {
// 如果是新时间戳,添加到数据中
this.dates.push(date);
this.klineData.push([
newKline['open'],
newKline['close'],
newKline['low'],
newKline['high'],
Math.round(newKline['vol'])
]);
this.volumesData.push([
this.klineData.length + 1,
Math.round(newKline['vol']),
newKline['open'] > newKline['close'] ? 1 : -1
]);
}
// 更新图表
this.getKline();
},
//更新深度数据
async updateDepthData(tick) {
let buyList = tick.bids.map(item => ({
price: item[0], // 买价
amount: item[1], // 买量
width: this.sum(1, 100)
}));
let sellList = tick.asks.map(item => ({
price: item[0], // 卖价
amount: item[1], // 卖量
width: this.sum(1, 100)
}));
this.depthList = {
buyList: buyList,
sellList: sellList
};
this.getDepth();
},
// 获取24小时交易数据统计
async updateTickerData(tick) {
console.log('ticker', tick);
// 计算涨幅
const upRate = ((tick.close - tick.open) / tick.open * 100).toFixed(2) + "%";
// 判断涨跌
const upFlag = tick.close > tick.open ? "1" : "2"; // 1涨绿 2跌红
this.txData = {
// 最新成交价
"lastPrice": tick.close,
// 涨幅
"upRate": upRate,
// 1涨绿 2跌红
"upFlag": upFlag,
// 24小时交易量
"amount": Math.floor(tick.amount),
// 24小时最高价
"high": tick.high,
// 24小时最低价
"low": tick.low,
//以报价币种计量的交易量(以滚动24小时计)
"vol": Math.floor(tick.vol)
}
},
async updateDetailData(tick) {
let detailList = tick.data.map(item => ({
date: this.formatTimestamp(item['ts']),
// 1买入 2卖出
takerFlag: item['direction'] == "buy" ? "1" : "2",
price: item['price'],
amount: item['amount']
}));
// 合并数组
this.dealHis = this.dealHis.concat(detailList);
// 按时间降序排序(最新时间排在前面)
this.dealHis.sort((a, b) => {
// 将时间字符串转为秒数
const timeToSeconds = (time) => {
const [hours, minutes, seconds] = time.split(':').map(Number);
return hours * 3600 + minutes * 60 + seconds;
};
return timeToSeconds(b.date) - timeToSeconds(a.date);
});
},
//时间戳转时分秒
formatTimestamp(timestamp) {
// 创建一个新的Date对象,参数是时间戳(毫秒)
const date = new Date(timestamp);
// 获取小时、分钟、秒和毫秒,并确保它们都是两位数
let hh = date.getHours().toString().padStart(2, '0');
let mm = date.getMinutes().toString().padStart(2, '0');
let ss = date.getSeconds().toString().padStart(2, '0');
//let ms = date.getMilliseconds().toString().padStart(3, '0');
// 返回格式化后的字符串
return `${hh}:${mm}:${ss}`;
},
// 时间戳转换为 yyyy-mm-dd 格式
timestampToDate(timestamp) {
const date = new Date(timestamp * 1000);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
// 添加小时和分钟
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
},
// 转换火币数据为目标格式
transformData(huobiData) {
if (!Array.isArray(huobiData)) {
console.error("huobiData 不是一个有效的数组");
return {
rawData: [],
dates: [],
klineData: [],
volumes: []
};
}
const rawData = huobiData.map(item => {
const date = this.timestampToDate(item.KTime);
return [date, item.open, item.close, item.low, item.high, Math.round(item.vol)];
});
// 提取 dates
const dates = rawData.map(item => item[0]);
// 提取 kline 数据(价格和成交量)
///
///
const klineData = rawData.map(item => [+item[1], +item[2], +item[3], +item[4], +item[5]]);
// 提取成交量数据
const volumes = rawData.map((item, index) => {
return [index, item[5], item[1] > item[2] ? 1 : -1];
});
// console.log( {
// rawData,
// dates,
// klineData,
// volumes
// })
return {
rawData,
dates,
klineData,
volumes
};
},
//心跳信息
sendHeartMessage(ping) {
ws.send(JSON.stringify({
"pong": ping
}));
},
// 获取指定区间随机数
sum(m, n) {
var num = Math.floor(Math.random() * (m - n) + n);
return num;
}
}
})