← All tools · Guides

Watchlist alerts: a big move or a volume spike, pushed once

Local review series, part 4. The rules watch the list. You look only when one of them fires. This closes the local path.

This is part 4 of the Chinese series on a local review stack. The previous part, the after-close note, is an AI review note. Reuse its push channel and its environment. The same article in Chinese is the Chinese review note. That note is not this article.

Short answer: poll ak.stock_zh_a_spot_em once a minute, keep two or three rules in rules.yaml, and push each name and rule only once that day. Leave the PC on from 09:25 to 15:10, or move the same script to a cloud server.

How to choose: An alert is there so you can stop watching the screen. The previous note already has the Python environment and a push channel, ServerChan or email. Reuse both. The only design rule is to miss a move before you flood the phone. Start with two or three rules, run them for a week, and add more only after you still read the ones that arrive. During the China A-share session, call ak.stock_zh_a_spot_em once a minute, keep the rows whose code is on your watchlist, and rename the Chinese columns before you compare anything. Do not shorten the sleep to a second. That is the fastest way to get the IP blocked. Write the thresholds in rules.yaml, not in the script, so a change does not touch code. The same name and the same rule push once per day. An in-memory set of (code, rule) is enough. A restart can send one extra message, and that is acceptable. Where the loop runs is a separate choice. Leave the PC on and start the script at 09:25, stopping at 15:10, if you are already at the machine. Move the same script to a cloud server, under nohup or systemd, if the laptop lid will be shut. If you do not want a loop all day, run the same rules at the open, at 14:30, and at the close. The review note, the cloud server note, and TradingView alerts are different articles. This page is not the tool-order guide and not the site FAQ.

Who it is for: Someone who already has the local review stack, watches a short China A-share list during the session, and wants a phone push for a large rise, a large drop, or a volume spike without staring at quotes. What you need from this page is the one-minute poll, two or three rules, the once-a-day throttle, and a decision about whether the PC stays on.

Who it is not for: Someone who wants a broker terminal, a Level-2 feed, or an alert that places an order. This page only notices. It does not choose the trade. Chart alerts on a TradingView layout are a different article. A machine that must stay on after the close starts with the cloud server note, which is also a different article. This page is not the after-close review, not the tool-order guide, and not the site FAQ. Do not treat a push as a reason to buy or sell.

The same walkthrough in Chinese is a watchlist alert for a large move or a volume spike. A machine that stays on, including the first SSH login, is opening a cloud server. The same article in Chinese is the Chinese cloud server note. That note is not this article. Alerts drawn on a chart, on the free plan, are the TradingView setup. The same article in Chinese is the Chinese TradingView note. That article is not this one either.

Facts below follow the Chinese walkthrough. The commands were not re-run for this English page. This is not investment advice. Free data and push quotas follow the vendor's current page.

01 · The point is to look less

The failure mode of an alert is fatigue. Loose rules send dozens of messages, and by the third day you ignore the phone. Prefer a miss to a flood. Open with the two or three moves that would still pull you away from other work, keep them for a week, and only then add a rule. A new high or a new low belongs in that later pass, once you have a reference price to compare. This page does not invent that level for you.

02 · Live quotes: one snapshot a minute

import akshare as ak
import time
from datetime import datetime

def market_open() -> bool:
    now = datetime.now()
    t = now.hour * 100 + now.minute
    return now.weekday() < 5 and (925 <= t <= 1130 or 1300 <= t <= 1505)

while market_open():
    try:
        spot = ak.stock_zh_a_spot_em()          # one snapshot of the whole market
        rows = spot[spot["代码"].isin(WATCHLIST)]
        check_rules(rows)                        # section 03
    except Exception as e:
        log(f"fetch fail: {e}")                  # log it, then the next round
    time.sleep(60)                               # once a minute is enough

The snapshot uses Chinese column names. Rename them before the rules run. The five this page needs are code, name, last price, percent change, and volume:

rows = rows.rename(columns={
    "代码": "code",
    "名称": "name",
    "最新价": "price",
    "涨跌幅": "pct",
    "成交量": "volume",
})

WATCHLIST is the short list you already watch. One request a minute is the whole poll. Leave the 60-second sleep alone.

03 · Rules in a file, and a once-a-day throttle

Thresholds live in the config. Changing a number should not mean editing the script:

# rules.yaml
- name: large rise
  cond: "pct >= 5"
- name: large drop
  cond: "pct <= -5"
- name: volume spike
  cond: "pct >= 3 and vol_ratio >= 2"   # live volume / 5-day average, scaled by time open

pct is already in percent points. A print of 5.1 is a rise of 5.1 percent. Compare it with 5. vol_ratio is not a column in the snapshot. Compute it from volume and the recent average, scaled by how much of the session has elapsed, before the rule runs.

The throttle is what keeps the phone quiet. The same name and the same rule go out once:

seen: set[tuple[str, str]] = set()

def already_sent(code: str, rule: str) -> bool:
    key = (code, rule)
    if key in seen:
        return True
    seen.add(key)
    return False

