This article documents how pre-trade disclaimers are implemented in OpenAPI and what it takes to properly handle them in your own application. For an overview of when pre-trade will start being enforced, please see this page: Breaking Change - Pre-Trade Disclaimers on OpenAPI
What are pre-trade disclaimers?
Pre-trade disclaimers are disclaimers that have to be shown and accepted before an order can be placed. Saxo's platforms have supported this for a while, so you might be familiar with them already. They are shown after the "Place order" button is clicked, and look similar to this:
Once accepted the order is placed by the platform.
Several overall types of pre-trade disclaimers exist:
- Blocking disclaimers - These disclaimers can be shown, but not accepted. Essentially they block the trade from being placed.
- Normal disclaimers - These can be accepted and usually won't have to be accepted again unless the content of the disclaimer changes.
- Recurring disclaimers - These can be accepted, but will have to be accepted before every order placed.
It can also vary what accepting a disclaimers means. In the screenshot above it's simply clicking the Accept button, but that's not always the case since several types of acceptance criteria exists:
- Simple accept - User has to click a button to accept the disclaimer.
- Accept with checkbox confirmation - the user has to tick a checkbox before the buttons are enabled.
- Accept with user input - the user has to type a specific sentence before the buttons are enabled.
The criteria for when a pre-trade disclaimer has to be shown can also vary. Common examples of when they are required are:
- When a user is deemed as not appropriate for the instrument they are trying to trade.
- When an exchange requires the user to accept the trading rules before trading on this exchange.
- General market conduct rules are updated by Saxo.
Overall requirements
Supporting pre-trade disclaimers requires a change to how order placement is done via your application. Overall it requires four steps:
- Call the order pre-check endpoint to get a list of required disclaimers (or attempt to place the order and receive an error due to outstanding disclaimers).
- Call the disclaimer service to get the relevant details of each required disclaimer.
- Present the disclaimers in the correct way to the user of the application and send their response to the disclaimer back to the disclaimer service.
- Place the order as usual.
In the case of no disclaimers being present, everything will work exactly like it does today; where after calling the pre-check endpoint and not receiving any required disclaimers, the order endpoint can be called immediately.
Until all outstanding disclaimers have been properly handled as described above, it will not be possible to place the order.
1. Call the order pre-check endpoint to get a list of required disclaimers
There is no change to the request contract for the pre-check endpoint, so the request should be done exactly like it is today:
POST trade/v2/orders/precheck { "AccountKey": "LZTc7DdejXODf-WSl2aCyQ==", "Uic": 211, "OrderType": "Market", "...": "..." }
But now the response will include a list of required disclaimers if relevant for the order you are trying to place:
{ "PreCheckResult": "Ok", "EstimatedCashRequired": 1500.0, "EstimatedCashRequiredCurrency": "EUR", "...": "...", "PreTradeDisclaimers: { "DisclaimerContext": "bbe4ad5484bd2ef73e831e2b557c1f336077ce58e3260dca3214ed30eb29f4e6", "DisclaimerTokens": [ "token1234", "token4567", ] }
The DisclaimerContext is a representation of the specific order pre-checked, while each DisclaimerToken represents a single disclaimer that has to be shown to the user. Please beware that the DisclaimerToken is also specific to the order it's returned for, so you cannot make any assumptions about which disclaimer they represent by comparing DisclaimerTokens.
2. Call the disclaimer service to get the relevant details of each required disclaimer.
With the DisclaimerContext and the list of DisclaimerTokens, fetch the details for each disclaimer via the disclaimer service:
GET dm/v2/disclaimers?DisclaimerTokens=token1234,token4567
This will return details for all requested disclaimers:
{ "__count": 2, "Data": [ { "Body": "<h2 class=".h2">Malaysian Ringgit declaration</h2><p>You are trading an instrument that may involve the [...]", "Conditions": [], "DisclaimerToken": "token1234", "IsBlocking": false, "ResponseOptions": [ { "Label": "Accept", "ResponseType": "Accepted" }, ], "Title": "Malaysian Ringgit declaration" }, { "Body": "<h2 class=".h2">Disclaimer Example</h2><p>This is an example disclaimer [...]", "Conditions": [], "DisclaimerToken": "token4567", "IsBlocking": false, "ResponseOptions": [ { "Label": "Accept", "ResponseType": "Accepted" }, ], "Title": "Sample Disclaimer" } ] }
3. Present the disclaimers in the correct way to the user of the application and send their response to the disclaimer back to the disclaimer service.
These are common types of disclaimers you need to be able to handle. Please note that other combinations of fields are possible, and a single disclaimer can be a combination of the below. For example, it can both be dismissable and require a checkbox and user input.
Blocking DisclaimerThis is identified by having "IsBlocking: true" in the disclaimer details. This disclaimer type doesn't allow any responses and means the order will not be allowed to be placed. The reason for the block is stated within the disclaimer text, so it should be presented to the user of your application along with a button to close the disclaimer without proceeding with the trade. | |
Basic disclaimerThis is identified by having no conditions returned in the "Conditions" array. This type of disclaimer should be presented to the user, and it should be validated that the user has seen the full disclaimer text before enabling any of the response options. This means that if the disclaimer text is shown with a scrollbar, it should be validated that the user has scrolled to the bottom before they can send a response. | Single response option: Multiple response options: |
Disclaimer requiring additional action from the userThis is identified by having one or more conditions returned in the "Conditions" array. The type of the condition can be either "Checkbox" or "UserInput", and it's rare that more than one condition is used at the same time. | Checkbox: User Input: |
Dismissable disclaimerThis is identified by having the "DismissableUntil" field returned in the disclaimer details, which will indicate the last date (inclusive) that the user can respond with the "Dismiss" response type. The purpose of this disclaimer is to allow the user to properly read and make a decision on the disclaimer at a more convenient time. |
For each disclaimer, call the disclaimer service again to register the users response:
POST dm/v2/disclaimers/responses { "DisclaimerContext": "bbe4ad5484bd2ef73e831e2b557c1f336077ce58e3260dca3214ed30eb29f4e6", "DisclaimerToken": "token1234", "ResponseType": "Accepted" }
Testing pre-trade disclaimers in SIM
To allow testing all types of disclaimers, you can create a dedicated SIM user on this page: https://www.developer.saxo/openapi/learn/Disclaimer-User-Signup.
This user will always get a specific type of disclaimer returned, depending on which Exchange you place an order on. The different kinds of disclaimers that can be returned are:
Disclaimer Type | Exchange | UIC Example |
---|---|---|
Basic Disclaimer | NASDAQ | 211 (Apple) |
Multiple Responses Disclaimer | NYSE | 307 (Coca Cola) |
Checkbox disclaimer | AMS | 1636 (ASML) |
User Input disclaimer | CSE | 15629 (Novo) |
Dismissable disclaimer | LSE_SETS | 899 (Vodafone) |
Blocking Disclaimer | PAR | 112813 (LVMH) |
You can also test all of the above disclaimer types using our sample available here: https://orange-sky-0fa4ba403.5.azurestaticapps.net/samples/disclaimers or log in with the user to SaxoTraderGO (https://www.saxotrader.com/sim) and see how these disclaimers are presented by Saxo.