| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- /**
- * 将二进制数组转化为无符号整型数值的方法
- * array 二进制数组
- * islittleEndian 是否小端
- * @returns {number}
- */
- function byteArrayToUInt(array: Uint8Array, isLittleEndian: boolean): number {
- const dataView = new DataView(new Uint8Array(array).buffer);
- let value = 0;
- switch (array.length) {
- case 2:
- value = dataView.getUint16(0, isLittleEndian);
- break;
- case 4:
- value = dataView.getUint32(0, isLittleEndian);
- break;
- }
- return value;
- }
- /**
- * 解析行情订阅请求包
- * @param rspPackage
- */
- export function parseSubscribeRsp(content: Uint8Array): Promise<Proto.GoodsQuoteRsp[]> {
- const result: Proto.GoodsQuoteRsp[] = [];
- return new Promise((resolve, reject) => {
- if (content.length === 0) {
- // 有可能空订阅,也有可能订阅返回数据为空,但其实已经订阅了商品
- // 暂做正常返回 空字符串 处理,如遇到问题继续优化即可
- console.warn('行情订阅请求包返回为空');
- resolve(result);
- } else {
- const count = byteArrayToUInt(content.subarray(0, 4), false);
- if (count > 1000) {
- // 游客模式 刷新成长问题,为了不让页面卡死,暂时处理
- resolve(result);
- } else {
- switch (count) {
- case -1:
- reject('订阅失败');
- break;
- case -2:
- reject('Token校验失败');
- break;
- case -3:
- reject('无对应商品信息');
- break;
- default:
- // 判断返回的Count是否有问题
- if (!count || count > (content.length - 4) / 66) {
- reject('行情订阅返回数据不正确');
- } else {
- let position = 4;
- for (let i = 0; i < count; i++) {
- const dataArray = content.subarray(position, position + 66);
- const subState = dataArray[0];
- // FIXME: 目前行情接入服务不能正确返回交易所代码
- const exchangeCode = dataArray[2];
- const goodsCode = String.fromCharCode(...dataArray.subarray(2, dataArray.length)).trim();
- result.push({ subState, goodsCode, exchangeCode });
- position += 66;
- }
- resolve(result);
- }
- }
- }
- }
- })
- }
- /**
- * 解析行情推送报文
- * @param {Array} quotationData 行情信息
- */
- export function parseReceivePush(quotationData: Uint8Array) {
- const result: Proto.GoodsQuote[] = [];
- // 目前发现可能会传入空数组
- if (quotationData.length) {
- // 分解行正则
- const regRow = /10\s.*?11/g;
- // 分解单行 key 正则
- const regKey = /01\s.*?02/g;
- // 分解单行 value 正则
- const regValue = /02\s.*?01|02\s.*?11/g;
- // 记录已经更新盘面的商品信息数组
- // 0x10 ... 0x01 key 0x02 value 0x01 key 0x02 value ... 0x11
- const hexString = Array.prototype.map.call(quotationData, (x) => ('00' + x.toString(16)).slice(-2)).join(' ');
- // let hexString = 'FF 10 01 55 02 45 46 47 48 01 66 02 48 47 46 45 11 10 01 77 02 AA BB CC DD 11 00';
- // 获取单行行情
- const rows = hexString.match(regRow);
- if (rows) {
- for (const low of rows) {
- // 获取 key value 表列
- const keys = low.match(regKey);
- const values = low.match(regValue);
- if (keys && values) {
- const quote: Proto.GoodsQuote = {};
- for (let i = 0; i < keys.length; i++) {
- const key = parseInt(keys[i].substring(3, 5), 16);
- const tmpValue = values[i];
- const value = new Uint8Array(tmpValue.substring(3, tmpValue.length - 3).split(' ').map((byte) => parseInt(byte, 16)));
- setQuoteTikFieldByByte(quote, key, value);
- }
- if (Object.keys(quote).length) {
- result.push(quote);
- //console.log('行情推送', quote);
- }
- }
- }
- }
- }
- return result;
- }
- /**
- * 分解缓存行情字段的方法
- * @param quote
- * @param key
- * @param value
- */
- function setQuoteTikFieldByByte(quote: Proto.GoodsQuote, key: number, value: Uint8Array) {
- const strValue = String.fromCharCode(...value);
- switch (key) {
- case 0x56:
- quote.exchangecode = Number(strValue);
- break;
- case 0x21:
- quote.goodscode = strValue;
- break;
- case 0x24:
- quote.last = Number(strValue);
- break;
- case 0x5b:
- quote.holdvolume = Number(strValue);
- break;
- case 0x25:
- quote.lastvolume = Number(strValue);
- break;
- case 0x3c:
- quote.preholdvolume = Number(strValue);
- break;
- case 0x32:
- quote.presettle = Number(strValue);
- break;
- case 0x33:
- quote.settle = Number(strValue);
- break;
- case 0x29:
- quote.totalturnover = Number(strValue);
- break;
- case 0x28:
- quote.totalvolume = Number(strValue);
- break;
- case 0x35:
- quote.limithigh = Number(strValue);
- break;
- case 0x36:
- quote.limitlow = Number(strValue);
- break;
- case 'L'.charCodeAt(0):
- quote.ask = Number(strValue);
- break;
- case 'M'.charCodeAt(0):
- quote.ask2 = Number(strValue);
- break;
- case 'N'.charCodeAt(0):
- quote.ask3 = Number(strValue);
- break;
- case 'O'.charCodeAt(0):
- quote.ask4 = Number(strValue);
- break;
- case 'P'.charCodeAt(0):
- quote.ask5 = Number(strValue);
- break;
- case 'Q'.charCodeAt(0):
- quote.askvolume = Number(strValue);
- break;
- case 'R'.charCodeAt(0):
- quote.askvolume2 = Number(strValue);
- break;
- case 'S'.charCodeAt(0):
- quote.askvolume3 = Number(strValue);
- break;
- case 'T'.charCodeAt(0):
- quote.askvolume4 = Number(strValue);
- break;
- case 'U'.charCodeAt(0):
- quote.askvolume5 = Number(strValue);
- break;
- case 'B'.charCodeAt(0):
- quote.bid = Number(strValue);
- break;
- case 'C'.charCodeAt(0):
- quote.bid2 = Number(strValue);
- break;
- case 'D'.charCodeAt(0):
- quote.bid3 = Number(strValue);
- break;
- case 'E'.charCodeAt(0):
- quote.bid4 = Number(strValue);
- break;
- case 'F'.charCodeAt(0):
- quote.bid5 = Number(strValue);
- break;
- case 'G'.charCodeAt(0):
- quote.bidvolume = Number(strValue);
- break;
- case 'H'.charCodeAt(0):
- quote.bidvolume2 = Number(strValue);
- break;
- case 'I'.charCodeAt(0):
- quote.bidvolume3 = Number(strValue);
- break;
- case 'J'.charCodeAt(0):
- quote.bidvolume4 = Number(strValue);
- break;
- case 'K'.charCodeAt(0):
- quote.bidvolume5 = Number(strValue);
- break;
- case ','.charCodeAt(0):
- quote.highest = Number(strValue);
- break;
- case '-'.charCodeAt(0):
- quote.lowest = Number(strValue);
- break;
- case '@'.charCodeAt(0):
- quote.date = strValue;
- break;
- case 'A'.charCodeAt(0):
- quote.time = strValue;
- break;
- case '+'.charCodeAt(0):
- quote.preclose = Number(strValue);
- break;
- case '.'.charCodeAt(0):
- quote.opened = Number(strValue);
- break;
- case 0x5c:
- quote.exerciseprice = Number(strValue);
- break;
- case 0x7a:
- quote.inventory = Number(strValue);
- break;
- case 0x7c:
- quote.exchangedate = Number(strValue);
- break;
- case 0x70:
- quote.strbidorder = strValue;
- break;
- case 0x71:
- quote.strbidorder2 = strValue;
- break;
- case 0x72:
- quote.strbidorder3 = strValue;
- break;
- case 0x73:
- quote.strbidorder4 = strValue;
- break;
- case 0x74:
- quote.strbidorder5 = strValue;
- break;
- case 0x75:
- quote.straskorder = strValue;
- break;
- case 0x76:
- quote.straskorder2 = strValue;
- break;
- case 0x77:
- quote.straskorder3 = strValue;
- break;
- case 0x78:
- quote.straskorder4 = strValue;
- break;
- case 0x79:
- quote.straskorder5 = strValue;
- break;
- case 0x7d:
- quote.putoptionpremiums = Number(strValue);
- break;
- case 0x7e:
- quote.putoptionpremiums2 = Number(strValue);
- break;
- case 0x80:
- quote.putoptionpremiums3 = Number(strValue);
- break;
- case 0x81:
- quote.putoptionpremiums4 = Number(strValue);
- break;
- case 0x82:
- quote.putoptionpremiums5 = Number(strValue);
- break;
- case 0x83:
- quote.calloptionpremiums = Number(strValue);
- break;
- case 0x84:
- quote.calloptionpremiums2 = Number(strValue);
- break;
- case 0x85:
- quote.calloptionpremiums3 = Number(strValue);
- break;
- case 0x86:
- quote.calloptionpremiums4 = Number(strValue);
- break;
- case 0x87:
- quote.calloptionpremiums5 = Number(strValue);
- break;
- }
- }
|