@2oolkit/kiwoom-cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -1
- package/dist/index.js +66 -34
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +25 -7
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +14 -8
- package/skill/references/market-data.md +20 -13
package/README.md
CHANGED
|
@@ -106,7 +106,25 @@ kiwoom-cli chart week <코드> 주봉 (ka10082)
|
|
|
106
106
|
kiwoom-cli chart month <코드> 월봉 (ka10083)
|
|
107
107
|
kiwoom-cli chart year <코드> 년봉 (ka10094)
|
|
108
108
|
```
|
|
109
|
-
모두 `-n, --count <n>`(
|
|
109
|
+
모두 `-n, --count <n>`(봉 개수, 기본 50), `--raw`(수정주가 미적용), `-p, --paginate`(강제 다중 페이지) 지원.
|
|
110
|
+
|
|
111
|
+
**1회 요청당 최대 봉 개수 (per-request cap)** — 그 이상은 `cont-yn`/`next-key` 헤더로 **자동 페이지네이션**:
|
|
112
|
+
|
|
113
|
+
| 차트 | 1회 최대 | `--count` 한도 |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| tick / min | 900 | 100,000 (자동 분할) |
|
|
116
|
+
| day | 600 | 100,000 (자동 분할) |
|
|
117
|
+
| week | 300 | 100,000 (자동 분할) |
|
|
118
|
+
| month | 240 | 100,000 (자동 분할) |
|
|
119
|
+
| year | 30 | 100,000 (자동 분할) |
|
|
120
|
+
|
|
121
|
+
`--count`가 1회 최대를 넘으면 자동으로 여러 페이지를 받아 합칩니다(시간순 정렬·중복 제거는 API 순서를 그대로 유지). `-p/--paginate`로 강제할 수도 있습니다. `--count`는 양의 정수여야 하며 100,000으로 클램프됩니다.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
kiwoom-cli chart day 005930 -n 600 # 한 페이지(최대) — 일봉 600개
|
|
125
|
+
kiwoom-cli chart day 005930 -n 2000 -o json # 자동 페이지네이션 — 일봉 ~2000개
|
|
126
|
+
kiwoom-cli chart min 005930 -i 1 -n 2000 -o json # 1분봉 ~2000개 (여러 페이지)
|
|
127
|
+
```
|
|
110
128
|
|
|
111
129
|
### `account` — 계좌
|
|
112
130
|
```
|
package/dist/index.js
CHANGED
|
@@ -89,6 +89,15 @@ var ORDER_TYPES = {
|
|
|
89
89
|
"81": "\uC7A5\uB9C8\uAC10\uD6C4\uC2DC\uAC04\uC678"
|
|
90
90
|
};
|
|
91
91
|
var MARKET_ORDER_TYPES = /* @__PURE__ */ new Set(["3", "13", "23"]);
|
|
92
|
+
var CHART_PER_PAGE_CAP = {
|
|
93
|
+
tick: 900,
|
|
94
|
+
minute: 900,
|
|
95
|
+
day: 600,
|
|
96
|
+
week: 300,
|
|
97
|
+
month: 240,
|
|
98
|
+
year: 30
|
|
99
|
+
};
|
|
100
|
+
var CHART_MAX_COUNT = 1e5;
|
|
92
101
|
|
|
93
102
|
// src/config/store.ts
|
|
94
103
|
var DEFAULT_CONFIG = { env: "real" };
|
|
@@ -438,7 +447,7 @@ var KiwoomClient = class {
|
|
|
438
447
|
*/
|
|
439
448
|
async callEndpoint(def, body = {}, opts = {}) {
|
|
440
449
|
if (opts.paginate && def.listKey) {
|
|
441
|
-
const data = await this.requestAll(def.apiId, def.path, body, def.listKey);
|
|
450
|
+
const data = await this.requestAll(def.apiId, def.path, body, def.listKey, opts.maxPages);
|
|
442
451
|
return { data, contYn: false, nextKey: "" };
|
|
443
452
|
}
|
|
444
453
|
return this.request(def.apiId, def.path, body, {
|
|
@@ -448,9 +457,11 @@ var KiwoomClient = class {
|
|
|
448
457
|
}
|
|
449
458
|
/**
|
|
450
459
|
* Fetch all pages of a TR, concatenating the array under `listKey`.
|
|
451
|
-
* Caps at `maxPages` to avoid runaway loops
|
|
460
|
+
* Caps at `maxPages` to avoid runaway loops (default 100 — high enough for
|
|
461
|
+
* large chart pulls; callers pass a tighter bound when they know how many
|
|
462
|
+
* pages a target row count needs).
|
|
452
463
|
*/
|
|
453
|
-
async requestAll(apiId, path2, body, listKey, maxPages =
|
|
464
|
+
async requestAll(apiId, path2, body, listKey, maxPages = 100) {
|
|
454
465
|
let page = await this.request(apiId, path2, body);
|
|
455
466
|
const acc = Array.isArray(page.data[listKey]) ? [...page.data[listKey]] : [];
|
|
456
467
|
let pages = 1;
|
|
@@ -1254,81 +1265,102 @@ var CHART_ROW_FORMATTERS = {
|
|
|
1254
1265
|
pred_pre: unpad,
|
|
1255
1266
|
trde_tern_rt: unpad
|
|
1256
1267
|
};
|
|
1268
|
+
var PER_PAGE_CAP = CHART_PER_PAGE_CAP;
|
|
1269
|
+
function parseCount(raw) {
|
|
1270
|
+
const n = parseIntStrict(raw, "count");
|
|
1271
|
+
if (n < 1) {
|
|
1272
|
+
throw new ActionableError(`--count must be a positive integer (got ${n}).`);
|
|
1273
|
+
}
|
|
1274
|
+
return Math.min(n, CHART_MAX_COUNT);
|
|
1275
|
+
}
|
|
1257
1276
|
function emitChart(data, ep, fmt, count) {
|
|
1277
|
+
const all = Array.isArray(data[ep.listKey]) ? data[ep.listKey] : [];
|
|
1278
|
+
const sliced = all.slice(0, count);
|
|
1258
1279
|
if (fmt === "json") {
|
|
1259
|
-
output(data, "json");
|
|
1280
|
+
output({ ...data, [ep.listKey]: sliced }, "json");
|
|
1260
1281
|
return;
|
|
1261
1282
|
}
|
|
1262
|
-
|
|
1263
|
-
if (all.length === 0) {
|
|
1283
|
+
if (sliced.length === 0) {
|
|
1264
1284
|
console.log("No data");
|
|
1265
1285
|
return;
|
|
1266
1286
|
}
|
|
1267
1287
|
output(
|
|
1268
|
-
|
|
1288
|
+
sliced.map((row) => formatFields(row, CHART_ROW_FORMATTERS)),
|
|
1269
1289
|
"table"
|
|
1270
1290
|
);
|
|
1271
1291
|
}
|
|
1272
1292
|
function registerChartCommands(program2) {
|
|
1273
|
-
const chart = program2.command("chart").description(
|
|
1274
|
-
|
|
1293
|
+
const chart = program2.command("chart").description(
|
|
1294
|
+
"OHLC charts \u2014 tick / minute / daily / weekly / monthly / yearly. Per-request caps: tick/min 900, day 600, week 300, month 240, year 30. --count beyond the cap auto-paginates via cont-yn/next-key."
|
|
1295
|
+
);
|
|
1296
|
+
function planFetch(type, count, paginate) {
|
|
1297
|
+
const cap = PER_PAGE_CAP[type];
|
|
1298
|
+
const active = paginate || count > cap;
|
|
1299
|
+
const maxPages = active ? Math.max(1, Math.ceil(count / cap)) : 1;
|
|
1300
|
+
return { paginate: active, maxPages };
|
|
1301
|
+
}
|
|
1302
|
+
async function runIntraday(ep, type, code, ticScope, options) {
|
|
1275
1303
|
const client = createClient();
|
|
1276
1304
|
const stk = normalizeStockCode(code);
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1305
|
+
const count = parseCount(options.count);
|
|
1306
|
+
const plan = planFetch(type, count, !!options.paginate);
|
|
1307
|
+
const { data } = await client.callEndpoint(
|
|
1308
|
+
ep,
|
|
1309
|
+
{ stk_cd: stk, tic_scope: ticScope, upd_stkpc_tp: options.raw ? "0" : "1" },
|
|
1310
|
+
{ paginate: plan.paginate, maxPages: plan.maxPages }
|
|
1311
|
+
);
|
|
1312
|
+
emitChart(data, ep, getOutputFormat(options), count);
|
|
1283
1313
|
}
|
|
1284
|
-
async function runPeriod(ep, code, baseDt, options) {
|
|
1314
|
+
async function runPeriod(ep, type, code, baseDt, options) {
|
|
1285
1315
|
const client = createClient();
|
|
1286
1316
|
const stk = normalizeStockCode(code);
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1317
|
+
const count = parseCount(options.count);
|
|
1318
|
+
const plan = planFetch(type, count, !!options.paginate);
|
|
1319
|
+
const { data } = await client.callEndpoint(
|
|
1320
|
+
ep,
|
|
1321
|
+
{ stk_cd: stk, base_dt: baseDt, upd_stkpc_tp: options.raw ? "0" : "1" },
|
|
1322
|
+
{ paginate: plan.paginate, maxPages: plan.maxPages }
|
|
1323
|
+
);
|
|
1324
|
+
emitChart(data, ep, getOutputFormat(options), count);
|
|
1293
1325
|
}
|
|
1294
|
-
chart.command("tick <code>").description(
|
|
1326
|
+
chart.command("tick <code>").description(`Tick chart (ka10079) \u2014 up to ${PER_PAGE_CAP.tick} candles/request, auto-paginates beyond that`).option("-s, --scope <n>", "Ticks per candle (1/3/5/10/30)", "1").option("-n, --count <n>", "Number of candles (auto-paginates when > 900)", "50").option("-p, --paginate", "Force fetching multiple pages (cont-yn/next-key)").option("--raw", "Unadjusted (\uC218\uC815\uC8FC\uAC00 \uBBF8\uBC18\uC601) prices").option("-o, --output <format>", "Output format (table/json)", "table").action(async (code, options) => {
|
|
1295
1327
|
try {
|
|
1296
|
-
await runIntraday(ENDPOINTS.tickChart, code, options.scope, options);
|
|
1328
|
+
await runIntraday(ENDPOINTS.tickChart, "tick", code, options.scope, options);
|
|
1297
1329
|
} catch (err) {
|
|
1298
1330
|
handleError(err);
|
|
1299
1331
|
}
|
|
1300
1332
|
});
|
|
1301
|
-
chart.command("min <code>").alias("minute").description(
|
|
1333
|
+
chart.command("min <code>").alias("minute").description(`Minute chart (ka10080) \u2014 up to ${PER_PAGE_CAP.minute} candles/request, auto-paginates beyond that`).option("-i, --interval <n>", "Minutes per candle (1/3/5/10/15/30/45/60)", "1").option("-n, --count <n>", "Number of candles (auto-paginates when > 900)", "50").option("-p, --paginate", "Force fetching multiple pages (cont-yn/next-key)").option("--raw", "Unadjusted (\uC218\uC815\uC8FC\uAC00 \uBBF8\uBC18\uC601) prices").option("-o, --output <format>", "Output format (table/json)", "table").action(async (code, options) => {
|
|
1302
1334
|
try {
|
|
1303
|
-
await runIntraday(ENDPOINTS.minuteChart, code, options.interval, options);
|
|
1335
|
+
await runIntraday(ENDPOINTS.minuteChart, "minute", code, options.interval, options);
|
|
1304
1336
|
} catch (err) {
|
|
1305
1337
|
handleError(err);
|
|
1306
1338
|
}
|
|
1307
1339
|
});
|
|
1308
|
-
chart.command("day <code>").alias("daily").description(
|
|
1340
|
+
chart.command("day <code>").alias("daily").description(`Daily chart (ka10081) \u2014 up to ${PER_PAGE_CAP.day} candles/request, auto-paginates beyond that`).option("-d, --date <yyyymmdd>", "Base date (most recent candle)", todayKst()).option("-n, --count <n>", "Number of candles (auto-paginates when > 600)", "50").option("-p, --paginate", "Force fetching multiple pages (cont-yn/next-key)").option("--raw", "Unadjusted (\uC218\uC815\uC8FC\uAC00 \uBBF8\uBC18\uC601) prices").option("-o, --output <format>", "Output format (table/json)", "table").action(async (code, options) => {
|
|
1309
1341
|
try {
|
|
1310
|
-
await runPeriod(ENDPOINTS.dailyChart, code, options.date, options);
|
|
1342
|
+
await runPeriod(ENDPOINTS.dailyChart, "day", code, options.date, options);
|
|
1311
1343
|
} catch (err) {
|
|
1312
1344
|
handleError(err);
|
|
1313
1345
|
}
|
|
1314
1346
|
});
|
|
1315
|
-
chart.command("week <code>").description(
|
|
1347
|
+
chart.command("week <code>").description(`Weekly chart (ka10082) \u2014 up to ${PER_PAGE_CAP.week} candles/request, auto-paginates beyond that`).option("-d, --date <yyyymmdd>", "Base date (most recent candle)", todayKst()).option("-n, --count <n>", "Number of candles (auto-paginates when > 300)", "50").option("-p, --paginate", "Force fetching multiple pages (cont-yn/next-key)").option("--raw", "Unadjusted (\uC218\uC815\uC8FC\uAC00 \uBBF8\uBC18\uC601) prices").option("-o, --output <format>", "Output format (table/json)", "table").action(async (code, options) => {
|
|
1316
1348
|
try {
|
|
1317
|
-
await runPeriod(ENDPOINTS.weeklyChart, code, options.date, options);
|
|
1349
|
+
await runPeriod(ENDPOINTS.weeklyChart, "week", code, options.date, options);
|
|
1318
1350
|
} catch (err) {
|
|
1319
1351
|
handleError(err);
|
|
1320
1352
|
}
|
|
1321
1353
|
});
|
|
1322
|
-
chart.command("month <code>").description(
|
|
1354
|
+
chart.command("month <code>").description(`Monthly chart (ka10083) \u2014 up to ${PER_PAGE_CAP.month} candles/request, auto-paginates beyond that`).option("-d, --date <yyyymmdd>", "Base date (most recent candle)", todayKst()).option("-n, --count <n>", "Number of candles (auto-paginates when > 240)", "50").option("-p, --paginate", "Force fetching multiple pages (cont-yn/next-key)").option("--raw", "Unadjusted (\uC218\uC815\uC8FC\uAC00 \uBBF8\uBC18\uC601) prices").option("-o, --output <format>", "Output format (table/json)", "table").action(async (code, options) => {
|
|
1323
1355
|
try {
|
|
1324
|
-
await runPeriod(ENDPOINTS.monthlyChart, code, options.date, options);
|
|
1356
|
+
await runPeriod(ENDPOINTS.monthlyChart, "month", code, options.date, options);
|
|
1325
1357
|
} catch (err) {
|
|
1326
1358
|
handleError(err);
|
|
1327
1359
|
}
|
|
1328
1360
|
});
|
|
1329
|
-
chart.command("year <code>").description(
|
|
1361
|
+
chart.command("year <code>").description(`Yearly chart (ka10094) \u2014 up to ${PER_PAGE_CAP.year} candles/request, auto-paginates beyond that`).option("-d, --date <yyyymmdd>", "Base date (most recent candle)", todayKst()).option("-n, --count <n>", "Number of candles (auto-paginates when > 30)", "50").option("-p, --paginate", "Force fetching multiple pages (cont-yn/next-key)").option("--raw", "Unadjusted (\uC218\uC815\uC8FC\uAC00 \uBBF8\uBC18\uC601) prices").option("-o, --output <format>", "Output format (table/json)", "table").action(async (code, options) => {
|
|
1330
1362
|
try {
|
|
1331
|
-
await runPeriod(ENDPOINTS.yearlyChart, code, options.date, options);
|
|
1363
|
+
await runPeriod(ENDPOINTS.yearlyChart, "year", code, options.date, options);
|
|
1332
1364
|
} catch (err) {
|
|
1333
1365
|
handleError(err);
|
|
1334
1366
|
}
|