{"record":{"id":"8f3b2a599c1c52f5","repo":"jackwener/OpenCLI","slug":"no-data-8f3b2a","errorCode":"NO_DATA","errorMessage":"`No ${key} data returned`","messagePattern":"`No (.+?) data returned`","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"warning","filePath":"clis/eastmoney/northbound.js","lineNumber":41,"sourceCode":"  func: async (args) => {\n    const dir = String(args.direction ?? 'north').toLowerCase();\n    if (!['north', 'south', 'n', 's'].includes(dir)) {\n      throw new CliError('INVALID_ARGUMENT', `Unknown direction \"${dir}\". Valid: north / south`);\n    }\n    const limit = Math.max(1, Math.min(Number(args.limit) || 10, 240));\n\n    const url = new URL('https://push2.eastmoney.com/api/qt/kamtbs.rtmin/get');\n    url.searchParams.set('fields1', 'f1,f2,f3,f4');\n    url.searchParams.set('fields2', 'f51,f52,f54,f56');\n    url.searchParams.set('ut', 'b2884a393a59ad64002292a3e90d46a5');\n\n    const resp = await fetch(url, { headers: { 'User-Agent': 'Mozilla/5.0' } });\n    if (!resp.ok) throw new CliError('HTTP_ERROR', `northbound failed: HTTP ${resp.status}`);\n    const data = await resp.json();\n    const key = (dir === 'south' || dir === 's') ? 's2n' : 'n2s';\n    /** @type {string[]} */\n    const rows = Array.isArray(data?.data?.[key]) ? data.data[key] : [];\n    if (rows.length === 0) throw new CliError('NO_DATA', `No ${key} data returned`);\n\n    // CSV fields per entry: \"HH:MM,cumulative_net(万), minute_net(万), total_net(万)\"\n    // Drop rows with '-' (after market close or before open). Convert 万元 → 亿元 for readability.\n    const valid = rows\n      .map((r) => r.split(','))\n      .filter((c) => c.length >= 4 && c[1] !== '-');\n    if (valid.length === 0) {\n      throw new CliError('NO_DATA', `${key} has no valid minute data yet (markets may not be open)`);\n    }\n    return valid.slice(-limit).map(([time, cum, min, total]) => ({\n      time,\n      cumulativeNetYi: +(Number(cum) / 10000).toFixed(4),\n      minuteNetYi: +(Number(min) / 10000).toFixed(4),\n      totalNetYi: +(Number(total) / 10000).toFixed(4),\n    }));\n  },\n});\n","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/eastmoney/northbound.js#L23-L59","documentation":"After a successful HTTP call, northbound.js reads data.data[key] where key is 's2n' (southbound) or 'n2s' (northbound). If that field is missing or not an array, rows is [] and the command throws CliError NO_DATA with `No ${key} data returned`. This means eastmoney responded successfully but the payload contained no minute-bar series for the requested direction.","triggerScenarios":"The kamtbs.rtmin/get endpoint returns ok HTTP but data.data is null, or lacks the requested 'n2s'/'s2n' array — typically outside trading hours, during HK-mainland market holiday closures, or when eastmoney's feed is empty/partially degraded.","commonSituations":"Running the command on weekends, Chinese public holidays, or before market open; running after market close when eastmoney clears the intraday series; eastmoney API schema changes renaming the s2n/n2s keys; requesting southbound data on days when HK Connect south flow is suspended.","solutions":["Run the command during mainland A-share / HK trading hours (09:30–15:00 CST, weekdays)","Confirm it is not a HK Connect holiday (Connect closed days yield empty feeds)","Inspect the raw API response (curl the URL) to see whether data.data.s2n/n2s exists","If keys changed, update the key mapping in clis/eastmoney/northbound.js"],"exampleFix":"// before\nconst rows = Array.isArray(data?.data?.[key]) ? data.data[key] : [];\n// after — fallback to the opposite key or a clearer diagnostic\nconst rows = Array.isArray(data?.data?.[key]) ? data.data[key]\n  : Array.isArray(data?.data?.s2n) ? data.data.s2n : [];","handlingStrategy":"fallback","validationCode":"function isTradingWindow(d = new Date()) {\n  const day = d.getDay(); const h = d.getHours() + d.getMinutes() / 60;\n  return day >= 1 && day <= 5 && ((h >= 9.5 && h < 11.5) || (h >= 13 && h < 15));\n}\nif (!isTradingWindow()) console.warn('Outside A-share trading hours — empty feeds are expected');","typeGuard":"const hasFeed = (data, key) => Array.isArray(data?.data?.[key]) && data.data[key].length > 0;","tryCatchPattern":"try {\n  await runNorthbound(args);\n} catch (e) {\n  if (e.code === 'NO_DATA') console.warn(`Eastmoney feed empty for this direction/session — likely off-hours or holiday. ${e.message}`);\n  else throw e;\n}","preventionTips":["Schedule northbound jobs only during 09:30–15:00 CST on trading days","Maintain a HK Connect holiday calendar and skip those days","Treat NO_DATA during off-hours as expected, not an alert-worthy failure","Verify raw API payload shape periodically to catch key renames (s2n/n2s) early"],"tags":["empty-data","upstream-api","market-hours","eastmoney"],"backgroundTag":"upstream-empty-data","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}