Skip to content

Data Vendor Contractual Usage Restriction Tracking

data-vendor-contractual-usage-restriction-trackingsource

Use when an internal system asks for vendor market data and the firm must decide whether that purpose is inside the licensed scope: use case, non-display entitlement, redistribution and seat caps, failing closed with a reason.

Version
2.0.0
Reading
5 min
Hands off to
3
Handed off from
10
License
Apache-2.0
CoversLSEG DACS (formerly Refinitiv DACS)Bloomberg EMRSNasdaq Global Data AgreementPython Dataclasses

When to Use

Use this skill when an internal system — a research notebook, a risk engine, an execution algo, a client-facing portal — asks for vendor market data, and the firm must decide whether that specific purpose is inside the scope it actually licensed (Bloomberg B-PIPE, LSEG Real-Time / DACS, ICE Data Services, S&P Capital IQ).

The gate exists because licensing breaches are discovered late and priced retroactively. Under the Nasdaq Global Data Agreement, any use of the Information not already provided for in the Nasdaq Requirements — expressly including derived information, retransmission, redistribution and index calculation — requires prior written approval and payment of the applicable fees (GDA s.4(c)). Nasdaq may audit a Distributor's records, reports and systems, normally no more than once in twelve months (s.7(a)). Where a Final Audit finds underreporting, the amounts plus interest are due within sixty days, and for a good-faith error the Distributor's liability reaches back three years (s.7(e)); underreporting of 10% or more of reported Reportable Units also makes the Distributor liable for Nasdaq's audit, legal and administrative costs (s.7(f)). Other venues and vendors impose their own audit clauses on comparable terms — read yours.

When NOT to Use

  • Not a fee calculator. It counts contractual seats, not fee-liable units. Its seat counter cannot produce a vendor invoice or an exchange usage declaration — see the unit-of-count pitfall below.
  • Not a replacement for the vendor's entitlement system. Bloomberg EMRS and LSEG DACS enforce permissioning at the feed itself. This gate sits upstream of them and does not remove the need to configure them correctly.
  • Not for venue-level entitlement or subscriber classification. Professional vs non-professional status, per-venue licences and real-time vs delayed tiers belong to market-data-entitlement-and-licensing-per-venue and real-time-vs-delayed-data-entitlement-handling.
  • Not a legal opinion. It enforces the scope a compliance owner has encoded. Reading the contract and encoding it correctly is still a human job.

Prerequisites

  • VendorContractSpec: vendor_id, vendor_name, license_tier, allowed_use_cases, is_non_display_allowed, is_redistribution_allowed, max_concurrent_entitlements, current_active_entitlements (default 0), contract_expiration_date (ISO-8601 YYYY-MM-DD, or None for "not tracked").
  • DataAccessRequest: request_id, vendor_id, requested_by_system, use_case_type, is_external_redistribution, requested_seats (default 1).
  • A durable store for the returned VendorUsageAuditReport objects. The engine's in-memory buffer is bounded and is not the retained audit record.

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 restriction.

  1. Contract term gate — if as_of_date is past contract_expiration_date, deny with CONTRACT_EXPIRED. Checked first because a lapsed term withdraws every other permission. A contract registered with contract_expiration_date=None is not gated on expiry; the engine logs a warning once per vendor so the omission is visible rather than silent.
  2. External redistribution gate — deny with REDISTRIBUTION_LICENSING_VIOLATION when the request is external redistribution and the contract does not permit it. A request counts as redistribution if either is_external_redistribution is True or use_case_type == "EXTERNAL_REDISTRIBUTION"; the two signals can disagree, and this is the breach with the longest back-fee tail, so it fails closed on either one alone.
  3. Non-display gate — if use_case_type == "NON_DISPLAY_TRADING" and is_non_display_allowed is False, deny with NON_DISPLAY_LICENSING_VIOLATION. Non-display means machine access without a natural person reading a display; it is fee-liable whether the engine runs on a desktop, in a datacenter or in the cloud.
  4. Licensed scope gate — if the normalised use_case_type is not in allowed_use_cases, deny with UNAUTHORIZED_USE_CASE_VIOLATION. Unlisted means unlicensed: never widen the list to make a request pass.
  5. Concurrency headroom gate — if current_active_entitlements + requested_seats would exceed max_concurrent_entitlements, deny with CONCURRENCY_CAP_EXCEEDED. A request landing exactly on the cap is approved.
  6. Reserve and record — on approval the seats are reserved against the contract and a VendorUsageAuditReport is returned. Denials never mutate contract state. When the consuming system disconnects, call release_entitlement(vendor_id, seats).

Full procedure: see references/workflows.md. Standards reference: see references/standards.md. Printable pre-flight checklist: see assets/checklist.md.

Common Pitfalls

  • Approving without ever releasing. Every approval reserves seats permanently until release_entitlement returns them. A gate wired into connection setup but not into teardown drifts into denying compliant requests within hours, and the usual "fix" is to raise the cap above what the contract actually licensed.
  • Reading the seat counter as a reportable unit count. 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. A per-request seat counter will understate it. Derive declarations from your infrastructure inventory.
  • Assuming "derived" means "unrestricted". Derived Data is information that cannot be reverse-engineered back into Exchange Information or into a recognisable substitute for it. A client-facing chart of vendor quotes, a redistributed index recalculated from them, or a "summary" from which the underlying prices can be recovered is not derived data — it is redistribution, and GDA s.4(c) requires prior written approval and fees before it happens.
  • Trusting one of two disagreeing signals. A caller that sets use_case_type="EXTERNAL_REDISTRIBUTION" but leaves is_external_redistribution False is still redistributing. Gate on both.
  • Placeholder expiry dates. A hard-coded future contract_expiration_date authorises everything until the day it passes and then denies everything at once. Populate it from the executed contract or leave it None and track expiry elsewhere.
  • Running desktop-terminal data through an algo. A research desktop subscription does not carry non-display rights; pointing an automated strategy at it is a licensing breach regardless of how the bytes reached the process.

Verification

  • Instantiate VendorUsageRestrictionEngine. Register a B-PIPE-style contract (is_non_display_allowed=True, is_redistribution_allowed=False, max_concurrent_entitlements=10, current_active_entitlements=2, contract_expiration_date="2027-12-31").
  • Submit an internal HFT request (use_case_type="NON_DISPLAY_TRADING", is_external_redistribution=False) $\implies$ APPROVED, active_entitlements_remaining == 7.
  • Submit a client-portal request with is_external_redistribution=True $\implies$ REDISTRIBUTION_LICENSING_VIOLATION, is_approved False, and the contract's current_active_entitlements unchanged.
  • Submit use_case_type="EXTERNAL_REDISTRIBUTION" with is_external_redistribution=False $\implies$ still REDISTRIBUTION_LICENSING_VIOLATION.
  • Evaluate with as_of_date past the expiry $\implies$ CONTRACT_EXPIRED.
  • Run python -m unittest discover -s skills/data-vendor-contractual-usage-restriction-tracking/scripts.

Verify it, from the repository root

python -m unittest discover -s skills/data-vendor-contractual-usage-restriction-tracking/scripts

Hands off to 3

Skills this document names, usually in When NOT to Use, as the owner of a case it excludes.

Handed off from 10

Skills that name this one as the place a case belongs. The reverse edges of the graph.