Ember Configuration Reference
Overview
The Ember can be used in diverse solutions: as a matching engine, as a FIX Gateway, as a platform to host trading SELL side and BUY algorithms and trading connectors, etc.
The module design and configuration flexibility make these diverse solutions possible.
Format
Ember configuration uses text files in the HOCON (Human-Optimized Config Object Notation) format described here.
HOCON is more flexible than the JSON (JavaScript Object Notation) format in that there are several ways to write valid HOCON. Below are two examples of valid HOCON.
Example #1:
settings: {
topic: "NIAGARA",
maxSnapshotDepth: 30 # This is a comment
}
Example #2:
settings {
topic = NIAGARA
maxSnapshotDepth = 30 // This is also a comment
}
If a HOCON configuration does not appear to be working, check the following.
- Curly brackets must be balanced. (Keep identation and formatting neat. This helps spot errors.)
- Quotation marks must be balanced.
- Duplicate keys that appear later take precedence (override earlier values).
General Pattern
The most pluggable services in Ember follow the declaration pattern shown below:
MYSERVICE {
factory: <fully-qualified-name-of-Java-implementation>
settings {
parameter1: value1 // custom
parameter2: value2 // parameters
}
}
This Spring Beans-like approach allows extending the system with custom-build services. See the Custom Service settings section for more information.
Configuration files
Most components have the default configuration described in the “template” configuration file ember-default.conf. The main configuration file ember.conf overrides and refines the default configuration. For example:
On startup, the Ember searches the following locations for configuration files:
- Java System properties (For example,
-Dember.home=/home/deltix/emberhome). - The file ember.conf in Ember home directory.
- The resource ember.conf in CLASSPATH.
- Resource ember-default.conf.
The last resource (ember-default.conf) is shipped with installation and defines default values for all server configuration parameters.
Configuration secrets
Currently, there are several methods of storing sensitive information in configuration files (passwords, API keys, etc.).
- Secret as a Service: Ember is integrated with:
- Hashicorp Vault - This separately installed service is free to use for smaller deployments. See this article for more information.
- AWS Secret Manager. See this article for more information.
- Azure Key Vault. See this article for more information.
- Hashing Passwords can be hashed using a special utility (
bin/mangle). Ember automatically detects an encrypted secret and decrypt it at runtime. See this article for more information. - Environment variables. Sometimes secrets can be securely injected into environment variables. You can reference environment variables in HOCON using
${ENV_VARIABLE_NAME}notation.
Configuration Reference
TimeBase
Almost every deployment of Ember requires the Deltix TimeBase service:
timebase.settings {
url = dxtick://timebasehost1:8011
}
If your TimeBase has User Access control enabled, you need to define them as well:
timebase.settings {
url = dxtick://timebasehost1:8011
username = ember
password = EVcec95166e01fcf5792b8fc215a5dfb62 # NB: encrypted
}
If TimeBase is configured to use TLS(SSL), use dstick:// in URL schema:
timebase.settings {
url = dstick://timebasehost1:8011
}
When using self-signed certificate on TimeBase server side be sure to configure Ember per instructions here (as TimeBase client).
OAUTH2 TimeBase connection
When TimeBase is using OAUTH2 authentication, use the following configuration stanza to define connection parameters:
timebase {
factory = "deltix.ember.app.Oauth2TimeBaseFactory"
settings = null
settings {
url = "dxtick://localhost:8011"
oauth2url = "http://localhost:8282/realms/timebase/protocol/openid-connect/token"
clientId = "client id goes here"
clientSecret = "client secret" # use hashed value or vault
scope = "api://quantoffice/shell openid profile" # optional
}
}
For more information about configuring OAUTH2 authentication read documentation for TimeBase and TimeBase Admin.
OMS settings
Validation Logic
The configuration stanza engine.validation configures various parameters that affect the validation of inbound trading requests:
- allowCancelOfFinalOrders – When set to true, OMS rejects attempts to cancel orders that are in a completed state. By default, ember forwards such requests to a destination venue even if the order seems to be complete (according to state maintained by Ember OMS).
- allowFastCancel - Allows cancelling of unacknowledged orders (some destination venues does not allow this).
- allowFastReplace - Allows replacing of unacknowledged orders or orders that have pending replacement requests (pessimistic/optimistic approach to cancel replace chains).
- maxPendingReplaceCount – When fast replace is allowed, this parameter controls how many order replacement requests may be pending (unacknowledged by order destination venue).
- pricesMustBePositive – When set, OMS rejects orders that have a negative limit price (negative prices may be normal in some markets, e.g., exchange-traded synthetics). Default value is true.
- maxOrderRequestTimeDifference –
This parameter helps to detect order requests that spent too much time in transit to Ember OMS. Make sure the order source periodically synchronizes the local clock with some reliable source. This setting was removed in Ember 1.10.38+. You can now control this behavior via a similar setting in the FIX Order Entry gateway. - allowReplaceTrader – Allows modification of order’s trader (e.g., to follow the CME tag 50 requirement). Mutually exclusive with using Trader as a risk projection key: if Trader is configured as a projection key, replace requests that attempt to change the trader will be rejected regardless of this setting. See Mutable Keys.
- allowReplaceUserData - Allows modification of an order’s user data (e.g., when users put some free text notes into this field). When the modification of an order’s user data is allowed, the UserData projection cannot be used in risk rules.
- nullDestinations – An array of destinations that are no longer needed but might have accumulated orders and positions (this setting simply suppresses ember startup warnings).
The following example shows default values for each parameter:
engine {
validation {
settings {
allowCancelOfFinalOrders = true
allowFastCancel = true
allowFastReplace = false
pricesMustBePositive = true
maxPendingReplaceCount = 10
}
}
nullDestinations = [ “CME”, “ILINK2” ]
}
Order Router
Order Router is an OMS component that controls where trading requests flow. Normally, requests are routed according to their destination. The custom order router can handle requests with an undefined destination or even override the intended destination in certain cases.
Here is an example of a simple order router:
engine.router {
factory = "deltix.ember.service.engine.router.SimpleOrderRouterFactory"
settings {
defaultDestination = SIMULATOR
# ‘true’ routes ALL trading request to destination defined as defaultDestination
force: false
# if destination is not provided, tries to use request’s exchange as destination
fallbackToExchange: true
}
}
This is another example of a custom order router that re-routes trading requests that are designated to KRAKEN to one of the trading connectors, depending on the trader’s group:
engine {
router {
factory = "deltix.ember.service.engine.router.custom.TraderGroupOrderRouterFactory"
settings {
interceptedDestination = "KRAKEN"
traderGroupToDestination : [
"NewYorkGroup : KRAKEN-US",
"LondonGroup : KRAKEN-GB",
"SingaporeGroup : KRAKEN-SG"
]
}
}
}
Changing the router on a production system may result in a change in system behavior:
All historical trading requests that relied on the previous routing destinations are routed according to the new router logic after restart.
Cache
The configuration stanza engine.cache allows tuning internal OMS cache parameters:
engine {
cache {
orderCacheCapacity = 16K
maxInactiveOrdersCacheSize = 4K
initialActiveOrdersCacheSize = 4K
initialClientsCapacity = 16
hashFunction = DEFAULT
mapType = CHAINING
}
}
Where:
- initialClientsCapacity – How many sources of orders to expect (not a limit, just a hint).
- initialActiveOrdersCacheSize – How many active orders to expect (not a limit, just a hint).
- orderCacheCapacity – Defines the total expected order count that ember keeps in memory at any moment in time (not a limit). This is a hint to the order pool to pre-allocate a given number of blank order instances.
- maxInactiveOrdersCacheSize – Defines how many inactive (REJECTED/CANCELLED/COMPLETELY_FILLED) orders ember keeps in memory per order source.
- hashFunction - Defines hash function used, one of DEFAULT | NATIVE | XXHASH | METRO. Default is DEFAULT. Since Ember 1.15.
- mapType - Defines underlying data structure used for cache, one of CHAINING | LINEAR_PROBING | ROBIN_HOOD (default is CHAINING). Since Ember 1.15
** hashFunction = DEFAULT** indicates that Java Default hash function will be used for the cache.
** hashFunction = NATIVE** indicates that native hash from this blog will be used for the cache.
** hashFunction = XXHASH** indicates that xxHash from implementation here will be used for the cache.
** hashFunction = METRO** indicates that metro hash from implementation here will be used for the cache.
Ember OMS reloads journal on startup, but once started it but relies solely on in-memory cache of orders. This cache contains all active and last N inactive orders for each order source. The idea is to be able to process rare cases of "fill after cancel". For some exchanges Fill events may take slightly longer path than other order events like Cancel (and hence may arrive out of normal order lifecycle sequence). This out-of-sequence fill usually happens within a second or two of order completion.
We suggest the following math: let's say each order source (each algorithm, or API client) sends us up to 1000 orders per second. We want to be able to process late fills reported within 5 seconds of order completion. In this case inactive (completed) order cache size is set to 5000. Default value is 4096
# Maximum amount of inactive (complete) orders to keep in cache (per source)
engine.cache.maxInactiveOrdersCacheSize = 5000
We strongly advise not to set this to larger numbers - increased cache size leads to excessive memory consumption and slows down OMS order processing.
Engine Order Transformer
You can define a custom transformer of in-bound order requests.
Here is an example:
engine {
transformer: {
factory = …
settings {
…
}
}
}
Use this option with care. Ember stores the result of this transformation into Ember Journal. There is no durable trace of the original order request.
Transformation of inbound events or other message types is not yet supported.
See Order Request Transformer for the interface contract and how to implement a custom transformer.
Custom Instrument Metadata
In some rare cases, the engine needs access to additional information about each instrument. For example, a custom risk rule may want to keep track of some extra information like the instrument industry sector or per-exchange minNotional. This can be achieved using a custom Instrument Factory:
engine {
instrumentInfoFactory {
factory = "deltix.ember.service.engine.CustomExtendedInstrumentInfoFactory"
settings {}
}
}
Error Handling
The engine’s configuration stanza exceptions {} defines the system reaction to abnormal situations.
TimeBase Disconnect
Ember components (algorithms and connectors) can recover from the loss of a TimeBase connection, however, there may be a gap in market data, message loss in output channels, and other side effects. You can define how Ember should react to the loss of a TimeBase connection:
engine.exceptions.timebaseDisconnect = HaltTrading
Possible values are:
Continue- Logs the error, let Ember recover.HaltTrading- Halts Trading (forces the operator to confirm that the system fully recovered on TimeBase reconnect).Shutdown- Graceful Ember shutdown.ShutdownLeaderWithFollower- Shutdown when leader-with-follower, continue when follower, or leader without follower.
Prior to Ember 1.10.14:
exceptions.haltOnTimebaseLoss (true)- Halts trading every time Ember loses its TimeBase connection.
Misc parameters
This section describes the remaining parameters. If you want to change these, you can place them inside the engine configuration stanza:
-
maxNumberOfRequestErrorsToLog (64) - Threshold on the amount of exceptions Ember prints into the output log (subsequent errors are logged as request reject reasons on messages). The engine has a performance counter for it.
-
maxInactiveUnknownWarningsToLog (16) - Maximum number of warnings about events for no-longer active (or unknown) orders. These events cannot be processed. The engine has a performance counter for it.
-
maxRiskVetosToLog (16) - Maximum number of risk rule vetos (order rejects) to log. The engine has a performance counter for it.
-
convertStatusEventsToNormalEvents (true) - A "do not send Order Status to algorithms" event. Convert them to normal events that report incremental differences.
-
useMaxRemainingQuantity (false) - Instruct OMS to enrich messages using
maxRemainingQuantityrather than the remaining quantity of the working order. Slower. -
allowUnrestrictedPositionRequests (false) - By default system is configured in "single API client can only see own positions" mode. Clients are identified by API keys that are mapped to order Source IDs hence by default Source ID is a required part of projection when requesting positions. When this security-driven restriction is removed, different API Clients can see the positions of each other (as well as system-wide positions).
Security Metadata (Instruments)
By default, Ember uses the local TimeBase stream “securities” to learn about Security Metadata (AKA security master). This stream is supported by most QuantServer/QuantOffice/CryptoCortex ecosystems.
On startup, Ember reads a copy of the security metadata from the “securities” stream. During run time, Ember watches this stream for updates (only for inserts/updates; deletes are ignored). You can override the stream name as follows:
instruments {
subscription {
stream = "securities"
filter = null # SELECT * FROM $stream WHERE $filter
}
useCentralSMD = true
}