Rules that tell you when to look
The point of a watchlist is not to be watched. It is to tell you when watching is worthwhile. This lesson adds threshold rules; it also draws a line under what they can honestly promise on the data you currently have.
A rule is data, not code
The instinct is to write an if. Don't. Store rules the same way you store notes, so they can be edited, listed, and reasoned about:
type Rule = {
ticker: string;
field: "change_p" | "close";
op: ">" | "<";
value: number;
};
{ ticker: "AAPL.US", field: "change_p", op: "<", value: -3 } reads as "tell me if Apple is down more than 3%". Data-shaped rules can be shown to the user, exported, and evaluated in one place:
function fires(rule: Rule, q: Quote): boolean {
const actual = q[rule.field];
return rule.op === ">" ? actual > rule.value : actual < rule.value;
}
One function, every rule. Compare that with fifteen bespoke if statements scattered through a component, which is what you get if you let this grow organically.
Say what fired, not that something fired
A row that turns red tells you nothing you can act on. The useful sentence names the rule and the number:
AAPL.US down 3.4% — your rule was −3%
That is the difference between an alert you trust and a decoration you learn to ignore. And once again: colour is never the only signal. Red plus a written reason survives a colour-blind reader and a phone in sunlight.
The honest limit, and it is the point of this lesson
Your rules evaluate when the page renders. That is all they can do. There is no server watching your instruments while you sleep, so:
- A rule cannot fire while the tab is closed.
- A rule cannot fire between two loads: a price can cross your threshold and come back, and you will never know it happened.
- The number you compare against is as old as the timestamp on your data.
Write that in the interface. Something like "Rules are checked when this page loads" costs one line and prevents the worst possible outcome of this whole course: someone believing their tool is watching for them when it is not.
Real alerting needs something running on a schedule, something storing state so it does not tell you twice, and data fresh enough that the alert is not already stale when it arrives. All three are real work, and the third one is where you meet the wall in the next unit — which is exactly the honest version of this feature's story.
Do not fix this by polling
The tempting move is setInterval on a short timer. Do the arithmetic before you write it, with the per-symbol price from unit 1: a twelve-instrument watchlist refreshing every 30 seconds is 120 refreshes an hour × 12 = 1,440 calls an hour, roughly 9,400 in a 6.5-hour session, from one open tab.
Against a free allowance of 20 calls a day that is over in the first minute, and you will have spent it on a page nobody was looking at.
Your usage meter will show this happening. That is why it has been on screen since unit 1.
Try it now
Add one rule for one instrument, with a threshold close enough to today's value that it actually fires. Then write the honest sentence into your interface, in your own words, about when rules are checked. Read it back and ask whether a person who had not built this tool would be misled by anything on the screen.