mirror of
https://github.com/GMGNAI/gmgn-skills.git
synced 2026-08-15 09:08:05 +00:00
feat(market): add min/max range filters to trending command
- Register dynamic --min-*/--max-* flags on `market trending`, mirroring the trenches pattern; forwarded as min_<metric>/max_<metric> query params to /v1/market/rank - Add RANK_RANGE_FIELDS covering the 18 numeric metrics plus min/max-created token-age windows (m/h/d duration strings, passed through as-is) - Document range filters and web-client filter aliases in SKILL.md, cli-usage.md, Readme.md and Readme.zh.md Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4205bda0af
commit
ca55a80d12
@@ -461,6 +461,13 @@ gmgn-cli market trending \
|
||||
--order-by volume --limit 20 \
|
||||
--filter not_risk --filter not_honeypot
|
||||
|
||||
# Trending with numeric range filters (min_*/max_* are forwarded as query params)
|
||||
gmgn-cli market trending \
|
||||
--chain sol --interval 1h \
|
||||
--min-liquidity 10000 --max-liquidity 1000000 \
|
||||
--max-created 30m --min-smart-degen-count 1 \
|
||||
--order-by volume --limit 30
|
||||
|
||||
gmgn-cli market trenches \
|
||||
--chain sol \
|
||||
--type new_creation --type near_completion --type completed \
|
||||
|
||||
@@ -491,6 +491,13 @@ gmgn-cli market trending \
|
||||
--order-by volume --limit 20 \
|
||||
--filter not_risk --filter not_honeypot
|
||||
|
||||
# 热门榜 + 数值范围过滤(min_*/max_* 以查询参数透传)
|
||||
gmgn-cli market trending \
|
||||
--chain sol --interval 1h \
|
||||
--min-liquidity 10000 --max-liquidity 1000000 \
|
||||
--max-created 30m --min-smart-degen-count 1 \
|
||||
--order-by volume --limit 30
|
||||
|
||||
# 战壕新币列表
|
||||
gmgn-cli market trenches \
|
||||
--chain sol \
|
||||
|
||||
+6
-3
@@ -120,18 +120,21 @@ npx gmgn-cli market trending \
|
||||
[--direction asc|desc] \
|
||||
[--filter <tag>] \
|
||||
[--platform <name>] \
|
||||
[--min-<metric> <n>] [--max-<metric> <n>] \
|
||||
[--raw]
|
||||
```
|
||||
|
||||
| Option | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` |
|
||||
| `--interval` | Yes | `1h` / `3h` / `6h` / `24h` |
|
||||
| `--chain` | Yes | `sol` / `bsc` / `base` / `eth` |
|
||||
| `--interval` | Yes | `1m` / `5m` / `1h` / `6h` / `24h` |
|
||||
| `--limit` | No | Number of results (default 100, max 100) |
|
||||
| `--order-by` | No | Sort field: `volume` / `swaps` / `liquidity` / `marketcap` / `holders` / `price` / `change` / `change1m` / `change5m` / `change1h` / `renowned_count` / `smart_degen_count` / `bluechip_owner_percentage` / `rank` / `creation_timestamp` / `square_mentions` / `history_highest_market_cap` / `gas_fee` |
|
||||
| `--direction` | No | Sort direction: `asc` / `desc` (default `desc`) |
|
||||
| `--filter` | No | Filter tag (repeatable): `has_social` / `not_risk` / `not_honeypot` / `verified` / `locked` / `renounced` / `distributed` / `frozen` / `burn` / `token_burnt` / `creator_hold` / `creator_close` / `creator_add_liquidity` / `creator_remove_liquidity` / `creator_sell` / `creator_buy` / `not_wash_trading` / `not_social_dup` / `not_image_dup` / `is_internal_market` / `is_out_market` |
|
||||
| `--filter` | No | Filter tag (repeatable): `has_social` / `not_risk` / `not_honeypot` / `verified` / `locked` / `renounced` / `distributed` / `frozen` / `burn` / `token_burnt` / `creator_hold` / `creator_close` / `creator_add_liquidity` / `creator_remove_liquidity` / `creator_sell` / `creator_buy` / `not_wash_trading` / `not_social_dup` / `not_image_dup` / `is_internal_market` / `is_out_market`. The gmgn web client also sends aliases `social_not_duplicate` / `img_not_duplicate` / `is_burnt` / `launching` / `migrated`, which are accepted but only the canonical tags change behavior. |
|
||||
| `--platform` | No | Platform filter (repeatable). Omit (or pass an empty list) to include **all** platforms. Available values depend on chain — see below. |
|
||||
| `--min-<metric>` / `--max-<metric>` | No | Numeric range filters (inclusive). Supported metrics: `volume` / `liquidity` / `marketcap` / `history-highest-marketcap` / `swaps` / `holder-count` / `gas-fee` / `renowned-count` / `smart-degen-count` / `bot-degen-count` / `visiting-count` / `price-change-percent` / `insider-rate` / `bundler-rate` / `entrapment-ratio` / `top10-holder-rate` / `top70-sniper-hold-rate` / `dev-team-hold-rate`. Unknown metrics are ignored by the service. |
|
||||
| `--min-created` / `--max-created` | No | Token-age window, duration string (`1m` / `6h` / `7d`). `--min-created` is a minimum age (excludes younger tokens); `--max-created` a maximum age (excludes older tokens). |
|
||||
|
||||
**`sol` platforms:** `Pump.fun` / `pump_mayhem` / `pump_mayhem_agent` / `pump_agent` / `letsbonk` / `bonkers` / `bags` / `memoo` / `liquid` / `bankr` / `zora` / `surge` / `anoncoin` / `moonshot_app` / `wendotdev` / `heaven` / `sugar` / `token_mill` / `believe` / `trendsfun` / `trends_fun` / `jup_studio` / `Moonshot` / `boop` / `xstocks` / `ray_launchpad` / `meteora_virtual_curve` / `pool_ray` / `pool_meteora` / `pool_pump_amm` / `pool_orca`
|
||||
|
||||
|
||||
@@ -146,6 +146,32 @@ The response is an object with a `list` array. Each element in `list` is one can
|
||||
| `--filter <tag...>` | Repeatable filter tags (chain-specific). **⚠️ SOL defaults: `renounced frozen`; BSC/Base/ETH defaults: `not_honeypot verified renounced`.** Omitting `--filter` is NOT "no filter" — chain defaults always apply. **sol** tags: `renounced` / `frozen` / `burn` / `token_burnt` / `has_social` / `not_social_dup` / `not_image_dup` / `dexscr_update_link` / `not_wash_trading` / `is_internal_market` / `is_out_market`. **evm** tags: `not_honeypot` / `verified` / `renounced` / `locked` / `token_burnt` / `has_social` / `not_social_dup` / `not_image_dup` / `dexscr_update_link` / `is_internal_market` / `is_out_market` |
|
||||
| `--platform <name...>` | Repeatable platform filter (chain-specific). **sol**: `Pump.fun` / `pump_mayhem` / `pump_mayhem_agent` / `pump_agent` / `letsbonk` / `bonkers` / `bags` / `memoo` / `liquid` / `bankr` / `zora` / `surge` / `anoncoin` / `moonshot_app` / `wendotdev` / `heaven` / `sugar` / `token_mill` / `believe` / `trendsfun` / `trends_fun` / `jup_studio` / `Moonshot` / `boop` / `xstocks` / `ray_launchpad` / `meteora_virtual_curve` / `pool_ray` / `pool_meteora` / `pool_pump_amm` / `pool_orca`. **bsc**: `fourmeme` / `fourmeme_agent` / `bn_fourmeme` / `four_xmode_agent` / `cubepeg` / `likwid` / `goplus_creator` / `goplus_skills` / `openfour` / `flap` / `flap_stocks` / `flap_aioracle` / `clanker` / `lunafun` / `pool_uniswap` / `pool_pancake`. **base**: `clanker` / `bankr` / `flaunch` / `zora` / `zora_creator` / `baseapp` / `basememe` / `virtuals_v2` / `klik`. **eth**: `trench` / `clanker` / `klik` / `livo` / `stroid` / `pool_uniswap_v2` / `pool_uniswap_v3` / `printr` |
|
||||
|
||||
### `market trending` Range Filters
|
||||
|
||||
Optional `--min-*` / `--max-*` flags apply server-side numeric range filtering (inclusive). Unknown metrics are ignored by the service.
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `--min-volume` / `--max-volume` | Trading volume (USD) |
|
||||
| `--min-liquidity` / `--max-liquidity` | Liquidity (USD) |
|
||||
| `--min-marketcap` / `--max-marketcap` | Market cap (USD) |
|
||||
| `--min-history-highest-marketcap` / `--max-history-highest-marketcap` | Historical highest market cap (USD) |
|
||||
| `--min-swaps` / `--max-swaps` | Swap count |
|
||||
| `--min-holder-count` / `--max-holder-count` | Holder count |
|
||||
| `--min-gas-fee` / `--max-gas-fee` | Gas fee |
|
||||
| `--min-renowned-count` / `--max-renowned-count` | KOL / renowned wallet count |
|
||||
| `--min-smart-degen-count` / `--max-smart-degen-count` | Smart-money holder count |
|
||||
| `--min-bot-degen-count` / `--max-bot-degen-count` | Bot-degen wallet count |
|
||||
| `--min-visiting-count` / `--max-visiting-count` | Visitor count |
|
||||
| `--min-price-change-percent` / `--max-price-change-percent` | Price change ratio over the interval |
|
||||
| `--min-insider-rate` / `--max-insider-rate` | Insider trading ratio (0–1); tokens lacking this field are excluded |
|
||||
| `--min-bundler-rate` / `--max-bundler-rate` | Bundle-bot trading ratio (0–1); tokens lacking this field are excluded |
|
||||
| `--min-entrapment-ratio` / `--max-entrapment-ratio` | Entrapment trading ratio (0–1); tokens lacking this field are excluded |
|
||||
| `--min-top10-holder-rate` / `--max-top10-holder-rate` | Top-10 holder concentration (0–1) |
|
||||
| `--min-top70-sniper-hold-rate` / `--max-top70-sniper-hold-rate` | Top-70 sniper holding ratio (0–1) |
|
||||
| `--min-dev-team-hold-rate` / `--max-dev-team-hold-rate` | Dev-team holding ratio (0–1); `--min-dev-team-hold-rate` also excludes creator-close tokens |
|
||||
| `--min-created` / `--max-created` | Token age window, duration string `1m` / `6h` / `7d`. `--min-created` is a minimum age (excludes younger tokens); `--max-created` a maximum age (excludes older tokens) |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Kline
|
||||
@@ -277,6 +303,28 @@ gmgn-cli market trending \
|
||||
--order-by smart_degen_count --limit 20 --raw
|
||||
```
|
||||
|
||||
### Trending — Numeric Range Filters
|
||||
|
||||
```bash
|
||||
# SOL 1h trending — liquidity 10k–1M, market cap above 50k, sorted by volume
|
||||
gmgn-cli market trending \
|
||||
--chain sol --interval 1h \
|
||||
--min-liquidity 10000 --max-liquidity 1000000 --min-marketcap 50000 \
|
||||
--order-by volume --limit 30 --raw
|
||||
|
||||
# SOL 5m hottest — fresh tokens (under 30 min old) with smart money interest
|
||||
gmgn-cli market trending \
|
||||
--chain sol --interval 5m \
|
||||
--max-created 30m --min-smart-degen-count 1 \
|
||||
--order-by volume --limit 50 --raw
|
||||
|
||||
# SOL 1h trending — exclude high-insider / high-bundler tokens
|
||||
gmgn-cli market trending \
|
||||
--chain sol --interval 1h \
|
||||
--max-insider-rate 0.3 --max-bundler-rate 0.3 \
|
||||
--order-by volume --limit 20 --raw
|
||||
```
|
||||
|
||||
### Trending — Base by Launchpad Platform
|
||||
|
||||
```bash
|
||||
|
||||
+80
-14
@@ -48,7 +48,7 @@ export function registerMarketCommands(program: Command): void {
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
market
|
||||
const trendingCmd = market
|
||||
.command("trending")
|
||||
.description("Get trending token swap data")
|
||||
.requiredOption("--chain <chain>", "Chain: sol / bsc / base / eth")
|
||||
@@ -58,20 +58,40 @@ export function registerMarketCommands(program: Command): void {
|
||||
.option("--direction <dir>", "Sort direction: asc / desc")
|
||||
.option("--filter <tag...>", "Filter tags, repeatable. sol: renounced / frozen / has_social / not_wash_trading / ... evm: not_honeypot / verified / renounced / locked / ... (see docs for full list)")
|
||||
.option("--platform <name...>", "Platform filter, repeatable. sol: Pump.fun / letsbonk / moonshot_app / ... bsc: fourmeme / four_xmode_agent / cubepeg / likwid / goplus_creator / goplus_skills / openfour / flap / flap_stocks / flap_aioracle / clanker / ... base: clanker / flaunch / zora / ... eth: trench / clanker / klik / livo / stroid / pool_uniswap_v2 / pool_uniswap_v3 / printr (see docs for full list)")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
const extra: Record<string, string | number | string[]> = {};
|
||||
if (opts.limit != null) extra["limit"] = opts.limit;
|
||||
if (opts.orderBy) extra["order_by"] = opts.orderBy;
|
||||
if (opts.direction) extra["direction"] = opts.direction;
|
||||
if (opts.filter?.length) extra["filters"] = opts.filter;
|
||||
if (opts.platform?.length) extra["platforms"] = opts.platform;
|
||||
.option("--raw", "Output raw JSON");
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTrendingSwaps(opts.chain, opts.interval, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
// Dynamically register all server-side min_*/max_* range filter flags
|
||||
for (const def of RANK_RANGE_FIELDS) {
|
||||
const flag = def.api.replace(/_/g, "-");
|
||||
if (def.type === "int") {
|
||||
trendingCmd.option(`--${flag} <${def.type}>`, def.desc, parseInt);
|
||||
} else if (def.type === "float") {
|
||||
trendingCmd.option(`--${flag} <${def.type}>`, def.desc, parseFloat);
|
||||
} else {
|
||||
trendingCmd.option(`--${flag} <value>`, def.desc);
|
||||
}
|
||||
}
|
||||
|
||||
trendingCmd.action(async (opts) => {
|
||||
validateChain(opts.chain);
|
||||
const extra: Record<string, string | number | string[]> = {};
|
||||
if (opts.limit != null) extra["limit"] = opts.limit;
|
||||
if (opts.orderBy) extra["order_by"] = opts.orderBy;
|
||||
if (opts.direction) extra["direction"] = opts.direction;
|
||||
if (opts.filter?.length) extra["filters"] = opts.filter;
|
||||
if (opts.platform?.length) extra["platforms"] = opts.platform;
|
||||
|
||||
// Apply server-side min_*/max_* range filters
|
||||
const optsMap = opts as Record<string, unknown>;
|
||||
for (const def of RANK_RANGE_FIELDS) {
|
||||
const val = optsMap[apiFieldToCliKey(def.api)];
|
||||
if (val != null) extra[def.api] = val as string | number;
|
||||
}
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getTrendingSwaps(opts.chain, opts.interval, extra).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
|
||||
const trenchesCmd = market
|
||||
.command("trenches")
|
||||
@@ -270,6 +290,52 @@ const TRENCHES_FILTER_FIELDS: TrenchesFilterField[] = [
|
||||
{ api: "max_tg_call_count", type: "int", desc: "Max Telegram call count" },
|
||||
];
|
||||
|
||||
// Server-side numeric range filters for `market trending` (/v1/market/rank).
|
||||
// Passed through as min_<metric>/max_<metric> query params; the service applies the
|
||||
// metrics it understands and ignores the rest. min_created/max_created are token-age
|
||||
// windows expressed as duration strings (e.g. 1m / 6h / 7d) — note these use m/h/d,
|
||||
// NOT the s/m form used by trenches; min_created is a minimum age, max_created a maximum.
|
||||
const RANK_RANGE_FIELDS: TrenchesFilterField[] = [
|
||||
{ api: "min_volume", type: "float", desc: "Min trading volume (USD)" },
|
||||
{ api: "max_volume", type: "float", desc: "Max trading volume (USD)" },
|
||||
{ api: "min_liquidity", type: "float", desc: "Min liquidity (USD)" },
|
||||
{ api: "max_liquidity", type: "float", desc: "Max liquidity (USD)" },
|
||||
{ api: "min_marketcap", type: "float", desc: "Min market cap (USD)" },
|
||||
{ api: "max_marketcap", type: "float", desc: "Max market cap (USD)" },
|
||||
{ api: "min_history_highest_marketcap", type: "float", desc: "Min historical highest market cap (USD)" },
|
||||
{ api: "max_history_highest_marketcap", type: "float", desc: "Max historical highest market cap (USD)" },
|
||||
{ api: "min_swaps", type: "int", desc: "Min swap count" },
|
||||
{ api: "max_swaps", type: "int", desc: "Max swap count" },
|
||||
{ api: "min_holder_count", type: "int", desc: "Min holder count" },
|
||||
{ api: "max_holder_count", type: "int", desc: "Max holder count" },
|
||||
{ api: "min_gas_fee", type: "float", desc: "Min gas fee" },
|
||||
{ api: "max_gas_fee", type: "float", desc: "Max gas fee" },
|
||||
{ api: "min_renowned_count", type: "int", desc: "Min KOL / renowned wallet count" },
|
||||
{ api: "max_renowned_count", type: "int", desc: "Max KOL / renowned wallet count" },
|
||||
{ api: "min_smart_degen_count", type: "int", desc: "Min smart-money holder count" },
|
||||
{ api: "max_smart_degen_count", type: "int", desc: "Max smart-money holder count" },
|
||||
{ api: "min_bot_degen_count", type: "int", desc: "Min bot-degen wallet count" },
|
||||
{ api: "max_bot_degen_count", type: "int", desc: "Max bot-degen wallet count" },
|
||||
{ api: "min_visiting_count", type: "int", desc: "Min visitor count" },
|
||||
{ api: "max_visiting_count", type: "int", desc: "Max visitor count" },
|
||||
{ api: "min_price_change_percent", type: "float", desc: "Min price change ratio over the interval" },
|
||||
{ api: "max_price_change_percent", type: "float", desc: "Max price change ratio over the interval" },
|
||||
{ api: "min_insider_rate", type: "float", desc: "Min insider trading ratio (0–1); tokens lacking this field are excluded" },
|
||||
{ api: "max_insider_rate", type: "float", desc: "Max insider trading ratio (0–1); tokens lacking this field are excluded" },
|
||||
{ api: "min_bundler_rate", type: "float", desc: "Min bundle-bot trading ratio (0–1); tokens lacking this field are excluded" },
|
||||
{ api: "max_bundler_rate", type: "float", desc: "Max bundle-bot trading ratio (0–1); tokens lacking this field are excluded" },
|
||||
{ api: "min_entrapment_ratio", type: "float", desc: "Min entrapment trading ratio (0–1); tokens lacking this field are excluded" },
|
||||
{ api: "max_entrapment_ratio", type: "float", desc: "Max entrapment trading ratio (0–1); tokens lacking this field are excluded" },
|
||||
{ api: "min_top10_holder_rate", type: "float", desc: "Min top-10 holder concentration (0–1)" },
|
||||
{ api: "max_top10_holder_rate", type: "float", desc: "Max top-10 holder concentration (0–1)" },
|
||||
{ api: "min_top70_sniper_hold_rate", type: "float", desc: "Min top-70 sniper holding ratio (0–1)" },
|
||||
{ api: "max_top70_sniper_hold_rate", type: "float", desc: "Max top-70 sniper holding ratio (0–1)" },
|
||||
{ api: "min_dev_team_hold_rate", type: "float", desc: "Min dev-team holding ratio (0–1); also excludes creator-close tokens" },
|
||||
{ api: "max_dev_team_hold_rate", type: "float", desc: "Max dev-team holding ratio (0–1)" },
|
||||
{ api: "min_created", type: "string", desc: "Min token age (minimum age), duration string e.g. 1m / 6h / 7d" },
|
||||
{ api: "max_created", type: "string", desc: "Max token age (maximum age), duration string e.g. 600m / 24h" },
|
||||
];
|
||||
|
||||
// Named filter presets using actual server-side API field names
|
||||
const TRENCHES_FILTER_PRESETS: Record<string, Record<string, number | string>> = {
|
||||
safe: {
|
||||
|
||||
Reference in New Issue
Block a user