Skip to content

Commit

Permalink
Support for option module all.
Browse files Browse the repository at this point in the history
  • Loading branch information
nocodehummel committed Mar 18, 2024
1 parent 4dc2a42 commit 55bee5c
Show file tree
Hide file tree
Showing 32 changed files with 279 additions and 227 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"files.eol": "\n",
"prettier.singleQuote": false,
"prettier.quoteProps": "preserve",
}
4 changes: 2 additions & 2 deletions docs/modules/fundamentalsTimeSeries.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,8 @@ an array of symbols, and you'll receive an array of results back.
| ------------- | ----------| ---------- | --------------------------------- |
| `period1` | Date* | *required* | Starting period
| `period2` | Date* | (today) | Ending period
| `type` | "quarterly", "annual", "trailing" | "quarterly" | Financial time series type
| `module` | "income", "balance", "cashflow" | *required* | Financial statement module.
| `type` | "quarterly", "annual", "trailing" | "quarterly" | Reporting period type
| `module` | "income", "balance", "cashflow", "all" | *required* | Financial statement module
| `lang` | string | `"en-US"` | |
| `region` | string | `"US"` | |

Expand Down
17 changes: 16 additions & 1 deletion schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1327,10 +1327,25 @@
],
"additionalProperties": false
},
"NamedParameters<typeof processQuery>": {
"type": "object",
"properties": {
"queryOptions": {
"$ref": "#/definitions/FundamentalsTimeSeriesOptions",
"description": "Input query options."
}
},
"required": [
"queryOptions"
],
"additionalProperties": false
},
"NamedParameters<typeof processResponse>": {
"type": "object",
"properties": {
"response": {}
"response": {
"description": "Query response."
}
},
"required": [
"response"
Expand Down
11 changes: 10 additions & 1 deletion src/modules/fundamentalsTimeSeries.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe("fundamentalsTimeSeries", () => {
{
period1: "2020-01-01",
period2: "2024-01-01",
module: "income",
module: "all",
},
{
devel: `fundamentalsTimeSeries-${symbol}-2020-01-01-to-2021-01-01.json`,
Expand Down Expand Up @@ -79,6 +79,15 @@ describe("fundamentalsTimeSeries", () => {
).rejects.toThrow(/option module invalid/);
});

it("throws if module not set", async () => {
await expect(
yf.fundamentalsTimeSeries("TSLA", {
period1: "2020-01-01",
period2: "2021-01-01",
})
).rejects.toThrow(/called with invalid options/);
});

it("throws error with unexpected results", () => {
return expect(
yf.fundamentalsTimeSeries(
Expand Down
151 changes: 89 additions & 62 deletions src/modules/fundamentalsTimeSeries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,67 +74,7 @@ export default function fundamentalsTimeSeries(
schemaKey: "#/definitions/FundamentalsTimeSeriesOptions",
defaults: queryOptionsDefaults,
overrides: queryOptionsOverrides,
transformWith(
queryOptions: FundamentalsTimeSeriesOptions
): Partial<FundamentalsTimeSeriesOptions> {
// Convert dates
if (!queryOptions.period2) queryOptions.period2 = new Date();
const dates = ["period1", "period2"] as const;
for (const fieldName of dates) {
const value = queryOptions[fieldName];
if (value instanceof Date)
queryOptions[fieldName] = Math.floor(value.getTime() / 1000);
else if (typeof value === "string") {
const timestamp = new Date(value as string).getTime();

if (isNaN(timestamp))
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option '" +
fieldName +
"' invalid date provided: '" +
value +
"'"
);

queryOptions[fieldName] = Math.floor(timestamp / 1000);
}
}

if (queryOptions.period1 === queryOptions.period2) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() options `period1` and `period2` " +
"cannot share the same value."
);
}

// Validate timeseries type and module
if (!FundamentalsTimeSeries_Types.includes(queryOptions.type || "")) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option type invalid."
);
} else if (!queryOptions.module) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option module not set."
);
} else if (
!FundamentalsTimeSeries_Modules.includes(queryOptions.module || "")
) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option module invalid."
);
}

// Join the keys for the module into query types.
const keys = Timeseries_Keys[queryOptions.module];
const queryType =
queryOptions.type + keys.join(`,${queryOptions.type}`);

return {
period1: queryOptions.period1,
period2: queryOptions.period2,
type: queryType,
};
},
transformWith: processQuery,
},

