openpondai/agents/news-bot
OpenTool app
typescript
import type { ToolProfile } from "opentool";
import { backtestDecisionRequestSchema, resolveBacktestMode } from "opentool/backtest";
import { store } from "opentool/store";
import {
requestOverrideSchema,
resolveProfileAssets,
resolveRuntimeConfig,
resolveScheduleConfig,
NEWS_BOT_TEMPLATE_CONFIG,
} from "../src/config";
import {
buildBacktestDecisionSeries,
runSimpleNewsBot,
runSimpleNewsBotBacktest,
} from "../src/news-bot";
const config = resolveRuntimeConfig();
export const schema = requestOverrideSchema.or(backtestDecisionRequestSchema.partial());
type BacktestAwareToolProfile = ToolProfile & {
backtest?: {
mode: "decisions";
};
};
export const profile: BacktestAwareToolProfile = {
description: "News-driven strategy bot with optional Hyperliquid execution and replay support.",
category: "strategy",
backtest: {
mode: "decisions",
},
schedule: resolveScheduleConfig(config),
assets: resolveProfileAssets(config),
templatePreview: {
subtitle: "News signal strategy with execution-aware replay.",
description: `Reads a configured event or proposition signal from the gateway-backed news system.
Maps validated news outcomes to buy / close decisions.
Can submit standardized Hyperliquid orders when execution is enabled.
Supports hourly replay and decision-series backtests for event-driven strategy validation.`,
},
templateConfig: NEWS_BOT_TEMPLATE_CONFIG,
};
export async function POST(req: Request) {
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 = backtestDecisionRequestSchema.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 runtimeConfig = resolveRuntimeConfig();
const decisionSeries = await buildBacktestDecisionSeries({
config: runtimeConfig,
request: parsed.data,
});
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" },
});
}
}
const parsed = requestOverrideSchema.safeParse(payload ?? {});
if (!parsed.success) {
return new Response(
JSON.stringify({
ok: false,
error: parsed.error.issues[0]?.message ?? "invalid request payload",
}),
{
status: 400,
headers: { "content-type": "application/json" },
},
);
}
try {
const runtimeConfig = resolveRuntimeConfig(parsed.data);
const result = parsed.data.backtest
? await runSimpleNewsBotBacktest(runtimeConfig, parsed.data.backtest)
: await runSimpleNewsBot(runtimeConfig, parsed.data.asOf ?? null);
await store({
source: "news-bot",
ref: `news-bot-${Date.now()}`,
status: "info",
action: parsed.data.backtest ? "news_signal_backtest" : "news_signal",
metadata: result,
});
return Response.json(result);
} catch (error) {
const message = error instanceof Error ? error.message : "unknown";
await store({
source: "news-bot",
ref: `news-bot-${Date.now()}`,
status: "failed",
action: parsed.data.backtest ? "news_signal_backtest" : "news_signal",
metadata: { ok: false, error: message },
});
return new Response(JSON.stringify({ ok: false, error: message }), {
status: 400,
headers: { "content-type": "application/json" },
});
}
}