Liquidity Docs

Execution & Algorithms

Smart order routing, execution algorithms (TWAP, VWAP, Iceberg, Sniper, POV, DCA), pre-trade risk checks, and post-trade reporting

Liquidity.io provides institutional-grade execution capabilities through the @liquidityio/trading SDK. This includes smart order routing across multiple venues, algorithmic execution for minimizing market impact, pre-trade risk management, and post-trade analytics.

Smart Order Routing

When smart routing is enabled, the client aggregates order books from all connected venues and routes orders to the venue offering the best price for the requested size.

How It Works

  1. The client fetches the order book from every connected venue
  2. Order books are aggregated into a unified view with per-venue attribution
  3. For a buy order, the client finds the venue with the lowest ask that can fill the quantity
  4. For a sell order, it finds the venue with the highest bid
  5. The order is placed on the selected venue

Configuration

import { Client, Config, NativeVenueConfig, CcxtConfig } from '@liquidityio/trading';

const config = new Config()
  .withNative('liquidity', NativeVenueConfig.liquidDex('https://api.liquidity.io/v1'))
  .withCcxt('binance', CcxtConfig.create('binance').withCredentials('key', 'secret'))
  .withCcxt('okx', CcxtConfig.create('okx').withCredentials('key', 'secret'))
  .withVenuePriority(['liquidity', 'binance', 'okx'])
  .withSmartRouting(true);

const client = new Client(config);
await client.connect();

// This order is automatically routed to the best venue
const order = await client.buy('BTC-USDC', '1.0');
console.log(`Routed to ${order.venue} at ${order.averagePrice}`);

Manual Venue Selection

Override smart routing by specifying a venue:

// Force execution on Binance
const order = await client.buy('BTC-USDC', '1.0', 'binance');

// Force execution on the Liquidity.io ATS
const atsOrder = await client.limitBuy('AAPL', 100, '248.50', 'liquidity');

Python

from lx_trading import Client, Config
from lx_trading.config import NativeVenueConfig, CcxtConfig

config = Config()
config.with_native("liquidity", NativeVenueConfig.liquid_dex("https://api.liquidity.io/v1"))
config.with_ccxt("binance", CcxtConfig.create("binance").with_credentials("key", "secret"))
config.smart_routing = True

client = Client(config)
await client.connect()

# Smart-routed order
order = await client.buy("BTC-USDC", Decimal("1.0"))
print(f"Routed to {order.venue} at {order.average_price}")

# Explicit venue
order = await client.buy("BTC-USDC", Decimal("1.0"), venue="binance")

Execution Algorithms

The SDK provides six built-in execution algorithms for managing large orders with minimal market impact. All algorithms are implemented client-side and use the Client to place orders.

TWAP (Time-Weighted Average Price)

Splits a large order into equal slices executed at regular time intervals. Suitable when the goal is to match the time-weighted average price over a period.

Parameters:

ParameterTypeDescription
symbolstringTrading pair
sideSideBUY or SELL
totalQuantityDecimalTotal quantity to execute
durationSecondsnumberTime window for execution
numSlicesnumberNumber of child orders

TypeScript:

import { TwapExecutor, Side } from '@liquidityio/trading';
import { Decimal } from 'decimal.js';

const twap = new TwapExecutor(
  client,
  'BTC-USDC',              // symbol
  Side.BUY,                // side
  new Decimal('10'),       // total quantity: 10 BTC
  3600,                    // duration: 1 hour
  12,                      // 12 slices (one every 5 minutes)
);

const orders = await twap.execute();
console.log(`Executed ${orders.length} slices`);
for (const o of orders) {
  console.log(`  ${o.orderId}: ${o.filledQuantity} @ ${o.averagePrice}`);
}

Python:

from lx_trading.execution import TwapExecutor
from lx_trading.types import Side
from decimal import Decimal

twap = TwapExecutor(
    client=client,
    symbol="BTC-USDC",
    side=Side.BUY,
    total_quantity=Decimal("10"),
    duration_seconds=3600,
    num_slices=12,
)

orders = await twap.execute()
for o in orders:
    print(f"  {o.order_id}: {o.filled_quantity} @ {o.average_price}")

VWAP (Volume-Weighted Average Price)

Executes based on a participation rate of market volume. The algorithm monitors real-time volume and sizes each slice to represent a fixed percentage of observed volume. Suitable when the goal is to match the volume-weighted average price.

Parameters:

ParameterTypeDescription
symbolstringTrading pair
sideSideBUY or SELL
totalQuantityDecimalTotal quantity to execute
participationRateDecimalFraction of market volume (e.g., 0.10 = 10%)
maxDurationSecondsnumberMaximum execution window

TypeScript:

import { VwapExecutor, Side } from '@liquidityio/trading';

