1Branch0Tags
GL
glucryptoReserve only trade targets in price trigger profil...
4a63a6312 days ago20Commits
typescript
import { buildHyperliquidMarketIdentity, extractHyperliquidOrderIds, fetchHyperliquidResolvedMarketDescriptor, fetchHyperliquidTickSize, formatHyperliquidMarketablePrice, formatHyperliquidOrderSize, placeHyperliquidOrder, resolveHyperliquidLeverageMode, updateHyperliquidLeverage, type HyperliquidEnvironment, type HyperliquidOrderResponse, } from "opentool/adapters/hyperliquid"; import { store } from "opentool/store"; import type { WalletFullContext } from "opentool/wallet"; import { normalizeSymbol, type PriceTriggerConfig, type PriceTriggerRule } from "../config"; import { readObservedPrice, readOrderSizeDecimals } from "./market"; import type { PriceTriggerTriggeredTarget } from "./evaluate"; export async function executeTriggeredRule(params: { config: PriceTriggerConfig; environment: HyperliquidEnvironment; mids: Record<string, string | number>; rule: PriceTriggerRule; walletContext: WalletFullContext; budgetUsd: number; }) { const totalWeight = params.rule.targets.reduce( (sum, target) => sum + target.weight, 0, ); const normalizedWeight = totalWeight > 0 ? totalWeight : 1; const targets: PriceTriggerTriggeredTarget[] = []; for (const target of params.rule.targets) { const targetSymbol = normalizeSymbol(target.symbol); const targetDescriptor = await fetchHyperliquidResolvedMarketDescriptor({ environment: params.environment, symbol: targetSymbol, mids: params.mids, }); const orderSymbol = targetDescriptor.orderSymbol; const isSpot = targetDescriptor.kind === "spot" || targetDescriptor.kind === "spotIndex"; const currentPrice = await readObservedPrice({ environment: params.environment, symbol: targetSymbol, mids: params.mids, }); const targetBudgetUsd = (params.budgetUsd * target.weight) / normalizedWeight; const rawSize = targetBudgetUsd / currentPrice; const sizeDecimals = await readOrderSizeDecimals({ environment: params.environment, descriptor: targetDescriptor, }); const tick = await fetchHyperliquidTickSize({ environment: params.environment, symbol: orderSymbol, }); const size = formatHyperliquidOrderSize(rawSize, sizeDecimals); const price = formatHyperliquidMarketablePrice({ mid: currentPrice, side: params.rule.actionSide, slippageBps: params.config.execution?.slippageBps ?? 50, tick, szDecimals: sizeDecimals, marketType: isSpot ? "spot" : "perp", }); if (size === "0") { targets.push({ symbol: targetSymbol, side: params.rule.actionSide, budgetUsd: targetBudgetUsd, size, price, }); continue; } if ( !isSpot && typeof params.config.execution?.leverage === "number" ) { const leverageMode = resolveHyperliquidLeverageMode(orderSymbol); await updateHyperliquidLeverage({ wallet: params.walletContext, environment: params.environment, input: { symbol: orderSymbol, leverageMode, leverage: params.config.execution.leverage, }, }); } const orderResponse = await placeHyperliquidOrder({ wallet: params.walletContext, environment: params.environment, orders: [ { symbol: orderSymbol, side: params.rule.actionSide, price, size, tif: "FrontendMarket", reduceOnly: false, }, ], }); const orderIds = extractHyperliquidOrderIds([ orderResponse as unknown as { response?: { data?: { statuses?: Array<Record<string, unknown>>; }; }; }, ]); const marketIdentity = buildHyperliquidMarketIdentity({ environment: params.environment, symbol: targetDescriptor.pair ?? orderSymbol, rawSymbol: orderSymbol, isSpot, base: targetDescriptor.base ?? targetSymbol.split(/[:/-]/)[0] ?? null, quote: targetDescriptor.quote, }); if (marketIdentity) { await store({ source: "hyperliquid", ref: orderIds.cloids[0] ?? orderIds.oids[0] ?? `price-trigger-bot-${Date.now()}-${targetSymbol}`, status: "submitted", walletAddress: params.walletContext.address, action: "order", notional: size, network: params.environment === "mainnet" ? "hyperliquid" : "hyperliquid-testnet", market: marketIdentity, metadata: { strategy: "price-trigger-bot", sourceSymbol: params.rule.sourceSymbol, threshold: params.rule.threshold, condition: params.rule.condition, side: params.rule.actionSide, symbol: targetSymbol, price, size, budgetUsd: targetBudgetUsd, cloid: orderIds.cloids[0] ?? null, orderIds, orderResponse, orderResponses: [orderResponse], }, }); } targets.push({ symbol: targetSymbol, side: params.rule.actionSide, budgetUsd: targetBudgetUsd, size, price, orderIds, orderResponse: orderResponse as HyperliquidOrderResponse, }); } return targets; }