A volume alert that works compares the current window against that same series own recent baseline, requires the condition to persist for a stated period, clears only when the metric falls back below a lower threshold, and suppresses repeats per token. A volume alert that fails uses a fixed number, fires on a single sample, and sends one message per bucket.

The difference is not statistical sophistication. It is whether the design accounts for the fact that the recipient is a person with finite attention who will, entirely rationally, start ignoring a channel that has cried wolf four times this week.

Why volume alerts go numb

Alert channels degrade in a predictable sequence. A fixed threshold is chosen because it looked sensible for the token being watched that week. Activity conditions change, and the threshold now fires several times a day. Somebody mutes the channel during a busy period and forgets to unmute it. The next genuine event arrives and nobody sees it.

The root cause is almost always that the rule compares an absolute number against an absolute constant. Market activity varies across tokens by orders of magnitude and varies across the day for the same token, so any constant is simultaneously too high for the quiet cases and too low for the busy ones.

The second cause is single-sample firing. Volume data is spiky by nature, and a rule evaluated on one bucket will fire on one unusual minute that means nothing. Requiring persistence costs you a small amount of detection delay and removes most of the false positives, which is an excellent trade in almost every case.

Alert on a ratio, not a raw number

Replace the constant with a relationship. Instead of alerting when volume exceeds a fixed amount, alert when the current window is some multiple of the recent typical value for that same series. The threshold now means the same thing for a token that trades constantly and one that trades occasionally, which is what makes it possible to apply one rule to a whole watch list.

The same reasoning applies to any derived metric worth watching: trade count against its own baseline, average trade size against its own baseline, unique traders against theirs. Each answers a different question, and a spike in volume with flat trade count means something quite different from a spike in both.

There is one important floor. A ratio computed against a near-zero baseline explodes, so a token that traded twice yesterday and four times today shows a hundred percent increase that means nothing. Require a minimum absolute level before the ratio rule is allowed to fire, and choose that floor from your own data rather than from a round number.

Baselines that survive a spike

The baseline has to describe normal, and the standard tools do not. A rolling mean is dragged upward by the very spike you are detecting, and a standard deviation computed over a window containing a spike inflates enormously, so the next spike of similar size scores lower and may pass unnoticed. The statistic that is supposed to detect the event has been damaged by the event.

Robust statistics avoid this. The median is unmoved by a small number of extreme values, and the median absolute deviation, the median of the absolute differences from the median, is a spread measure with the same property. A score built from those two is stable across exactly the conditions that break a mean-based rule.

Exclude the current bucket from its own baseline

Compute the baseline from the window ending immediately before the bucket you are evaluating. It sounds obvious and it is a common bug, because the convenient query includes the present. When the current value is part of its own reference, a large spike partially raises the bar it is being measured against, and the rule becomes less sensitive precisely when it should be more so.

A worked threshold, with the arithmetic

The values below are illustrative. They exist to show the shape of the calculation and describe no real token and no real market.

Suppose one-minute volume for a series over the previous sixty minutes has a median of 12 SOL and a median absolute deviation of 3 SOL. A common scaling converts the deviation into something comparable with a standard deviation by multiplying by 1.4826, giving roughly 4.45.

Current bucketCalculationRobust scoreReading
15 SOL(15 - 12) / 4.450.7Ordinary variation, no alert
28 SOL(28 - 12) / 4.453.6Notable, worth a dashboard marker
60 SOL(60 - 12) / 4.4510.8Clearly outside the recent regime

Pick the firing level from your own history rather than from this table. Run the calculation over a month of your own data, count how many alerts each candidate threshold would have produced, and choose the one that lands inside the alert budget you decided in advance. That is a ten-minute exercise that prevents a year of noise.

Seasonality and the quiet hours

Trading activity has repeating structure. If your baseline window is short, that structure is invisible and every predictable quiet period looks like a collapse, while every predictable busy period looks like an event. Overnight false positives are almost always this problem.

