@decibeltrade/sdk

中文文档
0.8.2发布于 2026/09/18TypeScriptES Module构建来源已验证近 30 天下载 5849

用于与Decibel互动的TypeScript SDK,这是一款由Aptos所建的全链上交易引擎.

中文使用文档
文档目录59 节
  1. 概览
  2. 安装
  3. 快速启动
  4. 读取: 市场和账户数据
  5. 写入: 提交交易
  6. 文档
  7. 开始
  8. 读取 SDK
  9. 写入 SDK
  10. 高级
  11. 配置
  12. 自定义配置
  13. 何时使用
  14. 读取操作 API
  15. 十进制读取器
  16. 市场
  17. 运动奖
  18. 账户概览
  19. 用户费
  20. 用户位置
  21. 用户命令
  22. 市场数据
  23. 市场背景
  24. 用户贸易历史
  25. 用户供资历史
  26. 用户子账户
  27. 断层
  28. 第一次贸易
  29. 写入操作 API
  30. 十进制WriteDex
  31. 公开写作方法
  32. 交易账户和抵押品
  33. 贸易代表团和建筑商收费
  34. 市场配置
  35. 订单管理
  36. 点点交易
  37. 职位管理
  38. 过失和竞选奖励
  39. 会话账户
  40. 处理错误
  41. 常数和常数
  42. 生效时间
  43. 烛台间距
  44. 公用事业
  45. 地址公用事业
  46. 网页订阅
  47. 类型脚本
  48. 最佳做法
  49. 完整的交易瓶示例
  50. 智能合同交易
  51. 核心交易基础设施
  52. 工具函数
  53. 账户管理交易
  54. 命令管理交易
  55. 职位管理交易
  56. 贸易代表团
  57. 完整工作示例
  58. 最佳做法
  59. 资源

@ decibeltrade/ sdk (英语)

用于与Decibel互动的TypeScript SDK,这是一款由Aptos所建的全链上交易引擎.

📚 查看完整的文档 –

概览

Decibel TypeSDK提供了一个干净,打入的界面,在Aptos上与Decibel交互:

  • 读取操作 (单位:千美元)DecibelReadDex)——查询市场,深度,价格,交易,头寸,订单,分账户,金库
  • 写入操作 (单位:千美元)DecibelWriteDex(a) 地点/终止命令、管理职位和分账户、金库业务、授权

安装

npm install @decibeltrade/sdk @aptos-labs/ts-sdk zod
yarn add @decibeltrade/sdk @aptos-labs/ts-sdk zod
pnpm add @decibeltrade/sdk @aptos-labs/ts-sdk zod

对于节点环境中的TypeScript,您也可能想要:

npm install -D @types/ws

快速启动

读取: 市场和账户数据

import { DecibelReadDex, TESTNET_CONFIG } from "@decibeltrade/sdk";

const read = new DecibelReadDex(TESTNET_CONFIG, {
  nodeApiKey: process.env.APTOS_NODE_API_KEY, // required
  onWsError: (error) => console.error("WebSocket error:", error), // optional
});

// Get all markets
const markets = await read.markets.getAll();

// Get account overview
const account = await read.accountOverview.getByAddr("0x...account");

// Get market prices
const prices = await read.marketPrices.getAll();

// Get order book depth
const depth = await read.marketDepth.getBySymbol("BTC-PERP", { depth: 10 });

写入: 提交交易

import { DecibelReadDex, DecibelWriteDex, TESTNET_CONFIG } from "@decibeltrade/sdk";
import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const account = new Ed25519Account({
  privateKey: new Ed25519PrivateKey(process.env.PRIVATE_KEY!),
});

const read = new DecibelReadDex(TESTNET_CONFIG, {
  nodeApiKey: process.env.APTOS_NODE_API_KEY,
});

const write = new DecibelWriteDex(TESTNET_CONFIG, account, {
  nodeApiKey: process.env.APTOS_NODE_API_KEY, // optional
});

const markets = await read.markets.getAll();
const market = markets.find((m) => m.market_addr === "0x...");
if (!market) throw new Error("Market not found");

function amountToChainUnits(amount: number, decimals: number) {
  return Math.floor(amount * 10 ** decimals);
}

// Place an order
const order = await write.placeOrder({
  subaccountAddr: "0x...",
  marketAddr: "0x...",
  price: amountToChainUnits(5.67, market.px_decimals),
  size: amountToChainUnits(1, market.sz_decimals),
  isBuy: true,
  timeInForce: 0, // GoodTillCanceled
});

文档

开始

读取 SDK

  • 读取 SDK 指南 - 查询市场数据和账户信息
    • 市场数据(价格、深度、行业、烛台)
    • 账户概况和职位
    • 命令历史和开放命令
    • 分账户和代表团
    • 默认信息
    • 运动奖励,包括附属委员会

写入 SDK

  • 写入 SDK 指南 - 建立和提交交易
    • 设置和取消命令
    • TWAP和批发订单
    • 职位管理(TP/SL)
    • 分账户管理
    • 断层作业
    • 代表团

高级

配置

SDK支持多个网络配置 :

import { MAINNET_CONFIG, TESTNET_CONFIG, LOCAL_CONFIG, DOCKER_CONFIG } from "@decibeltrade/sdk";

// Mainnet
const read = new DecibelReadDex(MAINNET_CONFIG);

// Testnet
const read = new DecibelReadDex(TESTNET_CONFIG);

// Local development
const read = new DecibelReadDex(LOCAL_CONFIG);

// Docker environment
const read = new DecibelReadDex(DOCKER_CONFIG);

自定义配置

import { DecibelConfig } from "@decibeltrade/sdk";
import { Network } from "@aptos-labs/ts-sdk";

const customConfig: DecibelConfig = {
  network: Network.CUSTOM,
  fullnodeUrl: "https://api.testnet.aptoslabs.com/v1",
  tradingHttpUrl: "https://api.testnet.aptoslabs.com/decibel",
  tradingWsUrl: "wss://api.testnet.aptoslabs.com/decibel/ws",
  gasStationUrl: "https://api.testnet.aptoslabs.com/gs/v1", // optional: enables gas sponsorship
  gasStationApiKey: "your-gas-station-api-key", // optional: enables gas sponsorship
  gasStationAddress: "0x...", // optional: fee-payer address, required for encrypted submission
  deployment: {
    package: "0x...",
    usdc: "0x...",
    testc: "0x...",
    perpEngineGlobal: "0x...",
  },
};

何时使用

  • 使用 DecibelReadDex 当您需要市场数据、顺序/位置历史或账户状态时。 不需要私人密钥 .
  • 使用 DecibelWriteDex 用于链上行动和贸易。 在浏览器中,避免嵌入私密密钥——偏好会话密钥或钱包并传递 accountOverride 具体电话.

读取操作 API

十进制读取器

主要读取客户端提供所有市场数据和账户信息.

构造器

new DecibelReadDex(config: DecibelConfig, opts?: {
  nodeApiKey?: string;
  onWsError?: (error: ErrorEvent) => void;
  onChainFallback?: (info: ChainFallbackInfo) => void;
})

全球方法

// Get global perpetual engine state
await readDex.globalPerpEngineState();

// Get collateral balance decimals
await readDex.collateralBalanceDecimals();

