7 minute read

Korean Stock Exchange (KRX) is the only securities exchange in South Korea. Equities and ETPs get traded in Seoul while futures, options, and other derivatives get traded in Busan (hence, there exists an opportunity for latency arbitrage).

To gain a speed advantage, lots of firms place their trading engines near the matching engine, which is called co-location. A co-located trading engine receives its data via UDP as opposed to TCP which requires a handshake process that increases the latency.

Going through KRX data specification sheet is not an easy task. It contains information on all types of messages sent from the KRX matching engine. In this post, I will go over messages that are most frequently used but if you’re a data engineer at your company, I highly recommended that you peruse them.

Tradable Securities

KRX securities contain equities, futures, and options.

Equities can be largely divided into three markets: KOSPI, KOSDAQ, and KONEX.

In the Korean futures market, equity index futures exhibit the biggest volume: kospi200 futures and kosdaq150 futures. Equity futures are also traded in KRX but their volumes aren’t as consistent.

As opposed to other securities, options are least traded securities in KRX since there aren’t many options contracts to trade. There are option contracts for kospi200, kosdaq150 and mini kospi200. Unlike the US market, individual stock options aren’t available and are replaced by ELW.

IP address and port number

Each data gets received from differnet ip address and ports. For instance, messages containing kospi200 futures orderbook data are received from 233.38.231.112:10342 while those of kosdaq150 are received from 233.38.231.112:10343. For kospi equity trade data, the ip address is 233.38.231.2 with ports ranging from 10022 to 10026. Therefore, when receiving data, you need to make sure you are listening to the correct ip address and port.

Below is an exmaple config yaml file that maps data types to port number:

udp_port_mappings:
  # 증권 A : KOSPI
  # 증권 B : KOSDAQ
  # 증권 C : ETF, ELW, ETN

  ## 증권 A, 유가증권수직 12M/100M 
  10001:                    "stockA"             # stock fundamental
  
  ## 증권 A, 유가증권수직 12M
  10022:                    "stockA"     # trade (group 00001) 
  10023:                    "stockA"     # trade (group 00002)
  10024:                    "stockA"     # trade (group 00003)
  10025:                    "stockA"     # trade (group 00004)
  10026:                    "stockA"     # trade (group 00005)
  10027:                    "stockA"     # orderbook 
  10028:                    "stockA"     # orderbook

  ## 증권 B, 코스닥통합 12M/100M
  10101:                    "stockB"     # stock fundamental
  10107:                    "stockB"     # 주식종목정보변경  
  10108:                    "stockB"     # 종목별 투자자별 종가 통계
  10111:                    "stockB"     # stock fundamental
  10117:                    "stockB"     # stock index

  ## 증권 B, 코스닥통합12M
  10122:                    "stockB"     # trade (group 00001)
  10123:                    "stockB"     # trade (group 00002)
  10124:                    "stockB"     # trade (group 00003)
  10125:                    "stockB"     # trade (group 00004)
  10126:                    "stockB"     # trade (group 00005)
  10127:                    "stockB"     # orderbook
  10128:                    "stockB"     # orderbook
  
  10132:                    "stockB"     # stock info
  10133:                    "stockB"     # stock info

  ## 증권 C, 증권상품 12M/100M
  10201:                    "stockC"     # stock fundamental    
  10207:                    "stockC"     # stock info
  
  ## 증권 C, 증권상품12M
  10222:                    "stockC"     # trade (group 00006)
  10223:                    "stockC"     # trade (group 00007)
  10224:                    "stockC"     # trade (group 00008)
  10225:                    "stockC"     # trade (group 00009)
  10226:                    "stockC"     # trade (group 00010)
  10227:                    "stockC"     # orderbook
  10228:                    "stockC"     # orderbook

  10231:                    "stockC"     # ETF PDF
  10232:                    "stockC"     # ETF Nav
  10233:                    "stockC"     # overseas etf nav
  10234:                    "stockC"     # ELW sensitivity
  10235:                    "stockC"     # elw
  10236:                    "stockC"     # etn IIV
  10237:                    "stockC"     # ETF NAV


  ### 파생 A, 통합선물 100M

  ## 파생 A, 통합선물 12M/100M
  10301:                    "futureA"    # stock fundamental 
  10315:                    "futureA"    # stock fundamental
  10316:                    "futureA"    # stock fundamental
  10321:                    "futureA"    # option fundamental

  ## 파생 A, 통합선물 12M
  10342:                    "futureA"    # kospi200 future 
  10343:                    "futureA"    # kosdaq150 future
  10344:                    "futureA"    # equity future
  10345:                    "futureA"    # tbill future
  10346:                    "futureA"    # gold future
  10347:                    "futureA"    # mini kospi200 future
  10348:                    "futureA"    # kospi200 volatility future
  10349:                    "futureA"    # kospi200 sector index future
  10350:                    "futureA"    # krx300 future

  10362:                    "futureA"    # kospi200 call option
  10363:                    "futureA"    # kosdaq150 call option
  10364:                    "futureA"    # equity call option
  10366:                    "futureA"    # mini kospi200 call option
  10367:                    "futureA"    # weekly kospi200 call option

  10371:                    "futureA"    # kospi200 put option
  10372:                    "futureA"    # kosdaq150 put option
  10373:                    "futureA"    # equity put option
  10375:                    "futureA"    # mini kospi200 put option
  10376:                    "futureA"    # kospi200 weekly put option

