/crypto-price
Router для скилла цен и графиков крипты.
Trigger
Когда нужен токен прайс, изменение за период или график (BTC, ETH, HYPE, ...).
Commands
/crypto-price <SYMBOL> [duration]
Canonical generic command for any supported token/asset.
python3 {baseDir}/scripts/get_price_chart.py <SYMBOL> [duration]
Telegram Bot API command entities cannot contain hyphens. When wiring this skill into a Telegram Hermes gateway, add valid quick-command aliases such as /price, /crypto, and /crypto_price that point to scripts/price_quick.py. If users may type /crypto-price BTC 2h, make the /crypto alias strip a leading -price token before parsing args; otherwise Telegram may dispatch /crypto with tail -price BTC 2h and the wrapper will treat -price as the symbol.
Source routing is Hyperliquid-first for all live perp symbols from metaAndAssetCtxs, then CoinGecko for crypto tokens, then Yahoo Finance for traditional tickers/aliases (SILVER→SI=F, GOLD→GC=F, SPX→^GSPC, FX, stocks/ETFs when a Yahoo ticker is supplied).
/price <SYMBOL> [duration]
Quick command wrapper for Telegram/gateway. Prints text + verify + MEDIA:<png>.
python3 {baseDir}/scripts/price_quick.py <SYMBOL> [duration]
/spaghetti <SYMBOL...> [duration]
Multi-asset normalized line chart. Use for comparing assets over the same period, e.g. SP500 vs GOLD vs SILVER for 6 months. It normalizes every series to 0% at the first candle and plots % change, so different units/prices are comparable.
python3 {baseDir}/scripts/get_price_chart.py spaghetti SP500 GOLD SILVER 6mo
python3 {baseDir}/scripts/spaghetti_quick.py SP500 GOLD SILVER 6mo
Aliases: compare, multi, basket are accepted as the first script command. Use comma input too: SP500,GOLD,SILVER 6mo.
/hype [duration]
Built-in alias command owned by this same skill. It must remain inside crypto-price, not a separate hype skill.
python3 {baseDir}/scripts/hype_quick.py [duration]
The alias delegates to:
python3 {baseDir}/scripts/get_price_chart.py HYPE [duration]
Command contract
Every generated chart image must include the bottom-right public attribution watermark: Telegram: @human20. Keep this in both standard candlestick/volume charts and spaghetti comparison charts.
Duration: минуты/часы/дни/недели/месяцы. Компактный формат <число>[m|h|d|w|mo], без суффикса = часы. Примеры: 30m, 2h, 3h, 12h, 24h, 2d, 1w, 2weeks, 1mo, 2months; также поддерживаются раздельные формы вроде 1 week, 2 months, 30 мин, 3 часа, 1 месяц. Месяц считается как 30 дней. Default: 24h.
Router Map
- source/duration routing ->
modules/source-routing/SKILL.md - data fetch + chart artifact ->
modules/price-chart/SKILL.md - failures/rate-limit handling ->
modules/ops-fallback/SKILL.md - Hyperliquid live symbol snapshot ->
references/hyperliquid-symbol-map.md - HIP-3 / TradeXYZ ticker meanings ->
references/hip3-tradexyz-tickers.md - protocol revenue / stablecoin yield claim checks ->
references/protocol-revenue-yield-checks.md
HIP-3 routing pitfall
Do not conclude that a non-crypto asset is absent from Hyperliquid after checking only the default perp universe (metaAndAssetCtxs) and spot universe (spotMetaAndAssetCtxs). HIP-3 builder-deployed markets live under perp dex names and use fully-qualified symbols like xyz:SILVER.
Correct lookup order for /price <symbol>:
- Check default Hyperliquid perps.
- Query
perpDexsto discover HIP-3 dexes. - For each dex, query
metaAndAssetCtxswithdex=<name>and match the market name or alias. - Query candles with the full
dex:tickercoin string, e.g.xyz:SILVER, not bareSILVER. - Only then fall back to CoinGecko/Yahoo.
Alias examples from TradeXYZ/HIP-3: SILVER→xyz:SILVER, GOLD→xyz:GOLD, SPX/SP500→xyz:SP500, NASDAQ/NDX→xyz:XYZ100, WTI→xyz:CL, BRENT→xyz:BRENTOIL. See references/hip3-tradexyz-tickers.md before changing source routing.
Protocol revenue / yield claim verification
When the user asks to confirm crypto revenue claims (+25% annual revenue, reserve-yield share, token fundamental impact), do not stop at web-search summaries. Use direct data APIs where possible, then recalculate the claim explicitly:
- protocol revenue run-rate: DefiLlama fees API, usually last 30d annualized
- stablecoin supply: DefiLlama stablecoins API by chain/protocol
- uplift:
supply * reserve_yield * protocol_share / annualized_revenue
Return ranges and label them as back-of-envelope unless the team published official guidance. For details and a Hyperliquid/Coinbase/Circle worked example, see references/protocol-revenue-yield-checks.md.
Quick-command aliases
If a token-specific slash alias (for example /hype) uses Hermes quick_commands with type: exec, keep the alias inside this crypto-price skill and point the quick command to this skill's wrapper (scripts/hype_quick.py). The alias config must forward duration arguments (append_args: true) or expose HERMES_COMMAND_ARGS to the wrapper. Otherwise /alias 2h can call this script without 2h and return a default-period chart while looking superficially successful. See hermes-agent → references/gateway-quick-commands.md for the gateway mechanics.
/hype latency triage
/hype has no relation to chip-crypto-portfolio, /pf, or /pfsync. A complaint about slow /hype must stay in this skill and the Hermes quick-command delivery path. Do not load, edit, benchmark, or sync the portfolio skill for it.
Target normal latency is under 5 seconds. Diagnose the boundary before changing code:
- Fetch the exact Telegram command and response timestamps.
- Compare them with the generated artifact mtime under
$HERMES_HOME/cache/crypto-price/artifacts/. - Benchmark the wrapper directly without sending another Telegram command:
/usr/bin/time -f 'ELAPSED=%e' env HERMES_HOME=/home/hermes/.hermes \ /opt/hermes-agent/venv/bin/python3 \ /home/hermes/.hermes/skills/crypto-price/scripts/hype_quick.py >/tmp/hype-bench.out - Classify the delay:
- command → artifact is slow, but direct wrapper is fast: gateway ingress/scheduling delay; do not rewrite price fetching;
- wrapper itself is slow: inspect network retries/timeouts in
get_price_chart.py; - artifact → Telegram send is slow: inspect native media delivery;
- wrapper returns within ~2s but the command starts much later in a Telegram group: inspect shared executor saturation.
BasePlatformAdapter.handle_message()must not submit Telegram DM-topic recovery toasyncio.to_threadfor group/forum/channel traffic, because that recovery is a no-op there and can queue quick commands behind unrelated synchronous tools.
Do not invoke a real long-running command as an alias test. For /hype, use the direct wrapper benchmark plus file/media-contract tests; use one Telegram E2E only when delivery itself changed.
Output Contract (обязательный)
Всегда вернуть:
symbolиdurationpriceиchange_period_percent(или error)chart_path(если есть)text_plainбез лишнего форматирования- краткий verify (по JSON/файлу)
Если chart_path присутствует, нужно приложить PNG вместе с text_plain.
Delivery Rule (важно)
- В Telegram и других чат-каналах с вложениями отправляй график через
messagetool как файл (filePath/path=chart_path). - После
message action=sendотвечай толькоNO_REPLY, чтобы не было дубля. - Не полагайся на
MEDIA:для файлов из/tmpв Telegram, это может не прикрепиться. - Quick-command wrappers (
hype_quick.py,price_quick.py) обязаны копировать PNG в$HERMES_HOME/cache/crypto-price/artifacts/и печататьMEDIA:<persistent_path>только после проверки непустого файла. - Price quick commands are fail-closed for media: если
chart_pathотсутствует или файл пуст, вернуть ненулевой exit code и явную ошибкуchart unavailable; не выдавать цену как успешный text-only ответ. Регрессияtests/test_quick_media_contract.pyдолжна всегда оставаться зелёной. - Если доступный Telegram sender поддерживает только текст с
MEDIA:<path>(напримерsend_messageбез отдельногоfilePath), сначала скопируй PNG из/tmpв устойчивый путь вроде/home/hermes/workspace/artifacts/crypto_chart_<SYMBOL>_<ts>.png, проверьtest -s/размер, затем отправьMEDIA:<persistent_path>. Если текст+media одним сообщением таймаутится, отправь сначала короткий caption/verify, затем отдельное media-сообщение, и всё равно финальNO_REPLY. MEDIA:оставляй только как запасной вариант для web/local render, когдаmessagetool не нужен.
Duplicate-output triage
If user shows a duplicated caption (HYPE... + verify... repeated under one chart), do not start by rewriting the price script. First check layers:
- Run
python3 scripts/get_price_chart.py HYPE <duration>and confirm JSON contains onetext_plain, oneverify, and onechart_path. - If script output is not duplicated, cause is almost certainly delivery layer: caption + follow-up text,
MEDIA:+ final response, or missingNO_REPLYaftermessagetool. - Verify the Telegram shape with an exact message fetch when possible. If message A has
has_media=true/photo and the price text as caption, and message B hashas_media=falsewith the same text, this is OpenClaw delivery dedupe treatingtext+mediaand finaltext-onlyas different payloads. - For OpenClaw, inspect
reply-delivery.ts,agent-runner-payloads.ts, andblock-reply-pipeline.ts; the durable fix is to suppress a later text-only final payload when the same text was already delivered as a media caption. Seereferences/openclaw-media-caption-dedupe.md. - Check transcript/session JSONL: if toolResult is single but Telegram send/assistant response is double — fix gateway/skill delivery instructions, not price calculation.
- For live Claw additionally check logs around user message: memory-compaction/tool allowlist failures can surface as duplicate diagnostic replies but are a separate gateway/tool-policy issue.
Setup / dependency check
- Chart rendering imports
matplotlibinside_build_chart. If JSON returnschart_path: nullwhile candles exist, first verify the exact Python used by the failing path:- quick commands usually run from the Hermes gateway venv, often
/opt/hermes-agent/.venv/bin/python; - agent/terminal fallback may run plain
/usr/bin/python3.
- quick commands usually run from the Hermes gateway venv, often
- Check both when the failure came from a Telegram group/LLM follow-up:
/opt/hermes-agent/.venv/bin/python - <<'PY' import matplotlib print(matplotlib.__version__) PY python3 - <<'PY' import matplotlib print(matplotlib.__version__) PY - If missing in the gateway venv, install requirements from the active install cwd so editable Hermes paths resolve:
cd /opt/hermes-agent /opt/hermes-agent/.venv/bin/python -m pip install -r /home/hermes/.hermes/skills/crypto-price/requirements.txt - If missing in system Python and the agent terminal path uses
python3, install distro packages or equivalent system deps:apt-get install -y python3-requests python3-numpy python3-pandas python3-yaml python3-matplotlib - Capture the durable lesson as “install the chart dependency in the same Python env the gateway/terminal path actually uses”, not as a claim that charting is broken.
Quick Test Checklist
-
/opt/hermes-agent/venv/bin/python3 /home/hermes/.hermes/skills/crypto-price/scripts/get_price_chart.py BTC -
python3 /home/hermes/.hermes/skills/crypto-price/scripts/get_price_chart.py HYPE 12h -
python3 /home/hermes/.hermes/skills/crypto-price/scripts/get_price_chart.py HYPE 2hreturnsduration: "2h",text_plainsaysover 2h, andchart_pathpoints to an existing PNG. -
python3 /home/hermes/.hermes/skills/crypto-price/scripts/get_price_chart.py HYPE 1wreturnsduration: "1w"and a week-scale chart. -
python3 /home/hermes/.hermes/skills/crypto-price/scripts/get_price_chart.py HYPE 1moreturnsduration: "1mo"and a month-scale chart. -
HERMES_COMMAND_ARGS='1 week' /opt/hermes-agent/venv/bin/python3 /home/hermes/.hermes/skills/crypto-price/scripts/hype_quick.pyprintsover 1wandMEDIA:<png>. - JSON содержит
price|change_period_percent|text_plainпри success - For short windows like
2h, visually verify the chart spans the requested duration, not a trimmed subset. The chart builder must not cut the requested candle window for “breathing room”; use the full duration for both change calculation and x-axis. - If a fractal lands on the same candle as the absolute high/low, verify the chart shows only one price label for that point; absolute markers own those labels to avoid doubled text.
- invalid symbol возвращает понятный error JSON
Manual Review Checklist
- нет секретов/токенов/chat id в skill-файлах
-
text_plainиспользуется как есть (без дополнительной разметки) - fallback path не раскрывает внутренние stack traces
- команда backward-compatible с legacy usage
Done Criteria
-
SKILL.mdhas valid frontmatter and command contract. -
scripts/get_price_chart.py HYPE 12hreturns JSON withsymbol,duration,price,change_period_percent,text_plain, and optionalchart_path. - If
chart_pathis returned, the PNG exists and can be attached by the chat channel. - Invalid symbols return structured error JSON without stack traces.
Canonical Repo / Push Notes
- Runtime installs under
~/.hermes/skills/crypto-pricemay not be git worktrees. The canonical public repo ishttps://github.com/evgyur/crypto-price.git. - When pushing runtime fixes, clone/sync into a clean temp checkout of that repo; preserve repo metadata like
.github/workflows, docs,.clawdhub, fonts, and publish files. - Prefer a surgical patch in the clean checkout over copying the whole runtime file; runtime files may contain whitespace/local drift that would pollute the canonical diff.
- Push the default remote branch (
origin/HEAD; currentlymaster) unless the user asks for another branch. - After push, verify
git ls-remote/remote-head match and, if GitHub Actions are configured, poll the latest workflow run untilsuccessor report the failure explicitly.
Backward-Compat Map
- legacy запуск
python3 {baseDir}/scripts/get_price_chart.py <SYMBOL> [duration]сохранён - legacy описание перенесено в
references/legacy-SKILL.md - код скрипта оставлен без rename для совместимости
- JSON должен включать и
duration, иduration_label; некоторые OpenClaw command aliases and chat delivery checks look fordurationexplicitly. scripts/price_quick.py: generic/price <SYMBOL> [duration]wrapper; parses argv andHERMES_COMMAND_ARGS, printstext_plain, verify line, andMEDIA:<png>.scripts/spaghetti_quick.py:/spaghetti <SYMBOL...> [duration]wrapper for normalized multi-asset comparison charts; default isSP500 GOLD SILVER 6mo./hypein OpenClaw/Hermes must remain a thin alias command inside this samecrypto-priceskill that delegates tocrypto-price/scripts/get_price_chart.py HYPE [duration]; do not create or maintain a separatehypeskill.- Period aliases must preserve the full requested window end-to-end. A prior bug accepted
2hand captionedover 2h, but then trimmed candles to 80% for chart “breathing room”, so the chart/change used ~96 minutes. Do not trim requested-duration candles; if visual padding is needed, adjust axis margins only, not data selection.