// Get USDC decimals (cached)
await readDex.usdcDecimals();

// Get USDC balance for an address
await readDex.usdcBalance("0x123...");

// Get account balance
await readDex.accountBalance("0x123...");

// Read on-chain fungible-asset metadata (symbol, decimals, name) for any
// asset address — e.g. entries in account_overview.secondary_collateral
await readDex.fungibleAssetMetadata("0x...asset_metadata");

// Resolve a spot market's base/quote asset addresses (not exposed by /markets)
await readDex.spotMarketAssets("0x...spot_market");

// Get position size
await readDex.positionSize("0x123...", "metadata_address");

// Get crossed position
await readDex.getCrossedPosition("0x123...");

市场

市场准入信息和配置.

// Get all available perp markets
const markets = await readDex.markets.getAll();

// Include spot markets too (rows are discriminated by asset_type), or get
// spot markets alone. Narrow union rows with isSpotMarket / isPerpMarket.
const allMarkets = await readDex.markets.getAll({ includeSpot: true });
const spotMarkets = await readDex.markets.getAllSpot();

// Get specific market by name
const market = await readDex.markets.getByName("BTC-USD");

// Get market by symbol
const market = await readDex.markets.getBySymbol("BTC-PERP");

// List all market addresses
const addresses = await readDex.markets.listMarketAddresses();

// Get market name by address
const name = await readDex.markets.marketNameByAddress("0x123...");

运动奖

const campaigns = await readDex.campaigns.getActive();
const summary = await readDex.campaigns.getSummary({
  accountAddress: "0x...",
  limit: 20,
  offset: 0,
});

运动元数据, summary.claims,以及 summary.breakdownByType 使用情况 campaignType数字 : "fee_rebate", (中文(简体) ), "maker_incentive", (中文(简体) ), "liquidation_rebate", (中文(简体) ), "volume_milestone", (中文(简体) ), "first_funded_trial",或 "affiliate"。未知的运动类型失败响应验证. 奖励金额是原始的代号单位(按美元数额分列) 10 ** 6) (中文(简体) ). 每项索赔均披露 hasAllocation, (中文(简体) ), readyToClaim, (中文(简体) ), claimedAmount, (中文(简体) ), claimedAtTsSec,以及 claimTxHash。 。 。 .

账户概览

获得全面的账户信息,包括余额和职位.

// Get account overview
const overview = await readDex.accountOverview.getByAddr("subaccount_address", "30d"); // volume_window = "30d"

// Subscribe to real-time account updates
const unsubscribe = readDex.accountOverview.subscribeByAddr("subaccount_address", (data) =>
  console.log("Account update:", data),
);

// Later, unsubscribe
unsubscribe();

用户费