result: {
Expand All @@ -151,9 +91,97 @@ export default function fundamentalsTimeSeries(
});
}

/**
* Transform the input options into query parameters.
* The options module defines which keys that are used in the query.
* The keys are joined together into the query parameter type and
* pre-fixed with the options type (e.g. annualTotalRevenue).
* @param queryOptions Input query options.
* @returns Query parameters.
*/
export const processQuery = function (
queryOptions: FundamentalsTimeSeriesOptions
): Partial<FundamentalsTimeSeriesOptions> {
// Convert dates
if (!queryOptions.period2) queryOptions.period2 = new Date();
const dates = ["period1", "period2"] as const;

for (const fieldName of dates) {
const value = queryOptions[fieldName];
if (value instanceof Date)
queryOptions[fieldName] = Math.floor(value.getTime() / 1000);
else if (typeof value === "string") {
const timestamp = new Date(value as string).getTime();

if (isNaN(timestamp))
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option '" +
fieldName +
"' invalid date provided: '" +
value +
"'"
);

queryOptions[fieldName] = Math.floor(timestamp / 1000);

Check warning on line 125 in src/modules/fundamentalsTimeSeries.ts

View check run for this annotation

Codecov / codecov/patch

src/modules/fundamentalsTimeSeries.ts#L125

Added line #L125 was not covered by tests
}
}

// Validate query parameters.
if (queryOptions.period1 === queryOptions.period2) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() options `period1` and `period2` " +
"cannot share the same value."
);
} else if (!FundamentalsTimeSeries_Types.includes(queryOptions.type || "")) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option type invalid."
);
} else if (!queryOptions.module) {
throw new Error(

Check warning on line 140 in src/modules/fundamentalsTimeSeries.ts

View check run for this annotation

Codecov / codecov/patch

src/modules/fundamentalsTimeSeries.ts#L140

Added line #L140 was not covered by tests
"yahooFinance.fundamentalsTimeSeries() option module not set."
);
} else if (
!FundamentalsTimeSeries_Modules.includes(queryOptions.module || "")
) {
throw new Error(
"yahooFinance.fundamentalsTimeSeries() option module invalid."
);
}

// Join the keys for the module into query types.
const keys = Object.entries(Timeseries_Keys).reduce(
(previous: Array<string>, [module, keys]) => {
if (queryOptions.module == "all") {
return previous.concat(keys);
} else if (module == queryOptions.module) {
return previous.concat(Timeseries_Keys[queryOptions.module]);
} else return previous;
},
[] as Array<string>
);
const queryType = queryOptions.type + keys.join(`,${queryOptions.type}`);

return {
period1: queryOptions.period1,
period2: queryOptions.period2,
type: queryType,
};
};

/**
* Transforms the time-series into an array with reported values per period.
* Each object represents a period and its properties are the data points.
* Financial statement content variates and keys are skipped when empty.
* The query keys include the option type (e.g. annualTotalRevenue).
* In the response the type is removed (e.g. totalRevenue) for
* easier mapping by the client.
* @param response Query response.
* @returns Formatted response.
*/
export const processResponse = function (response: any): any {
const keyedByTimestamp: Record<string, any> = {};
const replace = new RegExp(FundamentalsTimeSeries_Types.join("|"));

for (let ct = 0; ct < response.timeseries.result.length; ct++) {
const result = response.timeseries.result[ct];
if (!result.timestamp || !result.timestamp.length) {
Expand All @@ -174,7 +202,6 @@ export const processResponse = function (response: any): any {
continue;
}

// Extract the type from the dataKey for later mapping.
const short = dataKey.replace(replace, "");
const key =
short == short.toUpperCase()
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

0 comments on commit 55bee5c

Please sign in to comment.