Pressão antes de o preço se mover
Um preço raramente se move sozinho; move-se porque ordens chegam e retiram liquidez. Olhar só os negócios perde boa parte da história, pois quase toda a ação são ordens colocadas e canceladas no topo do livro. O desequilíbrio do fluxo de ordens (OFI) resume cada atualização do melhor bid e ask em um número com sinal: positivo quando compradores adicionam ou vendedores recuam, negativo no caso oposto. Em horizontes curtos ele prevê notavelmente bem as próximas mudanças de preço.
def book_imbalance(bid_size, ask_size):
total = bid_size + ask_size
if total == 0:
return 0.0
return (bid_size - ask_size) / total
print(book_imbalance(450, 200)) # 0.3846 more size on the bid: upward pressure
print(book_imbalance(100, 400)) # -0.6 sellers dominate
print(book_imbalance(0, 0)) # 0.0 an empty top does not divide by zeroUma atualização, um número
Compare duas cotações sucessivas. No bid: se o preço do bid sobe ou se mantém, seu novo tamanho é somado; se cai ou se mantém, seu tamanho antigo é subtraído (com preço inalterado ambos se aplicam, então conta a variação de tamanho). No ask os sinais se invertem: um ask menor ou igual adiciona pressão vendedora (- novo tamanho ask), um maior ou igual remove a antiga (+ tamanho antigo ask). Os quatro termos são (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as + (a >= pa) * pas, onde cada comparação vale 1 ou 0.
# The order-flow imbalance of one quote update, tried on four changes of the top of the book
def ofi_event(prev, cur):
pb, pbs, pa, pas_ = prev
b, bs, a, as_ = cur
return (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as_ + (a >= pa) * pas_
q0 = (99.5, 300, 100.0, 200)
print(ofi_event(q0, (99.5, 450, 100.0, 200))) # 150 more size on the same bid
print(ofi_event(q0, (99.6, 100, 100.0, 200))) # 100 a higher bid: the whole new size counts
print(ofi_event(q0, (99.4, 300, 100.0, 200))) # -300 the bid price fell: the old size is gone
print(ofi_event(q0, (99.5, 300, 100.1, 200))) # 200 the ask retreated: less selling pressureUma série e o que ela explica
Aplicar a regra a cada par de cotações sucessivas dá uma série de OFI. Numa janela curta, como um segundo, some os eventos e compare com a variação do preço médio: a relação é quase linear, d_mid = slope * OFI. A inclinação diz quanto cada unidade de fluxo move o preço, e diminui quando o livro é profundo. Ajusta-se como uma reta de mínimos quadrados pela origem: sum(ofi * dmid) / sum(ofi ** 2).
# A series of events from consecutive quotes, set beside the change of the mid price
import numpy as np
def ofi_event(prev, cur):
pb, pbs, pa, pas_ = prev
b, bs, a, as_ = cur
return (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as_ + (a >= pa) * pas_
quotes = [(99.5, 300, 100.0, 200), (99.5, 450, 100.0, 200), (99.6, 100, 100.0, 150), (99.6, 100, 100.1, 400)]
events = np.array([ofi_event(prev, cur) for prev, cur in zip(quotes, quotes[1:])], dtype=float)
print(events) # [150. 150. 150.]
mid = np.array([(q[0] + q[2]) / 2 for q in quotes])
dmid = np.diff(mid)
print(np.round(dmid, 3)) # the mid moved in the direction of the flow# Recover the price impact of the flow with a slope through the origin
import numpy as np
def impact_slope(ofi, dmid):
return float(np.sum(ofi * dmid) / np.sum(ofi ** 2))
rng = np.random.default_rng(1)
flow = rng.normal(0, 200, size=500) # order-flow imbalance per second
price_change = 0.00005 * flow + rng.normal(0, 0.004, size=500) # the mid moves with the flow, plus noise
print(round(impact_slope(flow, price_change), 6)) # 5e-05, the true impact per unit of flow- O desequilíbrio do livro
(bid - ask) / (bid + ask)fica entre -1 e +1; proteja o caso vazio. - OFI de uma atualização:
(b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as + (a >= pa) * pas; uma série o aplica a cada par consecutivo. - As variações do preço médio são quase lineares no OFI:
slope = sum(ofi * dmid) / sum(ofi**2); é um sinal de curto horizonte, mais útil para execução.
A seguir: código assíncrono com asyncio, lidar com muitos fluxos de dados sem esperar por cada um.
Lab: o que é avaliado
- Comparar os dois lados com
book_imbalance25 pts - Pontuar uma atualização com
ofi_event25 pts - Acompanhar a pressão continuamente com
ofi_series25 pts - Precificar o fluxo com
impact_slope25 pts