Skip to main content

Algorithms API

The Algorithms API provides execution algorithms that break large orders into smaller slices to minimize market impact and achieve better average prices.

Key Features

  • Time-sliced execution: TWAP and TimePace spread orders evenly over time
  • Multi-level orders: Ladder places limit orders at multiple price levels
  • Aggressive fills: Sweep uses IOC orders for immediate execution
  • Spread trading: Two-leg execution for basis/arb trades with risk management
  • Anti-gaming: Randomization of size and timing to avoid detection
  • Limit price guardrails: Won’t execute beyond your price limit
  • TCA metrics: Arrival price, VWAP, slippage tracking
  • Full lifecycle: Start, pause, resume, cancel algorithms

Algorithm Types

AlgorithmStatusDescription
twapAvailableTime-Weighted Average Price - executes evenly over time
ladderAvailablePlaces limit orders at multiple price levels
sweepAvailableAggressive fill - hits all available liquidity with IOC orders
timepaceAvailableFixed quantity per interval, no catch-up
spreadAvailableTwo-leg spread/basis trade execution

POST /oems/algorithms/start

Start a new execution algorithm.

Request Body (JSON)

ParameterTypeRequiredDescription
algorithm_typestringYesAlgorithm type: twap, ladder, sweep, timepace, spread
symbolstringYesTrading pair (e.g., “BTC/USDC”)
sidestringYesbuy or sell
quantitynumberYesTotal quantity to execute
exchange_account_idsarrayYesList of exchange account IDs
limit_pricenumberNoWon’t execute beyond this price
paramsobjectYesAlgorithm-specific parameters (see below)

TWAP Parameters

ParameterTypeDefaultDescription
duration_secondsintrequiredTotal execution time in seconds
interval_secondsintrequiredTime between slices
aggressionstring"neutral"passive, neutral, aggressive, auto
randomize_sizebooltrue+/-20% size randomization
randomize_timingbooltrue+/-30% timing randomization
catch_up_enabledbooltrueCatch up if falling behind
max_catch_up_pctint200Max catch-up as % of interval size
Request Example
curl -X POST "http://localhost:8082/oems/algorithms/start" \
  -H "Content-Type: application/json" \
  -d '{
    "algorithm_type": "twap",
    "symbol": "BTC/USDC",
    "side": "buy",
    "quantity": 0.001,
    "exchange_account_ids": ["binance-001"],
    "params": {
      "duration_seconds": 60,
      "interval_seconds": 10,
      "aggression": "neutral"
    }
  }'
Response Example
{
  "isError": false,
  "message": "Algorithm started successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "893dc6ba-3b13-407a-a06c-41dcdd39d1ee",
    "algorithm_type": "twap",
    "symbol": "BTC/USDC",
    "side": "buy",
    "total_quantity": 0.001,
    "status": "RUNNING",
    "arrival_price": 78836.00,
    "arrival_spread_bps": 10,
    "estimated_completion": "2026-02-02T23:42:58.862514",
    "progress": {
      "filled_quantity": 0.0,
      "remaining_quantity": 0.001,
      "fill_percentage": 0.0,
      "vwap": null,
      "child_orders_filled": 0,
      "total_fees": 0.0
    },
    "state": {
      "current_interval": 1,
      "total_intervals": 6,
      "base_quantity_per_interval": 0.000166
    }
  }
}
Best Practices
  • Use passive aggression for large orders to minimize market impact
  • Enable catch_up_enabled to ensure full quantity is executed
  • Set limit_price as a safety guardrail
  • Longer durations reduce market impact but increase timing risk

Ladder Parameters

