mcpField
D
dflow-kalshi-market-scanner

dflow-kalshi-market-scanner

github.com/dflowprotocol其他042 次安装3 周前更新
代码仓库

关于 dflow-kalshi-market-scanner

dflow-kalshi-market-scanner 是一项技能,通过 DFlow Metadata API 定义筛选并排序 Kalshi 市场的扫描方案。它涵盖快照查询和流式扫描,提供价格、成交量、价差、动量及结束时间等指标的方案。

主要功能

  1. 01命名筛选与排序方案
  2. 02价格及套利扫描
  3. 03成交量、价差和动量扫描
  4. 04REST 快照与 WebSocket 流
  5. 05市场、事件及系列查询

适用场景

  1. 01查找符合价格或价差条件的市场
  2. 02按成交量对市场排序
  3. 03实时监测价格变动
  4. 04比较同一事件中的不同结果

MCP 相关

它使用 https://pond.dflow.net/mcp 上的 DFlow docs MCP 查询 API 参数、分页方式和响应格式。扫描本身通过 REST 或 WebSocket 查询 DFlow Metadata API。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dflowprotocol/dflow-skills --skill dflow-kalshi-market-scanner

安装后在 Claude Code 中输入/dflow-kalshi-market-scanner确认已加载。

详细介绍

DFlow Kalshi Market Scanner

查找符合某项标准的 Kalshi 市场。此技能是一组命名的扫描(筛选并排序的方案),用于查询 DFlow Metadata API。

