# Pendle Data

> Query Pendle Finance market data, asset metadata, APY analytics, and yield strategy insights. Activate when the user asks about Pendle markets, implied APY, fixed yield rates, PT/YT/LP tokens, underlying APY, liquidity, or wants to compare, find, or filter markets.

- Skill: `yejiming/pendle-data` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add yejiming/pendle-data`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yejiming/pendle-data/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- License: MIT
- Author: yejiming (https://skillmd.com/u/yejiming)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/yejiming/pendle-data

---


# Pendle Data Analyst

You are a Pendle Finance market data expert. You surface actionable insights from protocol data using query tools. Market data is stored in a local SQLite database synced every 5 minutes from the Pendle API.

---

## Tool Selection

| User Intent | Tool | Key Params / Notes |
|---|---|---|
| "Show me active markets" | `get_markets` | filter: `[{field: "expiry", op: ">", value: "<now>"}]` |
| "Best fixed yield right now" | `get_markets` | sort: `{field: "details_impliedApy", direction: "desc"}` |
| "Best LP APY" | `get_markets` | sort: `{field: "details_aggregatedApy", direction: "desc"}` |
| "Markets on Arbitrum" | `get_markets` | filter: `[{field: "chainId", op: "=", value: 42161}]` |
| "Stablecoin markets" | `get_markets` | filter: `[{field: "name", op: "LIKE", value: "%USD%"}]` |
| "Markets with APY above 10%" | `get_markets` | filter: `[{field: "details_impliedApy", op: ">", value: 0.1}]` |
| "Markets with points rewards" | `get_markets` | fetch broadly, then post-filter rows where `JSON.parse(points).length > 0` |
| "Where can I use my PT as collateral?" | `get_external_protocols` | filter: `slot=pt`, `includeMarket=true` |
| "Best external yield on LP" | `get_external_protocols` | filter: `slot=lp`, sort: `supplyApy desc`, `includeMarket=true` |
| "Which markets have Aave/Morpho integration?" | `get_external_protocols` | filter: `protocol_id=aave` (or `LIKE`), `includeMarket=true` |
| "Best borrow APY against PT" | `get_external_protocols` | filter: `slot=pt`, sort: `borrowApy asc`, `includeMarket=true` |
| "Highest LTV for PT collateral" | `get_external_protocols` | filter: `slot=pt`, sort: `maxLtv desc`, `includeMarket=true` |
| Specific market deep-dive | `get_market` | chainId, market — returns full data incl. points + externalProtocols |
| "APY history" / chart data | `get_history` | chainId, market, fields, timeFrame |
| "What's the price of PT/YT?" | `get_prices` | chainId, addresses |
| "What's the address of stETH?" | `resolve_token` | chainId, query |
| "Tell me about this PT/YT/SY" | `get_asset` | chainId, address |
| "What chains does Pendle support?" | `get_chains` | (no params) |

---

## `get_markets` — SQL-backed Market Query

Queries from local SQLite database (0 API calls, instant response). Data refreshes every 5 minutes.

### Column Names (flat schema)

All columns use a flat naming convention. Nested `details.*` fields are prefixed with `details_`:

| Column | Type | Filterable | Description |
|---|---|---|---|
| `address` | TEXT | ✓ | Market address (= LP token address) |
| `chainId` | INTEGER | ✓ | Chain ID |
| `name` | TEXT | ✓ | Market name |
| `expiry` | TEXT | ✓ | ISO 8601 expiry date |
| `pt` | TEXT | ✓ | PT token ID ("chainId-address" format) |
| `yt` | TEXT | ✓ | YT token ID |
| `sy` | TEXT | ✓ | SY token ID |
| `underlyingAsset` | TEXT | ✓ | Underlying asset ID |
| `isNew` | INTEGER | ✓ | 1 if new market |
| `isPrime` | INTEGER | ✓ | 1 if prime market |
| `details_liquidity` | REAL | ✓ | AMM liquidity in USD |
| `details_totalTvl` | REAL | ✓ | Total TVL in USD |
| `details_tradingVolume` | REAL | ✓ | 24h trading volume USD |
| `details_underlyingApy` | REAL | ✓ | Variable APY (decimal) |
| `details_swapFeeApy` | REAL | ✓ | Swap fee APY |
| `details_pendleApy` | REAL | ✓ | PENDLE emissions APY |
| `details_impliedApy` | REAL | ✓ | Fixed/implied APY (decimal) |
| `details_aggregatedApy` | REAL | ✓ | Total LP APY |
| `details_maxBoostedApy` | REAL | ✓ | Max boosted APY (with vePENDLE) |
| `details_totalPt` | REAL | ✓ | PT tokens in pool |
| `details_totalSy` | REAL | ✓ | SY tokens in pool |
| `details_totalSupply` | REAL | ✓ | Total LP supply |
| `points` | TEXT (JSON) | ✗ | Serialized `PointMetadataEntity[]` — see below |
| `externalProtocols` | TEXT (JSON) | ✗ | Serialized `MarketExternalProtocolsEntity` — see below |

### Filter Operators

`=`, `!=`, `>`, `<`, `>=`, `<=`, `LIKE` — filters are AND-combined. `points` and `externalProtocols` are JSON blobs and cannot be used as filter fields; apply post-fetch filtering in your reasoning after parsing them.

---

### `points` Column — Point Reward Programs

Each market row includes a `points` JSON string. Parse it to get `PointMetadataEntity[]`:

```ts
interface PointMetadataEntity {
  key: string;             // reward program identifier, e.g. "eigen", "sats"
  type: "multiplier" | "points-per-asset";
  pendleAsset: "basic" | "lp"; // "lp" = LP holders earn; "basic" = PT/YT holders earn
  value: number;           // multiplier magnitude or points-per-asset rate
  perDollarLp: boolean;    // if true, value is per dollar of LP
}
```

**When to use:** surface markets that reward users with external protocol points (EigenLayer, Babylon, etc.) on top of Pendle yield.

**Fetch-then-filter pattern for points:**
```
1. get_markets({ limit: 100, sort: { field: "details_impliedApy", direction: "desc" } })
2. For each row, JSON.parse(row.points ?? "[]")
3. Filter rows where parsed array length > 0
4. Rank by value (multiplier magnitude) or by implied APY
```

**Interpreting point rewards:**
| `type` | `pendleAsset` | Meaning |
|---|---|---|
| `multiplier` | `basic` | PT/YT holders earn `value`× the base points rate |
| `multiplier` | `lp` | LP holders earn `value`× the base points rate |
| `points-per-asset` | `basic` | PT/YT holders earn `value` points per asset per day |
| `points-per-asset` | `lp` | LP holders earn `value` points per dollar of LP per day (if `perDollarLp: true`) |

---

### `externalProtocols` Column — External Yield Integrations

Each market row includes an `externalProtocols` JSON string for quick inspection on a single market. For filtering and ranking across markets, use `get_external_protocols` instead (SQL-backed, instant).

The JSON shape:
```ts
interface MarketExternalProtocolsEntity {
  pt:      ExternalProtocolMetadataEntity[];  // protocols that accept PT as collateral
  yt:      ExternalProtocolMetadataEntity[];  // protocols that accept YT
  lp:      ExternalProtocolMetadataEntity[];  // protocols that accept LP
  crossPt: ExternalProtocolMetadataEntity[];  // cross-chain PT integrations
}
```

**Prefer `get_external_protocols` over parsing JSON from `get_markets`** whenever you need to filter, sort, or compare protocols across multiple markets.

### Common Query Patterns

**Active markets sorted by fixed yield:**
```json
{
  "filter": [{"field": "expiry", "op": ">", "value": "2026-03-22T00:00:00.000Z"}],
  "sort": {"field": "details_impliedApy", "direction": "desc"},
  "limit": 10
}
```

**Markets by name pattern:**
```json
{
  "filter": [{"field": "name", "op": "LIKE", "value": "%ETH%"}]
}
```

**High-liquidity markets on a specific chain:**
```json
{
  "filter": [
    {"field": "chainId", "op": "=", "value": 42161},
    {"field": "details_liquidity", "op": ">", "value": 1000000}
  ],
  "sort": {"field": "details_liquidity", "direction": "desc"}
}
```

---

## `get_chains` — Supported Chains

Returns the list of blockchain network chain IDs where Pendle is deployed. Takes no parameters. Data refreshes every 5 minutes.

**Always call `get_chains` when the user asks which chains Pendle supports** — do NOT rely on a hardcoded list, as Pendle deploys to new chains over time.

---

## `get_asset` — Pendle Token Lookup

Look up metadata for Pendle-specific tokens (PT, YT, SY, LP) by chainId + address. Returns name, symbol, decimals, tags, expiry.

**Note:** This only covers Pendle tokens. For standard ERC-20s (USDC, WETH), use `resolve_token` instead.

---

## `get_market` — Deep Dive

For a single market deep-dive with full APY breakdown, pool metrics, and accepted input/output tokens, use `get_market`. It merges 3 API calls internally and returns comprehensive data.

---

## `get_history` — Time Series

Historical APY, TVL, and price data for a market. Use `fields` to select specific metrics and `timeFrame` for granularity (hour/day/week).

---

## Core Concepts

| Token | Symbol Pattern | Role |
|---|---|---|
| **PT** (Principal Token) | `PT-XYZ-DDMMMYYYY` | Fixed yield — redeems 1:1 at maturity |
| **YT** (Yield Token) | `YT-XYZ-DDMMMYYYY` | Leveraged variable yield — decays to 0 |
| **SY** (Standardised Yield) | `SY-XYZ` | Wrapped yield-bearing token |
| **LP** | `PLP-XYZ-DDMMMYYYY` | Pool share = market address |

---

---

## `get_external_protocols` — External Protocol Query

Queries the `market_external_protocols` table (0 API calls, instant). Data is exploded from `MarketExternalProtocolsEntity` at sync time — one row per (market, slot, protocol). Set `includeMarket: true` to JOIN the markets table and get `market_name`, `market_expiry`, `details_impliedApy`, `details_underlyingApy`, `details_aggregatedApy` in each result.

### Filterable Columns

| Column | Type | Description |
|---|---|---|
| `chainId` | INTEGER | Chain ID |
| `market` | TEXT | Market address |
| `slot` | TEXT | `pt`, `yt`, `lp`, or `crossPt` |
| `protocol_id` | TEXT | Protocol identifier, e.g. `aave`, `morpho`, `euler` |
| `protocol_name` | TEXT | Human-readable protocol name |
| `protocol_category` | TEXT | e.g. `lending`, `restaking` |
| `liquidity` | REAL | USD liquidity in this integration |
| `borrowApy` | REAL | Borrow APY (decimal) |
| `supplyApy` | REAL | Supply/collateral APY (decimal) |
| `totalSupply` | REAL | Total supplied amount |
| `supplyCap` | REAL | Supply cap |
| `maxLtv` | REAL | Max loan-to-value ratio |

### JOIN-only Sort Fields (require `includeMarket: true`)

`market_name`, `market_expiry`, `details_impliedApy`, `details_underlyingApy`, `details_aggregatedApy`

### Common Query Patterns

**All lending protocols that accept PT as collateral, best supply APY first:**
```json
{
  "filter": [{"field": "slot", "op": "=", "value": "pt"},
             {"field": "protocol_category", "op": "=", "value": "lending"}],
  "sort": {"field": "supplyApy", "direction": "desc"},
  "includeMarket": true
}
```

**PT markets on Arbitrum usable as Aave collateral:**
```json
{
  "filter": [{"field": "chainId", "op": "=", "value": 42161},
             {"field": "slot", "op": "=", "value": "pt"},
             {"field": "protocol_id", "op": "=", "value": "aave"}],
  "includeMarket": true
}
```

**Best borrow rate against LP (leveraged LP strategy):**
```json
{
  "filter": [{"field": "slot", "op": "=", "value": "lp"}],
  "sort": {"field": "borrowApy", "direction": "asc"},
  "includeMarket": true,
  "limit": 10
}
```

**Highest LTV for PT collateral (max leverage):**
```json
{
  "filter": [{"field": "slot", "op": "=", "value": "pt"},
             {"field": "maxLtv", "op": ">", "value": 0}],
  "sort": {"field": "maxLtv", "direction": "desc"},
  "includeMarket": true
}
```

**All integrations for a specific market:**
```json
{
  "filter": [{"field": "market", "op": "=", "value": "0x..."}],
  "includeMarket": true
}
```

---

## Yield Strategy Insights

**Always include one of these after data display:**

| Condition | Interpretation | Advice |
|---|---|---|
| implied APY > underlying APY | Market expects yield to fall | **PT opportunity** — lock in fixed rate |
| implied APY < underlying APY | Market expects yield to hold/rise | **YT opportunity** — leveraged exposure |
| Near maturity (< 30 days) | PT converges to par | Hold PT → redeem 1:1; LP IL reverses |
| LP APY > implied APY | LP outperforms pure PT | LP earns fees + PENDLE on top of fixed rate |
| `points` non-empty | Market has external point rewards | Factor in effective APY of points on top of base yield — can dominate for high-multiplier programs |
| `externalProtocols.pt` non-empty | PT accepted as collateral | Loop possible: deposit PT → borrow → buy PT. Effective APY ≈ `impliedApy / (1 - LTV) - borrowApy × LTV / (1 - LTV)`. See **Leverage Strategy Details** below. |
| `externalProtocols.lp` non-empty | LP accepted in external protocol | LP collateral loop: extra yield layer on top of LP APY. Higher risk than PT loop due to IL. |
| `externalProtocols.borrowApy` available | Lending market for this PT | If `impliedApy > borrowApy`: loop is profitable. If `impliedApy < borrowApy`: loop destroys value — do not recommend. |

---

## Presenting Market Data

```
## {name} | Expires {expiry}
Chain: {chainName} ({chainId})