ParameterTypeDefaultDescription
num_levelsintrequiredNumber of price levels (1-20)
price_spacing_bpsnumber10Spacing between levels in basis points
size_distributionstring"equal"equal, linear, exponential
start_pricenumbermarket midStarting price for the ladder
end_pricenumber-End price (overrides spacing if set)
cancel_on_fill_pctnumber-Cancel remaining levels when X% filled
cancel_on_price_move_bpsnumber-Cancel all if mid-price moves X bps
reprice_on_move_bpsnumber-Recalculate levels if mid moves X bps
Size Distributions
DistributionBehaviorUse Case
equalSame quantity at each levelStandard ladder
linearMore quantity at better pricesFavor fills near mid-price
exponentialMuch more at best pricesAggressive near-touch accumulation
Request Example
curl -X POST "http://localhost:8082/oems/algorithms/start" \
  -H "Content-Type: application/json" \
  -d '{
    "algorithm_type": "ladder",
    "symbol": "BTC/USDT",
    "side": "buy",
    "quantity": 0.01,
    "exchange_account_ids": ["binance-sandbox-001"],
    "params": {
      "num_levels": 5,
      "price_spacing_bps": 20,
      "size_distribution": "linear",
      "cancel_on_fill_pct": 80,
      "reprice_on_move_bps": 50
    }
  }'
Response Example
{
  "isError": false,
  "message": "Algorithm started successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "algorithm_type": "ladder",
    "symbol": "BTC/USDT",
    "side": "buy",
    "total_quantity": 0.01,
    "status": "RUNNING",
    "arrival_price": 95000.00,
    "state": {
      "levels": [
        {"level_number": 1, "price": 95000.00, "quantity": 0.0033, "status": "active"},
        {"level_number": 2, "price": 94981.00, "quantity": 0.0027, "status": "active"},
        {"level_number": 3, "price": 94962.00, "quantity": 0.0020, "status": "active"},
        {"level_number": 4, "price": 94943.00, "quantity": 0.0013, "status": "active"},
        {"level_number": 5, "price": 94924.00, "quantity": 0.0007, "status": "active"}
      ],
      "total_filled": 0.0,
      "active_orders": 5,
      "initial_mid_price": 95000.00
    }
  }
}
Best Practices
  • Use linear distribution to concentrate size near market price
  • Set cancel_on_fill_pct to 70-80% to capture most fills without overfilling
  • Use reprice_on_move_bps for volatile markets to keep levels relevant
  • Keep num_levels at 3-10 for most use cases

Sweep Parameters

ParameterTypeDefaultDescription
urgencystring"aggressive"Aggression level for pricing
limit_pricenumber-Maximum price for buys, minimum for sells
use_sorbooltrueRoute across multiple venues via SOR
max_slippage_bpsnumber50Max slippage from arrival price before blocking
max_retriesint3Number of retry rounds if not fully filled
Request Example
curl -X POST "http://localhost:8082/oems/algorithms/start" \
  -H "Content-Type: application/json" \
  -d '{
    "algorithm_type": "sweep",
    "symbol": "BTC/USDT",
    "side": "buy",
    "quantity": 0.01,
    "exchange_account_ids": ["binance-sandbox-001"],
    "params": {
      "max_slippage_bps": 30,
      "max_retries": 5
    }
  }'
Response Example
{
  "isError": false,
  "message": "Algorithm started successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "algorithm_type": "sweep",
    "symbol": "BTC/USDT",
    "side": "buy",
    "total_quantity": 0.01,
    "status": "RUNNING",
    "arrival_price": 95000.00,
    "state": {
      "sweep_round": 0,
      "total_rounds": 6,
      "remaining_after_round": 0.0,
      "arrival_price": 95000.00
    }
  }
}
Best Practices
  • Sweep is the simplest algorithm - use it when you need immediate fills
  • All slices are IOC (Immediate-or-Cancel) - unfilled portions cancel immediately
  • Set max_slippage_bps to protect against adverse price movement
  • Use max_retries > 0 for illiquid markets where one pass may not fill

TimePace Parameters

