{binance} Spot Trading: Limit Orders

In the previous post we looked at creating market orders on Binance using the {binance} package. Today we’re going to dig into limit orders.

Market Orders & Limit Orders

What’s the difference between a market order and a limit order? I’m so glad you asked.

In the BTC/USDT chart below the current (or “market”) price is 62110.01. This means that at present 1 BTC costs 62110.01 USDT. The market price is driven by supply and demand. If demand is high (or supply is low) then the market price generally goes up. Conversely, if demand is low (or supply is high) then the market price will usually go down.

A market order is a request to buy or sell an asset at the current market price. A market order will normally be executed immediately. If you order 1 BTC at the market price then this order should immediately by filled at the market price. 🧯 Note: It is not guaranteed to be filled immediately. That depends on liquidity (which we’ll cover in the next post), but in an active market you can be fairly certain that a market order will be filled.

But what if you want to sell at a price higher than the market price? Or buy at a price lower than the market price? Well, then you should make a limit order. With a limit order you specify both the quantity of the asset that you want to buy or sell as well as the desired price. For example, you might make a limit order to buy 1 BTC for 60000 USDT (below the market price) or sell 1 BTC at 65000 USDT (above the market price).

Setup

The setup will be the same as the previous post.

library(binance)

packageVersion("binance")
[1] ‘0.0.4’

We’ll be transacting on the Binance Testnet.

Placing a Limit Order

We’re going to trade ETH/BUSD. First we’ll check on the market price.

market_price_ticker("ETHBUSD")
# A tibble: 1 × 2
  symbol  price
  <chr>   <dbl>
1 ETHBUSD 4379.

Suppose we have some ETH and we want to sell at a price of 4400 BUSD per ETH (above the market price).

spot_new_limit_order(symbol = "ETHBUSD", side = "SELL", quantity = 1, price = 4400)
# A tibble: 1 × 11
  symbol  order_id transact_time       price orig_qty exec_qty status time_in_force type  side  fills           
  <chr>      <int> <dttm>              <dbl>    <dbl>    <dbl> <chr>  <chr>         <chr> <chr> <list>          
1 ETHBUSD      399 2021-11-05 05:05:13  4400        1        0 NEW    GTC           LIMIT SELL  <tibble [0 × 0]>

The status of this order is NEW and it has not been filled (not even partially). Let’s check the order book (this list of unfilled orders).

market_order_book("ETHBUSD", "sell")
# A tibble: 3 × 3
  symbol  price   qty
  <chr>   <dbl> <dbl>
2 ETHBUSD 4390      2
3 ETHBUSD 4400      1

There are 2 ETH on offer at a price of 4390 BUSD and our 1 ETH on offer at a price of 4400 BUSD. Our order will not be filled until the market price of ETH shifts up to 4400 BUSD.

Use the spot_open_orders() function to list our open orders.

spot_open_orders("ETHBUSD")
# A tibble: 3 × 15
  symbol  order_id price orig_qty executed_qty status time_in_force type  side  time
  <chr>      <int> <dbl>    <dbl>        <dbl> <chr>  <chr>         <chr> <chr> <dttm>
3 ETHBUSD      399 4400         1           0  NEW    GTC           LIMIT SELL  2021-11-05 05:05:13

If we are patient then the market price will hopefully move in our direction.

Some time later the order at 4390 BUSD has been filled and our order has been partially filled. This is what the order book looks like:

# A tibble: 1 × 3
  symbol  price   qty
  <chr>   <dbl> <dbl>
1 ETHBUSD  4400  0.75

Let’s check in on our order using spot_order_query().

# A tibble: 1 × 15
  symbol  order_id price orig_qty executed_qty status           time_in_force type  side  update_time
  <chr>      <int> <dbl>    <dbl>        <dbl> <chr>            <chr>         <chr> <chr> <dttm>
1 ETHBUSD      399  4400        1         0.25 PARTIALLY_FILLED GTC           LIMIT SELL  2021-11-05 05:45:58

The status is PARTIALLY_FILLED because we have not yet sold the full amount we have on offer. The original quantity (orig_qty) is 1 ETH, of which 0.25 ETH has been filled (the executed quantity, executed_qty).

A little later still and the order book is empty. We’ll take one last look at our order.

# A tibble: 1 × 15
  symbol  order_id price orig_qty executed_qty status time_in_force type  side  update_time
  <chr>      <int> <dbl>    <dbl>        <dbl> <chr>  <chr>         <chr> <chr> <dttm>
1 ETHBUSD      399  4400        1            1 FILLED GTC           LIMIT SELL  2021-11-05 05:46:57

The executed quantity is now 1 ETH and the status is FILLED.

Cancelling a Limit Order

What if you want to cancel a limit order?

Let’s place another order.

