How to Build a Moonshot Memecoin Tracker with CoinMarketCap API
CoinMarketCap API DIY

How to Build a Moonshot Memecoin Tracker with CoinMarketCap API

Learn how to build a Moonshot memecoin tracker using CoinMarketCap DEX API for new token discovery on Solana.

How to Build a Moonshot Memecoin Tracker with CoinMarketCap API

Table of Contents

Moonshot is a memecoin launchpad built by DEX Screener, one of the most used token analytics platforms in crypto.

Tokens launch on Moonshot's bonding curve at 0.02 SOL. As buyers accumulate, the price climbs along the curve. When the token reaches the 500 SOL threshold (~$73,000 market cap), it graduates liquidity migrates to Raydium, LP tokens are burned, and the token enters public DEX trading.

The graduation moment is where most of the early opportunity lives. Traders who identify strong tokens in the first minutes after graduation — before momentum is visible to most — capture the asymmetric entry.

CoinMarketCap API solves the signal problem. The moment a Moonshot token graduates and its Raydium pool is seeded, the CMC DEX API begins indexing it. You can then filter by pool age, liquidity depth, security flags, and transaction flow — before the crowd notices.

In this guide, you will build a Moonshot Memecoin Tracker with CoinMarketCap API, where:
  • CoinMarketCap DEX API powers the signal engine
  • Solana RPC and Moonshot's official API handle bonding curve state and graduation events

Why Use CoinMarketCap API for a Moonshot Memecoin Tracker?

Moonshot graduates tokens. CoinMarketCap tells you which ones are worth tracking.

Instead of monitoring every graduation blindly, you can use CoinMarketCap to:

  • discover newly graduated tokens the moment they appear on Raydium
  • filter pools by age using pubAt to isolate recent launches
  • validate liquidity depth before entering
  • run security checks for honeypots, transfer restrictions, and hidden taxes
  • detect whale transaction flow in the first minutes of trading
  • track sub-minute candle momentum on new pools
  • apply macro regime filters to avoid launching into adverse conditions

System Architecture

CoinMarketCap DEX API (Signal Layer)
├─ New Token Discovery (graduated Moonshot pools on Raydium)

├─ Pool Validation (liquidity, age via pubAt)

├─ Security Checks (honeypot, taxes — may be empty for new tokens)

├─ Transaction Flow (whale detection)

├─ Sub-minute Candles (first-minutes momentum)

└─ Macro Regime (fear/greed, altcoin season)

Memecoin Signal Engine

Solana RPC / Moonshot API (Validation Layer)

Bonding Curve State + Graduation Events + On-Chain Safety

Architecture Clarification

The CoinMarketCap API acts strictly as an off-chain Signal Layer for memecoin discovery, liquidity validation, security screening, and market regime filtering. It is not a bonding curve monitor, graduation event oracle, or real-time launchpad feed.

Real bonding curve progress, graduation thresholds, LP burn status, and on-chain token safety must be validated directly on-chain via Solana RPC or Moonshot's official API. CMC data has cache delays that make it unsuitable as a sole trigger for latency-sensitive memecoin trading. Post-graduation indexing may take minutes before a new token appears in CMC endpoints.

Plan Note

The primary discovery endpoints (/v1/dex/new/list, /v1/dex/meme/list, /v1/dex/tokens/trending/list) require a paid CMC plan. This guide covers both paid endpoints and a Basic-plan fallback using /v4/dex/spot-pairs/latest.

Project Setup

Python Dependencies

import os

import time

import datetime

import requests

import pandas as pd

import numpy as np

Environment Variables

CMC_API_KEY  = os.getenv("CMC_API_KEY")

CMC_BASE_URL = "https://pro-api.coinmarketcap.com"

Headers

HEADERS = {
"Accept":            "application/json",
"Content-Type":      "application/json",
"X-CMC_PRO_API_KEY": CMC_API_KEY,
}

Config

# Solana platform ID — resolve dynamically, do not hardcode
SOLANA_PLATFORM_ID = None   # set by get_solana_platform_id()

# Pool age filter — only track pools newer than this
MAX_POOL_AGE_HOURS = 6

# Minimum liquidity to consider a graduation real
MIN_LIQUIDITY_USD = 10_000

Step 1: Resolve Solana Platform ID

def get_solana_platform_id():

url = f"{CMC_BASE_URL}/v1/dex/platform/list"

r = requests.get(url, headers=HEADERS)

r.raise_for_status()

for p in r.json()["data"]:

if p["n"].lower() == "solana":   # field is "n", not "name"