KRX Message

Each message can be identified with a message type code and a message type subcode. As an example, the Korean exchange sends out a stock directory message (aka stock batch data) that contains information about the stock. This informaton includes the isin, number of listed shares, ipo date, tradability, previous day closing price, and so on. As you can see, it contains vital information for traders. Putting everything together, we can summarize the message into a yaml file as shown below:

messages:
  IFMSBTD0001:
    name: StockBatchDataMessage
    code: A0
    subcodes:
      - 01S
      - 02S
      - 03S
      - 04S
      - 01Q
      - 01X
    fields:
      data_category:
        size: 2
        datatype_py: str
        datatype_rs: String
      information_category:
        size: 3
        datatype_py: str
        datatype_rs: String
      message_sequence_number:
        size: 8
        datatype_py: str
        datatype_rs: String 
      contract_instruments_total_number:
        size: 6
        datatype_py: int
        datatype_rs: i32
      business_date:
        size: 8
        datatype_py: str
        datatype_rs: String
      isin:
        size: 12
        datatype_py: str
        datatype_rs: String
      designated_issue_number:
        size: 6
        datatype_py: str
        datatype_rs: String
      
      ...
      
      ...

      ...
      
     upper_limit_quantity:
        size: 23
        datatype_py: float
      investment_warning_issue:
        size: 1
        datatype_py: str
        datatype_rs: String
      insufficient_number_of_listed_shares:
        size: 1
        datatype_py: str
        datatype_rs: String
      spac_merger:
        size: 1
        datatype_py: str
        datatype_rs: String
      segment_type_code:
        size: 1
        datatype_py: str
        datatype_rs: String
      system_datetime:      # created by our system!
        size: 19
        datatype_py: int
        datatype_rs: i64

Let’s go over the yaml file line by line. Every message has its own unique interface id, and the above stock batch data message has an interface id of IFMSBTD0001. The code field is used by the parser to determine the message type and the subcodes field contains information about security types and markets (e.g. 04F subcode indicates equity futures).

Some messages contain exchange datetime field which has a microsecond precision. To get a better precision, our trading engine inserts a nanosecond timestamp after every message and we denote it as system_datetime.

The size field indicates the byte length of the field, datatype_py field is the type we wish to convert the bytes into when using python, and datatype_rs for rust programming language.

I attached a yaml file that summarized most frequently used KRX messages.

Opening and Closing Auction