ParameterTypeDefaultDescription
quantity_per_intervalnumberrequiredFixed quantity per interval
interval_secondsintrequiredSeconds between intervals
limit_pricenumber-Skip interval if price is beyond limit
aggressionstring"neutral"passive, neutral, aggressive
randomize_sizebooltrueRandomize quantity per interval
randomize_size_pctnumber10Randomization percentage
Key Difference from TWAP: TimePace has no catch-up logic. If an interval is skipped (due to limit price breach), that quantity is lost. TWAP catches up on missed quantity. Request Example
curl -X POST "http://localhost:8082/oems/algorithms/start" \
  -H "Content-Type: application/json" \
  -d '{
    "algorithm_type": "timepace",
    "symbol": "BTC/USDT",
    "side": "buy",
    "quantity": 0.01,
    "exchange_account_ids": ["binance-sandbox-001"],
    "params": {
      "quantity_per_interval": 0.002,
      "interval_seconds": 30,
      "aggression": "neutral",
      "randomize_size": true
    }
  }'
Response Example
{
  "isError": false,
  "message": "Algorithm started successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "algorithm_type": "timepace",
    "symbol": "BTC/USDT",
    "side": "buy",
    "total_quantity": 0.01,
    "status": "RUNNING",
    "arrival_price": 95000.00,
    "state": {
      "current_interval": 1,
      "intervals_completed": 0,
      "intervals_skipped": 0,
      "quantity_per_interval_actual": 0.002
    }
  }
}
Best Practices
  • Use TimePace when you want predictable, fixed-size executions
  • Set limit_price to skip intervals during adverse price moves
  • Unlike TWAP, skipped intervals do NOT accumulate - choose TimePace for strict pacing
  • Runs until total_quantity is filled or the algorithm is cancelled

Spread Parameters

ParameterTypeDefaultDescription
anchor_symbolstringrequiredPrimary leg symbol
contra_symbolstringrequiredHedge leg symbol
anchor_exchange_account_idsarrayrequiredExchange accounts for anchor leg
contra_exchange_account_idsarrayrequiredExchange accounts for contra leg
risk_quantitynumberrequiredMax unhedged exposure
lead_modestring"anchor"Which leg posts first: anchor or contra
aggressionstring"neutral"Aggression for posting leg
sweep_trigger_modestring"immediate"Hedge trigger: immediate, disabled, threshold
sweep_threshold_pctnumber0Spread % threshold for threshold mode
pause_offset_pctnumber-Pause if spread exceeds this %
reprice_increment_bpsnumber10Reprice increment in bps
spread_offset_pctnumber0Target spread offset
Sweep Trigger Modes
ModeBehavior
immediateHedge with IOC order as soon as lead leg fills
disabledHedge with limit order (passive)
thresholdUse IOC only when spread exceeds sweep_threshold_pct
Request Example (BTC spot vs perp basis trade)
curl -X POST "http://localhost:8082/oems/algorithms/start" \
  -H "Content-Type: application/json" \
  -d '{
    "algorithm_type": "spread",
    "symbol": "BTC/USDT",
    "side": "buy",
    "quantity": 0.01,
    "exchange_account_ids": ["binance-sandbox-001"],
    "params": {
      "anchor_symbol": "BTC/USDT",
      "contra_symbol": "BTC/USDT:USDT",
      "anchor_exchange_account_ids": ["binance-sandbox-001"],
      "contra_exchange_account_ids": ["bybit-001"],
      "risk_quantity": 0.005,
      "lead_mode": "anchor",
      "aggression": "neutral",
      "sweep_trigger_mode": "immediate",
      "pause_offset_pct": 2.0
    }
  }'
Response Example
{
  "isError": false,
  "message": "Algorithm started successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "d4e5f6a7-b8c9-0123-def0-234567890123",
    "algorithm_type": "spread",
    "symbol": "BTC/USDT",
    "side": "buy",
    "total_quantity": 0.01,
    "status": "RUNNING",
    "arrival_price": 95000.00,
    "state": {
      "anchor_filled": 0.0,
      "contra_filled": 0.0,
      "current_spread_pct": 0.05,
      "unhedged_quantity": 0.0,
      "is_spread_paused": false
    }
  }
}
Best Practices
  • Set risk_quantity conservatively - it limits max unhedged exposure
  • Use immediate sweep trigger for tight risk management
  • Set pause_offset_pct to stop trading when the spread widens beyond tolerance
  • The algorithm completes when BOTH legs are fully filled
  • Use different exchange accounts for each leg for cross-venue basis trades