const vwap = new VwapExecutor(
  client,
  'BTC-USDC',              // symbol
  Side.BUY,                // side
  new Decimal('10'),       // total: 10 BTC
  new Decimal('0.10'),     // 10% participation rate
  7200,                    // max 2 hours
);

const orders = await vwap.execute();
const totalFilled = orders.reduce(
  (sum, o) => sum.plus(o.filledQuantity),
  new Decimal(0),
);
console.log(`VWAP filled ${totalFilled} BTC across ${orders.length} slices`);

Python:

from lx_trading.execution import VwapExecutor

vwap = VwapExecutor(
    client=client,
    symbol="BTC-USDC",
    side=Side.BUY,
    total_quantity=Decimal("10"),
    participation_rate=Decimal("0.10"),
    max_duration_seconds=7200,
)

orders = await vwap.execute()
total_filled = sum(o.filled_quantity for o in orders)
print(f"VWAP filled {total_filled} BTC in {len(orders)} slices")

Iceberg

Hides a large order by placing only a small visible quantity at a time. Each visible slice is a limit order; when it fills, the next slice is placed. The full order size is never revealed to the market.

Parameters:

ParameterTypeDescription
symbolstringTrading pair
sideSideBUY or SELL
totalQuantityDecimalTotal hidden quantity
visibleQuantityDecimalSize of each visible slice
priceDecimalLimit price for all slices
venuestring(Optional) Target venue

TypeScript:

import { IcebergExecutor, Side } from '@liquidityio/trading';

const iceberg = new IcebergExecutor(
  client,
  'BTC-USDC',              // symbol
  Side.BUY,                // side
  new Decimal('100'),      // total: 100 BTC (hidden)
  new Decimal('5'),        // visible: 5 BTC at a time
  new Decimal('83000'),    // limit price
  'liquidity',             // venue (optional)
);

const orders = await iceberg.execute();
console.log(`Iceberg completed: ${orders.length} slices filled`);

Python:

from lx_trading.execution import IcebergExecutor

iceberg = IcebergExecutor(
    client=client,
    symbol="BTC-USDC",
    side=Side.BUY,
    total_quantity=Decimal("100"),
    visible_quantity=Decimal("5"),
    price=Decimal("83000"),
    venue="liquidity",
)

orders = await iceberg.execute()

Sniper

Monitors the market and executes immediately when the price reaches a target. Useful for capturing specific price levels with minimal latency. Polls the ticker every 100ms.

Parameters:

ParameterTypeDescription
symbolstringTrading pair
sideSideBUY or SELL
quantityDecimalOrder quantity
targetPriceDecimalPrice trigger (buy: ask ≤ target, sell: bid ≥ target)
timeoutSecondsnumberMaximum wait time

TypeScript:

import { SniperExecutor, Side } from '@liquidityio/trading';

const sniper = new SniperExecutor(
  client,
  'BTC-USDC',              // symbol
  Side.BUY,                // side
  new Decimal('1'),        // quantity: 1 BTC
  new Decimal('80000'),    // trigger when ask <= 80000
  300,                     // timeout: 5 minutes
);

const order = await sniper.execute();
if (order) {
  console.log(`Sniped at ${order.averagePrice}`);
} else {
  console.log('Timeout reached, price target not hit');
}

Python:

from lx_trading.execution import SniperExecutor

sniper = SniperExecutor(
    client=client,
    symbol="BTC-USDC",
    side=Side.BUY,
    quantity=Decimal("1"),
    target_price=Decimal("80000"),
    timeout_seconds=300,
)

order = await sniper.execute()
if order:
    print(f"Sniped at {order.average_price}")
else:
    print("Timeout -- target not reached")

POV (Percent of Volume)

Executes as a fixed percentage of observed market volume over time. Similar to VWAP but tracks actual volume deltas rather than estimated hourly rates. Checks volume every 10 seconds.

Parameters:

ParameterTypeDescription
symbolstringTrading pair
sideSideBUY or SELL
totalQuantityDecimalTotal quantity to execute
targetPercentDecimalTarget percentage of volume (e.g., 0.05 = 5%)
maxDurationSecondsnumberMaximum execution window

TypeScript:

import { PovExecutor, Side } from '@liquidityio/trading';

const pov = new PovExecutor(
  client,
  'BTC-USDC',              // symbol
  Side.SELL,               // side
  new Decimal('50'),       // total: 50 BTC
  new Decimal('0.05'),     // 5% of market volume
  14400,                   // max 4 hours
);

const orders = await pov.execute();
console.log(`POV completed: ${orders.length} slices`);

DCA (Dollar Cost Averaging)

Invests a fixed dollar amount at regular intervals regardless of price. Useful for systematic accumulation strategies.

