# 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:

  1. Create at least one Fee Schedule
  2. Add at least two Assets
  3. Add at least one Instrument, referencing the Fee Schedule
  4. Make a deposit to at least one account, on the Settlement currency of the Instrument
  5. 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:

Message Reason Solution
UNABLE_TO_PERFORM_LIQUIDATION The liquidation account (insurance fund account) has not been set. Initialize the account using the /Account/LiquidationAccount endpoint
MANUALLY_SUSPENDED The exchange was suspended manually using the /ExchangeWideControls/SuspendTrading endpoint Resume using the /ExchangeWideControls/ResumeTrading endpoint

# 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 type Scope
Maker fee applied to an order that matches while resting in the order book
Taker fee applied to an order that matches immediately
Hidden fee (maker or taker) applied to a hidden order
Iceberg hidden maker fee applied to the hidden portion of the iceberg
Iceberg visible maker fee applied to the visible portion of the iceberg
Iceberg final fee applied when an iceberg resting order becomes fully visible
Iceberg taker fee applied to the portion of an iceberg order that executes immediately
Liquidation maker fee applied to the insurance fund when it takes over a position and is trading out of it
Liquidation taker fee applied when an order is generated by the system to liquidate a position

# 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.

Fee Tier 0 Tier 1 Tier 2 Tier 3 Tier 4
Maker Fee 0.0002 0.0002 0.0001 0 -0.00005
Taker Fee 0.001 0.00075 0.0005 0.0005 0.0005
Hidden Maker Fee 0.001 0.00075 0.0005 0.0005 0.0005
Hidden Taker Fee 0.0015 0.0009 0.001 0.001 0.001
Iceberg Hidden Maker Fee 0.001 0.00075 0.0005 0.0005 0.0005
Iceberg Visible Maker Fee 0.0002 0.0002 0.0001 0.0001 0.0001
Iceberg Final Berg Fee 0.0002 0.0002 0.0001 0 -0.00005
Iceberg Taker Fee 0.0015 0.0009 0.001 0.001 0.001
Liquidation Maker Fee 0.0002 0.0002 0.0002 0.0002 0.0002
Liquidation Taker Fee 0.001 0.00075 0.0005 0.0005 0.0005
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:

Major Symbol Minor Symbol Minor Multiplier Major-Minor ratio Major Multiplier Proper Name
BTC BTc 1,000 100,000,000 100,000,000,000 Bitcoin
ETH Gwei 1 1,000,000,000 1,000,000,000 Ethereum
USD USd 1,000 100 100,000 United States Dollar
USDT USDt 1 1,000,000 1,000,000 Tether
GBP GBp 1,000 100 100,000 Pound Sterling
EUR EUr 1,000 100 100,000 euro
MEME MEMe 1,000 100,000 100,000,000 Memecoin
ADA ADa 100 1,000,000 100,000,000 Cardano
DOGE DOGe 1 100,000,000 100,000,000 Dogecoin
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