Skip to main content

Venue retention

Set how many years a venue keeps its trades and orders, preview the monthly run, read the append-only archive, and hold records back with a legal hold.

A venue collects every order, order event and trade it ever handled. Retention sets how many years those records stay at the venue, and a monthly run then moves the expired ones into an append-only archive, which keeps them with no end date, before deleting them from the venue. A legal hold keeps any part of that history out of the run until it is released.

The period and the preview

Each venue carries one retention period: a whole number of years from 1 to 100, or none. A venue starts with none, which keeps every record forever and archives nothing. GET /api/v2/addons/trading-venues/{venueAddress}/retention-policy answers the stored period:

{
  "data": {
    "venueAddress": "0x7f3c2b5e8a1d4c6f9b0e2a5d8c1f4b7e0a3d6c9f",
    "retentionYears": 7
  },
  "links": {
    "self": "/api/v2/addons/trading-venues/0x7f3c2b5e8a1d4c6f9b0e2a5d8c1f4b7e0a3d6c9f/retention-policy"
  }
}

A member of the organisation can read the period. Changing it is PUT to the same route with retentionYears and walletVerification, and needs the venue admin role and a wallet verification. On a venue whose Trading venues row under “Approvals” on the “General” page of “Organisation settings” is on, the write answers with a venue configuration approval whose commandType is venue-retention-policy. A second venue admin decides it, the period changes when it is applied, and the database refuses a decision from the admin who proposed it. With the row off, the period changes at once and the write answers with the applied policy.

A period deletes records, so the Console asks for a preview before it saves one. GET .../retention-policy/preview?retentionYears=7 answers what the next run would archive and delete if that period were in force:

{
  "data": {
    "venueAddress": "0x7f3c2b5e8a1d4c6f9b0e2a5d8c1f4b7e0a3d6c9f",
    "retentionYears": 7,
    "orders": 18422,
    "orderEvents": 96031,
    "trades": 12760
  },
  "links": {
    "self": "/api/v2/addons/trading-venues/0x7f3c2b5e8a1d4c6f9b0e2a5d8c1f4b7e0a3d6c9f/retention-policy/preview"
  }
}

The counts apply the same eligibility the run uses, so they leave out records a legal hold covers and orders that a trade, a delivery, a staged fill or an active reservation still needs. The preview reads and changes nothing, and it needs the venue admin role.

In the Console, Data retention on the venue's Listing rules page holds “Retention period (years)”, an empty field that reads “Keep forever”, a “Preview” that prints the counts, and “Save retention period”. While a changed numeric period has not been previewed, the save stays disabled and the panel warns that older records are copied to the archive and then deleted from the venue. A save on a maker-checker venue reads “Your change is held for approval. The retention period stays as it is until another venue admin approves it.” and shows the current and proposed period.

What the monthly run removes

The run starts at 03:15 UTC on the first of each month and takes each venue on its own. A venue that fails is logged and retried at the next occurrence, and the other venues still run. The cutoff is the period subtracted from the run's date.

A trade leaves when it is delivered or undone, it executed before the cutoff and last changed before it, and no delivery of it is still unresolved. Its fee lines and its resolved delivery travel with it into the archived record.

An order leaves when it is closed, it was created and last changed before the cutoff, and no trade, delivery, staged fill or active reservation still refers to it. Its released reservation goes into its archived record, and its order events leave with it. An event that belongs to no order, such as a session transition, stays.

A record is deleted only when the archive holds it with the same payload. A record the archive already holds with a different payload stays at the venue, and the run counts it as a mismatch.

Each archived record names every participant it concerns: the maker and the recipient of an order and of its events, and the makers and recipients of both orders of a trade. A later hold or a search can therefore find a record by wallet.

What the archive holds

The archive keeps one append-only record set per record kind, keyed by organisation, venue and the source id, and each row carries the venue, the instrument, the participants, when the record happened, the payload and the time it was archived. The payload is the source row as JSON with every top-level number written as a string, so no numeric value loses precision. The platform refuses to update, delete or truncate an archived record. The archive lives in the operator's PostgreSQL database, so the database owner's own controls protect it beyond that.

A batch works on one instrument at a time, trades before orders. It takes the venue's retention lock, reads the holds in force, locks up to 500 expired rows in key order while skipping rows another transaction already holds, archives them, and deletes exactly the rows the archive now holds with that payload, checking eligibility again under the lock. Placing a hold takes the same lock, so a hold recorded before a batch starts is honoured by that batch.

Read and export the archive

GET /api/v2/reporting/venues/{venueAddress}/archived-records pages one venue's records oldest first. It takes from and to on the record's own time, kind as order, order-event or trade, a limit and a cursor, and answers the page with meta.nextCursor for the next one. A cursor the archive did not return is refused with a bad request.

GET .../archived-records/export streams the same filter as a CSV file, one row per record with the payload as a JSON string, and records the export in the request audit trail.

A reader is an organisation owner, a platform administrator, or a caller whose acting wallet holds a reporting role on the organisation's system. The caller must also have a wallet with the venue operator or venue admin role on that venue. A caller who does not operate the venue on the selected network gets venue not found, and so does a venue address that the network does not hold.

A legal hold keeps matching records out of every later run. POST /api/v2/reporting/venues/{venueAddress}/legal-holds takes a marketId, a participantAddress, a fromAt, a toAt and a required reason, and a hold with none of those bounds covers the whole venue. An instrument the venue does not list is refused, and a participant or time bound is recorded as sent, so a mistyped wallet produces a hold that matches nothing and protects nothing. The window is half open: a record at fromAt is held, a record that starts at toAt is not, and a window must start before it ends. A trade is placed in the window by its execution time. An order counts from its creation to its last change, so an order alive at any point in the window is held, and its events stay with it.

A participant hold covers the orders and order events where that wallet is the maker or the recipient, and the trades where either order is its own or pays it.

Only an organisation owner or a platform administrator can place or release a hold, acting on a wallet that operates or administers the venue. GET .../legal-holds lists the venue's holds with the scope, the reason, and who placed, asked to release and released each one.

Releasing a hold follows the organisation's approval policy: the Reporting row under “Approvals” on the “General” page of “Organisation settings”. That row is off unless an organisation turns it on.

  • With the row on, a release takes two people. POST .../legal-holds/{holdId}/release-requests records the requester and the reason, and a second request while one waits is refused with 409. POST .../legal-holds/{holdId}/release-decisions takes approve or reject. The requester cannot approve their own request, which answers 403.
  • With the row off, the request releases the hold at once. The answer carries releasedAt, and releasedBy reads approval-policy-waiver, so the stored hold shows the policy as the releaser. An approval of a request that was already waiting releases the hold whoever gives it.

On either setting, a rejection clears the request and the hold stays active. A decision on a hold with no waiting request answers 409, a hold that is already released refuses another request with 409, and a hold id the venue does not hold answers 404. A session acting as another user is refused on both release routes with 403, because one person could otherwise be the requester and the approver. It is refused the same way when it places a hold, because a hold carries the acting user's own signature and the hold would name the impersonated user as its placer. A platform administrator places and releases holds from their own session.

The Console path for both is the Legal holds tab of the venue. Legal holds covers that sheet, its labels and its states, and Trading Venue covers the orders, events and trades the archive holds.

Was this page helpful?