openpondai/agents/hyperliquid-delta-neutral
OpenTool app
2Branches0Tags
typescript
import { store } from "opentool/store";
import type { ToolProfile } from "opentool";
import { z } from "zod";
import {
buildBacktestDecisionSeriesInput,
backtestDecisionRequestSchema,
resolveBacktestMode,
} from "opentool/backtest";
import {
buildHyperliquidMarketIdentity,
HyperliquidApiError,
type HyperliquidOrderResponse,
} from "opentool/adapters/hyperliquid";
import {
DELTA_NEUTRAL_TEMPLATE_CONFIG,
readConfig,
resolveProfileAssets,
resolveScheduleConfig,
} from "../src/config";
import { buildBacktestDecisionSeries, runDeltaNeutral } from "../src/delta-neutral";
const config = readConfig();
const fundingRatePointSchema = z.object({
time: z.string().min(1),
rateBps: z.number(),
});
const deltaNeutralBacktestRequestSchema = backtestDecisionRequestSchema
.extend({
fundingRates: z.array(fundingRatePointSchema).optional(),
})
.partial();
export const schema = deltaNeutralBacktestRequestSchema;
type BacktestAwareToolProfile = ToolProfile & {
backtest?: {
mode: "decisions";
};
};
function buildFailureMetadata(error: unknown) {
const message = error instanceof Error ? error.message : "unknown";
return {
ok: false,
error: message,
errorType: error instanceof Error ? error.name : typeof error,
...(error instanceof HyperliquidApiError
? { errorResponse: error.response }
: {}),
};
}
function resolveOrderRef(params: {
response: HyperliquidOrderResponse | undefined;
fallbackCloid: string | undefined;
fallbackOid: string | undefined;
index: number;
}): string {
const statuses =
params.response &&
typeof params.response === "object" &&
params.response.response &&
typeof params.response.response === "object" &&
params.response.response.data &&
typeof params.response.response.data === "object" &&
Array.isArray((params.response.response.data as any).statuses)
? ((params.response.response.data as any).statuses as Array<Record<string, unknown>>)
: [];
for (const status of statuses) {
const filled =
status && typeof status.filled === "object"
? (status.filled as Record<string, unknown>)
: null;
if (filled) {
if (typeof filled.cloid === "string" && filled.cloid.trim().length > 0) {
return filled.cloid;
}
if (
typeof filled.oid === "number" ||
(typeof filled.oid === "string" && filled.oid.trim().length > 0)
) {
return String(filled.oid);
}
}
const resting =
status && typeof status.resting === "object"
? (status.resting as Record<string, unknown>)
: null;
if (resting) {
if (typeof resting.cloid === "string" && resting.cloid.trim().length > 0) {
return resting.cloid;
}
if (
typeof resting.oid === "number" ||
(typeof resting.oid === "string" && resting.oid.trim().length > 0)
) {
return String(resting.oid);
}
}
}
if (params.fallbackCloid && params.fallbackCloid.trim().length > 0) {
return params.fallbackCloid;
}
if (params.fallbackOid && params.fallbackOid.trim().length > 0) {
return params.fallbackOid;
}
return `delta-neutral-order-${Date.now()}-${params.index}`;
}
export const profile: BacktestAwareToolProfile = {
description: "Delta-neutral strategy (spot + perps) on Hyperliquid.",
category: "strategy",
backtest: {
mode: "decisions",
},
templatePreview: {
subtitle: "Spot and perp balancing to maintain a delta-neutral posture.",
description: `Monitors configured markets and computes hedge requirements each cycle.
Builds coordinated spot and perp orders to keep directional exposure balanced.
Uses standardized Hyperliquid execution and normalization helpers in OpenTool.
Includes risk-aware sizing controls for budget, leverage, and allocation limits.
Optimized for repeated autonomous operation with transparent execution logs.`,
},
schedule: resolveScheduleConfig(config),
assets: resolveProfileAssets(config),
templateConfig: DELTA_NEUTRAL_TEMPLATE_CONFIG,
};
async function executeLive() {
const snapshot = readConfig();
try {
const result = await runDeltaNeutral(snapshot);
const network =
result.environment === "testnet" ? "hyperliquid-testnet" : "hyperliquid";
const decisionAction = result.action ?? "delta-neutral";
const decisionRef = `delta-neutral-${Date.now()}`;
const {
orderResponses: _orderResponses,
orderIds: _orderIds,
executedOrders: _executedOrders,
...decisionResult
} = result;
await store({
source: "delta-neutral",
ref: decisionRef,
status: result.ok ? "info" : "failed",
eventLevel: "decision",
action: decisionAction,
network,
walletAddress: result.walletAddress
? (result.walletAddress as `0x${string}`)
: undefined,
metadata: {
...decisionResult,
decisionRef,
plannedOrderCount: result.plannedOrders.length,
executedOrderCount: result.executedOrders.length,
},
});
if (result.ok && result.executedOrders.length > 0) {
for (let index = 0; index < result.executedOrders.length; index += 1) {
const order = result.executedOrders[index];
if (!order) continue;
const response = result.orderResponses[index];
const market = buildHyperliquidMarketIdentity({
environment: result.environment,
symbol: order.symbol,
rawSymbol: order.symbol,
isSpot: order.kind === "spot",
base: order.kind === "spot" ? result.spotAsset : result.perpAsset,
quote: order.kind === "spot" ? "USDC" : null,
});
if (!market) continue;
const ref = resolveOrderRef({
response,
fallbackCloid: result.orderIds?.cloids[index],
fallbackOid: result.orderIds?.oids[index],
index,
});
await store({
source: "delta-neutral",
ref,
status: "submitted",
eventLevel: "execution",
action: "order",
network,
walletAddress: result.walletAddress
? (result.walletAddress as `0x${string}`)
: undefined,
notional: order.size,
market,
metadata: {
strategy: "delta-neutral",
parentDecisionRef: decisionRef,
executionRef: ref,
kind: order.kind,
side: order.side,
size: order.size,
price: order.price,
reduceOnly: Boolean(order.reduceOnly),
notionalUsd: order.notionalUsd,
orderResponse: response ?? null,
},
});
}
}
return Response.json(result);
} catch (error) {
const metadata = buildFailureMetadata(error);
await store({
source: "delta-neutral",
ref: `delta-neutral-${Date.now()}`,
status: "failed",
eventLevel: "decision",
action: "delta-neutral",
metadata,
});
return new Response(JSON.stringify(metadata), {
status: 400,
headers: { "content-type": "application/json" },
});
}
}
export async function POST(req: Request) {
const snapshot = readConfig();
const payload = await req.json().catch(() => null);
const mode =
payload && typeof payload === "object" && !Array.isArray(payload)
? (payload as { mode?: unknown }).mode
: null;
const normalizedMode = resolveBacktestMode(mode);
if (normalizedMode === "backtest_decisions") {
try {
const parsed = deltaNeutralBacktestRequestSchema.safeParse(payload);
if (!parsed.success) {
return new Response(
JSON.stringify({
ok: false,
error: parsed.error.issues[0]?.message ?? "invalid backtest request payload",
}),
{
status: 400,
headers: { "content-type": "application/json" },
}
);
}
const decisionSeries = await buildBacktestDecisionSeries({
config: snapshot,
...buildBacktestDecisionSeriesInput(parsed.data),
fundingRates: parsed.data.fundingRates,
});
return Response.json({
ok: true,
mode: normalizedMode,
backtest: decisionSeries,
});
} catch (error) {
const message = error instanceof Error ? error.message : "unknown";
return new Response(JSON.stringify({ ok: false, error: message }), {
status: 400,
headers: { "content-type": "application/json" },
});
}
}
return executeLive();
}