spot_new_limit_order(symbol = "ETHBUSD", side = "SELL", quantity = 5, price = 4400)
# A tibble: 1 × 11
  symbol  order_id transact_time       price orig_qty exec_qty status time_in_force type  side  fills           
  <chr>      <int> <dttm>              <dbl>    <dbl>    <dbl> <chr>  <chr>         <chr> <chr> <list>          
1 ETHBUSD      409 2021-11-05 06:18:39  4400        5        0 NEW    GTC           LIMIT SELL  <tibble [0 × 0]>

Use spot_order_cancel() to cancel the order, using the order_id field to identify the order.

spot_order_cancel("ETHBUSD", 409)
# A tibble: 1 × 10
  symbol  order_id price orig_qty executed_qty status   time_in_force type  side 
  <chr>      <int> <dbl>    <dbl>        <dbl> <chr>    <chr>         <chr> <chr>
1 ETHBUSD      409  4400        5            0 CANCELED GTC           LIMIT SELL 

Order Book

Let’s take a closer look at the order book. To make things more interesting though, we’ll flip over to the Binance Mainnet. Here’s a summary of the orders for a number of symbols. Only the top 100 orders (where “top” means closest to the market price) are listed.

# A tibble: 20 × 4
   symbol  last_update_id bids               asks              
   <chr>            <dbl> <list>             <list>            
 1 BNBBUSD     1766249387 <tibble [100 × 2]> <tibble [100 × 2]>
 2 BTCBUSD     6911574714 <tibble [100 × 2]> <tibble [100 × 2]>
 3 ETHBUSD     6368992102 <tibble [100 × 2]> <tibble [100 × 2]>
 4 LTCBUSD      756494068 <tibble [100 × 2]> <tibble [100 × 2]>
 5 TRXBUSD      673935674 <tibble [100 × 2]> <tibble [100 × 2]>
 6 XRPBUSD     1124317491 <tibble [100 × 2]> <tibble [100 × 2]>
 7 BNBUSDT     5911544226 <tibble [100 × 2]> <tibble [100 × 2]>
 8 BTCUSDT    14807883947 <tibble [100 × 2]> <tibble [100 × 2]>
 9 ETHUSDT    12256395023 <tibble [100 × 2]> <tibble [100 × 2]>
10 LTCUSDT     4601015676 <tibble [100 × 2]> <tibble [100 × 2]>
11 TRXUSDT     2655288332 <tibble [100 × 2]> <tibble [100 × 2]>
12 XRPUSDT     6576014338 <tibble [100 × 2]> <tibble [100 × 2]>
13 BNBBTC      2303506040 <tibble [100 × 2]> <tibble [100 × 2]>
14 ETHBTC      4424485089 <tibble [100 × 2]> <tibble [100 × 2]>
15 LTCBTC      1487088647 <tibble [100 × 2]> <tibble [100 × 2]>
16 TRXBTC       719114972 <tibble [100 × 2]> <tibble [100 × 2]>
17 XRPBTC      1507425977 <tibble [100 × 2]> <tibble [100 × 2]>
18 LTCBNB       290913789 <tibble [100 × 2]> <tibble [100 × 2]>
19 TRXBNB       269802601 <tibble [100 × 2]> <tibble [100 × 2]>
20 XRPBNB       317863766 <tibble [100 × 2]> <tibble [100 × 2]>

We’ll focus on the orders for ETH/BUSD.

market_price_ticker("ETHBUSD")

order_book <- market_order_book("ETHBUSD", limit = 500) %>%
  select(-last_update_id) %>%
  pivot_longer(cols = -symbol, names_to = "side") %>%
  unnest(cols = value)
# A tibble: 1,000 × 4
   symbol  side    price    qty
   <chr>   <chr>   <dbl>  <dbl>
 1 ETHBUSD bids  4548.34 5.2595
 2 ETHBUSD bids  4548.14 0.8011
 3 ETHBUSD bids  4548.13 1.75  
 4 ETHBUSD bids  4548.04 0.1912
 5 ETHBUSD bids  4548.01 0.0985
 6 ETHBUSD bids  4548    0.4516
 7 ETHBUSD bids  4547.81 0.1804
 8 ETHBUSD bids  4547.76 0.0194
 9 ETHBUSD bids  4547.75 0.0022
10 ETHBUSD bids  4547.74 0.0022
# … with 990 more rows

All those orders are easier to digest as a figure. The histogram below indicates the number of ETH/BUSD orders as a function of price. The market price is given by the vertical dashed line.

Histogram of ETH/BUSD order book.

Using a plot like this it’s possible to see where the interests of other traders lie.

Conclusion

In this post we’ve used the following functions from {binance} to explore limit orders:

  • market_price_ticker() — retrieve market price for specific pair
  • market_order_book() — retrieve pending orders for specific pair
  • spot_new_limit_order() — create a new limit order
  • spot_open_orders() — list open orders
  • spot_order_query() — query an order and
  • spot_order_cancel() — cancel an order.