@evatick/cli 0.4.1 → 0.4.2

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 CHANGED
@@ -45,6 +45,8 @@ eva stock bars --symbol cn:equity:XSHE:000001 \
45
45
  or alias.
46
46
  - `eva stock bars` queries normalized OHLCV bars.
47
47
  - `eva index constituents` queries index constituent memberships.
48
+ - `eva futures bars` queries official mainland China futures daily bars.
49
+ - `eva crypto quotes` queries one explicitly selected cryptocurrency exchange.
48
50
 
49
51
  Run `eva COMMAND --help` or `eva GROUP COMMAND --help` for supported options.
50
52
 
@@ -72,9 +74,10 @@ and `eva config show` masks stored keys.
72
74
  ## Current availability
73
75
 
74
76
  EVA Tick is designed as a provider-independent financial data layer. The
75
- current public service starts with mainland China A-shares and indices published
76
- by the Shanghai Stock Exchange, Shenzhen Stock Exchange, and China Securities
77
- Index. Availability varies by deployed service and enabled providers.
77
+ current public service covers mainland China A-shares; SSE, SZSE, and CSI
78
+ indices; CFFEX, SHFE, INE, and CZCE futures; and exchange-scoped Binance and
79
+ Coinbase cryptocurrency markets. Availability varies by deployed service and
80
+ enabled providers.
78
81
 
79
82
  ## Output and safety
80
83
 
