Browse Source

WIP: Examples of FAST

master
Julio Biason 3 years ago
parent
commit
73b349671c
  1. 62
      content/research/decoding-fast-examples.md
  2. 139
      content/research/decoding-fast-examples.pt.md
  3. 5
      content/research/decoding-fast.md
  4. 5
      content/research/decoding-fast.pt.md

62
content/research/decoding-fast-examples.md

@ -1,6 +1,6 @@
+++ +++
title = "Decoding the FAST Protocol: Examples" title = "Decoding the FAST Protocol: Examples"
date = 2022-01-11 date = 2022-01-12
draft = true draft = true
[taxonomies] [taxonomies]
@ -13,11 +13,17 @@ understand.
<!-- more --> <!-- more -->
{% note() %}
Same disclaimer as before: Because this is based on my personal experience,
some things may be out of place. I tried my best to keep things correctly, but
I may have misunderstood something, or maybe I just typed the value wrong here.
{% end %}
# Simple Hello World # Simple Hello World
This example is basically the same one in This example is basically the same one in
[JetTek](https://jettekfix.com/education/fix-fast-tutorial/) but it is really [JetTek](https://jettekfix.com/education/fix-fast-tutorial/) but it is really
simple, so here we go: simple to explain, so here we go:
## Template ## Template
@ -52,12 +58,12 @@ far; there is no information whatsoever about that second bit in the Presence
Map -- we need to find out which template should be used first. Map -- we need to find out which template should be used first.
The next byte is read: `1000_0001`. As mentioned above, this is the Template The next byte is read: `1000_0001`. As mentioned above, this is the Template
ID. Being a signed integer (and probably mandatory, but don't ask me how that ID. Being an unsigned integer (and probably mandatory, but don't ask me how
works), we read the value, it has the stop bit, so that's the whole integer. that works) and dropping high order bit, we get the Integer "1", which is the
Dropping the high order bit, we get the Integer "1", which is the exactly same exactly same ID we have in the template; now we know which fields should be
ID we have in the template, so now we know which fields are here. processed.
The first field in the template is the string with a default value. Because the The first field in the template is a string with a default value. Because the
field uses the Default operator, we need to check if the value is in the data field uses the Default operator, we need to check if the value is in the data
or we should use the default value. The bit in the Presence Map for this field or we should use the default value. The bit in the Presence Map for this field
is `1` meaning the value for the string is in the incoming data and we should is `1` meaning the value for the string is in the incoming data and we should
@ -69,7 +75,7 @@ letter in the ASCII table. The sequence is `100_1000` (72), `110_0101` (101),
`110_1100` (108), `110_1100` (108), `100_1111` (79), `101_0111` (87), `110_1100` (108), `110_1100` (108), `100_1111` (79), `101_0111` (87),
`110_1111` (79), `111_0010` (114), `110_1100` (108) and `110_0100` (100). `110_1111` (79), `111_0010` (114), `110_1100` (108) and `110_0100` (100).
Notice that we consumed all the bytes, and the last one have the stop, so Notice that we consumed all the bytes, and the last one have the stop, so
that's the end of string. Converting the bytes using the ASCII string, we get that's the end of string. Converting the bytes using the ASCII table, we get
"HelloWorld". "HelloWorld".
So, there we have it: We received a record of the "HelloWorld" type, with the So, there we have it: We received a record of the "HelloWorld" type, with the
@ -119,7 +125,10 @@ list of users and their IDs.
1100_0000 0101_0101 0111_0011 0110_0101 1100_0000 0101_0101 0111_0011 0110_0101
0111_0010 1011_0001 1000_0100 1000_0000 0111_0010 1011_0001 1000_0100 1000_0000
0101_0101 0111_0011 0110_0101 0111_0010 0101_0101 0111_0011 0110_0101 0111_0010
1011_0010 1011_0010 1111_1111 1000_0001 1100_0000
0101_0101 1011_0001 1111_1111 0000_1000
1000_0000 1000_0010 1100_0000 1100_1001
1011_0110 1000_0000 0100_1101 1110_0101
``` ```
## Processing ## Processing
@ -191,3 +200,38 @@ for the Presence Map, but for the "Username". The bytes for the field are
`0101_0101` (85), `0111_0011` (115), `0110_0101` (101), `0111_0010` (114) and `0101_0101` (85), `0111_0011` (115), `0110_0101` (101), `0111_0010` (114) and
`1011_0001` (50), which is "User2". `1011_0001` (50), which is "User2".
This second record have an empty presence map (`1000_0000`) meaning that the ID
is not present in the incoming data. Because the field has the Increment
operator, we should use the previous value -- 3 -- and increment by 1. So
"User2" have the ID 4.
That ends the "InnerSequence" for the first record of "OuterSequence". Going
faster now:
- `1111_1111`: The second "GroupID" (only one byte due the stop bit), which is
127.
- `1000_0001`: The length of "InnerSequence"; it is just 1 element.
- `1100_0000`: The presence map for the first record of "InnerSequence"; it
means the "ID" is present.
- `0101_0101`, `1011_0001`: The username. "U1".
- `1111_1111`: The "ID" for user "U1" is 126 (it reads as 127, but because the
field is optional, we decrement the value by 1).
- `0000_1000`, `1000_0000`: The third "GroupID". Removing the stop bit and
joining the bits we have `1000_0000_0000` which is 2048.
- `1000_0010`: Length of the "InnerSequence" in the 3rd group; 2 elements.
- `1100_0000`: Presence Map of the first record of "InnerSequence"; ID is
present.
- `1100_1001`: Username. "I".
- `1011_0110`: The "ID" for user "I". 53.
- `1000_0000`: Presence Map for the second record of "InnerSequence"; ID is not
present.
- `0100_1101`, `1110_0101`: Username. "Me".
- Not reading any bytes now 'cause the Presence Map pointed that the "ID" is
not present, but because the previous value was 53, the ID for username "Me"
is 54.
---
Changelog:
- 2022-01-12: First release.

139
content/research/decoding-fast-examples.pt.md

@ -0,0 +1,139 @@
+++
title = "Decodificando o Protocolo FAST: Exemplos"
date = 2022-01-12
draft = true
[taxonomies]
tags = ["finanças", "binário", "protocolo", "fix", "fast", "exemplos"]
+++
Depois de toda a explicação sobre a definição do protocolo FAST, eu notei que
tinha uma coisa faltando: Exemplos, para que fique mais fácil de entender.
<!-- more -->
{% note() %}
Mesmo aviso do post anterior: Como isso tudo é baseado na minha experiência
pessoal, algumas coisas podem estar erradas. Eu tentei o meu melhor para deixar
tudo correto, mas eu posso ter entendido alguma coisa errada, ou digitei errado
aqui.
{% end %}
# Hello World
Este exemplo é basicamente o mesmo da
[JetTek](https://jettekfix.com/education/fix-fast-tutorial/) mas é realmente
simples de explicar, então vamos nós:
## Template
```xml
<?xml version="1.0" encoding="UTF-8"?>
<templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1">
<template xmlns="http://www.fixprotocol.org/ns/fast/td/1.1" name="HelloWorld" id="1">
<string name="String" id="1">
<default value=""/>
</string>
</template>
</templates>
```
## Dados de Entrada
Bytes:
```
1110_0000 1000_0001 0100_1000 0110_0101
0110_1100 0110_1100 0100_1111 0101_0111
0110_1111 0111_0010 0110_1100 1110_0100
```
## Processamento
O primeiro byte é o Mapa de Presença. Removendo o bit de parada, temos
`110_0000`. Esse Mapa de Presença tem um campo que não é descrito no template:
O ID do Template. Como o primeiro bit está ligado, nós sabemos que o ID está
lá. Ainda, tenha em mente que o ID do Template é o único campo que nós sabemos
que existe até agora; não existe nenhuma outra informação sobre o que é aquele
segundo bit no Mapa de Presença -- nós precisamos encontrar qual template vamos
usar antes de mais nada.
O próximo byte é lido: `1000_0001`. Como mencionado acima, isso é o ID do
Template. Sendo um inteiro sem sinal (e provavelmente mandatório, mas não me
pergunte como isso funciona) e removendo o bit de parada, temos o inteiro "1",
que é exatamente o mesmo ID que temos no nosso template; agora nós sabemos
quais campos devem ser processados.
O primeiro campo do template é uma string com um valor default. Como o campo
usa o operador Default, nós precisamos verificar se o valor está presente nos
dados de entrada ou se devemos usar esse valor default. O bit no Mapa de
Presença para este campo é `1`, o que indica que a string está presente nos
dados de entrada e que nós devemos lê-la.
O campo é uma string, então vamos ler todos os bytes até encontrarmos um com o
bit de parada. Ainda, sendo string, nós não precisamos "juntar" os bits: cada
byte é uma letra da tabela ASCIII. A sequência é `100_10000` (72), `110_0101`
(101), `110_1100` (108), `110_1100` (108), `100_1111` (79), `101_0111` (87),
`110_1111` (79), `111_0010` (114), `110_1100` (108) e `110_0100` (100). Observe
que nós consumimos todos os bites e o último tinha o bit de parada, então
terminamos o pacote com a string. Convertendo os bytes usando a tabela ASCII,
temos "HelloWorld".
Assim, temos o resultado: Nós recebemos um registro do tipo "HelloWorld" cujo
campo com ID "1" (chamado "String") tem o valor "HelloWorld".
# Sequências
Vamos expandir nosso exemplo adicionando uma sequência e alguns operadores:
## Template
```xml
<?xml version="1.0" encoding="UTF-8"?>
<templates xmlns="http://www.fixprotocol.org/ns/fast/td/1.1">
<template xmlns="http://www.fixprotocol.org/ns/fast/td/1.1" name="HelloWorld" id="1">
<string name="String" id="1">
<default value=""/>
</string>
</template>
<template xmlns="http://www.fixprotocol.org/ns/fast/td/1.1" name="SequenceOfSequences" id="2">
<sequence name="OuterSequence">
<length name="NoOuterSequence" id="3"/>
<uInt32 name="GroupID" id="2"/>
<sequence name="InnerSequence">
<length name="NoInnerSequence" id="25"/>
<string name="Username" id="4"/>
<uInt32 name="ID" id="32" presence="optional">
<increment/>
</uInt32>
</sequence>
</sequence>
</template>
</templates>
```
Apesar do FAST ser criado para trabalhar com FIX e o mercado financeiro, não
existe nada que iniba o mesmo de ser usado para outras coisas. O novo template
descreve um group de usuários, então nós temos uma lista de grupos e, para cada
grupo, uma lista de usuários e seus IDs.
## Dados de Entrada
```
1100_0000 1000_0010 1000_0011 0000_0011
0010_0011 0001_1000 1110_0111 1000_0010
1100_0000 0101_0101 0111_0011 0110_0101
0111_0010 1011_0001 1000_0100 1000_0000
0101_0101 0111_0011 0110_0101 0111_0010
1011_0010 1111_1111 1000_0001 1100_0000
0101_0101 1011_0001 1111_1111 0000_1000
1000_0000 1000_0010 1100_0000 1100_1001
1011_0110 1000_0000 0100_1101 1110_0101
```
## Processamento
<!--
vim:spelllang=pt:
-->

5
content/research/decoding-fast.md

@ -587,6 +587,5 @@ mandatory sequences.
### Changelog: ### Changelog:
2022-01-10: First release. - 2022-01-10: First release.
- 2022-01-10: Added information about the template versioning.
2022-01-10: Added information about the template versioning.

5
content/research/decoding-fast.pt.md

@ -600,9 +600,8 @@ sequências mandatórias e opcionais.
Changelog: Changelog:
2022-01-10: Primeira versão. - 2022-01-10: Primeira versão.
- 2022-01-10: Adicionada informações sobre o versionamento de templates.
2022-01-10: Adicionada informações sobre o versionamento de templates.
<!-- <!--
vim:spelllang=pt: vim:spelllang=pt:

Loading…
Cancel
Save