-- Auto-generated protocol definition
-- DO NOT EDIT - This file is generated by Morel
local Protocol = {}
Protocol.name = "txse_moth_trading"
Protocol.description = "txse_moth_trading"
-- Enum definitions
Protocol.enums = {}
Protocol.enums.CancelReason = {
  [1] = "REQUESTED_BY_USER",
  [2] = "RELATED_TO_TIME_IN_FORCE",
  [3] = "RELATED_TO_MIN_QTY",
  [4] = "REG_NMS_VIOLATION_NO_SLIDE",
  [5] = "MARKETABLE_RESERVE",
  [6] = "SELF_MATCH_PREVENTION",
  [7] = "REPLENISHMENT_CANCELED_DUE_TO_RESERVE",
  [8] = "RELATED_TO_ORDER_TYPE",
  [9] = "CANCELED_DUE_TO_CROSSED_MARKETS",
  [10] = "CANCELED_DUE_TO_MASS_CANCEL_REQUEST",
  [11] = "EXCHANGE_LOCKED_OR_CROSSED_NO_SLIDE",
  [12] = "REG_SHO_VIOLATION_NO_SLIDE",
}
Protocol.enums.ExchangeCode = {
  [1] = "TXSE",
  [2] = "XNAS",
  [3] = "XBOS",
  [4] = "XPSX",
  [5] = "EDGA",
  [6] = "EDGX",
  [7] = "BATY",
  [8] = "BATS",
  [9] = "MEMX",
  [10] = "EPRL",
  [11] = "LTSE",
  [12] = "IEXG",
  [13] = "XNYS",
  [14] = "ARCX",
  [15] = "XCIS",
  [16] = "XCHI",
  [17] = "XASE",
  [18] = "FINRA",
  [19] = "X24EQ",
  [20] = "SIP",
}
Protocol.enums.MarketDataSource = {
  [1] = "EXCHANGE",
  [2] = "SIP",
}
Protocol.enums.OperationalHaltReason = {
  [0] = "ADMINISTRATIVE",
}
Protocol.enums.OrderCapacity = {
  [1] = "AGENCY",
  [2] = "PRINCIPAL",
  [3] = "RISKLESS_PRINCIPAL",
}
Protocol.enums.OrderDisposition = {
  [0] = "SPRIG_SENT_DISPOSITION",
  [1] = "MATCHING_ENGINE_POSTED_THE_ORDER",
  [2] = "ORDER_DID_NOT_POST",
}
Protocol.enums.PriceSlideInstruction = {
  [0] = "NO_PRICE_SLIDE",
  [1] = "SINGLE_PRICE_SLIDE_ON_LOCK_AND_CROSS",
  [2] = "MULTIPLE_PRICE_SLIDES_ON_LOCK_AND_CROSS",
  [3] = "SINGLE_PRICE_SLIDE_LOCK_ONLY",
}
Protocol.enums.RegulatoryHaltReason = {
  [0] = "REASON_NOT_AVAILABLE",
  [1] = "NEWS_PENDING",
  [2] = "NEWS_DISSEMINATION",
  [3] = "INFO_REQUESTED",
  [4] = "ORDER_IMBALANCE",
  [5] = "EXTRAORDINARY_MARKET_ACTIVITY",
  [6] = "LULD_PAUSE",
  [7] = "NON_COMPLIANCE",
  [8] = "FILINGS_NOT_CURRENT",
  [9] = "SEC_SUSPENSION",
  [10] = "REGULATORY_CONCERN",
  [11] = "SUB_PENNY_TRADING",
  [12] = "ETF",
  [13] = "IPO_NOT_TRADING",
  [14] = "CORPORATE_ACTION",
  [15] = "CIRCUIT_BREAKER_L1",
  [16] = "CIRCUIT_BREAKER_L2",
  [17] = "CIRCUIT_BREAKER_L3",
}
Protocol.enums.RejectReason = {
  [1] = "INVALID_CLIENT_ORDER_ID",
  [2] = "DUPLICATE_CLIENT_ORDER_ID",
  [3] = "UNKNOWN_ORIGINAL_CLIENT_ORDER_ID",
  [4] = "NO_LONGER_ON_BOOK",
  [5] = "INVALID_SYMBOL",
  [6] = "INVALID_PRICE",
  [7] = "INVALID_ORDER_QUANTITY",
  [8] = "INVALID_REFERENCE_PRICE_TARGET",
  [9] = "INVALID_IS_HIDDEN_FLAG",
  [10] = "INVALID_ORDER_TYPE",
  [11] = "INVALID_SIDE",
  [12] = "INVALID_MAX_FLOOR_QUANTITY",
  [13] = "INVALID_MAX_REPLENISH_QUANTITY_RANGE",
  [14] = "INVALID_MAX_REPLENISH_TIME_RANGE",
  [15] = "INVALID_MINIMUM_QUANTITY",
  [16] = "INVALID_LOCATE_REQUIRED_FLAG",
  [17] = "INVALID_TIME_IN_FORCE",
  [18] = "MODIFICATION_NOT_PERMITTED",
  [19] = "INVALID_MPID",
  [20] = "INVALID_SENDER_COMP",
  [21] = "INVALID_IS_POST_ONLY_FLAG",
  [22] = "INVALID_EXPIRE_TIME",
  [23] = "ORDER_INVALID_FOR_TRADING_SESSION",
  [24] = "ORDER_INVALID_FOR_TRADING_STATUS",
  [25] = "ORDER_INVALID_FOR_SYMBOL_STATUS",
  [26] = "INVALID_IS_ISO_FLAG",
  [27] = "TRADING_DISABLED_FOR_MPID_ON_PORT",
  [28] = "TRADING_DISABLED_FOR_NON_TEST_SYMBOLS",
  [29] = "TRADING_DISABLED_FOR_ORDER_CAPACITY",
  [30] = "TRADING_DISABLED_FOR_ISO",
  [31] = "MAXIMUM_ORDER_QUANTITY_BREACHED",
  [32] = "MAXIMUM_PRICE_BREACHED",
  [33] = "MAXIMUM_NOTIONAL_BREACHED",
  [34] = "INVALID_MASS_CANCEL_REQUEST_ID",
  [35] = "SYMBOL_ON_RESTRICTED_LIST",
}
Protocol.enums.SelfMatchInstruction = {
  [0] = "NO_SELF_MATCH_PREVENTION",
  [1] = "CANCEL_NEWEST",
  [2] = "CANCEL_OLDEST",
  [3] = "CANCEL_BOTH",
  [4] = "CANCEL_SMALLEST",
  [5] = "DECREMENT_AND_CANCEL",
}
Protocol.enums.SelfMatchScope = {
  [0] = "BY_MEMBER",
  [1] = "BY_MPID",
  [2] = "BY_MEMBER_GROUP",
  [3] = "BY_MPID_AND_MEMBER_GROUP",
}
Protocol.enums.ShortSaleRestrictionState = {
  [0] = "NONE",
  [1] = "ACTIVATED",
  [2] = "CONTINUED",
}
Protocol.enums.Side = {
  [0] = "BUY",
  [1] = "LONG_SELL",
  [2] = "SHORT_SELL",
  [3] = "SHORT_EXEMPT",
}
Protocol.enums.StateConflictReason = {
  [1] = "NO_OPEN_ORDER_FOUND",
  [2] = "NO_REPLENISHMENT_CAPACITY",
  [3] = "MARKETABLE_RESERVE",
  [4] = "REPRICE_DOES_NOT_CHANGE_RANK",
}
Protocol.enums.SymbolTradingState = {
  [1] = "TRADING",
  [2] = "HALTED",
}
Protocol.enums.TimeInForce = {
  [1] = "SYS",
  [2] = "IOC",
  [3] = "GTT",
  [4] = "DAY",
  [5] = "RHO",
}
-- Field definitions
-- Returns a function that creates Fields table given TXSE lib
Protocol.createFields = function(TXSE)
  local Fields = {}
  local Enums = Protocol.enums
  Fields["msgType"] = {
    length = 1,
    abbr = "txse_moth_trading.msgType",
    name = "msgType",
    ftype = ftypes.CHAR,
    encoding = ENC_ASCII,
    value_map = {
      [67] = "Cancel",
      [68] = "MarketData",
      [69] = "Execution",
      [72] = "ReplenishReserve",
      [73] = "Reprice",
      [75] = "ReplaceRejected",
      [77] = "Modify",
      [78] = "ModifyRejected",
      [79] = "Order",
      [81] = "MassCancelResult",
      [82] = "Replace",
      [83] = "StateConflict",
      [84] = "MarketOrderRejected",
      [85] = "LimitOrderRejected",
      [87] = "CancelRejected",
      [88] = "SequenceTime",
      [89] = "SymbolStatus",
      [90] = "SelfMatchTrade",
    },
  }
  Fields["presenceOffset"] = {
    length = 1,
    abbr = "txse_moth_trading.presenceOffset",
    name = "presenceOffset",
    ftype = ftypes.UINT8,
    encoding = ENC_NA,
  }
  Fields["appId"] = {
    length = 2,
    abbr = "txse_moth_trading.appId",
    name = "appId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["appSeq"] = {
    length = 4,
    abbr = "txse_moth_trading.appSeq",
    name = "appSeq",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppSeq",
  }
  Fields["ask"] = {
    length = 8,
    abbr = "txse_moth_trading.ask",
    name = "ask",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["bid"] = {
    length = 8,
    abbr = "txse_moth_trading.bid",
    name = "bid",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["cancelReason"] = {
    length = 1,
    abbr = "txse_moth_trading.cancelReason",
    name = "cancelReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.CancelReason",
    value_map = Enums.CancelReason,
  }
  Fields["canceledCount"] = {
    length = 4,
    abbr = "txse_moth_trading.canceledCount",
    name = "canceledCount",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.Int",
  }
  Fields["canceledQty"] = {
    length = 4,
    abbr = "txse_moth_trading.canceledQty",
    name = "canceledQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["clOrdId"] = {
    length = 8,
    abbr = "txse_moth_trading.clOrdId",
    name = "clOrdId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ClOrdId",
  }
  Fields["displayMatchingEngineIndex"] = {
    length = 4,
    abbr = "txse_moth_trading.displayMatchingEngineIndex",
    name = "displayMatchingEngineIndex",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MatchingEngineIndex",
  }
  Fields["displayOrderId"] = {
    length = 8,
    abbr = "txse_moth_trading.displayOrderId",
    name = "displayOrderId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.OrderId",
  }
  Fields["displayPrice"] = {
    length = 8,
    abbr = "txse_moth_trading.displayPrice",
    name = "displayPrice",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["displayQty"] = {
    length = 4,
    abbr = "txse_moth_trading.displayQty",
    name = "displayQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["exchangeCode"] = {
    length = 1,
    abbr = "txse_moth_trading.exchangeCode",
    name = "exchangeCode",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.ExchangeCode",
    value_map = Enums.ExchangeCode,
  }
  Fields["execId"] = {
    length = 8,
    abbr = "txse_moth_trading.execId",
    name = "execId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ExecId",
  }
  Fields["execPrice"] = {
    length = 8,
    abbr = "txse_moth_trading.execPrice",
    name = "execPrice",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["execQty"] = {
    length = 4,
    abbr = "txse_moth_trading.execQty",
    name = "execQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["com.txse.exchange.specs.moth.define.ExecutionBitFields"] = {
    length = 1,
    abbr = "txse_moth_trading.executionBitFields",
    name = "executionBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.moth.define.ExecutionBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      tree:add(buffer, string.format("isAggressor: %d", TXSE.extract_bits(numeric, 0)))
      tree:add(buffer, string.format("isRestingDisplayed: %d", TXSE.extract_bits(numeric, 1)))
      tree:add(buffer, string.format("executionReserved: %d", TXSE.extract_bits(numeric, 2, 6)))
    end,
  }
  Fields["expireTime"] = {
    length = 8,
    abbr = "txse_moth_trading.expireTime",
    name = "expireTime",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["fixClOrdId"] = {
    length = 20,
    abbr = "txse_moth_trading.fixClOrdId",
    name = "fixClOrdId",
    ftype = ftypes.STRING,
    encoding = ENC_ASCII,
    kotlin_type = "kotlin.String",
  }
  Fields["com.txse.exchange.specs.seed.define.LimitOrderBitFields"] = {
    length = 4,
    abbr = "txse_moth_trading.limitOrderBitFields",
    name = "limitOrderBitFields",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.seed.define.LimitOrderBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 4):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      local timeInForce = TXSE.extract_bits(numeric, 4, 4)
      tree:add(buffer, string.format("timeInForce: %d (%s)", timeInForce, Enums.TimeInForce[timeInForce] or "Unknown"))
      local orderCapacity = TXSE.extract_bits(numeric, 8, 3)
      tree:add(buffer, string.format("orderCapacity: %d (%s)", orderCapacity, Enums.OrderCapacity[orderCapacity] or "Unknown"))
      tree:add(buffer, string.format("isIso: %d", TXSE.extract_bits(numeric, 11)))
      tree:add(buffer, string.format("isHidden: %d", TXSE.extract_bits(numeric, 12)))
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 13)))
      tree:add(buffer, string.format("cancelAtEntryIfCrossed: %d", TXSE.extract_bits(numeric, 14)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 15, 17)))
    end,
  }
  Fields["locateBroker"] = {
    length = 4,
    abbr = "txse_moth_trading.locateBroker",
    name = "locateBroker",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.LocateBroker",
  }
  Fields["marketDataSource"] = {
    length = 1,
    abbr = "txse_moth_trading.marketDataSource",
    name = "marketDataSource",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MarketDataSource",
    value_map = Enums.MarketDataSource,
  }
  Fields["com.txse.exchange.specs.seed.define.MarketOrderBitFields"] = {
    length = 2,
    abbr = "txse_moth_trading.marketOrderBitFields",
    name = "marketOrderBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.seed.define.MarketOrderBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      local timeInForce = TXSE.extract_bits(numeric, 4, 4)
      tree:add(buffer, string.format("timeInForce: %d (%s)", timeInForce, Enums.TimeInForce[timeInForce] or "Unknown"))
      local orderCapacity = TXSE.extract_bits(numeric, 8, 3)
      tree:add(buffer, string.format("orderCapacity: %d (%s)", orderCapacity, Enums.OrderCapacity[orderCapacity] or "Unknown"))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 11, 5)))
    end,
  }
  Fields["massCancelId"] = {
    length = 8,
    abbr = "txse_moth_trading.massCancelId",
    name = "massCancelId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MassCancelId",
  }
  Fields["massCancelRequestId"] = {
    length = 8,
    abbr = "txse_moth_trading.massCancelRequestId",
    name = "massCancelRequestId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MassCancelId",
  }
  Fields["matchingEngineIndex"] = {
    length = 4,
    abbr = "txse_moth_trading.matchingEngineIndex",
    name = "matchingEngineIndex",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MatchingEngineIndex",
  }
  Fields["maxFloorQty"] = {
    length = 4,
    abbr = "txse_moth_trading.maxFloorQty",
    name = "maxFloorQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["maxReplenishQtyRange"] = {
    length = 4,
    abbr = "txse_moth_trading.maxReplenishQtyRange",
    name = "maxReplenishQtyRange",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["maxReplenishTimeRange"] = {
    length = 8,
    abbr = "txse_moth_trading.maxReplenishTimeRange",
    name = "maxReplenishTimeRange",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.time.Duration",
  }
  Fields["member"] = {
    length = 3,
    abbr = "txse_moth_trading.member",
    name = "member",
    ftype = ftypes.STRING,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.Member",
  }
  Fields["memberGroup"] = {
    length = 2,
    abbr = "txse_moth_trading.memberGroup",
    name = "memberGroup",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MemberGroup",
  }
  Fields["minQty"] = {
    length = 4,
    abbr = "txse_moth_trading.minQty",
    name = "minQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["com.txse.exchange.specs.seed.define.ModifyBitFields"] = {
    length = 1,
    abbr = "txse_moth_trading.modifyBitFields",
    name = "modifyBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.seed.define.ModifyBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 4, 4)))
    end,
  }
  Fields["mpid"] = {
    length = 4,
    abbr = "txse_moth_trading.mpid",
    name = "mpid",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MPID",
  }
  Fields["newClOrdId"] = {
    length = 8,
    abbr = "txse_moth_trading.newClOrdId",
    name = "newClOrdId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ClOrdId",
  }
  Fields["newFixClOrdId"] = {
    length = 20,
    abbr = "txse_moth_trading.newFixClOrdId",
    name = "newFixClOrdId",
    ftype = ftypes.STRING,
    encoding = ENC_ASCII,
    kotlin_type = "kotlin.String",
  }
  Fields["newMatchingEngineIndex"] = {
    length = 4,
    abbr = "txse_moth_trading.newMatchingEngineIndex",
    name = "newMatchingEngineIndex",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MatchingEngineIndex",
  }
  Fields["newOrderId"] = {
    length = 8,
    abbr = "txse_moth_trading.newOrderId",
    name = "newOrderId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.OrderId",
  }
  Fields["nextSeqTimestamp"] = {
    length = 8,
    abbr = "txse_moth_trading.nextSeqTimestamp",
    name = "nextSeqTimestamp",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["operationalHaltReason"] = {
    length = 1,
    abbr = "txse_moth_trading.operationalHaltReason",
    name = "operationalHaltReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.OperationalHaltReason",
    value_map = Enums.OperationalHaltReason,
  }
  Fields["com.txse.exchange.specs.moth.define.OrderBitFields"] = {
    length = 4,
    abbr = "txse_moth_trading.orderBitFields",
    name = "orderBitFields",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.moth.define.OrderBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 4):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isMarketOrderType: %d", TXSE.extract_bits(numeric, 3)))
      local timeInForce = TXSE.extract_bits(numeric, 4, 4)
      tree:add(buffer, string.format("timeInForce: %d (%s)", timeInForce, Enums.TimeInForce[timeInForce] or "Unknown"))
      local orderCapacity = TXSE.extract_bits(numeric, 8, 3)
      tree:add(buffer, string.format("orderCapacity: %d (%s)", orderCapacity, Enums.OrderCapacity[orderCapacity] or "Unknown"))
      tree:add(buffer, string.format("isIso: %d", TXSE.extract_bits(numeric, 11)))
      tree:add(buffer, string.format("isDisplayed: %d", TXSE.extract_bits(numeric, 12)))
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 13)))
      local priceSlideInstruction = TXSE.extract_bits(numeric, 14, 3)
      tree:add(buffer, string.format("priceSlideInstruction: %d (%s)", priceSlideInstruction, Enums.PriceSlideInstruction[priceSlideInstruction] or "Unknown"))
      local selfMatchScope = TXSE.extract_bits(numeric, 17, 3)
      tree:add(buffer, string.format("selfMatchScope: %d (%s)", selfMatchScope, Enums.SelfMatchScope[selfMatchScope] or "Unknown"))
      local selfMatchInstruction = TXSE.extract_bits(numeric, 20, 3)
      tree:add(buffer, string.format("selfMatchInstruction: %d (%s)", selfMatchInstruction, Enums.SelfMatchInstruction[selfMatchInstruction] or "Unknown"))
      tree:add(buffer, string.format("cancelAtEntryIfCrossed: %d", TXSE.extract_bits(numeric, 23)))
      tree:add(buffer, string.format("didCollarLimitPrice: %d", TXSE.extract_bits(numeric, 24)))
      tree:add(buffer, string.format("didDisplayPriceSlide: %d", TXSE.extract_bits(numeric, 25)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 26, 6)))
    end,
  }
  Fields["orderDisposition"] = {
    length = 1,
    abbr = "txse_moth_trading.orderDisposition",
    name = "orderDisposition",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.OrderDisposition",
    value_map = Enums.OrderDisposition,
  }
  Fields["orderId"] = {
    length = 8,
    abbr = "txse_moth_trading.orderId",
    name = "orderId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.OrderId",
  }
  Fields["orderQty"] = {
    length = 4,
    abbr = "txse_moth_trading.orderQty",
    name = "orderQty",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["origClOrdId"] = {
    length = 8,
    abbr = "txse_moth_trading.origClOrdId",
    name = "origClOrdId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ClOrdId",
  }
  Fields["origFixClOrdId"] = {
    length = 20,
    abbr = "txse_moth_trading.origFixClOrdId",
    name = "origFixClOrdId",
    ftype = ftypes.STRING,
    encoding = ENC_ASCII,
    kotlin_type = "kotlin.String",
  }
  Fields["originalLimitPrice"] = {
    length = 8,
    abbr = "txse_moth_trading.originalLimitPrice",
    name = "originalLimitPrice",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["originatingAppId"] = {
    length = 2,
    abbr = "txse_moth_trading.originatingAppId",
    name = "originatingAppId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["pendingExecCount"] = {
    length = 2,
    abbr = "txse_moth_trading.pendingExecCount",
    name = "pendingExecCount",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.Short",
  }
  Fields["price"] = {
    length = 8,
    abbr = "txse_moth_trading.price",
    name = "price",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["priceSlideInstruction"] = {
    length = 1,
    abbr = "txse_moth_trading.priceSlideInstruction",
    name = "priceSlideInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.PriceSlideInstruction",
    value_map = Enums.PriceSlideInstruction,
  }
  Fields["com.txse.exchange.specs.moth.define.ReferenceOrderBitFields"] = {
    length = 1,
    abbr = "txse_moth_trading.referenceOrderBitFields",
    name = "referenceOrderBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isDisplayed: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 4, 4)))
    end,
  }
  Fields["referencePriceTarget"] = {
    length = 2,
    abbr = "txse_moth_trading.referencePriceTarget",
    name = "referencePriceTarget",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.BasisPoints",
  }
  Fields["regulatoryHaltReason"] = {
    length = 1,
    abbr = "txse_moth_trading.regulatoryHaltReason",
    name = "regulatoryHaltReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RegulatoryHaltReason",
    value_map = Enums.RegulatoryHaltReason,
  }
  Fields["rejectReason"] = {
    length = 1,
    abbr = "txse_moth_trading.rejectReason",
    name = "rejectReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RejectReason",
    value_map = Enums.RejectReason,
  }
  Fields["com.txse.exchange.specs.seed.define.ReplaceBitFields"] = {
    length = 2,
    abbr = "txse_moth_trading.replaceBitFields",
    name = "replaceBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.seed.define.ReplaceBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      local side = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("side: %d (%s)", side, Enums.Side[side] or "Unknown"))
      tree:add(buffer, string.format("isLocateRequired: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("isIso: %d", TXSE.extract_bits(numeric, 4)))
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 5)))
      tree:add(buffer, string.format("cancelAtEntryIfCrossed: %d", TXSE.extract_bits(numeric, 6)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 7, 9)))
    end,
  }
  Fields["com.txse.exchange.specs.moth.define.ReplaceBitFields"] = {
    length = 2,
    abbr = "txse_moth_trading.replaceBitFields",
    name = "replaceBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.moth.define.ReplaceBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      tree:add(buffer, string.format("isIso: %d", TXSE.extract_bits(numeric, 0)))
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 1)))
      tree:add(buffer, string.format("cancelAtEntryIfCrossed: %d", TXSE.extract_bits(numeric, 2)))
      local priceSlideInstruction = TXSE.extract_bits(numeric, 3, 3)
      tree:add(buffer, string.format("priceSlideInstruction: %d (%s)", priceSlideInstruction, Enums.PriceSlideInstruction[priceSlideInstruction] or "Unknown"))
      local selfMatchScope = TXSE.extract_bits(numeric, 6, 3)
      tree:add(buffer, string.format("selfMatchScope: %d (%s)", selfMatchScope, Enums.SelfMatchScope[selfMatchScope] or "Unknown"))
      local selfMatchInstruction = TXSE.extract_bits(numeric, 9, 3)
      tree:add(buffer, string.format("selfMatchInstruction: %d (%s)", selfMatchInstruction, Enums.SelfMatchInstruction[selfMatchInstruction] or "Unknown"))
      tree:add(buffer, string.format("didCollarLimitPrice: %d", TXSE.extract_bits(numeric, 12)))
      tree:add(buffer, string.format("didDisplayPriceSlide: %d", TXSE.extract_bits(numeric, 13)))
      tree:add(buffer, string.format("replaceReserved: %d", TXSE.extract_bits(numeric, 14, 2)))
    end,
  }
  Fields["com.txse.exchange.specs.moth.define.RepriceBitFields"] = {
    length = 2,
    abbr = "txse_moth_trading.repriceBitFields",
    name = "repriceBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.moth.define.RepriceBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      tree:add(buffer, string.format("isPostOnly: %d", TXSE.extract_bits(numeric, 0)))
      local priceSlideInstruction = TXSE.extract_bits(numeric, 1, 3)
      tree:add(buffer, string.format("priceSlideInstruction: %d (%s)", priceSlideInstruction, Enums.PriceSlideInstruction[priceSlideInstruction] or "Unknown"))
      local selfMatchScope = TXSE.extract_bits(numeric, 4, 3)
      tree:add(buffer, string.format("selfMatchScope: %d (%s)", selfMatchScope, Enums.SelfMatchScope[selfMatchScope] or "Unknown"))
      local selfMatchInstruction = TXSE.extract_bits(numeric, 7, 3)
      tree:add(buffer, string.format("selfMatchInstruction: %d (%s)", selfMatchInstruction, Enums.SelfMatchInstruction[selfMatchInstruction] or "Unknown"))
      tree:add(buffer, string.format("didCollarLimitPrice: %d", TXSE.extract_bits(numeric, 10)))
      tree:add(buffer, string.format("didDisplayPriceSlide: %d", TXSE.extract_bits(numeric, 11)))
      tree:add(buffer, string.format("repriceReserved: %d", TXSE.extract_bits(numeric, 12, 4)))
    end,
  }
  Fields["selfMatchInstruction"] = {
    length = 1,
    abbr = "txse_moth_trading.selfMatchInstruction",
    name = "selfMatchInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SelfMatchInstruction",
    value_map = Enums.SelfMatchInstruction,
  }
  Fields["selfMatchScope"] = {
    length = 1,
    abbr = "txse_moth_trading.selfMatchScope",
    name = "selfMatchScope",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SelfMatchScope",
    value_map = Enums.SelfMatchScope,
  }
  Fields["com.txse.exchange.specs.moth.define.SelfMatchTradeBitFields"] = {
    length = 1,
    abbr = "txse_moth_trading.selfMatchTradeBitFields",
    name = "selfMatchTradeBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.moth.define.SelfMatchTradeBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      local selfMatchInstruction = TXSE.extract_bits(numeric, 0, 3)
      tree:add(buffer, string.format("selfMatchInstruction: %d (%s)", selfMatchInstruction, Enums.SelfMatchInstruction[selfMatchInstruction] or "Unknown"))
      tree:add(buffer, string.format("isAggressor: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("isRestingDisplayed: %d", TXSE.extract_bits(numeric, 4)))
      tree:add(buffer, string.format("selfMatchTradeReserved: %d", TXSE.extract_bits(numeric, 5, 3)))
    end,
  }
  Fields["seqTimestamp"] = {
    length = 8,
    abbr = "txse_moth_trading.seqTimestamp",
    name = "seqTimestamp",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["shortSaleRestrictionState"] = {
    length = 1,
    abbr = "txse_moth_trading.shortSaleRestrictionState",
    name = "shortSaleRestrictionState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.ShortSaleRestrictionState",
    value_map = Enums.ShortSaleRestrictionState,
  }
  Fields["stateConflictReason"] = {
    length = 1,
    abbr = "txse_moth_trading.stateConflictReason",
    name = "stateConflictReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.StateConflictReason",
    value_map = Enums.StateConflictReason,
  }
  Fields["symbolId"] = {
    length = 2,
    abbr = "txse_moth_trading.symbolId",
    name = "symbolId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolId",
  }
  Fields["symbolTradingState"] = {
    length = 1,
    abbr = "txse_moth_trading.symbolTradingState",
    name = "symbolTradingState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SymbolTradingState",
    value_map = Enums.SymbolTradingState,
  }
  Fields["updatesOffset"] = {
    length = 1,
    abbr = "txse_moth_trading.updatesOffset",
    name = "updatesOffset",
    ftype = ftypes.UINT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.morel.generate.MorelOffset",
  }
  Fields["userData"] = {
    length = 8,
    abbr = "txse_moth_trading.userData",
    name = "userData",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.Long",
  }
  Fields["cancelPresence"] = {
    length = 1,
    abbr = "txse_moth_trading.cancelPresence",
    name = "cancelPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["cancelRejectedPresence"] = {
    length = 1,
    abbr = "txse_moth_trading.cancelRejectedPresence",
    name = "cancelRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["limitOrderRejectedPresence"] = {
    length = 2,
    abbr = "txse_moth_trading.limitOrderRejectedPresence",
    name = "limitOrderRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["marketOrderRejectedPresence"] = {
    length = 1,
    abbr = "txse_moth_trading.marketOrderRejectedPresence",
    name = "marketOrderRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["modifyPresence"] = {
    length = 1,
    abbr = "txse_moth_trading.modifyPresence",
    name = "modifyPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["modifyRejectedPresence"] = {
    length = 1,
    abbr = "txse_moth_trading.modifyRejectedPresence",
    name = "modifyRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["orderPresence"] = {
    length = 2,
    abbr = "txse_moth_trading.orderPresence",
    name = "orderPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["replacePresence"] = {
    length = 1,
    abbr = "txse_moth_trading.replacePresence",
    name = "replacePresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["replaceRejectedPresence"] = {
    length = 2,
    abbr = "txse_moth_trading.replaceRejectedPresence",
    name = "replaceRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["repricePresence"] = {
    length = 1,
    abbr = "txse_moth_trading.repricePresence",
    name = "repricePresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["sequenceTimePresence"] = {
    length = 1,
    abbr = "txse_moth_trading.sequenceTimePresence",
    name = "sequenceTimePresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["symbolStatusPresence"] = {
    length = 1,
    abbr = "txse_moth_trading.symbolStatusPresence",
    name = "symbolStatusPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  return Fields
end
-- Message definitions
Protocol.messages = {
  {
    name = "Cancel",
    type = "C",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "cancelReason",
      "cancelPresence",
    },
    presence_fields = {
      "newFixClOrdId",
    },
  },
  {
    name = "CancelRejected",
    type = "W",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "origClOrdId",
      "rejectReason",
      "cancelRejectedPresence",
    },
    presence_fields = {
      "fixClOrdId",
      "origFixClOrdId",
    },
  },
  {
    name = "Execution",
    type = "E",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "com.txse.exchange.specs.moth.define.ExecutionBitFields",
      "execId",
      "execQty",
      "execPrice",
    },
  },
  {
    name = "LimitOrderRejected",
    type = "U",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.LimitOrderBitFields",
      "symbolId",
      "price",
      "rejectReason",
      "limitOrderRejectedPresence",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "minQty",
      "maxFloorQty",
      "maxReplenishQtyRange",
      "maxReplenishTimeRange",
      "referencePriceTarget",
      "expireTime",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
      "fixClOrdId",
    },
  },
  {
    name = "MarketData",
    type = "D",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "exchangeCode",
      "marketDataSource",
      "updatesOffset",
    },
    list_fields = {
      {
        name = "updates",
        offset_field = "updatesOffset",
        item_type = "MarketDataUpdate",
        item_length = 18,
        item_fields = {
          "symbolId",
          "bid",
          "ask",
        },
      },
    },
  },
  {
    name = "MarketOrderRejected",
    type = "T",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "clOrdId",
      "orderQty",
      "com.txse.exchange.specs.seed.define.MarketOrderBitFields",
      "symbolId",
      "rejectReason",
      "marketOrderRejectedPresence",
    },
    presence_fields = {
      "selfMatchScope",
      "selfMatchInstruction",
      "userData",
      "mpid",
      "memberGroup",
      "locateBroker",
      "fixClOrdId",
    },
  },
  {
    name = "MassCancelResult",
    type = "Q",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "originatingAppId",
      "massCancelRequestId",
      "massCancelId",
      "canceledCount",
    },
  },
  {
    name = "Modify",
    type = "M",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "newClOrdId",
      "orderQty",
      "modifyPresence",
    },
    presence_fields = {
      "newFixClOrdId",
      "locateBroker",
    },
  },
  {
    name = "ModifyRejected",
    type = "N",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "clOrdId",
      "origClOrdId",
      "rejectReason",
      "modifyRejectedPresence",
    },
    presence_fields = {
      "orderQty",
      "com.txse.exchange.specs.seed.define.ModifyBitFields",
      "locateBroker",
      "fixClOrdId",
      "origFixClOrdId",
    },
  },
  {
    name = "Order",
    type = "O",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "symbolId",
      "clOrdId",
      "com.txse.exchange.specs.moth.define.OrderBitFields",
      "orderQty",
      "price",
      "member",
      "mpid",
      "memberGroup",
      "newOrderId",
      "newMatchingEngineIndex",
      "orderDisposition",
      "pendingExecCount",
      "orderPresence",
    },
    presence_fields = {
      "fixClOrdId",
      "minQty",
      "maxFloorQty",
      "maxReplenishQtyRange",
      "maxReplenishTimeRange",
      "referencePriceTarget",
      "expireTime",
      "locateBroker",
      "userData",
      "originalLimitPrice",
    },
  },
  {
    name = "Replace",
    type = "R",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "newClOrdId",
      "com.txse.exchange.specs.moth.define.ReplaceBitFields",
      "orderQty",
      "price",
      "newOrderId",
      "newMatchingEngineIndex",
      "orderDisposition",
      "pendingExecCount",
      "replacePresence",
    },
    presence_fields = {
      "newFixClOrdId",
      "maxFloorQty",
      "referencePriceTarget",
      "locateBroker",
      "originalLimitPrice",
    },
  },
  {
    name = "ReplaceRejected",
    type = "K",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "clOrdId",
      "origClOrdId",
      "com.txse.exchange.specs.seed.define.ReplaceBitFields",
      "rejectReason",
      "replaceRejectedPresence",
    },
    presence_fields = {
      "price",
      "orderQty",
      "maxFloorQty",
      "selfMatchScope",
      "selfMatchInstruction",
      "priceSlideInstruction",
      "referencePriceTarget",
      "locateBroker",
      "fixClOrdId",
      "origFixClOrdId",
    },
  },
  {
    name = "ReplenishReserve",
    type = "H",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "displayQty",
      "displayPrice",
      "displayOrderId",
      "displayMatchingEngineIndex",
    },
  },
  {
    name = "Reprice",
    type = "I",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "com.txse.exchange.specs.moth.define.RepriceBitFields",
      "price",
      "newOrderId",
      "newMatchingEngineIndex",
      "orderDisposition",
      "pendingExecCount",
      "repricePresence",
    },
    presence_fields = {
      "originalLimitPrice",
    },
  },
  {
    name = "SelfMatchTrade",
    type = "Z",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "com.txse.exchange.specs.moth.define.SelfMatchTradeBitFields",
      "execId",
      "execQty",
      "execPrice",
      "canceledQty",
    },
  },
  {
    name = "SequenceTime",
    type = "X",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "sequenceTimePresence",
    },
    presence_fields = {
      "nextSeqTimestamp",
    },
  },
  {
    name = "StateConflict",
    type = "S",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "orderId",
      "matchingEngineIndex",
      "originatingAppId",
      "symbolId",
      "com.txse.exchange.specs.moth.define.ReferenceOrderBitFields",
      "stateConflictReason",
    },
  },
  {
    name = "SymbolStatus",
    type = "Y",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "symbolId",
      "symbolTradingState",
      "shortSaleRestrictionState",
      "symbolStatusPresence",
    },
    presence_fields = {
      "operationalHaltReason",
      "regulatoryHaltReason",
    },
  },
}
-- Dissector setup
-- opts.payload_decoder: optional function(buffer, pinfo, tree_item) for trailing payload
Protocol.register = function(opts)
  local TXSE = require("txse-lib")
  local proto, messages = TXSE.Proto.new(TXSE.createSpec(Protocol, opts))
  function proto.dissector(buffer, pinfo, tree)
    local length = buffer:len()
    if length < 1 then
      return 0
    end
    local msg_type = buffer(0, 1):uint()
    local msg = messages.mapping[msg_type]
    if not msg then
      return 0
    end
    pinfo.cols.protocol = proto.name
    pinfo.cols.info = msg.name
    local subtree = tree:add(proto, buffer, msg.name)
    msg:parse(buffer, pinfo, subtree)
    return buffer:len()
  end
  return proto
end
return Protocol