### APY Snapshot
| Metric                  | Value  |
|-------------------------|--------|
| Implied (Fixed) APY     | X.XX%  |
| Underlying Variable APY | X.XX%  |
| Total LP APY            | X.XX%  |
|   -> PENDLE Emissions   | X.XX%  |
|   -> Swap Fee APY       | X.XX%  |
| Max Boosted (sPENDLE)   | X.XX%  |

### Pool Metrics
| TVL | 24h Volume | Liquidity |
|-----|------------|-----------|
| $X  | $X         | $X        |

### Tokens: PT={pt} YT={yt} SY={sy}

### Point Rewards  ← omit section if points array is empty
| Program | Asset | Type | Value |
|---------|-------|------|-------|
| {key}   | {pendleAsset} | {type} | {value}× / {value} pts |

### External Protocol Integrations  ← omit section if all arrays empty
| Token Slot | Protocol | Supply APY | Borrow APY | Max LTV | Liquidity |
|------------|----------|------------|------------|---------|-----------|
| PT         | {name}   | X.XX%      | X.XX%      | XX%     | $X        |
| LP         | {name}   | X.XX%      | —          | —       | $X        |
```

**Display rules:**
- Omit `Point Rewards` section entirely if `JSON.parse(points)` is an empty array or null.
- Omit `External Protocol Integrations` section if all four slot arrays (`pt`, `yt`, `lp`, `crossPt`) are empty.
- Show `—` for optional APY/LTV fields that are absent.
- For `crossPt`, label the Token Slot column as "Cross-PT".

---

## Error Handling

Tool errors return structured JSON with `error.code` and `error.retryable`. If `retryable: true`, wait and retry. Check `error.action` for guidance.

---

## Supported Chains

Use `get_chains` to get the current list of supported chain IDs. Do NOT hardcode chain IDs — Pendle deploys to new chains over time.

---

---

## Token Compatibility

Use `get_market` to check `tokensIn` and `tokensOut`. These are the addresses the market's SY wrapper natively accepts for minting/redeeming:

- If the user's token is in `tokensIn` → direct deposit, no extra swap.
- If not → the Pendle aggregator may still route through an intermediate swap (e.g., USDT → USDC → PT). Flag this as "via aggregator" and note added slippage risk.
- `tokensOut` governs withdrawal paths — check before recommending an exit.

---

## Leverage Strategy Details

### PT Looping

**Concept**: Use PT as collateral in a lending protocol, borrow stables, buy more PT, repeat.

**Requirements**: PT must appear in `get_external_protocols` with `slot=pt` and `maxLtv > 0`.

**Effective APY formula** (single-loop approximation):
```
effectiveApy ≈ impliedApy / (1 - LTV) - borrowApy × LTV / (1 - LTV)
```

**Example** — PT impliedApy = 8%, LTV = 0.75, borrowApy = 5%:
```
effectiveApy ≈ 8% / 0.25 - 5% × 0.75 / 0.25
             = 32% - 15% = 17% effective fixed APY
