Skip to main content

Protocol Buffer Reference

Complete reference documentation for all Protocol Buffer messages, fields, and enumerations used in the gRPC streaming API with Python.

Package Structure

connamara.ep3.v1beta1              # Core API services
├── MarketDataSubscriptionAPI      # Market data streaming
├── OrderEntryAPI                  # Order streaming and entry
└── common.proto                   # Common message types

connamara.ep3.orders.v1beta1       # Order-specific types
└── orders.proto                   # Order enums and messages

connamara.ep3.instruments.v1beta1  # Instrument types
└── instruments.proto              # Instrument statistics

Obtaining Proto Files

Proto files are available:
  1. Download: trading-gateway-protos.zip - Complete proto package
  2. Via server reflection: Use gRPC reflection to discover services at runtime
# List all services using grpcurl
grpcurl traderapi.us-east-1.privatelink.preprod.polymarketexchange.com:443 list

# Describe a specific service
grpcurl traderapi.us-east-1.privatelink.preprod.polymarketexchange.com:443 describe \
  connamara.ep3.v1beta1.MarketDataSubscriptionAPI

Generating Python Client Code

Once you have the proto files, generate Python code:
python -m grpc_tools.protoc \
  --python_out=. \
  --grpc_python_out=. \
  --proto_path=protos \
  protos/connamara/ep3/v1beta1/market_data.proto \
  protos/connamara/ep3/v1beta1/order_entry.proto \
  protos/connamara/ep3/orders/v1beta1/orders.proto \
  protos/connamara/ep3/instruments/v1beta1/instruments.proto \
  protos/connamara/ep3/type/v1beta1/common.proto
This generates:
  • *_pb2.py - Message and enum definitions
  • *_pb2_grpc.py - Service stubs

Market Data Proto Reference

MarketDataSubscriptionAPI Service

service MarketDataSubscriptionAPI {
    rpc CreateMarketDataSubscription(CreateMarketDataSubscriptionRequest)
        returns (stream CreateMarketDataSubscriptionResponse);
}

Python Usage

from connamara.ep3.v1beta1 import market_data_pb2
from connamara.ep3.v1beta1 import market_data_pb2_grpc

# Create request
request = market_data_pb2.CreateMarketDataSubscriptionRequest(
    symbols=["mlb-ari-sf-2025-09-08"],
    depth=10
)

# Use stub
stub = market_data_pb2_grpc.MarketDataSubscriptionAPIStub(channel)
response_stream = stub.CreateMarketDataSubscription(request, metadata=metadata)

CreateMarketDataSubscriptionRequest

FieldTypeDescription
symbolslist[str]List of symbols to subscribe to. Empty = all symbols.
unaggregatedboolIf true, receive raw orders. If false, receive aggregated book.
depthintNumber of price levels to include. Default: 10
snapshot_onlyboolIf true, receive snapshot then close. Default: false

CreateMarketDataSubscriptionResponse

# Check event type
if response.HasField('heartbeat'):
    # Heartbeat message
    pass
elif response.HasField('update'):
    # Market data update
    update = response.update

Update Message

FieldTypeDescription
symbolstrInstrument symbol
bidslist[BookEntry]Bid side of order book
offerslist[BookEntry]Offer/ask side of order book
stateInstrumentStateCurrent instrument state
statsInstrumentStatsMarket statistics
transact_timeTimestampServer timestamp of update
book_hiddenboolIf true, order book is hidden

BookEntry Message

# price_scale from instrument metadata (via list_instruments API)
px = bid.px / price_scale
qty = bid.qty
symbol_sub_type = bid.symbol_sub_type
FieldTypeDescription
pxint64Price (divide by price_scale)
qtyint64Aggregate quantity at this price level
symbol_sub_typestrSymbol subtype (if applicable)

InstrumentState Enum

from connamara.ep3.v1beta1 import market_data_pb2

# Get state name
state_name = market_data_pb2.InstrumentState.Name(update.state)

# Check if open
if update.state == market_data_pb2.INSTRUMENT_STATE_OPEN:
    print("Market is open for trading")
NameValueDescription
INSTRUMENT_STATE_CLOSED0Market closed, no trading
INSTRUMENT_STATE_OPEN1Active trading, continuous matching
INSTRUMENT_STATE_PREOPEN2Pre-opening auction, no matching
INSTRUMENT_STATE_SUSPENDED3Trading suspended, cancel-only
INSTRUMENT_STATE_EXPIRED4Instrument expired
INSTRUMENT_STATE_TERMINATED5Instrument terminated
INSTRUMENT_STATE_HALTED6Trading halted
INSTRUMENT_STATE_MATCH_AND_CLOSE_AUCTION7Closing auction

