Login
The smallest possible IBX program: connect, wait for next_valid_id, disconnect.
Two flavors are shown below — paper for everyday testing and live for read-only validation against your real account.
Per the project rules, never send orders from a live account. Use live only for read-only checks (login, contract details).
What this shows
- Reading credentials from environment variables.
- Calling
EClient.connect(...)withpaper=True(paper) orpaper=False(live). - Receiving
next_valid_id— the signal that the session is fully established and ready for requests.
Paper
Run it
IB_USERNAME=... IB_PASSWORD=... python examples/hello_login.py
Source
"""Hello-world recipe: connect, wait for next_valid_id, disconnect.
Usage:
IB_USERNAME=... IB_PASSWORD=... python examples/hello_login.py
"""
import os
import threading
from ibx import EClient, EWrapper
class LoginWrapper(EWrapper):
def __init__(self):
self.ready = threading.Event()
self.order_id = None
def next_valid_id(self, order_id):
self.order_id = order_id
self.ready.set()
w = LoginWrapper()
c = EClient(w)
c.connect(
username=os.environ["IB_USERNAME"],
password=os.environ["IB_PASSWORD"],
host="cdc1.ibllc.com",
paper=True,
)
threading.Thread(target=c.run, daemon=True).start()
if not w.ready.wait(timeout=15):
raise RuntimeError("did not receive next_valid_id")
print(f"logged in. next_valid_id = {w.order_id}")
c.disconnect()
Live
The live login may trigger a second-factor push. Approve it on your mobile
authenticator when prompted — connect() blocks until the gate clears.
Run it
IB_LIVE_USERNAME=... IB_LIVE_PASSWORD=... python examples/hello_login_live.py
Source
"""Live-account login recipe: connect with paper=False, wait for next_valid_id,
disconnect. Read-only — no orders, no market data.
When the live login triggers a second-factor push, approve it on your mobile
authenticator. The connect call blocks until the gate clears.
Usage:
IB_LIVE_USERNAME=... IB_LIVE_PASSWORD=... python examples/hello_login_live.py
"""
import os
import threading
from ibx import EClient, EWrapper
class LoginWrapper(EWrapper):
def __init__(self):
self.ready = threading.Event()
self.order_id = None
def next_valid_id(self, order_id):
self.order_id = order_id
self.ready.set()
w = LoginWrapper()
c = EClient(w)
c.connect(
username=os.environ["IB_LIVE_USERNAME"],
password=os.environ["IB_LIVE_PASSWORD"],
host=os.environ.get("IB_HOST", "cdc1.ibllc.com"),
paper=False,
)
threading.Thread(target=c.run, daemon=True).start()
if not w.ready.wait(timeout=60):
raise RuntimeError("did not receive next_valid_id")
print(f"logged in LIVE. next_valid_id = {w.order_id}")
c.disconnect()