This assignment is about simulation of a multi-period version of the Glosten/Milgrom model.

Part I. Setting a simulation for the first 50 trading rounds of the model.

The simulation in R is done through a function ‘run_sim’. The essence of the simulation is to simulate the order direction dt and to adjust the probability theta accordingly. For that reason a vector(or a coulumn in Excel)is simulated with dt. We also initialize the first step of the simulation with theta equal to .5, and first transaction price equal to .5x150+.5x100 = 125. After that theta is simulated as it depends on the previous theta and the pi parameter(which indicates the proportion of informed traders). Then the bid and ask spreads are calculated based on the previous transaction price pt-1 and thetea t-1. The current transction price is the expected value given the probabilities thetea. Going forth we can run the simulation for as many periods as we want.

run_sim <- function(theta_0, Pi, v_h, v_l, n){
    d_t <- rep(0,n)
    theta_t <- rep(0,n); theta_t[1] <- theta_0
    p_t <- rep(0,n); p_t[1] <- theta_0*v_h + (1-theta_0)*v_l
    bid_t <- rep(0,n); bid_t[1] <- p_t[1] - Pi*.5*(v_h - v_l)
    ask_t <- rep(0,n); ask_t[1] <- p_t[1] + Pi*.5*(v_h - v_l)
    for (i in 1:n){
        if (runif(1) < Pi + (1-Pi)*.5 ) {d_t[i] <- 1}
        else {d_t[i] <- -1}
    }
    for (i in 2:n){
        if (d_t[i]==1) {theta_t[i] <- ((1+Pi)*theta_t[i-1])/(2*Pi*theta_t[i-1] + (1-Pi)) }
        else { theta_t[i] <- ((1-Pi)*theta_t[i-1])/(2*Pi*(1-theta_t[i-1]) + (1-Pi))}
    }
    for (i in 2:n){
        p_t[i] <- theta_t[i]*v_h + (1-theta_t[i])*v_l
    }
    for (i in 2:n){
        bid_t[i] <- p_t[i-1] - (Pi*theta_t[i-1]*(1-theta_t[i-1])*(v_h-  v_l))/(Pi*(1-theta_t[i-1])+(1-Pi)*.5)
    }
    for (i in 2:n){
        ask_t[i] <- p_t[i-1] + (Pi*theta_t[i-1]*(1-theta_t[i-1])*(v_h-v_l))/(Pi*(theta_t[i-1])+(1-Pi)*.5)
    }
    relative_spread_t <- (ask_t-bid_t)/((ask_t+bid_t)*.5)
    pricing_error_t <- (v_h-p_t)/p_t
    result <- data.frame(d_t,theta_t,bid_t,ask_t,p_t,relative_spread_t,pricing_error_t)
    result
}

#a function for plotting the bid-ask spread
myplot1 <- function(simulation, Title){
    plot(simulation[,5],type="S",col="red",lwd=4,main=Title,xlab ="", ylab = "" )
    points(simulation[,4],col="green",lwd=1.1,bg="black",pch=16)
    points(simulation[,3],col="blue",lwd=1.1,pch=16)
    legend( x="bottomright", 
        legend=c("transaction price","bid","ask"),
        col=c("red","blue","green"), lwd=1, lty=c(1,2), 
        pch=c(15,17) ,cex=.6)
}

An example of the first rows of the simulation is given below:

sim1 <- run_sim(.5,.1,150,100,50); head(sim1)
##   d_t theta_t bid_t    ask_t   p_t relative_spread_t pricing_error_t
## 1   1    0.50 122.5 127.5000 125.0        0.04000000       0.2000000
## 2   1    0.55 122.5 127.5000 127.5        0.04000000       0.1764706
## 3  -1    0.50 125.0 129.9505 125.0        0.03883495       0.2000000
## 4   1    0.55 122.5 127.5000 127.5        0.04000000       0.1764706
## 5  -1    0.50 125.0 129.9505 125.0        0.03883495       0.2000000
## 6   1    0.55 122.5 127.5000 127.5        0.04000000       0.1764706

