Guide
TradeZero Market-on-Open Orders with Python
Fetch Alphanume's top-five pre-market ranks and build TradeZero opening short orders with route checks, explicit submission and recorded order IDs.
A market-on-open order asks to trade at the stock's opening event. Sending an ordinary market order near 9:30 is a different instruction. This guide shows how the starter builds an opening short order from an Alphanume candidate, then verifies the account's routing capabilities.
This example requires an Alphanume API key with access to Pre-Market Drop Risk. TradeZero handles the account and execution; Alphanume supplies the ranked candidates. TradeZero's API can use other data, but this starter is built around Alphanume. See dataset access and plans.
Download the Python starter, Windows wrapper, and offline tests. Extract it before running commands. The ZIP includes setup instructions and the complete source.
Fetch today's ranks
Save this short example beside the starter files. It uses the same pagination-aware client as the runner.
from datetime import datetime
from zoneinfo import ZoneInfo
from client import alphanume_rows
day = datetime.now(ZoneInfo("America/New_York")).date().isoformat()
data = alphanume_rows("premarket-drop-risk", {
"date": day,
"max_rank": 5,
"min_price": 1,
})
for row in data:
print(row["ticker"], row["rank_for_date"], row["prob_drop"])
rank_for_date starts at one. max_rank=5 selects original ranks one through five; the price filter does not refill missing slots with lower-ranked stocks. The runner checks dates again locally, rejects stale-day data, removes duplicate tickers and rounds quantities down to whole shares.
The model's target is an open-to-close decline of at least 5%. Do not use its later outcome columns to decide a morning trade. At the decision time those outcomes are unknown. See the dataset page for the input cutoff and field definitions.
Find a route that supports the request
def route_for(routes, order_type, tif, preferred=None):
allowed = [r["routeName"] for r in routes
if "Stock" in r.get("securityTypes", ["Stock"])
and order_type in r.get("orderTypes", []) and tif in r.get("timesInForce", [])]
if preferred:
if preferred not in allowed:
raise ValueError("Configured route does not advertise the requested order type and time in force")
return preferred
if not allowed:
raise ValueError("No compatible route; no order will be submitted")
return "SMART" if "SMART" in allowed else sorted(allowed)[0]
This is the function used by the starter. For an opening entry it receives Market and AtTheOpening. It selects from the current account's route response, or validates the explicit --entry-route override. No compatible route means no submission.
The saved deployment check from September 24, 2026 found a different route set from the current documentation's examples. That is why the public code does not hard-code ARCA or assume every account has SMART. TradeZero's equity-trading documentation describes opening-order eligibility and destination-specific cutoffs. Confirm the intended auction behavior with the broker for your route and symbol.
Build the order body
def order_body(ticket, route, client_id, *, price=None):
closing = price is not None
body = {"securityType": "Stock", "symbol": ticket["symbol"],
"side": "Buy" if closing else "Sell", "openClose": "Close" if closing else "Open",
"orderType": "Limit" if closing else "Market", "orderQuantity": ticket["quantity"],
"timeInForce": "Day" if closing else "AtTheOpening", "route": route,
"clientOrderId": client_id}
if closing:
body["limitPrice"] = price
return body
With no price argument, this function produces the entry: Sell, Open, Market and AtTheOpening. The closing branch is used by the exit guide. The clientOrderId identifies your request so it can be looked up later.
The starter writes a new ID to disk before POSTing to the account's /order endpoint. If the request times out, it may still have reached the broker. A later scheduled entry sees the saved attempt and does not create a replacement blindly.
Inspect before enabling submission
.\.venv\Scripts\python.exe starter.py entry --budget 500
This previews the body and borrow check only. The sample dollar budget is illustrative. To submit, follow the explicit opt-in commands in the README. Live entry also requires the market-data key for the exit workflow. The runner accepts entry writes from 09:08 until before 09:24 ET, leaving time before the documented opening cutoff; a late launch skips rather than chasing the open.
A request can return HTTP 200 and still report a rejected order. Read orderStatus, then follow the order by its recorded ID. A paper fill or an advertised route does not demonstrate that a live fill matches the primary exchange's official opening print.
Common questions
Will I get the exact official open?
The order expresses opening intent. This series has not verified exchange-level fill evidence for every route and symbol, so it makes no exact-price claim. Compare actual execution reports with the relevant opening print when evaluating your own workflow.
Why did the starter submit fewer than five orders?
Price filters, whole-share sizing, existing exposure, borrow cost or availability, the entry cutoff, and rejection can all remove candidates. Skipped allocations are not redistributed.
Can I rerun entry after a crash?
You can inspect with reconcile, but the starter will not automatically repeat that day's marked entry attempt. Read the saved order and quote IDs in TradeZero before taking any manual action.
Continue to the exit workflow, or review locates and the overview.
API documentation checked September 27, 2026. Route availability and account access can change. Examples describe the included starter; they do not establish trading performance.