Public REST API
Overview
The DerivaDEX APIs provide readonly access to exchange data and are organized into two main categories:
- Public Stats REST API: Provides statistical data, trader information, market aggregations, and system information
- Public Exchange REST API: Provides real-time market data, order book information, and trading-related endpoints
All endpoints return JSON responses and support various query parameters for filtering and pagination.
Rate Limiting
Please be respectful with API usage. While there are no strict rate limits currently enforced, excessive usage may result in temporary restrictions.
Support
For API support and questions, please refer to the DerivaDEX documentation or contact the development team.
Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
System
These APIs return system info.
Get Exchange Info
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/exchange_info',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/exchange_info', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/exchange_info',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/exchange_info
Get global exchange configuration
Example responses
200 Response
{
"value": {
"settlementsInfo": [
{
"type": "epoch",
"durationValue": "5",
"durationUnit": "minute"
}
],
"assets": [
"USDC"
],
"symbols": [
{
"symbol": "ETHP",
"tickSize": "0.1",
"maxOrderNotional": "1000000",
"maxTakerPriceDeviation": "0.02",
"minOrderSize": "0.0001",
"kind": "SingleNamePerpetual"
}
]
},
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Exchange info data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Exchange Info API
| Name | Type | Required | Restrictions | Description |
|---|
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » anonymous | object | false | none | none |
| »» value | object | true | none | The value of the response. |
| »»» settlementsInfo | [object] | true | none | A settlement info, contains the specific settlement and the interval value. |
| »»»» type | string | true | none | The type of the settlement. |
| »»»» durationValue | string | true | none | The duration value of this type of settlement. |
| »»»» durationUnit | string | true | none | The duration unit of this type of settlement. |
| »»» assets | [string] | true | none | The assets supported in the exchange. |
| »»» symbols | [object] | true | none | A symbol info, with details of the symbol present in the exchange. |
| »»»» symbol | string | true | none | The symbol name. |
| »»»» tickSize | string | true | none | The tick size of the symbol. |
| »»»» maxOrderNotional | string | true | none | The max order notional of the symbol. |
| »»»» maxTakerPriceDeviation | string | true | none | The max taker price deviation of the symbol. |
| »»»» minOrderSize | string | true | none | The min order size of the symbol. |
| »»»» kind | string | true | none | The type of the symbol. |
| »» success | boolean | true | none | Whether the request was successful |
| »» timestamp | number | true | none | The timestamp of the response |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » anonymous | object | false | none | none |
| »» success | boolean | true | none | none |
| »» errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | [object] | false | none | none |
Enumerated Values
| Property | Value |
|---|---|
| kind | SingleNamePerpetual |
| kind | IndexFundPerpetual |
| kind | FixedExpiryFuture |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Connection Info
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/ping',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/ping', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/ping',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/ping
Simple connectivity test
Example responses
200 Response
{}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | empty object | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Symbols
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/symbols',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/symbols', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/symbols',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/symbols
SEO-friendly alias for tradable products
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| kind | query | integer | false | The type of spec update. Values include: |
| isActive | query | boolean | false | Checks for the active state of the tradable product. Values include: |
| limit | query | integer | false | The number of rows to return |
| offset | query | integer | false | The offset of returned rows |
Detailed descriptions
kind: The type of spec update. Values include: 0: Market 1: SpotGateway
isActive: Checks for the active state of the tradable product. Values include: true false
Enumerated Values
| Parameter | Value |
|---|---|
| kind | 0 |
| kind | 1 |
Example responses
200 Response
{
"value": [
{
"kind": 0,
"symbol": "ETHP",
"name": "ETHP",
"isActive": true,
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tradable products data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Tradable Product API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» kind | number | true | none | The type of setting. Values include: 0: Perpetual Market, 2: Index Market, 3: Quarterly Expiry Future |
| »» symbol | string | true | none | The symbol of the asset for this product. |
| »» name | string | true | none | The corresponding name in the specs setting. |
| »» isActive | boolean | true | none | The state of the tradable product. If true, then this product is available to trade on the exchange, otherwise false. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Server Time
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/time',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/time', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/time',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/time
Get server time for clock synchronization
Example responses
200 Response
{
"serverTime": 1747304089528
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Server time data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » serverTime | number | true | none | none |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Collateral Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/collateral',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/collateral', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/collateral',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/collateral
Returns a rolling sum of collateral per time period grouped by the inflow and outflow types.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| aggregationPeriod | query | string | false | The period for the aggregation. |
| startingValue | query | number | false | The partial total of this aggregation, used for rolling aggregation paging. |
| fromEpoch | query | integer | false | The from epoch |
| toEpoch | query | integer | false | The to epoch |
Enumerated Values
| Parameter | Value |
|---|---|
| aggregationPeriod | week |
| aggregationPeriod | day |
| aggregationPeriod | hour |
| aggregationPeriod | minute |
Example responses
200 Response
{
"nextStartingValue": "34000",
"value": [
{
"timestamp": 1673222400,
"collateral_deposits": "765000000",
"collateral_withdrawals": "-4125604.939779",
"collateral_fees": "-122277.669972",
"collateral_liquidations": "-339878.8954",
"collateral_overall": "760412238.494849"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Collateral aggregation data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Collateral aggregation API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextStartingValue | string,null | true | none | The partial total for this aggregation, which can be passed as startingValue to get the next page for rolling aggregation type APIs. |
| » value | [object] | true | none | The value of the response |
| »» additionalProperties | string | false | none | none |
| »» timestamp | number | true | none | The unix timestamp at the start of the aggregation period. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get DDX Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/ddx',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/ddx', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/ddx',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/ddx
Returns a rolling sum of DDX per time period grouped by the inflow and outflow types.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| aggregationPeriod | query | string | false | The period for the aggregation. |
| startingValue | query | number | false | The partial total of this aggregation, used for rolling aggregation paging. |
| fromEpoch | query | integer | false | The from epoch |
| toEpoch | query | integer | false | The to epoch |
Enumerated Values
| Parameter | Value |
|---|---|
| aggregationPeriod | week |
| aggregationPeriod | day |
| aggregationPeriod | hour |
| aggregationPeriod | minute |
Example responses
200 Response
{
"nextStartingValue": "34000",
"value": [
{
"timestamp": 1669680000,
"ddx_deposits": "2000000",
"ddx_withdrawals": "0",
"ddx_trade-mining-rewards": "0",
"ddx_fees": "0",
"ddx_overall": "2000000"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | DDX aggregation data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the DDX aggregaton API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextStartingValue | string,null | true | none | The partial total for this aggregation, which can be passed as startingValue to get the next page for rolling aggregation type APIs. |
| » value | [object] | true | none | The value of the response |
| »» additionalProperties | string | false | none | none |
| »» timestamp | number | true | none | The unix timestamp at the start of the aggregation period. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Insurance Fund Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/insurance_fund',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/insurance_fund', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/insurance_fund',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/insurance_fund
Returns a rolling sum of insurance fund value per time period grouped by the inflow and outflow types.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| aggregationPeriod | query | string | false | The period for the aggregation. |
| startingValue | query | number | false | The partial total of this aggregation, used for rolling aggregation paging. |
| fromEpoch | query | integer | false | The from epoch |
| toEpoch | query | integer | false | The to epoch |
Enumerated Values
| Parameter | Value |
|---|---|
| aggregationPeriod | week |
| aggregationPeriod | day |
| aggregationPeriod | hour |
| aggregationPeriod | minute |
Example responses
200 Response
{
"nextStartingValue": "34000",
"value": [
{
"timestamp": 1669766400,
"insurance-fund_fees": "99.99534",
"insurance-fund_positive-liquidations": "0",
"insurance-fund_negative-liquidations": "0",
"insurance-fund_deposits": "0",
"insurance-fund_withdrawals": "0",
"insurance-fund_overall": "99.99534"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Insurance Fund aggregation data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Insurance Fund aggregation API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextStartingValue | string,null | true | none | The partial total for this aggregation, which can be passed as startingValue to get the next page for rolling aggregation type APIs. |
| » value | [object] | true | none | The value of the response |
| »» additionalProperties | string | false | none | none |
| »» timestamp | number | true | none | The unix timestamp at the start of the aggregation period. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Epoch History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/epochs',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/epochs', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/epochs',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/epochs
Get epoch timetable and paging cursors
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| epoch | query | integer | false | The epoch boundary used when fetching the next timeseries page. |
| limit | query | integer | false | The number of rows to return |
| offset | query | integer | false | The offset of returned rows |
Example responses
200 Response
{
"value": [
{
"epochId": 100,
"startTime": "2023-01-06T16:37:27.929Z",
"endTime": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Epoch start and end time data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for Epochs API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» epochId | string | true | none | The epoch number. |
| »» startTime | string(date-time) | true | none | The timestamp at which this epoch started. |
| »» endTime | string | true | none | The timestamp at which this epoch ended. This will be null if the epoch is still ongoing. |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | object(date-time) | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | null | false | none | none |
continued
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Insurance Fund History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/insurance_fund',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/insurance_fund', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/insurance_fund',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/insurance_fund
Get insurance fund balance
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | false | The number of rows to return |
| epoch | query | integer | false | The epoch boundary used when fetching the next timeseries page. |
| txOrdinal | query | integer | false | The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch. |
| order | query | string | false | The ordering of the results. |
| symbol | query | string | false | The symbol |
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextEpoch": 100,
"nextTxOrdinal": 3432,
"nextOrdinal": 100,
"value": [
{
"epochId": 100,
"txOrdinal": 3432,
"symbol": "USDC",
"totalCapitalization": "1000000",
"kind": 0,
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Insurance fund capitalization timeseries data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for Insurance Fund API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextEpoch | number,null | true | none | Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch. |
| » nextTxOrdinal | number,null | true | none | Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » nextOrdinal | number,null | true | none | Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» epochId | string | true | none | The epoch in which this transaction occured. |
| »» txOrdinal | string | true | none | The transaction ordinal, within the epoch. |
| »» symbol | string | true | none | The symbol of the insurance fund asset. |
| »» totalCapitalization | string,null | true | none | The total capitalization of the insurance fund after this transaction occured. |
| »» kind | number | true | none | The type of insurance fund capitalization change. Values include: 0: fill, 1: liquidation, 2: deposit, 3: withdrawal |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Specs
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/specs',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/specs', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/specs',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/specs
Get current operator configuration settings
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| kind | query | integer | false | The type of spec update. Values include: |
| limit | query | integer | false | The number of rows to return |
| offset | query | integer | false | The offset of returned rows |
Detailed descriptions
kind: The type of spec update. Values include: 0: Market, 1: SpotGateway, 2: IndexMarket, 3: QuarterlyExpiryMarket
Enumerated Values
| Parameter | Value |
|---|---|
| kind | 0 |
| kind | 1 |
| kind | 2 |
| kind | 3 |
Example responses
200 Response
{
"value": [
{
"kind": 0,
"name": "ETHP",
"expr": "(Market :name \"ETHP\":tick-size 0.1:max-order-notional 1000000:max-taker-price-deviation 0.02:min-order-size 0.0001)",
"value": {
"tickSize": "0.1",
"minOrderSize": "0.0001",
"maxOrderNotional": "1000000",
"maxTakerPriceDeviation": "0.02"
}
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Specs data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Specs API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» kind | number | true | none | The type of setting. Values include: 0: Market, 1: SpotGateway - a group of settings for a particular price feed source, 2: Index Market, 3: Quarterly Expiry Future |
| »» name | string | true | none | The name of the setting. |
| »» expr | string | true | none | A colon seperated set of key value pairs describing the setting |
| »» value | any | true | none | The value of the setting . |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Exchange Status
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/status',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/status', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/status',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/status
Get high-level exchange status information
Example responses
200 Response
{
"value": {
"currentEpoch": "9958",
"latestOnChainCheckpoint": {
"latestOnChainCheckpoint": 9920,
"latestCheckpointTransactionLink": "https://goerli.etherscan.io/tx/0x05f4e74a64b2626af2edc555249484781732508f2096aed0aa52be2d09a51a73"
},
"activeAddresses": "20"
},
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Exchange status data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Exchange Status API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | object | true | none | The value of the response. |
| »» latestOnChainCheckpoint | any | true | none | Information about the latest on-chain checkpoint. Returns null if there haven't been any on-chain checkpoints. |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | object | false | none | Data about the latest on-chain checkpoint. |
| »»»» latestOnChainCheckpoint | number | true | none | The latest on-chain checkpoint number. |
| »»»» latestCheckpointTransactionLink | string,null | true | none | An etherscan link to the latest on-chain checkpoint transaction. |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | null | false | none | none |
continued
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» activeAddresses | number | true | none | The number of active addresses on the exchange. Active addresses are defined as addresses that have deposited, withdrawn, or traded within the last 24 hours or have currently open positions. |
| »» currentEpoch | string | true | none | The latest epoch on the Operator network. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get DDX Supply
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/supply',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/supply', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/supply',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/supply
Get total DDX circulation information
Example responses
200 Response
{
"value": {
"circulatingSupply": "26094663"
},
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | DDX Circulating Supply | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Exchange Supply API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | object | true | none | The value of the response. |
| »» circulatingSupply | string | true | none | The current circulating supply of DDX tokens. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Tradable Products
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/tradable_products',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/tradable_products', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/tradable_products',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/tradable_products
Get list of available trading products
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| kind | query | integer | false | The type of spec update. Values include: |
| isActive | query | boolean | false | Checks for the active state of the tradable product. Values include: |
| limit | query | integer | false | The number of rows to return |
| offset | query | integer | false | The offset of returned rows |
Detailed descriptions
kind: The type of spec update. Values include: 0: Market 2: Index Market 3: Quearterly Expiry Market
isActive: Checks for the active state of the tradable product. Values include: true false
Enumerated Values
| Parameter | Value |
|---|---|
| kind | 0 |
| kind | 2 |
| kind | 3 |
Example responses
200 Response
{
"value": [
{
"kind": 0,
"symbol": "ETHP",
"name": "ETHP",
"isActive": true,
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tradable products data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Tradable Product API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» kind | number | true | none | The type of setting. Values include: 0: Perpetual Market, 2: Index Market, 3: Quarterly Expiry Future |
| »» symbol | string | true | none | The symbol of the asset for this product. |
| »» name | string | true | none | The corresponding name in the specs setting. |
| »» isActive | boolean | true | none | The state of the tradable product. If true, then this product is available to trade on the exchange, otherwise false. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Trade
These APIs provide data for a particular trader.
Get Strategy Fees History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/fees',
params: {
'trader' => 'string',
'strategyId' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/fees', params={
'trader': '0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d', 'strategyId': 'main'
}, headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/fees?trader=0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d&strategyId=main',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/fees
Get maker/taker fee aggregates for a strategy
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | true | The trader address. |
| strategyId | query | string | true | The strategy ID. |
| limit | query | integer | false | The number of rows to return |
| epoch | query | integer | false | The epoch boundary used when fetching the next timeseries page. |
| txOrdinal | query | integer | false | The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch. |
| ordinal | query | integer | false | The ordinal boundary used when fetching the next timeseries page. Must be passed along with epoch and txOrdinal. |
| symbol | query | string | false | The symbol |
| order | query | string | false | The ordering of the results. |
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextEpoch": 100,
"nextTxOrdinal": 3432,
"nextOrdinal": 100,
"value": [
{
"epochId": 100,
"txOrdinal": 3432,
"ordinal": 0,
"amount": "1.0",
"feeSymbol": "USDC",
"symbol": "ETHP",
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Fees timeseries data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Fee API
| Name | Type | Required | Restrictions | Description |
|---|
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » anonymous | object | false | none | none |
| »» nextEpoch | number,null | true | none | Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch. |
| »» nextTxOrdinal | number,null | true | none | Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch. |
| »» nextOrdinal | number,null | true | none | Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| »» value | [object] | true | none | The value of the response |
| »»» epochId | string | true | none | The epoch in which this transaction occured. |
| »»» txOrdinal | string | true | none | The transaction ordinal, within the epoch. |
| »»» ordinal | string | true | none | The ordinal within this particular transaction. |
| »»» amount | string | true | none | The amount of fee paid |
| »»» feeSymbol | string | true | none | The symbol of the fee paid (USDC or DDX) |
| »»» symbol | string | true | none | The symbol of the asset for which the fee was paid. |
| »»» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| »» success | boolean | true | none | Whether the request was successful |
| »» timestamp | number | true | none | The timestamp of the response |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » anonymous | object | false | none | none |
| »» success | boolean | true | none | none |
| »» errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »»» anonymous | [object] | false | none | none |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Strategy Positions
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/positions',
params: {
'trader' => 'string',
'strategyId' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/positions', params={
'trader': '0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d', 'strategyId': 'main'
}, headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/positions?trader=0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d&strategyId=main',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/positions
Get current positions for a strategy
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | true | The trader address. |
| strategyId | query | string | true | The strategy ID. |
| limit | query | integer | false | The number of rows to return |
| offset | query | integer | false | The offset of returned rows |
| symbol | query | string | false | The symbol |
Example responses
200 Response
{
"value": [
{
"trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"symbol": "ETHP",
"strategyIdHash": "0x2576ebd1",
"side": 0,
"balance": "1.0",
"avgEntryPrice": "1500",
"lastModifiedInEpoch": 35
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Positions data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for positions API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» trader | string | true | none | The trader address prefixed with the blockchain discriminant of the trader who owns this position. |
| »» symbol | string | true | none | The symbol of the asset for this position. |
| »» strategyIdHash | string | true | none | The hash of the strategy which owns this position. |
| »» side | number | true | none | The side of the position. Values include: 0: None, 1: Long, 2: Short |
| »» balance | string | true | none | The current balance of this position. |
| »» avgEntryPrice | string | true | none | The average entry price of this position. |
| »» lastModifiedInEpoch | number,null | true | none | The epoch in which this position's balance was last modified. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Strategy
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/strategy',
params: {
'trader' => 'string',
'strategyId' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/strategy', params={
'trader': '0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d', 'strategyId': 'main'
}, headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/strategy?trader=0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d&strategyId=main',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/strategy
Get current state of trader’s strategy
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | true | The trader address. |
| strategyId | query | string | true | The strategy ID. |
Example responses
200 Response
{
"value": {
"trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"strategyIdHash": "0x2576ebd1",
"strategyId": "main",
"maxLeverage": 3,
"availCollateral": "10000",
"lockedCollateral": "1000",
"frozen": false
},
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Strategy data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Strategy API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | any | true | none | The value of the response. |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | object | false | none | Current state of a trader's strategy. |
| »»» trader | string | true | none | The trader address prefixed with the blockchain discriminant of the trader who owns this strategy. |
| »»» strategyIdHash | string | true | none | The hashed version of this strategy ID. |
| »»» strategyId | string | true | none | An identifier for this strategy. |
| »»» maxLeverage | number | true | none | The maximum leverage this strategy is allowed to take on. |
| »»» availCollateral | string | true | none | The amount of collateral that this strategy holds. |
| »»» lockedCollateral | string | true | none | The amount of collateral which has been initiated for withdrawal. |
| »»» frozen | boolean | true | none | Whether this strategy is frozen. Not currently in use. |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | null | false | none | The value will be null if there is no value for the parameters used. |
continued
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Strategy Metrics
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/strategy_metrics',
params: {
'trader' => 'string',
'strategyId' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/strategy_metrics', params={
'trader': '0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d', 'strategyId': 'main'
}, headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/strategy_metrics?trader=0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d&strategyId=main',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/strategy_metrics
Get KPIs and risk metrics for a strategy, like margin fraction, maintenance margin ratio, leverage, strategy available collateral and strategy value.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | true | The trader address. |
| strategyId | query | string | true | The strategy ID. |
Example responses
200 Response
{
"value": {
"marginFraction": "999999999999",
"mmr": "0.05",
"leverage": "3",
"strategyMargin": "6147.5",
"strategyValue": "9233.3"
},
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Strategy metrics data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Strategy Metrics API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | any | true | none | The value of the response. |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | object | false | none | Strategy metrics |
| »»» marginFraction | string | true | none | The current margin fraction of the strategy. |
| »»» mmr | string | true | none | The maintenance margin ratio. The margin fraction of the strategy should be greater than this number, or it may be subject to liquidation. |
| »»» leverage | string | true | none | The current leverage of the strategy. |
| »»» strategyMargin | string | true | none | The amount of unsettled margin and unutilized collateral available for new trades, or as a buffer against losses. |
| »»» strategyValue | string | true | none | The total value of all positions owned by this strategy. |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | null | false | none | The value will be null if there is no value for the parameters used. |
continued
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Trader
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/trader',
params: {
'trader' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/trader', params={
'trader': '0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d'
}, headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/trader?trader=0xb993e587c15a9e0a0fe4f111de98fd6b5ce7067d',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/trader
Get current trader DDX balance and profile
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | true | The trader address. |
Example responses
200 Response
{
"value": {
"trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"availDdx": "1000",
"lockedDdx": "200",
"payFeesInDdx": true
},
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Trader data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Trader API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | any | true | none | The value of the response. |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | object | false | none | Entity which represents the current trader state. |
| »»» trader | string | true | none | The trader address prefixed with the blockchain discriminant. |
| »»» availDdx | string | true | none | The amount of DDX that the trader holds. |
| »»» lockedDdx | string | true | none | The amount of DDX that the trader has initiated for withdrawal. |
| »»» payFeesInDdx | boolean | true | none | A flag which indicates whether the trader wants to attempt to pay trading fees using their DDX balance. |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | null | false | none | The value will be null if there is no value for the parameters used. |
continued
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Market
These APIs return key high level metrics for markets.
Get Mark Price History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/mark_prices',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/mark_prices', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/mark_prices',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/mark_prices
Get mark prices over time
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | false | The number of rows to return |
| epoch | query | integer | false | The epoch boundary used when fetching the next timeseries page. |
| symbol | query | string | false | The symbol |
| order | query | string | false | The ordering of the results. |
| globalOrdinal | query | integer | false | The global ordinal boundary used when fetching the next timeseries page. |
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextGlobalOrdinal": 100,
"value": [
{
"globalOrdinal": 9,
"epochId": 100,
"symbol": "ETHP",
"price": 3428.44,
"fundingRate": 0.005,
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Mark price data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Mark Price API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextGlobalOrdinal | number,null | true | none | Pointer for the global ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» globalOrdinal | number | true | none | The global ordinal for an order update that identifies it uniquely. |
| »» epochId | number | true | none | The epoch in which the mark price belongs. |
| »» symbol | string | true | none | The symbol of the asset. |
| »» price | string | true | none | The mark price value. |
| »» fundingRate | string | true | none | The funding rate value. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Order Book (L3)
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/order_book',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/order_book', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/order_book',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/order_book
Get current L3 order book
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | false | The trader address, with the discriminant prefix. |
| strategyIdHash | query | string | false | The strategy id hash. |
| depth | query | integer | false | The best N bids and asks to return, where N = depth |
| symbol | query | string | false | The symbol |
| side | query | integer | false | The side of the order. Values include: |
Detailed descriptions
side: The side of the order. Values include: 0: Bid, 1: Ask
Enumerated Values
| Parameter | Value |
|---|---|
| side | 0 |
| side | 1 |
Example responses
200 Response
{
"value": [
{
"bookOrdinal": 0,
"orderHash": "0xc8ab0f901fc3968dfae99b6efb34b0bdd81d69aefb21effcf5",
"symbol": "ETHP",
"side": 0,
"originalAmount": "1.0",
"amount": "0.9",
"price": "595.8",
"traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"strategyIdHash": "0x2576ebd1"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Order book l3 data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the OrderBook L3 API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» bookOrdinal | number | true | none | none |
| »» orderHash | string | true | none | A hash of the order details. |
| »» symbol | string | true | none | The symbol of the asset for this order. |
| »» side | number | true | none | The side of the order. Values include: 0: Bid, 1: Ask |
| »» originalAmount | string | true | none | The original order amount (before any fills). |
| »» amount | string | true | none | The order amount currently left on this order. |
| »» price | string | true | none | The order price. |
| »» traderAddress | string | true | none | The trader address prefixed with the blockchain discriminant of the trader who owns this order. |
| »» strategyIdHash | string | true | none | The strategy id hash of the trader. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Order Update History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/order_updates',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/order_updates', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/order_updates',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/order_updates
Get order updates (trades, liquidations, cancels)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | false | The trader address, with the discriminant prefix. |
| strategyIdHash | query | string | false | The strategy id hash. |
| limit | query | integer | false | The number of rows to return |
| globalOrdinal | query | integer | false | The global ordinal boundary used when fetching the next timeseries page. |
| order | query | string | false | The ordering of the results. |
| symbol | query | string | false | The symbol |
| orderHash | query | string | false | the order hash of the order intent. Multiple order hash values can be provided. |
| reason | query | integer | false | The reason for the creation of this row. Multiple reason values can be provided. Values include: |
| since | query | integer | false | The earliest time in seconds to fetch rows for. This param cannot be used together with param order = 'desc' |
Detailed descriptions
reason: The reason for the creation of this row. Multiple reason values can be provided. Values include: 0-Post; 1-Trade; 2-Liquidation; 3-Cancel, 4-Order Rejection, 5-Cancel Rejection.
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextGlobalOrdinal": 100,
"value": [
{
"globalOrdinal": 9,
"epochId": 100,
"txOrdinal": 3432,
"ordinal": 0,
"orderRejection": 0,
"cancelRejection": 0,
"reason": 0,
"amount": "1.5",
"quoteAssetAmount": "750",
"symbol": "ETHP",
"price": "500",
"makerFeeCollateral": "0",
"makerFeeDDX": "0",
"makerRealizedPnl": "0",
"takerOrderIntent": {
"epochId": 100,
"orderHash": "0xa3c4c1c18c6e72c4aea8cfa0a1868ac4bc0f9b6463e8c9687f",
"symbol": "ETHP",
"side": 0,
"amount": "1.0",
"price": "1500.0",
"traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"strategyIdHash": "main",
"orderType": 0,
"stopPrice": "0",
"nonce": "0x3136373332393531393331383537373332363800000000000000000000000000",
"signature": "0xf9b19b088e3d0ad2c6330231899e03e50b45a8c7a1f52082aa0e9a61391fd5a35d3aece9dd2d42132a25b0aef5ac1bda7aee87c0c0c25ab9525d5eeeff9787d81b",
"createdAt": "2023-01-06T16:37:27.929Z"
},
"takerFeeCollateral": "1.7874",
"takerFeeDDX": "1.7874",
"takerRealizedPnl": "0",
"liquidatedTraderAddress": null,
"liquidatedStrategyIdHash": null,
"makerOrderIntent": {
"epochId": 100,
"orderHash": "0xa3c4c1c18c6e72c4aea8cfa0a1868ac4bc0f9b6463e8c9687f",
"symbol": "ETHP",
"side": 0,
"amount": "1.0",
"price": "1500.0",
"traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"strategyIdHash": "main",
"orderType": 0,
"stopPrice": "0",
"nonce": "0x3136373332393531393331383537373332363800000000000000000000000000",
"signature": "0xf9b19b088e3d0ad2c6330231899e03e50b45a8c7a1f52082aa0e9a61391fd5a35d3aece9dd2d42132a25b0aef5ac1bda7aee87c0c0c25ab9525d5eeeff9787d81b",
"createdAt": "2023-01-06T16:37:27.929Z"
},
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Order update data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Order Update API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextGlobalOrdinal | number,null | true | none | Pointer for the global ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» globalOrdinal | number | true | none | The global ordinal for an order update that identifies it uniquely. |
| »» epochId | number | true | none | The epoch in which this transaction occured. |
| »» txOrdinal | number | false | none | The transaction ordinal, within the epoch. |
| »» ordinal | number | false | none | The ordinal within this particular transaction. |
| »» orderRejection | number | false | none | The order rejection type. Only applicable when its rejection. |
| »» cancelRejection | number | false | none | The cancel rejection type. Only applicable when its rejection. |
| »» reason | number | true | none | The reason for the order update. |
| »» amount | string | true | none | The amount that was filled. |
| »» quoteAssetAmount | string | false | none | The quote asset amount. |
| »» symbol | string | true | none | The symbol of the asset that was filled. |
| »» price | string | false | none | The fill price. |
| »» makerFeeCollateral | string | false | none | The USDC fee that was incurred to the maker side of the fill if the maker receives fees in USDC. |
| »» makerFeeDDX | string | false | none | The fee that was incurred to the maker side of the fill if the maker elected to receive fees in DDX. Null otherwise. |
| »» makerRealizedPnl | string | false | none | The realized profit and loss (not inclusive of fees) incurred to the maker due to this fill. Null otherwise. |
| »» takerOrderIntent | object | false | none | The order intent from the taker associated with this fill. Only present when reason is trade. |
| »»» epochId | number | true | none | The epoch in which this transaction occured. |
| »»» orderHash | string | true | none | A hash of this order contents. |
| »»» symbol | string | true | none | The symbol of the asset for this order. |
| »»» side | number | true | none | The side of the order. Values include: 0: Bid, 1: Ask |
| »»» amount | string | true | none | The amount of the order. |
| »»» price | string | true | none | The price of the order. |
| »»» traderAddress | string | true | none | The trader address prefixed with the blockchain discriminant of the trader who issues this order. |
| »»» strategyIdHash | string | true | none | The strategy of the trader which owns this order. |
| »»» orderType | number | true | none | The type of order. Values include: 0: Limit, 1: Market 2: Stop 3: LimitPostOnly |
| »»» stopPrice | string | true | none | The stop price for this order. Not currently an active field. |
| »»» nonce | string | true | none | The nonce sent by the trader when placing this order. |
| »»» signature | string | true | none | A signature which was used to verify the authenticity of the order, when it was sent by the trader. Encrypted using the public key exposed by the leader Operator. |
| »»» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| »» takerFeeCollateral | string | false | none | The fee that was incurred to the taker side of the fill if taker receives fees in USDC. Null otherwise |
| »» takerFeeDDX | string | false | none | The fee that was incurred to the taker side of the fill if taker receives fees in DDX. Null otherwise |
| »» takerRealizedPnl | string | false | none | The realized profit and loss (not inclusive of fees) incurred to the taker due to this fill. |
| »» liquidatedTraderAddress | string | false | none | In the case that this was a liquidation fill, the trader address prefixed with the blockchain discriminant of the trader that was liquidated. |
| »» liquidatedStrategyIdHash | string | false | none | The liquidated strategy id hash |
| »» makerOrderIntent | object | true | none | The order intent from the maker associated with this fill. |
| »»» epochId | number | true | none | The epoch in which this transaction occured. |
| »»» orderHash | string | true | none | A hash of this order contents. |
| »»» symbol | string | true | none | The symbol of the asset for this order. |
| »»» side | number | true | none | The side of the order. Values include: 0: Bid, 1: Ask |
| »»» amount | string | true | none | The amount of the order. |
| »»» price | string | true | none | The price of the order. |
| »»» traderAddress | string | true | none | The trader address prefixed with the blockchain discriminant of the trader who issues this order. |
| »»» strategyIdHash | string | true | none | The strategy of the trader which owns this order. |
| »»» orderType | number | true | none | The type of order. Values include: 0: Limit, 1: Market 2: Stop 3: LimitPostOnly |
| »»» stopPrice | string | true | none | The stop price for this order. Not currently an active field. |
| »»» nonce | string | true | none | The nonce sent by the trader when placing this order. |
| »»» signature | string | true | none | A signature which was used to verify the authenticity of the order, when it was sent by the trader. Encrypted using the public key exposed by the leader Operator. |
| »»» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Enumerated Values
| Property | Value |
|---|---|
| orderRejection | 0 |
| orderRejection | 1 |
| orderRejection | 2 |
| orderRejection | 3 |
| orderRejection | 4 |
| orderRejection | 5 |
| reason | 0 |
| reason | 1 |
| reason | 2 |
| reason | 3 |
| reason | 4 |
| reason | 5 |
| side | 0 |
| side | 1 |
| orderType | 0 |
| orderType | 1 |
| orderType | 2 |
| orderType | 3 |
| side | 0 |
| side | 1 |
| orderType | 0 |
| orderType | 1 |
| orderType | 2 |
| orderType | 3 |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Strategy Update History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/strategy_updates',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/strategy_updates', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/strategy_updates',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/strategy_updates
Get strategy updates over time
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | false | The trader address, with the discriminant prefix. |
| strategyIdHash | query | string | false | The strategy id hash. |
| reason | query | integer | false | The type of strategy update. Multiple strategy update values can be provided. Values include: |
| limit | query | integer | false | The number of rows to return |
| globalOrdinal | query | integer | false | The global ordinal boundary used when fetching the next timeseries page. |
| order | query | string | false | The ordering of the results. |
Detailed descriptions
reason: The type of strategy update. Multiple strategy update values can be provided. Values include: 0: Deposit - Collateral was deposited on-chain, 1: Withdraw - Collateral withdrawal was claimed on-chain, 2: WithdrawIntent - Collateral was locked for withdrawal, 3: FundingPayment - Funding payments were distributed, 4: PnlSettlement - PnL was realized, 5: Trade, 6: Fee, 7: Liquidation, 8: ADL - ADL occurred on one or more positions, 9: Withdraw Rejection.
Enumerated Values
| Parameter | Value |
|---|---|
| reason | 0 |
| reason | 1 |
| reason | 2 |
| reason | 3 |
| reason | 4 |
| reason | 5 |
| reason | 6 |
| reason | 7 |
| reason | 8 |
| reason | 9 |
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextGlobalOrdinal": 100,
"value": [
{
"globalOrdinal": 9,
"epochId": 0,
"txOrdinal": 3432,
"ordinal": 0,
"withdrawRejection": 0,
"reason": 0,
"traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x8ea76477cfaca8f7ea06477fd3c09a740ac6012a",
"collateralSymbol": "USDC",
"amount": "1000",
"newAvailCollateral": "10000",
"newLockedCollateral": "10000",
"blockNumber": "344100",
"txHash": "0xfcdae2edac7063ae3a3fb0e74b48816a0593644a3b2f5d701c8e5fafec70828e",
"positions": [
{
"symbol": "ETHP",
"side": 0,
"avgEntryPrice": "1500",
"realizedPnl": "1500"
}
],
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Strategy update data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Strategy Update API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextGlobalOrdinal | number,null | true | none | Pointer for the global ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» globalOrdinal | number | true | none | The global ordinal for a strategy update that identifies it uniquely. |
| »» epochId | number | true | none | The epoch in which this transaction occured. |
| »» txOrdinal | number | false | none | The transaction ordinal, within the epoch. |
| »» ordinal | number | false | none | The ordinal within this particular transaction. |
| »» withdrawRejection | number | false | none | The withdraw rejection type when applicable. Optional field only present on rejections. |
| »» reason | number | true | none | The reason of strategy update. |
| »» traderAddress | string | true | none | The trader address prefixed with the blockchain discriminant. |
| »» strategyIdHash | string | true | none | The strategy id hash of the trader. |
| »» collateralAddress | string | false | none | The collateral address on which this strategy update took place. |
| »» collateralSymbol | string | false | none | The collateral symbol on which this strategy update took place. |
| »» amount | string | false | none | The amount that was modified in the strategy. |
| »» newAvailCollateral | string | false | none | If affected, the updated available collateral amount after this strategy update. Not present on Adl reason. |
| »» newLockedCollateral | string | false | none | If affected, the updated locked collateral amount after this strategy update. Not present on Adl reason. |
| »» blockNumber | number | false | none | The block number in which this strategy update was processed. Not present on Adl reason. |
| »» txHash | string | false | none | The on-chain transaction hash corresponding to this strategy update |
| »» positions | [object] | false | none | The position fields and values affected by this strategy update. |
| »»» symbol | string | true | none | The symbol affected. |
| »»» side | number | false | none | The side. Only present on Adl strategy update. Values include: 0: Bid, 1: Ask |
| »»» avgEntryPrice | string | false | none | After a RealizedPnl strategy update, what the new average entry prices is for this strategies open positions. |
| »»» realizedPnl | string | true | none | After a RealizedPnl or Adl strategy update, what the realized pnl is for this strategies open positions. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Enumerated Values
| Property | Value |
|---|---|
| withdrawRejection | 0 |
| withdrawRejection | 1 |
| withdrawRejection | 2 |
| withdrawRejection | 3 |
| withdrawRejection | 4 |
| reason | 0 |
| reason | 1 |
| reason | 2 |
| reason | 3 |
| reason | 4 |
| reason | 5 |
| reason | 6 |
| reason | 7 |
| reason | 8 |
| reason | 9 |
| side | 0 |
| side | 1 |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Tickers
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/tickers',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/tickers', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/tickers',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/tickers
Get convenient market tickers data, like funding rate and open interest data, price related data, trading volume in the last 24 hours.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| symbol | query | string | false | The symbol |
| marketKind | query | integer | false | The type of markets to return data for. 0: SingleNamePerpetual, 2: IndexFundPerpetual, 3: FixedExpiryFuture. Multiple types can be provided. |
Detailed descriptions
marketKind: The type of markets to return data for. 0: SingleNamePerpetual, 2: IndexFundPerpetual, 3: FixedExpiryFuture. Multiple types can be provided.
Enumerated Values
| Parameter | Value |
|---|---|
| marketKind | 0 |
| marketKind | 2 |
| marketKind | 3 |
Example responses
200 Response
{
"value": [
{
"symbol": "ETHP",
"kind": 0,
"highPrice24h": "2650",
"lowPrice24h": "2300",
"prevPrice24h": "2300",
"lastPrice": "2650",
"markPrice": "2500",
"indexPrice": "2450",
"nextFundingTime": "2023-01-06T16:37:27.929Z",
"volume24h": "100000",
"amount24h": "1000",
"fundingRate": "0.0005",
"openInterest": "220",
"openInterestValue": "1500000"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Tickers data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Ticker API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» symbol | string | true | none | The symbol of the market. |
| »» kind | number | true | none | The type of setting. Values include: 0: Perpetual Market, 2: Index Market, 3: Quarterly Expiry Future |
| »» highPrice24h | string | true | none | The highest price in the last 24 hours. |
| »» lowPrice24h | string | true | none | The lowest price in the last 24 hours. |
| »» prevPrice24h | string | true | none | The open price 24 hours ago. |
| »» lastPrice | string | true | none | The last traded price. |
| »» markPrice | string | true | none | The mark price. |
| »» indexPrice | string | true | none | The index price. |
| »» nextFundingTime | string(date-time) | true | none | The time estimated for the next funding rate to occur. |
| »» volume24h | string | true | none | The volume in the last 24 hours. |
| »» amount24h | string,null | true | none | The amount in the last 24 hours. |
| »» fundingRate | string | true | none | The funding rate value.. |
| »» openInterest | string | true | none | The current open interest for the market. |
| »» openInterestValue | string | true | none | The current open interest value, amount of positions multiplied by the average price, for the market. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Trader Update History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/exchange/api/v1/trader_updates',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/exchange/api/v1/trader_updates', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/exchange/api/v1/trader_updates',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /exchange/api/v1/trader_updates
Get trader DDX balance and profile updates over time
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | false | The trader address, with the discriminant prefix. |
| reason | query | integer | false | The type of trader update. Multiple trader update values can be provided. Values include: |
| limit | query | integer | false | The number of rows to return |
| globalOrdinal | query | integer | false | The global ordinal boundary used when fetching the next timeseries page. |
| order | query | string | false | The ordering of the results. |
Detailed descriptions
reason: The type of trader update. Multiple trader update values can be provided. Values include: 0: Deposit - DDX was deposited on-chain, 1: WithdrawDDX - DDX withdrawal was claimed on-chain, 2: WithdrawDDXIntent - DDX was locked for withdrawal, 3: TradeMiningReward - DDX was rewarded for participation in trade mining, 4: ProfileUpdate - DDX fee preferences were changed, 5: FeeDistribution - DDX was rewarded for participation as a custodian during checkpointing, 6: Admission 7: Denial 8: Fee - DDX amount paid as a fee in a trade, 9: WithdrawDDXRejection - Withdraw DDX rejection.
Enumerated Values
| Parameter | Value |
|---|---|
| reason | 0 |
| reason | 1 |
| reason | 2 |
| reason | 3 |
| reason | 4 |
| reason | 5 |
| reason | 6 |
| reason | 7 |
| reason | 8 |
| reason | 9 |
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextGlobalOrdinal": 100,
"value": [
{
"globalOrdinal": 9,
"epochId": 100,
"txOrdinal": 3432,
"ordinal": 0,
"withdrawDdxRejection": 0,
"reason": 0,
"traderAddress": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"amount": "1000",
"newAvailDdxBalance": "1200",
"newLockedDdxBalance": "100",
"payFeesInDdx": true,
"blockNumber": "344100",
"txHash": "0xfcdae2edac7063ae3a3fb0e74b48816a0593644a3b2f5d701c8e5fafec70828e",
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | trader update data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Trader Update API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextGlobalOrdinal | number,null | true | none | Pointer for the global ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» globalOrdinal | number | true | none | The global ordinal for a trader update that identifies it uniquely. |
| »» epochId | number | true | none | The epoch in which this transaction occured. |
| »» txOrdinal | number | false | none | The transaction ordinal, within the epoch. |
| »» ordinal | number | false | none | The ordinal within this particular transaction. |
| »» withdrawDdxRejection | number | false | none | The withdraw rejection type when applicable. Optional field only present on rejections. |
| »» reason | number | true | none | The reason of trader update. |
| »» traderAddress | string | true | none | The trader address prefixed with the blockchain discriminant of the trader. |
| »» amount | string | false | none | The amount of DDX was modified in this trader. |
| »» newAvailDdxBalance | string | false | none | The new DDX balance after updating this trader. |
| »» newLockedDdxBalance | string | false | none | The new locked DDX balance after updating this trader. |
| »» payFeesInDdx | boolean | false | none | A flag which when set will attempt to pay trading fees using the DDX held in this trader. |
| »» blockNumber | number | false | none | The block number in which this strategy update was processed. |
| »» txHash | string | false | none | The on-chain transaction hash corresponding to this trader update (for Deposit and WithdrawDDX kinds) |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Enumerated Values
| Property | Value |
|---|---|
| withdrawDdxRejection | 0 |
| withdrawDdxRejection | 1 |
| reason | 0 |
| reason | 1 |
| reason | 2 |
| reason | 3 |
| reason | 4 |
| reason | 5 |
| reason | 6 |
| reason | 7 |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Balance Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/balance',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/balance', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/balance',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/balance
Returns the change of trader's balance for a specific strategy over a specific time period, looking back from the present
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | false | The trader address, with the discriminant prefix. |
| strategyId | query | string | false | The strategy ID. |
| limit | query | integer | false | The number of rows to return |
| aggregationPeriod | query | string | false | The period for the aggregation. |
| lookbackCount | query | integer | false | The number of periods to look back from present. |
Enumerated Values
| Parameter | Value |
|---|---|
| aggregationPeriod | week |
| aggregationPeriod | day |
| aggregationPeriod | hour |
| aggregationPeriod | minute |
Example responses
200 Response
{
"value": [
{
"trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"strategyIdHash": "0x2576ebd1",
"amount": "0.9",
"timestamp": 1673308800
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Balance aggregation data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Balance API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» trader | string | true | none | The trader address prefixed with the blockchain discriminant. |
| »» strategyIdHash | string | true | none | The strategy id hash of the trader. |
| »» amount | string | true | none | The amount. |
| »» timestamp | number | true | none | The unix timestamp at the start of the aggregation period. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Fees Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/fees',
params: {
'group' => 'string'
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/fees', params={
'group': 'symbol'
}, headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/fees?group=symbol',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/fees
Returns fees per time period looking back from the present
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| group | query | string | true | The grouping for the aggregation. |
| symbol | query | string | false | The symbol |
| feeSymbol | query | string | false | The fee symbol |
| aggregationPeriod | query | string | false | The period for the aggregation. |
| lookbackCount | query | integer | false | The number of periods to look back from present. |
| lookbackTimestamp | query | number | false | The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results. |
Detailed descriptions
lookbackTimestamp: The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results.
Enumerated Values
| Parameter | Value |
|---|---|
| group | symbol |
| group | feeSymbol |
| feeSymbol | USDC |
| feeSymbol | DDX |
| aggregationPeriod | week |
| aggregationPeriod | day |
| aggregationPeriod | hour |
| aggregationPeriod | minute |
Example responses
200 Response
{
"nextLookbackTimestamp": 1673384400,
"value": [
{
"timestamp": 1671062400,
"fees_DDX": "5.823239",
"fees_USDC": "7.8"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Fees aggregation data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Fees aggregation API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextLookbackTimestamp | number,null | true | none | Time pointer for where the next lookback should begin. Pass this value as lookbackTimestamp to get the next page of data. Will also skip over gaps in the data to return the next non-null. aggregation period. When this value is null, it indicates there is no more data to fetch. |
| » value | [object] | true | none | The value of the response |
| »» additionalProperties | string | false | none | none |
| »» timestamp | number | true | none | The unix timestamp at the start of the aggregation period. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Funding Rate Comparison Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/funding_rate_comparison',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/funding_rate_comparison', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/funding_rate_comparison',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/funding_rate_comparison
Returns funding rate comparison data between DerivaDEX and major exchanges
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| symbol | query | string | false | The symbol |
Example responses
200 Response
{
"value": [
{
"symbol": "BTCP",
"derivadexFundingRate": "0.005",
"binanceFundingRate": "0.005",
"derivadexBinanceArbitrage": "0.005",
"bybitFundingRate": "0.005",
"derivadexBybitArbitrage": "0.005",
"hyperliquidFundingRate": "0.005",
"derivadexHyperliquidArbitrage": "0.005"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Funding Rate Comparison Data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Funding Rate Comparison API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» symbol | string | true | none | The symbol of the market. |
| »» derivadexFundingRate | number | true | none | The funding rate for the given market. |
| »» binanceFundingRate | number | true | none | The funding rate for the given market. |
| »» derivadexBinanceArbitrage | number | true | none | The funding rate difference between DerivaDEX and the given market. |
| »» bybitFundingRate | number | true | none | The funding rate for the given market. |
| »» derivadexBybitArbitrage | number | true | none | The funding rate difference between DerivaDEX and the given market. |
| »» hyperliquidFundingRate | number | true | none | The funding rate for the given market. |
| »» derivadexHyperliquidArbitrage | number | true | none | The funding rate difference between DerivaDEX and the given market. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Top Traders Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/traders',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/traders', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/traders',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/traders
Returns the top N traders by volume
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| trader | query | string | false | The trader address, with the discriminant prefix. |
| limit | query | integer | false | The number of rows to return |
| cursor | query | integer | false | The cursor for the beginning of the next page of top traders to fetch. |
| topTradersOrdering | query | string | false | The order by which to fetch top traders. |
| order | query | string | false | The ordering of the results. |
Enumerated Values
| Parameter | Value |
|---|---|
| topTradersOrdering | volume |
| topTradersOrdering | pnl |
| topTradersOrdering | accountValue |
| order | asc |
| order | desc |
Example responses
200 Response
{
"value": [
{
"trader": "0x00b993e587c15a9e0a0fe4f111de98fd6b5ce7067d",
"volume": "18026.42",
"realizedPnl": "173.10",
"accountValue": "5600"
}
],
"nextCursor": 100,
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Top Traders data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the TopTraders API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» trader | string | true | none | The trader address prefixed with the blockchain discriminant. |
| »» volume | string,null | true | none | The notional sum of the asset traded. |
| »» realizedPnl | string,null | true | none | The total realized pnl for the trader, excluding funding payments. |
| »» accountValue | string,null | true | none | The total amount of usdc collateral held by this trader. |
| » nextCursor | number,null | true | none | The cursor for the beginning of the next page of top traders to fetch. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Volume Aggregation
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/aggregations/volume',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/aggregations/volume', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/aggregations/volume',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/aggregations/volume
Returns volume per time period looking back from the present
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| group | query | string | false | The grouping for the aggregation. |
| symbol | query | string | false | The symbol |
| aggregationPeriod | query | string | false | The period for the aggregation. |
| lookbackCount | query | integer | false | The number of periods to look back from present. |
| lookbackTimestamp | query | number | false | The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results. |
Detailed descriptions
lookbackTimestamp: The timestamp of the when to begin the lookback from. Each lookback query will return nextLookbackTimestamp in the response, which can be passed as a query parameter here to get the next page of results.
Enumerated Values
| Parameter | Value |
|---|---|
| group | symbol |
| aggregationPeriod | week |
| aggregationPeriod | day |
| aggregationPeriod | hour |
| aggregationPeriod | minute |
Example responses
200 Response
{
"nextLookbackTimestamp": 1673384400,
"value": [
{
"timestamp": 1673308800,
"volume_notional_overall": "164113411.21248"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Volume aggregation data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Volume aggregation API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextLookbackTimestamp | number,null | true | none | Time pointer for where the next lookback should begin. Pass this value as lookbackTimestamp to get the next page of data. Will also skip over gaps in the data to return the next non-null. aggregation period. When this value is null, it indicates there is no more data to fetch. |
| » value | [object] | true | none | The value of the response |
| »» additionalProperties | string | false | none | none |
| »» timestamp | number | true | none | The unix timestamp at the start of the aggregation period. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Funding Rate History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/funding_rate_history',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/funding_rate_history', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/funding_rate_history',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/funding_rate_history
Get funding rates over time
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | false | The number of rows to return |
| epoch | query | integer | false | The epoch boundary used when fetching the next timeseries page. |
| txOrdinal | query | integer | false | The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch. |
| order | query | string | false | The ordering of the results. |
| symbol | query | string | false | The symbol |
| since | query | integer | false | The earliest time in seconds to fetch rows for. This param cannot be used together with param order = 'desc' |
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextEpoch": 100,
"nextTxOrdinal": 3432,
"nextOrdinal": 100,
"value": [
{
"epochId": 100,
"txOrdinal": 3432,
"symbol": "BTCP",
"fundingRate": "0.005",
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Funding Rate History Data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Funding Rate History API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextEpoch | number,null | true | none | Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch. |
| » nextTxOrdinal | number,null | true | none | Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » nextOrdinal | number,null | true | none | Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» epochId | string | true | none | The epoch in which this funding rate update occured. |
| »» txOrdinal | string | true | none | The transaction ordinal, within the epoch. |
| »» symbol | string | true | none | The symbol of the market. |
| »» fundingRate | string | true | none | The funding rate for the given market. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Open Interest History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/open_interest_history',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/open_interest_history', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/open_interest_history',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/open_interest_history
Get open interest over time
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | false | The number of rows to return |
| order | query | string | false | The ordering of the results. |
| symbol | query | string | false | The symbol |
| interval | query | string | false | The interval for open interest history. |
| since | query | integer | false | The earliest time in seconds to fetch rows for. This param cannot be used together with param order = 'desc' |
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
| interval | 5m |
| interval | 1h |
| interval | 1d |
Example responses
200 Response
{
"value": [
{
"symbol": "BTCP",
"amount": "1000",
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Open Interest History Data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Open Interest History API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» symbol | string | true | none | The symbol of the market. |
| »» amount | string | true | none | The amount of open interest for the given market. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Order Book (L2)
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/order_book_l2',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/order_book_l2', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/order_book_l2',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/order_book_l2
Get current L2 aggregated order book
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| symbol | query | string | false | The symbol |
| depth | query | integer | false | The best N bids and asks to return, where N = depth |
| side | query | integer | false | The side of the order. Values include: |
| priceAggregation | query | number | false | The price aggregation to use for the L2 orderbook. Valid values for each symbol include: |
Detailed descriptions
side: The side of the order. Values include: 0: Bid, 1: Ask
priceAggregation: The price aggregation to use for the L2 orderbook. Valid values for each symbol include: ETHP: 0.1, 1, 10 BTCP: 1, 10, 100
Enumerated Values
| Parameter | Value |
|---|---|
| side | 0 |
| side | 1 |
| priceAggregation | 0.1 |
| priceAggregation | 1 |
| priceAggregation | 10 |
| priceAggregation | 100 |
Example responses
200 Response
{
"value": [
{
"symbol": "ETHP",
"amount": "0.1",
"price": 1000,
"side": 0
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Order Book L2 data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Order Book L2 API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » value | [object] | true | none | The value of the response |
| »» symbol | string | true | none | The symbol of the asset for this order aggregation. |
| »» side | number | true | none | The side of the order aggregation. Values include: 0: Bid, 1: Ask |
| »» amount | string | true | none | The order amount currently left on this aggregation level. |
| »» price | string | true | none | The price level of the aggregation. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Get Price Checkpoint History
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/stats/api/v1/price_checkpoints',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/stats/api/v1/price_checkpoints', headers = headers)
print(r.json())
const headers = {
'Accept':'application/json'
};
fetch('/stats/api/v1/price_checkpoints',
{
method: 'GET',
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
GET /stats/api/v1/price_checkpoints
Get price checkpoints over time
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| limit | query | integer | false | The number of rows to return |
| epoch | query | integer | false | The epoch boundary used when fetching the next timeseries page. |
| txOrdinal | query | integer | false | The txOrdinal boundary used when fetching the next timeseries page. Must be passed along with epoch. |
| order | query | string | false | The ordering of the results. |
| symbol | query | string | false | The symbol |
| priceHash | query | string | false | the index price hash of the mark price. Multiple price hash values can be provided. |
Enumerated Values
| Parameter | Value |
|---|---|
| order | asc |
| order | desc |
Example responses
200 Response
{
"nextEpoch": 100,
"nextTxOrdinal": 3432,
"nextOrdinal": 100,
"value": [
{
"epochId": 100,
"txOrdinal": 3432,
"indexPriceHash": "0x607b9303d1da6aa842c4f7af2ae18d8616e5af63b692a05151",
"symbol": "ETHP",
"indexPrice": "5311.571505",
"markPrice": "5311.203",
"time": "100",
"ema": "-2.67",
"priceOrdinal": "100",
"createdAt": "2023-01-06T16:37:27.929Z"
}
],
"success": true,
"timestamp": 1673031089
}
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | Price checkpoint data | Inline |
| 400 | Bad Request | Bad request | Inline |
| 500 | Internal Server Error | Unexpected error | Inline |
Response Schema
Status Code 200
Successful response for the Price Checkpoints API
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » nextEpoch | number,null | true | none | Pointer for the epoch boundary of the next page. Will return null when there is no more data left to fetch. |
| » nextTxOrdinal | number,null | true | none | Pointer for the txOrdinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » nextOrdinal | number,null | true | none | Pointer for the ordinal boundary of the next page. Will return null when there is no more data left to fetch. |
| » value | [object] | true | none | The value of the response |
| »» epochId | string | true | none | The epoch in which this transaction occured. |
| »» txOrdinal | string | true | none | The transaction ordinal, within the epoch. |
| »» indexPriceHash | string | true | none | The hash of the index price. |
| »» symbol | string | true | none | The symbol of the asset. |
| »» indexPrice | string | true | none | The exponential weighted average of prices from the price feed by source. |
| »» markPrice | string | true | none | The index price + ema clamped to 50bps above/below the index price at all times. |
| »» time | string | true | none | The monotonic clock tick associated with this price checkpoint. |
| »» ema | string,null | true | none | Exponential moving average which tracks the spread between the DerivaDEX Petual swap price and the underlying index price it is tracking. |
| »» priceOrdinal | string | true | none | The ordinal of this price update. |
| »» createdAt | string(date-time) | true | none | The time when this row was added to the database. |
| » success | boolean | true | none | Whether the request was successful |
| » timestamp | number | true | none | The timestamp of the response |
Status Code 400
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Status Code 500
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| » success | boolean | true | none | none |
| » errorMsg | any | false | none | none |
anyOf
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | string | false | none | none |
or
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| »» anonymous | [object] | false | none | none |
Derivadex Operator REST API
Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
License:
Make Client Request
Code samples
require 'rest-client'
require 'json'
headers = {
'Content-Type' => 'application/octet-stream',
'Accept' => 'application/json'
}
result = RestClient.post '/v2/request',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Content-Type': 'application/octet-stream',
'Accept': 'application/json'
}
r = requests.post('/v2/request', headers = headers)
print(r.json())
const inputBody = 'string';
const headers = {
'Content-Type': 'application/octet-stream',
Accept: 'application/json',
};
fetch('/v2/request', {
method: 'POST',
body: inputBody,
headers: headers,
})
.then(function (res) {
return res.json();
})
.then(function (body) {
console.log(body);
});
POST /v2/request
Only the leader can accept client requests.
The endpoint accepts encrypted client requests. If successful, will return a receipt of the successfully sequenced request. Otherwise, will return an error message indicating why the request was not sequenced.
The request body must be an AES-GCM128 encrypted ClientRequest. To construct the payload:
- Generate a 16-byte (128-bit) ECDH shared key using the operator's public key (available from the encryption key handler) and a 32-byte private key of your choosing. Use a
keccak256ECDH key derivation and keep only the first 16 bytes of the result. - Generate a 12-byte random nonce.
- Prepare the plaintext payload: the bytes-encoded client request contents prefixed with a 4-byte length prefix.
- Encrypt the payload with AES-GCM128 to produce ciphertext plus MAC tag.
- Assemble the final request bytes as
[ciphertext][tag][nonce][client_public_key_compressed_format].
Body parameter
0xcfd66c1dee1a67f6caf4de178eff81531c805663b476d79b699ae7b16ccbbd57bb36a02ca3958f945e4e105bee40f365012fc0b626de18df77f527ef
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| body | body | bytes | true | ClientRequest encrypted as bytes in manner described above. |
ClientRequest
Client requests wrap a discriminator t and an intent payload c. Each variant is documented below.
{
"c": {
"amount": 0.1,
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"orderType": {
"Limit": {
"post_only": true
}
},
"price": 0.1,
"sessionKeySignature": "0xcc6577428c2f6d6bc64e5a22fac180d6b2e6e1b465e551305fd2d2490ca4c616e8c4bf144d3334955d46af783b52901a6ccaccdb251bce79793a67c9e2ed829af4",
"side": "Bid",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"stopPrice": 0.1,
"strategy": "0x6d61696e00000000000000000000000000000000000000000000000000000000",
"symbol": "ETHP"
},
"t": "Order"
}
Order→ OrderIntentModifyOrder→ ModifyOrderIntentCancelOrder→ CancelOrderIntentCancelAll→ CancelAllIntentWithdraw→ WithdrawIntentWithdrawDDX→ WithdrawDDXIntentProfileUpdate→ ProfileUpdateIntent
Place Order
{
"amount": 0.1,
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"orderType": {
"Limit": {
"post_only": true
}
},
"price": 0.1,
"sessionKeySignature": "0xcc6577428c2f6d6bc64e5a22fac180d6b2e6e1b465e551305fd2d2490ca4c616e8c4bf144d3334955d46af783b52901a6ccaccdb251bce79793a67c9e2ed829af4",
"side": "Bid",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"stopPrice": 0.1,
"strategy": "0x6d61696e00000000000000000000000000000000000000000000000000000000",
"symbol": "ETHP"
}
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| amount | number(double) | true | none | Order amount |
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| orderType | OrderType | true | none | The order type: 0-Limit, 1-Market, 2-Stop-Limit |
| price | number(double) | true | none | Order price. For a limit order, it is the limit price. |
| sessionKeySignature | Signature | false | none | EIP-191 signature of the 1CT session public key. Use null if trader did not opt into 1 click trading. |
| side | OrderSide | true | none | 0 - Long, 1 - Short |
| signature | Signature | true | none | EIP-712 signature of the order intent attributes |
| stopPrice | number(double) | true | none | Stop price. Set to 0 if the order is not a Stop-Limit. |
| strategy | Bytes32 | true | none | Strategy Id |
| symbol | ProductSymbol | true | none | Compact 6-byte product symbol |
Modify Order
{
"amount": 0.1,
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"orderHash": "0x9b62179273c8eb5bb682575ec87a171ac826a6fce48478dcb7",
"orderType": {
"Limit": {
"post_only": true
}
},
"price": 0.1,
"sessionKeySignature": "0xcc6577428c2f6d6bc64e5a22fac180d6b2e6e1b465e551305fd2d2490ca4c616e8c4bf144d3334955d46af783b52901a6ccaccdb251bce79793a67c9e2ed829af4",
"side": "Bid",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"stopPrice": 0.1,
"strategy": "0x6d61696e00000000000000000000000000000000000000000000000000000000",
"symbol": "ETHP"
}
Modify order intents are intents that modify the original order details of a specific order identified by its order hash.
This is identical to a cancel and a re-placing of the new order, the only difference from doing them separately being that the execution is atomic when executed as a ModifyOrderIntent.
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| amount | number(double) | true | none | Order amount |
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| orderHash | Bytes25 | true | none | Order hash of the order to modify |
| orderType | OrderType | true | none | The order type: 0-Limit, 1-Market, 2-Stop-Limit |
| price | number(double) | true | none | Order price. For a limit order, it is the limit price. |
| sessionKeySignature | Signature | false | none | EIP-191 signature of the 1CT session public key. Use null if trader did not opt into 1 click trading. |
| side | OrderSide | true | none | 0 - Long, 1 - Short |
| signature | Signature | true | none | EIP-712 signature of the modify intent attributes |
| stopPrice | number(double) | true | none | Stop price. Set to 0 if the order is not a Stop-Limit. |
| strategy | Bytes32 | true | none | Strategy Id |
| symbol | ProductSymbol | true | none | Compact 6-byte product symbol |
Cancel Order
{
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"orderHash": "0x9b62179273c8eb5bb682575ec87a171ac826a6fce48478dcb7",
"sessionKeySignature": "0xcc6577428c2f6d6bc64e5a22fac180d6b2e6e1b465e551305fd2d2490ca4c616e8c4bf144d3334955d46af783b52901a6ccaccdb251bce79793a67c9e2ed829af4",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"symbol": "ETHP"
}
Cancel a single order
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| orderHash | Bytes25 | true | none | Hash of the corresponding order intent |
| sessionKeySignature | Signature | false | none | EIP-191 signature of the 1CT session public key. Use null if trader did not opt into 1 click trading. |
| signature | Signature | true | none | EIP-712 signature of the order cancellation intent attributes |
| symbol | ProductSymbol | true | none | Compact 6-byte product symbol |
CancelAllIntent
{
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"sessionKeySignature": "0xcc6577428c2f6d6bc64e5a22fac180d6b2e6e1b465e551305fd2d2490ca4c616e8c4bf144d3334955d46af783b52901a6ccaccdb251bce79793a67c9e2ed829af4",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"strategy": "0x6d61696e00000000000000000000000000000000000000000000000000000000",
"symbol": "ETHP"
}
Batch cancel all orders of a given symbol for a given strategy
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| sessionKeySignature | Signature | false | none | EIP-191 signature of the 1CT session public key. Use null if trader did not opt into 1 click trading. |
| signature | Signature | true | none | EIP-712 signature of the order cancellation intent attributes |
| strategy | Bytes32 | true | none | Strategy Id to cancel all orders for |
| symbol | ProductSymbol | true | none | Compact 6-byte product symbol |
Withdraw
{
"amount": 0.1,
"currency": "0x12d810a485ed03241b4d419b1b673bd4755d05ad",
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"strategyId": "0x6d61696e00000000000000000000000000000000000000000000000000000000"
}
Traders signal their intent to withdraw which freezes the requested collateral in their account.
Funds may be available on-chain at the next checkpoint the operator is kind enough to "prove" the withdrawals on behalf of traders. Otherwise, traders may submit a merkle proof at any time after a Checkpoint to collect their funds.
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| amount | number(double) | true | none | Amount to withdraw |
| currency | EthAddress | true | none | Ethereum address of the collateral token (ERC-20, currently USDC only) |
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| signature | Signature | true | none | EIP-712 signature of the withdraw intent attributes |
| strategyId | Bytes32 | true | none | Strategy Id |
Withdraw DDX
{
"amount": 0.1,
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8"
}
Traders signal their intent to withdraw ddx which freezes the specified amount in their account.
Funds may be available on-chain at the next checkpoint the operator is kind enough to "prove" the withdrawals on behalf of traders.
Otherwise, traders may submit a merkle proof at any time after a Checkpoint to collect their funds.
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| amount | number(double) | true | none | Amount to withdraw |
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| signature | Signature | true | none | EIP-712 signature of the withdraw ddx intent attributes |
Update Trader Profile
{
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"payFeesInDdx": true,
"signature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8"
}
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| nonce | Bytes32 | true | none | A salt for uniqueness of the EIP-712 hash function. May optionally have business meaning to the client. |
| payFeesInDdx | boolean | true | none | Sets the flag in the trader profile |
| signature | Signature | true | none | EIP-712 signature of the profile update intent attributes |
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | none | SequencedReceiptResponse |
| 4XX | Unknown | none | HttpError |
| 5XX | Unknown | none | HttpError |
SequencedReceiptResponse
The signed receipt of a successfully sequenced client request.
{
"c": {
"enclaveSignature": "0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8",
"nonce": "0x0000000000000000000000000000000000000000000000000000000000000001",
"requestHash": "0x6be1679f6ae28652eb6fa7cd62de963a8cc7d2cd0e63b0bb0841d5824cbf5f95",
"requestIndex": 100,
"sender": "0x0030877432d1026706d7e805da846a32c3bb81e3c2"
},
"t": "Sequenced"
}
SequencedReceiptResponse wrap a discriminator t, which is always Sequenced, and content c with the Receipt. Receipt schema documented below.
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| enclaveSignature | Signature | true | none | 65 byte hex string |
| nonce | Bytes32 | true | none | 32 byte hex string |
| requestHash | Bytes32 | true | none | 32 byte hex string |
| requestIndex | integer(int64) | true | none | Request index given to this request by the sequencer |
| sender | Bytes21 | true | none | 21 byte hex string representing user addresses on the Derivadex platform |
Get Encryption Key
Returns the operator's public key derived from the user attestation data
Code samples
require 'rest-client'
require 'json'
headers = {
'Accept' => 'application/json'
}
result = RestClient.get '/v2/encryption-key',
params: {
}, headers: headers
p JSON.parse(result)
import requests
headers = {
'Accept': 'application/json'
}
r = requests.get('/v2/encryption-key', headers = headers)
print(r.json())
const headers = {
Accept: 'application/json',
};
fetch('/v2/encryption-key', {
method: 'GET',
headers: headers,
})
.then(function (res) {
return res.json();
})
.then(function (body) {
console.log(body);
});
GET /v2/encryption-key
Responses
| Status | Meaning | Description | Schema |
|---|---|---|---|
| 200 | OK | none | Bytes33 |
| 421 | Misdirected request | none | HttpError |
HttpError
{
"error_reason": "Forbidden",
"message": "string",
"safety_failure": {}
}
API Error
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| error_reason | ErrorReason | true | none | The general error reason returned by the API |
| message | string | true | none | Error message |
| safety_failure | SafetyFailureReason | false | none | Specific safety failure that triggered client request validation. Optional. |
ErrorReason
General reasons that accompany an HTTP error response.
| Value | Description |
|---|---|
| Forbidden | The request was understood but refused (for example, the operator is switching epochs and not processing requests). |
| InvalidEncryption | The payload could not be decrypted according to the expected encryption convention. |
| InvalidRequestPayload | The decrypted payload could not be deserialized into a Request. |
| IllegalNonce | The supplied request nonce exists but is not monotonically increasing. |
| SignerNotFound | The signer recovered from the signature does not exist. |
| KycNotFound | The signer’s KYC authorization has expired or is missing. |
| RateLimit | The signer is authenticated but was rejected by the rate limiter. |
| NotAcceptingRequests | The operator is not accepting this type of request (e.g., the request was sent to a follower). |
| InternalServerError | A generic internal server error occurred. |
| ServiceUnavailable | The service is temporarily unavailable (for example, the mark price is not yet available). |
| SafetyFailure | Validation safety failure; see safety_failure for the specific reason. |
SafetyFailureReason
Safety failures are raised during client request validation. If a client request triggers one of the reasons below, it is rejected and the corresponding code is returned in safety_failure.
| Value | Description |
|---|---|
| TraderNotFound | Trader address not found in exchange verified state. |
| NotEnoughCollateral | Minimum collateral requirements breached. |
| NoStrategies | Trader has no strategies configured. |
| StrategyNotFound | Specified strategy id not found for trader. |
| SignatureRecoveryMismatch | EIP-712 signature recovery returned a mismatching trader. |
| InsuranceFundContributionNotFound | Insurance fund contribution not found for the trader. |
| MaxOrderNotionalBreached | Order notional value exceeded the configured maximum. |
| MaxTakerPriceDeviationBreached | Taker price deviated from mark price beyond the allowed percentage. |
| OrderNotFound | Order hash not found in the exchange verified state. |
| OMFLessThanIMF | Strategy OMF is less than the IMF requirement. |
| MaxWithdrawAmountBreached | Withdraw request exceeds the maximum allowed collateral amount. |
| MaxDDXWithdrawAmountBreached | Withdraw request exceeds the maximum allowed DDX amount. |
| TooMuchCollateralToWithdrawDDX | Collateral level would exceed the post-withdrawal maximum after the DDX withdrawal. |
| MaxInsuranceFundWithdrawBreached | Insurance fund withdrawal exceeds the maximum allowed amount. |
| OrderPriceNeg | Order intent specifies a negative price. |
| OrderAmountZeroNeg | Order intent amount is zero or negative. |
| OrderAmountNotMultipleOfMinOrderSize | Order amount is not a multiple of the minimum order size. |
| OrderTypeIncompatibleWithPrice | Order type is invalid for the supplied price (e.g., market order with non-zero price). |
| PriceNotMultipleOfTickSize | Price is not a multiple of the product's tick size. |
| UnsupportedMarket | Symbol does not correspond to a supported market. |
| UnsupportedCurrency | Currency is unsupported (currently only USDC is allowed). |
| TooManyOrders | Strategy already has the maximum number of open orders for the market. |
| WithdrawAmountZeroNeg | Withdraw amount is zero or negative. |
| WithdrawDDXAmountZeroNeg | Withdraw DDX amount is zero or negative. |
| WithdrawInsuranceFundZeroNeg | Insurance fund withdrawal amount is zero or negative. |
| AccessDenied | Trader is not permitted to perform the requested action. |
| CancelNoLiquidityForMarket | Strategy has no liquidity for the symbol; no open orders to cancel. |
| UnsupportedTraderUpdate | Trader update request is not supported. |
| MarketPriceNotAvailable | No mark price is currently available for the symbol. |
Schemas
Bytes21
"0x0030877432d1026706d7e805da846a32c3bb81e3c2"
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| Bytes21 | string(byte) | false | none | 21 byte hex string representing user addresses on the Derivadex platform |
Bytes25
"0x9b62179273c8eb5bb682575ec87a171ac826a6fce48478dcb7"
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| Bytes25 | string(byte) | false | none | 25 byte hex string |
Bytes32
"0x0000000000000000000000000000000000000000000000000000000000000001"
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| Bytes32 | string(byte) | false | none | 32 byte hex string |
Bytes33
"0x4f21345d2cce8038a39d5e0853964b50af03b971722f244f58d669cbee3772a077"
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| Bytes33 | string(byte) | false | none | 33 byte hex string |
EthAddress
"0x12d810a485ed03241b4d419b1b673bd4755d05ad"
20 byte Ethereum address
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| EthAddress | string(byte) | false | none | 20 byte Ethereum address |
OrderSide
"Bid"
Enumerated Values
| Variant | Type | Description |
|---|---|---|
| Bid | string | Int representation is 0 |
| Ask | string | Int representation is 1 |
OrderType
{
"Limit": {
"post_only": true
}
}
Enumerated Values
| Variant | Type | Description |
|---|---|---|
| Limit | object | Int representation is 0 |
| »» post_only | boolean | Whether we want to post the order directly without filling |
| Market | string | Int representation is 1 |
| StopLimit | string | Int representation is 2 |
ProductSymbol
"ETHP"
Compact 6-byte product symbol.
Bytes layout (big-endian, MSB→LSB):
- bit 47 : VERSION flag (1 = v2)
- bits 46..42 : ProductKind (5 bits)
- bits 41..0 : scheme-specific fields (per kind)
Binary Market (BM v2.1) field layout (MSB→LSB, total 42 bits):
- bits 41..40 :
event_len(2 bits) — storeslen-2(so 0→2, 1→3, 2→4) - bits 39..35 : event[0] (A..Z→0..25)
- bits 34..30 : event[1]
- bits 29..25 : event[2]
- bits 24..20 : event[3]
- bits 19..13 : qualifier (7 bits, recommended 0..=99; commonly a year like
25) - bits 12..1 : market id (12 bits, 0..=4095)
- bit 0 : reserved (0)
Perp & Quarterly
Encoded with compact 5-bit letters + small length fields.
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| ProductSymbol | string | false | none | Compact 6-byte product symbol |
Signature
"0x021721a278f64f7fd633dbdde131ca3766e4d58e72e310275dff6c15c0c8e9df469611a11f5125227c3712da86a78c49ea20e32684b27b95e909348334896a68f8"
| Name | Type | Required | Restrictions | Description |
|---|---|---|---|---|
| Signature | string(byte) | false | none | 65 byte hex string |
Realtime API
- Default content type: application/json
The DerivaDEX Realtime API is a WebSockets API that offers real-time market and user data updates.
These updates provide information about the order book and mark price, as well as user-specific data such as outstanding orders, strategy collateral balances, and trader DDX balances.
General notes:
-
TL;DR is the "Operations" section. That will tell you all of the WebSockets endpoints and how to interact with them.
-
We only offer unauthenticated endpoints in part due to the nature of our exchange having all information publicly available and thus independently verifiable by way of Merkle proof. In exchange, we offer filters on
traderAddresses in the parameters of the relevant feed subscriptions so that users can narrow down their feeds to information only relevant to them. Note that publicly verifiable is not necessarily synonymous with zero privacy.In the future, we will implement privacy features (via ZKP) that allow traders to obfuscate details about their trades, strategies, and positions from other traders while still remaining publicly verifiable and retaining the resulting security guarantees.
-
Users are expected to retrieve their initial user data state (e.g., current orders, strategies, balances) via the DerivaDEX REST API, and then rely on the DerivaDEX Realtime API to receive ongoing updates to that data in real time.
-
Our current collateral currency is USDC. Might be subject to additions.
-
Our current quote currency is USD. Not subject to change anytime soon. Unless stated otherwise, this is the default currency for prices.
-
Every outbound message now carries two ordering fields:
•sequence– Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications.
•ordinal– Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. -
Traders are uniquely identified (keyed) by trader address; strategies are uniquely identified by trader address and strategy ID hash; and orders are uniquely identified by trader address, strategy ID hash, and symbol. When subscribing to updates, users can additionally filter on reasons for the update in addition to key attributes. Some notes:
-
Trader addresses are prefixed with its blockchain discriminant. For Ethereum, this is the Ethereum address (20 bytes) prefixed by the hex prefix and blockchain discriminant
0x00to make a string representing 21 bytes. -
A strategy ID hash is exactly the first 4 bytes (abbreviated) of the
keccak256hash of the strategy ID as a 32-byte UTF-8 array with a preceding length byte and zeroes for any extra space. See the code samples for an example. -
A list of valid symbols (tradable products) can be obtained from the REST endpoint
/stats/api/v1/tradable_productsor/exchange/api/v1/symbols.
-
-
All objects disallow additional properties unless stated otherwise. Fields marked with ⚠️ are required.
Code samples
def strategy_id_hash(strategy_id):
# 1. UTF-8 encode and ensure ≤31 bytes
id_bytes = strategy_id.encode('utf-8')
assert len(id_bytes) <= 31, "ID must be at most 31 bytes"
# 2. Build 32-byte buffer:
# • byte 0 = length
# • bytes 1... = data
# • remaining = zero padding
buf = bytes([len(id_bytes)]) + id_bytes + b'\x00' * (31 - len(id_bytes))
# 3. Compute Keccak-256 hash of the 32-byte buffer
digest = keccak256(buf)
# 4. Return first 4 bytes as the abbreviated ID, prefixed with 0x
return '0x' + digest[:4].hex()
short_id = strategy_id_hash("main")
assert short_id == "0x2576ebd1"
Table of Contents
Servers
mainnet Server
- URL:
wss://exchange.derivadex.com/realtime-api - Protocol:
wss
Server providing real-time market and user data updates for mainnet.
Operations
REPLY / Operation: Subscribe
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :open do |event|
payload = {
action: "SUBSCRIBE",
nonce: "foo",
feeds: [
{ feed: "ORDER_BOOK_L2", params: { orderBookL2Filters: [ { symbol: "ETHP", aggregation: 1 } ] } }
]
}
ws.send(payload.to_json)
end
ws.on :message do |event|
p JSON.parse(event.data)
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
payload = {
"action": "SUBSCRIBE",
"nonce": "foo",
"feeds": [
{"feed": "ORDER_BOOK_L2", "params": {"orderBookL2Filters": [{"symbol": "ETHP", "aggregation": 1}]}}
]
}
ws.send(json.dumps(payload))
result = ws.recv()
print(json.loads(result))
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('open', () => {
const payload = {
action: 'SUBSCRIBE',
nonce: 'foo',
feeds: [{ feed: 'ORDER_BOOK_L2', params: { orderBookL2Filters: [{ symbol: 'ETHP', aggregation: 1 }] } }],
};
ws.send(JSON.stringify(payload));
});
ws.addEventListener('message', (event) => {
console.log(JSON.parse(event.data));
ws.close();
});
- Operation ID:
subscribeListener
Receive a feed subscription, reply with an acknowledgement.
Operation tags
| Name | Description |
|---|---|
| websockets | Dealing with or part of the WebSockets protocol. |
Message Subscribe subscribe
Subscribe to a data feed.
- Message ID:
subscribe - Content type: application/json
Subscribe to multiple feeds at once, each with their own (mandatory) respective parameters. Expect a reply/acknowledgement with a nonce matching the given nonce.
Payload
| Name | Type | Description | Value | Constraints | |||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| (root) | object | Information for subscribing to feeds. | - | - | |||||||||||||||||||||||||||||||||
| action ⚠️ | string | WebSockets action. | allowed ("SUBSCRIBE", "UNSUBSCRIBE") |
- | |||||||||||||||||||||||||||||||||
| nonce ⚠️ | string | Unique nonce/ID for identification. | - | - | |||||||||||||||||||||||||||||||||
| feeds ⚠️ | array<object> | The feeds to subscribe to. | - | non-empty | |||||||||||||||||||||||||||||||||
| feeds.feed ⚠️ | string | Feed name. | allowed ("ORDER_BOOK_L2", "ORDER_BOOK_L3", "MARK_PRICE", "ORDER_UPDATE", "STRATEGY_UPDATE", "TRADER_UPDATE") |
- | |||||||||||||||||||||||||||||||||
| feeds.params ⚠️ | oneOf | - | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.0 (oneOf item) | object | The parameters for the order book level 2 feed. No parameters means all L2 book orders for all symbols and all aggregations (be careful). | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.0.orderBookL2Filters | array<object> | Multiple order book L2 filters. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.0.orderBookL2Filters (single item) | object | A single order book L2 filter. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.0.orderBookL2Filters.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.0.orderBookL2Filters.aggregation ⚠️ | number | Aggregation level for prices. Our aggregations vary by symbol and currently are as follows:
|
- | > 0 | |||||||||||||||||||||||||||||||||
| feeds.params.1 (oneOf item) | object | The parameters for the order book level 3 feed. No parameters means all L3 book orders for all symbols (be careful). | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.1.symbols | array<string> | Multiple product symbols for filtering. | - | non-empty | |||||||||||||||||||||||||||||||||
| feeds.params.1.symbols (single item) | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.2 (oneOf item) | object | The parameters for the mark price feed. No parameters means all mark prices for all symbols (be careful). | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.2.symbols | array<string> | Multiple product symbols for filtering. | - | non-empty | |||||||||||||||||||||||||||||||||
| feeds.params.2.symbols (single item) | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.3 (oneOf item) | object | The parameters for the order update feed. No parameters means all order updates for all traders (be careful). | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.3.orderFilters | array<object> | Multiple order filters. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.3.orderFilters (single item) | object | A single order filter. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.3.orderFilters.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||||||||||||||
| feeds.params.3.orderFilters.strategyIdHash | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||||||||||||||
| feeds.params.3.orderFilters.symbol | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.3.orderFilters.reason | integer | The type of order update:
|
allowed (0, 1, 2, 3, 4, 5) |
- | |||||||||||||||||||||||||||||||||
| feeds.params.4 (oneOf item) | object | The parameters for the strategy update feed. No parameters means all strategy updates for all traders (be careful). | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.4.strategyFilters | array<object> | Multiple strategy filters. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.4.strategyFilters (single item) | object | A single strategy filter. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.4.strategyFilters.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||||||||||||||
| feeds.params.4.strategyFilters.strategyIdHash | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||||||||||||||
| feeds.params.4.strategyFilters.reason | integer | The type of strategy update:
|
allowed (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
- | |||||||||||||||||||||||||||||||||
| feeds.params.5 (oneOf item) | object | The parameters for the trader update feed. No parameters means all trader updates for all traders (be careful). | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.5.traderFilters | array<object> | Multiple trader filters. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.5.traderFilters (single item) | object | A single trader filter. | - | - | |||||||||||||||||||||||||||||||||
| feeds.params.5.traderFilters.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||||||||||||||
| feeds.params.5.traderFilters.reason | integer | The type of trader update:
|
allowed (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
- |
Examples of payload
Order book L2 feed subscription with parameters
{
"action": "SUBSCRIBE",
"nonce": "foo",
"feeds": [
{
"feed": "ORDER_BOOK_L2",
"params": {
"orderBookL2Filters": [
{ "symbol": "ETHP", "aggregation": 1 }
]
}
}
]
}
Message tags
| Name | Description |
|---|---|
| websockets | Dealing with or part of the WebSockets protocol. |
Response information
- Reply will be provided via this designated address:
/
Message Acknowledge acknowledge
Acknowledge the receipt of a message.
- Message ID:
acknowledge - Content type: application/json
Acknowledge a message and respond with success or failure.
Payload
| Name | Type | Description | Value | Constraints |
|---|---|---|---|---|
| (root) | object | Acknowledgement of a (un)subscription. | - | - |
| action | string | WebSockets action. | allowed ("SUBSCRIBE", "UNSUBSCRIBE") |
- |
| nonce | string | Unique nonce/ID for identification. | - | - |
| result ⚠️ | object | The result. Empty means success. | - | - |
| result.error | string | The error. | - | - |
Examples of payload
Success
{
"action": "SUBSCRIBE",
"nonce": "foo",
"result": {}
}
Failure
{
"action": "UNSUBSCRIBE",
"nonce": "bar",
"result": {
"error": "Unexpected error."
}
}
Unknown failure
{
"result": {
"error": "Unknown error."
}
}
Message tags
| Name | Description |
|---|---|
| websockets | Dealing with or part of the WebSockets protocol. |
REPLY / Operation: Unsubscribe
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :open do |event|
payload = {
action: "UNSUBSCRIBE",
nonce: "foo",
feeds: ["ORDER_UPDATE", "ORDER_BOOK_L2"]
}
ws.send(payload.to_json)
end
ws.on :message do |event|
p JSON.parse(event.data)
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
payload = {
"action": "UNSUBSCRIBE",
"nonce": "foo",
"feeds": ["ORDER_UPDATE", "ORDER_BOOK_L2"]
}
ws.send(json.dumps(payload))
result = ws.recv()
print(json.loads(result))
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('open', () => {
const payload = {
action: 'UNSUBSCRIBE',
nonce: 'foo',
feeds: ['ORDER_UPDATE', 'ORDER_BOOK_L2'],
};
ws.send(JSON.stringify(payload));
});
ws.addEventListener('message', (event) => {
console.log(JSON.parse(event.data));
ws.close();
});
- Operation ID:
unsubscribeListener
Receive a feed unsubscription, reply with an acknowledgement.
Operation tags
| Name | Description |
|---|---|
| websockets | Dealing with or part of the WebSockets protocol. |
Message Unsubscribe unsubscribe
Unsubscribe from a data feed.
- Message ID:
unsubscribe - Content type: application/json
Unsubscribe from multiple feeds at once. Expect a reply/acknowledgement with a nonce matching the given nonce.
Payload
| Name | Type | Description | Value | Constraints |
|---|---|---|---|---|
| (root) | object | Information for unsubscribing from feeds. | - | - |
| action ⚠️ | string | WebSockets action. | allowed ("SUBSCRIBE", "UNSUBSCRIBE") |
- |
| nonce ⚠️ | string | Unique nonce/ID for identification. | - | - |
| feeds ⚠️ | array<string> | The feeds to unsubscribe from. | - | non-empty |
| feeds (single item) | string | Feed name. | allowed ("ORDER_BOOK_L2", "ORDER_BOOK_L3", "MARK_PRICE", "ORDER_UPDATE", "STRATEGY_UPDATE", "TRADER_UPDATE") |
- |
Examples of payload
Unsubscriptions
{
"action": "UNSUBSCRIBE",
"nonce": "foo",
"feeds": ["ORDER_UPDATE", "ORDER_BOOK_L2"]
}
Message tags
| Name | Description |
|---|---|
| websockets | Dealing with or part of the WebSockets protocol. |
Response information
- Reply will be provided via this designated address:
/
Message Acknowledge acknowledge
Acknowledge the receipt of a message.
- Message ID:
acknowledge - Content type: application/json
Acknowledge a message and respond with success or failure.
Payload
| Name | Type | Description | Value | Constraints |
|---|---|---|---|---|
| (root) | object | Acknowledgement of a (un)subscription. | - | - |
| action | string | WebSockets action. | allowed ("SUBSCRIBE", "UNSUBSCRIBE") |
- |
| nonce | string | Unique nonce/ID for identification. | - | - |
| result ⚠️ | object | The result. Empty means success. | - | - |
| result.error | string | The error. | - | - |
Examples of payload
Success
{
"action": "SUBSCRIBE",
"nonce": "foo",
"result": {}
}
Failure
{
"action": "UNSUBSCRIBE",
"nonce": "bar",
"result": {
"error": "Unexpected error."
}
}
Unknown failure
{
"result": {
"error": "Unknown error."
}
}
Message tags
| Name | Description |
|---|---|
| websockets | Dealing with or part of the WebSockets protocol. |
SEND / Operation: Order Book L2
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :message do |event|
data = JSON.parse(event.data)
next unless data['feed'] == 'ORDER_BOOK_L2'
puts data['contents']
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
result = ws.recv()
data = json.loads(result)
if data.get("feed") == "ORDER_BOOK_L2":
print(data["contents"])
break
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.feed === 'ORDER_BOOK_L2') {
console.log(data.contents);
ws.close();
}
});
- Operation ID:
orderBookL2Sender
Push an order book level 2 snapshot.
Operation tags
| Name | Description |
|---|---|
| public-data | Dealing with public data including but not limited to markets and relevant system information. |
Message Order Book L2 orderBookL2
Provides order book level 2 data.
- Message ID:
orderBookL2 - Content type: application/json
Record order book level 2 data with the given symbol and aggregation.
Upon subscribing, the Order Book L2 Feed will first return a message reflecting the current state of the Order Book (called a PARTIAL). Subsequent messages will contain UPDATEs to that initial state. An amount of "0" is sent in an update to reflect that the order book row is no longer present.
Payload
| Name | Type | Description | Value | Constraints | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| (root) | object | Order book level 2 data. | - | - | ||||||
| sequence ⚠️ | integer | Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications. | - | >= 0 | ||||||
| ordinal ⚠️ | integer | Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. | - | >= 0 | ||||||
| feed ⚠️ | string | Order book level 2 feed name. | const ("ORDER_BOOK_L2") |
- | ||||||
| subscriptionKey ⚠️ | string | Normalized key for ordering scope and subscription identification. | - | - | ||||||
| contents ⚠️ | object | The contents of the message. | - | - | ||||||
| contents.messageType ⚠️ | string | Message type. | allowed ("PARTIAL", "UPDATE") |
- | ||||||
| contents.data ⚠️ | array<object> | The order book data. | - | - | ||||||
| contents.data.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | ||||||
| contents.data.side ⚠️ | integer | The side of the order:
|
allowed (0, 1) |
- | ||||||
| contents.data.amount ⚠️ | string | The aggregated amount for this price level. Stored as string to preserve decimal precision. | - | >= 0 | ||||||
| contents.data.price ⚠️ | string | The aggregated price level. Stored as string to preserve decimal precision. | - | >= 0 |
Examples of payload
Order Book L2 partial snapshot (ETHP)
{
"sequence": 0,
"ordinal": 0,
"feed": "ORDER_BOOK_L2",
"subscriptionKey": "ORDER_BOOK_L2|symbol=ETHP|aggr=0.1",
"contents": {
"messageType": "PARTIAL",
"data": [
{
"symbol": "ETHP",
"side": 0,
"amount": "50.25",
"price": "2000.0"
},
{
"symbol": "ETHP",
"side": 1,
"amount": "100.5",
"price": "2000.5"
}
]
}
}
Order Book L2 update with removal (ETHP)
{
"sequence": 1,
"ordinal": 1,
"feed": "ORDER_BOOK_L2",
"subscriptionKey": "ORDER_BOOK_L2|symbol=ETHP|aggr=1",
"contents": {
"messageType": "UPDATE",
"data": [
{
"symbol": "ETHP",
"side": 0,
"amount": "0",
"price": "2100"
},
{
"symbol": "ETHP",
"side": 1,
"amount": "15.5",
"price": "2101"
}
]
}
}
Order Book L2 partial snapshot (BTCP)
{
"sequence": 0,
"ordinal": 0,
"feed": "ORDER_BOOK_L2",
"subscriptionKey": "ORDER_BOOK_L2|symbol=BTCP|aggr=10",
"contents": {
"messageType": "PARTIAL",
"data": [
{
"symbol": "BTCP",
"side": 0,
"amount": "5",
"price": "30000"
},
{
"symbol": "BTCP",
"side": 1,
"amount": "3.5",
"price": "30050"
}
]
}
}
Message tags
| Name | Description |
|---|---|
| public-data | Dealing with public data including but not limited to markets and relevant system information. |
SEND / Operation: Order Book L3
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :message do |event|
data = JSON.parse(event.data)
next unless data['feed'] == 'ORDER_BOOK_L3'
puts data['contents']
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
result = ws.recv()
data = json.loads(result)
if data.get("feed") == "ORDER_BOOK_L3":
print(data["contents"])
break
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.feed === 'ORDER_BOOK_L3') {
console.log(data.contents);
ws.close();
}
});
- Operation ID:
orderBookL3Sender
Push an order book level 3 snapshot.
Operation tags
| Name | Description |
|---|---|
| public-data | Dealing with public data including but not limited to markets and relevant system information. |
Message Order Book L3 orderBookL3
Provides order book level 3 data.
- Message ID:
orderBookL3 - Content type: application/json
Record order book level 3 data with the given symbol.
Upon subscribing, the Order Book L3 Feed will first return a message reflecting the current state of the Order Book (called a PARTIAL). Subsequent messages will contain UPDATEs to that initial state. An amount of "0" is sent in an update to reflect that the order book row is no longer present.
Payload
| Name | Type | Description | Value | Constraints | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| (root) | object | Order book level 3 data. | - | - | ||||||
| sequence ⚠️ | integer | Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications. | - | >= 0 | ||||||
| ordinal ⚠️ | integer | Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. | - | >= 0 | ||||||
| feed ⚠️ | string | Order book level 3 feed name. | const ("ORDER_BOOK_L3") |
- | ||||||
| subscriptionKey ⚠️ | string | Normalized key for ordering scope and subscription identification. | - | - | ||||||
| contents ⚠️ | object | The contents of the message. | - | - | ||||||
| contents.messageType ⚠️ | string | Message type. | allowed ("PARTIAL", "UPDATE") |
- | ||||||
| contents.data ⚠️ | array<object> | The order book data. | - | - | ||||||
| contents.data.orderHash ⚠️ | string | The unique hash of an order. | - | pattern (^0x[0-9a-fA-f]+$) |
||||||
| contents.data.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | ||||||
| contents.data.side ⚠️ | integer | The side of the order:
|
allowed (0, 1) |
- | ||||||
| contents.data.originalAmount ⚠️ | string | The original amount of the order (before any fills). | - | >= 0 | ||||||
| contents.data.amount ⚠️ | string | The amount of an order. Stored as string to preserve decimal precision. | - | >= 0 | ||||||
| contents.data.price ⚠️ | string | The price of an order. Stored as string to preserve decimal precision. | - | >= 0 | ||||||
| contents.data.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
||||||
| contents.data.strategyIdHash ⚠️ | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
||||||
| contents.data.bookOrdinal ⚠️ | integer | The ordinal of when this order arrived on the book. | - | >= 0 |
Examples of payload
Order Book L3 partial snapshot (ETHP)
{
"sequence": 0,
"ordinal": 0,
"feed": "ORDER_BOOK_L3",
"subscriptionKey": "ORDER_BOOK_L3|symbol=ETHP",
"contents": {
"messageType": "PARTIAL",
"data": [
{
"orderHash": "0x92aaeac66831b00d0db66517debb3eac7370105d854420ed82",
"symbol": "ETHP",
"side": 0,
"originalAmount": "50",
"amount": "50",
"price": "2000",
"traderAddress": "0x00112233445566778899aabbccddeeff0011223344",
"strategyIdHash": "0x2576ebd1",
"bookOrdinal": 0
},
{
"orderHash": "0x83bcdac12345b00d0eb66517debb3eac7370105d854420ed83",
"symbol": "ETHP",
"side": 1,
"originalAmount": "30",
"amount": "30",
"price": "2001",
"traderAddress": "0x00abcdef0123456789abcdef0123456789abcdef01",
"strategyIdHash": "0x2576ebd1",
"bookOrdinal": 1
}
]
}
}
Order Book L3 update with removal (BTCP)
{
"sequence": 1,
"ordinal": 1,
"feed": "ORDER_BOOK_L3",
"subscriptionKey": "ORDER_BOOK_L3|symbol=BTCP",
"contents": {
"messageType": "UPDATE",
"data": [
{
"orderHash": "0x74cdfeaa98765b00d0fb66517debb3eac7370105d854420ed84",
"symbol": "BTCP",
"side": 0,
"originalAmount": "10",
"amount": "5",
"price": "30000",
"traderAddress": "0x00ffeeddccbbaa99887766554433221100ffeeddcc",
"strategyIdHash": "0x2576ebd1",
"bookOrdinal": 2
},
{
"orderHash": "0x12ab3cd456ef7890abcd1234ef5678901234567890abcdef12",
"symbol": "BTCP",
"side": 1,
"originalAmount": "5",
"amount": "0",
"price": "30000",
"traderAddress": "0x00f4d1a2b3c4e5f67890abcdeffedcba0987654321",
"strategyIdHash": "0x2576ebd1",
"bookOrdinal": 3
}
]
}
}
Message tags
| Name | Description |
|---|---|
| public-data | Dealing with public data including but not limited to markets and relevant system information. |
SEND / Operation: Mark Price
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :message do |event|
data = JSON.parse(event.data)
next unless data['feed'] == 'MARK_PRICE'
puts data['contents']
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
result = ws.recv()
data = json.loads(result)
if data.get("feed") == "MARK_PRICE":
print(data["contents"])
break
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.feed === 'MARK_PRICE') {
console.log(data.contents);
ws.close();
}
});
- Operation ID:
markPriceSender
Push a mark price snapshot.
Operation tags
| Name | Description |
|---|---|
| public-data | Dealing with public data including but not limited to markets and relevant system information. |
Message Mark Price markPrice
Provides mark price updates.
- Message ID:
markPrice - Content type: application/json
Record mark price data with the given symbol.
Upon subscribing, the Mark Price Feed will first return a message reflecting the most recent mark prices and funding rates (called a PARTIAL). Subsequent messages will contain new mark prices (and funding rates) as UPDATEs.
Payload
| Name | Type | Description | Value | Constraints |
|---|---|---|---|---|
| (root) | object | Latest mark price for a trading product symbol, as well as its updated funding rate. | - | - |
| sequence ⚠️ | integer | Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications. | - | >= 0 |
| ordinal ⚠️ | integer | Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. | - | >= 0 |
| feed ⚠️ | string | Mark price feed name. | const ("MARK_PRICE") |
- |
| subscriptionKey ⚠️ | string | Normalized key for ordering scope and subscription identification. | - | - |
| contents ⚠️ | object | The contents of the message. | - | - |
| contents.messageType ⚠️ | string | Message type. | allowed ("PARTIAL", "UPDATE") |
- |
| contents.data ⚠️ | array<object> | The mark price chronological data. | - | - |
| contents.data.globalOrdinal ⚠️ | integer | The global ordinal, over all individual updates of this update type. This uniquely identifies an individual update, and can be used for pagination in the REST API. | - | >= 0 |
| contents.data.epochId ⚠️ | integer | The epoch ID. | - | >= 0 |
| contents.data.price ⚠️ | string | The mark price. | - | >= 0 |
| contents.data.fundingRate ⚠️ | string | The new funding rate for this symbol. Stored as a string to preserve decimal precision. | - | - |
| contents.data.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - |
| contents.data.createdAt ⚠️ | string | The timestamp when this object was created. | - | format (dateTime) |
Examples of payload
Mark Price partial snapshot (ETHP)
{
"sequence": 0,
"ordinal": 0,
"feed": "MARK_PRICE",
"subscriptionKey": "MARK_PRICE|symbols=ETHP",
"contents": {
"messageType": "PARTIAL",
"data": [
{
"globalOrdinal": 0,
"epochId": 43,
"price": "1986.81",
"fundingRate": "0.000381",
"symbol": "ETHP",
"createdAt": "2023-10-01T12:00:30Z"
}
]
}
}
Mark Price update (BTCP)
{
"sequence": 1,
"ordinal": 1,
"feed": "MARK_PRICE",
"subscriptionKey": "MARK_PRICE|symbols=BTCP",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 1,
"epochId": 44,
"price": "30500.57",
"fundingRate": "0.003532",
"symbol": "BTCP",
"createdAt": "2023-10-01T12:01:00Z"
}
]
}
}
Message tags
| Name | Description |
|---|---|
| public-data | Dealing with public data including but not limited to markets and relevant system information. |
SEND / Operation: Order Update
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :message do |event|
data = JSON.parse(event.data)
next unless data['feed'] == 'ORDER_UPDATE'
puts data['contents']
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
result = ws.recv()
data = json.loads(result)
if data.get("feed") == "ORDER_UPDATE":
print(data["contents"])
break
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.feed === 'ORDER_UPDATE') {
console.log(data.contents);
ws.close();
}
});
- Operation ID:
orderUpdateSender
Push an order update.
Operation tags
| Name | Description |
|---|---|
| user-data | Dealing with personal user data including but not limited to traders, strategies, and balances. |
Message Order Update orderUpdate
Provides updates for order changes.
- Message ID:
orderUpdate - Content type: application/json
Record order updates with the given trader addresses (and optionally symbol and strategy ID hash), with all maker and taker/liquidated-trader details (including original order intents). Includes order updates due to trades, liquidations, cancellations, and ADLs, as well as order rejections and cancellation rejections. Note that when the order is fully rejected, some of the fields of makerOrderIntent will be filled with the empty string "" (and side and orderType will be 0), as not all information is available, since the "maker" order intent is not created if the order is fully rejected.
Upon subscribing, the Order Update Feed will first return an empty PARTIAL. Users are expected to get the initial state of one's own orders from our REST API. Subsequent messages will contain order UPDATEs to existing orders.
Payload
| Name | Type | Description | Value | Constraints | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| (root) | object | Order update data. | - | - | |||||||||||||||||||||
| sequence ⚠️ | integer | Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications. | - | >= 0 | |||||||||||||||||||||
| ordinal ⚠️ | integer | Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. | - | >= 0 | |||||||||||||||||||||
| feed ⚠️ | string | Order update feed name. | const ("ORDER_UPDATE") |
- | |||||||||||||||||||||
| subscriptionKey ⚠️ | string | Normalized key for ordering scope and subscription identification. | - | - | |||||||||||||||||||||
| contents ⚠️ | object | The contents of the message. | - | - | |||||||||||||||||||||
| contents.messageType ⚠️ | string | Message type. | allowed ("PARTIAL", "UPDATE") |
- | |||||||||||||||||||||
| contents.data ⚠️ | array<object> | The order update data. | - | - | |||||||||||||||||||||
| contents.data.globalOrdinal ⚠️ | integer | The global ordinal, over all individual updates of this update type. This uniquely identifies an individual update, and can be used for pagination in the REST API. | - | >= 0 | |||||||||||||||||||||
| contents.data.epochId ⚠️ | integer | The epoch ID. | - | >= 0 | |||||||||||||||||||||
| contents.data.orderRejection | integer | The order rejection reason (if any):
|
allowed (0, 1, 2, 3, 4, 5) |
- | |||||||||||||||||||||
| contents.data.cancelRejection | integer | The cancel rejection reason (if any):
|
allowed (0) |
- | |||||||||||||||||||||
| contents.data.reason ⚠️ | integer | The type of order update:
|
allowed (0, 1, 2, 3, 4, 5) |
- | |||||||||||||||||||||
| contents.data.amount | string | The fill amount. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.quoteAssetAmount | string | The filled order amount in the quote asset. | - | >= 0 | |||||||||||||||||||||
| contents.data.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||
| contents.data.price | string | The fill price. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.orderMatchOrdinal | integer | The ordinal of the order match outcome that this order update belongs to. Every order update/trade outcome that resulted from the same order match will have the same orderMatchOrdinal. |
- | >= 0 | |||||||||||||||||||||
| contents.data.ordinal | integer | The ordinal of this order update/trade outcome (trade, liquidation, cancellation, or ADL) within its order match outcome. All order updates/trade outcomes that resulted from the same order match will have the same orderMatchOrdinal but different ordinals. |
- | >= 0 | |||||||||||||||||||||
| contents.data.lastExecutedAmount | string | The last/previously executed fill amount of a series of trade outcomes (from a single order match). Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.lastExecutedPrice | string | The last/previously executed fill price of a series of trade outcomes (from a single order match). Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.cumulativeFilledAmount | string | The cumulative filled amount of a series of trade outcomes (from a single order match) up to and including this point. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.cumulativeQuoteAssetTransactedAmount | string | The cumulative transacted amount of the quote asset of a series of trade outcomes (from a single order match) up to and including this point. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.lastQuoteAssetTransactedAmount | string | The last/previously transacted amount of the quote asset of a series of trade outcomes (from a single order match) up to this point. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerOrderIntent ⚠️ | object | An order intent. | - | - | |||||||||||||||||||||
| contents.data.makerOrderIntent.epochId ⚠️ | integer | The epoch ID. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerOrderIntent.orderHash ⚠️ | string | The unique hash of an order. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.makerOrderIntent.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||
| contents.data.makerOrderIntent.side ⚠️ | integer | The side of the order:
|
allowed (0, 1) |
- | |||||||||||||||||||||
| contents.data.makerOrderIntent.amount ⚠️ | string | The amount of an order. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerOrderIntent.price ⚠️ | string | The price of an order. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerOrderIntent.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.makerOrderIntent.strategyIdHash ⚠️ | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.makerOrderIntent.orderType ⚠️ | integer | The order type:
|
allowed (0, 1, 2, 3) |
- | |||||||||||||||||||||
| contents.data.makerOrderIntent.stopPrice ⚠️ | string | The stop price of an order. Stored as string to preserve decimal precision. NOT CURRENTLY ACTIVE. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerOrderIntent.nonce ⚠️ | string | Unique nonce/ID for identification. | - | - | |||||||||||||||||||||
| contents.data.makerOrderIntent.signature ⚠️ | string | A signature used to verify the authenticity of the order, when it was sent by the trader. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.makerOrderIntent.createdAt ⚠️ | string | The timestamp when this object was created. | - | format (dateTime) |
|||||||||||||||||||||
| contents.data.makerFeeCollateral | string | The fee for the maker trade in the collateral currency. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerFeeDDX | string | The fee for the maker trade in DDX. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.makerRealizedPnl | string | The realized PnL for the maker trade in the collateral currency. Stored as string to preserve decimal precision. | - | - | |||||||||||||||||||||
| contents.data.takerOrderIntent | object | An order intent. | - | - | |||||||||||||||||||||
| contents.data.takerOrderIntent.epochId ⚠️ | integer | The epoch ID. | - | >= 0 | |||||||||||||||||||||
| contents.data.takerOrderIntent.orderHash ⚠️ | string | The unique hash of an order. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.takerOrderIntent.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | |||||||||||||||||||||
| contents.data.takerOrderIntent.side ⚠️ | integer | The side of the order:
|
allowed (0, 1) |
- | |||||||||||||||||||||
| contents.data.takerOrderIntent.amount ⚠️ | string | The amount of an order. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.takerOrderIntent.price ⚠️ | string | The price of an order. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.takerOrderIntent.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.takerOrderIntent.strategyIdHash ⚠️ | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.takerOrderIntent.orderType ⚠️ | integer | The order type:
|
allowed (0, 1, 2, 3) |
- | |||||||||||||||||||||
| contents.data.takerOrderIntent.stopPrice ⚠️ | string | The stop price of an order. Stored as string to preserve decimal precision. NOT CURRENTLY ACTIVE. | - | >= 0 | |||||||||||||||||||||
| contents.data.takerOrderIntent.nonce ⚠️ | string | Unique nonce/ID for identification. | - | - | |||||||||||||||||||||
| contents.data.takerOrderIntent.signature ⚠️ | string | A signature used to verify the authenticity of the order, when it was sent by the trader. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.takerOrderIntent.createdAt ⚠️ | string | The timestamp when this object was created. | - | format (dateTime) |
|||||||||||||||||||||
| contents.data.takerFeeCollateral | string | The fee for the taker trade in the collateral currency. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.takerFeeDDX | string | The fee for the taker trade in DDX. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||
| contents.data.takerRealizedPnl | string | The realized PnL for the taker trade in the collateral currency. Stored as string to preserve decimal precision. | - | - | |||||||||||||||||||||
| contents.data.liquidatedTraderAddress | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.liquidatedStrategyIdHash | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||
| contents.data.createdAt ⚠️ | string | The timestamp when this object was created. | - | format (dateTime) |
Examples of payload
Order Update - empty partial
{
"sequence": 0,
"ordinal": 0,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "PARTIAL",
"data": []
}
}
Order Update - post
{
"sequence": 1,
"ordinal": 1,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 0,
"epochId": 200,
"reason": 0,
"amount": "0",
"quoteAssetAmount": "0",
"symbol": "ETHP",
"orderMatchOrdinal": 8,
"ordinal": 0,
"makerOrderIntent": {
"epochId": 200,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "20",
"price": "100",
"traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-1",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"createdAt": "2023-10-01T12:00:05Z"
}
]
}
}
Order Update - trade (with trade outcome cancels)
{
"sequence": 2,
"ordinal": 2,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 0,
"epochId": 200,
"reason": 1,
"amount": "10",
"quoteAssetAmount": "2000",
"symbol": "ETHP",
"price": "100",
"orderMatchOrdinal": 10,
"ordinal": 0,
"cumulativeFilledAmount": "10",
"cumulativeQuoteAssetTransactedAmount": "2000",
"makerRealizedPnl": "30",
"takerFeeDDX": "0.05",
"takerRealizedPnl": "50",
"makerOrderIntent": {
"epochId": 200,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "20",
"price": "100",
"traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-1",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"takerOrderIntent": {
"epochId": 200,
"orderHash": "0xb1c2d3e4f5a67890abcdef0123456789234567890abcdef12",
"symbol": "ETHP",
"side": 1,
"amount": "20",
"price": "100",
"traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-taker-1",
"signature": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"createdAt": "2023-10-01T11:59:55Z"
},
"createdAt": "2023-10-01T12:00:05Z"
},
{
"globalOrdinal": 1,
"epochId": 200,
"reason": 3,
"amount": "10",
"quoteAssetAmount": "3000",
"symbol": "ETHP",
"orderMatchOrdinal": 10,
"ordinal": 1,
"makerOrderIntent": {
"epochId": 200,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "20",
"price": "100",
"traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-1",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"takerOrderIntent": {
"epochId": 200,
"orderHash": "0xb1c2d3e4f5a67890abcdef0123456789234567890abcdef12",
"symbol": "ETHP",
"side": 1,
"amount": "20",
"price": "100",
"traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-taker-1",
"signature": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"createdAt": "2023-10-01T11:59:55Z"
},
"createdAt": "2023-10-01T12:00:05Z"
}
]
}
}
Order Update - order rejection (SelfMatch) with previous trade outcomes
{
"sequence": 3,
"ordinal": 3,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 2,
"epochId": 201,
"reason": 1,
"amount": "20",
"quoteAssetAmount": "2000",
"symbol": "ETHP",
"price": "100",
"orderMatchOrdinal": 10,
"ordinal": 0,
"cumulativeFilledAmount": "20",
"cumulativeQuoteAssetTransactedAmount": "2000",
"makerRealizedPnl": "30",
"takerFeeDDX": "0.05",
"takerRealizedPnl": "50",
"makerOrderIntent": {
"epochId": 201,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "5",
"price": "100",
"traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-rej",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"takerOrderIntent": {
"epochId": 201,
"orderHash": "0xb1c2d3e4f5a67890abcdef0123456789234567890abcdef12",
"symbol": "ETHP",
"side": 1,
"amount": "20",
"price": "100",
"traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-taker-1",
"signature": "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"createdAt": "2023-10-01T11:59:55Z"
},
"createdAt": "2023-10-01T12:00:05Z"
},
{
"globalOrdinal": 3,
"epochId": 201,
"orderRejection": 0,
"reason": 4,
"amount": "0",
"quoteAssetAmount": "0",
"symbol": "ETHP",
"price": "100",
"lastExecutedAmount": "20",
"lastExecutedPrice": "100",
"cumulativeFilledAmount": "20",
"cumulativeQuoteAssetTransactedAmount": "2000",
"lastQuoteAssetTransactedAmount": "2000",
"makerOrderIntent": {
"epochId": 201,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "5",
"price": "100",
"traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-rej",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"createdAt": "2023-10-01T12:00:10Z"
}
]
}
}
Order Update - full order rejection (InvalidStrategy)
{
"sequence": 4,
"ordinal": 4,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 4,
"epochId": 201,
"orderRejection": 4,
"reason": 4,
"amount": "0",
"symbol": "ETHP",
"price": "100",
"makerOrderIntent": {
"epochId": 201,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "5",
"price": "",
"traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "",
"nonce": "",
"signature": "",
"createdAt": "2023-10-01T11:59:50Z"
},
"createdAt": "2023-10-01T12:00:10Z"
}
]
}
}
Order Update - user cancellation
{
"sequence": 5,
"ordinal": 5,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 5,
"epochId": 201,
"reason": 3,
"amount": "30",
"quoteAssetAmount": "3000",
"symbol": "ETHP",
"orderMatchOrdinal": 11,
"ordinal": 0,
"makerOrderIntent": {
"epochId": 201,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "5",
"price": "100",
"traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-cancel",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"createdAt": "2023-10-01T12:00:10Z"
}
]
}
}
Order Update - user cancellation rejection
{
"sequence": 6,
"ordinal": 6,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 6,
"epochId": 201,
"cancelRejection": 0,
"reason": 5,
"symbol": "ETHP",
"makerOrderIntent": {
"epochId": 201,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "5",
"price": "100",
"traderAddress": "0x00c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-cancel-rej",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"createdAt": "2023-10-01T12:00:10Z"
}
]
}
}
Order Update - liquidation
{
"sequence": 7,
"ordinal": 7,
"feed": "ORDER_UPDATE",
"subscriptionKey": "ORDER_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|symbol=ETHP|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 7,
"epochId": 200,
"reason": 2,
"amount": "20",
"quoteAssetAmount": "2000",
"symbol": "ETHP",
"price": "100",
"orderMatchOrdinal": 12,
"ordinal": 0,
"cumulativeFilledAmount": "20",
"cumulativeQuoteAssetTransactedAmount": "2000",
"makerRealizedPnl": "30",
"makerOrderIntent": {
"epochId": 200,
"orderHash": "0xa1b2c3d4e5f67890abcdef01234567891234567890123456789",
"symbol": "ETHP",
"side": 0,
"amount": "20",
"price": "100",
"traderAddress": "0x00f1e2d3c4b5a6978899aabbccddeeff1122334455",
"strategyIdHash": "0x2576ebd1",
"orderType": 0,
"stopPrice": "0",
"nonce": "nonce-maker-liq",
"signature": "0xfedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
"createdAt": "2023-10-01T11:59:50Z"
},
"liquidatedTraderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"liquidatedStrategyIdHash": "0x2576ebd1",
"createdAt": "2023-10-01T12:00:05Z"
}
]
}
}
Message tags
| Name | Description |
|---|---|
| user-data | Dealing with personal user data including but not limited to traders, strategies, and balances. |
SEND / Operation: Strategy Update
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :message do |event|
data = JSON.parse(event.data)
next unless data['feed'] == 'STRATEGY_UPDATE'
puts data['contents']
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
result = ws.recv()
data = json.loads(result)
if data.get("feed") == "STRATEGY_UPDATE":
print(data["contents"])
break
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.feed === 'STRATEGY_UPDATE') {
console.log(data.contents);
ws.close();
}
});
- Operation ID:
strategyUpdateSender
Push a strategy update.
Operation tags
| Name | Description |
|---|---|
| user-data | Dealing with personal user data including but not limited to traders, strategies, and balances. |
Message Strategy Update strategyUpdate
Provides updates for strategy collateral changes.
- Message ID:
strategyUpdate - Content type: application/json
Record strategy (collateral) updates with the given trader addresses (and optionally strategy ID hash), including positions if PnL was realized. Includes strategy updates due to deposits, withdrawals, withdrawal intents, funding payments, and PnL realization, as well as withdrawal rejections.
Upon subscribing, the Strategy Update Feed will first return an empty PARTIAL. Users are expected to get the initial state of one's own strategies from our REST API. Subsequent messages will contain strategy UPDATEs to existing strategies.
Payload
| Name | Type | Description | Value | Constraints | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| (root) | object | The strategy update data. | - | - | ||||||||||||||||||||||||||||||||||
| sequence ⚠️ | integer | Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications. | - | >= 0 | - | |||||||||||||||||||||||||||||||||
| ordinal ⚠️ | integer | Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. | - | >= 0 | - | |||||||||||||||||||||||||||||||||
| feed ⚠️ | string | Strategy update feed name. | const ("STRATEGY_UPDATE") |
- | ||||||||||||||||||||||||||||||||||
| subscriptionKey ⚠️ | string | Normalized key for ordering scope and subscription identification. | - | - | ||||||||||||||||||||||||||||||||||
| contents ⚠️ | object | The contents of the message. | - | - | ||||||||||||||||||||||||||||||||||
| contents.messageType ⚠️ | string | Message type. | allowed ("PARTIAL", "UPDATE") |
- | ||||||||||||||||||||||||||||||||||
| contents.data ⚠️ | array<object> | The strategy update data. | - | - | ||||||||||||||||||||||||||||||||||
| contents.data.globalOrdinal ⚠️ | integer | The global ordinal, over all individual updates of this update type. This uniquely identifies an individual update, and can be used for pagination in the REST API. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.epochId ⚠️ | integer | The epoch ID. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.withdrawRejection | integer | The withdraw rejection reason (if any):
|
allowed (0, 1, 2, 3, 4) |
- | ||||||||||||||||||||||||||||||||||
| contents.data.reason ⚠️ | integer | The type of strategy update:
|
allowed (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
- | ||||||||||||||||||||||||||||||||||
| contents.data.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
||||||||||||||||||||||||||||||||||
| contents.data.strategyIdHash ⚠️ | string | The strategy ID hash. | - | pattern (^0x[0-9a-fA-f]+$) |
||||||||||||||||||||||||||||||||||
| contents.data.collateralAddress ⚠️ | string | The collateral address on which this strategy update took place. | - | pattern (^0x[0-9a-fA-f]+$) |
||||||||||||||||||||||||||||||||||
| contents.data.collateralSymbol ⚠️ | string | A collateral symbol, e.g. USDC. Might be subject to additions. | allowed ("USDC") |
- | ||||||||||||||||||||||||||||||||||
| contents.data.amount | string | The amount added to the strategy (may be negative). If we are realizing PnL (reason is 4), then amount = sum(positions.realizedPnl) Stored as string to preserve decimal precision. |
- | - | ||||||||||||||||||||||||||||||||||
| contents.data.newAvailCollateral | string | If affected, the available collateral amount after this strategy update. Stored as string to preserve decimal precision. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.newLockedCollateral | string | If affected, the locked collateral amount after this strategy update. Stored as string to preserve decimal precision. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.blockNumber | integer | The block number in which this strategy update was processed, if applicable. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.positions | array<object> | The positions following a PnL realization. This field will be null for strategy updates not containing a PnL realization. | - | - | ||||||||||||||||||||||||||||||||||
| contents.data.positions.symbol ⚠️ | string | A product symbol, e.g. ETHP. | - | - | ||||||||||||||||||||||||||||||||||
| contents.data.positions.balance ⚠️ | string | Position balance (after PnL was realized, if applicable). Stored as string to preserve decimal precision. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.positions.side ⚠️ | integer | The side of the position:
|
allowed (0, 1) |
- | ||||||||||||||||||||||||||||||||||
| contents.data.positions.avgEntryPrice ⚠️ | string | Average entry price (after PnL was realized, if applicable). Stored as string to preserve decimal precision. | - | >= 0 | ||||||||||||||||||||||||||||||||||
| contents.data.positions.realizedPnl ⚠️ | string | The realized PnL from a PnL realization in the collateral currency. Stored as string to preserve decimal precision. | - | - | ||||||||||||||||||||||||||||||||||
| contents.data.createdAt ⚠️ | string | The timestamp when this object was created. | - | format (dateTime) |
Examples of payload
Strategy Update - empty partial
{
"sequence": 0,
"ordinal": 0,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "PARTIAL",
"data": []
}
}
Strategy Update - deposit (USDC)
{
"sequence": 1,
"ordinal": 1,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 0,
"epochId": 300,
"reason": 0,
"traderAddress": "0x00a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"collateralSymbol": "USDC",
"amount": "1000",
"newAvailCollateral": "5000",
"blockNumber": 150000,
"createdAt": "2023-10-01T12:05:00Z"
}
]
}
}
Strategy Update - withdrawal (USDC)
{
"sequence": 2,
"ordinal": 2,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 1,
"epochId": 304,
"reason": 1,
"traderAddress": "0x00e9f8d7c6b5a4e3f2d1c0b9a8f7e6d5c4b3a2f1e0",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00abc123def4567890abcdef1234567890abcdef",
"collateralSymbol": "USDC",
"amount": "-150",
"newLockedCollateral": "10",
"blockNumber": 150200,
"createdAt": "2023-10-01T12:10:00Z"
}
]
}
}
Strategy Update - withdrawal intent (USDC)
{
"sequence": 3,
"ordinal": 3,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00ffeeddccbbaa99887766554433221100ffeeddcc|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 5,
"epochId": 306,
"reason": 2,
"traderAddress": "0x00ffeeddccbbaa99887766554433221100ffeeddcc",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00112233445566778899aabbccddeeff00112233",
"collateralSymbol": "USDC",
"amount": "200",
"newAvailCollateral": "100",
"newLockedCollateral": "210",
"createdAt": "2023-10-01T12:11:00Z"
}
]
}
}
Strategy Update - withdrawal rejection (USDC)
{
"sequence": 4,
"ordinal": 4,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 2,
"epochId": 301,
"reason": 9,
"withdrawRejection": 0,
"traderAddress": "0x00b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9ba",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"collateralSymbol": "USDC",
"blockNumber": 150220,
"createdAt": "2023-10-01T12:06:00Z"
}
]
}
}
Strategy Update - PnL realization (USDC)
{
"sequence": 5,
"ordinal": 5,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 3,
"epochId": 303,
"reason": 4,
"traderAddress": "0x00d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9ab1234",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9ab1235",
"collateralSymbol": "USDC",
"amount": "5",
"positions": [
{
"symbol": "ETHP",
"balance": "50",
"side": 0,
"avgEntryPrice": "95",
"realizedPnl": "5"
}
],
"createdAt": "2023-10-01T12:08:00Z"
}
]
}
}
Strategy Update - Liquidation
{
"sequence": 6,
"ordinal": 6,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 4,
"epochId": 305,
"reason": 7,
"traderAddress": "0x00e9f8d7c6b5a4e3f2d1c0b9a8f7e6d5c4b3a2f1e0",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00abc123def4567890abcdef1234567890abcdef",
"collateralSymbol": "USDC",
"amount": "-1000",
"newAvailCollateral": "0",
"createdAt": "2023-10-01T12:12:00Z"
}
]
}
}
Strategy Update - funding payment (USDC)
{
"sequence": 7,
"ordinal": 7,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00abcdef0123456789abcdef0123456789abcdef01|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 6,
"epochId": 307,
"reason": 3,
"traderAddress": "0x00abcdef0123456789abcdef0123456789abcdef01",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x002233445566778899aabbccddeeff0011223344",
"collateralSymbol": "USDC",
"amount": "12",
"newAvailCollateral": "4512",
"createdAt": "2023-10-01T12:13:30Z"
}
]
}
}
Strategy Update - trade fill (Trade + Fee)
{
"sequence": 8,
"ordinal": 8,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00aabbccddeeff00112233445566778899aabbccdd|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 7,
"epochId": 308,
"reason": 5,
"traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00abc123def4567890abcdef1234567890abcdef",
"collateralSymbol": "USDC",
"amount": "25",
"positions": [
{
"symbol": "ETHP",
"balance": "40",
"side": 0,
"avgEntryPrice": "100",
"realizedPnl": "25"
}
],
"newAvailCollateral": "2000",
"createdAt": "2023-10-01T12:14:00Z"
},
{
"globalOrdinal": 8,
"epochId": 308,
"reason": 6,
"traderAddress": "0x00aabbccddeeff00112233445566778899aabbccdd",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00abc123def4567890abcdef1234567890abcdef",
"collateralSymbol": "USDC",
"amount": "-0.75",
"newAvailCollateral": "1999.25",
"createdAt": "2023-10-01T12:14:00Z"
}
]
}
}
Strategy Update - ADL
{
"sequence": 9,
"ordinal": 9,
"feed": "STRATEGY_UPDATE",
"subscriptionKey": "STRATEGY_UPDATE|trader=0x00abcabcabcabcabcabcabcabcabcabcabcabcab|strategy=0x2576ebd1|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 9,
"epochId": 309,
"reason": 8,
"traderAddress": "0x00abcabcabcabcabcabcabcabcabcabcabcabcab",
"strategyIdHash": "0x2576ebd1",
"collateralAddress": "0x00abcabcabcabcabcabcabcabcabcabcabcabcab",
"collateralSymbol": "USDC",
"amount": "-100",
"newAvailCollateral": "3000",
"createdAt": "2023-10-01T12:14:30Z"
}
]
}
}
Message tags
| Name | Description |
|---|---|
| user-data | Dealing with personal user data including but not limited to traders, strategies, and balances. |
SEND / Operation: Trader Update
Code samples
require 'faye/websocket'
require 'eventmachine'
require 'json'
EM.run do
ws = Faye::WebSocket::Client.new('wss://exchange.derivadex.com/realtime-api')
ws.on :message do |event|
data = JSON.parse(event.data)
next unless data['feed'] == 'TRADER_UPDATE'
puts data['contents']
ws.close
end
endimport websocket
import json
ws = websocket.create_connection("wss://exchange.derivadex.com/realtime-api")
while True:
result = ws.recv()
data = json.loads(result)
if data.get("feed") == "TRADER_UPDATE":
print(data["contents"])
break
ws.close()const ws = new WebSocket('wss://exchange.derivadex.com/realtime-api');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.feed === 'TRADER_UPDATE') {
console.log(data.contents);
ws.close();
}
});
- Operation ID:
traderUpdateSender
Push a trader update.
Operation tags
| Name | Description |
|---|---|
| user-data | Dealing with personal user data including but not limited to traders, strategies, and balances. |
Message Trader Update traderUpdate
Provides updates for trader DDX balances.
- Message ID:
traderUpdate - Content type: application/json
Record trader (DDX balance) updates with the given trader addresses. Includes trader updates due to DDX deposits, DDX withdrawals, DDX withdrawal intents, trade mining rewards, fee distribution rewards, and profile updates as well as DDX withdrawal rejections.
Upon subscribing, the Trader Update Feed will first return an empty PARTIAL. Users are expected to get the initial state of one's own trader balances from our REST API. Subsequent messages will contain trader UPDATEs to existing trader balances.
Payload
| Name | Type | Description | Value | Constraints | |||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| (root) | object | The trader update data. | - | - | |||||||||||||||||||||||||||||||||
| sequence ⚠️ | integer | Global, monotonically increasing sequence assigned by the server to every notification across all feeds across all connections. In a given connection's view, it might NOT increment by 1 every time, since a particular connection's subscriptions may not be affected by all notifications. | - | >= 0 | |||||||||||||||||||||||||||||||||
| ordinal ⚠️ | integer | Per-connection monotonically increasing sequence number of a message over all subscribed feeds of a connection. Every message in a connection will increment this value by 1 and thus establishes an ordering across all feed messages in a connection. | - | >= 0 | |||||||||||||||||||||||||||||||||
| feed ⚠️ | string | Trader update feed name. | const ("TRADER_UPDATE") |
- | |||||||||||||||||||||||||||||||||
| subscriptionKey ⚠️ | string | Normalized key for ordering scope and subscription identification. | - | - | |||||||||||||||||||||||||||||||||
| contents ⚠️ | object | The contents of the message. | - | - | |||||||||||||||||||||||||||||||||
| contents.messageType ⚠️ | string | Message type. | allowed ("PARTIAL", "UPDATE") |
- | |||||||||||||||||||||||||||||||||
| contents.data ⚠️ | array<object> | The trader update data. | - | - | |||||||||||||||||||||||||||||||||
| contents.data.globalOrdinal ⚠️ | integer | The global ordinal, over all individual updates of this update type. This uniquely identifies an individual update, and can be used for pagination in the REST API. | - | >= 0 | |||||||||||||||||||||||||||||||||
| contents.data.epochId ⚠️ | integer | The epoch ID. | - | >= 0 | |||||||||||||||||||||||||||||||||
| contents.data.withdrawDDXRejection | integer | The DDX withdraw rejection reason (if any):
|
allowed (0, 1) |
- | |||||||||||||||||||||||||||||||||
| contents.data.reason ⚠️ | integer | The type of trader update:
|
allowed (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) |
- | |||||||||||||||||||||||||||||||||
| contents.data.traderAddress ⚠️ | string | The trader address prefixed with the blockchain discriminant. | - | pattern (^0x[0-9a-fA-f]+$) |
|||||||||||||||||||||||||||||||||
| contents.data.amount | string | The amount added to the trader's DDX balance (may be negative). Stored as string to preserve decimal precision. | - | - | |||||||||||||||||||||||||||||||||
| contents.data.newAvailDDXBalance | string | If affected, the available DDX balance after this trader update. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||||||||||||||
| contents.data.newLockedDDXBalance | string | If affected, the locked DDX balance after this trader update. Stored as string to preserve decimal precision. | - | >= 0 | |||||||||||||||||||||||||||||||||
| contents.data.payFeesInDDX | boolean | Whether to pay trading fees in DDX or in the collateral currency. | - | - | |||||||||||||||||||||||||||||||||
| contents.data.blockNumber | integer | The block number in which this trader update was processed, if applicable. | - | - | |||||||||||||||||||||||||||||||||
| contents.data.createdAt ⚠️ | string | The timestamp when this object was created. | - | format (dateTime) |
Examples of payload
Trader Update - empty partial
{
"sequence": 0,
"ordinal": 0,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00123456789abcdef0123456789abcdef01234567|reason=3",
"contents": {
"messageType": "PARTIAL",
"data": []
}
}
Trader Update - DDX deposit
{
"sequence": 1,
"ordinal": 1,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00112233445566778899aabbccddeeff00112233|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 0,
"epochId": 500,
"reason": 0,
"traderAddress": "0x00112233445566778899aabbccddeeff00112233",
"amount": "150",
"newAvailDDXBalance": "1150",
"blockNumber": 123456,
"createdAt": "2023-10-01T12:15:00Z"
}
]
}
}
Trader Update - DDX withdrawal
{
"sequence": 2,
"ordinal": 2,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00112233445566778899aabbccddeeff00112233|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 4,
"epochId": 504,
"reason": 1,
"traderAddress": "0x00112233445566778899aabbccddeeff00112233",
"amount": "-150",
"newLockedDDXBalance": "1000",
"createdAt": "2023-10-01T12:18:00Z"
}
]
}
}
Trader Update - DDX withdraw intent
{
"sequence": 3,
"ordinal": 3,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 1,
"epochId": 503,
"reason": 2,
"traderAddress": "0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd",
"amount": "150",
"newAvailDDXBalance": "1220",
"newLockedDDXBalance": "35",
"createdAt": "2023-10-01T12:16:00Z"
}
]
}
}
Trader Update - DDX withdrawal rejection
{
"sequence": 4,
"ordinal": 4,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 2,
"epochId": 501,
"reason": 9,
"withdrawDDXRejection": 1,
"traderAddress": "0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd",
"createdAt": "2023-10-01T12:16:00Z"
}
]
}
}
Trader Update - profile update
{
"sequence": 5,
"ordinal": 5,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00fedcba9876543210fedcba9876543210fedcba98|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 3,
"epochId": 502,
"reason": 4,
"traderAddress": "0x00fedcba9876543210fedcba9876543210fedcba98",
"payFeesInDDX": true,
"createdAt": "2023-10-01T12:17:00Z"
}
]
}
}
Trader Update - trade mining reward
{
"sequence": 6,
"ordinal": 6,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 5,
"epochId": 505,
"reason": 3,
"traderAddress": "0x00abcdefabcdefabcdefabcdefabcdefabcdefabcd",
"amount": "12",
"newAvailDDXBalance": "1232",
"createdAt": "2023-10-01T12:19:00Z"
}
]
}
}
Trader Update - DDX fee charged
{
"sequence": 7,
"ordinal": 7,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00fedcba9876543210fedcba9876543210fedcba98|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 6,
"epochId": 506,
"reason": 8,
"traderAddress": "0x00fedcba9876543210fedcba9876543210fedcba98",
"amount": "-0.1",
"newAvailDDXBalance": "999.9",
"createdAt": "2023-10-01T12:19:30Z"
}
]
}
}
Trader Update - fee distribution reward
{
"sequence": 8,
"ordinal": 8,
"feed": "TRADER_UPDATE",
"subscriptionKey": "TRADER_UPDATE|trader=0x00ffeeddccbbaa99887766554433221100ffeeddcc|reason=",
"contents": {
"messageType": "UPDATE",
"data": [
{
"globalOrdinal": 7,
"epochId": 507,
"reason": 5,
"traderAddress": "0x00ffeeddccbbaa99887766554433221100ffeeddcc",
"amount": "3",
"newAvailDDXBalance": "1003",
"createdAt": "2023-10-01T12:20:00Z"
}
]
}
}
Message tags
| Name | Description |
|---|---|
| user-data | Dealing with personal user data including but not limited to traders, strategies, and balances. |
Auditor
The Auditor is a Pythonic application that connects to the DerivaDEX Operators' WebSocket API upon initialization and allows anyone to validate the honesty and integrity of the exchange's operations.
Running the Auditor is not required to trade on the exchange, however can certainly be run in-band or out-of-band with respect to programmatic strategies to ensure you are verifiably up-to-date with the latest exchange data.
DerivaDEX's data model is powered by a Sparse Merkle Tree data store and a transaction log of state-modifying transitions. These are emitted in raw formats by the DerivaDEX Operators API, and the Auditor efficiently processes them to perform validation.
Setup
To run the Auditor from source, follow these steps from the DerivaDEX ddx repository (< 5 minutes):
-
If you don't already have it, it is recommended you set up Anaconda/Python(>3) on your machine
-
Initialize and activate a Conda environment (located at the root level of the repo) from which you will run the Auditor:
conda env create -f environment.yml && conda activate derivadex -
Set your PYTHONPATH:
export PYTHONPATH="${PYTHONPATH}:/your/full/path/upto/but/not/including/ddx" -
Navigate to the
auditorsubdirectory and create an.auditor.conf.jsonfile using the template:cp .auditor.conf.json.template .auditor.conf.json -
Run the Auditor with:
PYTHON_LOG=info python auditor_driver.py --config ".auditor.conf.json"
You will almost immediately see logging messages (should be lots of green) with state initialized and transactions streaming through successfully.
Voila! You now have the Auditor running locally validating the entire DerivaDEX exchange!
Sparse Merkle Tree
DerivaDEX utilizes a Sparse Merkle Tree (SMT) in order to efficiently maintain the state of the exchange at all times. Storing data on-chain (such as user's balances and positions), something most decentralized exchanges do, is very costly and one that is usually passed on to the user, making exchange use prohibitively expensive to most. An SMT, however, allows the system to only store a single root hash (the root of the tree) on-chain, while still allowing for anyone to verify the integrity of the data (leaves) through inclusion (or non-inclusion) proofs.
So what kind of data is stored and where in the SMT? The short answer is - everything. This means any data pertaining to a trader (their account-level data, strategy-level data, positions, and volume statistics), to a given market (the various open orders and the price feed information), and to the system (the insurance fund capitalization) is stored as individual leaf entries in the SMT. The DerivaDEX SMT consists of 2^256 possible leaves, each uniquely located at a specific leaf location (as indicated by its key, which is a 32-byte value). As you might surmise, the vast majority of the SMT will be empty (2^256 is very, very, very large number), but the data that does exist can exist at a location anywhere within these large bounds. For efficient querying and data management (while maintaining practical collision-resistance), the various types of leaf items are prefixed to reside in the same general vicinity as one another. Each leaf item type is described in detail below. The full set of leaf types can be seen in the following table, along with their corresponding numeric discriminants.
| Item | Discriminant |
|---|---|
| Empty | 0 |
| Trader | 1 |
| Strategy | 2 |
| Position | 3 |
| BookOrder | 4 |
| Price | 5 |
| InsuranceFund | 6 |
| Stats | 7 |
| Signer | 8 |
| Specs | 9 |
| InsuranceFundContribution | 10 |
| FeePool | 11 |
| EpochMetadata | 12 |
Each leaf type is described in detail below.
Trader
A Trader leaf contains information pertaining to a trader's available and locked DDX balances, referral address, and fee payment mechanism.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right
def encode_key(trader_address: str):
# ItemType.TRADER == 1
return zpad32_right(
ItemType.TRADER.to_bytes(1, byteorder="little")
+ bytes.fromhex(trader_address[2:])
)
def decode_key(trader_key: bytes):
# trader_address
return f"0x{trader_key[1:22].hex()}"
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right
def encode_key(trader_address: str):
# ItemType.TRADER == 1
return zpad32_right(
ItemType.TRADER.to_bytes(1, byteorder="little")
+ bytes.fromhex(trader_address[2:])
)
def decode_key(trader_key: bytes):
# trader_address
return f"0x{trader_key[1:22].hex()}"The location of a Trader leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Trader discriminant |
| [1, 21] | Trader's Ethereum address prefixed with the chain discriminant |
| [22, 31] | Zero-padding |
The following sample Trader materials generates the following encoded key: 0x0100603699848c84529987e14ba32c8a66def67e9ece00000000000000000000.
| field | value |
|---|---|
| trader_address | "0x00603699848c84529987E14Ba32C8a66DEF67E9eCE" |
Value definition
Value encoding / decoding (Python)
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, avail_ddx_balance: Decimal, locked_ddx_balance: Decimal, referral_address: str):
# Trader item discriminant
item_type = 1
# Scale collateral amounts to grains
return encode_single(
"(uint8,(uint128,uint128,address,bool))",
[
item_type,
[
to_base_unit_amount(avail_ddx_balance, 6),
to_base_unit_amount(locked_ddx_balance, 6),
referral_address,
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(
item_type,
(avail_ddx_balance, locked_ddx_balance, referral_address),
) = decode_single(
"(uint8,(uint128,uint128,address,bool))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale collateral amounts from grains
return (
to_unit_amount(avail_ddx_balance, 6),
to_unit_amount(locked_ddx_balance, 6),
referral_address,
)
Value encoding / decoding (Python)
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, avail_ddx_balance: Decimal, locked_ddx_balance: Decimal, referral_address: str):
# Trader item discriminant
item_type = 1
# Scale collateral amounts to grains
return encode_single(
"(uint8,(uint128,uint128,address,bool))",
[
item_type,
[
to_base_unit_amount(avail_ddx_balance, 6),
to_base_unit_amount(locked_ddx_balance, 6),
referral_address,
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(
item_type,
(avail_ddx_balance, locked_ddx_balance, referral_address),
) = decode_single(
"(uint8,(uint128,uint128,address,bool))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale collateral amounts from grains
return (
to_unit_amount(avail_ddx_balance, 6),
to_unit_amount(locked_ddx_balance, 6),
referral_address,
)A Trader leaf holds the following data:
| type | field | description |
|---|---|---|
| decimal | avail_ddx_balance | DDX collateral available for staking/fees |
| decimal | locked_ddx_balance | DDX collateral available for on-chain withdrawal |
| address_s | referral_address | Referral address pertaining to the Ethereum address who referred this trader (if applicable) |
| bool | pay_fees_in_ddx | Whether trader has opted to pay fees in DDX by default or not |
These contents are always stored in the tree in ABI-encoded form: (uint8,(uint128,uint128,address,bool)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.
The following sample Trader materials generates the following ABI-encoded value: 0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b9aca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a8dda8d7f5310e4a9e24f8eba77e091ac264f8720000000000000000000000000000000000000000000000000000000000000000.
| field | value |
|---|---|
| avail_ddx_balance | 1000 |
| locked_ddx_balance | 0 |
| referral_address | "0xA8dDa8d7F5310E4A9E24F8eBA77E091Ac264f872" |
| pay_fees_in_ddx | True |
Strategy
A Strategy leaf contains information pertaining to a trader's cross-margined strategy, such as their available and locked collaterals and max leverage.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def generate_strategy_id_hash(strategy_id: str) -> bytes:
# Get the first 4 bytes of the hash of the strategy id
return w3.keccak(
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
)[:4]
def encode_key(trader_address: str, strategy_id: str, chain_discriminant: int):
# ItemType.STRATEGY == 2
return zpad32_right(
ItemType.STRATEGY.to_bytes(1, byteorder="little")
+ bytes.fromhex(trader_address[2:])
+ generate_strategy_id_hash(strategy_id)
)
def decode_key(strategy_key: bytes):
# trader_address, strategy_id_hash
return (
f"0x{strategy_key[1:22].hex()}",
f"0x{strategy_key[22:26].hex()}",
)
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def generate_strategy_id_hash(strategy_id: str) -> bytes:
# Get the first 4 bytes of the hash of the strategy id
return w3.keccak(
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
)[:4]
def encode_key(trader_address: str, strategy_id: str, chain_discriminant: int):
# ItemType.STRATEGY == 2
return zpad32_right(
ItemType.STRATEGY.to_bytes(1, byteorder="little")
+ bytes.fromhex(trader_address[2:])
+ generate_strategy_id_hash(strategy_id)
)
def decode_key(strategy_key: bytes):
# trader_address, strategy_id_hash
return (
f"0x{strategy_key[1:22].hex()}",
f"0x{strategy_key[22:26].hex()}",
)The location of a Strategy leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Strategy discriminant |
| [1, 21] | Trader's Ethereum address prefixed with the chain discriminant |
| [22, 25] | Abbreviated hash of strategy ID |
| [26, 25] | Zero-padding |
The following sample Strategy materials generates the following encoded key: 0x0200603699848c84529987e14ba32c8a66def67e9ece2576ebd1000000000000.
| field | value |
|---|---|
| trader_address | "0x00603699848c84529987E14Ba32C8a66DEF67E9eCE" |
| strategy_id | "main" |
Value definition
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_base_unit_amount_list(vals, decimals):
return [to_base_unit_amount(val, decimals) for val in vals]
def to_unit_amount(val: int, decimals: int) -> Decimal:
return Decimal(str(val)) / 10 ** decimals
def to_unit_amount_list(vals: List[int], decimals: int):
return [to_unit_amount(val, decimals) for val in vals]
def to_adjusted_encoding_for_negative_val(val: int):
return 16 ** 32 + abs(val) if val < 0 else val
def to_adjusted_encoding_for_negative_val_list(vals: List[int]):
return [to_adjusted_encoding_for_negative_val(val) for val in vals]
def from_adjusted_encoding_for_negative_val(val: int):
return val if val < 16 ** 32 else -(val - 16 ** 32)
def abi_encoded_value(self, strategy_id: str, avail_collateral: Dict[str, Decimal], locked_collateral: Dict[str, Decimal], max_leverage: int, frozen: bool):
# Strategy item discriminant
item_type = 2
# Scale collateral amounts to grains
return encode_single(
"((uint8,(bytes32,(address[],uint256[]),(address[],uint128[]),uint64,bool)))",
[
[
item_type,
[
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[
:-1
],
[
list(avail_collateral.keys()),
to_adjusted_encoding_for_negative_val_list(
to_base_unit_amount_list(
list(avail_collateral.values()), 6
)
),
],
[
list(locked_collateral.keys()),
to_base_unit_amount_list(
list(locked_collateral.values()), 6
),
],
max_leverage,
frozen,
],
]
],
)
def abi_decoded_value(abi_encoded_value: str):
(
(
item_type,
(
strategy_id,
(avail_collateral_tokens, avail_collateral_amounts),
(locked_collateral_tokens, locked_collateral_amounts),
max_leverage,
frozen,
),
),
) = decode_single(
"((uint8,(bytes32,(address[],uint256[]),(address[],uint128[]),uint64,bool)))",
w3.toBytes(hexstr=abi_encoded_value),
)
# Scale collateral amounts from grains
return (
strategy_id[1 : 1 + strategy_id[0]].decode("utf8"),
{
k: to_unit_amount(from_adjusted_encoding_for_negative_val(v), 6)
for k, v in zip(
list(avail_collateral_tokens), list(avail_collateral_amounts)
)
},
{
k: to_unit_amount(v, 6)
for k, v in zip(
list(locked_collateral_tokens), list(locked_collateral_amounts)
)
},
max_leverage,
frozen,
)
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_base_unit_amount_list(vals, decimals):
return [to_base_unit_amount(val, decimals) for val in vals]
def to_unit_amount(val: int, decimals: int) -> Decimal:
return Decimal(str(val)) / 10 ** decimals
def to_unit_amount_list(vals: List[int], decimals: int):
return [to_unit_amount(val, decimals) for val in vals]
def to_adjusted_encoding_for_negative_val(val: int):
return 16 ** 32 + abs(val) if val < 0 else val
def to_adjusted_encoding_for_negative_val_list(vals: List[int]):
return [to_adjusted_encoding_for_negative_val(val) for val in vals]
def from_adjusted_encoding_for_negative_val(val: int):
return val if val < 16 ** 32 else -(val - 16 ** 32)
def abi_encoded_value(self, strategy_id: str, avail_collateral: Dict[str, Decimal], locked_collateral: Dict[str, Decimal], max_leverage: int, frozen: bool):
# Strategy item discriminant
item_type = 2
# Scale collateral amounts to grains
return encode_single(
"((uint8,(bytes32,(address[],uint256[]),(address[],uint128[]),uint64,bool)))",
[
[
item_type,
[
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[
:-1
],
[
list(avail_collateral.keys()),
to_adjusted_encoding_for_negative_val_list(
to_base_unit_amount_list(
list(avail_collateral.values()), 6
)
),
],
[
list(locked_collateral.keys()),
to_base_unit_amount_list(
list(locked_collateral.values()), 6
),
],
max_leverage,
frozen,
],
]
],
)
def abi_decoded_value(abi_encoded_value: str):
(
(
item_type,
(
strategy_id,
(avail_collateral_tokens, avail_collateral_amounts),
(locked_collateral_tokens, locked_collateral_amounts),
max_leverage,
frozen,
),
),
) = decode_single(
"((uint8,(bytes32,(address[],uint256[]),(address[],uint128[]),uint64,bool)))",
w3.toBytes(hexstr=abi_encoded_value),
)
# Scale collateral amounts from grains
return (
strategy_id[1 : 1 + strategy_id[0]].decode("utf8"),
{
k: to_unit_amount(from_adjusted_encoding_for_negative_val(v), 6)
for k, v in zip(
list(avail_collateral_tokens), list(avail_collateral_amounts)
)
},
{
k: to_unit_amount(v, 6)
for k, v in zip(
list(locked_collateral_tokens), list(locked_collateral_amounts)
)
},
max_leverage,
frozen,
)A Strategy leaf holds the following data:
| type | field | description |
|---|---|---|
| string | strategy_id | Identifier for strategy (e.g. "main") |
| dict<address_s, decimal> | avail_collateral | Mapping of collateral address to available collateral amount |
| dict<address_s, decimal> | locked_collateral | Mapping of collateral address to locked collateral amount |
| int | max_leverage | Maximum leverage strategy can take |
| bool | frozen | Whether the strategy is frozen or not (relevant for tokenization) |
These contents are always stored in the tree in ABI-encoded form: ((uint8,(bytes32,(address[],uint128[]),(address[],uint128[]),uint64,bool))). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.
The following sample Strategy materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040046d61696e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000b69e673309512a9d726f87304c6984054f87a93b00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000002e8f3487400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.
| field | value |
|---|---|
| strategy_id | "main" |
| avail_collateral | {"0xb69e673309512a9d726f87304c6984054f87a93b": 199971.08} |
| locked_collateral | {} |
| max_leverage | 3 |
| frozen | False |
Position
A Position leaf contains information pertaining to an open position.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def generate_strategy_id_hash(strategy_id: str) -> bytes:
# Get the first 4 bytes of the hash of the strategy id
return w3.keccak(
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
)[:4]
def pack_bytes(text: str):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = ""
for letter in text:
for i, char in enumerate(charset):
if char == letter:
bits = format(i, "08b")[::-1]
symbol_bits += bits[:5]
symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
(len(symbol_bits) + 7) // 8, byteorder="little"
)
return zpad_right(symbol_bytes, 6)
def unpack_bytes(packed_text: bytes):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
symbol_char_bit_chunks = [
symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
]
symbol = ""
for symbol_char_bit_chunk in symbol_char_bit_chunks:
reversed_bit_chunk = symbol_char_bit_chunk[::-1]
char_index = int(reversed_bit_chunk, 2)
symbol += charset[char_index]
return symbol
def encode_key(trader_address: str, strategy_id: str, symbol: str, chain_discriminant: int):
# ItemType.POSITION == 3
return (
ItemType.POSITION.to_bytes(1, byteorder="little")
+ pack_bytes(symbol)
+ bytes.fromhex(trader_address[2:])
+ generate_strategy_id_hash(strategy_id)
)
def decode_key(position_key: bytes):
# symbol, trader_address, strategy_id_hash
return (
unpack_bytes(position_key[1:7]),
f"0x{position_key[7:28].hex()}",
f"0x{position_key[28:].hex()}",
)
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def generate_strategy_id_hash(strategy_id: str) -> bytes:
# Get the first 4 bytes of the hash of the strategy id
return w3.keccak(
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
)[:4]
def pack_bytes(text: str):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = ""
for letter in text:
for i, char in enumerate(charset):
if char == letter:
bits = format(i, "08b")[::-1]
symbol_bits += bits[:5]
symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
(len(symbol_bits) + 7) // 8, byteorder="little"
)
return zpad_right(symbol_bytes, 6)
def unpack_bytes(packed_text: bytes):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
symbol_char_bit_chunks = [
symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
]
symbol = ""
for symbol_char_bit_chunk in symbol_char_bit_chunks:
reversed_bit_chunk = symbol_char_bit_chunk[::-1]
char_index = int(reversed_bit_chunk, 2)
symbol += charset[char_index]
return symbol
def encode_key(trader_address: str, strategy_id: str, symbol: str, chain_discriminant: int):
# ItemType.POSITION == 3
return (
ItemType.POSITION.to_bytes(1, byteorder="little")
+ pack_bytes(symbol)
+ bytes.fromhex(trader_address[2:])
+ generate_strategy_id_hash(strategy_id)
)
def decode_key(position_key: bytes):
# symbol, trader_address, strategy_id_hash
return (
unpack_bytes(position_key[1:7]),
f"0x{position_key[7:28].hex()}",
f"0x{position_key[28:].hex()}",
)The location of a Position leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Position discriminant |
| [1, 6] | Symbol (5-bit encoded/packed) |
| [7, 27] | Trader's Ethereum address prefixed with the chain discriminant |
| [28, 31] | Abbreviated hash of strategy ID |
The following sample Position materials generates the following encoded key: 0x0385225824040000603699848c84529987e14ba32c8a66def67e9ece2576ebd1.
| field | value |
|---|---|
| trader_address | "0x603699848c84529987E14Ba32C8a66DEF67E9eCE" |
| strategy_id | "main" |
| symbol | "ETHP" |
Value definition
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(side: int, balance: Decimal, avg_entry_price: Decimal):
# Position item discriminant
item_type = 3
# Scale balance and average entry price grains
return encode_single(
"(uint8,(uint8,uint128,uint128))",
[
item_type,
[
side,
to_base_unit_amount(balance, 6),
to_base_unit_amount(avg_entry_price, 6),
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(item_type, (side, balance, avg_entry_price)) = decode_single(
"(uint8,(uint8,uint128,uint128))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale balance and average entry price from DDX grains
return (
side, to_unit_amount(balance, 6), to_unit_amount(avg_entry_price, 6)
)
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(side: int, balance: Decimal, avg_entry_price: Decimal):
# Position item discriminant
item_type = 3
# Scale balance and average entry price grains
return encode_single(
"(uint8,(uint8,uint128,uint128))",
[
item_type,
[
side,
to_base_unit_amount(balance, 6),
to_base_unit_amount(avg_entry_price, 6),
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(item_type, (side, balance, avg_entry_price)) = decode_single(
"(uint8,(uint8,uint128,uint128))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale balance and average entry price from DDX grains
return (
side, to_unit_amount(balance, 6), to_unit_amount(avg_entry_price, 6)
)A Position leaf holds the following data:
| type | field | description |
|---|---|---|
| int | side | Side of position (Long=1, Short=2) |
| decimal | balance | Size of the position |
| decimal | average_entry_price | Average entry price of the position |
These contents are always stored in the tree in ABI-encoded form: (uint8,(uint8,uint128,uint128)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.
The following sample Position materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000068155a43676e0000000000000000000000000000000000000000000000000000d4eff354906660000.
| field | value |
|---|---|
| side | 1 |
| balance | 120 |
| avg_entry_price | 245.5 |
Book Order
A BookOrder leaf contains information pertaining to a maker order in the order book.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def generate_strategy_id_hash(strategy_id: str) -> bytes:
# Get the first 4 bytes of the hash of the strategy id
return w3.keccak(
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
)[:4]
def pack_bytes(text: str):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = ""
for letter in text:
for i, char in enumerate(charset):
if char == letter:
bits = format(i, "08b")[::-1]
symbol_bits += bits[:5]
symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
(len(symbol_bits) + 7) // 8, byteorder="little"
)
return zpad_right(symbol_bytes, 6)
def unpack_bytes(packed_text: bytes):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
symbol_char_bit_chunks = [
symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
]
symbol = ""
for symbol_char_bit_chunk in symbol_char_bit_chunks:
reversed_bit_chunk = symbol_char_bit_chunk[::-1]
char_index = int(reversed_bit_chunk, 2)
symbol += charset[char_index]
return symbol
def encode_key(symbol: str, order_hash: str):
# ItemType.BOOK_ORDER == 3
return (
ItemType.BOOK_ORDER.to_bytes(1, byteorder="little")
+ pack_bytes(symbol)
+ bytes.fromhex(order_hash[2:52])
)
def decode_key(book_order_key: bytes):
# symbol, first 25 bytes of order_hash
return (
unpack_bytes(book_order_key[1:7]),
f"0x{book_order_key[7:].hex()}",
)
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def generate_strategy_id_hash(strategy_id: str) -> bytes:
# Get the first 4 bytes of the hash of the strategy id
return w3.keccak(
len(strategy_id).to_bytes(1, byteorder="little")
+ encode_single("bytes32", strategy_id.encode("utf8"))[:-1]
)[:4]
def pack_bytes(text: str):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = ""
for letter in text:
for i, char in enumerate(charset):
if char == letter:
bits = format(i, "08b")[::-1]
symbol_bits += bits[:5]
symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
(len(symbol_bits) + 7) // 8, byteorder="little"
)
return zpad_right(symbol_bytes, 6)
def unpack_bytes(packed_text: bytes):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
symbol_char_bit_chunks = [
symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
]
symbol = ""
for symbol_char_bit_chunk in symbol_char_bit_chunks:
reversed_bit_chunk = symbol_char_bit_chunk[::-1]
char_index = int(reversed_bit_chunk, 2)
symbol += charset[char_index]
return symbol
def encode_key(symbol: str, order_hash: str):
# ItemType.BOOK_ORDER == 3
return (
ItemType.BOOK_ORDER.to_bytes(1, byteorder="little")
+ pack_bytes(symbol)
+ bytes.fromhex(order_hash[2:52])
)
def decode_key(book_order_key: bytes):
# symbol, first 25 bytes of order_hash
return (
unpack_bytes(book_order_key[1:7]),
f"0x{book_order_key[7:].hex()}",
)The location of a BookOrder leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Book order discriminant |
| [1, 6] | Symbol (5-bit encoded/packed) |
| [7, 31] | First 25 bytes of order's unique hash |
The following sample BookOrder materials generates the following encoded key: 0x048522582404009fcf480aa9606f5bbb64ab36e642566bd893f715b346df244e.
| field | value |
|---|---|
| symbol | "ETHP" |
| order_hash | "0x9fcf480aa9606f5bbb64ab36e642566bd893f715b346df244eABABABABABABAB" |
Value definition
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, side: int, amount: Decimal, price: Decimal, trader_address: str, strategy_id_hash: str, book_ordinal: int, time_value: int):
# BookOrder item discriminant
item_type = 4
# Scale amount and price to grains
return encode_single(
"(uint8,(uint8,uint128,uint128,bytes21,bytes32,uint64,uint64))",
[
item_type,
[
side,
to_base_unit_amount(amount, 6),
to_base_unit_amount(price, 6),
bytes.fromhex(trader_address[2:]),
bytes.fromhex(strategy_id_hash[2:]),
book_ordinal,
time_value,
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(
item_type,
(side, amount, price, trader_address, strategy_id_hash, book_ordinal, time_value),
) = decode_single(
"(uint8,(uint8,uint128,uint128,bytes21,bytes32,uint64,uint64))",
w3.toBytes(hexstr=abi_encoded_value),
)
# Scale amount and price from grains
return (
side,
to_unit_amount(amount, 6),
to_unit_amount(price, 6),
f"0x{trader_address.hex()}",
f"0x{strategy_id_hash[:4].hex()}",
book_ordinal,
time_value,
)
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, side: int, amount: Decimal, price: Decimal, trader_address: str, strategy_id_hash: str, book_ordinal: int, time_value: int):
# BookOrder item discriminant
item_type = 4
# Scale amount and price to grains
return encode_single(
"(uint8,(uint8,uint128,uint128,bytes21,bytes32,uint64,uint64))",
[
item_type,
[
side,
to_base_unit_amount(amount, 6),
to_base_unit_amount(price, 6),
bytes.fromhex(trader_address[2:]),
bytes.fromhex(strategy_id_hash[2:]),
book_ordinal,
time_value,
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(
item_type,
(side, amount, price, trader_address, strategy_id_hash, book_ordinal, time_value),
) = decode_single(
"(uint8,(uint8,uint128,uint128,bytes21,bytes32,uint64,uint64))",
w3.toBytes(hexstr=abi_encoded_value),
)
# Scale amount and price from grains
return (
side,
to_unit_amount(amount, 6),
to_unit_amount(price, 6),
f"0x{trader_address.hex()}",
f"0x{strategy_id_hash[:4].hex()}",
book_ordinal,
time_value,
)A BookOrder leaf holds the following data:
| type | field | description |
|---|---|---|
| str | side | Side of order (Bid, Ask) |
| decimal | amount | Amount/size of order |
| decimal | price | Price the order has been placed at |
| str | trader_address | The order creator's Ethereum address prefixed with the chain discriminant |
| str | strategy_id_hash | First 4 bytes of strategy ID hash this order belongs to |
| int | book_ordinal | Numerical sequencing identifier for a BookOrder, which can be used to sort orders at any given price level |
| int | time_value | Time value of order placement since genesis (s) |
These contents are always stored in the tree in ABI-encoded form: (uint8,(uint8,uint128,uint128,address,bytes32,uint64)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.
The following sample BookOrder materials generates the following ABI-encoded value: 00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001158e460913d0000000000000000000000000000000000000000000000000000d8d726b7177a80000603699848c84529987e14ba32c8a66def67e9ece0000000000000000000000002576ebd100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000003e8
| field | value |
|---|---|
| side | "Bid" |
| amount | 20 |
| price | 250 |
| trader_address | "0x603699848c84529987E14Ba32C8a66DEF67E9eCE" |
| strategy_id_hash | "0x2576ebd1" |
| book_ordinal | 3 |
| book_ordinal | 1000 |
Price
A Price contains information pertaining to a market's price checkpoint.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def pack_bytes(text: str):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = ""
for letter in text:
for i, char in enumerate(charset):
if char == letter:
bits = format(i, "08b")[::-1]
symbol_bits += bits[:5]
symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
(len(symbol_bits) + 7) // 8, byteorder="little"
)
return zpad_right(symbol_bytes, 6)
def unpack_bytes(packed_text: bytes):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
symbol_char_bit_chunks = [
symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
]
symbol = ""
for symbol_char_bit_chunk in symbol_char_bit_chunks:
reversed_bit_chunk = symbol_char_bit_chunk[::-1]
char_index = int(reversed_bit_chunk, 2)
symbol += charset[char_index]
return symbol
def encode_key(symbol: str, index_price_hash: str):
# ItemType.PRICE == 5
return zpad32_right(
ItemType.PRICE.to_bytes(1, byteorder="little")
+ pack_bytes(symbol)
+ bytes.fromhex(index_price_hash[2:])
)
def decode_key(price_key: bytes):
# symbol, index price hash
return (
unpack_bytes(price_key[1:7]),
f"0x{leaf_key[7:].hex()}",
)
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right, encode_single, decode_single
from web3.auto import w3
def pack_bytes(text: str):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = ""
for letter in text:
for i, char in enumerate(charset):
if char == letter:
bits = format(i, "08b")[::-1]
symbol_bits += bits[:5]
symbol_bytes = int(symbol_bits[::-1], 2).to_bytes(
(len(symbol_bits) + 7) // 8, byteorder="little"
)
return zpad_right(symbol_bytes, 6)
def unpack_bytes(packed_text: bytes):
charset = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"
symbol_bits = format(int.from_bytes(packed_text, "little"), "030b")[::-1]
symbol_char_bit_chunks = [
symbol_bits[i : i + 5] for i in range(0, len(symbol_bits), 5)
]
symbol = ""
for symbol_char_bit_chunk in symbol_char_bit_chunks:
reversed_bit_chunk = symbol_char_bit_chunk[::-1]
char_index = int(reversed_bit_chunk, 2)
symbol += charset[char_index]
return symbol
def encode_key(symbol: str, index_price_hash: str):
# ItemType.PRICE == 5
return zpad32_right(
ItemType.PRICE.to_bytes(1, byteorder="little")
+ pack_bytes(symbol)
+ bytes.fromhex(index_price_hash[2:])
)
def decode_key(price_key: bytes):
# symbol, index price hash
return (
unpack_bytes(price_key[1:7]),
f"0x{leaf_key[7:].hex()}",
)The location of a Price leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Price discriminant |
| [1, 6] | Symbol (5-bit encoded/packed) |
| [7, 31] | 25 bytes of index price's unique hash |
The following sample Price materials generates the following encoded key: 0x0585225824040023c2b28e94b9dfcb8630a369fed134cdb6689dcb2528578779.
| field | value |
|---|---|
| symbol | "ETHP" |
| index_price_hash | "0x23c2b28e94b9dfcb8630a369fed134cdb6689dcb2528578779ABABABABABABAB" |
Value definition
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, index_price: Decimal, ema: Decimal, ordinal: int):
# Price item discriminant
item_type = 5
# Scale index price and ema to grains
price_encoding = encode_single(
"(uint8,(uint128,uint256,uint64))",
[
item_type,
[
to_base_unit_amount(index_price, 6),
to_base_unit_amount(abs(ema), 6),
ordinal,
],
],
)
if self.ema < 0:
price_encoding_byte_array = bytearray(price_encoding)
price_encoding_byte_array[-49] = 1
price_encoding = bytes(price_encoding_byte_array)
return price_encoding
def abi_decoded_value(abi_encoded_value: str):
price_encoding_byte_array = bytearray(bytes.fromhex(abi_encoded_value[2:]))
multiplier = -1 if price_encoding_byte_array[-49] == 1 else 1
price_encoding_byte_array[-49] = 0
abi_encoded_value = bytes(price_encoding_byte_array).hex()
(item_type, (index_price, ema, ordinal)) = decode_single(
"(uint8,(uint128,uint256,uint64))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale index price and ema from grains
return (
to_unit_amount(index_price, 6),
to_unit_amount(ema * multiplier, 6),
ordinal,
)
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, index_price: Decimal, ema: Decimal, ordinal: int):
# Price item discriminant
item_type = 5
# Scale index price and ema to grains
price_encoding = encode_single(
"(uint8,(uint128,uint256,uint64))",
[
item_type,
[
to_base_unit_amount(index_price, 6),
to_base_unit_amount(abs(ema), 6),
ordinal,
],
],
)
if self.ema < 0:
price_encoding_byte_array = bytearray(price_encoding)
price_encoding_byte_array[-49] = 1
price_encoding = bytes(price_encoding_byte_array)
return price_encoding
def abi_decoded_value(abi_encoded_value: str):
price_encoding_byte_array = bytearray(bytes.fromhex(abi_encoded_value[2:]))
multiplier = -1 if price_encoding_byte_array[-49] == 1 else 1
price_encoding_byte_array[-49] = 0
abi_encoded_value = bytes(price_encoding_byte_array).hex()
(item_type, (index_price, ema, ordinal)) = decode_single(
"(uint8,(uint128,uint256,uint64))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale index price and ema from grains
return (
to_unit_amount(index_price, 6),
to_unit_amount(ema * multiplier, 6),
ordinal,
)A Price leaf holds the following data:
| type | field | description |
|---|---|---|
| decimal | index_price | Composite index price Petual is tracking |
| decimal | ema | EMA component of price, tracking the difference between the DerivaDEX order book price and the underlying |
| int | ordinal | Numerical sequencing identifier for PriceCheckpoint that created this Price state leaf, can be used to arrange Price leaves in order of entry |
These contents are always stored in the tree in ABI-encoded form: (uint8,(uint128,uint256,uint64)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right. It's demonstrated in the code sample, but it's worth highlighting that the ema component, which can be a negative value, is ABI-encoded to a 32-byte value where the first 16 bytes will either be 0x00000000000000000000000000000000 (positive) or 0x00000000000000000000000000000001 (negative), and the next 16 bytes is the absolute value of the ema.
The following sample Price materials generates the following ABI-encoded value: 0x00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000ff439f867f838f4000000000000000000000000000000000000000000000000004d94aaad5556854d300000000000000000000000000000000000000000000000000000000000020e2.
| field | value |
|---|---|
| index_price | 4708.7925 |
| ema | 89.444491182582813907 |
| ordinal | 8418 |
Insurance Fund
An InsuranceFund leaf contains information pertaining to the insurance fund' capitalization.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right
def encode_key():
# ItemType.INSURANCE_FUND == 6
return zpad32_right(
ItemType.INSURANCE_FUND.to_bytes(1, byteorder="little")
+ "OrganicInsuranceFund".encode("utf8")
)
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right
def encode_key():
# ItemType.INSURANCE_FUND == 6
return zpad32_right(
ItemType.INSURANCE_FUND.to_bytes(1, byteorder="little")
+ "OrganicInsuranceFund".encode("utf8")
)The location of an InsuranceFund leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Insurance fund discriminant |
| [1, 20] | "OrganicInsuranceFund" bytes-encoded |
| [21, 31] | Zero-padding |
The InsuranceFund leaf is located at the encoded key: 0x064f7267616e6963496e737572616e636546756e640000000000000000000000.
Value definition
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, capitalization: Dict[str, Decimal]):
# InsuranceFund item discriminant
item_type = 6
# Scale collateral amounts to grains
return encode_single(
"((uint8,(address[],uint128[])))",
[
[
self.item_type,
[
list(capitalization.keys()),
to_base_unit_amount_list(
list(capitalization.values()), 6
),
],
]
],
)
def abi_decoded_value(abi_encoded_value: str):
(
(item_type, (capitalization_tokens, capitalization_amounts,),),
) = decode_single(
"((uint8,(address[],uint128[])))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale collateral amounts from grains
return cls(
{
k: to_unit_amount(v, 6)
for k, v in zip(
list(capitalization_tokens), list(capitalization_amounts)
)
},
)
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, capitalization: Dict[str, Decimal]):
# InsuranceFund item discriminant
item_type = 6
# Scale collateral amounts to grains
return encode_single(
"((uint8,(address[],uint128[])))",
[
[
self.item_type,
[
list(capitalization.keys()),
to_base_unit_amount_list(
list(capitalization.values()), 6
),
],
]
],
)
def abi_decoded_value(abi_encoded_value: str):
(
(item_type, (capitalization_tokens, capitalization_amounts,),),
) = decode_single(
"((uint8,(address[],uint128[])))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale collateral amounts from grains
return cls(
{
k: to_unit_amount(v, 6)
for k, v in zip(
list(capitalization_tokens), list(capitalization_amounts)
)
},
)An InsuranceFund leaf holds the following data:
| type | field | description |
|---|---|---|
| dict<address_s, decimal> | capitalization | Mapping of collateral address to organic insurance fund capitalization |
These contents are always stored in the tree in ABI-encoded form: ((uint8,(address[],uint128[]))). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.
The following sample InsuranceFund materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000cfc18cec799fbd1793b5c43e773c98d4d61cc2db000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000532d4737cf8c716f0000.
| field | value |
|---|---|
| capitalization | {"0xcfc18cec799fbd1793b5c43e773c98d4d61cc2db": 392791.65336} |
Stats
A Stats leaf contains data such as volume info for trade mining for any given trader.
Key encoding / decoding
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right
def encode_key(trader_address: str):
# ItemType.STATS == 7
return zpad32_right(
ItemType.STATS.to_bytes(1, byteorder="little")
+ bytes.fromhex(trader_address[2:])
)
def decode_key(stats_key: bytes):
# chain_discriminant, trader_address
return f"0x{stats_key[1:22].hex()}"
Key encoding / decoding (Python)
from eth_abi.utils.padding import zpad32_right
def encode_key(trader_address: str):
# ItemType.STATS == 7
return zpad32_right(
ItemType.STATS.to_bytes(1, byteorder="little")
+ bytes.fromhex(trader_address[2:])
)
def decode_key(stats_key: bytes):
# chain_discriminant, trader_address
return f"0x{stats_key[1:22].hex()}"The location of a Stats leaf is determined by its key, which is encoded as follows:
| Bytes | Value |
|---|---|
| 0 | Stats discriminant |
| [1, 21] | Trader' Ethereum address prefixed with the chain discriminant |
| [22, 31] | Zero-padding |
The following sample Stats materials generates the following encoded key: 0x0700603699848c84529987e14ba32c8a66def67e9ece00000000000000000000.
| field | value |
|---|---|
| trader_address | "0x00603699848c84529987E14Ba32C8a66DEF67E9eCE" |
Value definition
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, maker_volume: Decimal, taker_volume: Decimal):
# Stats item discriminant
item_type = 6
# Scale volume amounts to grains
return encode_single(
"(uint8,(uint128,uint128))",
[
item_type,
[
to_base_unit_amount(maker_volume, 6),
to_base_unit_amount(taker_volume, 6),
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(item_type, (maker_volume, taker_volume)) = decode_single(
"(uint8,(uint128,uint128))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale volumes from DDX grains
return (to_unit_amount(maker_volume, 6), to_unit_amount(taker_volume, 6))
Value encoding / decoding (Python)
from typing import Dict
from ddx._rust.decimal import Decimal
from eth_abi import encode_single, decode_single
from web3.auto import w3
def round_to_unit(val):
return val.quantize(6)
def to_base_unit_amount(val, decimals):
return int(round_to_unit(val) * 10 ** decimals)
def to_unit_amount(val, decimals):
return Decimal(str(val)) / 10 ** decimals
def abi_encoded_value(self, maker_volume: Decimal, taker_volume: Decimal):
# Stats item discriminant
item_type = 6
# Scale volume amounts to grains
return encode_single(
"(uint8,(uint128,uint128))",
[
item_type,
[
to_base_unit_amount(maker_volume, 6),
to_base_unit_amount(taker_volume, 6),
],
],
)
def abi_decoded_value(abi_encoded_value: str):
(item_type, (maker_volume, taker_volume)) = decode_single(
"(uint8,(uint128,uint128))", w3.toBytes(hexstr=abi_encoded_value),
)
# Scale volumes from DDX grains
return (to_unit_amount(maker_volume, 6), to_unit_amount(taker_volume, 6))A Stats leaf holds the following data:
| type | field | description |
|---|---|---|
| decimal | maker_volume | Maker volume of trader during this trade mining epoch |
| decimal | taker_volume | Taker volume of trader during this trade mining epoch |
These contents are always stored in the tree in ABI-encoded form: (uint8,(uint128,uint128)). Meaning, you will want to decode the contents into a more suitable form for your purposes as necessary (for example loading data from a snapshot of the state), and will need to encode it back again if you are saving it back into the tree. A sample of Python code that derives this ABI-encoding, including the grains conversion for certain variables, is shown on the right.
The following sample Stats materials generates the following ABI-encoded value: 0x000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000032d26d12e980b60000000000000000000000000000000000000000000000000030fe0cfcba2f4700000.
| field | value |
|---|---|
| maker_volume | 15000 |
| taker_volume | 14460 |
Transactions
Transactions refer to the state-changing events that modify the SMT and its leaves (thus the root hash) described above.
There are several types of transactions on DerivaDEX. The full set of transactions along with their corresponding numeric discrimants can be seen in the table below:
| Event | Discriminant |
|---|---|
| PartialFill | 0 |
| CompleteFill | 1 |
| PostOrder | 2 |
| Cancel | 3 |
| CancelAll | 30 |
| Liquidation | 4 |
| StrategyUpdate | 5 |
| TraderUpdate | 6 |
| Withdraw | 7 |
| WithdrawDDX | 8 |
| PriceCheckpoint | 9 |
| PnlRealization | 10 |
| Funding | 11 |
| TradeMining | 12 |
| SpecsUpdate | 13 |
| InsuranceFundUpdate | 14 |
| InsuranceFundWithdraw | 15 |
| DisasterRecovery | 16 |
| SignerRegistered | 60 |
| EpochMarker | 100 |
| NoTransition | 999 |
Each of these transaction types as received from the Operator WebSocket API are described at length below.
Partial fill
Sample PartialFill (JSON)
{
"event": [
{
"side": "Ask",
"price": "53008",
"amount": "7.8",
"symbol": "BTCP",
"orderHash": "0xcd69dd0341444be5bc46c0a7e9b305bc4a3a322fae3eedd70e",
"strategyId": "main",
"bookOrdinal": 41,
"traderAddress": "0x00aa6676733e2e259d879127519d973ac71135f797"
},
{},
[
{
"Fill": {
"price": "53163",
"amount": "0.1",
"reason": "Trade",
"symbol": "BTCP",
"takerSide": "Ask",
"makerOutcome": {
"fee": "0",
"trader": "0x000e646446bfd163dc1cb3010754a7e1a5dd73a6de",
"strategy": "main",
"ddxFeeElection": false
},
"takerOutcome": {
"fee": "10.6326",
"trader": "0x00aa6676733e2e259d879127519d973ac71135f797",
"strategy": "main",
"ddxFeeElection": false
},
"makerOrderHash": "0xc7aa4937f79ee9fbc3f8c5f00f46157ac0c0ab6a485227e920",
"takerOrderHash": "0xcd69dd0341444be5bc46c0a7e9b305bc4a3a322fae3eedd70e",
"makerOrderRemainingAmount": "0"
}
}
]
]
}
A PartialFill transaction is a scenario where the taker order has been partially filled across 1 or more maker orders and thus has a remaining order that enters the order book. The event portion of the transaction response consists of a 3-item array. The first item is the remaining Post event, the second item is a dictionary of any relevant price updates, and the third item is a list of trade outcomes, which can either be TradeFill or Cancel events pertaining to maker orders that may have been canceled.
Complete fill
Sample CompleteFill (JSON)
{
"event": [
{},
[
{
"Fill": {
"price": "53163",
"amount": "0.1",
"reason": "Trade",
"symbol": "BTCP",
"takerSide": "Ask",
"makerOutcome": {
"fee": "0",
"trader": "0x000e646446bfd163dc1cb3010754a7e1a5dd73a6de",
"strategy": "main",
"ddxFeeElection": false
},
"takerOutcome": {
"fee": "10.6326",
"trader": "0x00aa6676733e2e259d879127519d973ac71135f797",
"strategy": "main",
"ddxFeeElection": false
},
"makerOrderHash": "0xc7aa4937f79ee9fbc3f8c5f00f46157ac0c0ab6a485227e920",
"takerOrderHash": "0xcd69dd0341444be5bc46c0a7e9b305bc4a3a322fae3eedd70e",
"makerOrderRemainingAmount": "0"
}
}
]
]
}
A CompleteFill is a scenario where the taker order has been completely filled across 1 or more maker orders. The event portion of the transaction response consists of a consists of a trade outcomes, which can either be TradeFill or Cancel events pertaining to maker orders that may have been canceled.
Post order
Sample PostOrder (JSON)
{
"event": [
{
"side": "Bid",
"price": "1870.25",
"amount": "1.39",
"symbol": "ETHP",
"orderHash": "0x860b1065b629df495de7a0d97432a48b098cadcbb37a1fdbd9",
"strategyId": "main",
"bookOrdinal": 0,
"traderAddress": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
"timeValue": 1024
},
{},
[]
]
}
A PostOrder is a 3-item array where the first item is a Post order that enters the order book, the second item is price checkpoints that may have taken place, and the third item is a list of Cancel events pertaining to maker orders that may have been canceled.
Cancel
Sample Cancel (JSON)
{
"event": {
"amount": "1.39",
"symbol": "ETHP",
"orderHash": "0x860b1065b629df495de7a0d97432a48b098cadcbb37a1fdbd9"
}
}
A Cancel is when an existing order is canceled and removed from the order book. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal_s | event.amount | Size of order canceled from the order book |
| string | event.symbol | Symbol for the market this order has been canceled (e.g. ETHP) |
| bytes32_s | event.orderHash | Hexstr representation of the first 25 bytes of the unique EIP-712 hash of the order being canceled |
Liquidation
Sample Liquidation (JSON)
{
"event": [
{
"positions": [
[
"ETHP",
{
"price": {
"ema": "-212.602242612626064356",
"ordinal": 157,
"indexPrice": "2718.2459",
"indexPriceHash": "0x16f0d2a4abfd17f788c900a392cf4297439bae04d0f5a13cd1"
},
"amount": "6.1",
"adlOutcomes": [],
"tradeOutcomes": [
{
"Fill": {
"price": "2322",
"amount": "6.1",
"reason": "Liquidation",
"symbol": "ETHP",
"takerSide": "Ask",
"makerOutcome": {
"fee": "0",
"trader": "0x00e834ec434daba538cd1b9fe1582052b880bd7e63",
"strategy": "main",
"realizedPnl": "595.832921348314606732",
"positionSide": "Short",
"newCollateral": "942709.042921348314605958",
"ddxFeeElection": false,
"newPositionBalance": "2.8",
"newPositionAvgEntryPrice": "2419.677528089887640448"
},
"indexPriceHash": "0x16f0d2a4abfd17f788c900a392cf4297439bae04d0f5a13cd1",
"makerOrderHash": "0x63d8e48a6536760deaf29e5f2f2e0039356fc77a437ccc47f7",
"makerOrderRemainingAmount": "4.7"
}
}
],
"newInsuranceFundCap": "734.512240000000000005"
}
]
],
"strategyId": "main",
"traderAddress": "0x00d9a605a32d920d90d8119ffd5fe1fd247c500479",
"canceledOrders": []
}
]
}
A Liquidation is when a set of strategies are under-collateralized and closed out forcibly closed out:
| type | field | description |
|---|---|---|
| list | event | The contents of the transaction event |
| dict | event[n] | Liquidation entry |
| address_s | event[n].traderAddress | Liquidated trader'prefixed Ethereum address |
| string | event[n].strategyId | Liquidated trader's strategy id |
| dict | event[n].strategyId | Liquidated trader's strategy id |
| list | event[n].canceledOrders | Cancel events pertaining to canceled orders for the liquidated trader |
| list | event[n].positions | List of tuples pertaining to liquidated positions |
| string | event[n].positions[n][0] | Liquidated position symbol |
| dict | event[n].positions[n][1] | Liquidated position details |
| dict | event[n].positions[n][1].price | Latest PriceCheckpoint corresponding to this position being liquidated |
| decimal_s | event[n].positions[n][1].amount | Amount of position being liquidated |
| list | event[n].positions[n][1].adlOutcomes | ADL outcomes as a result of liquidation |
| list | event[n].positions[n][1].tradeOutcomes | Trade outcomes as a result of liquidation |
| decimal_s | event[n].positions[n][1].newInsuranceFundCap | New insurance fund capitalization after position has been liquidated |
Strategy update
Sample StrategyUpdate (JSON)
{
"event": {
"amount": "1000000",
"trader": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
"txHash": "0x239a452c6abc453e153c8c53e4bdb995c558619b3aa1980c8977cbc4c283618f",
"strategyId": "main",
"updateType": "Deposit",
"collateralAddress": "0xb69e673309512a9d726f87304c6984054f87a93b"
}
}
A StrategyUpdate is an update to a trader's strategy (such as depositing or withdrawing collateral). The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal_s | event.amount | Amount deposited or withdrawn |
| address_pre_s | event.trader | Trader's Ethereum address prefixed with the chain discriminant |
| bytes32_s | event.txHash | Ethereum transaction hash for the on-chain deposit / withdrawal |
| string | event.strategyId | Strategy ID deposited to or withdrawn from (e.g. "main") |
| string | event.updateType | Action corresponding to either "Deposit" or "Withdraw" |
| address_s | event.collateralAddress | Deposited / withdrawn collateral token'Ethereum address |
Trader update
Sample TraderUpdate (JSON)
{
"event": {
"amount": "1000000",
"trader": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
"txHash": "0x239a452c6abc453e153c8c53e4bdb995c558619b3aa1980c8977cbc4c283618f",
"updateType": "Deposit"
}
}
A TraderUpdate is an update to a trader'DDX account (such as depositing or withdrawing DDX). The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal_s | event.amount | Amount of DDX deposited or withdrawn |
| address_pre_s | event.trader | Trader's Ethereum address prefixed with the chain discriminant |
| bytes32_s | event.txHash | Ethereum transaction hash for the on-chain deposit / withdrawal |
| string | event.updateType | Action corresponding to either "Deposit" or "Withdraw" |
Withdraw
Sample Withdraw (JSON)
{
"event": {
"amount": "1000",
"currency": "0xb69e673309512a9d726f87304c6984054f87a93b",
"strategy": "main",
"signerAddress": "0x6ecbe1db9ef729cbe972c83fb886247691fb6beb",
"traderAddress": "0x006ecbe1db9ef729cbe972c83fb886247691fb6beb"
}
}
A Withdraw is when a withdrawal of a collateral token is signaled. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal_s | event.amount | Amount of collateral token withdrawal has been signaled for |
| address_s | event.currency | Collateral ERC-20 token address |
| string | event.strategy | Strategy ID the withdrawal applies to |
| address_s | event.signerAddress | Signer'Ethereum address withdrawal is taking place from |
| address_pre_s | event.traderAddress | Trader's Ethereum address prefixed with the chain discriminant collateral is being withdrawn to |
Withdraw DDX
Sample WithdrawDDX (JSON)
{
"event": {
"amount": "100",
"signerAddress": "0xa8dda8d7f5310e4a9e24f8eba77e091ac264f872",
"traderAddress": "0x00603699848c84529987e14ba32c8a66def67e9ece"
}
}
A WithdrawDDX is when a withdrawal of DDX is signaled. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal_s | event.amount | Amount of DDX withdrawal has been signaled for |
| address_s | event.signerAddress | Signer'Ethereum address withdrawal is taking place from |
| address_pre_s | event.traderAddress | Trader's Ethereum address prefixed with the chain discriminant DDX is being withdrawn to |
Price checkpoint
Sample PriceCheckpoint (JSON)
{
"event": {
"ETHP": {
"ema": "0",
"indexPrice": "1874.075454545454545454",
"indexPriceHash": "0xa35d3dac391cc18671daacab1c393554aac1546a2cbfe630da1e4e86fb44f542"
}
}
}
A PriceCheckpoint is when a market registers an update to the composite index price a Petual is tracking along with the ema component. The event portion of the transaction essentially emits the latest Price leaf contents, and is defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| string | event.symbol | The market name for which this PriceCheckpoint transaction applies |
| decimal_s | event.symbol.ema | Captures a smoothed average of the spread between the underlying index price and the DerivaDEX order book for the market |
| decimal_s | event.symbol.indexPrice | Composite index price (a weighted average across several price feed sources) |
| bytes32_s | event.symbol.indexPriceHash | Index price hash |
PNL Realization
Sample PnlRealization (JSON)
{
"event": {
"settlementEpochId": 19
}
}
A PnlRealization is when a there is a PNL realization event. This event realizes the PNL of all open positions and adjusts the average entry price to the current mark price. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| int | event.settlementEpochId | The epoch id for the PNL realization event |
Funding
Sample Funding (JSON)
{
"event": [
{
"settlementEpochId": 9
},
[]
]
}
A Funding is when a there is a funding rate distribution. At this time, all strategies are either credited or debited an amount based on the current funding rate and their position notional values and side. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| list | event | The contents of the transaction event |
| int_s | event[0].settlementEpochId | The epoch id for the funding event |
| list | event[1] | Liquidation events that have taken place as a result of funding distributions |
Trade mining
Sample TradeMining (JSON)
{
"event": {
"totalVolume": {
"makerVolume": "41249.393239489105059823",
"takerVolume": "40101.194995030184814398"
},
"ddxDistributed": "3192.388588391993848193",
"tradeMiningEpochId": 15
}
}
A TradeMining is when there is a trade mining distribution. Traders will receive a portion of the overall DDX distributed proportional to their volume traded that interval. Makers will receive 20% of the DDX allocation and takers will receive 80% of the allocation. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| dict | event.totalVolume | Holds the total volume information for this trade mining interval |
| decimal_s | event.totalVolume.makerVolume | Maker volume total for this trade mining interval |
| decimal_s | event.totalVolume.takerVolume | Taker volume total for this trade mining interval. Note that this number may be <= the makerTotalVolume, and any discrepancy is due to liquidations only counting towards maker allocation (i.e. the liquidation engine does not receive any DDX per trade mining) |
| decimal_s | event.ddxDistributed | Total DDX distributed for trade mining for this interval |
| int | event.tradeMiningEpochId | Interval counter for when trade mining occurred |
Post
Sample Post (JSON)
{
"event": {
"side": "Bid",
"price": "1870.25",
"amount": "1.39",
"symbol": "ETHP",
"orderHash": "0x860b1065b629df495de7a0d97432a48b098cadcbb37a1fdbd9",
"strategyId": "main",
"bookOrdinal": 0,
"traderAddress": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
"timeValue": 1024
}
}
A Post is an order that enters the order book. The transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal_s | event.amount | Size of order posted to the order book |
| bytes32_s | event.orderHash | Hexstr representation of the first 25 bytes of the unique EIP-712 hash of the order being placed |
| decimal_s | event.price | Price the order has been placed at |
| string | event.side | Side of order (Bid or Ask) |
| string | event.strategyId | Strategy ID this order belongs to (e.g. "main") |
| string | event.symbol | Symbol for the market this order has been placed (e.g. ETHP) |
| int | event.bookOrdinal | Numerical value signifying sequence of order placement, which can be used to arrange multiple orders at the same price level to achieve FIFO priority in a local order book |
| address_pre_s | event.traderAddress | Trader's Ethereum address prefixed with the chain discriminant |
| timeValue | event.timeValue | Time value |
Trade fill
Sample TradeFill (JSON)
{
"event": {
"price": "1860",
"amount": "1.23",
"reason": "Trade",
"symbol": "ETHP",
"takerSide": "Ask",
"makerOutcome": {
"fee": "0",
"trader": "0x006ecbe1db9ef729cbe972c83fb886247691fb6beb",
"strategy": "main",
"ddxFeeElection": false
},
"takerOutcome": {
"fee": "4.5756",
"trader": "0x00e36ea790bc9d7ab70c55260c66d52b1eca985f84",
"strategy": "main",
"newPositionBalance": "2.46"
},
"makerOrderHash": "0x542ad7f2640447d3e93723253099fd45ae721925e0df64702e",
"takerOrderHash": "0x100d1edd45edede9eedc0e3aac28e7df17168fbef9b459ffc8",
"makerOrderRemainingAmount": "2.54"
}
}
A TradeFill is when there is a fill / match that has taken place. Technically, a TradeFill is not a transaction in it of itself, but rather a part of CompleteFill and PartialFill transactions. We often look to these individual TradeFill events as their own dedicated transaction type, however, for Traders to subscribe to and follow as they would other transactions. The event portion of the transaction has attributes defined as follows:
| type | field | description |
|---|---|---|
| dict | event | The contents of the transaction event |
| decimal | event.price | Price the fill took place |
| decimal | event.amount | Size of the fill |
| string | event.reason | Reason for fill (Trade, Liquidation) |
| string | event.symbol | Market symbol for which this fill took place |
| string | event.takerSide | Taker / aggressor side (Bid, Ask) |
| dict | event.makerOutcome | Data containing the some relevant information pertaining to the maker in the trade |
| address_pre_s | event.makerOutcome.traderAddress | Maker trader's Ethereum address prefixed with the chain discrimimant |
| string | event.makerOutcome.strategyId | Cross-margined strategy identifier for the maker trader |
| decimal_s | event.makerOutcome.fee | Fees paid by the maker as a result of the trade |
| bool | event.makerOutcome.ddxFeeElection | Whether maker fees are being paid in DDX (true) or USDC (false) |
| dict | event.takerOutcome | Data containing the some relevant information pertaining to the taker in the trade |
| address_pre_s | event.takerOutcome.traderAddress | Taker trader's Ethereum address prefixed with the chain discrimimant |
| string | event.takerOutcome.strategyId | Cross-margined strategy identifier for the taker trader |
| decimal_s | event.takerOutcome.fee | Fees paid by the taker as a result of the trade |
| bool | event.takerOutcome.ddxFeeElection | Whether taker fees are being paid in DDX (true) or USDC (false) |
Types
The types labeled throughout this document in the request and response parameters may be familiar to those who have a background in Ethereum. In any case, please refer to the table below for additional information on the terminology used here. This reference in conjunction with the JSON samples should provide enough clarity:
| type | description | example |
|---|---|---|
| string | Literal of a sequence of characters surrounded by quotes | "ETHP" |
| address_s | 20-byte "0x"-prefixed hexadecimal string literal (i.e. 40 digits long) corresponding to an address ETH type |
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" |
| address_pre_s | 21-byte "0x"-prefixed hexadecimal string literal (i.e. 42 digits long) corresponding to an address ETH type prefixed with a single byte for the chain discriminant |
"0x00A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" |
| decimal | Numerical value with up to, but no more than 18 decimals of precision | 10.031500000000000000 |
| decimal_s | String representation of decimal |
"10.031500000000000000" |
| bool | Boolean value, either true or false |
True |
| bytes_s | "0x"-prefixed hexadecimal string literal corresponding to a bytes ETH type |
"0x00000001" |
| bytes32_s | 32-byte "0x"-prefixed hexadecimal string literal (i.e. 64 digits long) corresponding to an bytes32 ETH type |
"0x0000000000000000000000000000000000000000000000000000000000000001" |
| timestamp_s_i | String representation of numerical UNIX timestamp representing the number of seconds since 1/1/1970 | "1616667513875" |
| timestamp_s | String representation representing the ISO 8601 UTC timestamp | "2021-03-25T10:38:09.503654" |
