feat(data): extend market data provider with charts, fundamentals, and quant analysis

Adds a stock data cache layer and indicator helpers (MA/RSI/MACD), expands
the MarketDataProvider interface with candles, fundamentals, related-data,
and quant analysis, and threads tags + source attribution through the
shared types. Updates affected agent tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 23:20:42 +08:00
parent 30f6cd84a8
commit a4a2cb2ccf
12 changed files with 2187 additions and 32 deletions

View File

@@ -19,13 +19,13 @@ describe("WatchlistStore", () => {
const path = join(tempDir, "watchlist.json");
const store = new WatchlistStore(path);
await store.add("aapl", "Apple");
await store.add("aapl", "Apple", ["Core", " AI ", "Core"]);
await store.add("AAPL", "Duplicate");
await store.add("00700.HK", "Tencent");
expect(await store.list()).toEqual([
expect.objectContaining({ display: "AAPL", market: "US", name: "Apple" }),
expect.objectContaining({ display: "00700.HK", market: "HK", name: "Tencent" })
expect.objectContaining({ display: "AAPL", market: "US", name: "Apple", tags: ["Core", "AI"] }),
expect.objectContaining({ display: "00700.HK", market: "HK", name: "Tencent", tags: [] })
]);
const reloaded = new WatchlistStore(path);
@@ -41,4 +41,23 @@ describe("WatchlistStore", () => {
expect(await store.list()).toEqual([]);
});
it("updates tags for a persisted stock", async () => {
tempDir = await mkdtemp(join(tmpdir(), "stock-agent-"));
const store = new WatchlistStore(join(tempDir, "watchlist.json"));
await store.add("MSFT", "Microsoft");
await store.updateTags("MSFT.US", ["cloud", "quality"]);
expect((await store.list())[0]).toEqual(expect.objectContaining({ tags: ["cloud", "quality"] }));
});
it("canonicalizes persisted China ETF exchange suffixes", async () => {
tempDir = await mkdtemp(join(tmpdir(), "stock-agent-"));
const store = new WatchlistStore(join(tempDir, "watchlist.json"));
await store.add("512480.SZ", "Semiconductor ETF");
expect((await store.list())[0]).toEqual(expect.objectContaining({ display: "512480.SS", id: "512480.SS" }));
});
});