iturri 0.1.0
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/cli.mjs +42 -0
- package/index.mjs +50 -0
- package/package.json +12 -0
package/cli.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// iturri CLI — query the verified market-data catalog from the terminal.
|
|
3
|
+
// iturri catalog
|
|
4
|
+
// iturri bars BTC 1h --start 2024-01-01 --end 2024-02-01
|
|
5
|
+
// iturri features SPY 1d_split --start 2026-06-01
|
|
6
|
+
// iturri bundle crypto
|
|
7
|
+
|
|
8
|
+
import { catalog, bars, features, bundle } from "./index.mjs";
|
|
9
|
+
|
|
10
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
11
|
+
const flags = {};
|
|
12
|
+
const args = [];
|
|
13
|
+
for (let i = 0; i < rest.length; i++)
|
|
14
|
+
rest[i].startsWith("--") ? (flags[rest[i].slice(2)] = rest[++i]) : args.push(rest[i]);
|
|
15
|
+
|
|
16
|
+
const out = (x) => console.log(JSON.stringify(x, null, 1));
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
if (cmd === "catalog") {
|
|
20
|
+
const c = await catalog();
|
|
21
|
+
const syms = Object.entries(c.symbols).map(([s, v]) =>
|
|
22
|
+
`${s.padEnd(6)} ${v.asset.padEnd(7)} ${Object.keys(v.tfs).join(" ")}`);
|
|
23
|
+
console.log(`iturri catalog · ${syms.length} symbols · generated ${c.generated}\n`);
|
|
24
|
+
console.log(syms.join("\n"));
|
|
25
|
+
} else if (cmd === "bars") {
|
|
26
|
+
const rows = await bars(args[0], args[1], flags);
|
|
27
|
+
for (const r of rows.slice(0, Number(flags.limit ?? 20)))
|
|
28
|
+
console.log(r.timestamp.toISOString().slice(0, 16), r.open, r.high, r.low,
|
|
29
|
+
r.close, r.volume, r.quality);
|
|
30
|
+
if (rows.length > 20 && !flags.limit) console.log(`… ${rows.length} rows total (--limit N)`);
|
|
31
|
+
} else if (cmd === "features") {
|
|
32
|
+
out(await features(args[0], args[1], flags));
|
|
33
|
+
} else if (cmd === "bundle") {
|
|
34
|
+
out(await bundle(args[0]));
|
|
35
|
+
} else {
|
|
36
|
+
console.log("usage: iturri <catalog|bars|features|bundle> [args] [--start --end --limit]");
|
|
37
|
+
process.exit(cmd ? 1 : 0);
|
|
38
|
+
}
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.error(String(e.message ?? e));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
package/index.mjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// iturri — client for the Iturri verified market-data API.
|
|
2
|
+
// Every bar carries a quality flag; filter on it.
|
|
3
|
+
// Data and tooling only — never signals, predictions, or financial advice.
|
|
4
|
+
|
|
5
|
+
export const BASE_URL = "https://iturri-data.odd-haze-3940.workers.dev";
|
|
6
|
+
export const QUALITY = ["verified", "raw", "reconciled", "interpolated", "disputed", "outage"];
|
|
7
|
+
|
|
8
|
+
async function get(path, params) {
|
|
9
|
+
const url = new URL(BASE_URL + path);
|
|
10
|
+
for (const [k, v] of Object.entries(params ?? {}))
|
|
11
|
+
if (v !== undefined && v !== null) url.searchParams.set(k, v);
|
|
12
|
+
const r = await fetch(url);
|
|
13
|
+
if (!r.ok) throw new Error(`iturri api ${r.status}: ${(await r.json()).error ?? r.statusText}`);
|
|
14
|
+
return r.json();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Full catalog: symbols, timeframes, ranges, pricing, quality legend. Free. */
|
|
18
|
+
export const catalog = () => get("/api/catalog");
|
|
19
|
+
|
|
20
|
+
/** Quality-flagged OHLCV rows. tf: "1h" | "1d" | "1d_raw" | "1d_split". */
|
|
21
|
+
export async function bars(symbol, tf, { start, end } = {}) {
|
|
22
|
+
const r = await get("/api/bars", { symbol, tf, start, end });
|
|
23
|
+
const { t, o, h, l, c, v, q } = r.data;
|
|
24
|
+
return t.map((ts, i) => ({
|
|
25
|
+
timestamp: new Date(ts * 1000), open: o[i], high: h[i], low: l[i],
|
|
26
|
+
close: c[i], volume: v[i], quality: QUALITY[q[i]] ?? "raw",
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Leakage-safe feature matrix rows (19 documented features + regime). */
|
|
31
|
+
export async function features(symbol, tf, { start, end } = {}) {
|
|
32
|
+
const r = await get("/api/features", { symbol, tf, start, end });
|
|
33
|
+
const { t, ...cols } = r.data;
|
|
34
|
+
return t.map((ts, i) => ({
|
|
35
|
+
timestamp: new Date(ts * 1000),
|
|
36
|
+
...Object.fromEntries(Object.entries(cols).map(([k, arr]) => [k, arr[i]])),
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Signed download URLs for a training pack: "crypto" | "equities". */
|
|
41
|
+
export async function bundle(pack) {
|
|
42
|
+
const r = await fetch(BASE_URL + "/api/bundle", {
|
|
43
|
+
method: "POST", headers: { "content-type": "application/json" },
|
|
44
|
+
body: JSON.stringify({ pack }),
|
|
45
|
+
});
|
|
46
|
+
if (!r.ok) throw new Error(`iturri api ${r.status}`);
|
|
47
|
+
const out = await r.json();
|
|
48
|
+
out.signed_urls = (out.signed_urls ?? []).map((u) => BASE_URL + u);
|
|
49
|
+
return out;
|
|
50
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iturri",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Client + CLI for the Iturri verified market-data API — every bar verified or flagged",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.mjs",
|
|
7
|
+
"exports": "./index.mjs",
|
|
8
|
+
"bin": { "iturri": "cli.mjs" },
|
|
9
|
+
"engines": { "node": ">=18" },
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"files": ["index.mjs", "cli.mjs", "README.md"]
|
|
12
|
+
}
|