diff --git a/package-lock.json b/package-lock.json index 39f2a540..2240727b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "greeks": "^1.0.0", "html2canvas": "^1.4.1", "https": "^1.0.0", + "jsconfig.json": "^2.3.3", "marked": "^12.0.2", "mode-watcher": "^0.3.1", "sharp": "^0.33.5", @@ -4006,7 +4007,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -4574,7 +4574,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -5090,7 +5089,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5281,8 +5279,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/entities": { "version": "4.5.0", @@ -5371,7 +5368,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } @@ -5677,7 +5673,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -6097,7 +6092,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -6228,6 +6222,20 @@ "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", "dev": true }, + "node_modules/jsconfig.json": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/jsconfig.json/-/jsconfig.json-2.3.3.tgz", + "integrity": "sha512-why4CyeZ6NDeOEtm+c7Pq5LyD6JHlBDiNvjVAR5Ynp1tsgpmS/fcm9Se8FLZwBYmhvUGRji1D8ZbXDIsXGJGPw==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.2.2", + "picocolors": "^1.0.0", + "yargs": "^17.2.1" + }, + "bin": { + "jsconfig.json": "bin/cli.js" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -7124,7 +7132,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -7506,7 +7513,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7900,7 +7906,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7929,7 +7934,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9044,7 +9048,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -9094,7 +9097,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -9115,7 +9117,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -9145,7 +9146,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9163,7 +9163,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } diff --git a/package.json b/package.json index 8d5dec35..a4451660 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "greeks": "^1.0.0", "html2canvas": "^1.4.1", "https": "^1.0.0", + "jsconfig.json": "^2.3.3", "marked": "^12.0.2", "mode-watcher": "^0.3.1", "sharp": "^0.33.5", diff --git a/src/routes/options-flow/+page.svelte b/src/routes/options-flow/+page.svelte index 533c94da..be4bab51 100644 --- a/src/routes/options-flow/+page.svelte +++ b/src/routes/options-flow/+page.svelte @@ -467,6 +467,10 @@ } } + const currentTime = new Date( + new Date().toLocaleString("en-US", { timeZone: "America/New_York" }), + )?.getTime(); + const nyseDate = new Date( data?.getOptionsFlowFeed?.at(0)?.date ?? null, )?.toLocaleString("en-US", { @@ -601,7 +605,6 @@ function daysLeft(targetDate) { const targetTime = new Date(targetDate).getTime(); - const currentTime = new Date().getTime(); const difference = targetTime - currentTime; const millisecondsPerDay = 1000 * 60 * 60 * 24; @@ -1167,7 +1170,8 @@ {:else} {ruleCondition[row?.rule] ?.replace("under", "Under") - ?.replace("over", "Over") ?? ""} + ?.replace("over", "Over") + ?.replace("exactly", "Exactly") ?? ""} {valueMappings[row?.rule]} {/if} @@ -1212,7 +1216,8 @@ {ruleCondition[ruleName] ?.replace("under", "Under") ?.replace("over", "Over") - ?.replace("between", "Between")} + ?.replace("between", "Between") + ?.replace("exactly", "Exactly")} - {#each ["Over", "Under", "Between"] as item} + {#each ["Over", "Under", "Between", "Exactly"] as item} changeRuleCondition( @@ -1291,7 +1296,7 @@ /> {/if} - {#if ["over", "under"]?.includes(ruleCondition[ruleName]?.toLowerCase())} + {#if ["over", "under", "exactly"]?.includes(ruleCondition[ruleName]?.toLowerCase())}
@@ -1387,7 +1392,8 @@ > {ruleCondition[row?.rule] ?.replace("under", "Under") - ?.replace("over", "Over")} + ?.replace("over", "Over") + ?.replace("exactly", "Exactly")} {newValue} diff --git a/src/routes/options-flow/workers/filterWorker.ts b/src/routes/options-flow/workers/filterWorker.ts index b0d11e9a..7a12741e 100644 --- a/src/routes/options-flow/workers/filterWorker.ts +++ b/src/routes/options-flow/workers/filterWorker.ts @@ -137,7 +137,7 @@ if (ruleName === 'volumeoiratio') { return false; } - const ratio = (volume / openInterest) * 100; + const ratio = Math.ceil((volume / openInterest) * 100); // Handle 'between' condition for volume to open interest ratio if (rule.condition === 'between' && Array.isArray(ruleValue)) { @@ -153,6 +153,8 @@ if (ruleName === 'volumeoiratio') { // Existing conditions for 'over' and 'under' if (rule.condition === 'over' && ratio <= ruleValue) return false; if (rule.condition === 'under' && ratio >= ruleValue) return false; + if (rule.condition === 'exactly' && ratio !== ruleValue) return false; + return true; }; @@ -167,7 +169,7 @@ if (ruleName === 'sizeoiratio') { return false; } - const ratio = (size / openInterest) * 100; + const ratio = Math?.ceil((size / openInterest) * 100); // Handle 'between' condition for size to open interest ratio if (rule.condition === 'between' && Array.isArray(ruleValue)) { @@ -183,6 +185,8 @@ if (ruleName === 'sizeoiratio') { // Existing conditions for 'over' and 'under' if (rule.condition === 'over' && ratio <= ruleValue) return false; if (rule.condition === 'under' && ratio >= ruleValue) return false; + if (rule.condition === 'exactly' && ratio !== ruleValue) return false; + return true; }; @@ -200,7 +204,8 @@ if (ruleName === 'sizeoiratio') { const expirationDate = new Date(item[rule.name]); if (isNaN(expirationDate)) return false; // Handle invalid dates - const daysDiff = (expirationDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24); + const daysDiff = Math?.ceil((expirationDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); + if (rule.condition === 'between' && Array.isArray(ruleValue)) { const [minDays, maxDays] = ruleValue.map(val => @@ -221,6 +226,11 @@ if (ruleName === 'sizeoiratio') { if (rule.condition === 'under' && typeof ruleValue === 'number') { return daysDiff <= ruleValue; } + + if (rule.condition === 'exactly' && typeof ruleValue === 'number') { + return daysDiff === ruleValue; + } + return false; }; @@ -236,9 +246,9 @@ if (ruleName === 'sizeoiratio') { const itemValue = item[rule.name]; // Handle array of values for categorical fields - if (Array.isArray(ruleValue)) { + if (Array?.isArray(ruleValue)) { // Remove any empty or undefined values from ruleValue - const validRuleValues = ruleValue.filter(val => val !== "" && val !== undefined); + const validRuleValues = ruleValue?.filter(val => val !== "" && val !== undefined); // If no valid values remain, return true for all items if (validRuleValues.length === 0) { @@ -246,14 +256,14 @@ if (ruleName === 'sizeoiratio') { } // If itemValue is an array, check if any of the values match - if (Array.isArray(itemValue)) { - return validRuleValues.some(val => + if (Array?.isArray(itemValue)) { + return validRuleValues?.some(val => itemValue.some(iv => iv.toLowerCase() === val.toLowerCase()) ); } // If itemValue is a string, check if it's in the validRuleValues array - return validRuleValues.some(val => + return validRuleValues?.some(val => itemValue?.toLowerCase() === val.toLowerCase() ); } @@ -261,8 +271,8 @@ if (ruleName === 'sizeoiratio') { // Handle single string value if (typeof ruleValue === 'string') { // If itemValue is an array, check if any value matches - if (Array.isArray(itemValue)) { - return itemValue.some(iv => iv.toLowerCase() === ruleValue.toLowerCase()); + if (Array?.isArray(itemValue)) { + return itemValue?.some(iv => iv.toLowerCase() === ruleValue.toLowerCase()); } // If both are strings, do a direct comparison @@ -281,6 +291,8 @@ return (item) => { if (itemValue === null || itemValue === undefined) return false; const numericItemValue = parseFloat(itemValue); + + if (isNaN(numericItemValue)) return false; // Handle 'between' condition for numeric fields using convertUnitToValue @@ -295,9 +307,12 @@ return (item) => { } // Existing conditions + if (rule.condition === 'exactly' && numericItemValue !== ruleValue) return false; if (rule.condition === 'over' && numericItemValue <= ruleValue) return false; if (rule.condition === 'under' && numericItemValue >= ruleValue) return false; + + return true; };