0

I'm trying to decode the following HEX String from the stock markets.

34 00 01 31 24 05 00 00 2C 00 41 50 DE C1 28 05 00 00 00 C4 C9 67 02 42 
64 00 00 00 45 41 42 4C 2E 4F 30 30 30 30 20 20 50 62 25 00 00 01 20 10 
27 00 80 00

Here is more context around it from the documentation.

  1. Length begins from offset 0 and has a length of 2. It is a is a Little-Endian encoded 16 bit unsigned integer.
  2. MessageType begins from offset 2 and lenght 1. It is A single byte used to hold one ASCII character.
  3. Nanosecond begins from offset 3, lenth of 4 It is a Little-Endian encoded 32 bit unsigned integer.
  4. Order ID begins fro offset 7, length of 8. It is a Little-Endian encoded 64 bit unsigned integer.
  5. Side begins from offset 15 length of 1 It is A single byte used to hold one ASCII character.
  6. Quantity begins from offset 16 length of 4 It is a Little-Endian encoded 32 bit unsigned integer.
  7. Symbol begins from offset 20 length of 12 It has standard ASCII character bytes. They are left justified and padded on the right with spaces
  8. Price begins from offset 32 length of 4. It is Signed Little-Endian encoded four byte integer field with four implied decimal places.
  9. Flags begins from offset 36 and and has a length of 1. It is a A single byte used to hold up to eight 1-bit flags. Each bit will represent a Boolean flag. The 0 bit is the lowest significant bit and the 7 bit is the highest significant bit.
  10. Sub Book begins from offset 37 and has a lengt of 1. It is a 8 bit unsigned integer
  11. SettlementType begins from offset 38 and has a length of 1. It is a A single byte used to hold one ASCII character.
  12. Interest Rate begins from offset 39 an has a length of 4. It is a Signed Little-Endian encoded four byte integer field with four implied decimal places.
  13. Term begins from offset 43 and has alength of 1. It is a 8 bit unsigned integer.

Here is the Code I'm using to decode using the above context

hexString = hexString.replace(/\s/g, '')

// Convert the hex pairs to a buffer
let buffer = Buffer.from(hexString, 'hex');
// Extract the various fields from the buffer
let length = buffer.readUInt16LE(0);
let messageType = buffer.toString('ascii', 2, 3);
let nanosecond = buffer.readUInt32LE(3);
let orderId = buffer.readBigUInt64LE (7);
let side = buffer.toString('ascii', 15, 16);
let quantity = buffer.readUInt32LE(16);
let symbol = buffer.toString('ascii', 20, 32).replace(/ /g, '');
let price = buffer.readInt32LE(32) / 10000.0;
let flags = buffer.toString('ascii', 36, 37);
let subBook = buffer.toString('ascii', 37, 38);
let settlementType = buffer.toString('ascii', 38, 39);
let interestRate = buffer.readInt32LE(39) / 10000.0;
let term = buffer.toString('ascii', 43, 44);

Here is the result I'm getting

> Length: 52
> MessageType: ☺
> Nanosecond: 336945
> Order ID: 2936872868291554304
> Side: ♣
> Quantity: 3288334336
> Symbol: Ig☻BdEABL
> Price: 80847.2366
> Flags: 0
> Sub Book: 0
> SettlementType:
> Interest Rate: 62720.0032
> Term:

This is mostly wrong. Here is the expected output

Length: 52
MessageType: "4"
Nanosecond: 588124
Order ID: 739452273724920
Side: "1"
Quantity: 100
Symbol: "EABL.O0000 Pb"
Price: 25.0
Flags: " "
Sub Book: " "
SettlementType: " "
Interest Rate: 0.0
Term: " "

What Am I missing? Why are there such big differences in the final results? Could it be that I'm decoding the data wrongly or understood the context around the data wrongly or is it that the encoder of the data is wrong also? The data is encoded in Little Endian by the encoder. This is my first time dealing with such data.

VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • you might have better luck using an "unpack" function, see https://stackoverflow.com/questions/5605108/pack-unpack-functions-for-node-js – gog Jan 04 '23 at 09:40
  • Are you _sure_ that data is correct? There's no way for the byte `01` at offset 2 to become `"4"`. – AKX Jan 04 '23 at 10:27
  • @AKX, Here is the explanation I got when I researched more about it. In the ASCII table, the hexadecimal value "34" represents the digit "4". For example, the ASCII code for the letter "A" is 0x41, the ASCII code for the digit "0" is 0x30, and the ASCII code for the exclamation mark "!" is 0x21. When these characters are represented as hexadecimal numbers, they are "41", "30", and "21" respectively. In the messageType field, the hexadecimal value "34" is extracted as the ASCII character represented by that value, which is the digit "4". – Kinyua James Jan 04 '23 at 10:33
  • @KinyuaJames Yes, I know that perfectly well. The only 0x34 in the data you're showing is at the zeroth offset, the low byte of what's supposed to be the 2-byte length field. The data at offset 2 is `01`. Again, are you _sure_ the data you're showing is correct? – AKX Jan 04 '23 at 10:39
  • Makes sense. Yes, this data is correct. I'm 100% about it. How would you decode it using the context I've shared? – Kinyua James Jan 04 '23 at 11:41

1 Answers1

0

I don't have enough reputation to leave a comment so I'm having to put this as an answer...

I don't think you've got anything wrong. Given what the specification states, and just looking at the Nanosecond field, 4 bytes from offset 3 would be 31 24 05 00, and if Little-Endian encoded then this would become 00 05 24 31, which represents the value 336945

A really useful website I've found for visualising what a hex value might represent is https://www.scadacore.com/tools/programming-calculators/online-hex-converter/, it shows you how the different encodings get unpacked and shows what the resultant values are.

Lee
  • 149
  • 1
  • 8
  • Thanks, Lee. Could it be that the encoder is wrong? For example, the Quantity should be 100. but my values are way too big – Kinyua James Jan 04 '23 at 10:29
  • @KinyuaJames - It could be, but it's impossible for me to say. All I can say is that your code appears to match what the documentation requires, so either the encoder is wrong, or the documentation is wrong, or there's something else happening with the value between the encoder and your code. – Lee Jan 09 '23 at 15:11