return str(p["id"])

Use the returned ID as platformIds in all POST discovery calls.

Step 2: Discover Newly Graduated Tokens

Paid Plan

def fetch_new_solana_tokens(platform_id):

url = f"{CMC_BASE_URL}/v1/dex/new/list"

body = {"platformIds": platform_id, "limit": 50}

r = requests.post(url, headers=HEADERS, json=body)

r.raise_for_status()

return r.json()["data"]

def fetch_meme_tokens(platform_id):

url = f"{CMC_BASE_URL}/v1/dex/meme/list"

body = {"platformIds": platform_id, "limit": 50}

r = requests.post(url, headers=HEADERS, json=body)

r.raise_for_status()

return r.json()["data"]

Tokens graduated from Moonshot are indexed here almost immediately after their Raydium pool is seeded.

Basic Plan Fallback

def fetch_new_pairs_fallback():

url = f"{CMC_BASE_URL}/v4/dex/spot-pairs/latest"

params = {

"network_slug": "solana",
"dex_slug":     "raydium",
"sort":         "volume_24h",
"sort_dir":     "desc",
}

r = requests.get(url, headers=HEADERS, params=params)

r.raise_for_status()

return r.json()["data"]

This surfaces active Raydium pairs sorted by volume. It does not isolate brand-new launches, but high-volume new tokens rise to the top quickly.

Step 3: Validate Pool Liquidity and Age

Not every graduated token is worth tracking. Filter by liquidity depth and pool age.

Endpoint

GET /v1/dex/token/pools
def fetch_token_pools(token_address):

url = f"{CMC_BASE_URL}/v1/dex/token/pools"

params = {
"address":  token_address,
"platform": "solana"
}

r = requests.get(url, headers=HEADERS, params=params)

r.raise_for_status()

return r.json()["data"]

Key fields:

  • exn — DEX name
  • liqUsd — liquidity in USD, returned as a string — always cast to float
  • v24 — 24h volume
  • addr — pool address
  • pubAt — pool publish timestamp (UNIX seconds) — use to filter by pool age

Note: lr and br are in the schema but frequently absent in live data. Do not rely on them.

def is_pool_valid(pool):

liq = float(pool.get("liqUsd") or 0)

if liq < MIN_LIQUIDITY_USD:

return False

pub_at = pool.get("pubAt")

if pub_at:

pub_at_sec = int(pub_at) / 1000        # pubAt is milliseconds — convert to seconds

age_hours  = (time.time() - pub_at_sec) / 3600

if age_hours > MAX_POOL_AGE_HOURS:

return False

return True

def get_best_pool(pools):

valid = [p for p in pools if is_pool_valid(p)]

return max(valid, key=lambda p: float(p.get("liqUsd") or 0)) if valid else None

Step 4: Run Security and Rug Checks

Endpoint

GET /v1/dex/security/detail
def check_token_security(token_address):

url = f"{CMC_BASE_URL}/v1/dex/security/detail"

params = {
"platformName": "solana",
"address":      token_address
}

r = requests.get(url, headers=HEADERS, params=params)

r.raise_for_status()

results = r.json()["data"]       # data is a list

return results[0] if results else {}

Security data comes from Go+. For tokens with only minutes or hours on Raydium, the audit may not yet be processed - securityItems will be empty or absent. Always parse defensively:

def parse_security_flags(sec):

# Boolean flags inside securityItems[] — match by riskCode

items    = sec.get("securityItems") or []

risk_map = {
item["riskCode"]: item.get("isHit", False)

for item in items

if item.get("riskCode")

}

honeypot          = risk_map.get("honeypot", False)
transfer_pausable = risk_map.get("transfer_pausable", False)
transfer_pausable = risk_map.get("transfer_pausable", False)

# Taxes at root level — not inside securityItems

buy_tax  = 0

sell_tax = 0

try:

buy_tax  = float(sec.get("buyTax",  0) or 0)

sell_tax = float(sec.get("sellTax", 0) or 0)

except (TypeError, ValueError):

pass

return {

"honeypot":          honeypot,
"transfer_pausable": transfer_pausable,
"buy_tax":           buy_tax,
"sell_tax":          sell_tax,
"combined_tax":      buy_tax + sell_tax,
"scan_available":    bool(items),   # False = token too new for Go+ scan

}

If scan_available is False, treat the token as unverified — not necessarily malicious, but unscreened. Adjust your risk tolerance accordingly.

Step 5: Detect Whale Transaction Flow

Endpoint

GET /v1/dex/tokens/transactions
def fetch_transactions(token_address, min_volume=10_000):