Aggression Levels

Applies to TWAP, Ladder, TimePace, and Spread algorithms.
LevelDescriptionUse Case
passive25% into spreadMinimize market impact, patient execution
neutralMidpointBalanced approach
aggressive75% into spreadPrioritize fills over price
autoDynamic (TWAP only)Adjusts based on fill progress

GET /oems/algorithms/

Get the status and progress of an algorithm.

Path Parameters

ParameterTypeDescription
order_idstringAlgorithm order ID

Request Example

curl "http://localhost:8082/oems/algorithms/893dc6ba-3b13-407a-a06c-41dcdd39d1ee"

Response Example

{
  "isError": false,
  "message": "Success",
  "statusCode": 200,
  "data": {
    "order_id": "893dc6ba-3b13-407a-a06c-41dcdd39d1ee",
    "algorithm_type": "twap",
    "symbol": "BTC/USDC",
    "side": "buy",
    "total_quantity": 0.001,
    "status": "RUNNING",
    "arrival_price": 78836.00,
    "progress": {
      "filled_quantity": 0.0006,
      "remaining_quantity": 0.0004,
      "fill_percentage": 60.0,
      "vwap": 78842.50,
      "child_orders_filled": 3,
      "child_orders_failed": 0,
      "total_fees": 0.000045
    },
    "state": {
      "current_interval": 4,
      "total_intervals": 6,
      "behind_by": 0.0
    },
    "recent_slices": [
      {
        "slice_id": "abc123",
        "status": "filled",
        "quantity": 0.0002,
        "fill_price": 78840.00,
        "arrival_price": 78836.00,
        "slippage_bps": 0.51
      }
    ]
  }
}

POST /oems/algorithms//pause

Pause a running algorithm. Stops generating new slices but keeps open orders.

Request Example

curl -X POST "http://localhost:8082/oems/algorithms/893dc6ba-3b13-407a-a06c-41dcdd39d1ee/pause"

Response Example

{
  "isError": false,
  "message": "Algorithm paused successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "893dc6ba-3b13-407a-a06c-41dcdd39d1ee",
    "status": "PAUSED",
    "paused_at": "2026-02-02T23:45:00Z"
  }
}

POST /oems/algorithms//resume

Resume a paused algorithm.

Request Example

curl -X POST "http://localhost:8082/oems/algorithms/893dc6ba-3b13-407a-a06c-41dcdd39d1ee/resume"

Response Example

{
  "isError": false,
  "message": "Algorithm resumed successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "893dc6ba-3b13-407a-a06c-41dcdd39d1ee",
    "status": "RUNNING"
  }
}

POST /oems/algorithms//cancel

Cancel an algorithm. Cancels all open child orders.

Request Example

curl -X POST "http://localhost:8082/oems/algorithms/893dc6ba-3b13-407a-a06c-41dcdd39d1ee/cancel"

Response Example

{
  "isError": false,
  "message": "Algorithm cancelled successfully.",
  "statusCode": 200,
  "data": {
    "order_id": "893dc6ba-3b13-407a-a06c-41dcdd39d1ee",
    "status": "CANCELLED",
    "cancelled_at": "2026-02-02T23:47:00Z",
    "child_orders_cancelled": 2,
    "final_progress": {
      "filled_quantity": 0.0008,
      "fill_percentage": 80.0,
      "vwap": 78855.46,
      "total_fees": 0.000058
    }
  }
}

GET /oems/algorithms//slices

Get all child orders (slices) for an algorithm.

Request Example

curl "http://localhost:8082/oems/algorithms/893dc6ba-3b13-407a-a06c-41dcdd39d1ee/slices"

Response Example

