npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@senal-group/senal-sdk

v0.0.1-beta.8

Published

本文档覆盖 SDK 的所有功能模块,包含完整的代码示例与说明。

Downloads

13

Readme

Prediction Market MM SDK — Demo

本文档覆盖 SDK 的所有功能模块,包含完整的代码示例与说明。


安装

npm install @senal-group/senal-sdk

初始化客户端

ApiClient 继承自 BaseClient,同时提供 REST API 和 WebSocket 能力。
API 凭证(apiKey / apiSecret / passphrase)由平台统一分配,开始前请确认已获取。

import { ApiClient } from '@senal-group/senal-sdk';

const client = new ApiClient({
  baseUrl:    'https://api.example.com',
  wsUrl:      'wss://ws.example.com',
  apiKey:     'YOUR_API_KEY',
  apiSecret:  'YOUR_API_SECRET',
  passphrase: 'YOUR_PASSPHRASE',
  timeoutMs:  5000,
  l1Address:  '0xYourWalletAddress',  // 可选
});

模块一:账户 mm.account

查询余额

const balance = await client.mm.account.getBalance({});
console.log(`可用: ${balance.available}  锁定: ${balance.locked}`);

查询所有持仓

返回账户当前持有的所有预测市场头寸,包含盈亏、当前价格等信息。

const position = await client.mm.account.getPositions({});
console.log(`
  市场:      ${position.marketTitle}
  结果:      ${position.outcomeName}
  持仓量:    ${position.size}
  均价:      ${position.avgPrice}
  当前价:    ${position.curPrice}
  未实现PnL: ${position.cashPnl} (${position.percentPnl}%)
  已实现PnL: ${position.percentRealizedPnl}%
  可赎回:    ${position.redeemable}
`);

查询持仓总价值

const { totalValue } = await client.mm.account.getPositionsTotalValue({});
console.log(`持仓总价值: ${totalValue}`);

查询单个持仓(by tokenId)

const position = await client.mm.account.getPosition({
  tokenId: 'token-xxx',
});
console.log(`持仓量: ${position.size}  均价: ${position.avgPrice}  已实现PnL: ${position.realizedPnl}`);

模块二:市场 mm.markets

获取市场列表

支持按状态、是否接受挂单过滤,使用游标分页。

const result = await client.mm.markets.getMarkets({
  status:          'active',
  acceptingOrders: true,
  limit:           20,
});

console.log(`共 ${result.count} 个市场`);

for (const market of result.data) {
  console.log(`[${market.id}] ${market.question}`);
  console.log(`  状态: ${market.status}  最小下单量: ${market.minimumOrderSize}  tick: ${market.tickSize}`);
  for (const outcome of market.outcomes) {
    console.log(`  - ${outcome.name}  tokenId=${outcome.tokenId}  price=${outcome.price}`);
  }
}

// 翻页
if (result.next_cursor) {
  const nextPage = await client.mm.markets.getMarkets({
    cursor: result.next_cursor,
    limit:  20,
  });
}

获取单个市场详情

const market = await client.mm.markets.getMarketById({
  id: 'market-id-xxx',
});
console.log(market.question, market.outcomes);

模块三:行情 mm.market

查询订单簿

返回指定 token 的当前买卖盘深度。

const orderbook = await client.mm.market.getOrderbook({
  marketId: 'market-id-xxx',
  tokenId:  'token-xxx',
});

console.log('卖单 (asks):');
orderbook.asks.forEach(a => console.log(`  ${a.price} x ${a.size}`));

console.log('买单 (bids):');
orderbook.bids.forEach(b => console.log(`  ${b.price} x ${b.size}`));

查询最新成交价

返回指定市场下所有 outcome 的最新成交价,key 为 tokenId。

const prices = await client.mm.market.getLastTradePrices({
  marketId: 'market-id-xxx',
});
// { 'token-yes': '0.62', 'token-no': '0.38' }

查询价格历史

const history = await client.mm.market.getPriceHistory({
  outcomeId: 'token-xxx',
  interval:  '1h',   // 时间粒度
  fidelity:  100,    // 返回数据点数量上限
});

history.forEach(point => {
  console.log(`${point.timestamp}  price=${point.price}`);
});

模块四:订单 mm.order

单笔下单

const order = await client.mm.order.placeOrder({
  marketId:  'market-id-xxx',
  tokenId:   'token-xxx',
  side:      'BUY',   // 'BUY' | 'SELL'
  orderType: 'GTC',   // 'GTC' | 'FOK' | 'GTD' | 'FAK'
  price:     0.47,
  size:      100,
  postOnly:  true,    // 可选,仅挂单不吃单
});
console.log(`订单ID: ${order.id}  状态: ${order.status}`);

orderType 说明:

| 类型 | 含义 | |-------|------| | GTC | Good Till Cancelled,挂单直到手动撤销 | | FOK | Fill Or Kill,立即全部成交否则撤销 | | GTD | Good Till Date,到期自动撤销,需传 expiration | | FAK | Fill And Kill,立即成交可成交部分,剩余撤销 |

批量下单

单次最多提交 15 个订单。

const results = await client.mm.order.batchPlaceOrders({
  orders: [
    { marketId, tokenId, side: 'BUY',  orderType: 'GTC', price: 0.44, size: 50 },
    { marketId, tokenId, side: 'BUY',  orderType: 'GTC', price: 0.41, size: 40 },
    { marketId, tokenId, side: 'SELL', orderType: 'GTC', price: 0.56, size: 50 },
    { marketId, tokenId, side: 'SELL', orderType: 'GTC', price: 0.59, size: 40 },
  ],
});

