DEX orderflow analysis, trade classification, buyer/seller pressure, and microstructure signals for Solana tokens
Market microstructure on Solana DEXes differs fundamentally from traditional finance. There are no orderbooks on AMMs — every trade is a swap against a liquidity pool. Yet trade flow analysis remains powerful: the sequence, size, and direction of swaps reveal accumulation, distribution, whale activity, and wash trading patterns.
This skill covers:
On CEXes, microstructure means orderbook depth, bid-ask spread, and queue position. On AMMs, liquidity sits in pool curves — there is no spread or queue. But the trade tape (the chronological list of swaps) contains rich signal:
These signals feed into entry/exit timing, position sizing, and token quality scoring.
On Solana DEXes, every swap has an input token and output token:
| Swap Direction | Classification | Meaning |
|---|---|---|
| SOL → Token | Buy | Trader spending SOL to acquire token |
| USDC → Token | Buy | Trader spending stables to acquire token |
| Token → SOL | Sell | Trader converting token back to SOL |
| Token → USDC | Sell | Trader converting token to stables |
| Token A → Token B | Context-dependent | Classify based on which token you're analyzing |
Birdeye Trade History (/defi/txs/token):
side field: "buy" or "sell"from (input token) and to (output token) amountsDexScreener Pair Trades:
type field indicating swap direction relative to the pairHelius Parsed Transactions:
See references/trade_classification.md for detailed classification logic and size buckets.
Aggregate trade volume into fixed time buckets to identify patterns:
# Hourly volume profile
hourly_volume = {}
for trade in trades:
hour = trade["timestamp"] // 3600 * 3600
hourly_volume.setdefault(hour, {"buy_vol": 0, "sell_vol": 0})
if trade["side"] == "buy":
hourly_volume[hour]["buy_vol"] += trade["volume_usd"]
else:
hourly_volume[hour]["sell_vol"] += trade["volume_usd"]
Key metrics from time profiles:
Classify trades into size buckets to separate whale activity from retail:
| Bucket | SOL Range | Typical Actor |
|---|---|---|
| Micro | < 0.1 SOL | Dust / test trades |
| Small | 0.1 – 1 SOL | Retail traders |
| Medium | 1 – 10 SOL | Active traders |
| Large | 10 – 50 SOL | Serious positions |
| Whale | 50+ SOL | Whales / institutions |
def compute_pressure(trades: list[dict], period_seconds: int = 3600) -> dict:
"""Compute buy/sell pressure metrics over a time period."""
buy_vol = sum(t["volume_usd"] for t in trades if t["side"] == "buy")
sell_vol = sum(t["volume_usd"] for t in trades if t["side"] == "sell")
total_vol = buy_vol + sell_vol
buy_trades = sum(1 for t in trades if t["side"] == "buy")
sell_trades = sum(1 for t in trades if t["side"] == "sell")
total_trades = buy_trades + sell_trades
return {
"buy_sell_ratio": buy_vol / sell_vol if sell_vol > 0 else float("inf"),
"buy_volume_pct": buy_vol / total_vol if total_vol > 0 else 0.5,
"net_flow_usd": buy_vol - sell_vol,
"trade_count_ratio": buy_trades / total_trades if total_trades > 0 else 0.5,
}
| Metric | Bullish | Neutral | Bearish |
|---|---|---|---|
| Buy Volume % | > 60% | 40–60% | < 40% |
| Net Flow | Positive, increasing | Near zero | Negative, increasing |
| Trade Count Ratio | > 0.55 | 0.45–0.55 | < 0.45 |
| Large Trade Ratio | High buy-side | Balanced | High sell-side |
See references/flow_signals.md for the full signal catalog and composite scoring.
Analyzing the distribution of trade sizes reveals market structure:
import statistics
def analyze_trade_sizes(trades: list[dict]) -> dict:
"""Analyze trade size distribution."""
sizes = [t["volume_usd"] for t in trades]
if not sizes:
return {}
return {
"mean": statistics.mean(sizes),
"median": statistics.median(sizes),
"stdev": statistics.stdev(sizes) if len(sizes) > 1 else 0,
"skew_indicator": statistics.mean(sizes) / statistics.median(sizes),
"max_trade": max(sizes),
"whale_pct": sum(s for s in sizes if s > 5000) / sum(sizes),
}
Interpreting skew: A skew_indicator (mean/median) well above 1.0 indicates a
fat-tailed distribution — a few large trades dominate. This is normal for tokens with
whale interest but can also signal manipulation.
Compare current period volume to the previous period:
acceleration = current_volume / previous_volume if previous_volume > 0 else 0
Track how the buy ratio changes over time:
current_buy_ratio = current_buy_vol / current_total_vol
previous_buy_ratio = prev_buy_vol / prev_total_vol
buy_momentum = current_buy_ratio - previous_buy_ratio
Positive buy_momentum with increasing volume is a strong accumulation signal.
Token velocity measures how frequently tokens change hands:
velocity = daily_volume / circulating_supply
| Velocity | Interpretation |
|---|---|
| < 0.01 | Low activity, illiquid, or strong holders |
| 0.01–0.05 | Normal trading activity |
| 0.05–0.20 | Active trading, possible speculation |
| > 0.20 | Very high turnover, potential wash trading |
High velocity combined with low unique trader count is a wash trading red flag.
Wash trading inflates volume to make a token appear more active than it truly is. Key detection signals:
unique_wallets / trade_count < 0.3daily_volume / tvl > 10 (volume vastly exceeds liquidity)See references/wash_trading.md for detailed detection methods and scoring.
Primary source for trade history on Solana tokens:
GET /defi/txs/token — recent trades for a tokenGET /defi/ohlcv — candle data with volumeGET /defi/price/volume — aggregated volume dataRequires API key. See the birdeye-api skill for endpoint details.
Free, no-auth alternative for pair-level data:
GET /latest/dex/tokens/{address} — token pairs with volumeGET /latest/dex/pairs/solana/{pairAddress} — pair detailsFor wallet-level trade analysis and parsed transactions:
helius-api skill for transaction parsing.Combine multiple flow signals into a single score (range: -100 to +100):
def compute_momentum_score(
buy_ratio: float,
volume_accel: float,
whale_buy_pct: float,
unique_trader_trend: float,
) -> float:
"""Compute composite momentum score from flow signals.
Args:
buy_ratio: Buy volume / total volume (0 to 1).
volume_accel: Current vol / previous vol.
whale_buy_pct: Whale buy volume / total whale volume (0 to 1).
unique_trader_trend: Change in unique traders vs previous period.
Returns:
Score from -100 (strong sell pressure) to +100 (strong buy pressure).
"""
# Buy ratio component: 0.5 = neutral, maps to [-40, +40]
buy_component = (buy_ratio - 0.5) * 80
# Volume acceleration: >1 = growing, maps to [-20, +20]
vol_component = min(max((volume_accel - 1.0) * 20, -20), 20)
# Whale direction: 0.5 = neutral, maps to [-25, +25]
whale_component = (whale_buy_pct - 0.5) * 50
# Unique trader growth: positive = healthy, maps to [-15, +15]
trader_component = min(max(unique_trader_trend * 15, -15), 15)
score = buy_component + vol_component + whale_component + trader_component
return max(-100, min(100, score))
| Score Range | Interpretation |
|---|---|
| +60 to +100 | Strong accumulation — heavy buy pressure |
| +20 to +60 | Moderate buying — cautious accumulation |
| -20 to +20 | Neutral / balanced flow |
| -60 to -20 | Moderate selling — distribution underway |
| -100 to -60 | Strong distribution — heavy sell pressure |
| Skill | How It Connects |
|---|---|
birdeye-api | Primary data source for trade history and volume |
helius-api | Wallet-attributed trade data from parsed transactions |
liquidity-analysis | Volume/TVL ratios, liquidity context for flow signals |
whale-tracking | Identify whale wallets for large trade attribution |
token-holder-analysis | Supply distribution context for velocity metrics |
position-sizing | Use flow signals to adjust entry sizing |
regime-detection | Combine flow momentum with regime classification |
references/trade_classification.md — Buy/sell classification logic, size buckets, aggregationreferences/flow_signals.md — Complete signal catalog with formulas and interpretationreferences/wash_trading.md — Detection methods, metrics, and risk scoringscripts/trade_flow_analysis.py — Fetch trades, classify, compute flow signals and momentumscripts/volume_profile.py — Hourly volume profiles, trend detection, anomaly identification