获得子账户的有效制作人/交易商的收费标准,当期收费水平,全额 贵宾收费表 及其上链收费窗口的日用量历史. 收费 比率为小数(如:. 0.00034 =0.034%;体积值为整美元整数 字符串.

const fees = await readDex.userFees.getByAddr({ subAddr: "subaccount_address" });
// fees.user_taker_rate, fees.user_maker_rate, fees.fee_tier
// fees.fee_schedule.tiers.vip[], fees.daily_user_volume[]

用户位置

查询市场的用户位置.

// Get all positions for a user
const positions = await readDex.userPositions.getByAddr({
  subAddr: "subaccount_address",
  includeDeleted: false,
  limit: 10,
});

// Get positions for specific market
const marketPositions = await readDex.userPositions.getByAddr({
  subAddr: "subaccount_address",
  marketAddr: "market_address",
  limit: 10,
});

// Subscribe to position updates
const unsubscribe = readDex.userPositions.subscribeByAddr("subaccount_address", (data) =>
  console.log("Position update:", data),
);

用户命令

查取开封令和令史. 命令的终点是罪犯和现场 在每行共享路线上 asset_type 歧视者; 列表阅读器 默认为 assetType: "perp"。通过 "spot" - 发现范围,或 "all" 改为 获得两种产品合并.

打开命令

// Get open orders (perp by default)
const openOrders = await readDex.userOpenOrders.getByAddr({ subAddr: "subaccount_address" });

// Spot only, or both products merged
const spotOrders = await readDex.userOpenOrders.getByAddr({
  subAddr: "subaccount_address",
  assetType: "spot",
});
const allOrders = await readDex.userOpenOrders.getByAddr({
  subAddr: "subaccount_address",
  assetType: "all",
});

// Subscribe to open orders updates
const unsubscribe = readDex.userOpenOrders.subscribeByAddr("subaccount_address", (data) =>
  console.log("Orders update:", data),
);

顺序历史

// Get order history (perp by default; assetType works as above)
const orderHistory = await readDex.userOrderHistory.getByAddr({
  subAddr: "subaccount_address",
  limit: 50,
});

// Subscribe to order history updates
const unsubscribe = readDex.userOrderHistory.subscribeByAddr("subaccount_address", (data) =>
  console.log("Order history update:", data),
);

单次搜索

// Look up one order by orderId (perp + spot) or clientOrderId (perp only).
// assetType defaults to unset: the API checks perp first, then spot.
const order = await readDex.userOrders.getOrder({
  subAddr: "subaccount_address",
  market: "market_address",
  orderId: "42",
});

散装命令

// Get bulk orders (perp by default; assetType works as above)
const bulkOrders = await readDex.userBulkOrders.getByAddr({ subAddr: "subaccount_address" });

// Placement status of one bulk order by sequence number
const status = await readDex.userBulkOrders.getStatus({
  subAddr: "subaccount_address",
  market: "market_address",
  sequenceNumber: 7,
});

// Bulk order fills (optionally by market and sequence number range)
const fills = await readDex.userBulkOrders.getFills({
  subAddr: "subaccount_address",
  startSequenceNumber: 5,
  endSequenceNumber: 9,
});

市场数据

市场深度(命令书)

// Subscribe to depth updates (aggregationSize buckets price levels)
const unsubscribe = readDex.marketDepth.subscribeByName("BTC-USD", 1, (data) =>
  console.log("Depth update:", data),
);

// Spot markets derive a different address than perp markets with the same
// name, so pass the asset type (defaults to "perp")
const unsubSpot = readDex.marketDepth.subscribeByName("APT/USDC", 1, onDepth, "spot");

// Or skip name→address derivation when you already hold the market address
const unsubByAddr = readDex.marketDepth.subscribeByAddr(market.market_addr, 1, onDepth);

// Reset subscription (clear cached data)
readDex.marketDepth.resetSubscriptionByName("BTC-USD", 1);
readDex.marketDepth.resetSubscriptionByAddr(market.market_addr, 1);

市场价格

// Get current prices
const prices = await readDex.marketPrices.getByName("BTC-USD");
const prices = await readDex.marketPrices.getAll();

// Subscribe to price updates
const unsubscribe = readDex.marketPrices.subscribeByName("BTC-USD", (data) =>
  console.log("Price update:", data),
);

市场贸易

// Get recent trades
const trades = await readDex.marketTrades.getByName({ marketName: "BTC-USD", limit: 50 });

// Spot markets: pass assetType (defaults to "perp")
const spotTrades = await readDex.marketTrades.getByName({
  marketName: "APT/USDC",
  assetType: "spot",
});

// Or skip name→address derivation when you already hold the market address
const tradesByAddr = await readDex.marketTrades.getByAddr({ marketAddr: market.market_addr });

// Subscribe to trade updates
const unsubscribe = readDex.marketTrades.subscribeByName("BTC-USD", (data) =>
  console.log("Trade update:", data),
);
const unsubSpot = readDex.marketTrades.subscribeByName("APT/USDC", onTrades, "spot");
const unsubByAddr = readDex.marketTrades.subscribeByAddr(market.market_addr, onTrades);

烛台

import { CandlestickInterval } from "@decibeltrade/sdk";

// Get historical candlestick data (assetType defaults to "perp"; pass "spot"
// for spot markets — perp and spot derive different addresses for the same name)
const candlesticks = await readDex.candlesticks.getByName({
  marketName: "BTC-USD",
  interval: CandlestickInterval.OneMinute,
  startTime: startTimestamp,
  endTime: endTimestamp,
});

// Or skip name→address derivation when you already hold the market address
const byAddr = await readDex.candlesticks.getByAddr({
  marketAddr: market.market_addr,
  interval: CandlestickInterval.OneMinute,
  startTime: startTimestamp,
  endTime: endTimestamp,
});

// Subscribe to candlestick updates
const unsubscribe = readDex.candlesticks.subscribeByName(
  "BTC-USD",
  CandlestickInterval.OneMinute,
  (data) => console.log("Candlestick update:", data),
);
const unsubByAddr = readDex.candlesticks.subscribeByAddr(
  market.market_addr,
  CandlestickInterval.OneMinute,
  (data) => console.log("Candlestick update:", data),
);

市场背景

获取更多市场元数据和上下文.

// Get market contexts
const contexts = await readDex.marketContexts.getAll();

// Subscribe to market context updates
const unsubscribe = readDex.marketContexts.subscribeAll((data) =>
  console.log("Market contexts update:", data),
);

用户贸易历史

为用户查询历史贸易数据.

// Get trade history
const trades = await readDex.userTradeHistory.getByAddr({
  subAddr: "subaccount_address",
  marketAddr: "market_address", // optional
  limit: 100,
});

// Subscribe to trade history updates
const unsubscribe = readDex.userTradeHistory.subscribeByAddr("subaccount_address", (data) =>
  console.log("Trade history update:", data),
);

用户供资历史

查询资助支付历史.

// Get funding history
const funding = await readDex.userFundingHistory.getByAddr({
  subAddr: "subaccount_address",
  marketAddr: "market_address", // optional
  limit: 50,
});

// Subscribe to funding history updates
const unsubscribe = readDex.userFundingHistory.subscribeByAddr("subaccount_address", (data) =>
  console.log("Funding history update:", data),
);

用户子账户

// Get all subaccounts for a user
const subaccounts = await readDex.userSubaccounts.getByAddr("account_address");

断层

// Get user vault positions
const userVaults = await readDex.userVaults.getByAddr("account_address");

// Get public vault information
const vaults = await readDex.vaults.getAll();

第一次贸易

运动代表了资金到位的第一次贸易流动。 总计为 SQL 级计数 : 在塑造时跳过服务器并进行计数,因此驱动页码 offset + limit < total,从不通过查找空/短页.

// Composed on-chain eligibility snapshot (locks, credits, budgets, live tier/payout config)
const eligibility = await readDex.fundedFirstTrade.getEligibility({ account: "account_address" });

// Active trial, or null
const activeTrial = await readDex.fundedFirstTrade.getActiveTrial({ account: "account_address" });

// Terminal trial history — { history, historyTotalCount }
const page = await readDex.fundedFirstTrade.getTrialHistory({
  account: "account_address",
  limit: 20,
  offset: 0,
});

// Campaign reward locks — { account, locks, total_count }; server default limit 10
const locks = await readDex.fundedFirstTrade.getCampaignLocks({
  account: "account_address",
  status: "Active", // optional: "Active" | "Claimed"
});

// Real-time trial updates (TrialOpened / TrialClosed / TrialResetByAdmin)
const unsubscribe = readDex.fundedFirstTrade.subscribeByAddr("account_address", ({ trials }) => {
  console.log(trials);
});

写入操作 API

十进制WriteDex

主要书写客户执行交易和管理交易账户、职位、金库和竞选奖励.

构造器

import { GasPriceManager } from "@decibeltrade/sdk";
import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

const account = new Ed25519Account({
  privateKey: new Ed25519PrivateKey("your-private-key"),
});

const gasPriceManager = new GasPriceManager(config);

const writeDex = new DecibelWriteDex(config, account, {
  nodeApiKey: process.env.APTOS_NODE_API_KEY,
  skipSimulate: false,
  gasPriceManager,
  timeDeltaMs: 0,
  defaultEncrypted: false,
});

defaultEncrypted 决定是否将前端运行敏感写作为加密待决提交 交易; 可读取实例 writeDex.defaultEncrypted加密 提交要求有一个暴露加密密钥的全节点 配置 - a gasStationAddress 在配置中, 因为付费者被烤入加密 建造时的有效载荷。 提前检查一下 configSupportsEncryptedSubmission(config)。 。 。 .

公开写作方法

  • 交易账户和抵押品: renameSubaccount, (中文(简体) ), createSubaccount, (中文(简体) ), adminCreateSubaccount, (中文(简体) ), sendSubaccountTx, (中文(简体) ), withSubaccount, (中文(简体) ), deposit, (中文(简体) ), withdraw, (中文(简体) ), withdrawNonCollateral, (中文(简体) ), configureUserSettingsForMarket, (中文(简体) ), buildDeactiveSubaccountTx
  • 命令和匹配 : placeOrder, (中文(简体) ), triggerMatching, (中文(简体) ), placeTwapOrder, (中文(简体) ), cancelOrder, (中文(简体) ), cancelClientOrder, (中文(简体) ), cancelBulkOrder, (中文(简体) ), updateOrder, (中文(简体) ), cancelTwapOrder
  • 点交易 : placeSpotOrder, (中文(简体) ), cancelSpotOrder, (中文(简体) ), placeSpotBulkOrder, (中文(简体) ), cancelSpotBulkOrder, (中文(简体) ), cancelSpotBulkOrderAtPriceLevel, (中文(简体) ), approveMaxSpotBuilderFee, (中文(简体) ), revokeMaxSpotBuilderFee, (中文(简体) ), setHoldAsNonCollateral, (中文(简体) ), processSpotPendingRequests
  • TP/SL位置 : placeTpSlOrderForPosition, (中文(简体) ), updateTpOrderForPosition, (中文(简体) ), updateSlOrderForPosition, (中文(简体) ), cancelTpSlOrderForPosition
  • 代表团、金库和奖励: delegateTradingToForSubaccount, (中文(简体) ), revokeDelegation, (中文(简体) ), createVault, (中文(简体) ), buildCreateVaultTx, (中文(简体) ), buildActivateVaultTx, (中文(简体) ), buildDepositToVaultTx, (中文(简体) ), depositToVault, (中文(简体) ), withdrawFromVault, (中文(简体) ), buildDelegateDexActionsToTx, (中文(简体) ), approveMaxBuilderFee, (中文(简体) ), revokeMaxBuilderFee, (中文(简体) ), claimCampaignReward, (中文(简体) ), openFftTrial, (中文(简体) ), claimFftUnlock, (中文(简体) ), settleFftTrial

交易账户和抵押品

// Create a new subaccount
await writeDex.createSubaccount();

// Admin-only: create a subaccount for another owner
await writeDex.adminCreateSubaccount("0x...owner");

// Rename a subaccount via trading API
await writeDex.renameSubaccount({
  subaccountAddress: "0x...subaccount",
  newName: "Treasury",
});

// Deposit collateral to primary subaccount
await writeDex.deposit(1000000); // amount in smallest unit

// Deposit to specific subaccount
await writeDex.deposit(1000000, "subaccount_address");

// Withdraw from subaccount
await writeDex.withdraw(500000, "subaccount_address");

// Withdraw a non-collateral asset from a subaccount
await writeDex.withdrawNonCollateral("0x...asset_metadata", 250000, "subaccount_address");

贸易代表团和建筑商收费

// Delegate trading permissions
await writeDex.delegateTradingToForSubaccount({
  subaccountAddr: "your_subaccount",
  accountToDelegateTo: "delegate_account_address",
  expirationTimestampSecs: 1735689600, // optional
});

// Revoke delegation
await writeDex.revokeDelegation({
  subaccountAddr: "your_subaccount",
  accountToRevoke: "delegate_account_address",
});

// Approve and revoke builder fees (values are basis points)
await writeDex.approveMaxBuilderFee({
  builderAddr: "0x...builder",
  maxFee: 25,
});

await writeDex.revokeMaxBuilderFee({
  builderAddr: "0x...builder",
});

市场配置

// Configure user settings for a market
await writeDex.configureUserSettingsForMarket({
  marketAddr: "market_address",
  subaccountAddr: "subaccount_address",
  isCross: true, // cross-margin mode
  userLeverage: 1000, // 10x leverage (basis points)
});

订单管理

import { DecibelReadDex, getMarketAddr, TimeInForce } from "@decibeltrade/sdk";

const readDex = new DecibelReadDex(config, {
  nodeApiKey: process.env.APTOS_NODE_API_KEY,
});

const marketAddr = getMarketAddr("BTC-USD", config.deployment.perpEngineGlobal).toString();
const market = await readDex.markets.getByName("BTC-USD");
if (!market) throw new Error("Market not found");

const amountToChainUnits = (amount: number, decimals: number) =>
  Math.floor(amount * 10 ** decimals);

// Place a limit order
const result = await writeDex.placeOrder({
  marketName: "BTC-USD",
  price: amountToChainUnits(45_000, market.px_decimals),
  size: amountToChainUnits(1.5, market.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  clientOrderId: "12345", // optional
  subaccountAddr: "subaccount_address", // optional
});

// Place order with stop-loss and take-profit
await writeDex.placeOrder({
  marketName: "BTC-USD",
  price: amountToChainUnits(45_000, market.px_decimals),
  size: amountToChainUnits(1, market.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  stopPrice: amountToChainUnits(44_000, market.px_decimals),
  tpTriggerPrice: amountToChainUnits(46_000, market.px_decimals),
  tpLimitPrice: amountToChainUnits(45_900, market.px_decimals),
  slTriggerPrice: amountToChainUnits(44_000, market.px_decimals),
  slLimitPrice: amountToChainUnits(44_100, market.px_decimals),
});

// Place order with builder fee and automatic tick-size snapping
await writeDex.placeOrder({
  marketName: "BTC-USD",
  price: amountToChainUnits(45_000, market.px_decimals),
  size: amountToChainUnits(1, market.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  builderAddr: "builder_account_address",
  builderFee: 100,
  tickSize: market.tick_size,
});

// Place a TWAP order
await writeDex.placeTwapOrder({
  marketName: "BTC-USD",
  size: amountToChainUnits(10, market.sz_decimals),
  isBuy: true,
  isReduceOnly: false,
  twapFrequencySeconds: 60,
  twapDurationSeconds: 3600,
});

// Cancel orders
// Choose `marketName` when you only have a symbol/name.
await writeDex.cancelOrder({
  orderId: 12345,
  marketName: "BTC-USD",
  subaccountAddr: "subaccount_address", // optional
});

// Choose `marketAddr` when the address is already resolved/cached.
await writeDex.cancelOrder({
  orderId: 12345,
  marketAddr,
  subaccountAddr: "subaccount_address", // optional
});

await writeDex.cancelClientOrder({
  clientOrderId: "54321",
  marketName: "BTC-USD",
});

await writeDex.cancelTwapOrder({
  orderId: "twap_order_id",
  marketAddr,
});

// Cancel all bulk orders for a market
// By market name (symbol-driven flow)
await writeDex.cancelBulkOrder({
  marketName: "BTC-USD",
  subaccountAddr: "subaccount_address", // optional
});

// By market address (address-driven flow)
await writeDex.cancelBulkOrder({
  marketAddr,
  subaccountAddr: "subaccount_address", // optional
});

// Update an existing order
await writeDex.updateOrder({
  orderId: 12345,
  marketAddr,
  price: amountToChainUnits(45_500, market.px_decimals),
  size: amountToChainUnits(1.25, market.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  tpTriggerPrice: amountToChainUnits(47_000, market.px_decimals),
  tpLimitPrice: amountToChainUnits(46_900, market.px_decimals),
});

点点交易

所有即时方法都是子账户范围(默认为主交易账户)并接受 marketName 或者说 marketAddr一样 cancelOrder。 。 。 .

import { roundToTickSizeForSide, TimeInForce } from "@decibeltrade/sdk";

const spotMarkets = await readDex.markets.getAllSpot();
const spotMarket = spotMarkets.find((m) => m.market_name === "APT/USDC");
if (!spotMarket) throw new Error("Market not found");

// Place a spot limit order. On spot markets sz_decimals is the base-asset
// decimals and px_decimals the quote-asset decimals.
const spotResult = await writeDex.placeSpotOrder({
  marketName: "APT/USDC",
  price: amountToChainUnits(4.25, spotMarket.px_decimals),
  size: amountToChainUnits(100, spotMarket.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  tickSize: spotMarket.tick_size, // optional price snapping
});

// Spot placement is CBS-backed and async: when funding needs a rate-limited
// CBS withdrawal the transaction succeeds but the order is queued, not
// resting. `pendingCbs: true` signals this — resolve the outcome via
// readDex.userOrders.getOrder / userOrderHistory, which cover every terminal
// state. userOpenOrders only sees orders that rest, so an IOC order never
// shows up there whether it filled, cancelled, or is still queued.
if (spotResult.success && spotResult.pendingCbs) {
  console.log("Order queued behind a CBS withdrawal", spotResult.orderId);
}

// There is no market order on chain for spot: submit an IOC limit at the
// slippage cap. `roundToTickSizeForSide` is the same side-safe rounding
// `tickSize` applies internally (buys down, sells up, so the cap is never
// crossed) — pre-round with it to know the exact price the order is
// submitted and escrowed at. It is idempotent.
//
// Spot has no perp-style price feed, so the reference price comes from the
// spot asset contexts (mid of the book, or the last trade).
const spotContexts = await readDex.spotAssetContexts.getAll();
const spotContext = spotContexts.find((c) => c.market_addr === spotMarket.market_addr);
const mid = spotContext?.mid ?? spotContext?.last_price;
if (mid == null) throw new Error("No spot reference price");

// Scale WITHOUT rounding first: amountToChainUnits rounds to the nearest
// integer, which can carry the value across a tick boundary and put the
// submitted price on the wrong side of the cap. Let the side-safe rounding
// consume the exact fractional value instead.
const cap = mid * 1.01 * 10 ** spotMarket.px_decimals;
const submittedPrice = roundToTickSizeForSide(cap, spotMarket.tick_size, true);

const spotMarketOrder = await writeDex.placeSpotOrder({
  marketName: "APT/USDC",
  price: submittedPrice,
  size: amountToChainUnits(100, spotMarket.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.ImmediateOrCancel,
  tickSize: spotMarket.tick_size,
});

// Cancel a spot order
if (spotResult.success && spotResult.orderId) {
  await writeDex.cancelSpotOrder({
    orderId: spotResult.orderId,
    marketName: "APT/USDC",
  });
}

// Spot bulk orders (funded from the subaccount PFS only)
await writeDex.placeSpotBulkOrder({
  marketName: "APT/USDC",
  sequenceNumber: 1, // strictly increasing per market
  bidPrices: [amountToChainUnits(4.2, spotMarket.px_decimals)],
  bidSizes: [amountToChainUnits(50, spotMarket.sz_decimals)],
  askPrices: [amountToChainUnits(4.3, spotMarket.px_decimals)],
  askSizes: [amountToChainUnits(50, spotMarket.sz_decimals)],
});

await writeDex.cancelSpotBulkOrderAtPriceLevel({
  marketName: "APT/USDC",
  price: amountToChainUnits(4.2, spotMarket.px_decimals),
  isBuy: true,
});

await writeDex.cancelSpotBulkOrder({ marketName: "APT/USDC" });

// Spot builder fees (basis points). Unlike perp, the builder address may be
// a subaccount or a primary wallet.
await writeDex.approveMaxSpotBuilderFee({ builderAddr: "0x...builder", maxFee: 10 });
await writeDex.revokeMaxSpotBuilderFee({ builderAddr: "0x...builder" });

// Keep future deposits of an asset in the PFS (non-collateral) instead of
// routing them into CBS collateral. Flag-only: existing balances don't move.
await writeDex.setHoldAsNonCollateral({ assetAddr: "0x...asset_metadata", hold: true });

职位管理

const markets = await readDex.markets.getAll();
const market = markets.find((m) => m.market_addr === "market_address");
if (!market) throw new Error("Market not found");

// Place TP/SL order for an existing position
await writeDex.placeTpSlOrderForPosition({
  marketAddr: "market_address",
  tpTriggerPrice: amountToChainUnits(46_000, market.px_decimals),
  tpLimitPrice: amountToChainUnits(45_900, market.px_decimals),
  tpSize: amountToChainUnits(0.5, market.sz_decimals),
  slTriggerPrice: amountToChainUnits(44_000, market.px_decimals),
  slLimitPrice: amountToChainUnits(44_100, market.px_decimals),
  slSize: amountToChainUnits(1, market.sz_decimals),
  subaccountAddr: "subaccount_address",
});

// Update TP and SL orders independently
await writeDex.updateTpOrderForPosition({
  marketAddr: "market_address",
  prevOrderId: "previous_tp_order_id",
  tpTriggerPrice: amountToChainUnits(47_000, market.px_decimals),
  tpLimitPrice: amountToChainUnits(46_900, market.px_decimals),
  tpSize: amountToChainUnits(0.75, market.sz_decimals),
});

await writeDex.updateSlOrderForPosition({
  marketAddr: "market_address",
  prevOrderId: "previous_sl_order_id",
  slTriggerPrice: amountToChainUnits(43_800, market.px_decimals),
  slLimitPrice: amountToChainUnits(43_750, market.px_decimals),
  slSize: amountToChainUnits(1, market.sz_decimals),
});

await writeDex.cancelTpSlOrderForPosition({
  marketAddr: "market_address",
  orderId: 12345,
  subaccountAddr: "subaccount_address",
});

过失和竞选奖励

// Create a vault
await writeDex.createVault({
  // Asset metadata object address (for example USDC metadata), not a Move type tag
  contributionAssetType: writeDex.config.deployment.usdc,
  vaultName: "Basis Trade",
  vaultDescription: "Example strategy",
  vaultSocialLinks: [],
  vaultShareSymbol: "BASIS",
  feeBps: 0,
  feeIntervalS: 0,
  contributionLockupDurationS: 0,
  initialFunding: 0,
  acceptsContributions: false,
  delegateToCreator: false,
});

// Contribute to and redeem from a vault
await writeDex.depositToVault({
  vaultAddress: "0x...vault",
  amount: 1000000,
  subaccountAddr: "0x...subaccount",
});

await writeDex.withdrawFromVault({
  vaultAddress: "0x...vault",
  shares: 1000000,
});

// Build transactions for custom signing flows
await writeDex.buildCreateVaultTx({
  contributionAssetType: writeDex.config.deployment.usdc,
  vaultName: "Basis Trade",
  vaultDescription: "Example strategy",
  vaultSocialLinks: [],
  vaultShareSymbol: "BASIS",
  feeBps: 0,
  feeIntervalS: 0,
  contributionLockupDurationS: 0,
  initialFunding: 0,
  acceptsContributions: false,
  delegateToCreator: false,
  signerAddress: account.accountAddress,
});

await writeDex.buildActivateVaultTx({
  vaultAddress: "0x...vault",
  signerAddress: account.accountAddress,
});

await writeDex.buildDepositToVaultTx({
  vaultAddress: "0x...vault",
  amount: 1000000,
  signerAddress: account.accountAddress,
});

await writeDex.buildDelegateDexActionsToTx({
  vaultAddress: "0x...vault",
  accountToDelegateTo: "0x...delegate",
  signerAddress: account.accountAddress,
});

// Claim a campaign reward by numeric campaign ID
await writeDex.claimCampaignReward(42);

会话账户

您可以使用会话账户覆盖特定交易的默认账户 :

import { TimeInForce } from "@decibeltrade/sdk";
import { Ed25519Account } from "@aptos-labs/ts-sdk";

const sessionAccount = Ed25519Account.generate();
const market = await readDex.markets.getByName("BTC-USD");
if (!market) throw new Error("Market not found");

const amountToChainUnits = (amount: number, decimals: number) =>
  Math.floor(amount * 10 ** decimals);

await writeDex.placeOrder({
  marketName: "BTC-USD",
  price: amountToChainUnits(45_000, market.px_decimals),
  size: amountToChainUnits(1, market.sz_decimals),
  isBuy: true,
  timeInForce: TimeInForce.GoodTillCanceled,
  isReduceOnly: false,
  accountOverride: sessionAccount,
});

处理错误

所有写入操作返回交易结果 。 对于顺序放置,您得到一个结构化的结果:

type PlaceOrderResult =
  | {
      success: true;
      orderId: string | undefined;
      transactionHash: string;
    }
  | {
      success: false;
      error: string;
    };

const result = await writeDex.placeOrder({
  // ... order parameters
});

if (result.success) {
  console.log("Order placed successfully:", result.orderId);
  console.log("Transaction:", result.transactionHash);
} else {
  console.error("Order failed:", result.error);
}

常数和常数

生效时间

export const TimeInForce = {
  GoodTillCanceled: 0,
  PostOnly: 1,
  ImmediateOrCancel: 2,
} as const;

烛台间距

export enum CandlestickInterval {
  MINUTE_1 = "1m",
  MINUTE_5 = "5m",
  MINUTE_15 = "15m",
  HOUR_1 = "1h",
  HOUR_4 = "4h",
  DAY_1 = "1d",
}

公用事业

地址公用事业

import { getPrimarySubaccountAddr, getMarketAddr } from "@decibeltrade/sdk";

// Get primary subaccount address for an account
const subaccountAddr = getPrimarySubaccountAddr(
  "account_address",
  sdkConfig.compatVersion,
  sdkConfig.deployment.package,
);

// Get market address from name
const marketAddr = getMarketAddr("BTC-USD", "perp_engine_global_address");

网页订阅

所有支持实时更新的已读操作返回一个未订阅的函数 :

// Subscribe to multiple streams
const unsubscribeDepth = readDex.marketDepth.subscribeByName("BTC-USD", 1, handleDepth);
const unsubscribePrices = readDex.marketPrices.subscribeByName("BTC-USD", handlePrices);
const unsubscribeOrders = readDex.userOpenOrders.subscribeByAddr("subaccount", handleOrders);

// Clean up subscriptions
function cleanup() {
  unsubscribeDepth();
  unsubscribePrices();
  unsubscribeOrders();
}

// Handle errors
const readDex = new DecibelReadDex(TESTNET_CONFIG, {
  onWsError: (error) => {
    console.error("WebSocket error:", error);
  },
  // Fired (once per method per instance) when a trading-api read fails and is
  // rebuilt from on-chain views
  onChainFallback: ({ method, error }) => {
    console.warn(`${method} fell back to chain views:`, error);
  },
});

// The SDK reconnects and resubscribes automatically. Streaming-only topics get
// no replay of events missed during an outage — re-seed their state on:
const unregister = readDex.onWsReconnect(() => {
  // re-fetch WS-seeded state over HTTP
});

类型脚本

SDK与Zod schemas完全打入,用于运行时间验证. 为更好的发展经验而进口的类型:

import type {
  DecibelConfig,
  PerpMarket,
  UserPosition,
  MarketDepth,
  CandlestickData,
  AccountOverview,
  PlaceOrderResult,
} from "@decibeltrade/sdk";

最佳做法

  1. 连接管理: 在可能的情况下重新使用 SDK 实例来维护 WebSocket 连接.

  2. 处理错误: 总是将 SDK 的电话包装在试捕区块中,并妥善处理出错.

  3. 订阅清理: 总是调用未订阅的函数来防止内存出漏.

  4. 限制费率:在频繁提出请求时注意API的费率限制.

  5. 账户安全:从不披露客户端代码中的私钥. 使用环境变量或安全密钥管理.

  6. 精确度:注意物价和尺寸的数字精确度. SDK在内部处理小数精度.

完整的交易瓶示例

import { DecibelReadDex, DecibelWriteDex, TESTNET_CONFIG, TimeInForce } from "@decibeltrade/sdk";
import { Ed25519Account, Ed25519PrivateKey } from "@aptos-labs/ts-sdk";

class TradingBot {
  private readDex: DecibelReadDex;
  private writeDex: DecibelWriteDex;
  private subaccountAddr: string;

  constructor(privateKey: string, subaccountAddr: string) {
    this.readDex = new DecibelReadDex(TESTNET_CONFIG, {
      nodeApiKey: process.env.APTOS_NODE_API_KEY,
    });

    const account = new Ed25519Account({
      privateKey: new Ed25519PrivateKey(privateKey),
    });
    this.writeDex = new DecibelWriteDex(TESTNET_CONFIG, account, {
      nodeApiKey: process.env.APTOS_NODE_API_KEY,
    });
    this.subaccountAddr = subaccountAddr;
  }

  async start() {
    // Subscribe to market data
    this.readDex.marketPrices.subscribeByName("BTC-USD", this.handlePriceUpdate.bind(this));
    this.readDex.marketDepth.subscribeByName("BTC-USD", 1, this.handleDepthUpdate.bind(this));

    // Subscribe to account updates
    this.readDex.userPositions.subscribeByAddr(
      this.subaccountAddr,
      this.handlePositionUpdate.bind(this),
    );
  }

  private async handlePriceUpdate(priceData: any) {
    // Implement your trading logic here
    console.log("Price update:", priceData);
  }

  private async handleDepthUpdate(depthData: any) {
    // Analyze order book for trading opportunities
    console.log("Depth update:", depthData);
  }

  private async handlePositionUpdate(positionData: any) {
    // Monitor positions and manage risk
    console.log("Position update:", positionData);
  }

  async placeMarketBuyOrder(size: number) {
    try {
      const result = await this.writeDex.placeOrder({
        marketName: "BTC-USD",
        price: 0, // Market order (implementation may vary)
        size,
        isBuy: true,
        timeInForce: TimeInForce.ImmediateOrCancel,
        isReduceOnly: false,
        subaccountAddr: this.subaccountAddr,
      });

      if (result.success) {
        console.log(`Market buy order placed: ${result.orderId}`);
      } else {
        console.error(`Order failed: ${result.error}`);
      }
    } catch (error) {
      console.error("Error placing order:", error);
    }
  }
}

// Usage
const bot = new TradingBot("your-private-key", "your-subaccount-address");
bot.start();

智能合同交易

对于需要直接访问Decibel智能合同的开发者,本节展示了如何使用Aptos SDK直接构建和提交交易.

核心交易基础设施

基础交易管理器

import {
  Account,
  AccountAddress,
  AccountAuthenticator,
  Aptos,
  AptosConfig,
  CommittedTransactionResponse,
  InputGenerateTransactionPayloadData,
  MoveString,
  Network,
  PendingTransactionResponse,
  SimpleTransaction,
  createObjectAddress,
} from "@aptos-labs/ts-sdk";

class DecibelTransactionManager {
  private aptos: Aptos;
  private config: DecibelConfig;
  private skipSimulate: boolean;

  constructor(
    config: DecibelConfig,
    private account: Account,
    options?: {
      skipSimulate?: boolean;
      nodeApiKey?: string;
    },
  ) {
    this.config = config;
    this.skipSimulate = options?.skipSimulate ?? false;

    const aptosConfig = new AptosConfig({
      network: config.network,
      fullnode: config.fullnodeUrl,
      clientConfig: { API_KEY: options?.nodeApiKey },
    });
    this.aptos = new Aptos(aptosConfig);
  }

  private async getSimulatedTransaction(
    payload: InputGenerateTransactionPayloadData,
    sender: AccountAddress,
  ): Promise<SimpleTransaction> {
    const transaction = await this.aptos.transaction.build.simple({
      sender,
      data: payload,
    });

    const [simulationResult] = await this.aptos.transaction.simulate.simple({
      transaction,
      options: {
        estimateMaxGasAmount: true,
        estimateGasUnitPrice: true,
      },
    });

    if (!simulationResult?.max_gas_amount || !simulationResult?.gas_unit_price) {
      throw new Error("Transaction simulation failed - no gas estimates returned");
    }

    return await this.aptos.transaction.build.simple({
      sender,
      data: payload,
      options: {
        maxGasAmount: Number(simulationResult.max_gas_amount),
        gasUnitPrice: Number(simulationResult.gas_unit_price),
      },
    });
  }

  async sendTransaction(
    payload: InputGenerateTransactionPayloadData,
    accountOverride?: Account,
  ): Promise<CommittedTransactionResponse> {
    const signer = accountOverride ?? this.account;
    const sender = signer.accountAddress;

    let transaction: SimpleTransaction;

    if (!this.skipSimulate) {
      transaction = await this.getSimulatedTransaction(payload, sender);
    } else {
      transaction = await this.aptos.transaction.build.simple({
        sender,
        data: payload,
      });
    }

    const senderAuthenticator = this.aptos.transaction.sign({
      signer,
      transaction,
    });

    const pendingTransaction = await this.aptos.transaction.submit.simple({
      transaction,
      senderAuthenticator,
    });
    return await this.aptos.waitForTransaction({
      transactionHash: pendingTransaction.hash,
    });
  }
}

工具函数

/**
 * Get market address from market name
 */
function getMarketAddress(marketName: string, perpEngineGlobalAddr: string): AccountAddress {
  const marketNameBytes = new MoveString(marketName).bcsToBytes();
  return createObjectAddress(AccountAddress.fromString(perpEngineGlobalAddr), marketNameBytes);
}

/**
 * Get primary subaccount address for a user account
 */
function getPrimarySubaccountAddress(userAddress: AccountAddress): string {
  // TODO update
  const seed = new TextEncoder().encode("primary_account");
  return createObjectAddress(userAddress, seed).toString();
}

/**
 * Extract order ID from transaction events
 */
function extractOrderIdFromTransaction(
  txResponse: CommittedTransactionResponse,
  subaccountAddr: string,
): string | null {
  try {
    if ("events" in txResponse && Array.isArray(txResponse.events)) {
      for (const event of txResponse.events) {
        if (event.type.includes("::market_types::OrderEvent")) {
          const orderEvent = event.data as any;
          if (orderEvent.user === subaccountAddr) {
            return orderEvent.order_id;
          }
        }
      }
    }
    return null;
  } catch (error) {
    console.error("Error extracting order ID:", error);
    return null;
  }
}

账户管理交易

创建子账户

async function createSubaccount(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
): Promise<CommittedTransactionResponse> {
  return await transactionManager.sendTransaction({
    function: `${config.deployment.package}::dex_accounts::create_new_subaccount`,
    typeArguments: [],
    functionArguments: [],
  });
}

担保

async function depositCollateral(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  amount: number,
  subaccountAddr: string,
): Promise<CommittedTransactionResponse> {
  return await transactionManager.sendTransaction({
    function: `${config.deployment.package}::dex_accounts::deposit_to_subaccount_at`,
    typeArguments: [],
    functionArguments: [subaccountAddr, config.deployment.usdc, amount],
  });
}

撤销担保

async function withdrawCollateral(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  amount: number,
  subaccountAddr?: string,
): Promise<CommittedTransactionResponse> {
  const subaccount =
    subaccountAddr ?? getPrimarySubaccountAddress(transactionManager.account.accountAddress);

  return await transactionManager.sendTransaction({
    function: `${config.deployment.package}::dex_accounts::withdraw_from_cross_collateral`,
    typeArguments: [],
    functionArguments: [subaccount, config.deployment.usdc, amount],
  });
}

配置市场设置

async function configureMarketSettings(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  marketAddr: string,
  subaccountAddr: string,
  isCross: boolean,
  userLeverage: number,
): Promise<CommittedTransactionResponse> {
  return await transactionManager.sendTransaction({
    function: `${config.deployment.package}::dex_accounts::configure_user_settings_for_market`,
    typeArguments: [],
    functionArguments: [subaccountAddr, marketAddr, isCross, userLeverage],
  });
}

命令管理交易

位置顺序

type PlaceOrderResult =
  | {
      success: true;
      orderId: string | undefined;
      transactionHash: string;
    }
  | {
      success: false;
      error: string;
    };

async function placeOrder(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  params: {
    marketName: string;
    price: number;
    size: number;
    isBuy: boolean;
    timeInForce: number;
    isReduceOnly: boolean;
    clientOrderId?: string;
    stopPrice?: number;
    tpTriggerPrice?: number;
    tpLimitPrice?: number;
    slTriggerPrice?: number;
    slLimitPrice?: number;
    builderAddr?: string;
    builderFee?: number;
    subaccountAddr?: string;
    accountOverride?: Account;
  },
): Promise<PlaceOrderResult> {
  try {
    const marketAddr = getMarketAddress(params.marketName, config.deployment.perpEngineGlobal);
    const subaccountAddr =
      params.subaccountAddr ??
      getPrimarySubaccountAddress(transactionManager.account.accountAddress);

    const txResponse = await transactionManager.sendTransaction(
      {
        function: `${config.deployment.package}::dex_accounts_entry::place_order_to_subaccount`,
        typeArguments: [],
        functionArguments: [
          subaccountAddr,
          marketAddr.toString(),
          params.price,
          params.size,
          params.isBuy,
          params.timeInForce,
          params.isReduceOnly,
          params.clientOrderId,
          params.stopPrice,
          params.tpTriggerPrice,
          params.tpLimitPrice,
          params.slTriggerPrice,
          params.slLimitPrice,
          params.builderAddr,
          params.builderFee,
        ],
      },
      params.accountOverride,
    );

    const orderId = extractOrderIdFromTransaction(txResponse, subaccountAddr);

    return {
      success: true,
      orderId: orderId || undefined,
      transactionHash: txResponse.hash,
    };
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

取消顺序

async function cancelOrder(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  params: {
    orderId: number;
    marketName?: string;
    marketAddr?: string;
    subaccountAddr?: string;
    accountOverride?: Account;
  },
): Promise<CommittedTransactionResponse> {
  const marketAddr =
    params.marketAddr ??
    (params.marketName
      ? getMarketAddress(params.marketName, config.deployment.perpEngineGlobal).toString()
      : "");

  if (!marketAddr) {
    throw new Error("Either marketName or marketAddr must be provided");
  }

  const subaccountAddr =
    params.subaccountAddr ?? getPrimarySubaccountAddress(transactionManager.account.accountAddress);

  return await transactionManager.sendTransaction(
    {
      function: `${config.deployment.package}::dex_accounts::cancel_order_to_subaccount`,
      typeArguments: [],
      functionArguments: [subaccountAddr, params.orderId, marketAddr],
    },
    params.accountOverride,
  );
}

位置 TWAP 顺序

async function placeTwapOrder(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  params: {
    marketName: string;
    size: number;
    isBuy: boolean;
    isReduceOnly: boolean;
    twapFrequencySeconds: number;
    twapDurationSeconds: number;
    subaccountAddr?: string;
    accountOverride?: Account;
  },
): Promise<CommittedTransactionResponse> {
  const marketAddr = getMarketAddress(params.marketName, config.deployment.perpEngineGlobal);
  const subaccountAddr =
    params.subaccountAddr ?? getPrimarySubaccountAddress(transactionManager.account.accountAddress);

  return await transactionManager.sendTransaction(
    {
      function: `${config.deployment.package}::dex_accounts::place_twap_order_to_subaccount`,
      typeArguments: [],
      functionArguments: [
        subaccountAddr,
        marketAddr.toString(),
        params.size,
        params.isBuy,
        params.isReduceOnly,
        params.twapFrequencySeconds,
        params.twapDurationSeconds,
      ],
    },
    params.accountOverride,
  );
}

职位管理交易

放置 TP/ SL 顺序

async function placeTpSlOrderForPosition(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  params: {
    marketAddr: string;
    tpTriggerPrice?: number;
    tpLimitPrice?: number;
    tpSize?: number;
    slTriggerPrice?: number;
    slLimitPrice?: number;
    slSize?: number;
    subaccountAddr?: string;
    accountOverride?: Account;
  },
): Promise<CommittedTransactionResponse> {
  const subaccountAddr =
    params.subaccountAddr ?? getPrimarySubaccountAddress(transactionManager.account.accountAddress);

  return await transactionManager.sendTransaction(
    {
      function: `${config.deployment.package}::dex_accounts::place_tp_sl_order_for_position`,
      typeArguments: [],
      functionArguments: [
        subaccountAddr,
        params.marketAddr,
        params.tpTriggerPrice,
        params.tpLimitPrice,
        params.tpSize,
        params.slTriggerPrice,
        params.slLimitPrice,
        params.slSize,
      ],
    },
    params.accountOverride,
  );
}

贸易代表团

代表贸易

async function delegateTradingToForSubaccount(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  params: {
    accountToDelegateTo: string;
    subaccountAddr?: string;
  },
): Promise<CommittedTransactionResponse> {
  const subaccountAddr =
    params.subaccountAddr ?? getPrimarySubaccountAddress(transactionManager.account.accountAddress);

  return await transactionManager.sendTransaction({
    function: `${config.deployment.package}::dex_accounts::delegate_trading_to_for_subaccount`,
    typeArguments: [],
    functionArguments: [subaccountAddr, params.accountToDelegateTo],
  });
}

撤销代表团

async function revokeDelegation(
  transactionManager: DecibelTransactionManager,
  config: DecibelConfig,
  params: {
    accountToRevoke: string;
    subaccountAddr?: string;
  },
): Promise<CommittedTransactionResponse> {
  const subaccountAddr =
    params.subaccountAddr ?? getPrimarySubaccountAddress(transactionManager.account.accountAddress);

  return await transactionManager.sendTransaction({
    function: `${config.deployment.package}::dex_accounts::revoke_delegation`,
    typeArguments: [],
    functionArguments: [subaccountAddr, params.accountToRevoke],
  });
}

完整工作示例

import { Account } from "@aptos-labs/ts-sdk";

async function basicTradingExample() {
  const privateKey = "your-private-key-here";
  const account = Account.fromPrivateKey({ privateKey });
  const transactionManager = new DecibelTransactionManager(TESTNET_CONFIG, account, {
    skipSimulate: false,
  });

  try {
    // Create a subaccount
    console.log("Creating subaccount...");
    const createTx = await createSubaccount(transactionManager, TESTNET_CONFIG);
    console.log("Subaccount created:", createTx.hash);

    // Get the primary subaccount address
    const subaccountAddr = getPrimarySubaccountAddress(account.accountAddress);
    console.log("Primary subaccount address:", subaccountAddr);

    // Deposit collateral (1000 USDC = 1000000000 if 6 decimals)
    console.log("Depositing collateral...");
    const depositTx = await depositCollateral(
      transactionManager,
      TESTNET_CONFIG,
      1000000000,
      subaccountAddr,
    );
    console.log("Deposit successful:", depositTx.hash);

    // Configure market settings for BTC-USD
    const btcMarketAddr = getMarketAddress("BTC-USD", TESTNET_CONFIG.deployment.perpEngineGlobal);
    console.log("Configuring market settings...");
    const configTx = await configureMarketSettings(
      transactionManager,
      TESTNET_CONFIG,
      btcMarketAddr.toString(),
      subaccountAddr,
      true, // Use cross-margin
      1000, // 10x leverage (1000 basis points)
    );
    console.log("Market configured:", configTx.hash);

    // Place a limit buy order for 0.1 BTC at $45,000
    console.log("Placing buy order...");
    const orderResult = await placeOrder(transactionManager, TESTNET_CONFIG, {
      marketName: "BTC-USD",
      price: 45000,
      size: 0.1,
      isBuy: true,
      timeInForce: TimeInForce.GoodTillCanceled,
      isReduceOnly: false,
      subaccountAddr,
    });

    if (orderResult.success) {
      console.log("Order placed successfully!");
      console.log("Order ID:", orderResult.orderId);
      console.log("Transaction:", orderResult.transactionHash);

      // Cancel the order
      if (orderResult.orderId) {
        console.log("Canceling order...");
        const cancelTx = await cancelOrder(transactionManager, TESTNET_CONFIG, {
          orderId: parseInt(orderResult.orderId),
          marketName: "BTC-USD",
          subaccountAddr,
        });
        console.log("Order canceled:", cancelTx.hash);
      }
    } else {
      console.error("Order failed:", orderResult.error);
    }
  } catch (error) {
    console.error("Error in trading example:", error);
  }
}

最佳做法

  1. 处理错误: 总是在试捕区块中包接交易呼叫,并适当处理不同类型的错误.

  2. 天然气管理: 使用 skipSimulate: false 用于生产中的气体估算。 为复杂的交易设定适当的气体限制.

  3. 子账户管理: 使用主子账户进行简单的使用。 为不同的策略创建单独的子账户. 总是在交易前验证子账户地址.

  4. 市场地址处理:缓存市场地址以避免重复计算. 在生成地址之前验证市场名称正确 .

  5. 订单管理: 存储后取消的订单ID. 使用客户端命令ID来方便跟踪. 实施适当的订单状态监测.

资源

版本与发布记录

@decibeltrade/sdk 共发布 30 个版本,首次发布于 2025/11/30;过去 12 个月发布了 30 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.8.2latest2026/09/181 个月前
0.8.12026/09/171 个月前
0.8.02026/08/192 个月前
0.7.02026/06/164 个月前
0.6.02026/04/166 个月前
0.5.02026/04/077 个月前

关于 @decibeltrade/sdk 的常见问题

@decibeltrade/sdk 是什么?

用于与Decibel互动的TypeScript SDK,这是一款由Aptos所建的全链上交易引擎.

如何安装 @decibeltrade/sdk?

在项目目录运行 npm install @decibeltrade/sdk,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:zod(^3.25.62)、@types/ws(^8.18.0)、@aptos-labs/ts-sdk(^7.1.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@decibeltrade/sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@decibeltrade/sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@decibeltrade/sdk 可以商用吗?

@decibeltrade/sdk 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@decibeltrade/sdk 的下载量有多少?

根据 npm 官方下载统计,@decibeltrade/sdk 在 2026/10/12 – 2026/11/10 这 30 天内被下载 5,849 次,日均约 195 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@decibeltrade/sdk 还在维护吗?

最新版本 0.8.2 发布于 2026/09/18(1 个月前);至今共发布 30 个版本,其中过去 12 个月发布了 30 个;首次发布于 2025/11/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。