The straightforward fix is a same-period baseline: compare this minute against the same minute on previous days rather than against the last hour. It handles daily structure without any modelling, and it degrades gracefully because a token with only a few days of history simply falls back to the rolling baseline.

Weekly structure exists too, and whether it is worth modelling depends on how expensive your false positives are. A useful middle path is to keep the rolling baseline for detection and use the same-period comparison to set severity, so a move that is large against both is escalated and a move that is only large against the last hour is not.

Dwell time and hysteresis

Two controls turn a jumpy rule into a stable one, and they are frequently confused with each other.

Dwell time is how long the condition must hold before the alert fires. Requiring three consecutive minutes above the threshold, or three of the last five, removes single-bucket noise at the cost of a few minutes of detection delay. For volume monitoring that trade is almost always worth taking.

Hysteresis is the gap between the firing threshold and the clearing threshold. If an alert fires above a score of eight and clears below a score of eight, a metric sitting near the line produces a stream of firing and clearing messages. Clear at a lower level, say five, and the oscillation disappears entirely.

  1. Choose the firing threshold from history so that its alert count fits the budget you set for the channel.
  2. Set the clearing threshold well below it, far enough that ordinary variation cannot cross both lines repeatedly.
  3. Require dwell on the way in, so a single unusual bucket cannot page anyone.
  4. Require dwell on the way out too, so a brief dip does not send a premature all clear.
  5. Emit state changes, not states. One message when the condition begins and one when it ends, never one per evaluation.

Deduplication and per-key suppression

Suppression must be scoped to the alert key, which for volume work is normally the token and the venue. A global cooldown silences unrelated series that happened to move in the same window, which is how a real event gets swallowed by an unrelated one.

Deduplication is a separate control and belongs to the delivery layer. If the same condition on the same key generates a message from two evaluators, or from a retry, only one should reach a person. Give every alert a stable identity built from the key and the condition, and let the delivery layer collapse repeats.

Watch for correlated storms. A market-wide move can breach the rule for every token you watch at once, producing hundreds of individually correct alerts that are collectively useless. A cap on alerts per interval, with an aggregate message when the cap is hit, is a small feature that saves the channel on the days it matters most.

Severity, routing and who gets woken

Most volume signals are not worth waking anybody. Be explicit about the tiers so that the routing follows from the rule rather than from habit.

TierExample conditionDestinationExpected response
InformationalA series exceeds its baseline modestlyDashboard marker onlyNobody acts; it is context for later
NotableSustained multiple of baseline with dwell satisfiedA channel read during working hoursSomebody looks when convenient
UrgentExtreme score plus a second corroborating signalDirect notification to a named personInvestigation begins now
Pipeline faultWatermark stalled or feed silent past its expected cadenceWhoever owns the ingestionFix the pipeline; market data is unreliable meanwhile

The last row is the one most teams omit and the one that pays for itself first. A stalled feed and a quiet market look identical on a chart, so without a liveness alert the most likely explanation for silence is never tested. That check is described in data gaps and backfill.

The alert payload that saves five minutes

An alert is a handover. The recipient has to reconstruct the situation from whatever the message contains, usually in a hurry and often on a phone. Six fields do nearly all of the work.

  • What changed, named precisely: the token, the venue and the metric.
  • By how much, expressed as the current value, the baseline and the score, so the reader can judge without opening anything.
  • Over what window, including the dwell already satisfied, so nobody wonders whether this is one odd minute.
  • Which commitment level and watermark the data came from, so a stale pipeline is visible immediately.
  • A link to the evidence, ideally a filtered view or a signature that can be checked independently.
  • What this alert does not claim, in one clause, because a counter cannot tell you the cause.

That last field deserves defending. A message that says volume rose sharply and links to the transactions is honest. A message that says a token is being accumulated is an interpretation the data does not support, and the counter genuinely cannot distinguish between organic buying, one large order, and activity generated by a volume bot on Solana DEXs. Say what moved and let the reader do the attribution.