{
  "isError": false,
  "message": "Success",
  "statusCode": 200,
  "data": {
    "order_id": "893dc6ba-3b13-407a-a06c-41dcdd39d1ee",
    "slices": [
      {
        "slice_id": "slice-001",
        "interval_number": 1,
        "status": "filled",
        "quantity": 0.0002,
        "filled_quantity": 0.0002,
        "price": 78830.00,
        "fill_price": 78832.50,
        "arrival_price": 78836.00,
        "slippage_bps": -0.44,
        "fees": 0.000015,
        "fee_currency": "BNB",
        "submitted_at": "2026-02-02T23:42:10Z",
        "filled_at": "2026-02-02T23:42:10Z",
        "venue": "binance"
      }
    ]
  }
}

GET /oems/algorithms

List all algorithms.

Query Parameters

ParameterTypeDescription
statusstringFilter by status: RUNNING, PAUSED, COMPLETED, CANCELLED, FAILED
algorithm_typestringFilter by type: twap, ladder, sweep, timepace, spread
symbolstringFilter by trading pair
sidestringFilter by buy or sell
limitintMax results (default: 50, max: 200)
offsetintPagination offset

Request Example

# List all
curl "http://localhost:8082/oems/algorithms"

# List running only
curl "http://localhost:8082/oems/algorithms?status=RUNNING"

# List ladder algorithms
curl "http://localhost:8082/oems/algorithms?algorithm_type=ladder"

GET /oems/algorithms/by-status/

List algorithms by status.

Request Example

curl "http://localhost:8082/oems/algorithms/by-status/RUNNING"
curl "http://localhost:8082/oems/algorithms/by-status/COMPLETED"

GET /oems/algorithms/by-account/

List algorithms for a specific exchange account.

Request Example

curl "http://localhost:8082/oems/algorithms/by-account/binance-001"

Algorithm Status Lifecycle

PENDING -> RUNNING -> COMPLETED
               |
            PAUSED -> RUNNING (resume)
               |
           CANCELLED
               |
            FAILED
StatusDescription
PENDINGCreated but not started
RUNNINGActively executing slices
PAUSEDTemporarily stopped by user
COMPLETEDAll quantity filled
CANCELLEDStopped by user
FAILEDError occurred

TCA Metrics (Transaction Cost Analysis)

Each algorithm tracks execution quality metrics:
MetricDescription
arrival_priceMarket mid-price when algorithm started
vwapVolume-weighted average fill price
slippage_bpsDifference between arrival and fill price (basis points)
fill_percentagePercentage of order filled
total_feesTotal trading fees incurred

Calculating Implementation Shortfall

Implementation Shortfall = (VWAP - Arrival Price) / Arrival Price * 10000 bps
Positive = paid more than arrival (for buys), negative = got better price.

Error Handling

ErrorCauseResolution
DAILY_LIMIT_EXCEEDEDOrder would exceed daily limitReduce quantity or wait until tomorrow
MIN_ORDER_SIZESlice below exchange minimumAlgorithm skips tiny slices automatically
SYMBOL_NOT_PERMITTEDAccount can’t trade this pairCheck exchange account permissions
EXCHANGE_ERRORExchange rejected orderCheck error message for details

Daily Limit Behavior

When an algorithm hits the daily trading limit:
  • Remaining slices are rejected
  • Algorithm is paused automatically
  • Check /oems/execution/daily-limit for current limit status

Choosing an Algorithm

ScenarioAlgorithmWhy
Minimize market impact over timetwapSpreads execution evenly, catches up if behind
Fixed-pace execution, no catch-uptimepacePredictable pacing, skipped intervals stay skipped
Fill entire order NOWsweepIOC execution with retry logic
Accumulate at multiple price levelsladderPosts limit orders across a price range
Basis/arb trade across venuesspreadTwo-leg execution with risk management

TWAP vs TimePace

FeatureTWAPTimePace
Catch-up on missed intervalsYesNo
Fixed end timeYes (duration-based)No (runs until filled)
Size per intervalCalculated from total/intervalsUser-specified
Use caseFill X quantity in Y timeSend Z quantity every N seconds