Pre-trade checks for agents
One call before every order, in the shape an execution loop actually wants.
For a human trader, the quoted-versus-realized gap is survivable. Humans hesitate: they feel a thin market before they can describe it, they cut size on instinct, they wait for the second print. Agents do none of that. This guide wires the missing instinct in as a function call.
The shape of the check
type ExitEstimate = {
pool: string;
as_of: string;
oracle_price: number;
exit_size_usd: number;
realized_price_est: number;
exit_gap_pct: number;
exceeds_book: boolean;
lowest_depth_7d_usd: number;
days_observed: number;
market_open: boolean;
evidence_url: string;
};
async function checkBeforeOrder(pool: string, sizeUsd: number) {
const url = new URL(`https://api.crifine.app/v1/exit/${pool}`);
url.searchParams.set("size_usd", String(sizeUsd));
const response = await fetch(url, { signal: AbortSignal.timeout(800) });
return (await response.json()) as ExitEstimate;
}Deciding on the result
Three fields drive the decision, and the order matters. Check exceeds_book first: a size past the edge of the data is not a bad price, it is an unknown one, and it should never be treated as a number.
const estimate = await checkBeforeOrder("uniswap-v3-zec", 500_000);
// 1. Past the edge of the data is not a price.
if (estimate.exceeds_book) return { action: "resize", to: estimate.filled_usd };
// 2. A closed underlying market is separate risk, not a footnote.
if (!estimate.market_open) return { action: "defer", until: "session_open" };
// 3. Only now is the gap a number worth branching on.
if (estimate.exit_gap_pct < policy.maxGapPct) return { action: "hold" };
return { action: "proceed", expected: estimate.realized_price_est };Latency
Pre-trade calls target sub-second responses, and ladders are precomputed per pool so request-time work is a walk plus interpolation. Set a hard client timeout anyway and treat a timeout as a decision input, per the note above.