Skip to content

Routing model and matching

Route

Field Type Default Meaning
id int assigned Immutable route id
name string required Unique route name
description string empty Administrative description
priority int 0 Higher values are evaluated first
enabled bool true Whether the route participates in matching
conditions.operation string/int ANY / 0 Request operation
conditions.group_mask string * Wildcard account-group expression
conditions.symbol_mask string * Wildcard symbol expression
conditions.login int 0 Exact login; 0 matches every login
conditions.cmd int OP_NOTHING Exact trade command; OP_NOTHING matches every command
conditions.reason int -1 Exact reason; negative matches every reason
conditions.volume_min int 0 Inclusive minimum; 0 disables the lower bound
conditions.volume_max int 0 Inclusive maximum; 0 disables the upper bound
steps array required Ordered execution targets
created_at int64 assigned Creation timestamp
updated_at int64 assigned Last mutation timestamp

All configured conditions use AND. Group and symbol expressions use the server wildcard matcher. Volumes are represented in the server's integer volume units.

Operations

Name Value
ANY 0
OPEN 1
CLOSE 2
PARTIAL_CLOSE 3

Route steps

Field Type Meaning
id int Server-assigned step id
route_id int Owning route id
position int Zero-based position in the execution plan
target string/int Execution target
timeout_ms int Time before advancing to the next step
dealer_pool_id int Manual dealer pool identifier
virtual_dealer_policy_id int Virtual Dealer policy identifier
gateway_id int Configured Gateway instance identifier
Target Value Behavior
INTERNAL 0 Continue the existing execution flow
MANUAL_DEALER 1 Create a request for the selected manual dealer pool
VIRTUAL_DEALER 2 Evaluate the referenced automatic dealer policy
REJECT 3 Reject the routed trade operation
GATEWAY 4 Execute through the selected Gateway/LP instance and continue the chain

GATEWAY is an independent execution target. Group selection remains a route condition; symbol mapping and lot limits are taken from the confirmed Gateway runtime specifications.

Example chain:

[
  {"position":0,"target":"VIRTUAL_DEALER","virtual_dealer_policy_id":3,"timeout_ms":3000},
  {"position":1,"target":"GATEWAY","gateway_id":1,"timeout_ms":5000},
  {"position":2,"target":"INTERNAL","timeout_ms":0}
]

Validation

  • name must not be empty and must be unique.
  • Login and volume bounds cannot be negative.
  • A non-zero volume_max cannot be less than volume_min.
  • A route must contain at least one step.
  • Step positions must be contiguous and start at 0.
  • Timeouts cannot be negative.
  • MANUAL_DEALER requires a positive dealer_pool_id.
  • VIRTUAL_DEALER requires a positive virtual_dealer_policy_id.
  • GATEWAY requires a positive gateway_id.
  • The referenced manual pool, Virtual Dealer policy, or Gateway configuration must exist when a route is created or updated.
  • Every non-final manual, virtual dealer, or Gateway step requires a positive timeout.
  • INTERNAL and REJECT are terminal and may only be the final step.
  • The final step must be INTERNAL or REJECT so every chain terminates deterministically.

Resolution

The cached route list is ordered by:

ORDER BY priority DESC, id ASC

The first enabled route whose conditions match is returned with all its steps. Equal priorities are therefore stable: the older route with the lower id wins.

No match produces an implicit plan that is not stored in the database:

{
  "matched": false,
  "route_id": 0,
  "route_name": "default",
  "steps": [{"target":"INTERNAL","target_id":0}],
  "snapshot_version": 7
}

Persistence and cache

RoutingManager owns bases/routing.db with two tables:

  • routes contains conditions and ordering fields;
  • route_steps contains the ordered target chain and is deleted through its route foreign key.

Create and update operations persist a route and all steps in one SQLite transaction. After commit, the manager loads and atomically publishes a complete immutable RoutingSnapshot. Read and resolve operations acquire this snapshot and do not hold the database mutex.

snapshot_version changes after every successful reload and identifies the exact ruleset used by dry-run resolution. Optimistic concurrency based on this version is not implemented yet.

Trade execution integration

DealerPolicyService builds the routing context for OPEN, CLOSE, and PARTIAL_CLOSE. Routing runs after the operation's existing validation and before it is committed to the trade queue.

With routing execution disabled, trade behavior is unchanged. With it enabled, the ordered plan is executed as follows:

  • INTERNAL continues Core execution;
  • REJECT returns RET_TRADE_DISABLE;
  • MANUAL_DEALER creates a persistent request and defers execution;
  • VIRTUAL_DEALER evaluates its policy and accepts, rejects, or advances to the next step.
  • GATEWAY sends an execution request to the selected ready Gateway instance.

Virtual Dealer ACCEPT advances to the next configured step. Manual Dealer ACCEPT also resumes from the following step. A Gateway EXECUTED result advances to the next step, normally INTERNAL. NOT_APPLICABLE, unavailable, transport failure, and timeout advance to the configured fallback step. An explicit Gateway/LP REJECTED result terminates the chain with RET_TRADE_DISABLE.

INTERNAL remains terminal. Post-trade hedging such as INTERNAL → GATEWAY requires a separate HEDGE lifecycle and is not executed by this version.

A rejected pending activation follows the existing non-retryable activation-error path and cancels the pending order. ImportOpenTrade is excluded because it restores an already accepted position. Virtual Dealer policy details are documented in Dealing Center: Virtual Dealer.