add repeated flow

This commit is contained in:
MuslemRahimi 2024-12-13 21:23:47 +01:00
parent 2471ce872a
commit 2026bb5ed0
2 changed files with 66 additions and 21 deletions

View File

@ -95,6 +95,11 @@
step: ["ITM", "OTM"], step: ["ITM", "OTM"],
defaultValue: "any", defaultValue: "any",
}, },
flowType: {
label: "Flow Type",
step: ["Repeated Flow"],
defaultValue: "any",
},
put_call: { put_call: {
label: "Contract Type", label: "Contract Type",
step: ["Calls", "Puts"], step: ["Calls", "Puts"],
@ -128,6 +133,16 @@
}, },
}; };
const categoricalRules = [
"moneyness",
"flowType",
"put_call",
"sentiment",
"execution_estimate",
"option_activity_type",
"underlying_type",
];
// Generate allRows from allRules // Generate allRows from allRules
$: allRows = Object?.entries(allRules) $: allRows = Object?.entries(allRules)
?.sort(([, a], [, b]) => a.label.localeCompare(b.label)) // Sort by label ?.sort(([, a], [, b]) => a.label.localeCompare(b.label)) // Sort by label
@ -218,6 +233,7 @@
switch (ruleName) { switch (ruleName) {
case "moneyness": case "moneyness":
case "flowType":
case "put_call": case "put_call":
case "sentiment": case "sentiment":
case "execution_estimate": case "execution_estimate":
@ -347,16 +363,7 @@
} }
// Specific rule handling for options-related rules // Specific rule handling for options-related rules
if ( if (categoricalRules?.includes(ruleName)) {
[
"moneyness",
"put_call",
"sentiment",
"execution_estimate",
"option_activity_type",
"underlying_type",
]?.includes(ruleName)
) {
// Ensure valueMappings[ruleName] is initialized as an array // Ensure valueMappings[ruleName] is initialized as an array
if (!Array.isArray(valueMappings[ruleName])) { if (!Array.isArray(valueMappings[ruleName])) {
valueMappings[ruleName] = []; valueMappings[ruleName] = [];
@ -1130,7 +1137,7 @@
<DropdownMenu.Content <DropdownMenu.Content
class="w-64 min-h-auto max-h-72 overflow-y-auto scroller" class="w-64 min-h-auto max-h-72 overflow-y-auto scroller"
> >
{#if !["moneyness", "put_call", "sentiment", "execution_estimate", "option_activity_type", "underlying_type"]?.includes(row?.rule)} {#if !categoricalRules?.includes(row?.rule)}
<DropdownMenu.Label <DropdownMenu.Label
class="absolute mt-2 h-11 border-gray-800 border-b -top-1 z-20 fixed sticky bg-[#09090B]" class="absolute mt-2 h-11 border-gray-800 border-b -top-1 z-20 fixed sticky bg-[#09090B]"
> >
@ -1290,7 +1297,7 @@
></div> ></div>
{/if} {/if}
<DropdownMenu.Group class="min-h-10 mt-2"> <DropdownMenu.Group class="min-h-10 mt-2">
{#if !["moneyness", "put_call", "sentiment", "execution_estimate", "option_activity_type", "underlying_type"]?.includes(row?.rule)} {#if !categoricalRules?.includes(row?.rule)}
{#each row?.step as newValue, index} {#each row?.step as newValue, index}
{#if ruleCondition[row?.rule] === "between"} {#if ruleCondition[row?.rule] === "between"}
{#if newValue && row?.step[index + 1]} {#if newValue && row?.step[index + 1]}
@ -1334,7 +1341,7 @@
</DropdownMenu.Item> </DropdownMenu.Item>
{/if} {/if}
{/each} {/each}
{:else if ["moneyness", "put_call", "sentiment", "execution_estimate", "option_activity_type", "underlying_type"]?.includes(row?.rule)} {:else if categoricalRules?.includes(row?.rule)}
{#each row?.step as item} {#each row?.step as item}
<DropdownMenu.Item <DropdownMenu.Item
class="sm:hover:bg-[#2A2E39]" class="sm:hover:bg-[#2A2E39]"

View File

@ -1,4 +1,8 @@
interface FilterContext {
flowTypeCache?: Map<string, number>;
}
const categoricalFields = [ const categoricalFields = [
'put_call', 'put_call',
'sentiment', 'sentiment',
@ -36,6 +40,7 @@ function convertUnitToValue(
"etf", "etf",
"itm", "itm",
"otm", "otm",
"repeated flow"
]); ]);
if (nonNumericValues.has(lowerInput)) return input; if (nonNumericValues.has(lowerInput)) return input;
if (input.endsWith("%")) { if (input.endsWith("%")) {
@ -72,10 +77,38 @@ function createRuleCheck(rule, ruleName, ruleValue) {
const now = new Date(new Date().toLocaleString("en-US", { timeZone: "America/New_York" })); const now = new Date(new Date().toLocaleString("en-US", { timeZone: "America/New_York" }));
if (ruleName === 'flowtype') {
return (item: any, context: FilterContext = {}) => {
// Check for 'any' rule or other non-repeated flow conditions
if (ruleValue === 'any' || ruleValue?.includes("any")) {
return true;
}
// Handle Repeated Flow logic
if (ruleValue?.includes('Repeated Flow')) {
// Initialize flowTypeCache if it doesn't exist
context.flowTypeCache = context.flowTypeCache || new Map();
// Create a unique key for repeated flow based on item characteristics
const key = `${item.ticker}-${item.put_call}-${item.strike_price}-${item.date_expiration}`;
// Increment the count for the key in the flowTypeCache
const currentCount = (context.flowTypeCache.get(key) || 0) + 1;
context.flowTypeCache.set(key, currentCount);
// Return true if this flow appears more than N times (3 in this case)
return currentCount > 3;
}
// Fallback for other flow type conditions (i.e., non-repeated flow)
return true;
};
}
if (ruleName === 'moneyness') { if (ruleName === 'moneyness') {
return (item) => { return (item) => {
if (ruleValue === 'any' || ruleValue?.includes("any")) return true;
if (ruleValue === 'any') return true;
const currentPrice = parseFloat(item?.underlying_price); const currentPrice = parseFloat(item?.underlying_price);
const strikePrice = parseFloat(item?.strike_price); const strikePrice = parseFloat(item?.strike_price);
@ -280,11 +313,16 @@ async function filterRawData(rawData, ruleOfList, filterQuery) {
// Preprocess filter tickers // Preprocess filter tickers
const filterTickers = filterQuery const filterTickers = filterQuery
? filterQuery.split(",").map((ticker) => ticker.trim().toUpperCase()) ? filterQuery?.split(",").map((ticker) => ticker.trim().toUpperCase())
: []; : [];
// Initialize context with optional flowTypeCache
const context: FilterContext = {
flowTypeCache: new Map()
};
// Precompile rules for more efficient filtering // Precompile rules for more efficient filtering
const compiledRules = ruleOfList.map(rule => { const compiledRules = ruleOfList?.map(rule => {
const ruleName = rule?.name?.toLowerCase(); const ruleName = rule?.name?.toLowerCase();
const ruleValue = convertUnitToValue(rule.value); const ruleValue = convertUnitToValue(rule.value);
@ -302,12 +340,12 @@ async function filterRawData(rawData, ruleOfList, filterQuery) {
return false; return false;
} }
// Apply all precompiled rules // Apply all precompiled rules, passing the context
return compiledRules.every(rule => rule?.compiledCheck(item)); return compiledRules?.every(rule => rule?.compiledCheck(item, context));
}); });
} }
// Web Worker message handler // Web Worker message handler remains the same
onmessage = async (event: MessageEvent) => { onmessage = async (event: MessageEvent) => {
const { rawData, ruleOfList, filterQuery } = event.data || {}; const { rawData, ruleOfList, filterQuery } = event.data || {};
// Filter the data // Filter the data