InstrumentStats Message

# Check if stats field exists
if update.HasField('stats'):
    stats = update.stats

    # price_scale from instrument metadata
    if stats.HasField('last_trade_px'):
        last_px = stats.last_trade_px / price_scale
        print(f"Last Trade: ${last_px:.4f}")
FieldTypeDescription
open_pxint64Opening price (÷ price_scale)
close_pxint64Closing price (÷ price_scale)
low_pxint64Session low price (÷ price_scale)
high_pxint64Session high price (÷ price_scale)
last_trade_pxint64Last trade price (÷ price_scale)
shares_tradedint64Total shares/contracts traded
open_interestint64Current open interest
notional_tradedint64Total notional value traded
Stats fields use protobuf oneof, so they may not always be present. Always check with HasField().

Order Entry Proto Reference

OrderEntryAPI Service

service OrderEntryAPI {
    rpc CreateOrderSubscription(CreateOrderSubscriptionRequest)
        returns (stream CreateOrderSubscriptionResponse);
}

Python Usage

from connamara.ep3.v1beta1 import order_entry_pb2
from connamara.ep3.v1beta1 import order_entry_pb2_grpc
from connamara.ep3.orders.v1beta1 import orders_pb2

# Create request
request = order_entry_pb2.CreateOrderSubscriptionRequest(
    symbols=["mlb-ari-sf-2025-09-08"],
    accounts=[],
    snapshot_only=False
)

# Use stub
stub = order_entry_pb2_grpc.OrderEntryAPIStub(channel)
response_stream = stub.CreateOrderSubscription(request, metadata=metadata)

CreateOrderSubscriptionRequest

FieldTypeDescription
symbolslist[str]Filter by symbols. Empty = all symbols.
accountslist[str]Filter by accounts. Empty = all user’s accounts.
snapshot_onlyboolIf true, snapshot only. Default: false

CreateOrderSubscriptionResponse

# Check event type
if response.HasField('heartbeat'):
    pass
elif response.HasField('snapshot'):
    snapshot = response.snapshot
    for order in snapshot.orders:
        # Process order
        pass
elif response.HasField('update'):
    update = response.update
    for execution in update.executions:
        # Process execution
        pass

# Access session ID
session_id = response.session_id
FieldTypeDescription
eventoneofOne of: heartbeat, snapshot, or update
session_idstrUnique session identifier
processed_sent_timeTimestampServer processing timestamp

Order Message

# Access order fields
print(f"Order ID: {order.id}")
print(f"Symbol: {order.symbol}")
print(f"Side: {orders_pb2.Side.Name(order.side)}")
print(f"State: {orders_pb2.OrderState.Name(order.state)}")

if order.price > 0:
    price = order.price / order.price_scale
    print(f"Price: ${price:.4f}")
Key fields:
FieldTypeDescription
idstrExchange-assigned order ID
clord_idstrClient-assigned order ID
symbolstrTrading symbol
typeOrderTypeOrder type
sideSideBUY or SELL
order_qtyint64Original order quantity
priceint64Limit price (÷ price_scale)
time_in_forceTimeInForceDAY, GTC, IOC, FOK, GTT
accountstrTrading account identifier
cum_qtyint64Cumulative filled quantity
avg_pxint64Average fill price (÷ price_scale)
leaves_qtyint64Remaining unfilled quantity
stateOrderStateCurrent order state
insert_timeTimestampWhen order was inserted

Execution Message

# Process execution
exec_type = orders_pb2.ExecutionType.Name(execution.type)
print(f"Execution Type: {exec_type}")

if execution.last_shares > 0:
    fill_px = execution.last_px / execution.order.price_scale
    print(f"Fill: {execution.last_shares} @ ${fill_px:.4f}")

if execution.order_reject_reason != orders_pb2.ORD_REJECT_REASON_UNDEFINED:
    reject_reason = orders_pb2.OrdRejectReason.Name(execution.order_reject_reason)
    print(f"Rejected: {reject_reason}")