messages:
  IFMSRPD0004:
    name: StockTradeMessage
    contains: stock_trade
    code: A3
    subcodes:
      - 01S
      - 01Q
      - 01X
      - 02S
      - 03S
      - 04S
    fields:
      data_category:
        size: 2
        datatype_py: str
        datatype_rs: String
      information_category:
        size: 3
        datatype_py: str
        datatype_rs: String
      message_sequence_number:
        size: 8
        datatype_py: str
        datatype_rs: String 
      board_id:
        size: 2
        datatype_py: str
        datatype_rs: String
      session_id:
        size: 2
        datatype_py: str
        datatype_rs: String
      isin:
        size: 12
        datatype_py: str
        datatype_rs: String
      designated_issue_number:
        size: 6
        datatype_py: str
        datatype_rs: String
      datetime:
        size: 12
        datatype_py: chrono.krx_time_to_timestamp
        datatype_rs: i64
      price_change_since_previous_day_code:
        size: 1
        datatype_py: str
        datatype_rs: String
      price_change_since_previous_day_price:
        size: 11
        datatype_py: float
        datatype_rs: double
      trade_price:
        size: 11
        datatype_py: float
        datatype_rs: double
      trade_volume:
        size: 10
        datatype_py: int
      opening_price:
        size: 11
        datatype_py: float
        datatype_rs: double
      high_price:
        size: 11
        datatype_py: float
        datatype_rs: double
      low_price:
        size: 11
        datatype_py: float
        datatype_rs: double
      accumulated_trade_volume:
        size: 12
        datatype_py: int
        datatype_rs: i32
      accumulated_trade_value:
        size: 22
        datatype_py: float
        datatype_rs: double
      trade_type:
        size: 1
        datatype_py: decode_side
        datatype_rs: String
      lp_holding_quantity:
        size: 15
        datatype_py: int
        datatype_rs: i64
      l1askprice:
        size: 11
        datatype_py: float
        datatype_rs: double
      l1bidprice:
        size: 11
        datatype_py: float
        datatype_rs: double
      system_datetime:
        size: 19
        datatype_py: int
        datatype_rs: i64

Each trade message contains trade_type field which can be a BUY, SELL, or AUCTION. When running our trading system, it is imperative that our algorithm check opening trae AUCTION message since the regular trading hour begins after that message. These messages do not come exactly at 09:00:00 in the morning but rather at any time between 09:00:00.0 and 09:00:01.0. All messages received before the opening trade message pertain to the opening cross, therefore, should not be used after the opening cross.

Trade, Marketdepth, Trade&Marketdepth, and Board&Marketdepth Messages

KRX UDP realtime data provides orderbook of depth 5 and 10. ETP and equity orderbooks have depth of 10, and derivative orderbooks have depth of 5. However, equity futures have orderbook depth of 10. Derivative orderbooks contain number of orders at a given price and ETP orderbook data contains the quantity of sitting orders made by liquidity providers(LP) in addition to the total quantity.

Furthermore, there are four differnet types of messages that contain trade or marketdepth data: trade message (code A3), marketdepth message (code B6 and B7), trade&marketdepth message (code G7) and board&marketdepth message (code R1). These messages are crucial to traders who rely on price movement and trade statistics. Below is a brief summary of these messages:

  • Trade Message (A3): contains trade price and trade volume of a given security
  • Marketdepth Message (B6 and B7): contains orderbok of depth 5 or 10 depending on the type of security. LP quantity is also provided for ETPs.
  • Trade & Marketdepth (G7): contains trade price and trade volume data in addition to orderbook data
  • Board & Marketdepth (R1): contains board event and orderbook data. Board event contains information about the market hours (e.g. regular trading hours, post-market trading hours, etc).

Koscom Messages

Koscom is a financial IT company whose parent company is the Korean stock exchange (KRX). Koscom also disseminates messages pertaining to exchange traded products (ETPs). Below are some messages that are often used by traders:

  • ETN IIV message
  • ETN Divergence message
  • ETF PDF message

Specifications of Koscom messages are also included in the attached file.

Attached file

Leave a comment