name: pykx
description: Use when working with KDB-X Python for Python-to-q data conversion, querying tables with Column API, IPC connections, DB management, or integrating Python with q. Also use when encountering type conversion issues, connection errors, or licensed vs unlicensed mode questions.
KDB-X Python
KDB-X Python is the Python-first interface to kdb+ and q. import pykx as kx
For full Column methods, DB API, IPC details, type mapping: see reference.md
Critical Patterns (Common Mistakes)
Column API for WHERE: Use Operators, Not Strings
# CORRECT: kx.Column with Python operators
table.select(where=kx.Column('price') > 100)
table.select(where=(kx.Column('sym') == 'AAPL') & (kx.Column('price') > 150))
# WRONG — string-based where does NOT work
table.select(where='price > 100') # WRONG!
table.select(where='sym = `AAPL') # WRONG!
Combining WHERE Conditions: Use & | ~ (Not and/or/not)
# CORRECT: bitwise operators with parentheses
where=(kx.Column('sym') == 'AAPL') & (kx.Column('price') > 100) # AND
where=(kx.Column('sym') == 'AAPL') | (kx.Column('sym') == 'GOOG') # OR
where=~(kx.Column('size') < 100) # NOT
# WRONG — Python keywords don't work with Column objects
where=kx.Column('sym') == 'AAPL' and kx.Column('price') > 100 # WRONG!
RawQConnection: Async + Queue Then poll_send/poll_recv
# CORRECT: async construction, queue query, then poll_send/poll_recv
q = await kx.RawQConnection(host='localhost', port=5000)
q('select from trades') # Queue the query (not sent yet)
q.poll_send() # Send queued queries
result = q.poll_recv() # Receive response
# WRONG — poll_send does NOT take a query string
q.poll_send('select from trades') # WRONG! poll_send takes amount, not query
# WRONG — RawQConnection requires async construction
with kx.RawQConnection(...) as q: # WRONG! use await, not sync with
Creating pykx Objects
qlist = kx.toq([1, 2, 3]) # LongVector (auto)
qlist = kx.toq([1, 2, 3], kx.FloatVector) # Explicit type
qtable = kx.toq(df) # DataFrame -> Table
kx.random.random(10, 100.0) # 10 random floats 0-100
Execute q Code
kx.q('til 10') # 0 1 2 3 ... 9
kx.q('{x+y}', 2, 4) # 6 (function with args, max 8)
kx.q['myvar'] = [1, 2, 3] # Assign to q memory
kx.q.sql('SELECT * FROM trades WHERE sym = $1', 'AAPL') # SQL interface
Converting Back to Python
Deferred conversion -- data stays in q memory until explicitly converted:
| Method |
Returns |
Use Case |
.py() |
Python dict/list |
General Python use |
.np() |
NumPy array |
Numerical computation |
.pd() |
Pandas DataFrame |
Data analysis |
.pa() |
PyArrow table |
Big data/Parquet |
Querying Tables (Pythonic API)
table.select() # All
table.select(columns=kx.Column('price')) # Single column
table.select(columns={'maxP': kx.Column('price').max()}) # Named aggregation
table.select(where=kx.Column('sym') == 'AAPL') # Filter
table.select(columns=kx.Column('price').max(),
where=kx.Column('sym') == 'GOOG', by=kx.Column('date')) # Group by
prices = table.exec(columns=kx.Column('price')) # Returns vector
table.update(columns={'price': kx.Column('price') * 1.1},
where=kx.Column('sym') == 'AAPL')
table.delete(where=kx.Column('size') < 100)
Column Methods
kx.Column('price').max() # max, min, avg, sum, count, dev, var
kx.Column('price').name('maxPrice') # Rename in output
kx.Column('size').last() # first, last, med, prd, sdev, svar
kx.Column('price').avg().name('avgPrice') # Chain name after aggregation
Variable for Dynamic Values
kx.Variable('threshold') # Reference q variable in queries
table.select(where=kx.Column('price') > kx.Variable('minPrice'))
Or use q directly: kx.q('select max price by date from trades where sym=AAPL')`
DB Management (On-Disk Tables)
db = kx.DB(path='hdb')
db.tables # List available tables
db.trades # Access table by name
# Schema operations
db.rename_column('trades', 'oldName', 'newName')
db.add_column('trades', 'newCol', default_value=0)
db.delete_column('trades', 'dropCol')
db.rename_table('oldTable', 'newTable')
# Partition management
db.fill_database() # Fill missing tables/columns across partitions
IPC Connections
# Sync (most common) - context manager recommended
with kx.SyncQConnection('localhost', 5000) as q:
result = q('select from trades')
df = result.pd()
# With auth
with kx.SyncQConnection('localhost', 5000, username='user', password='pass') as q: ...
# TLS
with kx.SecureQConnection('localhost', 5000, tls=True) as q: ...
# Async (returns QFuture)
async with await kx.AsyncQConnection('localhost', 5000) as q:
fut = q('select from trades') # Returns QFuture
result = await fut # Await the result
# Raw (fine-grained control, async construction)
q = await kx.RawQConnection(host='localhost', port=5000)
q('select from trades') # Queue query
q.poll_send() # Send queued
result = q.poll_recv() # Receive response
# Call remote functions
with kx.SyncQConnection('localhost', 5000) as q:
result = q.myns.myfunc(arg1, arg2)
# Fire and forget
with kx.SyncQConnection('localhost', 5000) as q:
q('insert[`trades; data]', wait=False)
| Type |
Use Case |
SyncQConnection |
Standard queries, data retrieval |
AsyncQConnection |
async with await, returns QFuture |
SecureQConnection |
TLS-enabled servers (sync) |
RawQConnection |
await construction, poll_send/poll_recv, server emulation |
Licensed vs Unlicensed Mode
import os
os.environ['PYKX_LICENSED'] = '1' # Before importing pykx
import pykx as kx
kx.licensed # True if licensed
| Feature |
Licensed |
Unlicensed |
kx.q() execution |
Yes |
No |
| IPC connections |
Yes |
Yes |
| Data conversion |
Yes |
Yes |
| Table creation |
Yes |
Limited |
kx.DB management |
Yes |
No |
Type Mapping
| Python |
pykx |
q |
int |
LongAtom |
long |
float |
FloatAtom |
float |
str |
SymbolAtom |
symbol |
bool |
BooleanAtom |
boolean |
datetime |
TimestampAtom |
timestamp |
list |
List |
list |
dict |
Dictionary |
dict |
DataFrame |
Table |
table |
Common Errors & Fixes
| Error |
Fix |
| Type error on conversion |
Use homogeneous types: kx.toq([1,2,3]) not kx.toq([1,'a',2.0]) |
| Connection refused |
Ensure q server running: q -p 5000 |
| Lost type info round-trip |
Use explicit types: kx.FloatVector(data) |
| Context not persisted over IPC |
Embedded kx.q shares context; IPC connections do NOT |
PYKX_UNLICENSED but need q |
Set PYKX_LICENSED=1 before import, ensure kc.lic present |
AttributeError: poll_recv |
Use RawQConnection, not SyncQConnection or AsyncQConnection |
and/or in Column where |
Use & / ` |
Performance Tips
- Keep data in q memory -- avoid unnecessary conversions
- Use
.pd() only when needed -- conversion has overhead
- Batch operations -- fewer IPC calls = better performance
- Use context manager -- ensures proper connection cleanup
Related skills
q — q language syntax and kdb+ workflows
kdbx — KDB-X platform features
kdbai — KDB.AI vector database