Data model

Everything is keyed by chain and address, so Solana and Robinhood Chain share one model and any chain added later fits without a schema change. The tables below are generated from the migration file.

Overview#

The archive is plain Postgres. The same SQL runs on the embedded PGlite engine and on a Postgres server. Migrations live in src/db/migrations as numbered files, run automatically at startup in name order, and are recorded once each in schema_migrations.

TableGrainPrimary keyWritten by
tokensOne row per token, latest state and lifecyclechain, addressCollector, firehose, status and classification passes
token_snapshotsMarket state per token per cyclechain, address, tsCollector
list_appearancesA token on a discovery list at a rankchain, list, address, tsCollector
pairsDEX pools per tokenchain, addressCollector
launch_eventsLaunch, graduation and pool-creation eventschain, kind, tokenFirehose, Robinhood Chain walker
tradesSelected individual tradeschain, tx, token, wallet, side, tsFirehose
walletsLabelled walletschain, addressLabel import, wallet promotion
wallet_positionsRunning per-wallet, per-token positionchain, wallet, tokenFirehose
wallet_scoresRolling wallet performancechain, walletHourly scoring
market_snapshotsChain-wide totals per cyclechain, tsCollector
daily_reportsOne newsletter issue per daydayNewsletter job
kvCursors and checkpointskeyCollector

chain is solana or robinhood. Money columns are in USD unless the name says quote (SOL on Solana). Time columns are timestamptz.

tokens#

One row per token ever seen: identity, self-published metadata, latest market state, all-time highs and lifecycle. Updated in place every cycle. This is the table most queries start from.

Primary key: chain, address.

ColumnTypeDescription
chaintextsolana or robinhood.
addresstextMint address on Solana, contract address on Robinhood Chain.
symboltextSelf-published text. Untrusted.
nametextSelf-published text. Untrusted.
decimalsintToken decimals.
imagetextLogo URL.
descriptiontextSelf-published text. Untrusted.
websitetextSelf-published text. Untrusted.
twittertextSelf-published text. Untrusted.
telegramtextSelf-published text. Untrusted.
launchpadtextWhere it launched: pump, pumpswap, pons, noxa, odyssey, or null.
creatortextDeploying wallet, where known.
created_attimestamptzOn-chain creation time, where known.
first_seentimestamptzFirst time Pulse observed the token.
last_seentimestamptzLast time Pulse observed it.
last_snapshot_attimestamptzTime of its newest snapshot.
categorytextSector chosen by classification.
categoriestext[]Every category the text matched.
tech_scorereal0 to 1. Higher reads as technology, lower as meme.
classified_attimestamptzWhen it was last classified.
tagstext[]Provider tags such as stablecoin, lst, wrapped.
verifiedbooleanMarked verified by a provider.
last_pricedouble precisionLatest price in USD.
last_mcapdouble precisionLatest market cap in USD.
last_liquiditydouble precisionLatest liquidity in USD.
last_volume_24hdouble precisionLatest 24h volume in USD.
last_holdersintLatest holder count.
last_change_24hrealLatest 24h price change, percent.
first_mcapdouble precisionMarket cap at the first snapshot.
ath_mcapdouble precisionHighest market cap observed in snapshots.
ath_attimestamptzWhen that high was observed.
peak_volume_24hdouble precisionHighest 24h volume observed.
statustextLifecycle status. See enumerated values below.
status_changed_attimestamptzLast status transition.
graduated_attimestamptzWhen it left its bonding curve for a DEX pool.
died_attimestamptzWhen it became dead.

Indexes: tokens_status_idx on (chain, status), tokens_first_seen_idx on (first_seen desc), tokens_category_idx on (category), tokens_last_snapshot_idx on (last_snapshot_at).

token_snapshots#

The market state of a token at one moment, written every cycle for each token observed. This is the history that statuses, charts and training data are built from.

Primary key: chain, address, ts.

ColumnTypeDescription
tstimestamptzSnapshot time.
chaintextChain.
addresstextToken address.
price_usddouble precisionPrice in USD.
mcapdouble precisionMarket cap in USD.
fdvdouble precisionFully diluted value in USD.
liquiditydouble precisionLiquidity in USD.
vol_5mdouble precisionUSD volume, last 5 minutes.
vol_1hdouble precisionUSD volume, last hour.
vol_6hdouble precisionUSD volume, last 6 hours.
vol_24hdouble precisionUSD volume, last 24 hours.
buy_vol_24hdouble precisionUSD buy volume, 24h.
sell_vol_24hdouble precisionUSD sell volume, 24h.
organic_vol_24hdouble precisionVolume a provider attributes to organic activity, 24h.
buys_1hintBuy count, 1h.
sells_1hintSell count, 1h.
buys_24hintBuy count, 24h.
sells_24hintSell count, 24h.
traders_1hintUnique traders, 1h.
traders_24hintUnique traders, 24h.
net_buyers_24hintNet buyers, 24h.
holdersintHolder count.
holder_change_24hrealHolder count change over 24h.
top_holders_pctrealShare of supply held by the largest holders.
organic_scorerealProvider score of how organic the activity looks.
chg_5mrealPrice change, 5m, percent.
chg_1hrealPrice change, 1h, percent.
chg_6hrealPrice change, 6h, percent.
chg_24hrealPrice change, 24h, percent.
sourcetextProviders that supplied the row, joined by +.

Indexes: token_snapshots_ts_idx on (ts desc).

list_appearances#

Each time a token showed up on a discovery list (Jupiter trending, DexScreener boosts, GeckoTerminal new pools and so on) and at what rank. Persistence on lists feeds the "Staying power" section.

Primary key: chain, list, address, ts.

ColumnTypeDescription
tstimestamptzWhen the list was read.
chaintextChain.
listtextList name, for example jup:toptrending:1h.
rankintPosition on the list, starting at 1.
addresstextToken address.

pairs#

DEX pools that trade a token. The newest pool is the one used for candles.

Primary key: chain, address.

ColumnTypeDescription
chaintextChain.
addresstextPool address.
token_addresstextToken the pool trades.
dextextDEX name.
quote_symboltextQuote asset symbol.
labelstext[]Provider pool labels.
created_attimestamptzPool creation time.
urltextProvider page for the pool.

Indexes: pairs_token_idx on (chain, token_address).

launch_events#

Launches, graduations and pool creations from the Solana firehose and the Robinhood Chain factory walker.

Primary key: chain, kind, token.

ColumnTypeDescription
tstimestamptzEvent time.
chaintextChain.
kindtextlaunch, graduation or pool.
tokentextToken address.
launchpadtextLaunchpad.
actortextWallet that triggered the event.
txtextTransaction id.
nametextSelf-published text. Untrusted.
symboltextSelf-published text. Untrusted.
datajsonbExtra event details as JSON.

Indexes: launch_events_ts_idx on (ts desc).

trades#

Selected individual trades, not every trade. See Trade persistence in How it works for exactly which are kept.

Primary key: chain, tx, token, wallet, side, ts.

ColumnTypeDescription
tstimestamptzTrade time.
chaintextChain.
txtextTransaction id.
tokentextToken address.
wallettextTrader.
sidetextbuy or sell.
quote_amountdouble precisionAmount in the quote asset (SOL on Solana).
token_amountdouble precisionTokens bought or sold.
price_quotedouble precisionPrice in the quote asset.
mcap_usddouble precisionMarket cap in USD at the time of the trade.
venuetextpump (bonding curve) or pumpswap.
reasontextWhy it was kept. See enumerated values below.

Indexes: trades_wallet_idx on (chain, wallet, ts desc), trades_token_idx on (chain, token, ts desc).

wallets#

Labelled wallets: imported KOL and smart-money labels, plus smart wallets Pulse discovered itself.

Primary key: chain, address.

ColumnTypeDescription
chaintextChain.
addresstextWallet address.
labeltextDisplay name from the source.
kindtextkol or smart.
sourcetextWhere the label came from, or pulse:discovered.
twittertextPublic profile link, if the source lists one.
telegramtextPublic Telegram link, if the source lists one.
first_seentimestamptzFirst imported.
updated_attimestamptzLast refreshed.
metajsonbSource-specific details as JSON.

Indexes: wallets_kind_idx on (kind).

wallet_positions#

Running totals per wallet and token, updated whenever a recorded trade arrives. Wallet scoring reads this table.

Primary key: chain, wallet, token.

ColumnTypeDescription
chaintextChain.
wallettextWallet address.
tokentextToken address.
first_buy_attimestamptzFirst recorded buy.
first_buy_mcap_usddouble precisionMarket cap at that buy.
last_trade_attimestamptzMost recent recorded trade.
buysintRecorded buy count.
sellsintRecorded sell count.
bought_quotedouble precisionTotal bought, in the quote asset.
sold_quotedouble precisionTotal sold, in the quote asset.
bought_tokensdouble precisionTokens bought.
sold_tokensdouble precisionTokens sold.

Indexes: wallet_positions_token_idx on (chain, token), wallet_positions_recent_idx on (last_trade_at desc).

