Skip to main content

price-alert

Fire when the tracked token does something - new ATH, sharp 1h move, or operator-set target crossed. Silent on normal days.

Ir para a instalação

Informações da origem

Repositório
aeonfun/aeon
Última atividade na origem
4 de agosto de 2026 às 21:01
Idioma detectado do SKILL.md
inglês
Estrelas
738
Forks
265

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
price-alert
description
Fire when the tracked token does something - new ATH, sharp 1h move, or operator-set target crossed. Silent on normal days.
metadata
{"title":"Price Alert","category":"basics","var":"","tags":["crypto"]}
> **${var}** — Optional. Pass one or more `target_price` levels (comma-separated USD numbers, scientific notation allowed) to fire a one-time alert when the price crosses any of them. Empty = only ATH and sharp-move gates run. Pass `dry-run` to skip notify (state still updates). Pass `set-target:<price>` — the shape the Telegram force-reply sends (step 7) — to register a target and get a one-line confirmation. Today is ${today}. `repo-pulse` reports star/fork deltas once a day, and the other scheduled digests run at fixed hours. None of them tell the operator "the price just hit a new high" or "the token moved 28% in the last hour" — both are events that warrant attention the moment they happen, not 14 hours later in a daily digest. This skill closes that window. ## Why this exists Scheduled daily digests are calm summaries. Real moves need real-time signal. Three classes of move are worth a same-day ping: - **New all-time high.** The single most narrative-shaping price event a token can have. Worth marking on the timeline regardless of size. - **Sharp 1h moves (±20%).** Either a buyer wave or a liquidation cascade — both change what the operator does next (post about it, watch for follow-through, check the chart). - **Operator-set target crossings.** The operator may want to know when price clears $X (often a personal stretch goal or a level tied to a tweet/launch). One alert per target per direction. Everything else is noise not worth a same-day ping. ## Config Reads: - `memory/MEMORY.md` "Tracked Token" section — the tracked token's contract/chain. If absent, exit silently. - `memory/topics/price-alert-state.json` — last-known ATH, last-alert timestamps per event type, target-crossing history. Created with defaults on first run. Writes: - `memory/topics/price-alert-state.json` — updated state every run. - `memory/logs/${today}.md` — one log block per run, even on `OK`. - Notification via `./notify` — only when a gate fires. No new secrets. Uses keyless DexScreener; falls back to WebFetch when a public `curl` GET is flaky (there is no network sandbox). ## State schema ```json { "contract": "0xbf8e8f0e8866a7052f948c16508644347c57aba3", "chain": "base", "ath": { "price_usd": 0.000003757, "observed_at": "2026-05-10T19:00:00Z", "announced_at": "2026-05-10T19:30:00Z" }, "last_alerts": { "ath": "2026-05-10T19:30:00Z", "sharp_move": null, "target_hit": null }, "targets": { "0.000005": { "side": "above", "first_seen_below_at": "2026-05-11T08:00:00Z", "hit_at": null, "announced_at": null } } } ``` Key invariants: - `ath.price_usd` only ever monotonically increases. If a run sees a lower price than the stored ATH, leave the ATH alone. - `last_alerts.*` powers the 4h dedup window. Each gate has its own clock. - `targets.${price}.side` is `above` if `current_price < target` when the target was first observed (operator is waiting for the price to climb to it), and `below` otherwise. Set once, never flipped. - `targets.${price}.hit_at` is set the run the cross happens. `announced_at` is set the run the notification fires. They differ only if the run lands inside a dedup window — but target alerts never re-fire, so `hit_at == announced_at` in practice. ## Steps ### 1. Parse var - If `${var}` starts with `set-target:` → set `FROM_REPLY=1`, `MODE=execute`. Strip the `set-target:` prefix (`${var#set-target:}`); the remainder is the target(s) list, parsed exactly like the comma-split below. This is the shape `scripts/telegram-route.sh` sends when the operator replies to the step-7 force-reply prompt. The run proceeds normally (register the target, don't fire on first observation) and closes the loop with a confirmation in step 7. - Else if `${var}` matches `^dry-run` → `MODE=dry-run`. Strip the prefix; remainder (if any) is treated as targets. - Otherwise `MODE=execute`. - Split the remainder on `,` (commas) and strip whitespace. - For each token: if it parses as a positive float (scientific notation OK, e.g. `5e-6`), include it. Reject zero / negative / non-numeric tokens and log `PRICE_ALERT_BAD_TARGET: ${token}` — continue with the surviving targets. - If after filtering the remainder was non-empty but yielded zero valid targets → log `PRICE_ALERT_BAD_VAR: ${var}` and exit. Normally no notify — **but if `FROM_REPLY=1`**, first close the loop with `./notify "Couldn't read \"${var#set-target:}\" as a price. Reply with a number like 0.000005."` (a force-reply always deserves an acknowledgement). - If the remainder was empty, `TARGETS=()` is fine — ATH and sharp-move gates still run. ### 2. Resolve tracked token ```bash mkdir -p memory/topics [ -f memory/topics/price-alert-state.json ] || cat > memory/topics/price-alert-state.json <<'EOF' {"contract":null,"chain":null,"ath":null,"last_alerts":{"ath":null,"sharp_move":null,"target_hit":null},"targets":{}} EOF ``` Parse the "Tracked Token" table in `memory/MEMORY.md`. Pull `CONTRACT` (column 2 of the first data row) and `CHAIN` (column 3, lowercased). If the section is missing, the table is empty, or the contract field doesn't match `^0x[0-9a-fA-F]{40}$` → log `PRICE_ALERT_NO_TOKEN` and exit (no notify, no state write). If the state file's `contract` is set and differs from the resolved contract → log `PRICE_ALERT_TOKEN_CHANGED` and reset the state file to defaults with the new contract/chain. ATH starts over with the new token. ### 3. Fetch current price (DexScreener primary) ```bash RESP=$(curl -fsS "https://api.dexscreener.com/latest/dex/tokens/${CONTRACT}" 2>/dev/null || echo "") ``` If the response is empty, falsy, or `jq` can't parse it → fall back to **WebFetch** on the same URL with prompt `"Return the raw JSON body verbatim."` and try again. If both paths fail → log `PRICE_ALERT_FETCH_FAIL` and exit with status `ERROR` (no notify, no state mutation beyond touching `last_run_at`). From the parsed JSON: - Filter `.pairs[]` to entries where `.chainId == "${CHAIN}"`. - Of those, pick the entry with the **highest `.liquidity.usd`** — call this the deepest pool. If no pair matches the chain, fall back to the highest-liquidity pair across all chains and mark `chain=fallback` in the log. - Extract: `CURRENT_PRICE=.priceUsd` (float), `H1_CHANGE_PCT=.priceChange.h1` (float, may be missing → treat as 0), `H24_CHANGE_PCT=.priceChange.h24` (float, may be missing → treat as 0), `POOL_URL=.url`. If `CURRENT_PRICE` is missing, zero, or non-numeric → log `PRICE_ALERT_BAD_PRICE` and exit `ERROR`. ### 4. Evaluate ATH gate ``` prior_ath = state.ath.price_usd (null on first run) new_ath = (prior_ath is null) OR (CURRENT_PRICE > prior_ath) ``` If `new_ath`: - Always update `state.ath.price_usd = CURRENT_PRICE`, `state.ath.observed_at = NOW`. - Notify only if the last `ath` alert was >4h ago (or never). On the first run after token initialisation, suppress the notification (we don't know if this is genuinely an ATH or just the starting baseline) — set `state.ath.announced_at = NOW` so subsequent strict-higher prices alert correctly. - If suppressed because `prior_ath is null` (first run), record verdict `ATH_BASELINE` for the log; no notify. - Otherwise verdict for this gate is `ATH`. ### 5. Evaluate sharp-move gate ``` sharp = abs(H1_CHANGE_PCT) >= 20.0 ``` If `sharp`: - If `state.last_alerts.sharp_move` is within the last 4h → verdict `SHARP_MOVE_DEDUPED`, no notify. - Otherwise verdict `SHARP_MOVE`, notify, set `state.last_alerts.sharp_move = NOW`. Sign of `H1_CHANGE_PCT` decides the direction word in the message (`up` for ≥0, `down` for <0). ### 6. Evaluate target-crossing gate For each target in `TARGETS`: - If the target isn't yet in `state.targets`: this is the first time the operator has set it. Record `side` (`above` if `CURRENT_PRICE < target`, else `below`), `first_seen_below_at=NOW`, `hit_at=null`, `announced_at=null`. **Do not notify on first observation.** This avoids "the price was already there when you set the target" noise. - If the target is in `state.targets` and `hit_at` is already set → skip; target-hit alerts are one-shot per side. - Otherwise check the cross: - `side=above` & `CURRENT_PRICE >= target` → crossed. - `side=below` & `CURRENT_PRICE <= target` → crossed. - On cross: set `hit_at=NOW`, `announced_at=NOW`, verdict `TARGET_HIT` for this target, notify (subject to 4h dedup on `last_alerts.target_hit`). Targets that crossed in prior runs stay in the state file with `hit_at` set so they don't refire if the price wobbles back. ### 7. Combine verdicts and notify Run-level verdict precedence (used for the log status line and the notification ordering): 1. `ATH` — strict new high after baseline. 2. `TARGET_HIT` — operator-set level crossed. 3. `SHARP_MOVE` — ±20% in 1h. 4. `OK` — no gate fired. If multiple gates fired in the same run, send one notification per gate. Each gate independently respects its own dedup clock — an ATH and a TARGET_HIT in the same run produce two messages; an ATH and a SHARP_MOVE_DEDUPED produce one. #### Notification templates **ATH:** ``` *$TOKEN — New ATH — ${today}* $TOKEN just printed a new all-time high at $X.XXXXe-N. Previous ATH: $Y.YYYYe-N (set ${prior_ath_age} ago). 24h move: ±Z.Z% · 1h move: ±W.W% Chart: ${POOL_URL} ``` **SHARP_MOVE:** ``` *$TOKEN — Sharp 1h Move — ${today}* $TOKEN ${up|down} ${abs(h1):.1f}% in the last hour — now $X.XXXXe-N. 24h: ±Z.Z% ${one of: "Buyer wave — watch for follow-through." | "Selling pressure — watch the next hour for stabilisation." } Chart: ${POOL_URL} ``` (Direction phrase is hard-coded by sign: positive = buyer wave; negative = selling pressure. No freelance commentary.) **TARGET_HIT:** ``` *$TOKEN — Target Hit — ${today}* $TOKEN just crossed $${target} (now $X.XXXXe-N). Direction: ${above|below} 24h: ±Z.Z% · 1h: ±W.W% Chart: ${POOL_URL} ``` If `MODE == dry-run`: build the messages, log the planned notifications, but skip `./notify`. State still updates so dedup clocks advance correctly. Cap each message at ~2500 chars; price-alert messages are short by nature and shouldn't approach this. #### Send the alert Build each firing gate's message to a file and send it with `./notify -f alert.md` (one send per gate). State still advances even on a deduped run, so the dedup clocks stay correct. #### Set-a-target follow-up (force-reply) Buttons and force_reply can't share one message, so this is a **separate** send. After a genuine **ATH** alert (post-baseline, not a deduped repeat), and only when no un-hit operator target currently sits above `CURRENT_PRICE` (don't nag operators who already queued one), offer to capture the next level: ```bash ./notify "New high — want an alert when $SYMBOL clears a level above this? Reply with a price." \ --force-reply --placeholder "e.g. 0.000005" \ --context "price-alert::set-target" ``` The reply routes back as `var=set-target:<price>` (handled in step 1). On that run, once the target is registered (step 6, first-observation — no cross alert), close the loop with a one-line confirmation: `./notify "Target set: \$<price> for $SYMBOL — I'll alert you when it crosses."` (Send it only when a *new* target was actually registered this run.) ### 8. Persist state Rewrite `memory/topics/price-alert-state.json` atomically: ```bash TMP=$(mktemp) jq --arg ts "$(date -u +%FT%TZ)" ' .last_run_at = $ts | .contract = $contract | .chain = $chain | .ath = $ath_obj | .last_alerts = $last_alerts_obj | .targets = $targets_obj ' memory/topics/price-alert-state.json > "$TMP" mv "$TMP" memory/topics/price-alert-state.json ``` Validate with `jq empty memory/topics/price-alert-state.json` after writing; if it fails, restore from a `.bak` copy and log `PRICE_ALERT_STATE_CORRUPT`. Keep one `.bak` rolling. Cap `state.targets` to 20 most-recent entries (LRU by `first_seen_below_at`) so a long-running fork doesn't accumulate stale operator targets. ### 9. Log Append to `memory/logs/${today}.md`: ``` ## Price Threshold Alert - **Skill**: price-alert - **Token**: ${SYMBOL} (${CONTRACT}) - **Current**: $X.XXXXe-N | 1h: ±W.W% | 24h: ±Z.Z% - **ATH**: $Y.YYYYe-N (set ${YYYY-MM-DD HH:MM} UTC) [${UNCHANGED|NEW}] - **Sharp-move gate**: ${FIRED|QUIET|DEDUPED} - **Targets evaluated**: ${comma-list of target prices} → ${comma-list of per-target verdicts} - **Verdicts fired**: ${comma-list, or NONE} - **Notifications sent**: ${N} - **Status**: ${PRICE_ALERT_OK | PRICE_ALERT_ATH | PRICE_ALERT_SHARP_MOVE | PRICE_ALERT_TARGET_HIT | PRICE_ALERT_DRY_RUN | PRICE_ALERT_NO_TOKEN | PRICE_ALERT_TOKEN_CHANGED | PRICE_ALERT_FETCH_FAIL | PRICE_ALERT_BAD_PRICE | PRICE_ALERT_BAD_VAR | PRICE_ALERT_STATE_CORRUPT} ``` The status field carries the *highest-priority* gate fired this run, or the most relevant error. `OK` means the run completed cleanly and no gate fired. ## Exit taxonomy | Status | Meaning | Notify? | |--------|---------|---------|
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub