openpondai/agents/pair-trade
OpenTool app
typescript
import type { PairTradeConfig } from "./config";
import { resolvePairTradePerpSymbol } from "./runtime/market";
import type { PairTradeHistoricalFundingRatePoint } from "./runtime/types";
const DEFAULT_OPENPOND_BASE_URL = "https://api.openpond.ai";
function resolveBaseUrl(): string | null {
const raw = process.env.BASE_URL ?? DEFAULT_OPENPOND_BASE_URL;
if (typeof raw !== "string") return null;
const trimmed = raw.trim();
if (!trimmed) return null;
return trimmed.replace(/\/$/, "");
}
function resolveApiKey(): string | null {
const raw = process.env.OPENPOND_API_KEY;
if (typeof raw !== "string") return null;
const trimmed = raw.trim();
return trimmed.length > 0 ? trimmed : null;
}
type FundingPointResponse = {
time?: string;
rateBps?: number;
};
export async function loadPairTradeHistoricalFundingRates(params: {
config: PairTradeConfig;
timeframeStart: string;
timeframeEnd: string;
}): Promise<PairTradeHistoricalFundingRatePoint[]> {
const baseUrl = resolveBaseUrl();
const apiKey = resolveApiKey();
if (!baseUrl || !apiKey) return [];
const startMs = Date.parse(params.timeframeStart);
const endMs = Date.parse(params.timeframeEnd);
if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs <= startMs) {
return [];
}
const url = new URL(`${baseUrl}/apps/hyperliquid/funding-rates`);
url.searchParams.set("environment", params.config.environment);
url.searchParams.set("symbol", resolvePairTradePerpSymbol(params.config.shortAsset));
url.searchParams.set("startMs", String(startMs));
url.searchParams.set("endMs", String(endMs));
const response = await fetch(url.toString(), {
method: "GET",
headers: {
"openpond-api-key": apiKey,
accept: "application/json",
},
});
if (!response.ok) {
throw new Error(`Funding history request failed (${response.status}).`);
}
const data = (await response.json().catch(() => null)) as
| {
points?: FundingPointResponse[];
}
| null;
const points = Array.isArray(data?.points) ? data.points : [];
return points
.map((point) => {
if (!point || typeof point.time !== "string" || !Number.isFinite(point.rateBps)) {
return null;
}
return {
time: point.time,
rateBps: point.rateBps,
};
})
.filter((point): point is PairTradeHistoricalFundingRatePoint => Boolean(point));
}