openpondai/agents/hip4-edge-bot
OpenTool app
typescript
import type { HyperliquidEnvironment } from "opentool/adapters/hyperliquid";
import { store } from "opentool/store";
import { wallet } from "opentool/wallet";
import type { WalletFullContext } from "opentool/wallet";
import type { Hip4EdgeBotConfig } from "../config";
import { executeHip4EdgeCandidate } from "./execute";
import { fetchHip4EdgeAnalytics } from "./gateway";
import { selectHip4EdgeCandidates } from "./select";
import { readLatestState } from "./state";
import type {
Hip4EdgeBotState,
Hip4EdgeCandidate,
Hip4EdgeExecutionResult,
Hip4GatewayAnalytics,
} from "./types";
export type Hip4EdgeBotResult = {
ok: boolean;
simulated: boolean;
environment: HyperliquidEnvironment;
amountUsd: number;
maxPerRunUsd: number;
selected: number;
submitted: number;
analytics: Hip4GatewayAnalytics;
candidates: Hip4EdgeCandidate[];
executions: Hip4EdgeExecutionResult[];
state: Hip4EdgeBotState;
};
function resolveBudgetPerTrade(config: Hip4EdgeBotConfig, selectedCount: number) {
if (selectedCount <= 0) return 0;
const perTradeCap = config.maxPerRunUsd / selectedCount;
return Math.min(config.amountUsd, perTradeCap);
}
export async function runHip4EdgeBot(
config: Hip4EdgeBotConfig,
): Promise<Hip4EdgeBotResult> {
const environment = config.execution.environment;
const [analytics, previousState] = await Promise.all([
fetchHip4EdgeAnalytics(config),
readLatestState(),
]);
const candidates = selectHip4EdgeCandidates({
config,
analytics,
markets: analytics.markets,
state: previousState,
});
const budgetPerTrade = resolveBudgetPerTrade(config, candidates.length);
const walletContext =
config.execution.enabled && candidates.length > 0
? ((await wallet()) as WalletFullContext)
: null;
const executions: Hip4EdgeExecutionResult[] = [];
const nextState: Hip4EdgeBotState = { ...previousState };
for (const candidate of candidates) {
if (!walletContext || !config.execution.enabled || budgetPerTrade <= 0) {
continue;
}
const execution = await executeHip4EdgeCandidate({
config,
environment,
walletContext,
candidate,
budgetUsd: budgetPerTrade,
});
executions.push(execution);
if (execution.orderResponse && execution.size !== "0") {
nextState[candidate.stateKey] = {
side: candidate.side,
seriesKey: candidate.seriesKey,
roundKey: candidate.roundKey,
marketDataCoin: candidate.marketDataCoin,
executedAt: new Date().toISOString(),
edge: candidate.edge,
roi: candidate.roi,
};
}
}
const result: Hip4EdgeBotResult = {
ok: true,
simulated: !config.execution.enabled,
environment,
amountUsd: config.amountUsd,
maxPerRunUsd: config.maxPerRunUsd,
selected: candidates.length,
submitted: executions.filter((execution) => execution.orderResponse).length,
analytics,
candidates,
executions,
state: nextState,
};
await store({
source: "hip4-edge-bot",
ref: `hip4-edge-bot-${Date.now()}`,
status: "info",
action: "signal",
metadata: result,
});
return result;
}