results.forEach(r => {
  console.log(`订单 ${r.id}  状态: ${r.status}  成交笔数: ${r.trades.length}`);
});

查询订单列表

const { items, total, page, pageSize } = await client.mm.order.getOrders({
  marketId,
  status:   'open',  // 'open' | 'filled' | 'cancelled' | 'expired'
  page:     1,
  pageSize: 20,
});

console.log(`共 ${total} 笔,当前第 ${page} 页`);
items.forEach(o => {
  console.log(`[${o.id}] ${o.side} ${o.size}@${o.price}  已成交: ${o.filledSize}  剩余: ${o.remainingSize}`);
});

查询单笔订单

const order = await client.mm.order.getOrder({
  id: 'order-id-xxx',
});
console.log(order.status, order.filledSize);

撤销单笔订单

const result = await client.mm.order.cancelOrder({
  orderId: 'order-id-xxx',
});
console.log(result.results[0].success);

批量撤单(by orderIds)

const result = await client.mm.order.batchCancelOrders({
  orderIds: ['order-id-1', 'order-id-2', 'order-id-3'],
});
result.results.forEach(r => {
  console.log(`${r.orderId}  成功: ${r.success}  ${r.reason ?? ''}`);
});

撤销某市场全部订单(by tokenId)

const result = await client.mm.order.cancelMarketOrders({
  tokenId: 'token-xxx',
});
console.log(`撤单 ${result.results.length} 笔`);

撤销所有订单

const result = await client.mm.order.cancelAllOrders({});
console.log(`撤单 ${result.results.length} 笔`);

模块五:成交记录 mm.trade

查询作为 Maker 的历史成交,支持游标分页。

const result = await client.mm.trade.getMakerTrades({
  marketId,
  tokenId,
  limit: 20,
});

console.log(`共 ${result.count} 笔成交`);
result.data.forEach(t => {
  console.log(`[${t.id}] ${t.side} ${t.size}@${t.price}  链上状态: ${t.status}`);
});

// 翻页
if (result.next_cursor) {
  const next = await client.mm.trade.getMakerTrades({
    cursor: result.next_cursor,
    limit:  20,
  });
}

链上状态(ChainStatus):

| 状态 | 含义 | |-------------|----------------| | pending | 等待上链 | | submitted | 已提交至链上 | | confirmed | 链上已确认 | | failed | 链上执行失败 |


模块六:WebSocket 实时推送

SDK 内置 WebSocket 客户端,支持订单、持仓、行情的实时推送。

连接与认证

await client.connect();
await client.authenticate();

内置频道常量

| 常量 | 频道名 | 说明 | |--------------------------------------|-------------|--------------------| | ApiClient.CHANNAL_ORDERS | orders | 私有:订单更新 | | ApiClient.CHANNAL_POSITIONS | positions | 私有:持仓更新 | | ApiClient.CHANNAL_TRADE_PREFIX | trade | 公共:成交推送前缀 | | ApiClient.CHANNAL_ORDERBOOK_PREFIX | orderbook | 公共:盘口推送前缀 |

构建行情频道名

公共行情频道需通过 buildChannel 拼接 tokenId 生成完整频道名。

const tradeChannel     = client.buildChannel('trade',     tokenId);
const orderbookChannel = client.buildChannel('orderbook', tokenId);
// e.g. "trade:token-xxx" / "orderbook:token-xxx"

订阅 / 取消订阅

// 订阅
client.subscribe([
  ApiClient.CHANNAL_ORDERS,
  ApiClient.CHANNAL_POSITIONS,
  tradeChannel,
  orderbookChannel,
]);

// 取消订阅
client.unsubscribe([tradeChannel, orderbookChannel]);

监听消息

// 所有消息(调试用)
client.onMessage(msg => {
  console.log('raw:', msg);
});

// 订阅成功回调
client.onSubscribed(msg => {
  console.log('已订阅:', msg.channel);
});

// 取消订阅回调
client.onUnsubscribed(msg => {
  console.log('已取消:', msg.channel);
});

// 指定频道的数据更新
client.onUpdate(ApiClient.CHANNAL_ORDERS, msg => {
  console.log('订单更新:', msg.data);
});

client.onUpdate(ApiClient.CHANNAL_POSITIONS, msg => {
  console.log('持仓更新:', msg.data);
});

client.onUpdate(orderbookChannel, msg => {
  console.log('Orderbook 更新:', msg.data);
});

client.onUpdate(tradeChannel, msg => {
  console.log('成交更新:', msg.data);
});

等待单次消息(Promise 风格)

适合启动时等待初始快照,或做简单的请求-响应交互。

const msg = await client.waitOnce(
  msg => msg.channel === orderbookChannel,
  10_000, // 超时 ms,超时后 reject
);
console.log('首条 orderbook 快照:', msg.data);

关闭连接

client.close();

附录:订单状态(ExchangeOrderStatus)

| 状态 | 含义 | |--------------------|----------| | pending | 待处理 | | open | 挂单中 | | partially_filled | 部分成交 | | filled | 完全成交 | | cancelled | 已撤销 | | rejected | 已拒绝 |