When to Use
Use this skill when a system inside the firm — a strategy, a risk engine, a research notebook, a client-facing screen — is about to open a market data stream from a trading venue, and someone must be able to prove afterwards that the firm had licensed that venue, at that depth, for that kind of use, by a subscriber classified the way the venue's rules require.
The gate exists because market data breaches are discovered late and priced retroactively. The CTA Nonprofessional Subscriber Policy states it plainly: "If NYSE finds that the vendor has incorrectly qualified a professional subscriber as nonprofessional, the vendor will be liable for retroactive fees billed by NYSE for the subscriber at the professional rate." A wrong approval today is a back-fee assessment, with interest, months or years from now.
The single most expensive modelling mistake in this area is a firm-wide
"we have a non-display licence" flag. No major venue licenses non-display that
way — see Prerequisites and references/standards.md.
When NOT to Use
- Not a fee calculator or a usage declaration. It decides access; it does not produce reportable units. Nasdaq's non-display unit of count is the greater of (a) the number of Subscribers that can modify the application in real time or (b) the number of Devices (usually servers) that receive and benefit from the Information. Derive that from your infrastructure inventory, never from stream requests.
- Not a replacement for the vendor's permissioning system. LSEG DACS and Bloomberg EMRS enforce entitlements at the feed itself. This gate sits upstream and does not remove the need to configure them.
- Not for vendor contract scope (licensed use cases, redistribution rights,
seat caps) — that is
data-vendor-contractual-usage-restriction-tracking. - Not for real-time vs delayed tiering or for blocking execution on delayed
quotes — that is
real-time-vs-delayed-data-entitlement-handling. - Not a legal opinion. It enforces the scope a compliance owner has encoded from the executed Order Forms and agreements. Reading them is still a human job.
Prerequisites
VenueEntitlement— one per licensed venue:venue_id,max_data_level(L1/L2/L3, deepest licensed tier),non_display_categories(subset ofPRINCIPAL,CLIENT_FACILITATION,TRADING_PLATFORM; empty means display-only),license_expiry_date(ISO-8601YYYY-MM-DD, orNonefor "not tracked here"). Venues licensed separately need separate records. CME Group charges non-display per Designated Contract Market, soCME,CBOT,NYMEXandCOMEXare four entitlements, not one. LSE declares per segment and per level.UserEntitlementProfile—user_id,account_holder_type(NATURAL_PERSON/ORGANISATION),declared_classification(PROFESSIONAL/NON_PROFESSIONAL),is_securities_professional,classification_attested_on(ISO-8601; required for aNON_PROFESSIONALdeclaration),venue_entitlements.DataStreamRequest—user_id,venue_id,data_level,usage_type(DISPLAY/NON_DISPLAY_ALGO),non_display_category(required whenusage_typeisNON_DISPLAY_ALGO).- A durable store for the returned
EntitlementAuditReportobjects. The engine keeps no record of its own.
Workflow
Checks run in this order and short-circuit on the first denial. The order is part
of the contract: it determines which status an auditor sees for a request that
breaches more than one rule.
- Subscriber identity — if
request.user_iddoes not equalprofile.user_id, deny withENTITLEMENT_DENIED_SUBSCRIBER_MISMATCH. Entitlements are not transferable; evaluating one subscriber's request against another's profile silently lends out licences and files the decision under the wrong name. - Usage type recognised — if
usage_typeis neitherDISPLAYnorNON_DISPLAY_ALGO, deny withENTITLEMENT_DENIED_UNRECOGNISED_USAGE_TYPE. A near-miss such asNON_DISPLAYmust never fall through to the display path and skip the non-display gate entirely. - Classification integrity — deny with
ENTITLEMENT_DENIED_MISCLASSIFIED_SUBSCRIBERwhen aNON_PROFESSIONALdeclaration cannot stand: the account holder is anORGANISATION(only natural persons can qualify), the subscriber is a Securities Professional, or the request is automated non-display consumption.PROFESSIONALis never a defect — it is the default classification, and over-declaring it costs money rather than creating audit exposure. - Classification freshness — a
NON_PROFESSIONALdeclaration with noclassification_attested_on, a future-dated one, or one older thanmax_attestation_age_days(default 183, the semi-annual CTA re-verification cadence) is denied withENTITLEMENT_DENIED_STALE_CLASSIFICATION. - Venue licensed — if the normalised
venue_idhas noVenueEntitlement, deny withENTITLEMENT_DENIED_UNLICENSED_VENUE. Venue ids are normalised on both sides; a duplicate entitlement for one venue is a configuration error, not a silent last-one-wins. - Licence term — if
as_of_dateis pastlicense_expiry_date, deny withENTITLEMENT_DENIED_EXPIRED_LICENSE. The expiry date itself is the last licensed day. An entitlement withlicense_expiry_date=Noneis not gated on expiry; the engine logs a warning once per subscriber/venue so the omission is visible rather than silent. - Depth licensed — if the requested
data_levelis deeper thanmax_data_level, deny withENTITLEMENT_DENIED_UNLICENSED_DATA_LEVEL. AnL2entitlement coversL1; it does not coverL3. Depth-of-book is a separately licensed product everywhere this skill applies. - Non-display activity licensed — for
NON_DISPLAY_ALGO, deny withENTITLEMENT_DENIED_MISSING_NON_DISPLAY_LICENSEwhen the venue entitlement is display-only, when the request names nonon_display_category, or when the named category is not licensed at that venue. Trading as principal and facilitating client business are separate licences (CME Category A1 vs A2; LSE Principal vs Client Facilitation), so the engine refuses to guess. - Audit report — return an
EntitlementAuditReportcarrying the decision, the reason, and the normalised inputs it was made against. Persist it.
Full procedure: see
references/workflows.md. Standards reference: seereferences/standards.md. Printable pre-flight checklist: seeassets/checklist.md.
Common Pitfalls
- One firm-wide non-display flag. A boolean licensed by the CME desk will happily authorise a Nasdaq depth feed it has no rights to. Non-display fees and reporting "vary depending upon the Nasdaq data product", are charged per DCM at CME Group, and are declared per segment and level at LSE. Model the entitlement as (venue, depth, activity category) or the gate approves breaches.
- Treating a display entitlement as covering the algo. Nasdaq Basic is display-only — "Non-Display Usage is NOT included". Non-display is fee-liable regardless of whether the OMS/EMS runs in the cloud, in a datacenter, or on a desktop, so pointing a strategy at a desktop-tier feed does not make it display use.
- Falling through on an unrecognised usage type. A gate that compares
usage_typeto one literal and does nothing in theelsewill approveNON_DISPLAY,NONDISPLAY_ALGOandalgoas if they were display use. An unclassified usage cannot be shown to be licensed; refuse it. - Skipping expiry when no expiry is recorded. "No expiry on file" is not "licence valid forever". Either populate the date from the Order Form or accept — visibly, via the logged warning — that the term is unenforced for that venue.
- Placeholder expiry dates. A hard-coded far-future date authorises everything until the day it passes, then denies every venue at once, mid-session.
- Declaring a bot as Non-Professional to cut the monthly bill. Only natural persons can qualify, and an account held in an organisation's name is Professional even when one human uses it personally. The correction arrives as retroactive professional-rate fees on the distributor.
- Attesting Non-Professional status once and never again. Retired and inactive professionals must re-verify semi-annually under CTA policy; a never-refreshed attestation quietly becomes false.
- Assuming CME Group is one venue. Automated trading using additional DCMs
requires additional Category A licensing.
CMEin your config is notNYMEX.
Verification
- Instantiate
MarketDataEntitlementEngine. Build aPROFESSIONAL,ORGANISATIONprofile holding two entitlements:CMEatL2withnon_display_categories=("PRINCIPAL",)expiring2026-12-31, andNASDAQatL1with no non-display categories. - Request
CME/L2/NON_DISPLAY_ALGO/PRINCIPALatas_of_date=date(2026, 6, 15)$\implies$ENTITLEMENT_APPROVED. - Request
NASDAQ/L1/NON_DISPLAY_ALGO$\implies$ENTITLEMENT_DENIED_MISSING_NON_DISPLAY_LICENSE— the CME non-display licence does not travel. - Request
CME/L3$\implies$ENTITLEMENT_DENIED_UNLICENSED_DATA_LEVEL. - Request
CMEwithnon_display_category="CLIENT_FACILITATION"$\implies$ENTITLEMENT_DENIED_MISSING_NON_DISPLAY_LICENSE. - Request
usage_type="NON_DISPLAY"$\implies$ENTITLEMENT_DENIED_UNRECOGNISED_USAGE_TYPE, not an approval. - Request under a different
user_idthan the profile's $\implies$ENTITLEMENT_DENIED_SUBSCRIBER_MISMATCH. - Evaluate with
as_of_dateone day past the expiry $\implies$ENTITLEMENT_DENIED_EXPIRED_LICENSE; on the expiry date itself $\implies$ approved. - Run
python -m unittest discover -s skills/market-data-entitlement-and-licensing-per-venue/scripts.