url = f"{CMC_BASE_URL}/v1/dex/tokens/transactions"

params = {
"address":   token_address,
"platform":  "solana",    # "solana" only — "sol" returns 400
"minVolume": min_volume
}

r = requests.get(url, headers=HEADERS, params=params)

r.raise_for_status()

return r.json()["data"]

Returns raw swap records. Key fields: tx (hash), v (volume USD), t0a (base asset), t1a (quote asset). Use minVolume to isolate whale-sized entries in the first minutes of trading.

Step 6: Track Sub-Minute Momentum

Endpoint

GET /v1/k-line/candles
def fetch_candles(token_address, interval="1min"):

url = f"{CMC_BASE_URL}/v1/k-line/candles"

params = {
"platform": "solana",
"address":  token_address,
"interval": interval    # 1s, 5s, 30s, 1min, 3min
}

r = requests.get(url, headers=HEADERS, params=params)

r.raise_for_status()

return r.json()["data"]

Each candle is a positional array of 7 elements — not a dict:

Index

Field

[0]

open

[1]

high

[2]

low

[3]

close

[4]

volume

[5]

timestamp, UNIX milliseconds — divide by 1000 for seconds

[6]

traders, unique trader count
def parse_candle(c):

return {

"open":      c[0],
"high":      c[1],
"low":       c[2],
"close":     c[3],
"volume":    c[4],
"timestamp": c[5],
"traders":   c[6],
"datetime":  datetime.datetime.fromtimestamp(c[5] / 1000),  # ms → seconds

}

A rising traders count alongside a volume spike on the first 1-minute candles is the strongest momentum signal for a newly graduated token.

Step 7: Build the Memecoin Signal Score

def compute_memecoin_score(pool, security_flags, candles):

score = 0

# Liquidity

liq = float(pool.get("liqUsd") or 0)

if liq > 100_000:  score += 30

elif liq > 30_000: score += 15

# Pool age — younger pools score higher

pub_at = pool.get("pubAt")

if pub_at:

pub_at_sec = int(pub_at) / 1000        # pubAt is milliseconds — convert to seconds

age_hours  = (time.time() - pub_at_sec) / 3600

if age_hours < 1:    score += 25

elif age_hours < 3:  score += 15

elif age_hours < 6:  score += 5

# Security

if security_flags.get("honeypot") or security_flags.get("transfer_pausable"):

return -100   # hard reject

combined_tax = security_flags.get("combined_tax", 0)

if combined_tax == 0:    score += 20

elif combined_tax < 5:   score += 10

elif combined_tax > 10:  score -= 25

if not security_flags.get("scan_available"):

score -= 10   # unscreened penalty, not a disqualifier

# Momentum — candles are positional arrays, traders at index [6]

if candles:

latest  = candles[-1]

traders = latest[6] if len(latest) > 6 else 0

traders = traders or 0   # c[6] can be None in live data

if traders > 50:   score += 25

elif traders > 20: score += 15

elif traders > 10: score += 8

return score

def should_track(score, threshold=40):

return score >= threshold

Step 8: Apply Macro Regime Filters

Memecoin momentum is highly correlated with macro risk appetite.

Endpoints

GET /v3/fear-and-greed/latest

GET /v1/altcoin-season-index/latest
def fetch_macro_regime():

fg_url = f"{CMC_BASE_URL}/v3/fear-and-greed/latest"

as_url = f"{CMC_BASE_URL}/v1/altcoin-season-index/latest"

fg     = requests.get(fg_url, headers=HEADERS).json()["data"]

as_idx = requests.get(as_url, headers=HEADERS).json()["data"]

return {

"fear_greed_value":          fg.get("value"),
"fear_greed_classification": fg.get("value_classification"),
"altcoin_index":             as_idx.get("altcoin_index"),
}

def is_regime_favorable(regime):

fg   = regime.get("fear_greed_value") or 0

as_i = regime.get("altcoin_index")    or 0

# Memecoins need strong risk-on conditions

return fg > 55 and as_i >= 60

Step 9: Minimal End-to-End Flow

def run_moonshot_tracker(platform_id):

# 1. Macro regime — poll every 15 min

regime = fetch_macro_regime()

if not is_regime_favorable(regime):

return {"skipped": "unfavorable regime", "regime": regime}

# 2. Discover new tokens

try:

tokens = fetch_new_solana_tokens(platform_id)

except Exception:

tokens = fetch_new_pairs_fallback()   # Basic plan fallback

results = []

for token in tokens:

