fix(options_flow): scan full universe before applying limit, rank by signal strength
Previously the scanner stopped as soon as self.limit candidates were found from as_completed() futures. Since futures complete in non-deterministic network-latency order, this was equivalent to random sampling — fast-to- respond tickers won regardless of how strong their options signal was. Fix: collect all candidates from the full universe, then sort by options_score (unusual strike count weighted 1.5x for calls to favor bullish flow) before applying the limit. The top-N strongest signals are now always returned. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
61b731ac28
commit
136fa47645
|
|
@ -85,14 +85,13 @@ class OptionsFlowScanner(BaseScanner):
|
||||||
result = future.result()
|
result = future.result()
|
||||||
if result:
|
if result:
|
||||||
candidates.append(result)
|
candidates.append(result)
|
||||||
if len(candidates) >= self.limit:
|
|
||||||
# Cancel remaining futures
|
|
||||||
for f in futures:
|
|
||||||
f.cancel()
|
|
||||||
break
|
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Sort by signal quality: unusual strike count, then bullish bias
|
||||||
|
candidates.sort(key=lambda c: c.get("options_score", 0), reverse=True)
|
||||||
|
candidates = candidates[: self.limit]
|
||||||
|
|
||||||
logger.info(f"Found {len(candidates)} unusual options flows")
|
logger.info(f"Found {len(candidates)} unusual options flows")
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
|
|
@ -193,6 +192,10 @@ class OptionsFlowScanner(BaseScanner):
|
||||||
f"{total_unusual_calls} unusual calls / {total_unusual_puts} unusual puts"
|
f"{total_unusual_calls} unusual calls / {total_unusual_puts} unusual puts"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Scoring: unusual strike count + bullish call bias bonus
|
||||||
|
# Calls weighted 1.5x to favour bullish directional flow
|
||||||
|
options_score = total_unusual_puts + (total_unusual_calls * 1.5)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"ticker": ticker,
|
"ticker": ticker,
|
||||||
"source": self.name,
|
"source": self.name,
|
||||||
|
|
@ -203,6 +206,7 @@ class OptionsFlowScanner(BaseScanner):
|
||||||
"unusual_calls": total_unusual_calls,
|
"unusual_calls": total_unusual_calls,
|
||||||
"unusual_puts": total_unusual_puts,
|
"unusual_puts": total_unusual_puts,
|
||||||
"best_expiration": best_expiration,
|
"best_expiration": best_expiration,
|
||||||
|
"options_score": options_score,
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue