#
Tutorial: Getting Started with the Engine
The following set of commands enable setting up the engine to be ready to accept orders from users and to be able to perform its core functions. They only need to be done once and must be done via the control gateway.
In the following section we will refer to the following input types:
int : 32 bits integer
long : 64 bits integer
string : a sequence of characters
double : 64 bits floating decimal value
#
Matching the first Trade
A few setup steps must be performed before it is possible to place the first order and make a trade:
- Create at least one Fee Schedule
- Add at least two Assets
- Add at least one Instrument, referencing the Fee Schedule
- Make a deposit to at least one account, on the Settlement currency of the Instrument
- Create an order
Each of these steps is outlined in detail below.
#
Exchange Suspended on Startup
The exchange is initially suspended when it first starts. This is to prevent any orders being placed before basic setup tasks have been completed. To check which setup tasks remain, run the "Resume" endpoint /ExchangeWideControls/ResumeTrading on the control gateway. The exchange will either be resumed, or it will send a response indicating which setup tasks remain.
Reasons why the exchange would be suspended:
#
Setting up Fees
We allow to set up any number of fee tiers which correspond to various types of customer relationships. At each tier, the engine expects the following fee types:
#
Fee Tier Example
Here's an example set of fee schedules. Generally the fees would decrease (or become rebates) as the tier increases. The intention is that higher tiered users are doing more volume and so are offered a more attractive fee schedule.
Path: /FeeSchedule
Method: POST
Parameters:
id: string (uuid) (used to link instruments to this fee schedule)
name: string (unused)
Body:
{
"elements": [
{
"userTierId": 0,
"makerFee": 0.01,
"takerFee": 0.02,
"hiddenMakerFee": 0.03,
"hiddenTakerFee": 0.04,
"icebergHiddenMakerFee": 0.05,
"icebergVisibleMakerFee": 0.06,
"icebergFinalBergFee": 0.06,
"icebergTakerFee": 0.07,
"liquidationMakerFee": 0.08,
"liquidationTakerFee": 0.09
},
{
"userTierId": 1
// ...
}
]
}
Whenever a fee is applied, it will be credited to a special account called the fees account. The application needs to be told the account number of the fees account.
Path: /Account/FeesAccount
Method: POST
Parameters:
account: long
#
Creating Assets
#
The engine needs to be given the assets that can be used to maintain balances and calculate margin requirements and fees.
The Nekuti matching engine supports the concept of major and minor asset names where the denomination of an asset might vary depending on the situation. For example for Bitcoin (BTC) instrument prices would be quoted in BTC but settlement occurs in Satoshi ( 10^8 Satoshi per 1 BTC). These are represented as the same asset internally and the nominal conversion will happen automatically. The minor multiplier specifies the finest grained native unit stored internally in the engine. In the example of BTC, the native unit is milliSatoshi (one thousandth of a Satoshi) so the minor multiplier is 1000. The major multiplier is the number of native units per Major currency unit. So since 1 Bitcoin (BTC) is 10^8 milliSatoshis, the major multiplier is 10^11.
Example currencies:
Path: /Asset
Method: POST
Parameters:
assetMajorName: string
majorMultiplier: long
assetMinorName: string
minorMultiplier: long
assetProperName: string
#
Adding Instruments
The engine needs to be given the instruments that can be traded. We support spot and margined futures instruments.
#
Spot
Path: /Instrument/Spot
Method: POST
Parameters:
instrumentShortCode: BTC_USD
asset1ShortCode: BTC
asset2ShortCode: USD
lotSize: 100
feeScheduleId: the uuid of the fee schedule as mentioned in the fees section
tickSize: 0.01
minPrice: 0.01
maxPrice: 1000000
maxOrderQuantity: 1000000
#
Futures
We support any combination of linear/inverse and term/perpetual futures. Settlement currency can be either side of the instrument or a different currency altogether (Quantos).
Path: /Instrument/Future
Method: POST
Parameters:
contractShortCode: BTCUSD
isInverse: true
isPerpetual: true
asset1ShortCode: BTC
asset2ShortCode: USD
settlementCurrency: BTc
lotSize: 100
feeScheduleId: the uuid of the fee schedule as mentioned in the fees section
tickSize: 0.5
minPrice: 0.01
maxPrice: 1000000
initialPrice: 53000.5
maxOrderQuantity: 1000000
isLastPriceMarked: false
initialMarginSpec: 0,0.01 20000000000,0.0135 40000000000,0.017
maintenanceMarginSpec: 0,0.0035 20000000000,0.007 40000000000,0.0105
The margin specs provide the margin requirements that apply at each risk level. In the example above, a client with a risk limit above 20bn BTc but below 40bn BTc/ would have an initial margin requirement of 1.35% and a maintenance margin requirement of 0.7%
#
Onboarding Customers
#
Depositing/Withdrawing funds
Creating a user account on the engine is as simple as depositing funds on to an account number. The asset short name must match an the minor name of an asset added via the /Asset request, e.g. Satoshi.
The account number can be any valid value in a 64-bit long. However, it is more memory efficient if the active account numbers are concentrated in a closely packed range.
Path: /Deposits
Method: POST
Parameters:
accountIdentifier: long
assetShortName: string
amount: long
For withdrawals, the engine will validate that the account contains sufficient free funds to be withdrawn. This excludes funds that are locked up by open orders or by a margined position.
Path: /Withdrawals
Method: POST
Parameters:
accountIdentifier: long
assetShortName: string
amount: long
Once you have deposited funds into at least two users' accounts, you are ready to place orders and match.
#
Further One-time setup
#
Liquidation account
The liquidation account is a special account where liquidated positions are transferred. The application needs to be told the account number of the liquidation account using the following request
Path: /Account/LiquidationAccount
Method: POST
Parameters:
account: long
#
Liquidation Strategy
When liquidation happens, the engine will try to liquidate positions on instruments one by one until the account’s margin requirement becomes less than its available funds. The order in which the engine goes down the list of instrument to liquidate is specified by this request:
Path: /Instrument/LiquidationStrategy
Method: POST
Parameters:
Body:
[
"BTCUSD",
"ETHUSD",
"BTCUSDT"
…
]
#
Rounding
The engine stores and calculates account balances and transaction amounts in whole integer units, so that arithmetic operations never unintentionally create or destroy balances. This means that in some cases, there will be a residual 1-unit discrepancy between the buy and sell sides of a trade.
A buyer wants to purchase 2000 units of an inverse futures product at a price of 3.0 and match with two sellers that sell 1000 each.
Buyer cost: \frac{2000}{3.0} = 667
Seller cost: 2 * \frac{1000}{3.0} = 2 * 333 = 666
In this example the buyer's cost is one unit higher than the sum of the seller's costs.
In such cases, the difference will be credited to (or taken away from) a special “penny jar” account, to ensure the net cost impact of the transaction on the overall exchange is always 0.
It is recommended to use fine-grained units in the definition of Assets (e.g. milliSatoshi) so that the size of rounding differences is minimised.
The application needs to be told the account number of the penny jar account using the following request:
Path: /Account/PennyJarAccount
Method: POST
Parameters:
account: long
Once the penny jar account has been set, a small amount of funds should be deposited there in each spot and margin currency in order to ensure the healthy operation of the exchange.
#
Ongoing Operations
To continue operation of the exchange, a few operational processes must be maintained. While these can certainly be handled manually, the intent is for automated external processes to be able to perform each operation.
#
Mark Prices
Futures instruments can be either last price marked or fair price marked. Last price mark uses the last price traded on the exchange, whereas a fair price mark uses an external source of prices. In the latter case, the engine must receive frequent market data updates.
Path: /Instrument/MarkPrices
Method: POST
Parameters:
instrument: string
price: double
Body:
[
{
"instrument": BTCUSD,
"price": 53000.5
},
{
"instrument": ETHUSD,
"price": 3765.2
}
// …
]
#
Termed Futures Expiry
Upon expiry, futures contracts will automatically settle at the expiryPrice. The engine must be notified of the expiration of termed Futures instruments using this request:
Path: /Instrument/Expire
Method: PUT
Parameters:
instrument: string
expiryPrice: double
#
Perpetual Futures Funding
Perpetual futures are subject to regular funding cycles. The engine must be notified each time there is a funding cycle for a particular instrument using this request.
Path: /Instrument/FundingCharge
Method: POST
Body:
[
{
"instrument": "XBTUSD",
"fundingRate": 0.0001,
"referencePrice": 61335.61
},
{ ... }
]
As an example, for a position of 0.5 BTC in a BTCUSDT linear future contract, with a reference price of 30000 and a rate of 0.0001, we calculate the funding charge by applying the funding rate to the cost of the position at the reference price:
fundingCharge = { 0.5 * 30000 * 0.0001 }
#
Optional Settings
#
Linking subaccounts
While depositing funds is sufficient for the account to start trading, there can be additional optional setup The below request links an account to a parent account (owner)
Path: /Account/Owner
Method: POST
Parameters:
account: long
owner: long
#
Setting the Fee Tier
Every account defaults to the 0th fee tier unless otherwise specified. To change the Fee tier for an account, use the Fee Tier endpoint:
Path: /Account/FeeTier
Method: POST
Parameters:
feeTier: int (32 bits integer) must match the userTierId of one of the fee schedule above
Body: [1, 2, 3]: array of long