commit b0fd582478aa91902fdfb8cb1022e7e3f2b1b773 Author: Tacit Lab Date: Thu Apr 16 03:03:25 2026 +0800 Initial commit: coin-hunter skill diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..13f3e62 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,296 @@ +--- +name: coin-hunter +description: Hunt, triage, and compare speculative crypto coins — especially meme coins, 妖币-style runners, fake-hype pumps, and possible rug/scam setups. Use when a user wants to actively search for coins with breakout potential, rank a shortlist, ask whether a coin still has "妖性", or check whether a token looks late, fragile, manipulated, or likely to be a scam. +--- + +# Coin Hunter + +## Overview + +Use this skill to help a user search for and judge **high-volatility crypto setups** without pretending certainty. + +Default buckets: +- **candidate runner** — has ingredients for further speculative expansion +- **watch-only / incomplete** — interesting, but not clean enough yet +- **late / overheated** — may still move, but entry quality is already poor +- **avoid / scam-risk** — liquidity, distribution, credibility, or structure is too weak + +Frame the work as **speculative pattern recognition**, not investment advice. + +## Core rule + +Judge a coin by **attention + liquidity + distribution + timing** first. Narrative matters, but only when it can attract and hold money. + +A technically weak project can still become a runner. A sophisticated-looking project can still be dead money. + +## Supported request types + +Use this skill for four common modes: +- **single-coin triage** — "look at this coin" +- **active discovery** — "find me coins that could become 妖币" +- **shortlist ranking** — "which of these 5 is most interesting" +- **scam / rug check** — "is this coin just fake hype" + +If the request is broad, ask at most **one compact clarifying question**. Prefer: +- chain +- theme / narrative +- risk level +- whether the user accepts microcaps or wants only reasonably tradable names + +If no preference is given, default to: **liquid speculative candidates, not ultra-illiquid microcaps**. + +## Workflow + +### 1. Identify the mode + +Decide whether the user wants: +- discovery +- triage +- comparison +- scam-check + +Then bias the workflow accordingly. + +### 2. Choose the data path + +Use **structured market data first** when available. Use web search to discover names and collect context, not as the only source of truth. + +Preferred source order: +- **Bybit** for real-time-ish price, 24h turnover, and tradability on a major venue +- **DexScreener** for meme-coin pair discovery, DEX liquidity, and small-cap flow +- **Birdeye** for Solana token activity and confirmation +- **CoinGecko** for market-cap, rank, and metadata cross-check +- **web_search** for discovery, narratives, and scam-discussion context + +Private user state must live outside the skill directory under `~/.coin-hunter/`, not inside `skills/coin-hunter/`. +Read `references/provider-playbook.md` when choosing which source to trust first. +Read `references/user-data-layout.md` when adding or updating personal accounts, positions, watchlists, or notes. +Use `scripts/market_probe.py` for deterministic provider lookups. +Use `scripts/init_user_state.py` to initialize the private user-data directory. + +### 3. Discovery mode: build a candidate list + +When the user wants active search rather than analysis of a known ticker, use public web sources to build a shortlist. + +Look for evidence of: +- rising attention +- listing or venue expansion +- narrative/theme alignment +- market-cap and liquidity context +- breakout discussion or unusual participation + +Useful search patterns include: +- ` meme coin trending` +- ` meme coin watchlist` +- `new meme coin listed` +- ` market cap liquidity` +- ` holders tokenomics` +- ` rug risk` + +Do not trust a single source or a single viral thread. Build the list first, then vet the names. + +Read `references/search-workflow.md` for the detailed discovery flow. + +### 4. Triage mode: score the coin on six dimensions + +Assess each coin qualitatively across these dimensions. + +#### A. Narrative fit +Ask: +- Is the story attached to a live theme? +- Is the idea easy to repeat in one sentence? +- Does the symbol / meme / framing have social spread potential? + +Strong examples: +- obvious meme identity +- attached to a live chain or hot sector +- easy cultural hook + +Weak examples: +- vague utility story +- no memorable angle +- cold or stale narrative + +#### B. Attention acceleration +Ask: +- Is visibility rising now? +- Is the coin spreading beyond its original niche? +- Are larger accounts, aggregators, or trading communities starting to notice it? + +Treat **acceleration** as more important than absolute popularity. + +#### C. Liquidity quality +Ask: +- Can a normal user realistically enter and exit? +- Is volume believable relative to market cap and attention? +- Are spreads or venue quality obviously problematic? + +If the user can probably buy but may not be able to exit cleanly, score this harshly. + +#### D. Distribution / holder risk +Ask: +- Is ownership too concentrated? +- Are deployer or team wallets still dangerous? +- Is there an obvious unlock or dump overhang? + +Ugly distribution does not automatically kill a trade, but it makes the setup fragile. + +#### E. Timing / chart state +Ask: +- Is it emerging from a base or already vertical? +- Has participation expanded recently? +- Do pullbacks hold, or do they collapse? + +Prefer: +- fresh breakout from longer consolidation +- early or mid-stage expansion +- resilient retraces + +Be cautious when: +- it already went parabolic +- volume fades after the first mania burst +- price action is mostly wick-and-dump behavior + +#### F. Rug / scam risk +Check for: +- fake partnerships or fake listing claims +- unverifiable team paired with aggressive promotion +- suspicious contract / public warning signals +- impossible tokenomics promises +- unverified liquidity-lock claims +- nothing but shill posts and no independent discussion + +One severe scam signal can outweigh several bullish ones. +Read `references/scam-signals.md` when the user specifically asks about rugs, scams, fake hype, manipulation, or exit-liquidity bait. + +### 5. Classify the result + +Use these buckets: + +#### Candidate runner +Use when most are true: +- narrative is live +- attention is accelerating +- liquidity is usable +- timing is not obviously exhausted +- no fatal scam / exit-risk signal is present + +#### Watch-only / incomplete +Use when: +- something is interesting, but evidence is incomplete +- narrative is decent but timing is unclear +- liquidity or distribution is acceptable but not clean +- it deserves monitoring more than action + +#### Late / overheated +Use when: +- the move is already widely noticed +- chart is extended or near blow-off behavior +- upside may remain, but entry quality is poor +- new buyers are at risk of becoming exit liquidity + +#### Avoid / scam-risk +Use when: +- liquidity quality is bad +- exit risk is high +- holder concentration is dangerous +- legitimacy claims are weak or fake +- the setup feels more fabricated than organic + +## Provider execution patterns + +### Known tradable coin +If the user gives a Bybit-listed ticker or asks for current price/tradability: +1. run `python3 scripts/market_probe.py bybit-ticker ` +2. optionally run `python3 scripts/market_probe.py bybit-klines --interval 60 --limit 10` +3. cross-check with CoinGecko when market-cap context matters + +### Meme / 妖币 discovery +If the user wants runners, meme coins, or small-cap candidates: +1. use `web_search` to gather names +2. run `python3 scripts/market_probe.py dex-search ` for the strongest candidates +3. if Solana, run Birdeye when API access is configured +4. use CoinGecko to verify market-cap and ranking +5. only use Bybit if the coin is also on a major CEX + +### Birdeye requirement +`market_probe.py birdeye-token
` requires `BIRDEYE_API_KEY` in the environment. If it is not configured, say so briefly and continue with DexScreener + CoinGecko + web search. + +### Private portfolio state +If the user wants account, position, watchlist, or thesis tracking for coin-hunter: +1. initialize `~/.coin-hunter/` with `python3 scripts/init_user_state.py` +2. store private data only there +3. never place personal holdings inside the skill folder +4. treat the skill folder as logic only, and the user-data directory as state only + +## Output style + +Default to **compact, decision-first** answers. + +For a single coin, include: +- **Verdict** +- **Radar score** — use the 0-12 checklist when evidence is sufficient +- **Why it could run** — 2-4 bullets +- **Why it could fail** — 2-4 bullets +- **What confirms strength** +- **What kills the thesis** +- **Risk line** — clearly state this is speculative, not investment advice + +For multiple coins: +1. rank the shortlist +2. mark each as candidate runner / watch-only / late / avoid +3. state the main attraction and main flaw for each + +Prefer bullets, short sections, and hard judgments over long essays. +Use `references/output-templates.md` when you want a reusable answer skeleton. + +## Practical heuristics + +### Often bullish for speculative expansion +- the meme or story is instantly repeatable +- attention is accelerating, not just present +- volume expands with the move +- pullbacks are bought +- exchange accessibility improves +- more mainstream crypto accounts begin to mention it + +### Often a sign it is late +- everyone is already talking about it +- the chart has been vertical for days +- promotion is everywhere after the main move already happened +- price keeps spiking while structure gets messier + +### Often a sign to avoid +- no trustworthy liquidity information +- suspicious ownership concentration +- clearly manufactured chart behavior +- incoherent or constantly shifting explanation +- obviously botted or repetitive social activity + +## What not to do + +- Do not describe a coin as safe. +- Do not confuse a polished whitepaper with breakout potential. +- Do not imply expected returns. +- Do not recommend leverage. +- Do not ignore slippage and exit risk. +- Do not push microcaps on beginners unless the user explicitly asks for extreme risk. + +## Optional deeper pass + +If the user wants more depth, expand in this order: +1. narrative and timing +2. liquidity and market structure +3. holder / tokenomics risk +4. why it could become a runner +5. why it probably will not +6. watch triggers + +## References + +Read `references/provider-playbook.md` for source selection and provider roles. +Read `references/user-data-layout.md` for private state layout under `~/.coin-hunter/`. +Read `references/radar-checklist.md` for a quick scoring framework. +Read `references/search-workflow.md` for active discovery. +Read `references/output-templates.md` for compact response structure. +Read `references/scam-signals.md` for sharper scam / fake-hype judgment. diff --git a/references/output-templates.md b/references/output-templates.md new file mode 100644 index 0000000..50b6c5c --- /dev/null +++ b/references/output-templates.md @@ -0,0 +1,71 @@ +# Output Templates + +Use these templates to keep answers crisp and decision-first. + +## Single-coin quick triage + +**Verdict:** candidate runner | late / overheated | avoid / scam-risk +**Radar score:** X/12 +**Spec setup quality:** high | medium | low + +**Why it could run** +- ... +- ... +- ... + +**Why it could fail** +- ... +- ... +- ... + +**What confirms strength** +- ... +- ... + +**What kills the thesis** +- ... +- ... + +**Risk note:** This is speculative pattern recognition, not investment advice. + +## Multi-coin shortlist + +### 1. +- **Verdict:** +- **Radar score:** X/12 +- **Why it made the cut:** +- **Biggest flaw:** + +### 2. +- **Verdict:** +- **Radar score:** X/12 +- **Why it made the cut:** +- **Biggest flaw:** + +### 3. +- **Verdict:** +- **Radar score:** X/12 +- **Why it made the cut:** +- **Biggest flaw:** + +**Bottom line** +- Most interesting now: +- Worth watching only: +- Avoid first: + +## Scam-check format + +**Verdict:** likely tradable speculation | fragile / high-risk | avoid / scam-risk + +**Main warning signs** +- ... +- ... + +**Any redeeming signs** +- ... +- ... + +**Decision** +- what a cautious user should do next + +**Risk note:** Absence of red flags is not proof of safety. diff --git a/references/provider-playbook.md b/references/provider-playbook.md new file mode 100644 index 0000000..8074866 --- /dev/null +++ b/references/provider-playbook.md @@ -0,0 +1,92 @@ +# Provider Playbook + +Use this reference when the user wants fresher crypto market data instead of relying only on web search. + +## Source roles + +### Bybit +Use for: +- real-time-ish price +- 24h turnover / volume +- tradability check +- kline context for listed pairs + +Prefer Bybit first when the coin has a clear CEX symbol like `BTCUSDT`, `ETHUSDT`, `BONKUSDT`, etc. + +### DexScreener +Use for: +- meme-coin discovery +- DEX liquidity / pair context +- chain and pool identification +- faster read on small-cap or newly-hot coins + +Prefer DexScreener when: +- the coin is meme-heavy +- it may not be on major CEXs +- you need pair/liquidity context more than exchange execution context + +### Birdeye +Use for: +- Solana meme-coin discovery +- Solana token activity and pair context +- confirming whether a Solana coin has genuine participation + +Birdeye is especially useful when Solana names appear early in discovery. + +### CoinGecko +Use for: +- market-cap cross-check +- ranking / metadata / basic overview +- fallback verification when exchange or DEX data is messy + +Use CoinGecko to sanity-check whether the coin is a real market object with broad coverage. + +## Recommended order + +### For a known Bybit-listed coin +1. Bybit +2. CoinGecko +3. DexScreener if meme angle matters + +### For a meme / 妖币 candidate +1. DexScreener +2. Birdeye if Solana +3. CoinGecko +4. Bybit only if it is also listed there + +### For discovery mode +1. web_search to gather candidate names +2. DexScreener to confirm pair/liquidity reality +3. Birdeye for Solana candidates +4. CoinGecko for market-cap verification +5. Bybit to see whether the name graduated into a major tradable venue + +## What each source answers + +- **Bybit** → "Can I trade it on a major venue, and what does the market look like right now?" +- **DexScreener** → "Does it actually have live DEX flow and liquidity?" +- **Birdeye** → "Is the Solana on-chain activity real enough to care about?" +- **CoinGecko** → "How big is it, and is it broadly recognized?" + +## Practical rule + +Do not make conviction from a single source. + +For high-risk coins, prefer at least two independent checks: +- one trading/liquidity source +- one metadata/market-cap source + +## Token identity hygiene + +DexScreener search can return clones, stale pairs, and same-name distractions. + +Before treating a result as the real target, prefer the pair that has: +- the strongest 24h volume and usable liquidity +- a market cap / FDV that roughly matches CoinGecko or other broad coverage sources +- a chain and venue context that fits the narrative you are checking + +If search results show multiple same-name tokens, explicitly say which contract or pair you are treating as the primary one. + +## Script usage + +Use `scripts/market_probe.py` for deterministic lookups instead of redoing provider URLs by hand. diff --git a/references/radar-checklist.md b/references/radar-checklist.md new file mode 100644 index 0000000..4c06b93 --- /dev/null +++ b/references/radar-checklist.md @@ -0,0 +1,63 @@ +# Coin Radar Checklist + +Use this checklist for fast triage. + +## Fast scorecard + +Score each dimension from 0 to 2. + +- **Narrative** + - 0 = no clear story or hook + - 1 = understandable but weak + - 2 = strong, simple, contagious + +- **Attention acceleration** + - 0 = stagnant / invisible + - 1 = niche chatter rising + - 2 = clearly spreading beyond niche + +- **Liquidity** + - 0 = poor / suspicious / hard to exit + - 1 = usable but thin + - 2 = solid enough for speculation + +- **Distribution quality** + - 0 = dangerous concentration + - 1 = somewhat fragile + - 2 = acceptable for a speculative trade + +- **Timing / chart state** + - 0 = broken or exhausted + - 1 = unclear + - 2 = early-to-mid expansion setup + +- **Scam-risk cleanliness** + - 0 = obvious warnings + - 1 = mixed / uncertain + - 2 = no major public red flags found + +## Quick interpretation + +- **10-12** → strong speculative candidate; timing still matters +- **7-9** → watchlist material; interesting but incomplete +- **4-6** → weak; only for high-risk curiosity +- **0-3** → avoid + +## Compact answer template + +- **Verdict:** +- **Radar score:** X/12 +- **Why it’s interesting:** +- **Main flaws:** +- **What would confirm it:** +- **What would invalidate it:** +- **Risk note:** speculative only, not investment advice + +## Hard-stop red flags + +If any of these appear, strongly consider overriding the score to avoid: +- obvious inability to exit +- strong public rug warnings +- fake or unverifiable listing/partnership claims +- extreme wallet concentration with live dump risk +- chart structure that looks purely manipulated diff --git a/references/scam-signals.md b/references/scam-signals.md new file mode 100644 index 0000000..90fd5a3 --- /dev/null +++ b/references/scam-signals.md @@ -0,0 +1,109 @@ +# Scam / Fake-Hype Signals + +Use this reference when a user asks whether a coin is a rug, scam, fake narrative pump, or suspicious meme coin. + +## Goal + +Separate three different bad cases: +- **obvious scam-risk** — high chance of rug, manipulation, or fabricated legitimacy +- **fake-hype / low-quality pump** — may trade, but the story is mostly noise and exit liquidity risk is high +- **messy but tradable** — ugly structure, but not enough evidence to call it a scam + +Do not collapse all weak coins into "scam." Be precise. + +## Primary red flags + +### 1. Liquidity illusion +Warning signs: +- the coin appears tradable, but exits are unclear +- volume looks large relative to real attention +- spreads are erratic or suspiciously wide +- price moves hard on small visible participation + +Interpretation: +- if buyers can enter more easily than they can exit, treat this as a severe warning + +### 2. Holder concentration risk +Warning signs: +- a few wallets dominate supply +- deployer/team wallets remain powerful +- clustered wallets look related +- unlock or dump overhang seems obvious + +Interpretation: +- concentration does not automatically mean scam, but it makes the coin structurally fragile +- if concentration is extreme and active, classify closer to avoid / scam-risk + +### 3. Legitimacy theater +Warning signs: +- loud claims of partnerships with no verifiable source +- fake exchange-listing rumors +- website looks polished but contains no falsifiable specifics +- team bios are vague, recycled, or unverifiable +- social posts overpromise and under-document + +Interpretation: +- fake credibility signals are often more important than weak fundamentals + +### 4. Social proof distortion +Warning signs: +- comments feel repetitive or botted +- follower count is high but engagement quality is low +- shill accounts post identical talking points +- the project feels ubiquitous inside its own bubble but invisible elsewhere + +Interpretation: +- hype quality matters more than hype quantity + +### 5. Chart manipulation smell +Warning signs: +- repeated long wicks without stable follow-through +- random explosive candles with no broader market pickup +- price repeatedly returns to the same area after dramatic spikes +- pattern looks designed to bait breakout traders + +Interpretation: +- manufactured excitement often looks different from organic expansion + +## Secondary warning signs + +These do not prove scam by themselves, but they weaken the case: +- narrative changes every few days +- too many sectors/themes stapled together +- tokenomics explanation is confusing on purpose +- everything depends on one influencer wave +- no credible venue improvement despite heavy promotion + +## Useful distinctions + +### Scam-risk +Use when one or more of these are true: +- severe exit/liquidity concerns +- strong public warnings from multiple independent places +- fabricated legitimacy claims look credible +- wallet concentration plus active dump risk is severe + +### Fake-hype / low-quality pump +Use when: +- the coin may still trade, but most of the fuel is shallow attention +- quality of discussion is poor +- market structure looks weak +- timing is bad and late buyers are likely exit liquidity + +### Messy but tradable +Use when: +- structure is ugly, but not enough to call scam +- there is still credible liquidity and real attention +- risk is high, but the market is not obviously fake + +## Output guidance + +When scam risk is part of the analysis, include: +- **Suspicion level:** low / medium / high +- **Main red flags:** 2-5 bullets +- **What would reduce suspicion:** specific evidence, not vibes +- **Bottom line:** tradable speculation / watch-only / avoid + +## Hard override rule + +Even if the narrative and attention look strong, classify as **avoid / scam-risk** when exit risk or fabricated legitimacy is severe enough. diff --git a/references/search-workflow.md b/references/search-workflow.md new file mode 100644 index 0000000..55593eb --- /dev/null +++ b/references/search-workflow.md @@ -0,0 +1,90 @@ +# Search Workflow + +Use this workflow when the user wants you to proactively discover meme-coin / 妖币 candidates instead of analyzing a known ticker. + +## Goal + +Produce a shortlist with enough evidence to answer: +- what deserves attention now +- what is merely noisy +- what should be avoided + +## Default search strategy + +Unless the user specifies otherwise, search for **liquid speculative candidates** first and avoid ultra-microcaps. + +Run search in this order: + +1. **Theme scan** + - Search current meme-coin themes by chain or narrative + - Examples: + - `Solana meme coins trending` + - `Base meme coin watchlist` + - `AI meme coin trending` + - `new meme coin listed today` + +2. **Candidate extraction** + - Pull out repeated names that appear across multiple sources + - Prefer coins that appear in both market-oriented and community-oriented sources + +3. **Candidate verification** + - For each candidate, search: + - ` market cap liquidity` + - ` holders tokenomics` + - ` rug risk` + - ` listed on exchange` + +4. **Cross-check timing** + - Search whether the coin is already broadly saturated: + - ` trending X` + - ` breakout volume` + - ` price surge` + - If it is already universally discussed, consider classifying it as late rather than early + +## Source preference + +Prefer a mix of: +- credible exchange announcements or listing pages +- market data summaries +- crypto news aggregation +- community/trading discussion summaries + +Do not rely entirely on project websites or obvious promotion pages. + +## Discovery rules + +### Good candidate signs during search +- name appears repeatedly across different sources +- tied to a live narrative or active chain +- discussion suggests recent acceleration, not just old fame +- accessible enough that the user can realistically trade it + +### Weak candidate signs during search +- only appears in promotional pages +- only appears on tiny venues +- no independent discussion or market data context +- most results are already about an explosive move that happened days ago + +## Shortlist size + +Default to **3-5 candidates**. + +If the search returns many names: +- keep the most repeated +- keep the ones with the clearest narrative +- remove obviously illiquid or scammy names first + +## Output shape for discovery mode + +For each shortlisted candidate include: +- ticker / name +- chain / venue context if known +- why it entered the shortlist +- biggest risk +- tentative bucket: candidate runner / watch-only / avoid + +Then give a final rank order. + +## Notes + +When evidence is weak, say so. Discovery mode is for narrowing attention, not pretending certainty. diff --git a/references/user-data-layout.md b/references/user-data-layout.md new file mode 100644 index 0000000..1f3d68c --- /dev/null +++ b/references/user-data-layout.md @@ -0,0 +1,143 @@ +# User Data Layout + +Store private coin-hunter data outside the skill directory. + +## Root directory + +Use: + +```text +~/.coin-hunter/ +``` + +This keeps personal accounts, positions, and watchlists out of packaged skill artifacts. + +## Layout + +```text +~/.coin-hunter/ +├── config.json +├── accounts.json +├── positions.json +├── watchlist.json +├── notes.json +└── cache/ +``` + +## File roles + +### config.json +Store user-level defaults. + +Suggested fields: +- `default_exchange` +- `default_quote_currency` +- `timezone` +- `preferred_chains` + +Example: + +```json +{ + "default_exchange": "bybit", + "default_quote_currency": "USDT", + "timezone": "Asia/Shanghai", + "preferred_chains": ["solana", "base"] +} +``` + +### accounts.json +Store exchange accounts and balances. + +Example: + +```json +{ + "accounts": [ + { + "id": "bybit-main", + "exchange": "bybit", + "label": "Bybit Main", + "currency": "USDT", + "cash_balance": 0, + "available_cash": 0, + "updated_at": null, + "note": "" + } + ] +} +``` + +### positions.json +Store coin positions. + +Example: + +```json +{ + "positions": [ + { + "account_id": "bybit-main", + "symbol": "BTCUSDT", + "base_asset": "BTC", + "quote_asset": "USDT", + "market_type": "spot", + "quantity": 0, + "avg_cost": 0, + "opened_at": null, + "updated_at": null, + "note": "" + } + ] +} +``` + +### watchlist.json +Store watched coins. + +Example: + +```json +{ + "watchlist": [ + { + "symbol": "FARTCOIN", + "chain": "solana", + "contract_address": null, + "source": "manual", + "status": "watching", + "added_at": null, + "note": "" + } + ] +} +``` + +### notes.json +Store discretionary notes and thesis fragments. + +Example: + +```json +{ + "notes": [ + { + "symbol": "FARTCOIN", + "title": "Why this stays on radar", + "body": "Good liquidity, strong meme spread, only for high-risk observation.", + "updated_at": null + } + ] +} +``` + +### cache/ +Store disposable API results or normalized snapshots. Never treat this as source-of-truth portfolio state. + +## Rules + +- Keep personal data only under `~/.coin-hunter/` +- Never write personal account or position data into `skills/coin-hunter/` +- Treat `cache/` as disposable +- Prefer stable IDs for accounts like `bybit-main` +- For meme coins, include `chain` and `contract_address` when known diff --git a/scripts/init_user_state.py b/scripts/init_user_state.py new file mode 100644 index 0000000..1cce039 --- /dev/null +++ b/scripts/init_user_state.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +import json +from datetime import datetime, timezone +from pathlib import Path + +ROOT = Path.home() / ".coin-hunter" +CACHE_DIR = ROOT / "cache" + + +def now_iso(): + return datetime.now(timezone.utc).replace(microsecond=0).isoformat() + + +def ensure_file(path: Path, payload: dict): + if path.exists(): + return False + path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + return True + + +def main(): + ROOT.mkdir(parents=True, exist_ok=True) + CACHE_DIR.mkdir(parents=True, exist_ok=True) + + created = [] + ts = now_iso() + + templates = { + ROOT / "config.json": { + "default_exchange": "bybit", + "default_quote_currency": "USDT", + "timezone": "Asia/Shanghai", + "preferred_chains": ["solana", "base"], + "created_at": ts, + "updated_at": ts, + }, + ROOT / "accounts.json": { + "accounts": [] + }, + ROOT / "positions.json": { + "positions": [] + }, + ROOT / "watchlist.json": { + "watchlist": [] + }, + ROOT / "notes.json": { + "notes": [] + }, + } + + for path, payload in templates.items(): + if ensure_file(path, payload): + created.append(str(path)) + + print(json.dumps({ + "root": str(ROOT), + "created": created, + "cache_dir": str(CACHE_DIR), + }, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/scripts/market_probe.py b/scripts/market_probe.py new file mode 100644 index 0000000..2e41344 --- /dev/null +++ b/scripts/market_probe.py @@ -0,0 +1,243 @@ +#!/usr/bin/env python3 +import argparse +import json +import os +import sys +import urllib.parse +import urllib.request + +DEFAULT_TIMEOUT = 20 + + +def fetch_json(url, headers=None, timeout=DEFAULT_TIMEOUT): + merged_headers = { + "Accept": "application/json", + "User-Agent": "Mozilla/5.0 (compatible; OpenClaw Coin Hunter/1.0)", + } + if headers: + merged_headers.update(headers) + req = urllib.request.Request(url, headers=merged_headers) + with urllib.request.urlopen(req, timeout=timeout) as resp: + data = resp.read() + return json.loads(data.decode("utf-8")) + + +def print_json(data): + print(json.dumps(data, ensure_ascii=False, indent=2)) + + +def bybit_ticker(symbol: str): + url = ( + "https://api.bybit.com/v5/market/tickers?category=spot&symbol=" + + urllib.parse.quote(symbol.upper()) + ) + payload = fetch_json(url) + items = payload.get("result", {}).get("list", []) + if not items: + raise SystemExit(f"No Bybit spot ticker found for {symbol}") + item = items[0] + out = { + "provider": "bybit", + "symbol": symbol.upper(), + "lastPrice": item.get("lastPrice"), + "price24hPcnt": item.get("price24hPcnt"), + "highPrice24h": item.get("highPrice24h"), + "lowPrice24h": item.get("lowPrice24h"), + "turnover24h": item.get("turnover24h"), + "volume24h": item.get("volume24h"), + "bid1Price": item.get("bid1Price"), + "ask1Price": item.get("ask1Price"), + } + print_json(out) + + +def bybit_klines(symbol: str, interval: str, limit: int): + params = urllib.parse.urlencode({ + "category": "spot", + "symbol": symbol.upper(), + "interval": interval, + "limit": str(limit), + }) + url = f"https://api.bybit.com/v5/market/kline?{params}" + payload = fetch_json(url) + rows = payload.get("result", {}).get("list", []) + out = { + "provider": "bybit", + "symbol": symbol.upper(), + "interval": interval, + "candles": [ + { + "startTime": r[0], + "open": r[1], + "high": r[2], + "low": r[3], + "close": r[4], + "volume": r[5], + "turnover": r[6], + } + for r in rows + ], + } + print_json(out) + + +def dexscreener_search(query: str): + url = "https://api.dexscreener.com/latest/dex/search/?q=" + urllib.parse.quote(query) + payload = fetch_json(url) + pairs = payload.get("pairs") or [] + out = [] + for p in pairs[:10]: + out.append({ + "chainId": p.get("chainId"), + "dexId": p.get("dexId"), + "pairAddress": p.get("pairAddress"), + "url": p.get("url"), + "baseToken": p.get("baseToken"), + "quoteToken": p.get("quoteToken"), + "priceUsd": p.get("priceUsd"), + "liquidityUsd": (p.get("liquidity") or {}).get("usd"), + "fdv": p.get("fdv"), + "marketCap": p.get("marketCap"), + "volume24h": (p.get("volume") or {}).get("h24"), + "buys24h": ((p.get("txns") or {}).get("h24") or {}).get("buys"), + "sells24h": ((p.get("txns") or {}).get("h24") or {}).get("sells"), + }) + print_json({"provider": "dexscreener", "query": query, "pairs": out}) + + +def dexscreener_token(chain: str, address: str): + url = f"https://api.dexscreener.com/tokens/v1/{urllib.parse.quote(chain)}/{urllib.parse.quote(address)}" + payload = fetch_json(url) + pairs = payload if isinstance(payload, list) else payload.get("pairs") or [] + out = [] + for p in pairs[:10]: + out.append({ + "chainId": p.get("chainId"), + "dexId": p.get("dexId"), + "pairAddress": p.get("pairAddress"), + "baseToken": p.get("baseToken"), + "quoteToken": p.get("quoteToken"), + "priceUsd": p.get("priceUsd"), + "liquidityUsd": (p.get("liquidity") or {}).get("usd"), + "fdv": p.get("fdv"), + "marketCap": p.get("marketCap"), + "volume24h": (p.get("volume") or {}).get("h24"), + }) + print_json({"provider": "dexscreener", "chain": chain, "address": address, "pairs": out}) + + +def coingecko_search(query: str): + url = "https://api.coingecko.com/api/v3/search?query=" + urllib.parse.quote(query) + payload = fetch_json(url) + coins = payload.get("coins") or [] + out = [] + for c in coins[:10]: + out.append({ + "id": c.get("id"), + "name": c.get("name"), + "symbol": c.get("symbol"), + "marketCapRank": c.get("market_cap_rank"), + "thumb": c.get("thumb"), + }) + print_json({"provider": "coingecko", "query": query, "coins": out}) + + +def coingecko_coin(coin_id: str): + params = urllib.parse.urlencode({ + "localization": "false", + "tickers": "false", + "market_data": "true", + "community_data": "false", + "developer_data": "false", + "sparkline": "false", + }) + url = f"https://api.coingecko.com/api/v3/coins/{urllib.parse.quote(coin_id)}?{params}" + payload = fetch_json(url) + md = payload.get("market_data") or {} + out = { + "provider": "coingecko", + "id": payload.get("id"), + "symbol": payload.get("symbol"), + "name": payload.get("name"), + "marketCapRank": payload.get("market_cap_rank"), + "currentPriceUsd": (md.get("current_price") or {}).get("usd"), + "marketCapUsd": (md.get("market_cap") or {}).get("usd"), + "fullyDilutedValuationUsd": (md.get("fully_diluted_valuation") or {}).get("usd"), + "totalVolumeUsd": (md.get("total_volume") or {}).get("usd"), + "priceChangePercentage24h": md.get("price_change_percentage_24h"), + "priceChangePercentage7d": md.get("price_change_percentage_7d"), + "priceChangePercentage30d": md.get("price_change_percentage_30d"), + "circulatingSupply": md.get("circulating_supply"), + "totalSupply": md.get("total_supply"), + "maxSupply": md.get("max_supply"), + "homepage": (payload.get("links") or {}).get("homepage", [None])[0], + } + print_json(out) + + +def birdeye_token(address: str): + api_key = os.getenv("BIRDEYE_API_KEY") or os.getenv("BIRDEYE_APIKEY") + if not api_key: + raise SystemExit("Birdeye requires BIRDEYE_API_KEY in the environment") + url = "https://public-api.birdeye.so/defi/token_overview?address=" + urllib.parse.quote(address) + payload = fetch_json(url, headers={ + "x-api-key": api_key, + "x-chain": "solana", + }) + print_json({"provider": "birdeye", "address": address, "data": payload.get("data")}) + + +def build_parser(): + parser = argparse.ArgumentParser(description="Coin Hunter market data probe") + sub = parser.add_subparsers(dest="command", required=True) + + p = sub.add_parser("bybit-ticker", help="Fetch Bybit spot ticker") + p.add_argument("symbol") + + p = sub.add_parser("bybit-klines", help="Fetch Bybit spot klines") + p.add_argument("symbol") + p.add_argument("--interval", default="60", help="Bybit interval, e.g. 1, 5, 15, 60, 240, D") + p.add_argument("--limit", type=int, default=10) + + p = sub.add_parser("dex-search", help="Search DexScreener by query") + p.add_argument("query") + + p = sub.add_parser("dex-token", help="Fetch DexScreener token pairs by chain/address") + p.add_argument("chain") + p.add_argument("address") + + p = sub.add_parser("gecko-search", help="Search CoinGecko") + p.add_argument("query") + + p = sub.add_parser("gecko-coin", help="Fetch CoinGecko coin by id") + p.add_argument("coin_id") + + p = sub.add_parser("birdeye-token", help="Fetch Birdeye token overview (Solana)") + p.add_argument("address") + + return parser + + +def main(): + parser = build_parser() + args = parser.parse_args() + if args.command == "bybit-ticker": + bybit_ticker(args.symbol) + elif args.command == "bybit-klines": + bybit_klines(args.symbol, args.interval, args.limit) + elif args.command == "dex-search": + dexscreener_search(args.query) + elif args.command == "dex-token": + dexscreener_token(args.chain, args.address) + elif args.command == "gecko-search": + coingecko_search(args.query) + elif args.command == "gecko-coin": + coingecko_coin(args.coin_id) + elif args.command == "birdeye-token": + birdeye_token(args.address) + else: + parser.error("Unknown command") + + +if __name__ == "__main__": + main()