Parameters:

ParameterTypeDescription
symbolstringTrading pair
sideSideBUY or SELL
amountPerIntervalDecimalDollar amount per interval (quote currency)
intervalMsnumberTime between orders (milliseconds)
numIntervalsnumberNumber of intervals
venuestring(Optional) Target venue

TypeScript:

import { DcaExecutor, Side } from '@liquidityio/trading';

const dca = new DcaExecutor(
  client,
  'BTC-USDC',              // symbol
  Side.BUY,                // side
  new Decimal('1000'),     // $1000 per interval
  3600000,                 // every 1 hour
  24,                      // 24 intervals (1 day)
  'liquidity',             // venue (optional)
);

const orders = await dca.execute();
const totalSpent = orders.reduce(
  (sum, o) => sum.plus(o.filledQuantity.mul(o.averagePrice ?? 0)),
  new Decimal(0),
);
console.log(`DCA invested $${totalSpent} across ${orders.length} buys`);

Python:

from lx_trading.execution import DcaExecutor

dca = DcaExecutor(
    client=client,
    symbol="BTC-USDC",
    side=Side.BUY,
    amount_per_interval=Decimal("1000"),
    interval_ms=3600000,
    num_intervals=24,
    venue="liquidity",
)

orders = await dca.execute()

Algorithm Comparison

AlgorithmUse CaseMarket ImpactUrgencyVolume Sensitivity
TWAPBenchmark trackingLowLowNo
VWAPVolume-matched executionLowLowYes
IcebergHide large ordersMinimalMediumNo
SniperPrice targetingNone (until trigger)HighNo
POVParticipation-limitedLowLowYes
DCASystematic accumulationMinimalNoneNo

Pre-Trade Risk Checks

The SDK includes a RiskManager that validates every order against configurable limits before submission.

Risk Parameters

ParameterTypeDescription
enabledbooleanEnable/disable risk checks
maxPositionSizeDecimalMaximum position in any single asset
maxOrderSizeDecimalMaximum size for a single order
maxDailyLossDecimalMaximum daily loss before kill switch
maxOpenOrdersnumberMaximum concurrent open orders per symbol
killSwitchEnabledbooleanAuto-halt trading on daily loss breach
positionLimitsMapPer-asset position limits

TypeScript

import { RiskManager, RiskError } from '@liquidityio/trading';
import { Decimal } from 'decimal.js';

const risk = new RiskManager({
  enabled: true,
  maxPositionSize: new Decimal('100'),    // Max 100 units of any asset
  maxOrderSize: new Decimal('10'),        // Max 10 units per order
  maxDailyLoss: new Decimal('5000'),      // $5000 daily loss limit
  maxOpenOrders: 50,                       // Max 50 open orders per symbol
  killSwitchEnabled: true,                 // Auto-halt on loss breach
  positionLimits: new Map([
    ['BTC', new Decimal('10')],           // Max 10 BTC position
    ['ETH', new Decimal('100')],          // Max 100 ETH position
  ]),
});

// Validate before placing an order
try {
  risk.validateOrder(orderRequest);
  const order = await client.placeOrder(orderRequest);
  risk.orderOpened(order.symbol);
} catch (e) {
  if (e instanceof RiskError) {
    console.error(`Risk check failed: ${e.message}`);
    // Do not place the order
  }
}

// Update after fills
risk.updatePosition('BTC', new Decimal('1'), Side.BUY);
risk.updatePnl(new Decimal('-250'));

// Check state
console.log(`BTC position: ${risk.position('BTC')}`);
console.log(`Daily PnL: ${risk.getDailyPnl()}`);
console.log(`Kill switch active: ${risk.isKilled}`);

// Reset daily PnL at start of trading day
risk.resetDailyPnl();

Python

from lx_trading import RiskManager, RiskError
from lx_trading.config import RiskConfig
from decimal import Decimal

risk = RiskManager(RiskConfig(
    enabled=True,
    max_position_size=Decimal("100"),
    max_order_size=Decimal("10"),
    max_daily_loss=Decimal("5000"),
    max_open_orders=50,
    kill_switch_enabled=True,
    position_limits={"BTC": Decimal("10"), "ETH": Decimal("100")},
))

try:
    risk.validate_order(order_request)
    order = await client.place_order(order_request)
    risk.order_opened(order.symbol)
except RiskError as e:
    print(f"Risk check failed: {e}")

Kill Switch

When killSwitchEnabled is true and the daily PnL exceeds maxDailyLoss, the risk manager activates the kill switch. All subsequent validateOrder calls throw RiskError('Kill switch is active').

To resume trading after a kill switch activation:

risk.reset();          // Deactivate kill switch
risk.resetDailyPnl();  // Reset daily PnL counter

