openpondai/agents/twap-bot
OpenTool app
typescript
import {
fetchHyperliquidAllMids,
fetchHyperliquidDexMetaAndAssetCtxs,
fetchHyperliquidPerpMarketInfo,
fetchHyperliquidResolvedMarketDescriptor,
fetchHyperliquidSpotMarketInfo,
normalizeHyperliquidMetaSymbol,
type HyperliquidEnvironment,
} from "opentool/adapters/hyperliquid";
import { normalizeMarketSymbol } from "../config/normalize";
export function isSpotSymbol(value: string) {
return value.includes("/") || value.includes(":");
}
export async function readObservedPrice(params: {
environment: HyperliquidEnvironment;
symbol: string;
}) {
const symbol = normalizeMarketSymbol(params.symbol);
const mids = await fetchHyperliquidAllMids(params.environment).catch(() => null);
const descriptor = await fetchHyperliquidResolvedMarketDescriptor({
environment: params.environment,
symbol,
...(mids ? { mids } : {}),
});
const midRaw = mids?.[descriptor.marketDataCoin];
const midPrice =
typeof midRaw === "number"
? midRaw
: typeof midRaw === "string"
? Number.parseFloat(midRaw)
: Number.NaN;
if (Number.isFinite(midPrice) && midPrice > 0) {
return midPrice;
}
if (descriptor.kind === "spot" || descriptor.kind === "spotIndex") {
const marketInfo = await fetchHyperliquidSpotMarketInfo({
environment: params.environment,
base: descriptor.base ?? symbol,
quote: descriptor.quote ?? "USDC",
...(mids ? { mids } : {}),
});
return marketInfo.price;
}
if (descriptor.dex) {
const data = (await fetchHyperliquidDexMetaAndAssetCtxs(
params.environment,
descriptor.dex,
)) as [{ universe?: Array<{ name?: string }> }, Array<Record<string, unknown>>];
const universe = Array.isArray(data?.[0]?.universe) ? data[0].universe : [];
const contexts = Array.isArray(data?.[1]) ? data[1] : [];
const target = normalizeHyperliquidMetaSymbol(descriptor.orderSymbol).toUpperCase();
const idx = universe.findIndex(
(entry) => normalizeHyperliquidMetaSymbol(entry?.name ?? "").toUpperCase() === target,
);
const ctx = idx >= 0 ? contexts[idx] : null;
const fallbackRaw = ctx?.markPx ?? ctx?.midPx ?? ctx?.oraclePx;
const fallbackPrice =
typeof fallbackRaw === "number"
? fallbackRaw
: typeof fallbackRaw === "string"
? Number.parseFloat(fallbackRaw)
: Number.NaN;
if (Number.isFinite(fallbackPrice) && fallbackPrice > 0) {
return fallbackPrice;
}
} else {
const marketInfo = await fetchHyperliquidPerpMarketInfo({
environment: params.environment,
symbol: descriptor.orderSymbol,
});
return marketInfo.price;
}
throw new Error(`Unable to resolve a live price for ${params.symbol}.`);
}