package/lib/cli.js CHANGED
@@ -19,7 +19,7 @@ const ROOT_HELP = `NAME
19
19
  eva
20
20
 
21
21
  PURPOSE
22
- 通过 EVA 查询股票和指数数据。
22
+ 通过 EVA 查询股票、指数、中国期货和交易所加密货币数据。
23
23
 
24
24
  USAGE
25
25
  eva [--config PATH] [--server-url URL] [--api-key KEY] COMMAND [OPTIONS]
@@ -31,6 +31,8 @@ OPTIONS
31
31
 
32
32
  COMMANDS
33
33
  config
34
+ crypto
35
+ futures
34
36
  health
35
37
  index
36
38
  instrument
@@ -45,16 +47,22 @@ const HELP = {
45
47
  health: "Usage: eva health [OPTIONS]\n\nOptions:\n --timeout FLOAT [default: 10]\n --retries INTEGER [default: 0]\n --help\n",
46
48
  version: "Usage: eva version [OPTIONS]\n\nOptions:\n --help\n",
47
49
  instrument: "Usage: eva instrument [OPTIONS] COMMAND [ARGS]...\n\n Discover and resolve canonical instruments.\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n list\n resolve\n search\n show\n",
48
- "instrument list": "Usage: eva instrument list [OPTIONS]\n\nOptions:\n --type [equity|index]\n --venue TEXT\n --publisher TEXT\n --capability [quote|bars|constituents]\n --cursor TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
49
- "instrument search": "Usage: eva instrument search [OPTIONS]\n\nOptions:\n --query TEXT [required]\n --type [equity|index]\n --venue TEXT\n --publisher TEXT\n --capability [quote|bars|constituents]\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
50
- "instrument resolve": "Usage: eva instrument resolve [OPTIONS]\n\nOptions:\n --query TEXT [required]\n --type [equity|index]\n --venue TEXT\n --publisher TEXT\n --capability [quote|bars|constituents]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
50
+ "instrument list": "Usage: eva instrument list [OPTIONS]\n\nOptions:\n --type [equity|index|future|crypto]\n --venue TEXT\n --publisher TEXT\n --capability [quote|bars|constituents]\n --cursor TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
51
+ "instrument search": "Usage: eva instrument search [OPTIONS]\n\nOptions:\n --query TEXT [required]\n --type [equity|index|future|crypto]\n --venue TEXT\n --publisher TEXT\n --capability [quote|bars|constituents]\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
52
+ "instrument resolve": "Usage: eva instrument resolve [OPTIONS]\n\nOptions:\n --query TEXT [required]\n --type [equity|index|future|crypto]\n --venue TEXT\n --publisher TEXT\n --capability [quote|bars|constituents]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
51
53
  "instrument show": "Usage: eva instrument show [OPTIONS]\n\nOptions:\n --id TEXT [required]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
52
54
  stock: "Usage: eva stock [OPTIONS] COMMAND [ARGS]...\n\n Query mainland A-share data.\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n bars\n quotes\n",
53
55
  index: "Usage: eva index [OPTIONS] COMMAND [ARGS]...\n\n Query SSE, SZSE, and CSI index data.\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n bars\n constituents\n quotes\n",
56
+ futures: "Usage: eva futures [OPTIONS] COMMAND [ARGS]...\n\n Query mainland China futures contracts.\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n bars\n quotes\n",
57
+ crypto: "Usage: eva crypto [OPTIONS] COMMAND [ARGS]...\n\n Query exchange-scoped cryptocurrency market data.\n\nOptions:\n --help Show this message and exit.\n\nCommands:\n bars\n quotes\n",
54
58
  "stock quotes": "Usage: eva stock quotes [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
55
59
  "index quotes": "Usage: eva index quotes [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
56
- "stock bars": "Usage: eva stock bars [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --interval [1m|5m|15m|30m|60m|1d|1w|1mo] [default: 1d]\n --start TEXT\n --end TEXT\n --adjustment [none|forward|backward] [default: none]\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
57
- "index bars": "Usage: eva index bars [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --interval [1m|5m|15m|30m|60m|1d|1w|1mo] [default: 1d]\n --start TEXT\n --end TEXT\n --adjustment [none|forward|backward] [default: none]\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
60
+ "futures quotes": "Usage: eva futures quotes [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
61
+ "crypto quotes": "Usage: eva crypto quotes [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --venue [BINANCE|COINBASE] [required]\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
62
+ "stock bars": "Usage: eva stock bars [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --interval [1m|5m|15m|30m|60m|1d|1w|1mo] [default: 1d]\n --start TEXT\n --end TEXT\n --adjustment [none|forward|backward] [default: none]\n --as-of TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
63
+ "index bars": "Usage: eva index bars [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --interval [1m|5m|15m|30m|60m|1d|1w|1mo] [default: 1d]\n --start TEXT\n --end TEXT\n --adjustment [none|forward|backward] [default: none]\n --as-of TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
64
+ "futures bars": "Usage: eva futures bars [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --interval [1m|5m|15m|30m|60m|1d|1w|1mo] [default: 1d]\n --start TEXT\n --end TEXT\n --adjustment [none|forward|backward] [default: none]\n --as-of TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
65
+ "crypto bars": "Usage: eva crypto bars [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --venue [BINANCE|COINBASE] [required]\n --interval [1m|5m|15m|30m|60m|1d|1w|1mo] [default: 1d]\n --start TEXT\n --end TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
58
66
  "index constituents": "Usage: eva index constituents [OPTIONS]\n\nOptions:\n --symbol TEXT [required]\n --as-of TEXT\n --limit INTEGER\n --output PATH\n --format [json|jsonl|csv|parquet]\n --overwrite\n --timeout FLOAT [default: 120]\n --retries INTEGER [default: 2]\n --help\n",
59
67
  };
60
68
 
@@ -75,7 +83,7 @@ const dataDefinitions = {
75
83
  ...requestDefinitions,
76
84
  };
77
85
  const discoveryDefinitions = {
78
- type: { type: "choice", choices: ["equity", "index"] },
86
+ type: { type: "choice", choices: ["equity", "index", "future", "crypto"] },
79
87
  venue: { type: "string" },
80
88
  publisher: { type: "string" },
81
89
  capability: { type: "choice", choices: ["quote", "bars", "constituents"] },
@@ -316,13 +324,15 @@ async function dispatch(context, command, subcommand, arguments_) {
316
324
  process.stdout.write(`${dumps(response.data ?? {})}\n`);
317
325
  return;
318
326
  }
319
- if (key === "stock quotes" || key === "index quotes") {
327
+ if (key === "stock quotes" || key === "index quotes" || key === "futures quotes" || key === "crypto quotes") {
320
328
  const options = parseOptions(arguments_, {
321
- symbol: { type: "string" }, ...requestDefinitions,
322
- }, ["symbol"]);
323
- const instrumentType = command === "stock" ? "equity" : "index";
329
+ symbol: { type: "string" },
330
+ ...(command === "crypto" ? { venue: { type: "choice", choices: ["BINANCE", "COINBASE"] } } : {}),
331
+ ...requestDefinitions,
332
+ }, command === "crypto" ? ["symbol", "venue"] : ["symbol"]);
333
+ const instrumentType = command === "stock" ? "equity" : command === "index" ? "index" : command === "futures" ? "future" : "crypto";
324
334
  const http = client(context, options);
325
- const instrumentId = await http.resolve(options.symbol, instrumentType, "quote");
335
+ const instrumentId = await http.resolve(options.symbol, instrumentType, "quote", options.venue);
326
336
  const response = await http.request(
327
337
  "GET",
328
338
  `/v1/instruments/${encodeURIComponent(instrumentId)}/quote`,
@@ -330,25 +340,30 @@ async function dispatch(context, command, subcommand, arguments_) {
330
340
  process.stdout.write(`${dumps(response.data ?? {})}\n`);
331
341
  return;
332
342
  }
333
- if (key === "stock bars" || key === "index bars") {
343
+ if (key === "stock bars" || key === "index bars" || key === "futures bars" || key === "crypto bars") {
334
344
  const options = parseOptions(arguments_, {
335
345
  symbol: { type: "string" },
346
+ ...(command === "crypto" ? { venue: { type: "choice", choices: ["BINANCE", "COINBASE"] } } : {}),
336
347
  interval: { type: "choice", choices: INTERVALS, default: "1d" },
337
348
  start: { type: "string" },
338
349
  end: { type: "string" },
339
- adjustment: { type: "choice", choices: ["none", "forward", "backward"], default: "none" },
350
+ ...(command === "crypto" ? {} : {
351
+ adjustment: { type: "choice", choices: ["none", "forward", "backward"], default: "none" },
352
+ "as-of": { type: "string" },
353
+ }),
340
354
  ...dataDefinitions,
341
- }, ["symbol"]);
342
- const instrumentType = command === "stock" ? "equity" : "index";
355
+ }, command === "crypto" ? ["symbol", "venue"] : ["symbol"]);
356
+ const instrumentType = command === "stock" ? "equity" : command === "index" ? "index" : command === "futures" ? "future" : "crypto";
343
357
  const http = client(context, options);
344
- const instrumentId = await http.resolve(options.symbol, instrumentType, "bars");
358
+ const instrumentId = await http.resolve(options.symbol, instrumentType, "bars", options.venue);
345
359
  const response = await http.request(
346
360
  "GET",
347
361
  `/v1/instruments/${encodeURIComponent(instrumentId)}/bars?${queryString({
348
362
  interval: options.interval,
349
363
  start: options.start,
350
364
  end: options.end,
351
- adjustment: options.adjustment,
365
+ adjustment: options.adjustment || "none",
366
+ as_of: options.asOf,
352
367
  })}`,
353
368
  );
354
369
  emit(response.data ?? [], options);
@@ -374,7 +389,7 @@ async function dispatch(context, command, subcommand, arguments_) {
374
389
  function commandParts(remaining) {
375
390
  const command = remaining[0];
376
391
  if (!command) return {};
377
- if (!["config", "health", "version", "instrument", "stock", "index"].includes(command)) {
392
+ if (!["config", "health", "version", "instrument", "stock", "index", "futures", "crypto"].includes(command)) {
378
393
  throw usage(`No such command '${command}'.`);
379
394
  }
380
395
  if (["health", "version"].includes(command)) {
@@ -389,6 +404,8 @@ function commandParts(remaining) {
389
404
  instrument: ["list", "search", "resolve", "show"],
390
405
  stock: ["quotes", "bars"],
391
406
  index: ["quotes", "bars", "constituents"],
407
+ futures: ["quotes", "bars"],
408
+ crypto: ["quotes", "bars"],
392
409
  }[command];
393
410
  if (!valid.includes(subcommand)) throw usage(`No such command '${subcommand}'.`);
394
411
  return { command, subcommand, arguments_: remaining.slice(2) };
@@ -91,10 +91,20 @@ class EvaHttpClient {
91
91
  throw new Error("HTTP retry loop exhausted");
92
92
  }
93
93
 
94
- async resolve(query, instrumentType, capability) {
94
+ async resolve(query, instrumentType, capability, venue) {
95
+ const canonicalParts = query.split(":", 4);
96
+ if (
97
+ canonicalParts.length === 4 &&
98
+ canonicalParts[1] === instrumentType &&
99
+ (!venue || canonicalParts[2].toUpperCase() === venue.toUpperCase())
100
+ ) return query;
95
101
  const response = await this.request("POST", "/v1/instrument-resolve", {
96
102
  query,
97
- context: { instrument_type: instrumentType, capability },
103
+ context: {
104
+ instrument_type: instrumentType,
105
+ capability,
106
+ ...(venue ? { venue } : {}),
107
+ },
98
108
  });
99
109
  const data = response.data || {};
100
110
  const instrumentId = data.instrument && data.instrument.instrument_id;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evatick/cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "EVA Tick CLI for deterministic, machine-readable financial data queries by AI agents, LLMs, and automation",
5
5
  "license": "MIT",
6
6
  "repository": {