dflow-kalshi-market-scanner
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDFlow Kalshi Market Scanner
DFlow Kalshi 市场扫描器
Find Kalshi markets that match a criterion. This skill is a set of named scans (filter-and-rank recipes) over the DFlow Metadata API.
查找符合特定条件的Kalshi市场。本技能是基于DFlow Metadata API的一组命名扫描规则(过滤与排序方案)。
Prerequisites
前置条件
- DFlow docs MCP () — install per the repo README. This skill is the recipe; the MCP is the reference. Look up exact query params, pagination, response shapes, and anything else field-level via
https://pond.dflow.net/mcp/search_d_flow— don't guess.query_docs_filesystem_d_flow
- DFlow文档MCP()——请按照仓库README中的说明安装。本技能是执行方案,MCP是参考依据。如需查询精确的请求参数、分页规则、响应结构及其他字段级信息,请使用
https://pond.dflow.net/mcp/search_d_flow——请勿自行猜测。query_docs_filesystem_d_flow
Surface
使用场景
All scans here run against the Metadata API () — REST for point-in-time queries, WebSockets for continuous streams. You can call both from anywhere: a quick from the command line, a Node/Python script, a cron job, a backend service, or a Next.js route proxying a browser UI.
https://pond.dflow.net/build/metadata-apicurlIf the user says "run this from my terminal", don't reach for the CLI — it has no discovery subcommands. Write a short HTTP/WS script that hits the Metadata API instead.
dflow所有扫描均基于Metadata API()运行——REST接口用于时点查询,WebSocket用于持续流式推送。你可以在任意环境调用这两种接口:比如命令行中快速执行命令、Node/Python脚本、定时任务、后端服务,或是Next.js路由代理的浏览器UI。
https://pond.dflow.net/build/metadata-apicurl如果用户要求“在我的终端运行”,不要使用 CLI——它没有发现类子命令。请编写一个简短的HTTP/WS脚本直接调用Metadata API。
dflowThe scanner skeleton
扫描框架
Every scan is the same four steps. Build around this pattern — don't reinvent it per scan:
- Enumerate the universe — (flat) or
GET /api/v1/markets(grouped). Filter toGET /api/v1/events?withNestedMarkets=true. Page through until done (see the pagination gotcha for thestatus=activeshape). Pass{ markets, cursor }only if the user wants markets tradable on DFlow right now (see Gotchas).isInitialized=true - Grab the per-market signal. For top-of-book scans the signal is already on the market object — /
yesBid/yesAsk/noBid(4-decimal probability strings),noAsk/volume24hFp/volumeFp(dollar-equivalent strings),openInterestFp(unix) — no orderbook call needed. For momentum use candlesticks or thecloseTime/pricesWebSocket channels. For ladder depth usetrades. For recent prints use/api/v1/orderbook/by-mint/{mint}or the/api/v1/tradeschannel.trades - Compute the metric.
- Filter and rank. Return the top-N (default 10, ask if the user wants more).
所有扫描均遵循相同的四个步骤。请围绕该模式构建——请勿为每个扫描重新发明流程:
- 枚举全量市场——调用(扁平结构)或
GET /api/v1/markets(按事件分组)。过滤条件设置为GET /api/v1/events?withNestedMarkets=true。分页遍历直到完成(注意status=active结构的分页陷阱)。仅当用户希望获取当前可在DFlow上交易的市场时,才传入{ markets, cursor }(详见注意事项)。isInitialized=true - 获取单市场信号。对于最优报价扫描,信号已包含在市场对象中——/
yesBid/yesAsk/noBid(4位小数概率字符串)、noAsk/volume24hFp/volumeFp(美元等价金额字符串)、openInterestFp(unix时间戳)——无需调用订单簿接口。对于动量扫描,使用K线数据或closeTime/pricesWebSocket频道。对于订单簿深度,使用trades。对于最新成交记录,使用/api/v1/orderbook/by-mint/{mint}或/api/v1/trades频道。trades - 计算指标。
- 过滤与排序。返回排名前N的结果(默认10个,若用户需要更多可询问)。
Polling vs streaming
轮询 vs 流式推送
Pick the mode that fits the intent:
- Polling (REST) — right when the user wants a snapshot ("show me the top 10 right now", "list all markets with X"). Re-run on a cadence if they want it fresh.
- Streaming (WebSocket) — right when the user wants to act on an event as it happens ("alert me when YES+NO drops below $1", "flag any market that moves > 5% in a minute", "trade when X trades"). Subscribe to the relevant channel (,
prices,trades) atorderbookand compute the metric on each update. For the full streaming plumbing (reconnection, backoff, subscription lifecycle), hand off towss://<host>/api/v1/ws.dflow-kalshi-market-data
Exact endpoint params, channel payloads, and pagination → docs MCP.
根据用户意图选择合适的模式:
- 轮询(REST)——适用于用户需要即时快照的场景(“现在给我显示排名前10的市场”“列出所有符合X条件的市场”)。若用户需要实时更新,可按一定频率重新执行。
- 流式推送(WebSocket)——适用于用户需要在事件发生时即时响应的场景(“当YES+NO价格低于1美元时提醒我”“标记任何1分钟内波动超过5%的市场”“当X成交时执行交易”)。在订阅相关频道(
wss://<host>/api/v1/ws、prices、trades),并在每次更新时计算指标。如需完整的流式处理机制(重连、退避、订阅生命周期),请移交至orderbook处理。dflow-kalshi-market-data
精确的接口参数、频道负载及分页规则请参考文档MCP。
Scans to offer
可提供的扫描类型
Each scan = a user question + a metric. Plug the metric into the skeleton.
Prefer rank-based filters over fixed numeric thresholds. Kalshi volume alone spans 5+ orders of magnitude across active markets — any hardcoded dollar floor is either a pass-through (too low) or excludes everything (too high), and it drifts as the platform grows. When a scan needs "busy" or "cheap" or "moved a lot," compute the cutoff from the scan result (percentile of the current universe), not from a number baked in here.
Only use a fixed number when it's semantic — e.g. for arbitrage (that's the no-arb invariant, not a tunable), or (a field value, not a threshold). If the user supplies a specific number, use theirs. If the user's phrasing implies a threshold you don't have ("serious volume", "big movers"), ask them — don't guess.
YES + NO < $1.00status=active每种扫描对应一个用户问题及一个指标。将指标代入上述框架即可。
优先使用基于排名的过滤,而非固定数值阈值。 Kalshi各活跃市场的交易量跨度可达5个数量级以上——任何硬编码的金额下限要么过于宽松(几乎无过滤效果),要么过于严苛(排除所有市场),且会随着平台发展逐渐失效。当扫描需要“活跃”“低价”“大幅波动”等条件时,请根据扫描结果计算截断值(当前全量市场的百分位数),而非使用硬编码数值。
仅当阈值具有语义明确性时才使用固定数值——例如套利场景中的(这是无套利不变量,而非可调参数),或(字段值,而非阈值)。若用户提供具体数值,则使用用户指定的值。若用户表述隐含未定义的阈值(“大额交易量”“大幅波动”),请询问用户——请勿自行猜测。
YES + NO < $1.00status=active1. Arbitrage — YES + NO < $1
YES + NO < $11. 套利——YES + NO < $1
YES + NO < $1"Find markets where I can buy both sides for under a dollar."
- Metric: . Semantic threshold — the no-arb invariant; keep this one fixed.
parseFloat(yesAsk) + parseFloat(noAsk) < 1.00 - Rank: largest gap () descending.
1 - sum - Skip rows where either or
yesAskis null (no resting ask on that side — not a real arb).noAsk
“查找可以低于1美元价格同时买入双边合约的市场。”
- 指标:。这是语义明确的阈值——无套利不变量,请保持固定。
parseFloat(yesAsk) + parseFloat(noAsk) < 1.00 - 排序:按(价差)降序排列。
1 - sum - 跳过或
yesAsk为null的行(对应单边无挂单报价——不属于真正的套利机会)。noAsk
2. Long-shot YES
2. 低价冷门YES合约
"Cheap YES that's actually trading."
- Rank by descending, take the top quartile of the active universe as the "actually trading" pool (compute the 75th-percentile cutoff from the scan, don't hardcode a dollar figure).
parseFloat(volume24hFp) - Within that pool, sort by ascending and return the bottom-N cheapest. If the user supplies a cap ("under 20¢", "under 3¢") use theirs; otherwise rank-only — don't invent a cents ceiling. "Cheap" isn't a fixed number; what counts as a long-shot depends on how much the user is willing to tolerate.
parseFloat(yesAsk) - Alternate rank for "best expected payoff": — busy and cheap at once. Ask the user which they want if ambiguous.
parseFloat(volume24hFp) / parseFloat(yesAsk) - A cheap market with no volume is a zombie ticker, not a long-shot. Volume-rank first, then look at price — that's the order that filters noise.
“有交易量的低价YES合约。”
- 先按降序排列,选取活跃市场的前四分之一作为“有实际交易”的池(根据扫描结果计算75百分位数截断值,请勿硬编码金额)。
parseFloat(volume24hFp) - 在该池中,按升序排列,返回排名后N的最低价合约。若用户提供上限(“低于20美分”“低于3美分”)则使用该值;否则仅按排名筛选——请勿自行设定价格上限。“低价”并非固定数值,冷门机会的定义取决于用户的风险承受能力。
parseFloat(yesAsk) - 另一种排序方式为“最佳预期收益”:——兼顾活跃度与低价。若用户表述模糊,请询问用户偏好哪种排序方式。
parseFloat(volume24hFp) / parseFloat(yesAsk) - 无交易量的低价市场属于僵尸标的,而非冷门机会。应先按交易量排序,再筛选价格——此顺序可过滤无效噪声。
3. Near-certain short-dated YES
3. 短期大概率YES合约
"YES above 97¢ closing soon — grind the theta."
- Filter: above a user-supplied threshold. "Near-certain" is a phrase, not a number — if the user says 97¢, use 0.97; if they say 99¢, use 0.99. If they just say "near-certain" with no number, ask them what bar they want (95¢? 99¢?). Don't invent a default cutoff.
parseFloat(yesAsk) - Rank: ascending — soonest-to-close first.
closeTime - Return top-N. If the user specifies a window ("under 48h", "this week"), apply that as an override; don't invent a default window.
“价格高于97美分且即将到期的YES合约——赚取时间价值。”
- 过滤条件:高于用户指定的阈值。“大概率”是表述而非固定数值——若用户说97美分,则使用0.97;若用户说99美分,则使用0.99。若用户仅说“大概率”未提供数值,请询问用户阈值(95美分?99美分?)。请勿自行设定默认阈值。
parseFloat(yesAsk) - 排序:按升序排列——到期时间越靠前排名越前。
closeTime - 返回排名前N的结果。若用户指定时间窗口(“48小时内”“本周内”),则应用该过滤条件;请勿自行设定默认窗口。
4. Momentum
4. 动量扫描
"What moved in the last hour?" or "Alert me when something moves"
- Polling: (or
/api/v1/market/{ticker}/candlesticks) per market at the smallest interval, compare latest close vs the close N minutes ago. Per-market and expensive — pre-filter the universe to top-of-volume first (re-use scan #6's ranking, take top-N busy markets, compute momentum on those)./market/by-mint/{mint}/candlesticks - Streaming: subscribe to the channel (
pricesor a ticker list) and compute rolling pct change in memory. Much cheaper for the "alert when X happens" variant, and this is how you'd wire "trade when a market moves > N%" (hand the matching market toall: true).dflow-kalshi-trading - Rank by absolute pct change (two-sided) or signed (directional) over a user-supplied window — default to 60 minutes if they don't specify, but no default pct threshold. Return top-N. If the user says "moved > N%" they supply N.
“过去一小时哪些市场波动了?” 或 “当市场波动时提醒我”
- 轮询模式:为每个市场调用(或
/api/v1/market/{ticker}/candlesticks)获取最小时间间隔的数据,比较最新收盘价与N分钟前的收盘价。此方式针对单市场且开销较高——应先按交易量筛选全量市场(复用扫描#6的排序结果,选取前N个活跃市场),再计算动量。/market/by-mint/{mint}/candlesticks - 流式推送模式:订阅频道(
prices或指定标的列表),在内存中计算滚动百分比变化。此方式更适合“当X发生时提醒我”的场景,也可用于实现“当市场波动超过N%时执行交易”(将匹配的市场移交至all: true)。dflow-kalshi-trading - 排序:按绝对百分比变化(双向)或带符号百分比变化(单向)排序,时间窗口由用户指定——若用户未指定则默认60分钟,但不设定默认波动阈值。返回排名前N的结果。若用户说“波动超过N%”,则使用用户指定的N值。
5. Widest bid-ask spreads
5. 买卖价差最大的市场
"Inefficient markets — market-make or avoid."
- Metric: (NO side is symmetric).
parseFloat(yesAsk) - parseFloat(yesBid) - Rank: spread descending.
- Source: market object; no extra calls.
“低效市场——做市或避开。”
- 指标:(NO侧逻辑对称)。
parseFloat(yesAsk) - parseFloat(yesBid) - 排序:按价差降序排列。
- 数据来源:市场对象;无需额外调用接口。
6. Highest volume
6. 交易量最高的市场
"Where's the action?"
- Metric: (24h dollar-equivalent) or sum over
parseFloat(volume24hFp)since a cutoff (intraday). For a live feed, subscribe to the/api/v1/tradeschannel and aggregate in a rolling window.trades - Rank: volume descending.
“交易最活跃的市场在哪里?”
- 指标:(24小时美元等价金额)或截止某时间点
parseFloat(volume24hFp)的累计交易量(日内)。如需实时推送,订阅/api/v1/trades频道并按滚动窗口聚合数据。trades - 排序:按交易量降序排列。
7. Closing soonest
7. 即将到期的市场
"Theta clock."
- Metric: .
closeTime - now - Rank: ascending.
- Most useful stacked with scan 3 ("near-certain AND closing soon") or scan 6 ("busy AND closing soon").
“时间价值倒计时。”
- 指标:。
closeTime - now - 排序:按升序排列。
- 最适合与扫描3(“大概率且即将到期”)或扫描6(“活跃且即将到期”)组合使用。
8. Event- and series-level scans
8. 事件与系列级扫描
"Cheapest YES across all outcomes in this event", "do mutually-exclusive buckets sum > 1?"
- Within one event (e.g. "Fed raises rates by X bps" with a bucket per outcome): pull , then reduce across the nested markets (
GET /api/v1/event/{eventTicker}?withNestedMarkets=true,min(yesAsk), etc.). Events are the natural scope for single-winner scans.Σ yesAsk - Across a series: pull plus its events, then roll up.
GET /api/v1/series/{seriesTicker} - There is no flag on series or events. Summing YES across outcomes only makes sense when the outcomes are a partition of one future (one must happen, exactly one can happen). That's a judgment from the event/series title and contract terms — not a field lookup. When in doubt, surface the numbers and flag the assumption to the user.
mutuallyExclusive
“该事件所有结果中最便宜的YES合约”“互斥标的总和是否超过1?”
- 单事件内(例如“美联储加息X基点”,每个结果对应一个标的):调用获取数据,然后对嵌套的市场进行聚合计算(
GET /api/v1/event/{eventTicker}?withNestedMarkets=true、min(yesAsk)等)。事件是单赢家扫描的天然范围。Σ yesAsk - 跨系列:调用获取系列及其包含的事件,然后进行汇总计算。
GET /api/v1/series/{seriesTicker} - 系列或事件没有标记。对所有结果的YES价格求和仅在结果构成单一未来的分区时才有意义(必有且仅有一个结果发生)。这需要根据事件/系列标题及合约条款判断——而非通过字段查询。若存在疑问,请展示数据并向用户说明假设前提。
mutuallyExclusive
Point lookups (N=1)
单点查询(N=1)
When the user already has one market in mind, skip the skeleton:
- By ticker: (singular
GET /api/v1/market/{ticker}, not plural).market - By outcome mint: (slash, not hyphen).
GET /api/v1/market/by-mint/{mint} - By event ticker: (singular
GET /api/v1/event/{eventTicker}?withNestedMarkets=true).event - Free-text: (natural-language to events/markets).
GET /api/v1/search
The plural forms (, ) are the list endpoints and take for pagination. The singular forms are point lookups by id. Mixing them up gets you 404s.
/markets/events?cursor=&limit=当用户已明确指定某一市场时,跳过上述框架:
- 通过标的代码:(单数
GET /api/v1/market/{ticker},非复数)。market - 通过结果mint地址:(使用斜杠,而非连字符)。
GET /api/v1/market/by-mint/{mint} - 通过事件代码:(单数
GET /api/v1/event/{eventTicker}?withNestedMarkets=true)。event - 自由文本搜索:(自然语言搜索事件/市场)。
GET /api/v1/search
复数形式(、)是列表接口,需传入进行分页。单数形式是按ID的单点查询。混用两种形式会导致404错误。
/markets/events?cursor=&limit=What to ASK the user (and what NOT to ask)
需要询问用户的内容(及无需询问的内容)
Query shape — infer if unambiguous, confirm if not:
- Which scan (or a plain-English intent you can map to one).
- Thresholds the user supplies — use theirs verbatim. If they say "> 5%" or "under 2¢" or "this week", use those numbers. Otherwise, use the rank-based defaults from each scan above (top quartile by volume, etc.); do not propose a fixed numeric threshold of your own. If the user's phrasing implies a threshold the scan doesn't define ("big movers", "serious volume"), ask them — don't guess a number.
- Polling vs streaming — if the intent sounds like "show me now" go REST; if it sounds like "alert me / react when" go WebSocket.
- Top-N (default 10).
Infra — always ask, never infer:
- DFlow API key — for the discovery / HTTP portion of the script only; CLI shell-outs authenticate themselves (see the "two auth paths" gotcha below). Ask with a clean, neutral question: "For the scanner / discovery side, do you have a DFlow API key?" Don't presuppose where the key lives — phrasings like "do you have it in env?" or "is set?" nudge the user toward env-var defaults they didn't ask for. Surface the choice; don't silently fall back to env or to dev. It's one DFlow key everywhere — same
DFLOW_API_KEYunlocks the Trade API and the Metadata API, REST and WebSocket. If yes → prod hosts (x-api-keyREST,https://prediction-markets-api.dflow.netWS) withwss://prediction-markets-api.dflow.net/api/v1/wson every request (REST and the WS upgrade). If no → dev hosts (x-api-key,https://dev-prediction-markets-api.dflow.net), rate-limited; point them atwss://dev-prediction-markets-api.dflow.net/api/v1/wsfor a prod key. When you generate a script, log the resolved host + key-presence at startup (https://pond.dflow.net/build/api-key/Using prod Metadata API) so the user can see which rails they're on without spelunking through code.Using dev Metadata API — rate-limited
Do NOT ask about:
- RPC, wallet, signing — this skill is read-only public metadata. No transactions.
- Settlement mint / slippage / fees — those are trade-side concerns. If the user pivots to placing an order on a market you surfaced, hand off to .
dflow-kalshi-trading
查询结构——表述明确则自行推断,表述模糊则确认:
- 扫描类型(或用户用自然语言表述的意图,你可映射到对应的扫描类型)。
- 用户提供的阈值——严格使用用户指定的值。若用户说“>5%”“低于2美分”“本周内”,则使用这些数值。否则,使用上述各扫描中基于排名的默认规则(如交易量前四分之一等);请勿自行提议固定数值阈值。若用户表述隐含扫描未定义的阈值(“大幅波动”“大额交易量”),请询问用户——请勿自行猜测数值。
- 轮询 vs 流式推送——若用户意图是“现在给我看”则使用REST;若用户意图是“提醒我/当发生时响应”则使用WebSocket。
- 返回数量Top-N(默认10个)。
基础设施——务必询问,绝不自行推断:
- DFlow API密钥——仅用于脚本的发现/HTTP部分;CLI调用会自行认证(详见下文“两种认证路径”的注意事项)。请用清晰中立的方式询问:“用于扫描/发现环节,你是否拥有DFlow API密钥?” 不要预设密钥的存储位置——类似“你是否已将其放入环境变量?”或“是否已设置?”的表述会引导用户使用未要求的环境变量默认值。请将选择权交给用户;不要静默回退到环境变量或开发环境。所有场景使用同一个DFlow密钥——相同的
DFLOW_API_KEY可同时解锁Trade API和Metadata API,包括REST和WebSocket。若用户有密钥→使用生产环境地址(REST:x-api-key,WS:https://prediction-markets-api.dflow.net),并在每个请求(REST和WebSocket升级)中携带wss://prediction-markets-api.dflow.net/api/v1/ws。若用户没有密钥→使用开发环境地址(x-api-key,https://dev-prediction-markets-api.dflow.net),存在速率限制;请引导用户访问wss://dev-prediction-markets-api.dflow.net/api/v1/ws获取生产环境密钥。当生成脚本时,请在启动时记录已解析的地址及密钥状态(https://pond.dflow.net/build/api-key/Using prod Metadata API),以便用户无需查看代码即可确认当前使用的环境。Using dev Metadata API — rate-limited
无需询问的内容:
- RPC、钱包、签名——本技能仅处理只读的公开元数据。无需涉及交易。
- 结算mint地址/滑点/手续费——这些属于交易环节的问题。若用户转向为你发现的市场下单,请移交至处理。
dflow-kalshi-trading
Gotchas (the docs MCP won't volunteer these)
注意事项(文档MCP不会主动提及)
-
Top-of-book lives on the market object./
yesBid/yesAsk/noBidare already there. Don't loop the orderbook endpoint just to get best prices.noAsk -
Prices and volume are market-wide; trading is rail-scoped. Every initialized market has both a USDC rail and a CASH rail under, each with its own
market.accounts/marketLedger/yesMint. The scan'snoMint/yesBid/yesAskcome off the shared Kalshi orderbook and don't tell you which rail you'll trade on. When handing off tovolume24hFp, pass the market ticker and let the trading step pick the rail (default: USDC). Don't silently pre-select a rail in the scan output — state it if you do.dflow-kalshi-trading -
The orderbook returns only bid ladders (,
yes_bids). Best YES ask is derived:no_bids(a NO bid at1 - max(no_bids keys)is a YES offer atp). Only matters if the user wants ladder depth.1-p -
Two price scales. Market/orderbook prices are 4-decimal probability strings (). Trade prices (REST and
"0.4200"channel) are integer 0–10000, withtrades/yes_price_dollarsstring fields alongside. Normalize before you compute.no_price_dollars -
is often event-level, not market-specific. On multi-outcome events (a market per candidate, per rate-hike bucket, per game winner, etc.), every market under that event shares the same
market.title— the outcome-specific wording lives intitle(andyesSubTitle). If your scan output only printsnoSubTitle, adjacent rows look identical and the user can't tell which outcome is which. Rendertitle(or fall back to justtitle — yesSubTitlewhentitleis null / empty, which happens on simple binary markets). Same applies when you hand a market off to a trade prompt: a "buy YES on X" confirmation that just showsyesSubTitleis ambiguous for multi-outcome events.title -
Volume fields — string, dollar-equivalent, and no. The market object has
volume24h(int, cumulative raw units),volume(string, cumulative dollar-equivalent), andvolumeFp(string, 24h dollar-equivalent). There is novolume24hFpfield. Alwaysvolume24htheparseFloatfields before comparing. Same shape on*Fp/openInterest.openInterestFp -
filter. Short-duration markets (15-min crypto, etc.) are often active on Kalshi but not yet tokenized on DFlow. Without the filter, scans include them; with
isInitialized, only markets tradable on DFlow right now. Usually you wantisInitialized=true.true -
Null bids/asks. Illiquid markets have null top-of-book fields. Every scan that reads them must skip nulls, not treat them as zero.
-
Maintenance window — Kalshi is offline Thursdays 3:00–5:00 AM ET. Top-of-book and volume fields can go stale or missing during the window; WS updates can go quiet. If scans look empty or weirdly wrong during the window, that's why.
-
Pagination shape.(and
/markets) return/events. First call: omit{ markets: [...], cursor: <number> }or passcursor— equivalent. The returnedcursor=0is the offset of the next page (= running row count); pass it back ascursoron the next call. Terminate when?cursor=N(canonical); amarkets.length < limitsanity check is harmless paranoia but not necessary.next === cursorcaps at 255 —limit+ returns HTTP 400limit=256(it's a"number too large to fit in target type"on the backend). Docs useu8as a conservative default;200is the true ceiling. Large scans that skip pagination silently drop matches.255 -
WebSocketis firehose-y. Subscribing
all: trueon busy channels (esp.all: true) streams every update across every market. Prefer ticker lists when the scan only cares about a known set; usepricesonly when the scan really is universe-wide.all: true -
"Scan then buy" = one interactive script, not two separate artifacts. When the user wants to find markets and then act on the result from the command line, the right output is a single script that scans, prints the ranked list, prompts the user to pick one (or confirm y/N per row), and then shells out to. Don't write a non-interactive scan script and tell the user to "pick one and run
dflow tradeyourself" — that forces them to context-switch and copy identifiers around. Adflow tradeprompt in Node /readlinein Python is fine. For full-auto flows (no per-row prompt), still keep it one script and make the "no confirmation" behavior explicit up front.input() -
Handoff shape to. The scan result is a market object, not a CLI-ready invocation. The CLI's
dflow tradeflag takes the--marketfrommarketLedger— notmarket.accounts[<settlementMint>].marketLedger, notmarket.ticker/yesMint, not any top-level mint. Default to the USDC rail unless the user says CASH (see the "prices and volume are market-wide; trading is rail-scoped" gotcha above). The samenoMintis used for both YES and NO buys — side selection ismarketLedger, not a different--side yes|no. For the full CLI argument shape (settlement-mint →--marketlookup, atomic-unit conversion, priority-fee flags, the "buy N whole contracts" idiom), seemarketLedger. Don't reinvent it here.dflow-kalshi-trading -
Mixed-surface scripts: two auth paths, not one. The natural shape of this skill plusis a script that does discovery over the Metadata API, then shells out to
dflow-kalshi-tradingfor execution. The two legs authenticate independently:dflow trade- Discovery (Metadata API HTTP) — plain /
fetch. Needs a DFlow API key in the script's env or config (see #5). No key → dev host, rate-limited.curl - Execution (shell-out) — uses whatever the CLI has stored from
dflow trade(key, wallet, RPC). The script plumbs nothing for CLI invocations.dflow setup
When a user says "the CLI is already set up," that's the execution leg covered — not the discovery leg. Frame the API-key ask as "for the scanner/discovery side, do you have a DFlow API key?" — not as "the CLI isn't enough, you need another key." The two are independent: one DFlow key, two plumbing sites. - Discovery (Metadata API HTTP) — plain
-
最优报价已包含在市场对象中。/
yesBid/yesAsk/noBid字段已存在于市场对象中。请勿循环调用订单簿接口仅为获取最优价格。noAsk -
价格和交易量是市场级的;交易是渠道特定的。每个已初始化的市场在下同时拥有USDC渠道和CASH渠道,每个渠道都有自己的
market.accounts/marketLedger/yesMint。扫描使用的noMint/yesBid/yesAsk来自Kalshi共享订单簿,无法告诉你将使用哪个渠道进行交易。当移交至volume24hFp时,只需传入市场代码,由交易环节选择渠道(默认:USDC)。请勿在扫描结果中静默预选渠道——若必须选择,请明确说明。dflow-kalshi-trading -
订单簿仅返回买单队列(、
yes_bids)。最优YES卖价需推导得出:no_bids(价格为1 - max(no_bids keys)的NO买单等价于价格为p的YES卖单)。仅当用户需要订单簿深度时才需关注此点。1-p -
两种价格刻度。市场/订单簿价格是4位小数的概率字符串()。交易价格(REST和
"0.4200"频道)是0–10000的整数,同时包含trades/yes_price_dollars字符串字段。计算前请先归一化。no_price_dollars -
通常是事件级的,而非市场特定的。在多结果事件中(每个候选人、每个加息区间、每个游戏胜者对应一个市场),该事件下的所有市场共享相同的
market.title——结果特定的描述位于title(及yesSubTitle)中。若扫描输出仅显示noSubTitle,相邻行看起来会完全相同,用户无法区分对应的结果。请显示title(当title — yesSubTitle为null/空时,仅显示yesSubTitle,适用于简单二元市场)。当你将市场移交至交易提示时同样适用:仅显示title的“买入X的YES合约”确认信息在多结果事件中会存在歧义。title -
交易量字段——字符串类型、美元等价金额、无字段。市场对象包含
volume24h(整数,累计原始单位)、volume(字符串,累计美元等价金额)和**volumeFp**(字符串,24小时美元等价金额)。不存在volume24hFp字段。比较前请务必对volume24h字段执行*Fp转换。parseFloat/openInterest字段结构相同。openInterestFp -
过滤器。短期市场(如15分钟加密货币市场)通常在Kalshi上已活跃,但尚未在DFlow上完成代币化。不使用该过滤器时,扫描会包含这些市场;使用
isInitialized时,仅包含当前可在DFlow上交易的市场。通常应设置为isInitialized=true。true -
空报价。流动性不足的市场的最优报价字段可能为null。所有读取这些字段的扫描必须跳过空值,而非将其视为0。
-
维护窗口——Kalshi在美国东部时间每周四3:00–5:00处于离线状态。维护窗口期间,最优报价和交易量字段可能过期或缺失;WebSocket推送可能中断。若扫描结果为空或异常,且时间处于维护窗口内,原因即在于此。
-
分页结构。(及
/markets)返回/events。首次调用:可省略{ markets: [...], cursor: <number> }或传入cursor——两者等价。返回的cursor=0是下一页的偏移量(=已返回的行数);在下一次调用时传入cursor。当?cursor=N时停止遍历(标准方式);额外检查markets.length < limit是安全的冗余操作,但非必需。next === cursor上限为255——limit及以上会返回HTTP 400错误limit=256(后端使用"number too large to fit in target type"类型)。文档使用u8作为保守默认值;200是真正的上限。未处理分页的大型扫描会静默丢失匹配结果。255 -
WebSocket是全量推送。在繁忙频道(尤其是
all: true)订阅prices会推送所有市场的每一次更新。当扫描仅关注已知标的集合时,优先使用标的列表;仅当扫描确实需要覆盖全量市场时,才使用all: true。all: true -
“扫描后买入”=一个交互式脚本,而非两个独立文件。当用户希望从命令行查找市场并对结果执行操作时,正确的输出是一个单一脚本:先执行扫描、打印排名列表、提示用户选择一个标的(或按行确认y/N),然后调用。请勿编写非交互式扫描脚本并让用户“自行选择标的并运行
dflow trade”——这会迫使用户切换上下文并复制标识符。在Node中使用dflow trade提示,或在Python中使用readline即可。对于全自动流程(无需逐行确认),仍需保持单一脚本,并提前明确说明“无确认”行为。input() -
移交至的格式。扫描结果是市场对象,而非CLI可直接调用的格式。CLI的
dflow trade参数需要传入--market——而非market.accounts[<settlementMint>].marketLedger、market.ticker/yesMint或任何顶级mint地址。默认使用USDC渠道,除非用户指定CASH(详见上文“价格和交易量是市场级的;交易是渠道特定的”注意事项)。同一个noMint可用于买入YES和NO合约——方向选择通过marketLedger参数,而非不同的--side yes|no参数。完整的CLI参数格式(结算mint地址→--market查找、原子单位转换、优先手续费标记、“买入N份完整合约”用法)请参考marketLedger。请勿在此处重新实现。dflow-kalshi-trading -
混合场景脚本:两种认证路径,而非一种。本技能与的自然组合是一个脚本:先通过Metadata API执行发现,然后调用
dflow-kalshi-trading执行交易。两个环节的认证相互独立:dflow trade- 发现环节(Metadata API HTTP)——使用普通/
fetch。需要在脚本的环境变量或配置中设置DFlow API密钥(详见第5点)。无密钥→使用开发环境地址,存在速率限制。curl - 执行环节(调用)——使用CLI通过
dflow trade存储的认证信息(密钥、钱包、RPC)。脚本无需为CLI调用传递任何认证信息。dflow setup
当用户说“CLI已设置完成”时,仅覆盖了执行环节——而非发现环节。请将API密钥询问表述为*“用于扫描/发现环节,你是否拥有DFlow API密钥?”——而非“CLI不够,你还需要另一个密钥”*。两者相互独立:同一个DFlow密钥,用于两个不同的环节。 - 发现环节(Metadata API HTTP)——使用普通
When something doesn't fit
未覆盖场景的处理
For anything not covered above — full parameter lists, pagination tokens, response schemas, WS reconnection semantics, rare filters (sports, tags, categories, series search), candlestick intervals — query the docs MCP (, ). Don't guess.
search_d_flowquery_docs_filesystem_d_flow对于上述未覆盖的内容——完整参数列表、分页令牌、响应 schema、WebSocket重连逻辑、罕见过滤器(体育、标签、分类、系列搜索)、K线时间间隔等——请查询文档MCP(、)。请勿自行猜测。
search_d_flowquery_docs_filesystem_d_flowSibling skills
关联技能
When the user pivots from discovery to action, hand off:
- — actually buy/sell/redeem a market you found here.
dflow-kalshi-trading - — view their positions and P&L.
dflow-kalshi-portfolio - — general live orderbook / trade / price streaming outside the "named scan" shape (reconnection patterns, full payload schemas, in-game live data).
dflow-kalshi-market-data - — verify a wallet so it can actually buy what you surfaced.
dflow-proof-kyc
当用户从发现转向操作时,移交至以下技能:
- ——实际买入/卖出/赎回你在此发现的市场。
dflow-kalshi-trading - ——查看用户自身的持仓及盈亏。
dflow-kalshi-portfolio - ——处理超出“命名扫描”范围的通用实时订单簿/交易/价格推送(重连模式、完整负载schema、实时游戏数据)。
dflow-kalshi-market-data - ——验证钱包以便用户能够买入你发现的标的。",
dflow-proof-kyc