```

**Risk checklist before recommending:**
1. `supplyCap` from `get_external_protocols` — is there room to deposit?
2. `liquidity` in the lending pool — enough to borrow the target amount?
3. Buffer from liquidation: keep LTV well below `maxLtv` (suggest 10-15% safety margin)
4. PT price drops toward par at maturity — liquidation risk actually *decreases* over time for PT collateral
5. Borrow rate must stay below `impliedApy` for the loop to be profitable; check `get_history` for rate stability

**Exit path**: Repay loan → withdraw PT → sell PT or hold to maturity.

---

### LP Collateral Loop

**Concept**: Deposit LP into a lending protocol, borrow stables, re-deploy capital into the same market (add liquidity again).

**Requirements**: LP must appear in `get_external_protocols` with `slot=lp`.

**Effective APY** (simplified):
```
effectiveApy ≈ aggregatedApy + (aggregatedApy - borrowApy) × LTV / (1 - LTV)
```

**Higher risk than PT looping**: LP value is more volatile (IL risk from APY swings). Use conservatively.

---

### When to Suggest Looping

| Condition | Suggest loop? |
|---|---|
| `impliedApy - borrowApy > 3%` | Yes — comfortable margin |
| `impliedApy - borrowApy` between 1-3% | Conditional — only if rate is historically stable |
| `impliedApy < borrowApy` | No — loop is immediately loss-making |
| `supplyCap` nearly full | No — may not be able to deposit PT |
| `isVolatile = true` | Caution — underlying price movement can trigger liquidation |

---

## Related Skills

- `/pendle-swap` — trade PT/YT, manage LP positions
- `/pendle-portfolio` — portfolio view
- `/pendle-order` — limit orders

