In previous posts we looked at creating market orders and limit orders with {binance}
. We saw a couple of successful trades. However, sometimes trades are not successful and the orders are not filled. Let’s try to understand why.
The setup will be the same as the previous posts and we’ll use the Binance Testnet. Let’s take a look at our Testnet account balance.
spot_account_balances()
# A tibble: 8 × 3
asset free locked
<chr> <dbl> <dbl>
1 BNB 971. 0
2 BTC 1.41 0
3 BUSD 37438. 116.
4 ETH 89.3 0
5 LTC 500 0
6 TRX 498722. 0
7 USDT 10111. 0
8 XRP 50000 0
Expired Orders
We’ve got plenty of TRX. Let’s try to sell 5000 TRX in exchange for USDT.
spot_new_market_order(symbol = "TRXUSDT", side = "SELL", quantity = 5000)
# A tibble: 1 × 11
symbol order_id transact_time price orig_qty exec_qty status time_in_force type side
<chr> <int> <dttm> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 TRXUSDT 650 2021-11-07 07:11:42 0 5000 0 EXPIRED GTC MARKET SELL
The order was not successful (status is EXPIRED
). What went wrong? It’s not like we don’t have enough TRX. The problem is that there’s nobody who wants to buy our TRX with USDT! A successful trade requires two parties: a seller and a buyer.
Order Book
The order book reflects the orders which are waiting to be executed. Let’s retrieve the order book for all pairs on the Testnet.
order_book <- market_price_ticker() %>% pull(symbol) %>% market_order_book()
# A tibble: 20 × 4
symbol last_update_id bids asks
<chr> <int> <list> <list>
1 BNBBUSD 3 <tibble [1 × 2]> <tibble [0 × 2]>
2 BTCBUSD 66 <tibble [1 × 2]> <tibble [1 × 2]>
3 ETHBUSD 4 <tibble [1 × 2]> <tibble [0 × 2]>
4 LTCBUSD 2 <tibble [0 × 2]> <tibble [0 × 2]>
5 TRXBUSD 40 <tibble [1 × 2]> <tibble [0 × 2]>
6 XRPBUSD 2 <tibble [0 × 2]> <tibble [0 × 2]>
7 BNBUSDT 432661 <tibble [15 × 2]> <tibble [3 × 2]>
8 BTCUSDT 634251 <tibble [44 × 2]> <tibble [20 × 2]>
9 ETHUSDT 2352 <tibble [9 × 2]> <tibble [10 × 2]>
10 LTCUSDT 8 <tibble [0 × 2]> <tibble [0 × 2]>
11 TRXUSDT 50 <tibble [0 × 2]> <tibble [0 × 2]>
12 XRPUSDT 18 <tibble [0 × 2]> <tibble [0 × 2]>
13 BNBBTC 8 <tibble [1 × 2]> <tibble [0 × 2]>
14 ETHBTC 22 <tibble [1 × 2]> <tibble [0 × 2]>
15 LTCBTC 2 <tibble [0 × 2]> <tibble [0 × 2]>
16 TRXBTC 2 <tibble [0 × 2]> <tibble [0 × 2]>
17 XRPBTC 3 <tibble [0 × 2]> <tibble [0 × 2]>
18 LTCBNB 2 <tibble [0 × 2]> <tibble [0 × 2]>
19 TRXBNB 2 <tibble [0 × 2]> <tibble [0 × 2]>
20 XRPBNB 2 <tibble [0 × 2]> <tibble [0 × 2]>
The asks are orders from sellers (these orders specify the price they are asking) and the bids are orders from buyers (these orders specify the price that they are bidding). Interesting! There are a few pairs (like BNB/USDT, BTC/USDT and ETH/USDT) where there is a lot of interest in trading. But other pairs have only a few orders (or none at all!).
Let’s take a closer look at the order book for TRX/USDT and TRX/BUSD.
order_book %>%
filter(symbol %in% c("TRXUSDT", "TRXBUSD")) %>%
select(-last_update_id) %>%
pivot_longer(bids:asks, names_to = "type", values_to = "orders") %>%
unnest(cols = c(orders))
# A tibble: 4 × 4
symbol type price qty
<chr> <chr> <dbl> <dbl>
1 TRXBUSD bids 0.15 773.1
2 TRXBUSD bids 0.14 167
3 TRXUSDT asks 0.1 336429.
4 TRXUSDT asks 0.102 2000
There are just bids for TRX/BUSD and only asks for TRX/USDT. This means that there’s nobody interested in buying our TRX for USDT, but there is interest in buying TRX for BUSD.
Filling Orders
Let’s change our order then, offering to sell 200 TRX for BUSD at the highest bid price.
spot_new_limit_order(symbol = "TRXBUSD", side = "SELL", quantity = 200, price = 0.15)
# A tibble: 1 × 11
symbol order_id transact_time price orig_qty exec_qty status time_in_force type side
<chr> <int> <dttm> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 TRXBUSD 189 2021-11-07 07:41:13 0.15 200 200 FILLED GTC LIMIT SELL
Our order was successful (status
is FILLED
). Checking back on the order book we see that the quantity of the bid has dropped from 773.1 TRX to 573.1 TRX because we sold them 200 TRX.
# A tibble: 2 × 4
symbol type price qty
<chr> <chr> <dbl> <dbl>
1 TRXBUSD bids 0.15 573.1
2 TRXBUSD bids 0.14 167
Partially Filling Orders
The previous order was filled completely, meaning that we managed to sell the full quantity that we offered. But what happens if the order can’t be completed fully?
Somebody still wants to buy another 573.1 TRX at a price of 0.15 BUSD per TRX. What happens if we offer to sell a larger amount at that price?
spot_new_limit_order(symbol = "TRXBUSD", side = "SELL", quantity = 1000, price = 0.15)
# A tibble: 1 × 11
symbol order_id transact_time price orig_qty exec_qty status time_in_force type side
<chr> <int> <dttm> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 TRXBUSD 190 2021-11-07 07:44:36 0.15 1000 573.1 PARTIALLY_FILLED GTC LIMIT SELL
Aha! Now the status is PARTIALLY_FILLED
. The original quantity for the order (orig_qty
) was 1000 TRX but only 573.1 TRX of that has been executed (exec_qty
).
Time in Force
We can be more specific about the way that we want our order to be handled using the time_in_force
option. This specifies how long the order is valid and dictates what happens when there are no matching orders in the order book. Possible values for time_in_force
are:
"GTC"
— (Good Til Canceled) order will remain on the book unless canceled;"IOC"
— (Immediate Or Cancel) try to fill as much as possible before it expires; or"FOK"
— (Fill Or Kill) Order will expire if full order cannot be filled.
Let’s look at the updated order book for TRX/BUSD.
# A tibble: 3 × 4
symbol type price qty
<chr> <chr> <dbl> <dbl>
1 TRXBUSD bids 0.13 1000
2 TRXBUSD asks 0.14 3000
3 TRXBUSD asks 0.15 5000
Somebody is offering to buy 1000 TRX at 0.13 BUSD per TRX. Let’s offer more TRX than they are requesting but specify "FOK"
for time_in_force
.
spot_new_limit_order(symbol = "TRXBUSD", side = "SELL", quantity = 5000, price = 0.13, time_in_force = "FOK")
# A tibble: 1 × 11
symbol order_id transact_time price orig_qty exec_qty status time_in_force type side
<chr> <int> <dttm> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 TRXBUSD 208 2021-11-07 08:10:47 0.13 5000 0 EXPIRED FOK LIMIT SELL
The full order could not be filled (we offered 5000 TRX but there was only 1000 TRX requested), so it expired. The executed quantity (exec_qty
) is zero: no trading happened.
Let’s try again with time_in_force
set to "IOC"
.
spot_new_limit_order(symbol = "TRXBUSD", side = "SELL", quantity = 5000, price = 0.13, time_in_force = "IOC")
# A tibble: 1 × 11
symbol order_id transact_time price orig_qty exec_qty status time_in_force type side
<chr> <int> <dttm> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 TRXBUSD 209 2021-11-07 08:10:52 0.13 5000 1000 EXPIRED IOC LIMIT SELL
That order has also expired but now the executed quantity is 1000 TRX. We offered 5000 TRX, while only 1000 TRX was requested. Of the 5000 TRX, 1000 TRX was sold and the balance of our order (the remaining 4000 TRX) was cancelled.
Some time later there’s another 1000 TRX requested at the same price. Let’s try with time_in_force
set to "GTC"
.
spot_new_limit_order(symbol = "TRXBUSD", side = "SELL", quantity = 5000, price = 0.13, time_in_force = "GTC")
# A tibble: 1 × 11
symbol order_id transact_time price orig_qty exec_qty status time_in_force type side
<chr> <int> <dttm> <dbl> <dbl> <dbl> <chr> <chr> <chr> <chr>
1 TRXBUSD 211 2021-11-07 08:11:05 0.13 5000 1000 PARTIALLY_FILLED GTC LIMIT SELL
Aha! Now the status of the order is PARTIALLY_FILLED
. Again the executed quantity is 1000 TRX, meaning that we’ve sold the full quantity requested. However, now, because we specified "GTC"
, the balance of the order (another 4000 TRX) is still pending. The order persists on the books until either we cancel it or it is filled.