The set is in memory. A restart drops it, and the next fire can push one extra time. That is acceptable. The message is three lines: code and name, the rule that fired, and the price with the percent. Send it with the ServerChan or email function from the review note.

04 · Where the computer sits

Pick one of these. They share the same rules.

05 · Acceptance

06 · Pitfalls

The local path is complete. The database updates after the close, the model writes the review, and the watchlist pings you during the session. Stay on the PC and there is no server bill. The other paths are on the guides index.

Back to the guides →

This is not investment advice. Free data and push quotas follow the vendor's current page.

Frequently asked questions

How to choose a watchlist alert that does not flood your phone?

An alert is there so you can stop watching the screen. The previous note already has the Python environment and a push channel, ServerChan or email. Reuse both. The only design rule is to miss a move before you flood the phone. Start with two or three rules, run them for a week, and add more only after you still read the ones that arrive. During the China A-share session, call ak.stock_zh_a_spot_em once a minute, keep the rows whose code is on your watchlist, and rename the Chinese columns before you compare anything. Do not shorten the sleep to a second. That is the fastest way to get the IP blocked. Write the thresholds in rules.yaml, not in the script, so a change does not touch code. The same name and the same rule push once per day. An in-memory set of (code, rule) is enough. A restart can send one extra message, and that is acceptable. Where the loop runs is a separate choice. Leave the PC on and start the script at 09:25, stopping at 15:10, if you are already at the machine. Move the same script to a cloud server, under nohup or systemd, if the laptop lid will be shut. If you do not want a loop all day, run the same rules at the open, at 14:30, and at the close. The review note, the cloud server note, and TradingView alerts are different articles. This page is not the tool-order guide and not the site FAQ.

Who it is for?

Someone who already has the local review stack, watches a short China A-share list during the session, and wants a phone push for a large rise, a large drop, or a volume spike without staring at quotes. What you need from this page is the one-minute poll, two or three rules, the once-a-day throttle, and a decision about whether the PC stays on.

Who it is not for?

Someone who wants a broker terminal, a Level-2 feed, or an alert that places an order. This page only notices. It does not choose the trade. Chart alerts on a TradingView layout are a different article. A machine that must stay on after the close starts with the cloud server note, which is also a different article. This page is not the after-close review, not the tool-order guide, and not the site FAQ. Do not treat a push as a reason to buy or sell.

How does the one-minute snapshot poll work?

On a weekday, while the clock is from 09:25 to 11:30 or from 13:00 to 15:05, call ak.stock_zh_a_spot_em. That one request is a snapshot of the whole market. Keep the rows whose code is in WATCHLIST, the names you actually watch. Rename the Chinese columns before any comparison: code, name, last price, percent change, and volume. Then run the rules. If the request throws, write the error and continue. Sleep 60 seconds and repeat. One request a minute stays well under a personal rate limit. A one-second loop is how the IP gets blocked. WATCHLIST is the same short list the earlier notes already use. This page does not download history and does not write the daily table.

How do you write a rule and stop it firing twice?

Put the rules in rules.yaml. A large rise is pct >= 5. A large drop is pct <= -5. A volume spike is pct >= 3 and vol_ratio >= 2. pct is the percent column from the snapshot. Compare it with 5, not with 0.05. vol_ratio is live volume divided by the average volume of the last five sessions, scaled by how much of the session has elapsed. The same name and the same rule push once that day. Keep an in-memory set of (code, rule). If the key is already there, skip the push. The set dies when the script restarts, so you may get one extra message. That is the tradeoff the Chinese page accepts. The message itself is three lines: code and name, the rule that fired, and the price with the percent. Send it through the ServerChan or email function from the review note.

Does the computer have to stay on?

Only during the session, and only if you want the one-minute loop. The default is the PC you already sit at. Task Scheduler starts the script at 09:25 and the script stops itself at 15:10, because market_open is false after that. If the laptop will be closed, move the same script to a cloud server and leave it under nohup or systemd. Opening that machine is the cloud server note, not this one. If you do not want a process running all day, call the snapshot three times instead: at the open, at 14:30, and at the close. The rules stay the same. You give up some of the timeliness, and the cost is almost nothing.

How do you check that a push actually arrives?

Three checks, in order. Find a watchlist name that is close to a threshold, widen that threshold for one trial, and confirm the phone receives the message. Fire the same name and the same rule a second time and confirm it does not push again. Pull the network for one round: the script should log the failure and stay alive, then keep going after the network returns. Put the real threshold back when the trial is done. A push that arrives is not a trade. What you do next should already be in the review note and the plan.

What pitfalls does this walkthrough call out?

Four. The percent column is already in percent points. Compare it with 5. Dividing by 100 makes every rule miss. A halted name has volume 0 and a price stuck at the previous close, which can throw a junk alert. Exclude volume == 0. Prints before 09:25 are the call auction, and the percent jumps. Turn the rules on after the open. An alert is not a decision. It helps you see the move. It does not say what to do. This is not investment advice. Free data and push quotas follow the vendor's current page.