You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

224 lines
7.1 KiB

/*********************************************/
// 次文件只需要关注 getBars 和 subscribeBars 函数即可
/******************************************/
import {
socket
} from './websocket.js'
import {
Event
} from './event.js'
// 历史数据 第一条数据的 时间撮 因为k线图一次性历史数据只拿一部分,用户吧图往前滑动,就会用这个时间撮去请求更早的 历史数据
var detafeed_historyTime = 0
// 上一次的 K线周期 切换产品的时候 需要从websock 取消订阅这个
var detafeed_lastResolution = null
// 上一次的产品 切换产品的时候 需要从websock 取消订阅这个
var detafeed_lastSymbol = null
function FeedBase() {}
FeedBase.prototype.onReady = function(callback) {
callback(this._configuration)
}
FeedBase.prototype.getSendSymbolName = function(symbolName) {
var name = symbolName.split('/')
return (name[0] + name[1]).toLocaleLowerCase()
}
FeedBase.prototype.defaultConfiguration = function defaultConfiguration() {
//设置默认配置
return {
supports_search: false,
supports_group_request: false,
supported_resolutions: ['1', '5', '15', '30', '60', '1D', '1W', '1M'],
supports_marks: false,
supports_timescale_marks: false,
supports_time: true
};
};
FeedBase.prototype.resolveSymbol = function(symbolName, onResolve, onError) {
onResolve({
"name": symbolName,
"timezone": "Asia/Shanghai",
"pricescale": 10000000000000000,
"minmov": 1,
"minmov2": 0,
"ticker": symbolName,
"description": "",
"session": "24x7",
"type": "bitcoin",
"volume_precision": 10,
"has_intraday": true,
"intraday_multipliers": ['1', '5', '15', '30', '60', '1D', '1W','1M'], // 时间
"supported_resolutions": ['1', '5', '15', '30', '60', '1D', '1W','1M'], // 时间
"supports_marks": true,
"supports_timescale_marks": true,
"supported_time": true,
"has_weekly_and_monthly": true,
"has_no_volume": true,
"regular_session": "24x7",
})
}
/**
* 更多时间类型在这里添加 时间类型请看火币文档
* @param resolution 订阅周期 按照自己喜欢的来 如 30 30分钟、 1D 一天
* @param name 交易对symbol
* @param to 结束时间
* @returns {object}
*/
const resolutionFormat = (resolution, name, to) => {
let req = `market.${name}.kline.${resolution}min`;
let minutes = resolution;
console.log(resolution)
if (resolution.includes('D')) {
if (resolution.length < 2) resolution = '1' + resolution;
req = `market.${name}.kline.${parseInt(resolution)}day`;
minutes = parseInt(resolution) * 24 * 60;
} else if (resolution.includes('W')) {
if (resolution.length < 2) resolution = '1' + resolution;
req = `market.${name}.kline.${parseInt(resolution)}week`;
minutes = parseInt(resolution) * 24 * 60 * 7;
} else if (resolution.includes('M')) {
if (resolution.length < 2) resolution = '1' + resolution;
req = `market.${name}.kline.${parseInt(resolution)}mon`;
minutes = parseInt(resolution) * 24 * 60 * 30;
} else {
if (resolution / 60 > 1) {
req = `market.${name}.kline.${resolution / 60}hour`;
}
}
let from = null;
if (to) {
from = to - 50 * minutes * 500;
if (resolution.includes('M') || resolution.includes('W')) { // 周线月线控制条数,时间超出火币规定范围, ws报错
from = to - 50 * minutes * 500;
}
}
return {
minutes,
req,
from,
to,
};
};
FeedBase.prototype.getBars = function(symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) {
console.log("获取历史数据")
// 切换产品周期 或者 切换产品 会执行这个函数
let reso = resolutionFormat(resolution, symbolInfo.name, periodParams.to > detafeed_historyTime ? periodParams
.to :
detafeed_historyTime)
if (resolution.includes('M') || resolution.includes('W')) { // 周线月线控制条数,时间超出火币规定范围, ws报错
reso = resolutionFormat(resolution, symbolInfo.name, periodParams.to)
}
// 是历史数据
var history = true
/*
!detafeed_historyTime 如果没请请求过这个产品或者这个周期的历史数据
resolution !== detafeed_lastResolution 是否更换了产品周期
detafeed_lastSymbol !== symbolInfo.name 是否切换了产品
*/
if (!detafeed_historyTime || (resolution !== detafeed_lastResolution) || detafeed_lastSymbol !== symbolInfo
.name) {
// 那就不是历史数据
history = false
// 储存请求过的产品
detafeed_lastSymbol = symbolInfo.name
// 记录目前时间戳,就用目前时间戳往前请求历史数据
detafeed_historyTime = window.parseInt((Date.now() / 1000))
}
/*
@socket.sendData
第一个参数订阅历史数据
第二个参数订阅实时数据
第三个参数 是 是否是历史数据
*/
socket.sendData({
event: "req",
type: "kline",
channel: [reso.req],
fromDate:reso.from,
toDate:reso.to
}, reso.req, history)
Event.off('data')
Event.on('data', data => {
if (data && Array.isArray(data)) {
// 记录这次请求的时间周期
detafeed_lastResolution = resolution
var meta = {
noData: false
}
const datas = []
if (data.length) {
detafeed_historyTime = data[0].id
for (let i of data) {
i.time = i.id * 1000
i.volume = i.vol
datas.push(i)
}
} else {
meta = {
noData: true,
nextTime: detafeed_historyTime
}
}
onHistoryCallback(datas, meta)
}
})
}
FeedBase.prototype.subscribeBars = function(symbolInfo, resolution, onRealtimeCallback, subscriberUID, onResetCacheNeededCallback) {
Event.off('realTime')
// 拿到实时数据 在这里画
Event.on('realTime', data => {
if (Object.prototype.toString.call(data) === '[object Object]' && data.hasOwnProperty('open')) {
//因为有的数值为科学计数法,故增加了转换函数,因为修改了源码中处理小数点的代码,所以需要二次元运算
//如果大于1则根据float形式进行toFixed(2),如果小于1则按照string形式进行截取处理显示
let realtimeData = {
time: data.id * 1000,
volume: data.vol <= 0.00001 ? transferToNumber(data.vol) : data.vol,
close: data.close <= 0.00001 ? transferToNumber(data.close) : data.close,
open: data.open <= 0.00001 ? transferToNumber(data.open) : data.open,
high: data.high <= 0.00001 ? transferToNumber(data.high) : data.high,
low: data.low <= 0.00001 ? transferToNumber(data.low) : data.low
}
onRealtimeCallback(realtimeData)
}
})
}
FeedBase.prototype.unsubscribeBars = function(listenerGuid) {
// 取消订阅产品的callback
}
//处理科学计数法
function transferToNumber(inputNumber) {
if (isNaN(inputNumber)) {
return inputNumber
}
inputNumber = '' + inputNumber
inputNumber = parseFloat(inputNumber)
let eformat = inputNumber.toExponential() // 转换为标准的科学计数法形式(字符串)
let tmpArray = eformat.match(/\d(?:\.(\d*))?e([+-]\d+)/) // 分离出小数值和指数值
let number = inputNumber.toFixed(Math.max(0, (tmpArray[1] || '').length - tmpArray[2]))
return number
}
exports.FeedBase = FeedBase