← Back to tsb playground

merge_asof — Ordered Nearest-Key Join

pandas equivalent: pd.merge_asof(left, right, on="time")

mergeAsof is an ordered left-join that matches on the nearest key rather than an exact key. It is especially useful for time-series data — e.g., matching each trade to the most recent quote.

Key concepts

Basic example — backward (default)

import { DataFrame, mergeAsof } from "tsb";

// Each trade is matched to the most recent quote (backward asof)
const trades = DataFrame.fromColumns({
  time:  [1,  5, 10],
  price: [100, 200, 300],
});
const quotes = DataFrame.fromColumns({
  time: [2,  6],
  bid:  [98, 195],
});

const result = mergeAsof(trades, quotes, { on: "time" });
// time | price | bid
//    1 |   100 | null   ← no quote ≤ 1
//    5 |   200 |   98   ← most recent quote ≤ 5 is at time=2
//   10 |   300 |  195   ← most recent quote ≤ 10 is at time=6

Forward direction

// Match each event to the next scheduled announcement
const events = DataFrame.fromColumns({ t: [1, 3, 7], v: [10, 30, 70] });
const schedule = DataFrame.fromColumns({ t: [2, 6, 10], w: [20, 60, 100] });

const result = mergeAsof(events, schedule, {
  on: "t",
  direction: "forward",
});
// t=1 → t=2 (w=20), t=3 → t=6 (w=60), t=7 → t=10 (w=100)

Nearest direction

const result = mergeAsof(trades, quotes, {
  on: "time",
  direction: "nearest",
});
// Picks the quote with the smallest absolute time difference.

Grouping with by

// Match trades to quotes within the same ticker symbol
const trades = DataFrame.fromColumns({
  time:   [1,    2,      3,    4],
  ticker: ["AAPL","MSFT","AAPL","MSFT"],
  price:  [100,  200,    110,   210],
});
const quotes = DataFrame.fromColumns({
  time:   [1,    1,      3,    3],
  ticker: ["AAPL","MSFT","AAPL","MSFT"],
  bid:    [99,   198,    109,   208],
});

mergeAsof(trades, quotes, { on: "time", by: "ticker" });

Tolerance

// Only match if the key distance is ≤ 2
mergeAsof(left, right, { on: "t", tolerance: 2 });

Different key column names (left_on / right_on)

mergeAsof(left, right, {
  left_on: "trade_time",
  right_on: "quote_time",
});

Using index as key

mergeAsof(left, right, {
  left_index: true,
  right_on: "timestamp",
});

Options reference

OptionDefaultDescription
onShared key column name
left_on / right_onDifferent key columns per side
left_index / right_indexfalseUse index as key
byColumn(s) that must match exactly
left_by / right_byDifferent by-columns per side
direction"backward""backward", "forward", or "nearest"
tolerancenullMax numeric key distance for a match
allow_exact_matchestrueInclude exact key matches
suffixes["_x","_y"]Suffixes for overlapping column names