前提条件

  • DFlow docs MCP(https://pond.dflow.net/mcp)——按照仓库 README 安装。此技能提供方案;MCP 提供参考资料。通过 search_d_flow / query_docs_filesystem_d_flow 查找精确的查询参数、分页方式、响应结构,以及其他字段级信息——不要猜测。

范围

此处的所有扫描都通过 Metadata API(https://pond.dflow.net/resources/metadata-api)运行——REST 用于特定时间点的查询,WebSocket 用于连续数据流。你可以在任何地方调用两者:从命令行快速运行 curl,使用 Node/Python 脚本、cron 任务、后端服务,或代理浏览器 UI 的 Next.js 路由。

如果用户说“在我的终端里运行”,不要使用 dflow CLI——它没有发现类子命令。改为编写简短的 HTTP/WS 脚本来调用 Metadata API。

扫描器骨架

每次扫描都包含相同的四个步骤。围绕此模式构建——不要为每次扫描重新发明做法:

  1. 枚举全集——GET /api/v1/markets(扁平)或 GET /api/v1/events?withNestedMarkets=true(分组)。筛选 status=active。持续翻页直到完成(请参阅 { markets, cursor } 结构的分页注意事项)。只有当用户希望筛选出此刻可在 DFlow 上交易的市场时,才传入 isInitialized=true(请参阅注意事项)。
  2. 获取每个市场的信号。 对于盘口顶层扫描,信号已包含在市场对象中——yesBid / yesAsk / noBid / noAsk(4 位小数的概率字符串)、volume24hFp / volumeFp / openInterestFp(美元等值字符串)、closeTime(Unix 时间戳)——无需调用订单簿接口。对于动量,使用 K 线数据或 prices / trades WebSocket 通道。对于档位深度,使用 /api/v1/orderbook/by-mint/{mint}。对于近期成交记录,使用 /api/v1/trades 或 trades 通道。
  3. 计算指标。
  4. 筛选并排序。 返回排名前 N 的结果(默认 10 个;如果用户想看更多,请询问)。
轮询与流式传输

根据用户意图选择合适的模式:

  • 轮询(REST)——适用于用户需要快照的场景(“现在显示前 10 个”,“列出所有符合 X 的市场”)。如果用户希望数据保持最新,则按固定频率重新运行。
  • 流式传输(WebSocket)——适用于用户希望在事件发生时采取行动的场景(“YES+NO 低于 1 美元时提醒我”,“标记一分钟内波动超过 5% 的任何市场”,“X 成交时交易”)。订阅相关通道(prices、trades、orderbook),地址为 wss://<host>/api/v1/ws,并在每次更新时计算指标。完整的流式处理机制(重新连接、退避、订阅生命周期)请交由 dflow-kalshi-market-data 处理。

精确的端点参数、通道载荷和分页方式 → docs MCP。

可提供的扫描

每项扫描都对应一个用户问题和一个指标。将指标代入扫描器骨架即可。

优先使用基于排名的筛选条件,而非固定数值阈值。 活跃市场的 Kalshi 成交量跨度超过 5 个数量级——任何硬编码的美元下限要么形同虚设(太低),要么会排除所有结果(太高),而且还会随着平台发展而失效。当扫描需要判断“活跃”“便宜”或“波动很大”时,应根据扫描结果计算阈值(当前全集的百分位数),而不是使用这里硬编码的数值。

仅在数值具有语义含义时使用固定数值——例如套利中的 YES + NO < $1.00(这是无套利不变量,而非可调参数),或 status=active(这是字段值,而非阈值)。如果用户提供了具体数值,就使用他们给出的数值。如果用户的说法隐含了一个你并不知道的阈值(如“成交量很大”“大幅波动的市场”),请询问用户——不要猜测。

1. 套利 — YES + NO < $1

“找出 YES 和 NO 两边合计买入价低于 1 美元的市场。”

  • 指标:parseFloat(yesAsk) + parseFloat(noAsk) < 1.00。这是语义阈值——无套利不变量;保持固定。
  • 排序:价差(1 - sum)从大到小。
  • 跳过 yesAsk 或 noAsk 任一为 null 的行(该方向没有挂单卖价,因此不是真正的套利机会)。
2. 长线 YES

“价格便宜且确实有交易的 YES。”

  • 按 parseFloat(volume24hFp) 降序排列,取活跃市场范围内的最高四分位作为“确实有交易”的池子(根据扫描结果计算第 75 百分位的截断值,不要硬编码金额)。
  • 在该池子内,按 parseFloat(yesAsk) 升序排列,并返回价格最低的前 N 项。如果用户给出上限(“低于 20¢”“低于 3¢”),就用用户指定的上限;否则只排序——不要凭空设定美分上限。“便宜”不是固定数值;什么算长线,取决于用户愿意承受多少。
  • “预期回报最佳”的替代排序方式:parseFloat(volume24hFp) / parseFloat(yesAsk)——同时满足交易活跃、价格便宜。如果用户的意思不明确,询问他们想要哪种排序。
  • 没有成交量的低价市场是僵尸行情,不是长线机会。先按成交量排序,再看价格——这样才能过滤噪声。
3. 即将到期的近乎确定 YES

“YES 高于 97¢,且即将收盘——赚取 Theta。”

  • 筛选:parseFloat(yesAsk) 高于用户指定的阈值。“近乎确定”是一种说法,不是具体数值——如果用户说 97¢,就用 0.97;如果说 99¢,就用 0.99。如果用户只说“近乎确定”,没有给出数值,就询问他们想要的标准(95¢?99¢?)。不要自行设定默认截断值。
  • 排序:closeTime 升序——最先收盘的排在前面。
  • 返回前 N 项。如果用户指定了时间范围(“48 小时以内”“本周”),则按此覆盖;不要自行设定默认时间范围。
4. 动量

“过去一小时内有哪些变动?” 或 “有变动时提醒我”

  • 轮询:对每个市场调用 /api/v1/market/{ticker}/candlesticks(或 /market/by-mint/{mint}/candlesticks),使用最小间隔,并比较最新收盘价与 N 分钟前的收盘价。此方式按市场逐一查询,成本较高——先按成交量对市场范围进行预筛选(复用扫描 #6 的排序,选取成交最活跃的前 N 个市场,再计算动量)。
  • 流式:订阅 prices 频道(all: true 或指定 ticker 列表),并在内存中计算滚动百分比变化。“发生 X 时提醒我”这种场景用这种方式便宜得多;要实现“市场变动超过 N% 时交易”,也可以这样接入 dflow-kalshi-trading(将符合条件的市场交给它)。
  • 按用户指定时间范围内的绝对百分比变化(双向)或带符号的百分比变化(有方向)排序——如果用户未指定,默认 60 分钟,但不设默认百分比阈值。返回前 N 项。如果用户说“变动超过 N%”,则由用户提供 N。
5. 买卖价差最大

“低效市场——做市或避开。”

  • 指标:parseFloat(yesAsk) - parseFloat(yesBid)(NO 方向对称)。
  • 排序:价差降序。
  • 来源:市场对象;无需额外调用。
6. 成交量最高

“哪里最热闹?”

  • 指标:parseFloat(volume24hFp)(24 小时美元等值),或者对截止时间之后的 /api/v1/trades 结果求和(盘中)。若要实时数据流,订阅 trades 频道并在滚动时间窗口内聚合。
  • 排序:成交量降序。
7. 最快收盘

“Theta 倒计时。”

  • 指标:closeTime - now。
  • 排序:升序。
  • 最适合与扫描 3(“近乎确定且即将收盘”)或扫描 6(“交易活跃且即将收盘”)组合使用。
8. 按事件和系列扫描

“该事件所有结果中 YES 价格最低的选项”“互斥的选项加起来是否大于 1?”

  • 单个事件内(例如,“美联储加息 X 个基点”,每个结果对应一个选项):调用 GET /api/v1/event/{eventTicker}?withNestedMarkets=true,然后汇总嵌套市场(min(yesAsk)、Σ yesAsk 等)。事件是扫描单一赢家的自然范围。
  • 跨系列:调用 GET /api/v1/series/{seriesTicker} 及其事件,然后汇总。
  • 系列或事件没有 mutuallyExclusive 标记。 只有当各结果构成同一未来情形的完整划分(必定发生其中一个,且恰好只能发生一个)时,汇总各结果的 YES 才有意义。这需要根据事件/系列标题和合约条款作出判断,不能通过查询字段得出。如有疑问,应展示数字并向用户说明这一假设。

单项查询(N=1)

当用户已经指定一个市场时,跳过骨架查询:

  • 按交易代码:GET /api/v1/market/{ticker}(用单数 market,不是复数)。
  • 按结果铸币地址:GET /api/v1/market/by-mint/{mint}(用斜杠,不是连字符)。
  • 按事件交易代码:GET /api/v1/event/{eventTicker}?withNestedMarkets=true(用单数 event)。
  • 自由文本:GET /api/v1/search(将自然语言映射到事件/市场)。

复数形式(/markets、/events)是列表端点,使用 ?cursor=&limit= 分页。单数形式是按 ID 进行的单项查询。混淆两者会导致 404 错误。

该向用户询问什么(以及不该问什么)

查询形式——明确时自行判断,不明确时进行确认:

  1. 要执行哪种扫描(或用户用自然语言表达的意图,你可以据此映射到一种扫描)。
  2. 用户提供的阈值——原样使用。 如果用户说“> 5%”“低于 2¢”或“本周”,就使用这些数值。否则,使用上述各扫描按排名设定的默认值(如成交量前四分之一);不要自行提出固定数值阈值。如果用户的说法隐含了扫描中未定义的阈值(如“大幅波动”“成交量可观”),应询问用户,不要猜测数值。
  3. 轮询还是流式传输——如果用户的意图听起来像“现在给我看看”,就用 REST;如果听起来像“提醒我/在……时采取行动”,就用 WebSocket。
  4. Top-N(默认值为 10)。

基础设施——始终询问,绝不自行推断:

  1. DFlow API 密钥——仅用于脚本中的发现/HTTP 部分;CLI shell 调用会自行进行身份验证(参见下方“两种身份验证路径”注意事项)。用简洁、中立的问题询问:“对于扫描器/发现部分,你有 DFlow API 密钥吗?” 不要预设密钥存放在哪里——类似 “你把它放在环境变量里了吗?” 或 “DFLOW_API_KEY 已设置了吗?” 的说法,会引导用户采用他们没有要求的环境变量默认设置。应明确提供选项;不要默默回退到环境变量或开发环境。所有地方都使用同一个 DFlow 密钥——同一个 x-api-key 可解锁 Trade API 和 Metadata API,以及 REST 和 WebSocket。如果有 → 使用生产环境主机(REST:https://prediction-markets-api.dflow.net,WS:wss://prediction-markets-api.dflow.net/api/v1/ws),并在每个请求(REST 和 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/get-started/api-key 获取生产密钥。生成脚本时,应在启动时记录最终使用的主机和密钥是否存在(Using prod Metadata API/Using dev Metadata API — rate-limited),让用户无需翻阅代码即可了解当前使用的环境。

不要询问:

  • RPC、钱包、签名——此技能只读取公开元数据,不进行交易。
  • 结算铸币地址/滑点/费用——这些属于交易环节。如果用户转而想要在你展示的市场下单,请转交给 dflow-kalshi-trading。

注意事项(文档 MCP 不会主动告知的内容)

  • 最优买卖价位于市场对象上。yesBid / yesAsk / noBid / noAsk 已经在其中。不要仅仅为了获取最优价格而循环调用订单簿端点。
  • **价格和成交量是市场级的;交易则按结算通道划分。**每个已初始化的市场在 market.accounts 下都有 USDC 和 CASH 两种结算通道,各自拥有自己的 marketLedger / yesMint / noMint。扫描结果中的 yesBid / yesAsk / volume24hFp 来自共享的 Kalshi 订单簿,并不能告诉你会通过哪个结算通道交易。移交给 dflow-kalshi-trading 时,传入市场代码,由交易步骤选择结算通道(默认:USDC)。不要在扫描输出中悄悄预先选择结算通道——如果这样做了,请明确说明。
  • 订单簿只返回买单阶梯(yes_bids、no_bids)。最优 YES 卖价 的计算方式是:1 - max(no_bids keys)(价格为 p 的 NO 买单对应价格为 1-p 的 YES 卖单)。只有用户需要查看阶梯深度时,这一点才重要。
  • **两种价格刻度。**市场/订单簿价格是 4 位小数的概率字符串("0.4200")。交易价格(REST 和 trades 通道)是 0–10000 的整数,同时带有 yes_price_dollars / no_price_dollars 字符串字段。计算前先统一格式。
  • **market.title 通常是事件级而非市场级标题。**在多结果事件中(例如每位候选人对应一个市场、每个加息幅度区间对应一个市场、每支队伍获胜对应一个市场等),该事件下的每个市场都共享同一个 title——描述具体结果的文字位于 yesSubTitle(和 noSubTitle)中。如果扫描输出只打印 title,相邻行看起来会完全相同,用户无法分辨具体结果。应显示 title — yesSubTitle(如果 yesSubTitle 为 null/空字符串,则只显示 title;简单的二元市场会出现这种情况)。将市场移交给交易提示词时也一样:对于多结果事件,只显示 title 的“买入 X 的 YES”确认信息会有歧义。
  • **成交量字段——字符串、美元等值,且没有 volume24h。**市场对象包含 volume(整数,累计原始单位)、volumeFp(字符串,累计美元等值)和 volume24hFp(字符串,24 小时美元等值)。不存在 volume24h 字段。比较前始终对 *Fp 字段使用 parseFloat。openInterest / openInterestFp 的结构也相同。
  • **isInitialized 筛选条件。**短时长市场(例如 15 分钟加密货币市场)在 Kalshi 上通常已处于活跃状态,但尚未在 DFlow 上代币化。如果不使用此筛选条件,扫描会包含这些市场;使用 isInitialized=true 时,则只包含目前可在 DFlow 上交易的市场。通常应设为 true。
  • **买单/卖单为 null 的情况。**流动性差的市场,其最优买卖价字段可能为 null。所有读取这些字段的扫描都必须跳过 null 值,不能将其视为零。
  • 维护时段——Kalshi 每周四美国东部时间凌晨 3:00–5:00 离线。此时段内,最优买卖价和成交量字段可能过时或缺失;WS 更新也可能停止。如果扫描结果为空或明显异常,原因就在这里。
  • 分页结构。/markets(和 /events)返回 { markets: [...], cursor: <number> }。首次调用时省略 cursor 或传入 cursor=0,两者等效。返回的 cursor 是下一页的偏移量(= 已读取的行数);下一次调用时将其作为 ?cursor=N 传回。当 markets.length < limit 时结束(标准做法);检查 next === cursor 以确保安全虽然无妨,但并非必要。limit 上限为 255——limit=256 或更大时会返回 HTTP 400 "number too large to fit in target type"(后端使用 u8)。文档将 200 作为保守默认值;实际最大值为 255。大型扫描若跳过分页,会悄悄漏掉匹配项。
  • **WebSocket 的 all: true 会产生大量数据。**在繁忙通道(尤其是 prices)上订阅 all: true,会流式传输所有市场的每次更新。如果扫描只关注一组已知市场,优先使用代码列表;只有扫描确实要覆盖整个市场范围时才使用 all: true。
  • **“扫描后买入”应是一个交互式脚本,而不是两个独立产物。**当用户想从命令行查找市场并随后根据结果采取行动时,正确的输出应是一个脚本:扫描市场、打印排序后的列表、提示用户选择一个(或逐行确认 y/N),然后调用 dflow trade。不要编写非交互式扫描脚本,再让用户“选一个并自行运行 dflow trade”——这会迫使他们切换上下文并手动复制标识符。在 Node 中使用 readline 提示,或在 Python 中使用 input() 都可以。对于完全自动化的流程(无需逐行提示),仍应使用单个脚本,并事先明确说明“不需确认”的行为。
  • **移交给 dflow trade 时的结构。**扫描结果是市场对象,不是可直接传给 CLI 的调用参数。CLI 的 --market 标志需要的是 market.accounts[<settlementMint>].marketLedger 中的 marketLedger——不是 market.ticker,不是 yesMint / noMint,也不是顶层的 mint。除非用户指定 CASH,否则默认使用 USDC 结算通道(参见上方“价格和成交量是市场级的;交易则按结算通道划分”这一注意事项)。买入 YES 和 NO 时使用的是同一个 marketLedger——通过 --side yes|no 选择方向,而不是换一个 --market。完整的 CLI 参数结构(从结算 mint 查找 marketLedger、原子单位换算、优先费标志、“买入 N 份完整合约”的惯用写法),请参阅 dflow-kalshi-trading。不要在这里重新设计。
  • **混合接口脚本:两种认证路径,而不是一种。**此技能与 dflow-kalshi-trading 配合时,典型脚本结构是通过 Metadata API 发现市场,然后调用 dflow trade 执行交易。这两步分别独立认证:
    • 发现(Metadata API HTTP)——直接使用 fetch / curl。脚本的环境变量或配置中需要 DFlow API 密钥(参见 #5)。没有密钥 → 使用开发主机,且会受到速率限制。
    • 执行(调用 dflow trade)——使用 CLI 通过 dflow setup 保存的配置(密钥、钱包、RPC)。脚本无需为 CLI 调用传入任何内容。 当用户说“CLI 已经配置好了”时,这只涵盖了执行环节,而不包括发现环节。询问 API 密钥时,应表述为*“扫描/发现环节需要用到,你有 DFlow API 密钥吗?”,而不是“光有 CLI 不够,你还需要另一个密钥。”*两者相互独立:一个 DFlow 密钥,两个接入点。

遇到不确定的情况时

对于以上未涵盖的内容——完整参数列表、分页令牌、响应架构、WS 重新连接语义、较少见的筛选条件(体育、标签、类别、系列搜索)、K 线间隔——请查询 docs MCP(search_d_flow、query_docs_filesystem_d_flow)。不要猜测。

相关技能

当用户从发现转向行动时,请移交给:

  • dflow-kalshi-trading — 实际买入/卖出/赎回你在此处发现的市场。
  • dflow-kalshi-portfolio — 查看他们的持仓和盈亏。
  • dflow-kalshi-market-data — 在“指定名称扫描”场景之外获取通用的实时订单簿/交易/价格流(重新连接模式、完整载荷架构、游戏中实时数据)。
  • dflow-proof-kyc — 验证钱包,以便它能实际买入你展示的内容。

评论

支持 Markdown