Initial commit: coin-hunter skill

This commit is contained in:
2026-04-16 03:03:25 +08:00
commit b0fd582478
9 changed files with 1170 additions and 0 deletions

296
SKILL.md Normal file
View File

@@ -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:
- `<theme> meme coin trending`
- `<chain> meme coin watchlist`
- `new meme coin listed`
- `<coin> market cap liquidity`
- `<coin> holders tokenomics`
- `<coin> 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 <SYMBOL>`
2. optionally run `python3 scripts/market_probe.py bybit-klines <SYMBOL> --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 <name>` 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 <address>` 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.

View File

@@ -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. <coin>
- **Verdict:**
- **Radar score:** X/12
- **Why it made the cut:**
- **Biggest flaw:**
### 2. <coin>
- **Verdict:**
- **Radar score:** X/12
- **Why it made the cut:**
- **Biggest flaw:**
### 3. <coin>
- **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.

View File

@@ -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.

View File

@@ -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 its 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

109
references/scam-signals.md Normal file
View File

@@ -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.

View File

@@ -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:
- `<coin> market cap liquidity`
- `<coin> holders tokenomics`
- `<coin> rug risk`
- `<coin> listed on exchange`
4. **Cross-check timing**
- Search whether the coin is already broadly saturated:
- `<coin> trending X`
- `<coin> breakout volume`
- `<coin> 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.

View File

@@ -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

View File

@@ -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()

243
scripts/market_probe.py Normal file
View File

@@ -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()