From the these rows it can be seen that if the dt = 1,i.e. we have a buy order the transaction price is equal to the ask price, and the reverse if dt = -1, i.e. a sell order the transaction price is equal to the bid price. That is consitent with the model, since it is build on this assumption.

Plotting some examples, and explanations

Plotting two examples with pi equal to .2 nad .7.

set.seed(123)
#sim1 <- run_sim(.5,.1,150,100,50);myplot1(sim1,"simulation with pi = .1")
sim2 <-run_sim(.5,.2,150,100,50);myplot1(sim2,"simulation with pi = .2")

From the graph above can be seen that with only 20% ‘informed traders’, the price eventually coverges to the ‘true’ value, but it takes a relatively long time. Also it can be observed that the bid-ask spread also declines in line with our expectations of the model.

Conversy, if the ‘informed traders’ are relatively large part of the market(70%), the price converges very quickly to the ‘true’ value of the security. The bid-ask price also collapses fast. Again, that is what we should expect from the model.

Part II. Computing the realtive bid-ask spread in percentage terms and the pricing error.

Acttually, in the first function ‘rum_sim’ the relative bid-ask spread and the error are already computed. In order to run 10 simulation and average across the a new function is created which does just that. The output of the function is two vectors with the average relative spread and the error term. It can then easily be plotted.

sim_average <- function(theta_0, Pi, v_h, v_l, n, nr_sim){
    averageError <- rep(0,n)
    averageRelativeSpread <- rep(0,n)
    for (i in 1:nr_sim){
        if (i==1){temp <- run_sim(theta_0, Pi, v_h, v_l, n)
            averageError<-temp[,7]
            averageRelativeSpread <- temp[,6]}
        else { temp <- run_sim(theta_0, Pi, v_h, v_l, n)
                averageError <- cbind(averageError,temp[,7])
                averageRelativeSpread <- cbind(averageRelativeSpread,temp[,6])
            
        }
        
    }
    averageError <- apply(averageError,1,mean)
    averageRelativeSpread <- apply(averageRelativeSpread,1,mean)
    cbind(averageRelativeSpread,averageError)
}


#plotting function for the part 2 of the assignment

myplot2 <- function(simulation, Title){
    plot(simulation[,2],col="blue",xlab = "",ylab="",type="l",ylim=c(0,.3),main=Title)
    lines(simulation[,1],col="red",type="l")

    legend( x="topright", 
        legend=c("average relative spread","average pricing error"),
        col=c("red","blue"), lwd=1, lty=c(1,2), 
        pch=c(15,17) ,cex=.6)
}

Once more the function ‘sim_average’ runs a loop of 10 times the first function and then averages across each round of trading. The results are protted below:

set.seed(123)
par(mfrow=c(1,2))
sim01<-sim_average(.5,.01,150,100,50,10); myplot2(sim01,"simulation with pi = .01")
sim02<-sim_average(.5,.2,150,100,50,10); myplot2(sim02,"simulation with pi = .2")

par(mfrow=c(1,2))
sim05 <- sim_average(.5,.5,150,100,50,10); myplot2(sim05,"simulation with pi = .5")
sim08 <- sim_average(.5,.8,150,100,50,10); myplot2(sim08,"simulation with pi = .8")

sim099 <- sim_average(.5,.8,150,100,50,10); myplot2(sim099,"simulation with pi = .99")

The picture clearly shows the main aspects of our model. Specifically, when there are no informed traders (pi=.01, the first graph), the price discovery is almost non-existent. it can be seen that the error term stays the same throughout the period. If we increase the nomber of the ‘informed traders’ to pi=.2(second graph), the pricing error and relative spread eventually decreases, but only gradually. On the other hand we see that when pi = .5, .8 and .99, both measures decline rapidly, signaling quick price discovery.