It is possible to place trades on a master account and have them allocated out to a number of sub accounts. The typical use case is a money manager with discretionary mandate who would like to buy a position in a particular stock for several of his/her clients. Instead of making individual trades on each of the client accounts, the money manager makes a single block trade and lets the Saxo trading system allocate the block trade to the individual client accounts.
The steps for doing so is roughly:
- Determine the total amount needed to cover all of the client accounts.
- Specify a rule (an allocation key) which will determine how the total amount is to be allocated out over the various client accounts.
- Make the trade and specify the allocation key to be used when the orders are filled.
The Saxo execution engine then takes care of filling the order in the market, and allocating the positions according to the rules specified in the allocation key.
OpenAPI supports two aspects of allocation key support:
- the trade/v1/allocationkeys endpoint allows the calling application to specify an allocation key.
- the trade/v1/orders and trade/v2/orders endpoints allows the calling application to specify which allocation key to use as the basis for the distribution.
Block trading is only possible on specially configured accounts. To get an account configured for block trading, the account owner must contact their Saxo Bank account manager.
The Saxo Github repository contains a code sample on creating the allocation and using is for ordering.
Defining Allocation Keys
Allocation keys are defined in the POST /trade/v1/allocationkeys endpoint. Allocation keys are "owned" by the client of the logged in user, so several users under the same client will share the same list.
An allocation key comprises a data structure along with an array of ParticipatingAccountsInfo. There should be one entry in the ParticipatingAccountsInfo array for each of the accounts onto which the block trade should be allocated.
About AllocationKeyAccountInfo
There must be one entry in the ParticipatingAccountsInfo array for each of the accounts onto which the block trade should be allocated. Each entry is defined as follows:
If AllocationUnitType is 'Percentage' then the sum of UnitValues in the ParticipatingAccountsInfo array must add up to 100. If AllocationUnitType is 'Unit" then the amount of the block trade is expected to add up to a multiple of the sum of UnitValues.
If the order amount does not match a multiple of the sum of UnitValues then any remainder will be distributed onto accounts for which the "AcceptRemainderAmount" has been set to true.
Accounts with "AcceptRemainderAmount" must also have a unique priority. In situations where orders are partially filled, then the Priority field is used to determine in what order any remaining amounts are added to each account.
While our allocation system is quite flexible and able to handle remainders etc. it is highly recommended that you ensure that the sum of amounts in the allocation key matches the order amount. This is easy to do by specifying onetime allocation keys.
There must be at least one entry in the ParticipatingAccountsInfo array, with the AcceptRemainderAmount field is set to true!
The list of entries in the ParticipatingAccountsInfo array must only include accounts belonging to underlying clients. It must not include accounts belonging directly to the client of the user creating the allocation key.
Managing Allocation Keys
You can use the GET /trade/v1/allocationkeys endpoints to get allocation keys and the DELETE /trades/v1/allocationkeys endpoint to invalidate them. Often an allocation key is not actually deleted, as the key could already have been used. For this reason it is not possible to modify an existing allocationkey. To "change" an allocation key you simply call POST to create a new allocation key, setting AllocationKeyName to the value of the key you want to modify. It is possible to create several allocation keys with the same AllocationKeyName. If you only want one active allocation key with the same AllocationKeyName, it is up to your application to delete other instances with the same AllocationKeyName.
We will later introduce a way to simulate the update of an existing allocation key, in effect
a) Creating a new key with the same AllocationKeyName
b) Invalidating the existing allocation key
c) Returning a new AllocationKeyId
About AllocationKey Status
An allocation key can take on one of three status values:
When creating a new key:
- If you specify "OneTime" = true then the status will be "OneTime".
- If you specify "OneTime" = false then the status will be "Active".
A "OneTime" allocation key is intended to be used only once. A typical usage scenario is the one outlined in the introduction, where a money manager would like to define a particular allocation to support a particular trade.
A "OneTime" allocation key:
- Will not be returned when you do a "GET..." to receive the list of allocationkeys, unless you include "OneTime" in statuses field fo the request,
- Can however be retrieved if you know the key id by calling GET .../{allocationkeyid}
- Maybe be removed by the system, if it has not been used for any trade within one week of it's creation.
An "Active" allocation key is intended to be used more than once. These are the type of keys, which you will typically administer in a trading platform. For example a money manager may have defined a key, which always distributes 10% of the total trade amount equally between 10 of his clients etc.
A "normal" or "Active" allocation key:
- Will be returned when you do a GET ..." to retrieve the list of allocation keys.
- Will not be removed by the system even if has not been used.
Using AllocationKeys when Trading
It is very simple to use an allocation key. Simply set the the AllocationKey property on an order to the Id of the key you want to use. You can use allocation keys with any type of order, from simple stand alone orders to entry orders with related stop/limit orders.
Allocation is done as a two step process:
- First the order is placed on the block trading account, and then allocated out to the participating accounts. If you inspect the port/orders resource for all participating accounts, you will find the allocated orders on the individual accounts. The allocated orders will have their CorrelationKey property set to that of the order placed on the block trading account.
- Then, when the order is executed, the trade is first placed on the block trade account and then allocated out. The resulting positions will also have their CorrelationKey set to that of the original order.
Sample
The following sample illustrates how to:
- Define two different allocation keys
- Use those keys to place a couple of trades on a block account
Sample Ownership Structure
The sample will work on the following client and account structure:
Notice, how in addition to the BlockTrade8393 account, there is also an ERROR_8393 account. This account is to hold any amounts, which cannot be distributed, when there is a mismatch between the size of the order being placed and the sum of units in the ParticipatingAccountsInfo array.
With the following client and account keys:
ClientId | ClientKey | AccountId | AccountKey |
---|---|---|---|
8328393 - AllocationKey Demo | BFDhvYIvyfFNeBW6zgsiZA== | BlockTrade8393 | LDC3XwbK1pQOp9igdanlzQ== |
8328394 - Test Client 1 | FrZAnfQg8dyVMQC3l47-MQ== | Demo_8328394 | SeZ92W8Z-LBMILUTWZtmpw== |
8328395 - Test Client 2 | WfDEUlg5K-RIH8-fqCCDhA== | Demo_8328395 | Z2sNFkNXjm-hbP2fBsyizg== |
8328424 - Test Client 3 | 6qLc-DhHJTeGNIk9EkH8-Q== | Demo_8328424 | w500reaC177EHgaRs7NBOQ== |
Defining allocation keys
Define an allocation key which:
- Is a "OneTime" allocationKey.
- Will distribute a trade of a total amount 60.000 so into 10.000, 20.000 and 30.000 across the three sub accounts.
- Will fail if any of the accounts do not have enough margin hold the amount to be allocated.
- Will distribute any amount over 60.000 to the first account
POST /trade/v1/allocationkeys { "AllocationKeyName": "10-20-30", "AllocationUnitType": "Unit", "MarginHandling": "Reject", "OneTime": true, "OwnerAccountKey": "LDC3XwbK1pQOp9igdanlzQ==", "ParticipatingAccountsInfo": [ { "AcceptRemainderAmount": true, "AccountKey": "SeZ92W8Z-LBMILUTWZtmpw==", "Priority": 1, "UnitValue": 10000 }, { "AcceptRemainderAmount": false, "AccountKey": "Z2sNFkNXjm-hbP2fBsyizg==", "Priority": 2, "UnitValue": 20000 }, { "AcceptRemainderAmount": false, "AccountKey": "w500reaC177EHgaRs7NBOQ==", "Priority": 3, "UnitValue": 30000 } ] } Returns: 201-Created: { "AllocationKeyId": "6014" }
Define another application keys which:
- Is a "OneTime" allocationKey.
- Will distribute a trade of a total amount 60.000 so into 10.000, 20.000 and 30.000 across the three sub accounts.
- Will fail if any of the accounts do not have enough margin hold the amount to be allocated.
- Will distribute amounts above 60000 to the first two accounts according to the specified priority.
POST trade/v1/allocationkeys { "AllocationKeyName": "10-20-30WithRemainder", "AllocationUnitType": "Unit", "MarginHandling": "Reject", "OneTime": true, "OwnerAccountKey": "LDC3XwbK1pQOp9igdanlzQ==", "ParticipatingAccountsInfo": [ { "AccountKey": "SeZ92W8Z-LBMILUTWZtmpw==", "AcceptRemainderAmount": true, "Priority": 2, "UnitValue": 10000 }, { "AccountKey": "Z2sNFkNXjm-hbP2fBsyizg==", "AcceptRemainderAmount": true, "Priority": 1, "UnitValue": 20000 }, { "AcceptRemainderAmount": false, "AccountKey": "w500reaC177EHgaRs7NBOQ==", "Priority": 3, "UnitValue": 30000 } ] } Returns: 201-Created { "AllocationKeyId": "6015" }
Define another allocation key which:
- Is a regular "active" allocation key
- Which will distribute trades on a percentage basis
- Will reduce the amount traded to accommodate for margin restrictions on some of the accounts.
- Will place any remainder on the first account.
POST /trade/v1/allocationkeys { "AllocationKeyName": "25-35-40 Pct", "AllocationUnitType": "percentage", "MarginHandling": "Reduce", "OneTime": false, "OwnerAccountKey": "LDC3XwbK1pQOp9igdanlzQ==", "ParticipatingAccountsInfo": [ { "AcceptRemainderAmount": true, "AccountKey": "SeZ92W8Z-LBMILUTWZtmpw==", "Priority": 1, "UnitValue": 25 }, { "AcceptRemainderAmount": false, "AccountKey": "Z2sNFkNXjm-hbP2fBsyizg==", "Priority": 2, "UnitValue": 35 }, { "AcceptRemainderAmount": false, "AccountKey": "w500reaC177EHgaRs7NBOQ==", "Priority": 3, "UnitValue": 40 } ] } Returns: 201-Created: { "AllocationKeyId": "6016" }
Using an AllocationKey
So lets use the first allocation key to buy 60.000 EURUSD and have them allocated out.
POST trade/v2/orders { "AccountKey": "LDC3XwbK1pQOp9igdanlzQ==", "AllocationKeyId": "6014", "Amount": 60000, "AssetType": "FxSpot", "BuySell": "Buy", "OrderDuration": { "DurationType": "DayOrder" }, "OrderType": "Market", "ManualOrder": true, "Uic": 21 } Returns: { "OrderId": "70423019" }
Notice how you get a number of trade messages. The first first messages pertain to the original order which is placed and the immediately filled. The second two documents that first the order and then the positions are allocated according to the key specification.
If instead I had specified Amount:65.000 (which is more than the total of 60.000), then the 60.000 will be allocated to the three accounts. The remaining 5000 will be placed on the first account (for at total amount of 15.000).
If on the other hand I had used the second allocationKey the remaining 5000 would be distributed between the two accounts, which had "AcceptRemainderAmount" set to true.