Post-Trade Reporting

Order Status Tracking

Track order execution in real-time:

import { orderIsOpen, orderIsDone, orderFillPercent } from '@liquidityio/trading';

const order = await client.limitBuy('BTC-USDC', '1.0', '83000');

// Check status
console.log(`Open: ${orderIsOpen(order)}`);
console.log(`Done: ${orderIsDone(order)}`);
console.log(`Fill %: ${orderFillPercent(order)}%`);
console.log(`Filled: ${order.filledQuantity} / ${order.quantity}`);
console.log(`Remaining: ${order.remainingQuantity}`);
console.log(`Avg price: ${order.averagePrice}`);
console.log(`Fees:`, order.fees);

Trade History

Each order may generate multiple fills (trades):

interface Trade {
  tradeId: string;        // Unique trade ID
  orderId: string;        // Parent order ID
  symbol: string;         // Trading pair
  venue: string;          // Execution venue
  side: Side;             // Buy or sell
  price: Decimal;         // Execution price
  quantity: Decimal;       // Fill quantity
  fee: Fee;               // Fee charged
  timestamp: number;      // Unix timestamp
  isMaker: boolean;       // True if maker, false if taker
}

Execution Quality Metrics

Use the orderbook's VWAP functions to measure execution quality:

const book = await client.orderbook('BTC-USDC');

// Expected VWAP for buying 1 BTC based on current book
const expectedVwap = book.vwapBuy(new Decimal('1'));

// Compare against actual execution
const actualPrice = order.averagePrice;
const slippage = actualPrice?.minus(expectedVwap ?? 0);
console.log(`Expected VWAP: ${expectedVwap}`);
console.log(`Actual price: ${actualPrice}`);
console.log(`Slippage: ${slippage}`);

Balance and Position Monitoring

// Aggregated balances across all venues
const balances = await client.balances();
for (const b of balances) {
  console.log(`${b.asset}: ${b.totalFree} free, ${b.totalLocked} locked`);
  for (const v of b.byVenue) {
    console.log(`  ${v.venue}: ${v.free} free, ${v.locked} locked`);
  }
}

// Single asset balance on a specific venue
const btcBalance = await client.balance('BTC', 'liquidity');
console.log(`BTC on Liquidity.io: ${btcBalance.free} free`);

FIX Protocol

The on-chain DEX supports FIX 4.4 protocol for institutional connectivity. Contact the Liquidity.io institutional desk for FIX session credentials and CompIDs.

Supported FIX Messages

MessageTagDirectionDescription
NewOrderSingleDClient -> ServerSubmit new order
ExecutionReport8Server -> ClientOrder status / fill
OrderCancelRequestFClient -> ServerCancel order
OrderCancelReject9Server -> ClientCancel rejection
MarketDataRequestVClient -> ServerSubscribe to market data
MarketDataSnapshotFullRefreshWServer -> ClientFull book snapshot
MarketDataIncrementalRefreshXServer -> ClientIncremental book update

FIX Performance

Benchmarked throughput (see On-Chain DEX for engine details):

EngineNewOrderSingle/secExecutionReport/sec
Go163K124K
C++444K804K
Rust484K232K

Configuration Reference

TOML Configuration

All SDK parameters can be set via a TOML configuration file:

[general]
log_level = "info"
timeout_ms = 30000
smart_routing = true
venue_priority = ["liquidity", "binance"]
min_improvement_bps = 5

[risk]
enabled = true
max_position_size = 100
max_order_size = 10
max_daily_loss = 5000
max_open_orders = 50
kill_switch_enabled = true

[risk.position_limits]
BTC = 10
ETH = 100

[native.liquidity]
venue_type = "dex"
api_url = "https://api.liquidity.io/v1"
ws_url = "wss://api.liquidity.io/ws"
api_key = "your-api-key"
api_secret = "your-api-secret"
network = "mainnet"
chain_id = 96369
streaming = true

[ccxt.binance]
exchange_id = "binance"
api_key = "your-binance-key"
api_secret = "your-binance-secret"
sandbox = false
rate_limit = true

Load in code:

import { Config } from '@liquidityio/trading';

const config = Config.fromObject(require('./config.toml'));
const client = new Client(config);
config = Config.from_file("config.toml")
client = Client(config)

Supported Venues

All execution algorithms and smart routing work across these venue types:

Venue TypeExamplesCapabilities
Native CLOBLiquidity.io ATS, LX DEXFull orderbook, limit/market, streaming
Native AMMLX AMMSwaps, liquidity provision, LP tracking
CCXTBinance, OKX, MEXC, Bybit, KuCoin, 100+Orderbook, orders, balances
Hummingbot GatewayAny Gateway-supported DEXSwaps, LP positions

On this page