@nshiab/simple-data-analysis-core 2.0.3 → 2.0.5
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/esm/class/SimpleTable.d.ts +202 -8
- package/esm/class/SimpleTable.d.ts.map +1 -1
- package/esm/class/SimpleTable.js +211 -9
- package/esm/methods/addCharacterCount.d.ts +3 -0
- package/esm/methods/addCharacterCount.d.ts.map +1 -0
- package/esm/methods/addCharacterCount.js +15 -0
- package/esm/methods/addGeoNoise.d.ts +7 -0
- package/esm/methods/addGeoNoise.d.ts.map +1 -0
- package/esm/methods/addGeoNoise.js +135 -0
- package/esm/methods/addNoise.d.ts +5 -0
- package/esm/methods/addNoise.d.ts.map +1 -0
- package/esm/methods/addNoise.js +53 -0
- package/esm/methods/addWordCount.d.ts +3 -0
- package/esm/methods/addWordCount.d.ts.map +1 -0
- package/esm/methods/addWordCount.js +15 -0
- package/esm/methods/columnProportions.d.ts +1 -0
- package/esm/methods/columnProportions.d.ts.map +1 -1
- package/esm/methods/columnProportions.js +7 -2
- package/esm/methods/loadArray.d.ts +4 -2
- package/esm/methods/loadArray.d.ts.map +1 -1
- package/esm/methods/loadArray.js +113 -4
- package/esm/methods/loadYahooFinanceData.d.ts +10 -0
- package/esm/methods/loadYahooFinanceData.d.ts.map +1 -0
- package/esm/methods/loadYahooFinanceData.js +133 -0
- package/esm/methods/rowProportions.d.ts +1 -0
- package/esm/methods/rowProportions.d.ts.map +1 -1
- package/esm/methods/rowProportions.js +5 -1
- package/llm.md +291 -14
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/script/class/SimpleTable.d.ts +202 -8
- package/script/class/SimpleTable.d.ts.map +1 -1
- package/script/class/SimpleTable.js +211 -9
- package/script/methods/addCharacterCount.d.ts +3 -0
- package/script/methods/addCharacterCount.d.ts.map +1 -0
- package/script/methods/addCharacterCount.js +21 -0
- package/script/methods/addGeoNoise.d.ts +7 -0
- package/script/methods/addGeoNoise.d.ts.map +1 -0
- package/script/methods/addGeoNoise.js +141 -0
- package/script/methods/addNoise.d.ts +5 -0
- package/script/methods/addNoise.d.ts.map +1 -0
- package/script/methods/addNoise.js +59 -0
- package/script/methods/addWordCount.d.ts +3 -0
- package/script/methods/addWordCount.d.ts.map +1 -0
- package/script/methods/addWordCount.js +21 -0
- package/script/methods/columnProportions.d.ts +1 -0
- package/script/methods/columnProportions.d.ts.map +1 -1
- package/script/methods/columnProportions.js +7 -2
- package/script/methods/loadArray.d.ts +4 -2
- package/script/methods/loadArray.d.ts.map +1 -1
- package/script/methods/loadArray.js +112 -3
- package/script/methods/loadYahooFinanceData.d.ts +10 -0
- package/script/methods/loadYahooFinanceData.d.ts.map +1 -0
- package/script/methods/loadYahooFinanceData.js +139 -0
- package/script/methods/rowProportions.d.ts +1 -0
- package/script/methods/rowProportions.d.ts.map +1 -1
- package/script/methods/rowProportions.js +5 -1
|
@@ -9,6 +9,10 @@ const assertNewColumns_js_1 = __importDefault(require("../helpers/assertNewColum
|
|
|
9
9
|
const queueOp_js_1 = __importDefault(require("../helpers/queueOp.js"));
|
|
10
10
|
const stringToArray_js_1 = __importDefault(require("../helpers/stringToArray.js"));
|
|
11
11
|
function columnProportions(simpleTable, column, newColumn, options = {}) {
|
|
12
|
+
if (options.base !== undefined &&
|
|
13
|
+
(!Number.isFinite(options.base) || options.base <= 0)) {
|
|
14
|
+
throw new Error("columnProportions() options.base must be a finite number greater than 0.");
|
|
15
|
+
}
|
|
12
16
|
options = structuredClone(options);
|
|
13
17
|
(0, queueOp_js_1.default)(simpleTable, {
|
|
14
18
|
kind: "fusable",
|
|
@@ -21,9 +25,10 @@ function columnProportions(simpleTable, column, newColumn, options = {}) {
|
|
|
21
25
|
const partition = by.length === 0
|
|
22
26
|
? ""
|
|
23
27
|
: `PARTITION BY ${by.map((d) => `${(0, quoteIdentifier_js_1.default)(d)}`).join(",")}`;
|
|
28
|
+
const proportion = `${(0, quoteIdentifier_js_1.default)(column)} / sum(${(0, quoteIdentifier_js_1.default)(column)}) OVER(${partition}) * ${options.base ?? 1}`;
|
|
24
29
|
return typeof options.decimals === "number"
|
|
25
|
-
? `SELECT *, ROUND(${
|
|
26
|
-
: `SELECT *, ${
|
|
30
|
+
? `SELECT *, ROUND(${proportion}, ${options.decimals}) AS ${(0, quoteIdentifier_js_1.default)(newColumn)} FROM ${input}`
|
|
31
|
+
: `SELECT *, ${proportion} AS ${(0, quoteIdentifier_js_1.default)(newColumn)} FROM ${input}`;
|
|
27
32
|
},
|
|
28
33
|
});
|
|
29
34
|
}
|
|
@@ -2,7 +2,7 @@ import { type DuckDBValue } from "@duckdb/node-api";
|
|
|
2
2
|
import type SimpleTable from "../class/SimpleTable.js";
|
|
3
3
|
export default function loadArray(simpleTable: SimpleTable, rows: {
|
|
4
4
|
[key: string]: unknown;
|
|
5
|
-
}[]): void;
|
|
5
|
+
}[], options?: NonNullable<Parameters<SimpleTable["loadArray"]>[1]>): void;
|
|
6
6
|
type PreparedArray = {
|
|
7
7
|
keys: string[];
|
|
8
8
|
types: string[];
|
|
@@ -11,7 +11,9 @@ type PreparedArray = {
|
|
|
11
11
|
};
|
|
12
12
|
export declare function prepareArray(rows: {
|
|
13
13
|
[key: string]: unknown;
|
|
14
|
-
}[]
|
|
14
|
+
}[], columnTypes?: {
|
|
15
|
+
[key: string]: string;
|
|
16
|
+
}): PreparedArray;
|
|
15
17
|
export declare function executePreparedArray(simpleTable: SimpleTable, prepared: PreparedArray): Promise<void>;
|
|
16
18
|
export {};
|
|
17
19
|
//# sourceMappingURL=loadArray.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadArray.d.ts","sourceRoot":"","sources":["../../src/methods/loadArray.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"loadArray.d.ts","sourceRoot":"","sources":["../../src/methods/loadArray.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAKvD,MAAM,CAAC,OAAO,UAAU,SAAS,CAC/B,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,EAClC,OAAO,GAAE,WAAW,CAAC,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAM,QAiBnE;AAED,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,WAAW,EAAE,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,YAAY,CAC1B,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,EAClC,WAAW,GAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAO,GAC1C,aAAa,CA2Ff;AAED,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,aAAa,iBA+BxB"}
|
|
@@ -11,12 +11,12 @@ const queueOp_js_1 = __importDefault(require("../helpers/queueOp.js"));
|
|
|
11
11
|
const parseTypes_js_1 = __importDefault(require("../helpers/parseTypes.js"));
|
|
12
12
|
const parseDuckDBType_js_1 = __importDefault(require("../helpers/parseDuckDBType.js"));
|
|
13
13
|
const quoteIdentifier_js_1 = __importDefault(require("../helpers/quoteIdentifier.js"));
|
|
14
|
-
function loadArray(simpleTable, rows) {
|
|
14
|
+
function loadArray(simpleTable, rows, options = {}) {
|
|
15
15
|
// This validation doesn't need the database, so it stays at call time.
|
|
16
16
|
if (rows.length === 0) {
|
|
17
17
|
throw new Error("The array is empty. loadArray needs at least one object to infer the column types.");
|
|
18
18
|
}
|
|
19
|
-
const prepared = prepareArray(rows);
|
|
19
|
+
const prepared = prepareArray(rows, options.columnTypes);
|
|
20
20
|
(0, queueOp_js_1.default)(simpleTable, {
|
|
21
21
|
kind: "barrier",
|
|
22
22
|
method: "loadArray()",
|
|
@@ -24,14 +24,38 @@ function loadArray(simpleTable, rows) {
|
|
|
24
24
|
execute: () => executePreparedArray(simpleTable, prepared),
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
function prepareArray(rows) {
|
|
27
|
+
function prepareArray(rows, columnTypes = {}) {
|
|
28
28
|
const keys = Object.keys(rows[0]);
|
|
29
|
+
const overrides = new Map();
|
|
30
|
+
for (const [key, type] of Object.entries(columnTypes)) {
|
|
31
|
+
if (!keys.includes(key)) {
|
|
32
|
+
throw new Error(`Unknown column ${JSON.stringify(key)} in loadArray columnTypes.`);
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const normalized = /^FLOAT\[[1-9]\d*\]$/i.test(type)
|
|
36
|
+
? type.toUpperCase()
|
|
37
|
+
: (0, parseTypes_js_1.default)(type);
|
|
38
|
+
(0, parseDuckDBType_js_1.default)(normalized);
|
|
39
|
+
overrides.set(key, normalized);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new Error(`Unsupported type ${JSON.stringify(type)} for column ${JSON.stringify(key)}.`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
29
45
|
const firstNonNullValue = keys.map((key) => rows.find((obj) => obj[key] !== null && obj[key] !== undefined)?.[key]);
|
|
30
46
|
const types = [];
|
|
31
47
|
const columnsData = keys.map(() => new Array(rows.length));
|
|
32
48
|
for (let i = 0; i < keys.length; i++) {
|
|
33
49
|
const key = keys[i];
|
|
34
50
|
const columnData = columnsData[i];
|
|
51
|
+
const override = overrides.get(key);
|
|
52
|
+
if (override !== undefined) {
|
|
53
|
+
types[i] = override;
|
|
54
|
+
for (let j = 0; j < rows.length; j++) {
|
|
55
|
+
columnData[j] = prepareTypedValue(rows[j][key], override, key, j + 1);
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
35
59
|
const value = firstNonNullValue[i];
|
|
36
60
|
const type = typeof value;
|
|
37
61
|
if (type === "symbol" || type === "function") {
|
|
@@ -104,3 +128,88 @@ async function executePreparedArray(simpleTable, prepared) {
|
|
|
104
128
|
}
|
|
105
129
|
appender.flushSync();
|
|
106
130
|
}
|
|
131
|
+
/** Validates and snapshots a value for an explicitly declared destination type. */
|
|
132
|
+
function prepareTypedValue(value, type, column, row) {
|
|
133
|
+
if (value === null || value === undefined || Number.isNaN(value))
|
|
134
|
+
return null;
|
|
135
|
+
let compatible = false;
|
|
136
|
+
if (type === "VARCHAR" && typeof value === "string")
|
|
137
|
+
return value;
|
|
138
|
+
if (type === "BOOLEAN" && typeof value === "boolean")
|
|
139
|
+
return value;
|
|
140
|
+
if (type === "DOUBLE") {
|
|
141
|
+
if (typeof value === "number")
|
|
142
|
+
return value;
|
|
143
|
+
compatible = typeof value === "bigint";
|
|
144
|
+
if (typeof value === "bigint") {
|
|
145
|
+
const number = Number(value);
|
|
146
|
+
if (Number.isFinite(number) && BigInt(number) === value)
|
|
147
|
+
return number;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else if (type === "INTEGER") {
|
|
151
|
+
compatible = typeof value === "number" || typeof value === "bigint";
|
|
152
|
+
if (typeof value === "number") {
|
|
153
|
+
if (Number.isInteger(value) && value >= -2147483648 && value <= 2147483647) {
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else if (typeof value === "bigint" && value >= -2147483648n && value <= 2147483647n) {
|
|
158
|
+
return Number(value);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (type === "BIGINT") {
|
|
162
|
+
compatible = typeof value === "number" || typeof value === "bigint";
|
|
163
|
+
if (typeof value === "bigint") {
|
|
164
|
+
if (value >= -9223372036854775808n && value <= 9223372036854775807n) {
|
|
165
|
+
return value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (typeof value === "number" && Number.isInteger(value) &&
|
|
169
|
+
value >= -(2 ** 63) && value < 2 ** 63) {
|
|
170
|
+
// The upper bound is exclusive: 2 ** 63 - 1 rounds up as a JS number.
|
|
171
|
+
return BigInt(value);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
else if (["DATE", "TIME", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE"].includes(type)) {
|
|
175
|
+
if (type === "TIME" && value instanceof node_api_1.DuckDBTimeValue) {
|
|
176
|
+
if (value.micros >= 0n && value.micros <= 86400000000n) {
|
|
177
|
+
return new node_api_1.DuckDBTimeValue(value.micros);
|
|
178
|
+
}
|
|
179
|
+
compatible = true;
|
|
180
|
+
}
|
|
181
|
+
else if (value instanceof Date) {
|
|
182
|
+
const millis = value.getTime();
|
|
183
|
+
compatible = Number.isFinite(millis);
|
|
184
|
+
if (compatible) {
|
|
185
|
+
if (type === "DATE" && millis % 86400000 === 0) {
|
|
186
|
+
return new node_api_1.DuckDBDateValue(millis / 86400000);
|
|
187
|
+
}
|
|
188
|
+
const micros = BigInt(millis) * 1000n;
|
|
189
|
+
if (type === "TIMESTAMP")
|
|
190
|
+
return new node_api_1.DuckDBTimestampValue(micros);
|
|
191
|
+
if (type === "TIMESTAMP WITH TIME ZONE") {
|
|
192
|
+
return new node_api_1.DuckDBTimestampTZValue(micros);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (type.startsWith("FLOAT[") && Array.isArray(value)) {
|
|
198
|
+
compatible = true;
|
|
199
|
+
const size = Number(type.slice(6, -1));
|
|
200
|
+
if (value.length === size &&
|
|
201
|
+
value.every((item) => item === null || item === undefined ||
|
|
202
|
+
(typeof item === "number" &&
|
|
203
|
+
(Number.isNaN(item) || Math.fround(item) === item)))) {
|
|
204
|
+
return (0, node_api_1.arrayValue)(value.map((item) => item === undefined || Number.isNaN(item)
|
|
205
|
+
? null
|
|
206
|
+
: item));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const displayed = typeof value === "string"
|
|
210
|
+
? JSON.stringify(value)
|
|
211
|
+
: String(value);
|
|
212
|
+
throw new Error(`Column ${JSON.stringify(column)}, row ${row}: value ${displayed} ${compatible
|
|
213
|
+
? `cannot be stored as ${type} without losing information`
|
|
214
|
+
: `is incompatible with ${type}`}. Select a type compatible with this value.`);
|
|
215
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
|
+
declare const INTERVAL_SECONDS: {
|
|
3
|
+
readonly "1d": number;
|
|
4
|
+
readonly "1h": number;
|
|
5
|
+
readonly "1m": 60;
|
|
6
|
+
};
|
|
7
|
+
type YahooInterval = keyof typeof INTERVAL_SECONDS;
|
|
8
|
+
export default function loadYahooFinanceData(table: SimpleTable, symbol: string, startDate: Date, endDate: Date, interval: YahooInterval): void;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=loadYahooFinanceData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadYahooFinanceData.d.ts","sourceRoot":"","sources":["../../src/methods/loadYahooFinanceData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAKvD,QAAA,MAAM,gBAAgB;;;;CAIZ,CAAC;AAeX,KAAK,aAAa,GAAG,MAAM,OAAO,gBAAgB,CAAC;AA6BnD,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAC1C,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,IAAI,EACb,QAAQ,EAAE,aAAa,GACtB,IAAI,CAeN"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = loadYahooFinanceData;
|
|
7
|
+
const SDAError_js_1 = __importDefault(require("../class/SDAError.js"));
|
|
8
|
+
const queueOp_js_1 = __importDefault(require("../helpers/queueOp.js"));
|
|
9
|
+
const loadArray_js_1 = require("./loadArray.js");
|
|
10
|
+
const INTERVAL_SECONDS = {
|
|
11
|
+
"1d": 24 * 60 * 60,
|
|
12
|
+
"1h": 60 * 60,
|
|
13
|
+
"1m": 60,
|
|
14
|
+
};
|
|
15
|
+
const COLUMN_TYPES = {
|
|
16
|
+
datetime: "TIMESTAMP",
|
|
17
|
+
open: "DOUBLE",
|
|
18
|
+
high: "DOUBLE",
|
|
19
|
+
low: "DOUBLE",
|
|
20
|
+
close: "DOUBLE",
|
|
21
|
+
adjustedClose: "DOUBLE",
|
|
22
|
+
volume: "DOUBLE",
|
|
23
|
+
};
|
|
24
|
+
const USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36";
|
|
25
|
+
function loadYahooFinanceData(table, symbol, startDate, endDate, interval) {
|
|
26
|
+
assertArguments(symbol, startDate, endDate, interval);
|
|
27
|
+
const request = {
|
|
28
|
+
symbol,
|
|
29
|
+
startDate: new Date(startDate),
|
|
30
|
+
endDate: new Date(endDate),
|
|
31
|
+
interval,
|
|
32
|
+
};
|
|
33
|
+
(0, queueOp_js_1.default)(table, {
|
|
34
|
+
kind: "barrier",
|
|
35
|
+
method: "loadYahooFinanceData()",
|
|
36
|
+
parameters: request,
|
|
37
|
+
execute: () => executeLoadYahooFinanceData(table, request),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async function executeLoadYahooFinanceData(table, request) {
|
|
41
|
+
try {
|
|
42
|
+
const rows = await getYahooFinanceData(request);
|
|
43
|
+
await (0, loadArray_js_1.executePreparedArray)(table, (0, loadArray_js_1.prepareArray)(rows, COLUMN_TYPES));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof SDAError_js_1.default) {
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
throw new SDAError_js_1.default({
|
|
50
|
+
method: "loadYahooFinanceData()",
|
|
51
|
+
parameters: request,
|
|
52
|
+
query: "",
|
|
53
|
+
cause: error,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function getYahooFinanceData(request) {
|
|
58
|
+
const { symbol, startDate, endDate, interval } = request;
|
|
59
|
+
const startTime = startDate.getTime();
|
|
60
|
+
const exclusiveEndTime = getExclusiveEndTime(endDate, interval);
|
|
61
|
+
const url = new URL(`https://query1.finance.yahoo.com/v8/finance/chart/${encodeURIComponent(symbol)}`);
|
|
62
|
+
url.search = new URLSearchParams({
|
|
63
|
+
includeAdjustedClose: "true",
|
|
64
|
+
interval,
|
|
65
|
+
period1: String(Math.floor(startTime / 1000)),
|
|
66
|
+
period2: String(Math.ceil(exclusiveEndTime / 1000)),
|
|
67
|
+
}).toString();
|
|
68
|
+
const response = await fetch(url, {
|
|
69
|
+
headers: { "User-Agent": USER_AGENT },
|
|
70
|
+
});
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
const text = (await response.text()).slice(0, 500).trim();
|
|
73
|
+
throw new Error(`Failed to fetch Yahoo Finance data: ${response.status} ${response.statusText}${text.length > 0 ? `. ${text}` : ""}. Yahoo may have changed, rate-limited, or disabled this undocumented endpoint.`);
|
|
74
|
+
}
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
if (data.chart?.error) {
|
|
77
|
+
throw new Error(data.chart.error.description ??
|
|
78
|
+
"Yahoo Finance returned an unknown error.");
|
|
79
|
+
}
|
|
80
|
+
const result = data.chart?.result?.[0];
|
|
81
|
+
const timestamps = result?.timestamp;
|
|
82
|
+
if (!result || !timestamps?.length) {
|
|
83
|
+
throw new Error("No Yahoo Finance data found.");
|
|
84
|
+
}
|
|
85
|
+
const quote = result.indicators?.quote?.[0];
|
|
86
|
+
const adjustedClose = result.indicators?.adjclose?.[0]?.adjclose;
|
|
87
|
+
const rows = [];
|
|
88
|
+
for (let index = 0; index < timestamps.length; index++) {
|
|
89
|
+
const timestamp = timestamps[index] * 1000;
|
|
90
|
+
if (Number.isFinite(timestamp) && timestamp >= startTime &&
|
|
91
|
+
timestamp < exclusiveEndTime) {
|
|
92
|
+
rows.push({
|
|
93
|
+
datetime: new Date(timestamp),
|
|
94
|
+
open: getFiniteValue(quote?.open, index),
|
|
95
|
+
high: getFiniteValue(quote?.high, index),
|
|
96
|
+
low: getFiniteValue(quote?.low, index),
|
|
97
|
+
close: getFiniteValue(quote?.close, index),
|
|
98
|
+
adjustedClose: getFiniteValue(adjustedClose, index),
|
|
99
|
+
volume: getFiniteValue(quote?.volume, index),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (rows.length === 0) {
|
|
104
|
+
throw new Error(`No Yahoo Finance data found for ${symbol}.`);
|
|
105
|
+
}
|
|
106
|
+
return rows;
|
|
107
|
+
}
|
|
108
|
+
function getFiniteValue(values, index) {
|
|
109
|
+
const value = values?.[index];
|
|
110
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
111
|
+
}
|
|
112
|
+
function getExclusiveEndTime(endDate, interval) {
|
|
113
|
+
const end = new Date(endDate);
|
|
114
|
+
if (interval === "1d") {
|
|
115
|
+
end.setUTCHours(0, 0, 0, 0);
|
|
116
|
+
}
|
|
117
|
+
else if (interval === "1h") {
|
|
118
|
+
end.setUTCMinutes(0, 0, 0);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
end.setUTCSeconds(0, 0);
|
|
122
|
+
}
|
|
123
|
+
return end.getTime() + INTERVAL_SECONDS[interval] * 1000;
|
|
124
|
+
}
|
|
125
|
+
function assertArguments(symbol, startDate, endDate, interval) {
|
|
126
|
+
if (typeof symbol !== "string" || symbol.trim().length === 0) {
|
|
127
|
+
throw new TypeError("loadYahooFinanceData() symbol must be a non-empty string.");
|
|
128
|
+
}
|
|
129
|
+
if (!(startDate instanceof Date) || !(endDate instanceof Date) ||
|
|
130
|
+
!Number.isFinite(startDate.getTime()) || !Number.isFinite(endDate.getTime())) {
|
|
131
|
+
throw new RangeError("loadYahooFinanceData() startDate and endDate must be valid dates.");
|
|
132
|
+
}
|
|
133
|
+
if (endDate.getTime() < startDate.getTime()) {
|
|
134
|
+
throw new RangeError("loadYahooFinanceData() endDate must be equal to or later than startDate.");
|
|
135
|
+
}
|
|
136
|
+
if (interval !== "1d" && interval !== "1h" && interval !== "1m") {
|
|
137
|
+
throw new Error('loadYahooFinanceData() interval must be "1d", "1h", or "1m".');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type SimpleTable from "../class/SimpleTable.js";
|
|
2
2
|
export default function rowProportions(simpleTable: SimpleTable, columns: string[], options?: {
|
|
3
3
|
suffix?: string;
|
|
4
|
+
base?: number;
|
|
4
5
|
decimals?: number;
|
|
5
6
|
}): void;
|
|
6
7
|
//# sourceMappingURL=rowProportions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rowProportions.d.ts","sourceRoot":"","sources":["../../src/methods/rowProportions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACd,
|
|
1
|
+
{"version":3,"file":"rowProportions.d.ts","sourceRoot":"","sources":["../../src/methods/rowProportions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACd,QA4CP"}
|
|
@@ -8,6 +8,10 @@ const quoteIdentifier_js_1 = __importDefault(require("../helpers/quoteIdentifier
|
|
|
8
8
|
const assertNewColumns_js_1 = __importDefault(require("../helpers/assertNewColumns.js"));
|
|
9
9
|
const queueOp_js_1 = __importDefault(require("../helpers/queueOp.js"));
|
|
10
10
|
function rowProportions(simpleTable, columns, options = {}) {
|
|
11
|
+
if (options.base !== undefined &&
|
|
12
|
+
(!Number.isFinite(options.base) || options.base <= 0)) {
|
|
13
|
+
throw new Error("rowProportions() options.base must be a finite number greater than 0.");
|
|
14
|
+
}
|
|
11
15
|
columns = [...columns];
|
|
12
16
|
options = structuredClone(options);
|
|
13
17
|
(0, queueOp_js_1.default)(simpleTable, {
|
|
@@ -20,7 +24,7 @@ function rowProportions(simpleTable, columns, options = {}) {
|
|
|
20
24
|
(0, assertNewColumns_js_1.default)(schema, columns.map((col) => `${col}${suffix}`), "rowProportions()");
|
|
21
25
|
let query = `SELECT *,`;
|
|
22
26
|
for (const col of columns) {
|
|
23
|
-
const tempQuery = `${(0, quoteIdentifier_js_1.default)(col)} / (${columns.map((d) => `${(0, quoteIdentifier_js_1.default)(d)}`).join(" + ")})`;
|
|
27
|
+
const tempQuery = `${(0, quoteIdentifier_js_1.default)(col)} / (${columns.map((d) => `${(0, quoteIdentifier_js_1.default)(d)}`).join(" + ")}) * ${options.base ?? 1}`;
|
|
24
28
|
if (typeof options.decimals === "number") {
|
|
25
29
|
query += ` ROUND(${tempQuery}, ${options.decimals})`;
|
|
26
30
|
}
|