1Branch0Tags
GL
glucryptoReserve only trade targets in price trigger profil...
4a63a6312 days ago20Commits
typescript
import { fetchHyperliquidAllMids, type HyperliquidEnvironment, } from "opentool/adapters/hyperliquid"; import { store } from "opentool/store"; import { wallet } from "opentool/wallet"; import type { WalletFullContext } from "opentool/wallet"; import type { PriceTriggerConfig } from "../config"; import { evaluateRule, resolveBudgetPerRule, type PriceTriggerRuleResult } from "./evaluate"; import { executeTriggeredRule } from "./execute"; import { readObservedPrice } from "./market"; import { readLatestState, type PriceTriggerRuleState } from "./state"; export type PriceTriggerBotResult = { ok: boolean; simulated: boolean; environment: HyperliquidEnvironment; amountUsd: number; maxPerRunUsd: number; triggeredRules: number; results: PriceTriggerRuleResult[]; state: Record<string, PriceTriggerRuleState>; }; export async function runPriceTriggerBot( config: PriceTriggerConfig, ): Promise<PriceTriggerBotResult> { const environment = config.execution?.environment ?? "mainnet"; const mids = await fetchHyperliquidAllMids(environment); const previousState = await readLatestState(); const evaluatedRules = await Promise.all( config.rules.map(async (rule) => { const currentPrice = await readObservedPrice({ environment, symbol: rule.sourceSymbol, mids, }); const prior = previousState[rule.id] ?? null; return { alreadyExecuted: Boolean(prior?.executedAt), currentPrice, previousState: prior, rule, triggered: !prior?.executedAt && evaluateRule({ rule, currentPrice, previousState: prior, }), }; }), ); const triggeredRules = evaluatedRules.filter((entry) => entry.triggered); const budgetPerRule = resolveBudgetPerRule(config, triggeredRules.length); const walletContext = config.execution?.enabled === true ? ((await wallet()) as WalletFullContext) : null; const results: PriceTriggerRuleResult[] = []; const nextState: Record<string, PriceTriggerRuleState> = {}; for (const entry of evaluatedRules) { let executedAt = entry.previousState?.executedAt ?? null; const targets = entry.triggered && walletContext && config.execution?.enabled ? await executeTriggeredRule({ config, environment, mids, rule: entry.rule, walletContext, budgetUsd: budgetPerRule, }) : []; const executedNow = targets.some( (target) => target.size !== "0" && target.orderResponse != null, ); if (executedNow && !executedAt) { executedAt = new Date().toISOString(); } nextState[entry.rule.id] = { lastObservedPrice: entry.currentPrice, ...(executedAt ? { executedAt } : {}), }; results.push({ id: entry.rule.id, sourceSymbol: entry.rule.sourceSymbol, condition: entry.rule.condition, threshold: entry.rule.threshold, currentPrice: entry.currentPrice, lastObservedPrice: entry.previousState?.lastObservedPrice ?? null, alreadyExecuted: entry.alreadyExecuted, executedAt, triggered: entry.triggered, actionSide: entry.rule.actionSide, targets, }); } const result: PriceTriggerBotResult = { ok: true, simulated: !config.execution?.enabled, environment, amountUsd: config.amountUsd, maxPerRunUsd: config.maxPerRunUsd, triggeredRules: triggeredRules.length, results, state: nextState, }; await store({ source: "price-trigger-bot", ref: `price-trigger-bot-${Date.now()}`, status: "info", action: "signal", metadata: result, }); return result; }