Intro
Most agent builders who call our scanner assume there is one fixed universe of perps behind it. There is not. Before any verdict is computed, scan_trade_calls first selects the universe it will look at, and that selection is a parameter you control. The choice of lens changes the output more than any confidence threshold does — and until now, we have not written about it.
This is part one of a three-part series on the scan lenses. It covers the default lens, oi (rank by open interest), and its companion parameter, minLiquidityUsd. It exists because a reader who does not know the universe is a choice cannot make a deliberate one.
The scanner sits on the same composite verdict engine as our per-asset endpoint, whose public record stands at 91.7% PFE win rate · 488,409+ verified calls · Merkle-anchored on Base L2. That engine does not change when the universe changes. What changes is what it is pointed at.
The problem: your agent is scanning the wrong universe
Here is the shape of the mistake I see most often. An agent builder wires up a scan-style tool, sees a ranked list of setups come back, and treats that list as the market. It is not. It is a ranked slice of some universe the tool chose for them — and in almost every scanner on the market, that universe is either turnover-weighted (24h volume) or fully undocumented.
Two things follow. First, the ranking silently biases toward whatever the tool's default sort surfaces — which, for most volume-ranked scanners, is whatever is being churned right now, not necessarily what is worth watching. Second, when the scanner returns a compelling setup on a thin book, the agent has no way of knowing the book is thin, because a per-call response does not carry a liquidity field. The agent trades a verdict it should never have been offered.
This is where the two parameters this post is about earn their existence. rankBy decides which perps are even in the running. minLiquidityUsd decides what floor of tradability they must clear to stay in. Neither touches the verdict engine. Both control the pond it fishes in.
If you separate universe-selection from scoring in your head, the rest of this post is common sense. If you do not, you will keep debugging the scoring layer for problems that live one layer up.
Open interest as the default lens (and why not volume)
scan_trade_calls defaults rankBy to oi — rank the universe by open interest on the venue you queried. This is a deliberate choice and worth explaining, because volume is the more common default in the wider tooling ecosystem and it is the wrong one for an agent's purposes.
Volume measures churn. Open interest measures commitment. A perp with high 24h volume and low open interest is telling you that a lot of paper has changed hands today; it is not telling you that anyone is holding conviction on the other side of the close. Open interest, by contrast, is capital sitting in positions right now. It is harder to fake — you cannot round-trip it with wash trades the way you can with volume — and it is a truer proxy for "this market has a real book behind it."
For an agent whose whole job is to decide whether a setup is worth entering, ranking by committed capital rather than churn is the more honest starting point. It biases the universe toward markets where the verdict, whatever it turns out to be, will be actionable.
That is why oi is the default. It is not the only sensible default one could pick — parts two and three of this series cover the activity and funding/volatility lenses, which are the right choice for different agent shapes — but if you have not thought about the question, oi is the answer you would arrive at if you had.
There is also a supporting parameter, oiBasis, which controls whether the ranking is done on notional open interest (contracts × mark price) or on contract count. Notional is what almost everyone means when they say "open interest," and it is the default. The contracts basis exists for one specific use: it is price-independent, so a sudden move in the underlying does not reshuffle the ranking. If you are running a scan on a fixed cadence and want a stable universe across price swings, contracts is worth knowing about. Most readers will never touch it.
Implementation walkthrough — one call, explained parameter by parameter
Here is the smallest useful scan_trade_calls invocation that makes the universe an explicit choice rather than a default. The floor is an example — pick your own; there is no recommended value.
import { Client } from "@modelcontextprotocol/sdk/client/index.js@^1.x";
const result = await client.callTool({
name: "scan_trade_calls",
arguments: {
rankBy: "oi",
oiBasis: "notional",
minLiquidityUsd: 50_000_000,
timeframe: "1h",
limit: 10,
confidence_threshold: 70,
},
});
Reading that call, parameter by parameter: rankBy: "oi" names the lens — rank the universe by open interest. oiBasis: "notional" says use dollar-notional, not contract count. minLiquidityUsd: 50_000_000 is the floor — an example, chosen by you, that says do not include a perp in the universe unless its OI clears fifty million. timeframe: "1h" is the decision cadence: verdicts are computed on the timeframe you ask for, not on a fixed clock. limit and confidence_threshold cap and filter the result set after the verdict runs.
The response the verdict engine returns per asset is the shape you already know from get_trade_call:
{
"call": "HOLD",
"confidence": 8,
"price": 64150.4,
"indicators": {
"funding_rate": 0.00004752,
"funding_state": "NORMAL",
"oi_change_pct": -2.56,
"volume_24h": 8357528090.33,
"trend_persistence": "MEDIUM"
},
"regime": "TRENDING_UP",
"reasoning": "Regime is trending up on the moving-average cross → bullish. Funding at +0.0048% sits in BTC's normal 14-day band: no crowd pressure either way.",
"coin": "BTC",
"timeframe": "15m",
"_algovault": { "version": "1.27.0", "tool": "get_trade_call", "exchange": "BINANCE" }
}
The scan wraps this shape in an array — one entry per asset that survived the universe selection and cleared confidence_threshold. Reading the result in an agent loop is the same one-liner you would use for a per-asset call, applied across the array:
# AlgoVault MCP example — coins=BTC confidence_threshold=70
[BTC] {
"call": "HOLD",
"confidence": 3,
"price": 64150.4,
"indicators": {
"funding_rate": 0.00004752,
"funding_state": "NORMAL",
"oi_change_pct": -2.56,
"volume_24h": 8357528090.33
},
...
}
# DRYRUN_MODE=1 — example complete
Your agent iterates the array, reads call + confidence + regime on each entry, and routes execution accordingly. That is the whole ergonomic difference between a per-asset call and a scan: the scan handed you a universe of verdicts instead of one.
The liquidity floor, and why it has to live on the server
minLiquidityUsd is the parameter I most want readers to understand, because its design is honest in a way that is easy to miss.
The floor is applied server-side, and it has to be — this is not a stylistic choice. A per-call verdict response does not carry a liquidity field. It carries price, indicators, regime, reasoning, and receipts. Nowhere in that payload is there a number a client could inspect to say "this one is too thin, drop it." A client physically cannot post-filter for liquidity, because the client is never given the data it would need to.
That means one of two things is true of any tool that offers a liquidity filter. Either it is applied on the server, where the OI/volume data actually lives, or it is not being applied at all and the parameter is decorative. We chose the first. minLiquidityUsd is enforced inside the universe-selection stage: the ranking is computed, the floor is applied to it, and only the surviving assets are handed to the verdict engine. By the time the response reaches your agent, the floor is already a fait accompli.
That is why it is a real feature and not a client-side filter dressed up in server-side clothing. It is also why you should think of it as a universe parameter, not a quality parameter. It changes what the scanner is allowed to look at. It does not change how the scanner scores what it looks at.
Pitfalls — the proxy-venue caveat, and what the floor does not do
Two honest limits, both of which matter more than they look like they should.
The OI-proxy caveat. Not every venue exposes a bulk open-interest endpoint that would let us rank an entire perp universe by OI in one query. On the venues that do, the ranking is what you would expect: notional OI, sorted, floor applied. On the venues that do not, the tool falls back to 24h volume as the ranking basis — and labels that behaviour honestly in the response metadata rather than pretending the underlying number is OI. This is worth stating plainly because it is where most vendors would quietly conflate the two and hope nobody noticed. If you are building an agent that cares about the lens, read the metadata; the tool will tell you which basis was used. The named list of proxy-venues drifts as exchanges ship OI endpoints, which is why this post talks about the behaviour and not the roster.
The floor does not touch accuracy. This is the one that most surprises agent builders. minLiquidityUsd changes the universe. It does not change the verdict, it does not change the confidence, and it does not improve win rate on the assets that survive it. A reader who expects "higher floor = better calls" has been misled by the shape of the parameter. What a higher floor gets you is tradability — the surviving assets are ones your agent can actually enter and exit without moving the book. That is a real and useful property, and it is the only one the floor is claiming.
If you want higher-conviction calls, that is what confidence_threshold is for. If you want a tradable universe, that is what minLiquidityUsd is for. Do not use one for the other.
A third, smaller point: the floor is expressed in USD, which means on the contracts-basis ranking (oiBasis: "contracts") the tool still converts to notional internally to apply it. If you set the basis to contracts and set a dollar floor, you get the price-independent ranking you asked for, with the tradability guard you asked for, both. That is the sensible combination for cadence-driven scans.
Performance — what the data shows about the universe layer
Because the floor and the lens both sit above the verdict engine, they do not shift the engine's public record — that number is what it is, and it is what the receipts on every response point to. What the universe layer does shift is the composition of the calls counted in that record.
The visible effect, when you compare a scan run with the default oi lens and a modest floor against a scan run with no floor at all: fewer results, more of them on markets that carry real book depth, and a materially lower rate of HOLDs generated on markets whose thinness was already the reason they had no coherent regime. This is the shape you would predict. The verdict engine cannot resolve a regime on a market where nothing is committed to either side, so it returns HOLD honestly. The floor keeps those markets out of the universe in the first place. You do not get better verdicts; you get fewer wasted ones.
That is the case for using the floor deliberately even at modest values. It is not the case for treating the floor as a scoring parameter.
What's Next?
Parts two and three of this series cover the activity and funding/volatility lenses respectively — they are the right choice for agents with different shapes than the OI-default is built for. For now, go make one deliberate call and see the universe you actually asked for.
- Verify the composite verdict engine's public record on the track record.
- Read the full
scan_trade_callsparameter surface in the docs. - Inspect the MCP server implementation on the GitHub repo.
- Try the free tier with no signup on Telegram.
- Read the companion piece on composite verdicts vs raw indicators.
— AlgoVault Labs
⭐ Star the repo to follow new exchanges and signals: https://github.com/AlgoVaultLabs/crypto-quant-signal-mcp



Top comments (0)