Skip to main content
Glama

Weather & Stock MCP Server

by Jeetinida
chart.js12.9 kB
// Co-authored by @gadicc, @PythonCreator27 and @huned. import { Type } from "@sinclair/typebox"; import { YahooFinanceDate, YahooNumber } from "../lib/yahooFinanceTypes.js"; const ChartMetaTradingPeriod = Type.Object({ timezone: Type.String(), // "EST", start: YahooFinanceDate, // new Date(1637355600 * 1000), end: YahooFinanceDate, // new Date(1637370000 * 10000), gmtoffset: YahooNumber, // -18000 }, { additionalProperties: Type.Any(), title: "ChartMetaTradingPeriod", }); const ChartMetaTradingPeriods = Type.Object({ pre: Type.Optional(Type.Array(Type.Array(ChartMetaTradingPeriod))), post: Type.Optional(Type.Array(Type.Array(ChartMetaTradingPeriod))), regular: Type.Optional(Type.Array(Type.Array(ChartMetaTradingPeriod))), }, { additionalProperties: Type.Any(), title: "ChartMetaTradingPeriods", }); const ChartResultArrayQuote = Type.Object({ date: YahooFinanceDate, high: Type.Union([YahooNumber, Type.Null()]), low: Type.Union([YahooNumber, Type.Null()]), open: Type.Union([YahooNumber, Type.Null()]), close: Type.Union([YahooNumber, Type.Null()]), volume: Type.Union([YahooNumber, Type.Null()]), adjclose: Type.Optional(Type.Union([YahooNumber, Type.Null()])), }, { additionalProperties: Type.Any(), title: "ChartResultArrayQuote", }); const ChartEventDividend = Type.Object({ amount: YahooNumber, date: YahooFinanceDate, }, { additionalProperties: Type.Any(), title: "ChartEventDividend", }); const ChartEventDividends = Type.Object({}, { additionalProperties: ChartEventDividend, title: "ChartEventDividends", }); const ChartEventSplit = Type.Object({ date: YahooFinanceDate, // new Date(1598880600 * 1000) numerator: YahooNumber, // 4 denominator: YahooNumber, // 1 splitRatio: Type.String(), // "4:1" }, { additionalProperties: Type.Any(), }); const ChartEventsArray = Type.Object({ dividends: Type.Optional(Type.Array(ChartEventDividend)), splits: Type.Optional(Type.Array(ChartEventSplit)), }, { additionalProperties: Type.Any(), title: "ChartEventsArray", }); const ChartMeta = Type.Object({ currency: Type.String(), // "USD" symbol: Type.String(), // "AAPL", exchangeName: Type.String(), // "NMS", instrumentType: Type.String(), // "EQUITY", firstTradeDate: Type.Union([YahooFinanceDate, Type.Null()]), // new Date(345479400 * 1000); null in e.g. "APS.AX" regularMarketTime: YahooFinanceDate, // new Date(1637355602 * 1000), gmtoffset: YahooNumber, // -18000, timezone: Type.String(), /// "EST", exchangeTimezoneName: Type.String(), // "America/New_York", regularMarketPrice: YahooNumber, // 160.55, chartPreviousClose: Type.Optional(YahooNumber), // 79.75; missing in e.g. "APS.AX" previousClose: Type.Optional(YahooNumber), // 1137.06 scale: Type.Optional(YahooNumber), // 3, priceHint: YahooNumber, // 2, currentTradingPeriod: Type.Object({ pre: ChartMetaTradingPeriod, regular: ChartMetaTradingPeriod, post: ChartMetaTradingPeriod, }, { additionalProperties: Type.Any(), }), tradingPeriods: Type.Optional( // TODO, would be great to use correct type as a generic based on // `includePrePost` and `interval`, see #812. Type.Union([ ChartMetaTradingPeriods, Type.Array(Type.Array(ChartMetaTradingPeriod)), ])), dataGranularity: Type.String(), // "1d", range: Type.String(), // "" validRanges: Type.Array(Type.String()), // ["1d", "5d", "1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "ytd", "max"] }, { additionalProperties: Type.Any(), title: "ChartMeta", }); const ChartResultArraySchema = Type.Object({ meta: ChartMeta, events: Type.Optional(ChartEventsArray), quotes: Type.Array(ChartResultArrayQuote), }, { title: "ChartResultArray" }); const ChartEventSplits = Type.Object({}, { additionalProperties: ChartEventSplit, title: "ChartEventSplits", }); const ChartIndicatorQuote = Type.Object({ high: Type.Array(Type.Union([YahooNumber, Type.Null()])), low: Type.Array(Type.Union([YahooNumber, Type.Null()])), open: Type.Array(Type.Union([YahooNumber, Type.Null()])), close: Type.Array(Type.Union([YahooNumber, Type.Null()])), volume: Type.Array(Type.Union([YahooNumber, Type.Null()])), }, { additionalProperties: Type.Any(), title: "ChartIndicatorQuote", }); const ChartIndicatorAdjclose = Type.Object({ adjclose: Type.Optional(Type.Array(Type.Union([YahooNumber, Type.Null()]))), // Missing in e.g. "APS.AX" }, { additionalProperties: Type.Any(), title: "ChartIndicatorAdjClose", }); const ChartEventsObject = Type.Object({ dividends: Type.Optional(ChartEventDividends), splits: Type.Optional(ChartEventSplits), }, { additionalProperties: Type.Any(), }); const ChartIndicatorsObject = Type.Object({ quote: Type.Array(ChartIndicatorQuote), adjclose: Type.Optional(Type.Array(ChartIndicatorAdjclose)), }, { additionalProperties: Type.Any(), title: "ChartIndicatorObject", }); const ChartResultObjectSchema = Type.Object({ meta: ChartMeta, timestamp: Type.Optional(Type.Array(YahooNumber)), events: Type.Optional(ChartEventsObject), indicators: ChartIndicatorsObject, }, { additionalProperties: Type.Any(), title: "ChartResultObject", }); export const ChartOptionsSchema = Type.Object({ period1: Type.Union([Type.Date(), Type.String(), YahooNumber]), period2: Type.Optional(Type.Union([Type.Date(), Type.String(), YahooNumber])), useYfid: Type.Optional(Type.Boolean()), // true interval: Type.Optional(Type.Union([ Type.Literal("1m"), Type.Literal("2m"), Type.Literal("5m"), Type.Literal("15m"), Type.Literal("30m"), Type.Literal("60m"), Type.Literal("90m"), Type.Literal("1h"), Type.Literal("1d"), Type.Literal("5d"), Type.Literal("1wk"), Type.Literal("1mo"), Type.Literal("3mo"), ])), includePrePost: Type.Optional(Type.Boolean()), // true events: Type.Optional(Type.String()), // 'history', lang: Type.Optional(Type.String()), // "en-US" return: Type.Optional(Type.Union([Type.Literal("array"), Type.Literal("object")])), }, { title: "ChartOptions", }); const ChartOptionsWithReturnArraySchema = Type.Composite([ ChartOptionsSchema, Type.Object({ return: Type.Optional(Type.Literal("array")), }), ], { title: "ChartOptionsWithReturnArray", }); const ChartOptionsWithReturnObjectSchema = Type.Composite([ ChartOptionsSchema, Type.Object({ return: Type.Literal("object"), }), ], { title: "ChartOptionsWithReturnObject", }); const queryOptionsDefaults = { useYfid: true, interval: "1d", includePrePost: true, events: "div|split|earn", lang: "en-US", return: "array", }; /* --- array input, typed output, honor "return" param --- */ // TODO: make this a deprecration passthrough export const _chart = chart; export default async function chart(symbol, queryOptionsOverrides, moduleOptions) { var _a, _b, _c; const returnAs = (queryOptionsOverrides === null || queryOptionsOverrides === void 0 ? void 0 : queryOptionsOverrides.return) || "array"; const result = (await this._moduleExec({ moduleName: "chart", query: { assertSymbol: symbol, url: "https://${YF_QUERY_HOST}/v8/finance/chart/" + symbol, schema: ChartOptionsSchema, defaults: queryOptionsDefaults, overrides: queryOptionsOverrides, transformWith(queryOptions) { if (!queryOptions.period2) queryOptions.period2 = new Date(); const dates = ["period1", "period2"]; for (const fieldName of dates) { const value = queryOptions[fieldName]; if (value instanceof Date) { queryOptions[fieldName] = Math.floor(value.getTime() / 1000); } else if (typeof value === "string") { const timestamp = new Date(value).getTime(); if (isNaN(timestamp)) throw new Error("yahooFinance.chart() option '" + fieldName + "' invalid date provided: '" + value + "'"); queryOptions[fieldName] = Math.floor(timestamp / 1000); } } if (queryOptions.period1 === queryOptions.period2) { throw new Error("yahooFinance.chart() options `period1` and `period2` " + "cannot share the same value."); } // Don't pass this on to Yahoo delete queryOptions.return; return queryOptions; }, }, result: { schema: ChartResultObjectSchema, transformWith(result) { if (!result.chart) throw new Error("Unexpected result: " + JSON.stringify(result)); const chart = result.chart.result[0]; // If there are no quotes, chart.timestamp will be empty, but Yahoo also // gives us chart.indicators.quotes = [{}]. Let's clean that up and // deliver an empty array rather than an invalid ChartIndicatorQuote/ if (!chart.timestamp) { if (chart.indicators.quote.length !== 1) throw new Error("No timestamp with quotes.length !== 1, please report with your query"); if (Object.keys(chart.indicators.quote[0]).length !== 0) // i.e. {} throw new Error("No timestamp with unexpected quote, please report with your query" + JSON.stringify(chart.indicators.quote[0])); chart.indicators.quote.pop(); } return chart; }, }, moduleOptions, })); if (returnAs === "object") { return result; } else if (returnAs === "array") { const timestamp = result.timestamp; /* seems as though yahoo inserts extra quotes at the event times, so no need. if (result.events) { for (let event of ["dividends", "splits"]) { // @ts-ignore if (result.events[event]) // @ts-ignore timestamp = timestamp.filter((ts) => !result.events[event][ts]); } } */ // istanbul ignore next if (timestamp && ((_a = result === null || result === void 0 ? void 0 : result.indicators) === null || _a === void 0 ? void 0 : _a.quote) && result.indicators.quote[0].high.length !== timestamp.length) { console.log({ origTimestampSize: result.timestamp && result.timestamp.length, filteredSize: timestamp.length, quoteSize: result.indicators.quote[0].high.length, }); throw new Error("Timestamp count mismatch, please report this with the query you used"); } const result2 = { meta: result.meta, quotes: timestamp ? new Array(timestamp.length) : [], }; const adjclose = (_c = (_b = result === null || result === void 0 ? void 0 : result.indicators) === null || _b === void 0 ? void 0 : _b.adjclose) === null || _c === void 0 ? void 0 : _c[0].adjclose; if (timestamp) for (let i = 0; i < timestamp.length; i++) { result2.quotes[i] = { date: new Date(timestamp[i] * 1000), high: result.indicators.quote[0].high[i], volume: result.indicators.quote[0].volume[i], open: result.indicators.quote[0].open[i], low: result.indicators.quote[0].low[i], close: result.indicators.quote[0].close[i], }; if (adjclose) result2.quotes[i].adjclose = adjclose[i]; } if (result.events) { result2.events = {}; for (const event of ["dividends", "splits"]) { // @ts-expect-error (eatkinson): Fix up type in follow up if (result.events[event]) // @ts-expect-error (eatkinson): Fix up type in follow up result2.events[event] = Object.values(result.events[event]); } } return result2; } // TypeScript runtime validation ensures no other values for // "returnAs" are possible. }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jeetinida/stocknews-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server