openpondai/agents/news-bot
OpenTool app
typescript
import { fetchHyperliquidBars } from "opentool/adapters/hyperliquid";
import type { SimpleNewsBotConfig } from "./config";
import { resolveExecutableMarketSymbol } from "./market-symbol";
import { evaluateGate, fetchSignal, type SimpleNewsBotSignal } from "./news-core";
import { buildBacktestDecisionSeries, runSimpleNewsBotBacktest, type NewsBacktestDecisionSeriesResult, type SimpleNewsBotBacktestResult } from "./news-backtest";
import { executeNewsTrade } from "./news-execution";
import { resolveNewsTradeDecision, type NewsTradeDecision } from "./news-trade";
export type SimpleNewsBotRunResult = {
ok: true;
mode: SimpleNewsBotConfig["mode"];
fetchedAt: string;
asOf: string | null;
price: number;
signal: SimpleNewsBotSignal;
gate: ReturnType<typeof evaluateGate>;
decision: NewsTradeDecision;
allocation: {
mode: SimpleNewsBotConfig["allocationMode"];
percentOfEquity: number | undefined;
maxPercentOfEquity: number | undefined;
amountUsd: number | undefined;
};
execution: Record<string, unknown>;
};
async function fetchCurrentPrice(config: SimpleNewsBotConfig): Promise<{ asOf: string; price: number }> {
const symbol = await resolveExecutableMarketSymbol(config);
const bars = await fetchHyperliquidBars({
symbol,
resolution: config.resolution,
countBack: Math.max(2, Math.min(config.countBack, 10)),
});
const bar = bars[bars.length - 1];
if (!bar) {
throw new Error("No price data returned.");
}
return {
asOf: new Date(bar.time).toISOString(),
price: bar.close,
};
}
export async function runSimpleNewsBot(
config: SimpleNewsBotConfig,
asOf?: string | null,
): Promise<SimpleNewsBotRunResult> {
const [signal, { asOf: priceAsOf, price }] = await Promise.all([
fetchSignal(config, asOf),
fetchCurrentPrice(config),
]);
const gate = evaluateGate(config, signal);
const decision = resolveNewsTradeDecision(config, signal, gate);
const execution = await executeNewsTrade({
config,
tradeSignal: decision.signal,
currentPrice: price,
});
if (!execution.ok) {
throw new Error(execution.error);
}
return {
ok: true,
mode: config.mode,
fetchedAt: new Date().toISOString(),
asOf: asOf ?? priceAsOf,
price,
signal,
gate,
decision,
allocation: {
mode: config.allocationMode,
percentOfEquity: config.percentOfEquity,
maxPercentOfEquity: config.maxPercentOfEquity,
amountUsd: config.amountUsd,
},
execution: execution.execution,
};
}
export {
buildBacktestDecisionSeries,
runSimpleNewsBotBacktest,
type NewsBacktestDecisionSeriesResult,
type SimpleNewsBotBacktestResult,
};