FieldTypeDescription
idstrUnique execution ID
typeExecutionTypeExecution type
orderOrderCurrent order state
last_sharesint64Quantity filled in this execution
last_pxint64Fill price (÷ price_scale)
textstrFree-form text message
order_reject_reasonOrdRejectReasonRejection reason (if rejected)
transact_timeTimestampTransaction timestamp
trade_idstrTrade identifier
aggressorboolTrue if you were the aggressor

Order Enumerations

OrderType

from connamara.ep3.orders.v1beta1 import orders_pb2

# Get type name
type_name = orders_pb2.OrderType.Name(order.type)
NameValue
ORDER_TYPE_LIMIT2
ORDER_TYPE_MARKET_TO_LIMIT1
ORDER_TYPE_STOP3
ORDER_TYPE_STOP_LIMIT4

Side

# Get side name
side_name = orders_pb2.Side.Name(order.side)

# Check side
if order.side == orders_pb2.SIDE_BUY:
    print("Buy order")
NameValue
SIDE_BUY1
SIDE_SELL2

TimeInForce

tif_name = orders_pb2.TimeInForce.Name(order.time_in_force)
NameValueDescription
TIME_IN_FORCE_DAY1Day order (expires at end of day)
TIME_IN_FORCE_GTC2Good-till-canceled
TIME_IN_FORCE_IOC3Immediate-or-cancel
TIME_IN_FORCE_FOK4Fill-or-kill
TIME_IN_FORCE_GTT5Good-till-time

OrderState

state_name = orders_pb2.OrderState.Name(order.state)

if order.state == orders_pb2.ORDER_STATE_FILLED:
    print("Order completely filled")
NameValueDescription
ORDER_STATE_NEW1Order accepted and resting
ORDER_STATE_PARTIALLY_FILLED2Partially executed
ORDER_STATE_FILLED3Completely filled
ORDER_STATE_CANCELED4Canceled
ORDER_STATE_REJECTED7Rejected by exchange
ORDER_STATE_EXPIRED9Expired

ExecutionType

exec_type = orders_pb2.ExecutionType.Name(execution.type)

if execution.type == orders_pb2.EXECUTION_TYPE_FILL:
    print("Order completely filled")
NameValueDescription
EXECUTION_TYPE_NEW1Order confirmation
EXECUTION_TYPE_PARTIAL_FILL2Partial fill
EXECUTION_TYPE_FILL3Complete fill
EXECUTION_TYPE_TRADE9Trade execution
EXECUTION_TYPE_CANCELED4Cancellation confirmation
EXECUTION_TYPE_REJECTED7Order rejection
EXECUTION_TYPE_EXPIRED10Order expired

OrdRejectReason

if execution.order_reject_reason != orders_pb2.ORD_REJECT_REASON_UNDEFINED:
    reason = orders_pb2.OrdRejectReason.Name(execution.order_reject_reason)
    print(f"Reject Reason: {reason}")
NameValueDescription
ORD_REJECT_REASON_UNKNOWN_SYMBOL1Symbol not found
ORD_REJECT_REASON_EXCHANGE_CLOSED2Market is closed
ORD_REJECT_REASON_ORDER_EXCEEDS_LIMIT3Exceeds risk limits
ORD_REJECT_REASON_DUPLICATE_ORDER4Duplicate clord_id
ORD_REJECT_REASON_UNKNOWN_ACCOUNT5Account not found
ORD_REJECT_REASON_INCORRECT_QUANTITY6Invalid quantity
ORD_REJECT_REASON_INVALID_PRICE7Invalid price
ORD_REJECT_REASON_OTHER99Other reason

Common Data Types

Price Representation

All prices are int64 values. Divide by the instrument’s price_scale to get the decimal value.price_scale varies by instrument. Get it from:
  • Instrument metadata via list_instruments or get_instrument_metadata
  • The price_scale field in order responses
# Get price_scale from instrument or order
decimal_price = int64_price / price_scale

# Example using order's price_scale
decimal_price = order.price / order.price_scale

Timestamp Handling

from datetime import datetime

# Check if field is set
if order.HasField('insert_time'):
    # Convert to Python datetime
    insert_dt = datetime.fromtimestamp(order.insert_time.seconds)
    print(f"Inserted at: {insert_dt}")

Checking Optional Fields

# Use HasField() for optional fields
if update.HasField('stats'):
    # price_scale from instrument metadata
    if update.stats.HasField('last_trade_px'):
        last_px = update.stats.last_trade_px / price_scale

Next Steps