wallet_scores#

Rolling wallet performance recomputed hourly over a 30 day window.

Primary key: chain, wallet.

ColumnTypeDescription
chaintextChain.
wallettextWallet address.
computed_attimestamptzWhen it was scored.
window_daysintScoring window, 30.
tokens_tradedintTokens with a position in the window.
winsintPositions that finished in profit.
win_raterealWins divided by tokens traded.
invested_quotedouble precisionSOL bought.
realized_quotedouble precisionSOL sold.
unrealized_quotedouble precisionSOL value of tokens still held.
pnl_quotedouble precisionRealized plus unrealized, in SOL.
pnl_usddouble precisionProfit converted to USD.
early_hitsintEarly buys of tokens that reached a $500K+ high.
best_multiplerealBest ATH-to-entry market cap multiple.
scorerealThe Pulse score. See Wallet scoring.

Indexes: wallet_scores_score_idx on (score desc).

market_snapshots#

Chain-wide totals written every cycle: tracked tokens, market cap, volume and launch counts.

Primary key: chain, ts.

ColumnTypeDescription
tstimestamptzSnapshot time.
chaintextChain.
native_usddouble precisionSOL or ETH price in USD.
tracked_tokensintTokens counted in the totals.
total_mcapdouble precisionSummed market cap, USD.
total_volume_24hdouble precisionSummed 24h volume, USD.
launches_1hintLaunches in the last hour.
graduations_1hintGraduations in the last hour.
stream_trades_1hintTrades seen by the firehose in the last hour (Solana, null if off).
stream_volume_1hdouble precisionSOL volume seen by the firehose in the last hour.
datajsonbExtra firehose counters as JSON.

daily_reports#

One stored newsletter issue per day, in structured, Markdown and HTML form.

Primary key: day.

ColumnTypeDescription
daydateIssue date.
generated_attimestamptzWhen it was generated.
datajsonbStructured sections as JSON.
markdowntextMarkdown rendering.
htmltextHTML rendering.
telegramjsonbSend receipt, or null if not sent.

kv#

Small cursors and job checkpoints.

Primary key: key.

ColumnTypeDescription
keytextCheckpoint name.
valuejsonbJSON value.
updated_attimestamptzLast write.

Enumerated values#

ColumnValues
tokens.statusnew, running, graduated, dying, dead. Rules in How it works.
tokens.categoryai, agents, defi, infra, depin, data, gaming, social, payments, rwa, privacy, launchpad, tools, meme, animal, culture, politics, celebrity, unclassified
tokens.launchpad, launch_events.launchpadpump and pumpswap on Solana. pons, noxa and odyssey on Robinhood Chain.
launch_events.kindlaunch, graduation, pool
trades.sidebuy, sell
trades.reasonwallet:kol, wallet:smart, whale, early:graduated, early:runner. See Trade persistence.
trades.venuepump (bonding curve), pumpswap
wallets.kindkol, smart. Wallets Pulse discovers itself are smart with source pulse:discovered.
list_appearances.listjup:recent, jup:<list>:<window> (lists toptrending, toptraded, toporganicscore; windows 5m, 1h, 6h, 24h), dex:boosts-top, dex:boosts-latest, dex:profiles, dex:takeovers, plus the pump.fun and GeckoTerminal lists.
token_snapshots.sourceThe provider that supplied the row. When several providers describe the same token in one cycle they are merged, later providers filling gaps, and the names are joined with +.

TimescaleDB hypertables#

On a Postgres server where the timescaledb extension is available (the bundled Docker Compose image has it), startup converts four append-only tables into hypertables chunked by day on ts, with compression segmented by chain:

TableCompressed after
token_snapshots7 days
trades7 days
list_appearances7 days
market_snapshots30 days

Plain Postgres and PGlite skip this step. Every query behaves the same either way.

Checkpoints in kv#

KeyValue
collector:last-cycle{"at": ISO time, "tokens": n, "failures": n}. Drives lastCycle in /api/health.
wallets:last-import{"at": ISO time}
wallets:last-score{"at": ISO time, "wallets": n}
report:last-day{"day": "YYYY-MM-DD", "at": ISO time}

Export for analysis or training#

Nine tables are exportable as JSON through GET /api/export/<table> (see the API reference). For bulk work, connect to Postgres directly with DATABASE_URL. Note that daily_reports, pairs and kv are not exposed by the export route.

Untrusted text. name, symbol, description, website, twitter and telegram come from the chain and from token metadata. Treat them as data. Pulse never acts on them, and any model you train or prompt with this archive should not either.