addr = token.get("addr") or token.get("base_asset_contract_address")

if not addr:

continue

# 3. Pool validation

try:

pools = fetch_token_pools(addr)

pool  = get_best_pool(pools)

except Exception:

continue

if not pool:

continue

# 4. Security check

try:

sec_raw   = check_token_security(addr)

sec_flags = parse_security_flags(sec_raw)

except Exception:

sec_flags = {

"honeypot": False, "transfer_pausable": False,

"combined_tax": 0, "scan_available": False,

}

if sec_flags["honeypot"] or sec_flags["transfer_pausable"]:

continue

# 5. Momentum

try:

candles = fetch_candles(addr, interval="1min")

except Exception:

candles = []

# 6. Score

score = compute_memecoin_score(pool, sec_flags, candles)

if should_track(score):

results.append({

"address":       addr,
"symbol":        token.get("symbol") or token.get("base_asset_symbol"),
"score":         score,
"pool":          pool.get("addr"),
"liqUsd":        pool.get("liqUsd"),
"pubAt":         pool.get("pubAt"),
"combined_tax":  sec_flags["combined_tax"],
"scan_available": sec_flags["scan_available"],
})

return {

"signals": sorted(results, key=lambda x: -x["score"]),
"regime":  regime,
}

Rate Limits and Polling

CoinMarketCap API is REST-only. There is no WebSocket streaming.

Cache Intervals

Endpoint Group

Cache Interval

Discovery, /v1/dex/new/list, /v1/dex/meme/list
60 seconds
Pool data, /v1/dex/token/pools
60 seconds
DEX pairs, /v4/dex/spot-pairs/latest
60 seconds
Candles, /v1/k-line/candles
60 seconds
Fear & Greed, Altcoin Season
15 minutes

Best Practices

  • poll every 60 seconds — faster polling returns cached data and wastes credits
  • cache responses locally between polls
  • use exponential backoff for HTTP 429 errors, rate reset at 60 seconds
def request_with_backoff(fn, retries=3, base_delay=2):

for attempt in range(retries):

try:

return fn()

except requests.exceptions.HTTPError as e:

if e.response.status_code == 429:

time.sleep(base_delay ** attempt)

else:

raise

raise Exception("Max retries exceeded")

Common Mistakes

Using p["name"] on platform list

The platform name field is "n", not "name". Using p["name"] raises a KeyError.

Not casting liqUsd to float

/v1/dex/token/pools returns liqUsd as a string. Comparing directly with >= raises a TypeError. Always cast: float(pool.get("liqUsd") or 0).

Expecting security scans on brand-new tokens

Go+ takes time to index new contracts. For tokens with minutes or hours on Raydium, securityItems will be empty. Use scan_available to track whether a scan exists — and adjust risk tolerance, not disqualify automatically.

Using "sol" as the platform value

/v1/dex/tokens/transactions only accepts "solana". The abbreviated form returns 400.

Calling .get() on candle arrays

Candles are positional arrays. Use candle[6] for traders — not candle.get("traders").

Treating CMC as a bonding curve monitor

CMC does not track bonding curve progress or graduation events. The DEX API only indexes a token after it graduates and its pool is seeded on Raydium. For real-time graduation detection, use Solana RPC directly.

Using Core API for memecoin discovery

Newly graduated tokens will not appear in /v3/cryptocurrency/quotes/latest or /v3/cryptocurrency/listings/latest for hours or days — the Core API requires manual review or sustained volume thresholds. Always use the DEX API family for memecoin discovery.

Passing tag="memes" as a query parameter

Returns a 400 error. The tag parameter only accepts "all", "defi", or "filesharing". Filter meme tags locally by inspecting the tags array in the response.

Final Thoughts

Moonshot tokens live and die in minutes. The edge is not speed — it is signal quality in the first window after graduation.

CoinMarketCap DEX API gives you a structured layer to filter the noise: liquidity depth, pool age, security status, whale flow, and momentum — all before you interact with any token on-chain.

The key separation:

  • CoinMarketCap identifies which graduated tokens are worth tracking
  • Solana RPC and Moonshot's API monitor bonding curve state and graduation events

Better filters lead to better memecoin decisions.

Next Steps

  • refine MAX_POOL_AGE_HOURS and MIN_LIQUIDITY_USD thresholds based on live results
  • add auto-exit signals using trailing candle momentum
  • integrate Moonshot's official API for real-time graduation event detection
  • track score-to-outcome correlation to improve signal weights
  • store graduated token snapshots locally to build historical reference data
0 people liked this article