Mid price is so noisy so I try to use the weighted price, which is much better. However I want to define a better price called weighted price

My questions are:

  1. How can I get a good weighted price

  2. How to judge the weighted-price. How can I define an indicator to judge whether the weighted price is good or bad?

  • $\begingroup$ The best approach depends on your objective. What are you trying to use the microprice for? $\endgroup$ – Jase Apr 27 at 7:50
  • $\begingroup$ There's nothing wrong with being discrete.. You gotta be very careful to concretely distinguish what is actually important in practice vs what is theory/unnecessary niceties for your particular application. $\endgroup$ – Jase Apr 28 at 1:08
  • $\begingroup$ why did the original question change from micro price to weighted price? $\endgroup$ – develarist Apr 28 at 14:59
  • $\begingroup$ Please don’t edit your questions in such a way they become about something else. It’s confusing for others and invalidates existing answers and comments. $\endgroup$ – Bob Jansen May 13 at 10:43

Arriving at a good microprice is one of the main preoccupations in the HFT and short-term quantitative trading industry. No answer here will be competitive with these more sophisticated micropricing models.

However if you want something that gives decent predictions (but won't make money after slippage and fees), use either of these two, or some weighted combination of the two:

P = (best_bid_volume * best_ask_price + best_ask_volume * best_bid_price) / (best_bid_volume + best_ask_volume)

P = last_trade_price

I know you mentioned bid-ask bounce as a significant problem, but for most applications (and certainly for prediction), it isn't. The last traded price is highly suggestive of future deltas. If you actually measure this, you will see. Either of these will be significantly better than midprice.

Note that these predict deltas in the midprice, $ln(mid_{t+1}/mid_{t})$, which is often the most directly actionable in terms of market taking and therefore the most relevant for market taking strategies.

| improve this answer | |
  • $\begingroup$ i think you should be more interested in predicting "micro-returns" not micro-price. would the return simply be calculated as log(micro-price$_t$ / micro-price$_{t-1}$) -1 ? $\endgroup$ – develarist Apr 27 at 11:33
  • $\begingroup$ you said earlier that "I use the mid price to calculate the return". so, once you do get a good micro price, would you calculate its return how i asked? $\endgroup$ – develarist Apr 27 at 17:34
  • $\begingroup$ @develarist I've updated my answer to briefly address the question of what it is that we're predicting $\endgroup$ – Jase Apr 28 at 1:07
  • $\begingroup$ @jimmychou123 To get a more predictive microprice than this requires significant R&D. Often the micropricing model will have several indicators that contribute. You won't find these in the academic literature. Join a HFT firm as a quantitative researcher in a delta one trading team if you want to find out. $\endgroup$ – Jase Apr 28 at 1:11
  • $\begingroup$ @jimmychou123 I can't give more info but you are on the right track. $\endgroup$ – Jase Apr 28 at 4:38

I found Lee & Mykland (2012, https://econpapers.repec.org/article/eeeeconom/v_3a168_3ay_3a2012_3ai_3a2_3ap_3a396-406.htm) to be a nice application for pre-averaging a noisy price process.

I will try and explain it not too rigorously so please correct me if I'm sloppy.

For the sake of completeness, fix a complete probability space $(\Omega , \mathcal{F}_t, \mathcal{P})$ where $\Omega$ is the set of events in a financial market, $\left \{ \mathcal{F}_t:t\in\left [ 0,T \right ] \right \}$ is the right-continuous information filtration for market participants, and $\mathcal{P}$ is a data-generating measure. So much for the theoretical foundation.

Now, assume that our price process is a random variable, e.g. \begin{align}dX_{t} = \sigma dW_{t}\end{align}

We have $X_t\in \mathbb {R}$ as our unobserved, true log price, $\sigma\in \mathbb {R}^+$ the volatility, and $W_t\in \mathbb {R}$ some $\mathcal{F}_t$-adapted Brownian Motion. This equation simply tells us that our observed price is moving randomly up and down within some corridor. In the original paper, this equation also includes a jump component, but since OP did not specifically ask about this, I omitted it.

Now, denote the observed, noisy price with noise component $\epsilon_t \in \mathbb {R} $ as \begin{align}P_{t} = X_{t} + \epsilon_t\end{align}

I.e., the true price is blurred by market microstructure noise, and we can't observe the true price. When dealing with tick data, all of our observations in the recorded time horizon $[0,T]$ lie in the grid $\mathcal{G}_n$: \begin{align}\mathcal{G}_n = \left \{0 = t_{n,0} < t_{n,1} < \cdots < t_{n,n} = T \right \} \end{align}

This may seem a little extensive, but it allows us to say that we observe trades whenever they occur, not only in regular periods like 1 second, 5 seconds, etc.

To approximate the true price, we need to make some assumptions about the noise process. In this case we assume that noise is stationary and with mean zero. We also assume that noise is $(k-1)$-dependent. In other words, only every $k$th observation is independent. Therefore, we subsample our observations on a reduced grid $\mathcal{G}_n^{k}$: \begin{align} \mathcal{G}_n^{k} = \left \{ t_n < t_{n,k} < t_{n,2k} < \cdots \right \} \end{align}

Denote the prices that were subsampled according to this grid as $\tilde{P}(t_{ik})$. To denoise this price, we take averages of $\tilde{P}(t_{ik})$ over some blocks of size $M \in N^+$. This part is a bit tricky, the authors of the paper gave data-driven recommendations based on simulations, so I will skip this part, but will include an example. The preprocessed price with (hopefully less microstructure noise) is \begin{align} \hat{P}(t_j) = \frac{1}{M}\sum_{i = \left \lfloor j/k\right \rfloor}^{\left \lfloor j/k\right \rfloor + M-1}\tilde{P}(t_{ik})\end{align}

Since this is all very theoretical, here's an example in R:

## install and load packages ##
libraries = c("data.table") # needed for shift function
lapply(libraries, function(x) if (!(x %in% installed.packages())) {install.packages(x)} )
invisible(lapply(libraries, library, quietly = TRUE, character.only = TRUE))
## ##

## Get data ##
P <- rnorm(100000, 100, 3)
P_tilde <- log(P)
## ##

## Determine k ##
# acf #
bacf <- acf(diff(P_tilde), plot = FALSE) # get ACF data
bacfdf <- with(bacf, data.frame(lag, acf))

# CI # https://stackoverflow.com/questions/42753017/adding-confidence-intervals-to-plotted-acf-in-ggplot2 #
alpha <- 0.90
conf.lims <- c(-1,1)*qnorm((1 + alpha)/2)/sqrt(bacf$n.used)
lag_outside_conf.lim <- sort(c(which(bacfdf$acf < conf.lims[1]), which(bacfdf$acf > conf.lims[2])))

# Specify k = maximum lag value + 1 #
k <- max(lag_outside_conf.lim) + 1 
# note that the choice of k is very important, so if you aren't dealing with a lot of data you may to this visually,
# also, there may be more advanced approaches for handling this #
## ##

# Get n #
n <- length(P_tilde)

# Get n-k #
n_diff <- n - k

# Vector with P_tilde_m+k values
P_tilde_shift <- shift(P_tilde, n = k, type = "lead")

## Calculate block size M ##
# Calculate q hat (this is from the paper, see table 5) #
q_hat <- sqrt(1/(2 * n_diff) * sum((P_tilde[1:n_diff] - P_tilde_shift[1:n_diff])^2)) # *100 for percentage value (but this will cause trouble in further calculations)

# Determine C w.r.t. q_hat #
C <- NaN
if (q_hat * 100 > 1) {C <- 1/8; print("Q_Hat is larger than 1. C defaulted to 1/8. Choose better value.")}
if (q_hat * 100 <= 1) C <- 1/8
if (q_hat * 100 <= (0.9 + 0.8)/2) C <- 1/9
if (q_hat * 100 <= (0.3 + 0.4)/2) C <- 1/16
if (q_hat * 100 <= (0.1 + 0.2)/2) C <- 1/18
if (q_hat * 100 <= (0.05 + 0.07)/2) C <- 1/19
if (q_hat * 100 < 0.01) print("Q_Hat is smaller than 0.01. C defaulted to 1/19. Choose better value.")

# Calculate M #
if (floor(C*sqrt(n/k)) == 0) {M <- 1
} else  {
  M <- floor(C*sqrt(n/k))}

# if testing different values for C #
C_vector <- c(1/8, 1/9, 1/16, 1/18, 1/19) 
M_vector <- floor(C_vector*sqrt(n/k))
M_vector <- unique(M_vector)

# Calculate P_hat_tj (first iteration) #
G_n_k <- seq(from = 0, to = n, by = k) # Grid for first subsampling
G_n_k[1] <- 1
P_tilde_t_ik <- P_tilde[G_n_k]
P_hat_tj <- array(dim = (length(G_n_k) - 1)) # preallocate

# Calculate P_hat_tj (second iteration) #
for (i in G_n_k) P_hat_tj[[i]] <- mean(P_tilde_t_ik[(floor(i/k)):(floor(i/k)+M-1)]) 
G_n_kM <- seq(from = 0, to = n, by = k*M) # Grid for second subsampling
G_n_kM[1] <- 1
P_hat_tj <- P_hat_tj[G_n_kM] # keep only those times t_j where they lie in the grid G_n_kM

I hope this kind of advertisement is allowed, but I implemented the full methodology of this paper here: https://github.com/QuantLet/SFM_Class_2019WS/tree/master/SFM_JumpsInCryptocurrencies/JumpDetectR

| improve this answer | |

For fixed income trading I acquired a single days worth of iSwap's bid-ask swap data, which is high quality constantly streamed prices of discrete book sizes.

I derived the three standard prices as measures for the mid:

  • Last traded.
  • Mid of Bid and Ask.
  • Weighted mid of bid and ask.

All three suffered from the problem of sporadic price jumps when new top level bid or asks were entered into the orderbook (whether it was a signifcant order by volume or not). This you could measure in terms of standard deviation of the absolute prices changes across timespans.

Instead I derived a model for the mid price dependent upon weighted bid-asks at different levels of the orderbook. You can see my answer here: definition of mid price in literature

| improve this answer | |
  • $\begingroup$ Did you look at the link? it gives an example of a model that uses different market depths to derive a weighted mid, then is better than the weighted mid taking only the top level depth. $\endgroup$ – Attack68 Apr 27 at 10:36
  • $\begingroup$ You asked what is a good metric to use to define a good price. The standard deviation provides a comparator between methods, it does not provide a way to adjust the price. $\endgroup$ – Attack68 Apr 27 at 10:45
  • $\begingroup$ If you had two instruments: apples priced at 1:2 and oranges priced at 5:7, you might say the mid prices are 1.5 and 6. What if there was also an apple/orange spread price at 4.5:5? You now your model is overspecified: 3 prices for 2 instruments: how to derive the mid for all products simultaneously. One way is is using minimum loss fucntion $\endgroup$ – Attack68 Apr 27 at 10:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.