knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

Introduction

To simulate the marketplace I assumed the market followed a continuous double auction mechanism. The double auction is the most widely used trading mechanism in financial markets around the world. Continuous double auction markets are characterised by the existence of a limit order book, which stores un-executed and partially filled orders. The limit order book has two sides: the bid side (for buy orders) and the ask side (for sell orders). The highest bid price available at any time is known as the best bid, and the lowest ask price listed in the book is the best ask price. The distance between best bid and best ask is known as the bid-ask spread.

Limit orders are created by market participants at random times throughout the day, with varying prices and sizes. A trade in the market is triggered when a participant submits a market order, indicating that they want to buy/sell a quantity at the best available price. If the quantity requested is larger than the volume available at the best price, the order “walks the book”, partially executing orders with progressively worse prices until the order is filled.

In the model implemented here, I assumed that if sufficient volume is unavailable when a market order is submitted, a market maker will intervene and match the order. That is, if the relevant order book is empty, the market maker will match the full order at a predetermined price. Also, if the orders available in the book are not enough to cover the submitted order, the existing orders are used to partially fill the order and the remained is covered by the market maker, again at a predetermined rate. This rate is 0.5% above/below the current price, depending on whether the order is to buy or sell.

Order Book Modelling

There are two main modelling approaches in the literature: agent based modelling and statistical modelling. In agent based modelling, the behaviour of individual types of market participants are implement in software, and are allowed to interact with other market agents to create an “artificial” market. The parameters of these models can be difficult to estimate, and typically involve large implementations/processing power.

The statistical approach assumes that the aggregate effects of the individual traders’ behaviours follow known distributions, and that a realistic order flow can be constructed using these quantities. As the parameters of the model are more transparent, and the implementation is less time consuming, a statistical model is implemented here.

The Model

The model used in this project is based on that presented in (Radivojevi’c et al. 2014), but extended to accommodate order cancellations, non-unit order sizes, and user-defined tick size/decimal prices. The model is itself an extension of earlier work by Farmer et al. (Smith et al. 2003; Daniels et al. 2003).

In the model, prices can assume a decimal price rounded to a defined tick size, up to a certain user-defined limit. Three types of order are allowed: market, limit and cancel limit. Limit orders can be bid or ask orders, with varying sizes. The order sizes are selected randomly from a list of feasible order sizes (for example, multiples of ten units, in the range 100 to 1,000 units). When a market order arrives it is filled either by the available orders in the appropriate order book, by the market maker, or by a combination of both.

To simulate random order arrivals, buy and sell limit orders are assumed to follow Poisson processes with rates $\lambda_b$ and $\lambda_a$ respectively. These orders are written to the order book until a corresponding market order arrives. Market orders to buy and sell arrive to the market with exponentially distributed waiting times defined by $\mu_b$ and $\mu_a$ respectively. If the appropriate side of the order book is empty, market orders are executed by the market maker

Limit ask orders are uniformly placed in price classes between one and n ticks away from the current best bid price, $p_b$. Conversely, limit bids are placed uniformly in classed from one to $n$ ticks below the current best ask price, $p_a$. The best bid is always less than the best ask. When $p_a$ is between $1$ and $n$ ticks ($p_b$ between $(N/ticks-n+1)$ and $N/ticks$, the bid (ask) interval is restricted correspondingly. For example, if $p_a=tick_size$, no bids are possible. If no orders are present in the book, the next bid and ask prices are set to be a random number of ticks away from the last traded price. To start the auction, the user only needs to supply a starting price and a tick size. The overall price generated by the market follows a continuous-time random walk.

For simplicity it is assumed that markets operate 24/7, and that market participants cannot edit order quantities or prices – they can only cancel orders entirely.

Implementation Overview

The below sections give a brief overview of the main function called in the code.

create_order_book()

This is the main “loop” of the simulation. An overall trade record and bid/ask limit order books are initialised. Orders are created randomly, and dealt with appropriately. Limit orders are added to the relevant books and best bid/offer prices are calculated. Market orders are filled, either by the available volume in the order books or by the market maker. Cancelled orders are removed from the books, and the overall market prices are recorded. The best bid and order prices are updated after every iteration of the loop.

The simulation runs until a predefined number of orders is created. The number of orders is a function of the overall number of trades expected per minute, and the desired time interval to simulate. For example, a one day simulation with 5 trades per minute will created $5 \times 1,440 = 7,200$ orders.

create_orders()

Order types and time stamps are created. Orders are created in proportions provided by the user (roulette wheel selection), and time stamps are exponentially distributed.

fill_orders()

Market orders are filled according to the limit order book. If no relevant orders exist, the market maker will fill the order. If sufficient volume exists in the limit order book, the order is filled from there. If multiple orders are used to fill the market order, the trade price is calculated as a weighted average of the corresponding limit orders, weighted by volume. Filled orders are removed from the limit order book, and partially filled orders are updated to reflect their new volume. The overall order record is also updated.

If orders exist in the book, but there is not enough volume to fill the order, the market maker will make up the deficit.

remove_and_update()

This function simply removes orders from the order book, either when they are filled or cancelled, and moves the remaining orders up to the vacant order positions.

Running The Code

To simulate an order book, the create_order_book() function is used. It takes as inputs the starting market price, the upper price limit and the tick size, as well as the arrival intensities of the various order types. The number of orders to produce is controlled using the n_events parameter.

The parameters can be specified manually, or by loading from the config.yml file.

# load package
library(marketsimulatr)

# select config
Sys.setenv("R_CONFIG_ACTIVE" = "test")

# current price
start_price <- config::get("start_price")
# upper limit on price
price_limit <- config::get("price_limit")
# number of ticks from price within which limit orders are placed
price_band <- config::get("price_band")
# minimum price increment
tick_size <- config::get("tick_size")
# buy orders per minute
market_buy <- config::get("market_buy")
# sell orders per minute
market_sell <- config::get("market_sell")
# ratio of bids to market sells
bid_order_ratio <- config::get("bid_order_ratio")
# ratio of asks to market buys
ask_order_ratio <- config::get("ask_order_ratio")
# proportion on limit bids cancelled
cancel_bid <- config::get("cancel_bid")
# proportion of limit asks cancelled
cancel_ask <- config::get("cancel_ask")
# days to simulate
days <- config::get("days")

Next, the total number of events to simulate is calculated:

# this gives us a rough figure for orders per minute (of all types)
total_orders <- ceiling(
  market_buy +
    market_sell +
    (market_buy * ask_order_ratio) +
    (market_sell * bid_order_ratio) +
    (market_buy * ask_order_ratio * cancel_ask) +
    (market_sell * bid_order_ratio * cancel_bid)
)

# number of minutes to simulate
n_minutes <- days * 1440 # days * number of minutes in one day

# number of orders to generate (number of minutes * number of orders per minute)
n_events <- n_minutes * total_orders

Finally, the create_order_book function is called. This will return a price series of traded prices, as well as the full order book. The ask and bid limit order books are also returned.

simulation_results <- marketsimulatr::create_order_book(
  start_price,
  price_limit,
  price_band,
  tick_size,
  market_sell,
  market_buy,
  bid_order_ratio,
  ask_order_ratio,
  cancel_bid,
  cancel_ask,
  n_events
)


norwegianblueparrot/marketsimulatr documentation built on Dec. 22, 2021, 3:13 a.m.