feat(sector_radar): enhance sector radar functionality with active moneyflow and detailed metrics

- Introduced ActiveMoneyflowSource to fetch optional active-order flow, enhancing the sector radar's data capabilities.
- Updated StockFactRecord and DailyAggregateRecord to include pct_change and active_buy_net_amount_yuan for improved financial insights.
- Modified the build process to incorporate active moneyflow data without invalidating main rankings on failure.
- Enhanced the HTTP API to return detailed sector history and metrics, including pct_change and active buy metrics for members.
- Updated tests to validate the new functionality and ensure data integrity across various scenarios.
This commit is contained in:
yuxuanhui
2026-09-06 16:06:17 +08:00
parent 68282f5d46
commit 7f93d6b0f5
48 changed files with 4883 additions and 95 deletions
@@ -3,6 +3,8 @@ import { beforeEach, describe, expect, it, vi } from "vitest"
const useQuery = vi.hoisted(() => vi.fn())
const useInfiniteQuery = vi.hoisted(() => vi.fn())
const api = vi.hoisted(() => ({
getSectorRadarHistory: vi.fn(),
getSectorRadarDetail: vi.fn(),
getSectorRadarDates: vi.fn(),
getSectorRadarRankings: vi.fn(),
}))
@@ -11,6 +13,9 @@ vi.mock("@tanstack/react-query", () => ({ useInfiniteQuery, useQuery }))
vi.mock("./sector-radar.api", () => api)
import {
sectorRadarSectorQueryKey,
useSectorRadarDetail,
useSectorRadarHistory,
sectorRadarDatesQueryKey,
sectorRadarRankingsQueryKey,
useSectorRadarDates,
@@ -36,6 +41,42 @@ describe("sector radar query hooks", () => {
useInfiniteQuery.mockImplementation((options) => options)
})
it("isolates sector resources by type, code and date and forwards cancellation", () => {
const sector = {
sectorType: "concept" as const,
sectorCode: "BK01",
tradeDate: "2026-08-28",
}
const signal = new AbortController().signal
useSectorRadarDetail(sector)
const options = useQuery.mock.calls.at(-1)?.[0]
expect(options.queryKey).toEqual([
"sectorRadar",
"detail",
"concept",
"BK01",
"2026-08-28",
])
expect(options.placeholderData).toBeUndefined()
options.queryFn({ signal })
expect(api.getSectorRadarDetail).toHaveBeenCalledWith(sector, signal)
expect(
sectorRadarSectorQueryKey("detail", {
...sector,
tradeDate: "2026-08-31",
}),
).not.toEqual(options.queryKey)
expect(
sectorRadarSectorQueryKey("detail", {
...sector,
sectorType: "industry",
}),
).not.toEqual(options.queryKey)
useSectorRadarHistory(sector)
useQuery.mock.calls.at(-1)?.[0].queryFn({ signal })
expect(api.getSectorRadarHistory).toHaveBeenCalledWith(sector, signal)
})
it("keeps filters in one ranking key without splitting cached pages", () => {
expect(sectorRadarDatesQueryKey).toEqual(["sectorRadar", "dates"])
expect(sectorRadarRankingsQueryKey(query)).toEqual([