2025-02-17 15:21:20 +07:00

166 lines
4.3 KiB
JavaScript

import { tool } from "ai";
import { z } from "zod";
import { queryBirdeye } from "./client.js";
const OHLCVTimeframe = {
OneMinute: "1m",
ThreeMinutes: "3m",
FiveMinutes: "5m",
FifteenMinutes: "15m",
ThirtyMinutes: "30m",
OneHour: "1H",
TwoHours: "2H",
FourHours: "4H",
SixHours: "6H",
EightHours: "8H",
TwelveHours: "12H",
OneDay: "1D",
ThreeDays: "3D",
OneWeek: "1W",
OneMonth: "1M",
};
const parseTimeString = (timeString) => {
//console.log(timeString);
const now = new Date();
if (timeString === "NOW") {
return Math.floor(now.getTime() / 1000); // Return in seconds for consistency
}
const regex = /^(\d+)([smHDWMy])$/;
const match = timeString.match(regex);
if (!match) {
throw new Error("Invalid time string format");
}
const value = parseInt(match[1]);
const unit = match[2];
switch (unit) {
case "m": // minutes
now.setMinutes(now.getMinutes() - value);
break;
case "H": // hours
now.setHours(now.getHours() - value);
break;
case "D": // days
now.setDate(now.getDate() - value);
break;
case "W": // weeks
now.setDate(now.getDate() - value * 7);
break;
case "M": // months
now.setMonth(now.getMonth() - value);
break;
case "Y": // years
now.setFullYear(now.getFullYear() - value);
break;
default:
return Math.floor(now.getTime() / 1000);
}
return Math.floor(now.getTime() / 1000);
};
const timeSchema = z.union([
z.literal("NOW"),
z.enum(Object.values(OHLCVTimeframe)),
]);
const timeEnum = z.enum([
"NOW",
OHLCVTimeframe.OneMinute,
OHLCVTimeframe.ThreeMinutes,
OHLCVTimeframe.FiveMinutes,
OHLCVTimeframe.FifteenMinutes,
OHLCVTimeframe.ThirtyMinutes,
OHLCVTimeframe.OneHour,
OHLCVTimeframe.TwoHours,
OHLCVTimeframe.FourHours,
OHLCVTimeframe.SixHours,
OHLCVTimeframe.EightHours,
OHLCVTimeframe.TwelveHours,
OHLCVTimeframe.OneDay,
OHLCVTimeframe.ThreeDays,
OHLCVTimeframe.OneWeek,
OHLCVTimeframe.OneMonth,
]);
const fetchOHLCVData = async ({
address,
timeframe = OHLCVTimeframe.FifteenMinutes,
timeFrom,
timeTo,
}) => {
const timeFromTimestamp = parseTimeString(timeFrom);
const timeToTimestamp = parseTimeString(timeTo);
//console.log(`Fetching OHLCV data for address: ${address}, timeframe: ${timeframe}, from: ${timeFromTimestamp} to: ${timeToTimestamp}`);
const response = await queryBirdeye("defi/ohlcv", {
address,
type: timeframe,
time_from: timeFromTimestamp,
time_to: timeToTimestamp,
});
if (response?.items) {
const last25Items = response.items.slice(-25);
// console.log(last25Items);
return {
type: timeframe,
items: last25Items.map(({ address, type, ...rest }) => rest),
};
}
return [];
};
export const getFetchOHLCVTool = (userId, chatId, responseId, dataStream) =>
tool({
description:
"Fetch OHLCV (Open, High, Low, Close, Volume) data for a given address and timeframe. The function returns 25 candlesticks maximum, so be sure to choose your time parameters wisely.",
parameters: z.object({
address: z.string().describe("The address to fetch OHLCV data for"),
timeframe: timeSchema
.describe("The timeframe for the OHLCV data (default is 15 minutes)")
.optional()
.default("15m"),
timeFrom: timeEnum.describe(
"The start time, either a timeframe or 'NOW'",
),
timeTo: timeEnum.describe("The end time, either a timeframe or 'NOW'"),
}),
execute: async ({ address, timeframe, timeFrom, timeTo }) => {
try {
console.log(
`${userId} ${chatId} called fetchOHLCVData with address: ${address} | timeframe: ${timeframe} | timeFrom: ${timeFrom} | timeTo: ${timeTo}`,
);
const ohlcvData = await fetchOHLCVData({
address,
timeframe,
timeFrom,
timeTo,
});
if (ohlcvData) {
dataStream.writeMessageAnnotation({
id: responseId,
tool_type: 'chart',
content: address,
});
}
return JSON.stringify(ohlcvData);
} catch (error) {
console.error(
`Error occurred while fetching OHLCV data: ${error.message}`,
);
return "Failed to fetch OHLCV data.";
}
},
});