Testing a rule against history first

Never deploy an alert rule you have not run against stored data. The evaluation is straightforward and it is the difference between a rule you tuned once and a rule you will be apologising for.

  1. Replay a representative month of your own buckets through the rule exactly as written, including dwell and hysteresis.
  2. Count the firings per day and compare against the alert budget for the destination channel.
  3. Inspect the largest cluster of firings and ask whether a person would have wanted all of them or just the first.
  4. Look for the events you know about and confirm the rule catches them, which is the only test of sensitivity that means anything.
  5. Sweep the threshold across a range and plot count against threshold, then choose from the curve rather than from intuition.
  6. Re-run quarterly. Activity regimes change, and a rule tuned to last spring is a rule tuned to a market that no longer exists.

What not to alert on

  • Any raw value compared against a constant that was chosen once and never revisited.
  • Percentage changes computed from a baseline near zero, which produce enormous numbers from trivial movements.
  • Single-bucket conditions with no dwell requirement.
  • Metrics nobody has agreed to act on, which belong on a dashboard rather than in a channel.
  • Conditions that fire for every token during a market-wide move, without an aggregate cap.
  • Anything whose message asserts a cause rather than describing a change.
  • Rules that have never been replayed against history, because their firing rate is unknown by definition.

There is one more habit that keeps a channel healthy over years rather than weeks: review the alerts that fired and ask, for each one, whether anybody did anything. An alert that has never once produced an action is not a low-value alert, it is a false positive with good manners, and deleting it improves the signal of everything around it. Run that review on a schedule and treat deletion as a normal outcome rather than as an admission of failure.

An alerting system is judged on the days it stays quiet as much as the days it fires. If the channel is trusted enough that a message interrupts somebody, the design is working, and that trust is built by every alert you chose not to send.

Questions this desk keeps getting

What threshold should I use for a volume spike alert?

Not a fixed amount. A number that is dramatic for a quiet token is background noise for a busy one, so the same threshold cannot serve both. Compare current volume against that series own recent baseline and alert on the ratio or on a robust score. The threshold then means the same thing for every token you watch, which is what makes it maintainable.

Why should I use median and MAD instead of mean and standard deviation?

Because the event you are trying to detect corrupts the statistic you are detecting it with. One large spike pulls the mean up and inflates the standard deviation, so the next comparable spike scores lower and may not fire at all. The median and the median absolute deviation are barely moved by a small number of extreme values, which keeps the baseline describing normal rather than describing the last incident.

How do I stop one event from producing twenty alerts?

Suppress per key rather than globally. Once an alert fires for a token, hold further alerts for that token for a defined period, and require the metric to fall back below a lower clear threshold before the alert can fire again. Global suppression is the wrong shape because it silences unrelated tokens that happened to move at the same time.

Should quiet hours have different thresholds?

If your data shows a repeating pattern, yes. Comparing a low-activity period against a baseline built from busy periods makes small absolute moves look enormous, which is the classic source of overnight noise. Build the baseline from the same period on previous days rather than from the last few hours, and the seasonality problem largely disappears.

Can an alert tell me why volume rose?

No, and pretending otherwise is how alerts lose credibility. A counter measures that value moved, not who moved it or why. Organic buying, a single large order, and automated activity all raise the same number. An alert should say what changed, by how much, relative to what baseline, and link to the evidence, then stop.

How many alerts per day is too many?

Decide the budget before you write the rule, then tune to it. A channel a person is expected to read in real time can sustain a handful of messages a day before it becomes wallpaper. If the rule produces more than the budget, the correct response is to raise the bar or split the channel, never to ask people to try harder.

What is the difference between an alert and a dashboard entry?

An alert claims somebody should act now. A dashboard entry claims somebody might want to look later. Most metrics belong on a dashboard, and moving a noisy alert there is usually an improvement rather than a defeat. The test is simple: if you cannot say what the recipient should do in the first minute, it is not an alert.