solana-traderclaw 1.0.36 → 1.0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -619,7 +619,7 @@ function traderCronPrescriptiveJobs(agentId) {
619
619
  schedule: "0 * * * *",
620
620
  agentId,
621
621
  message:
622
- "CRON_JOB: alpha_scan — Call solana_scan_launches to find new token launches from the last hour. For each candidate, call solana_token_snapshot to check price, volume, and age. Filter for: 24h volume above 50000 USD, market cap above 10000 USD. For tokens that pass, call solana_token_holders to check holder distribution (skip if top holder owns more than 30 percent), then solana_token_risk to check for mint/freeze authority (hard skip if present). If a token passes all checks, call solana_alpha_submit to add it to the alpha buffer for the CTO's next heartbeat evaluation. Log all scanned tokens and results using solana_memory_write. Do not execute trades directly — only submit to alpha buffer. Do not ask questions.",
622
+ "CRON_JOB: alpha_scan — Call solana_scan_launches to find new token launches from the last hour. For each candidate, call solana_token_snapshot to check price, volume, and age. Filter for: 24h volume above 50000 USD, market cap above 10000 USD. For tokens that pass, call solana_token_holders to check holder distribution (skip if top holder owns more than 30 percent), then solana_token_risk to check for mint/freeze authority (hard skip if present). If a token passes all checks, use solana_trade_precheck and consider trade execution using solana_trade_execute. Log all scanned tokens and results using solana_memory_write. Do not ask questions.",
623
623
  enabled: true,
624
624
  },
625
625
  {
package/dist/index.js CHANGED
@@ -1254,14 +1254,31 @@ var solanaTraderPlugin = {
1254
1254
  });
1255
1255
  api.registerTool({
1256
1256
  name: "solana_trade_precheck",
1257
- description: "Pre-trade risk check \u2014 validates a proposed trade against risk rules, kill switch, entitlement limits, and on-chain conditions. Returns approved/denied with reasons and capped size. Always call this before executing a trade. Buy: sizeSol required; do not send sizeTokens or sellPct. Sell: send exactly one of sizeTokens or sellPct (not sizeSol). If both sellPct and sizeTokens are sent, sellPct is preferred and sizeTokens is ignored.",
1257
+ description: "Pre-trade risk check \u2014 validates a proposed trade against risk rules, kill switch, entitlement limits, and on-chain conditions. Returns approved/denied with reasons and capped size. Always call this before executing a trade. Buy: sizeSol required; do not send sizeTokens or sellPct. Sell: send exactly one of sizeTokens or sellPct (not sizeSol). If both sellPct and sizeTokens are sent, sellPct is preferred and sizeTokens is ignored. Optional exit fields (trailingStopPct, trailingStop) are accepted to mirror execute payloads; sizing logic ignores them.",
1258
1258
  parameters: Type.Object({
1259
1259
  tokenAddress: Type.String({ description: "Solana token mint address" }),
1260
1260
  side: Type.Union([Type.Literal("buy"), Type.Literal("sell")], { description: "Trade direction" }),
1261
1261
  sizeSol: Type.Optional(Type.Number({ description: "Position size in SOL \u2014 required for buy, omit for sell" })),
1262
1262
  sellPct: Type.Optional(Type.Number({ description: "Sell percentage 1\u2013100 (100 = full exit) \u2014 sell only; preferred over sizeTokens if both sent" })),
1263
1263
  sizeTokens: Type.Optional(Type.Number({ description: "Token amount to sell \u2014 sell only; ignored if sellPct is also provided" })),
1264
- slippageBps: Type.Optional(Type.Number({ description: "Slippage tolerance in basis points (e.g., 300 = 3%)" }))
1264
+ slippageBps: Type.Optional(Type.Number({ description: "Slippage tolerance in basis points (e.g., 300 = 3%)" })),
1265
+ trailingStopPct: Type.Optional(Type.Number({ description: "Optional \u2014 same as execute; ignored for policy sizing" })),
1266
+ trailingStop: Type.Optional(
1267
+ Type.Object({
1268
+ levels: Type.Array(
1269
+ Type.Object({
1270
+ percentage: Type.Number({ description: "Trailing drawdown % from the armed high once the level is active" }),
1271
+ amount: Type.Optional(Type.Number({ description: "% of position to sell at this level (1\u2013100). Server default 100." })),
1272
+ triggerAboveATH: Type.Optional(
1273
+ Type.Number({
1274
+ description: "Optional. % above session ATH before this level arms. If omitted, API defaults to 100 (2\xD7 ATH)."
1275
+ })
1276
+ )
1277
+ }),
1278
+ { minItems: 1, maxItems: 5, description: "Multi-level trailing (optional on precheck)" }
1279
+ )
1280
+ })
1281
+ )
1265
1282
  }),
1266
1283
  execute: wrapExecute(async (_id, params) => {
1267
1284
  const body = {
@@ -1269,6 +1286,13 @@ var solanaTraderPlugin = {
1269
1286
  side: params.side,
1270
1287
  slippageBps: params.slippageBps
1271
1288
  };
1289
+ if (params.trailingStopPct !== void 0) {
1290
+ body.trailingStopPct = params.trailingStopPct;
1291
+ }
1292
+ const ts = params.trailingStop;
1293
+ if (ts?.levels && Array.isArray(ts.levels) && ts.levels.length > 0) {
1294
+ body.trailingStop = ts;
1295
+ }
1272
1296
  if (params.side === "buy") {
1273
1297
  body.sizeSol = params.sizeSol;
1274
1298
  } else {
@@ -1283,7 +1307,7 @@ var solanaTraderPlugin = {
1283
1307
  });
1284
1308
  api.registerTool({
1285
1309
  name: "solana_trade_execute",
1286
- description: "Execute a trade on Solana via the SpyFly bot. Enforces risk rules before proxying to on-chain execution. Returns trade ID, position ID, and transaction signature. IMPORTANT: tpLevels alone (e.g. [10, 15]) means EACH level sells 100% of the position at that gain \u2014 use tpExits for partials (e.g. +10% sell 50%, +15% sell 100%). Buy: sizeSol required; do not send sizeTokens or sellPct. Sell: send exactly one of sizeTokens or sellPct (not sizeSol). If both sellPct and sizeTokens are sent, sellPct is preferred and sizeTokens is ignored.",
1310
+ description: "Execute a trade on Solana via the SpyFly bot. Enforces risk rules before proxying to on-chain execution. Returns trade ID, position ID, and transaction signature. IMPORTANT: tpLevels alone (e.g. [10, 15]) means EACH level sells 100% of the position at that gain \u2014 use tpExits for partials (e.g. +10% sell 50%, +15% sell 100%). Trailing: use `trailingStopPct` for a single simple trailing %, or `trailingStop.levels` (1\u20135) for multi-level trailing with optional `triggerAboveATH` per level (% above session ATH before that level arms; if omitted, server defaults to 100 i.e. 2\xD7 ATH). When both are sent, `trailingStop` wins. Buy: sizeSol required; do not send sizeTokens or sellPct. Sell: send exactly one of sizeTokens or sellPct (not sizeSol). If both sellPct and sizeTokens are sent, sellPct is preferred and sizeTokens is ignored.",
1287
1311
  parameters: Type.Object({
1288
1312
  tokenAddress: Type.String({ description: "Solana token mint address" }),
1289
1313
  side: Type.Union([Type.Literal("buy"), Type.Literal("sell")], { description: "Trade direction" }),
@@ -1318,7 +1342,37 @@ var solanaTraderPlugin = {
1318
1342
  { description: "Multi-level stop-loss with partial exits (optional). Otherwise use slPct for a single full exit." }
1319
1343
  )
1320
1344
  ),
1321
- trailingStopPct: Type.Optional(Type.Number({ description: "Trailing stop percentage" })),
1345
+ trailingStopPct: Type.Optional(
1346
+ Type.Number({
1347
+ description: "Single trailing-stop % (legacy). Ignored if `trailingStop` is provided."
1348
+ })
1349
+ ),
1350
+ trailingStop: Type.Optional(
1351
+ Type.Object({
1352
+ levels: Type.Array(
1353
+ Type.Object({
1354
+ percentage: Type.Number({
1355
+ description: "Once armed, sell when price drops this % from the high (trailing drawdown)."
1356
+ }),
1357
+ amount: Type.Optional(
1358
+ Type.Number({
1359
+ description: "% of position to sell when this level fires (1\u2013100). Server default 100."
1360
+ })
1361
+ ),
1362
+ triggerAboveATH: Type.Optional(
1363
+ Type.Number({
1364
+ description: "Optional. Session price must reach this % above session ATH before this level arms (e.g. 50 \u2192 1.5\xD7 ATH). If omitted, API defaults to 100 (2\xD7 ATH)."
1365
+ })
1366
+ )
1367
+ }),
1368
+ {
1369
+ minItems: 1,
1370
+ maxItems: 5,
1371
+ description: "Ordered trailing-stop levels (up to 5)."
1372
+ }
1373
+ )
1374
+ })
1375
+ ),
1322
1376
  managementMode: Type.Optional(
1323
1377
  Type.Union([Type.Literal("LOCAL_MANAGED"), Type.Literal("SERVER_MANAGED")], {
1324
1378
  description: "Advisory only \u2014 server decides position mode internally. Sent for future compatibility."
@@ -1337,9 +1391,14 @@ var solanaTraderPlugin = {
1337
1391
  symbol: params.symbol,
1338
1392
  slippageBps: params.slippageBps,
1339
1393
  slPct: params.slPct,
1340
- trailingStopPct: params.trailingStopPct,
1341
1394
  managementMode: params.managementMode
1342
1395
  };
1396
+ const tsExecute = params.trailingStop;
1397
+ if (tsExecute?.levels && Array.isArray(tsExecute.levels) && tsExecute.levels.length > 0) {
1398
+ body.trailingStop = tsExecute;
1399
+ } else if (params.trailingStopPct !== void 0) {
1400
+ body.trailingStopPct = params.trailingStopPct;
1401
+ }
1343
1402
  if (params.side === "buy") {
1344
1403
  body.sizeSol = params.sizeSol;
1345
1404
  } else {
@@ -1507,7 +1566,7 @@ var solanaTraderPlugin = {
1507
1566
  });
1508
1567
  api.registerTool({
1509
1568
  name: "solana_capital_status",
1510
- description: "Get your current capital status \u2014 SOL balance, open position count, unrealized PnL, daily notional used, daily loss, and effective limits (adjusted by entitlements).",
1569
+ description: "Get your current capital status \u2014 SOL balance, open position count, unrealized/realized PnL, daily notional used, daily loss, and effective limits. **PnL:** `totalUnrealizedPnl` / `totalRealizedPnl` are USD (DB); use `totalUnrealizedPnlSol` / `totalRealizedPnlSol` / `totalPnlSol` for SOL (derived via `solPriceUsd`, same as positions API).",
1511
1570
  parameters: Type.Object({}),
1512
1571
  execute: wrapExecute(
1513
1572
  async () => get(`/api/capital/status?walletId=${walletId}`)
@@ -1515,7 +1574,7 @@ var solanaTraderPlugin = {
1515
1574
  });
1516
1575
  api.registerTool({
1517
1576
  name: "solana_positions",
1518
- description: "List your current trading positions with unrealized PnL, entry price, current price, stop-loss/take-profit settings, and management mode. Call at the START of every trading cycle for interrupt check. Also use to detect dead money (flat positions).",
1577
+ description: "List trading positions with mark-to-market. **PnL:** `realizedPnl` / `unrealizedPnl` are USD as stored; prefer `realizedPnlSol` / `unrealizedPnlSol` when reasoning in SOL. `unrealizedReturnPct` is ROI on cost basis (for sweep-dead-tokens logic). See response `pnlNote`.",
1519
1578
  parameters: Type.Object({
1520
1579
  status: Type.Optional(Type.String({ description: "Filter by status: 'open', 'closed', or omit for all" }))
1521
1580
  }),
@@ -1525,6 +1584,38 @@ var solanaTraderPlugin = {
1525
1584
  return get(path2);
1526
1585
  })
1527
1586
  });
1587
+ api.registerTool({
1588
+ name: "solana_wallet_token_balance",
1589
+ description: "Read on-chain SPL token balance (UI amount) for your trading wallet and a token mint. Same balance path as server exit monitoring (`balanceOf`).",
1590
+ parameters: Type.Object({
1591
+ tokenAddress: Type.String({ description: "SPL token mint address" })
1592
+ }),
1593
+ execute: wrapExecute(
1594
+ async (_id, params) => post("/api/wallet/token-balance", {
1595
+ walletId,
1596
+ tokenAddress: params.tokenAddress
1597
+ })
1598
+ )
1599
+ });
1600
+ api.registerTool({
1601
+ name: "solana_sweep_dead_tokens",
1602
+ description: "Sell 100% of each OPEN position whose unrealizedReturnPct is \u2264 -maxLossPct (default 80), using the same mark-to-market as positions. Use dryRun:true first to list candidates. Executes sequential full exits (sellPct 100). Requires trade:execute scope.",
1603
+ parameters: Type.Object({
1604
+ maxLossPct: Type.Optional(
1605
+ Type.Number({ description: "Threshold: sweep when unrealizedReturnPct <= -maxLossPct (default 80)" })
1606
+ ),
1607
+ slippageBps: Type.Optional(Type.Number({ description: "Per-exit slippage in bps (default 300)" })),
1608
+ dryRun: Type.Optional(Type.Boolean({ description: "If true, only return candidate tokens without selling" }))
1609
+ }),
1610
+ execute: wrapExecute(
1611
+ async (_id, params) => post("/api/wallet/sweep-dead-tokens", {
1612
+ walletId,
1613
+ maxLossPct: params.maxLossPct,
1614
+ slippageBps: params.slippageBps,
1615
+ dryRun: params.dryRun
1616
+ })
1617
+ )
1618
+ });
1528
1619
  api.registerTool({
1529
1620
  name: "solana_funding_instructions",
1530
1621
  description: "Get deposit instructions for funding your trading wallet with SOL.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solana-traderclaw",
3
- "version": "1.0.36",
3
+ "version": "1.0.37",
4
4
  "description": "TraderClaw V1 — autonomous Solana memecoin trading for OpenClaw (team edition: X/Twitter journal and engagement tools)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -14,7 +14,7 @@ The orchestrator gathers data, enforces execution policy, applies entitlement li
14
14
 
15
15
  ## How You Access the Orchestrator
16
16
 
17
- You interact with the orchestrator **exclusively through plugin tools** (e.g. `solana_system_status`, `solana_scan`, `solana_alpha_signals`, `solana_trade`, etc.). You have no other access method.
17
+ You interact with the orchestrator **exclusively through plugin tools** (e.g. `solana_system_status`, `solana_scan_hot_pairs`,`solana_scan_launches` , `solana_alpha_signals`, `solana_trade_precheck`, `solana_trade_execute`, etc.). You have no other access method.
18
18
 
19
19
  **Critical rules:**
20
20
  - **You do NOT have direct HTTP/API access.** Never attempt to call REST endpoints, use curl/fetch, or construct API URLs. You cannot reach the orchestrator that way.
@@ -234,8 +234,14 @@ All values are internal targets that must still comply with server policy caps.
234
234
  | Position size (exploratory) | 3–8% of capital | 5–10% of capital |
235
235
  | Max correlated cluster exposure | 40% of capital | 40% of capital |
236
236
  | Consecutive losses → kill switch | 5 | 7 |
237
- | Rapid drawdown defense trigger | -20% on any position | -15% on any position |
238
- | Partial profit trigger | +40–60% (optional) | +25–50% (take partial quickly) |
237
+ | Stop loss (slExits) | -20% on every position | -40% on every position |
238
+ | Trailing Stop loss ("trailingStop": {
239
+ "levels": [
240
+ { "percentage": 25, "amount": 50 },
241
+ { "percentage": 35, "amount": 100, "triggerAboveATH": 100 }
242
+ ]
243
+ }) where percent is the price decrease from entry price and amount is the size of position in percentage and in token holding | -20% on every position and optional triggerAboveATH | -40% on every position |
244
+ | Multiple Take Profit exits (tpExits) (e.g [{"percent": 100, "amountPct": 30},{ "percent": 200, "amountPct": 100" }], where percent is the price increase from entry price and amountPct is the size of position in percentage and in token holding) | +100–300% (multiple) | +200–500% (multiple) |
239
245
  | Exploration ratio | 20% experimental / 80% proven | 50% experimental / 50% proven |
240
246
  | Weight evolution (minimum trades) | ≥20 closed trades | ≥20 closed trades |
241
247
  | Max weight delta per update | ±0.10 | ±0.15 |
@@ -330,7 +336,7 @@ There is no context loss from this separation. Cron outputs flow into the persis
330
336
 
331
337
  2. Step 0: INTERRUPT CHECK — identify wake-up trigger, check kill switch, check dead money, STRATEGY INTEGRITY CHECK
332
338
 
333
- 3. Step 1: SCAN — call solana_scan for broad discovery, process Bitquery subscriptions
339
+ 3. Step 1: SCAN — call solana_scan_launches and solana_scan_hot_pairs for broad discovery, process Bitquery subscriptions
334
340
 
335
341
  4. Step 1.5b: ALPHA SIGNALS — poll solana_alpha_signals, score, classify priority
336
342
 
@@ -902,10 +908,6 @@ Discovery subscriptions complement — not replace — scan endpoints and alpha
902
908
 
903
909
  When multiple paths independently surface the same token = convergence = highest conviction. Log convergence events via `solana_memory_write` with tag `signal_convergence`.
904
910
 
905
- **Future enhancement (not yet available):**
906
-
907
- When `solana_firehose_config` and `solana_firehose_status` tools become available, you will be able to configure advanced filter parameters (volume thresholds, buyer counts, whale detection) directly on the orchestrator or local worker, and check health/stats. For now, use the existing `solana_bitquery_subscribe` with the available template keys and evolve your subscription strategy based on outcomes.
908
-
909
911
  ---
910
912
 
911
913
  ### Step 2: ANALYZE — Deep Dive
@@ -1128,9 +1130,11 @@ If BUY, you must define before executing:
1128
1130
  - `tpLevels` — staged take-profit levels as percentages
1129
1131
  - HARDENED: `[50, 100, 200]` (patient, ride trends)
1130
1132
  - DEGEN: `[25, 50, 100]` (lock gains faster)
1131
- - `trailingStopPct` — trailing stop activation
1132
- - HARDENED: 1218%
1133
- - DEGEN: 8–15%
1133
+ - `trailingStopPct` — single trailing stop (% drawdown from session high once active). Legacy/simple path on the server.
1134
+ - **`trailingStop`** (preferred for staging) — `{ levels: [ ... ] }` with **15** levels. Each level:
1135
+ - `percentage` — trailing drawdown % from the armed high once that level is active (required).
1136
+ - `amount` — % of position to sell at this level (1–100; server default **100**).
1137
+ - `triggerAboveATH` — **optional.** Price must reach this **% above the session ATH** before this level arms (e.g. `50` → 1.5× ATH). **If omitted, the API defaults to `100` (2× ATH).** Use a smaller value (e.g. `25`) to arm earlier; use `trailingStopPct` instead if you want the simpler single-level trailing that keys off ATH without this gate.
1134
1138
  - `managementMode` — LOCAL_MANAGED or SERVER_MANAGED
1135
1139
  - `slippageBps` — must scale with liquidity:
1136
1140
  - Pool depth > $500K: 100–200 bps
@@ -1227,7 +1231,7 @@ Call `solana_trade_execute` with:
1227
1231
  - **For buy:** `sizeSol` (amount in SOL to spend) — required
1228
1232
  - **For sell:** `sellPct` (percentage of position to sell, 1–100 where 100 = full exit) **or** `sizeTokens` (exact token count) — one is required. If both sent, `sellPct` wins. Do NOT send `sizeSol` for sells.
1229
1233
  - `slippageBps` (scaled to liquidity as defined in your exit plan — hard cap 800bps)
1230
- - `slPct`, `tpLevels`, `trailingStopPct`
1234
+ - `slPct`, `tpLevels`, **`trailingStopPct` and/or `trailingStop`** (see **Define Exit Plan** above — if both are sent, `trailingStop` wins)
1231
1235
  - `managementMode`
1232
1236
 
1233
1237
  Record the returned `tradeId` and `positionId`. You will need these for monitoring and review.
@@ -1669,7 +1673,6 @@ Your discovery subscriptions (Step 1.75) should evolve alongside your strategy w
1669
1673
  - **Adjusting discovery subscriptions** (broad, for token detection):
1670
1674
  Discovery subscriptions like `pumpFunTokenCreation` and `raydiumNewPools` are fire-and-forget — you set them up once and they run until you unsubscribe. Evolution here means deciding which broad subscriptions to keep vs remove, not changing their parameters.
1671
1675
 
1672
- When `solana_firehose_config` becomes available, you will be able to configure advanced filter parameters (volume thresholds, buyer counts, whale detection) on the orchestrator or local worker side without the unsub/resub cycle.
1673
1676
 
1674
1677
  5. Mode switches should trigger subscription review:
1675
1678
  - Switching to DEGEN → add more discovery subscriptions, broaden parameters
@@ -2064,8 +2067,10 @@ All authenticated endpoints use `Authorization: Bearer <accessToken>`.
2064
2067
  | `POST` | `/api/session/logout` | `refreshToken` | No auth needed. Revokes session |
2065
2068
  | `GET` | `/api/wallets` | — | List all wallets. Optional `?refresh=true` |
2066
2069
  | `POST` | `/api/wallet/create` | — | Create wallet. Optional: `label`, `publicKey`, `chain` (solana/bsc), `ownerRef`, `includePrivateKey`. Status `201` |
2067
- | `GET` | `/api/capital/status` | `?walletId=<uuid>` | Wallet capital and daily limits |
2068
- | `GET` | `/api/wallet/positions` | `?walletId=<uuid>` | Open positions. Optional `?status=` |
2070
+ | `GET` | `/api/capital/status` | `?walletId=<uuid>` | Wallet capital and daily limits. **PnL:** `totalUnrealizedPnl` / `totalRealizedPnl` are **USD** (stored); `totalUnrealizedPnlSol` / `totalRealizedPnlSol` / `totalPnlSol` are **SOL** derived with `solPriceUsd` (agent-safe). |
2071
+ | `GET` | `/api/wallet/positions` | `?walletId=<uuid>` | Positions. **`realizedPnl` / `unrealizedPnl` = USD** in DB; use **`realizedPnlSol` / `unrealizedPnlSol`** for SOL. `unrealizedReturnPct` = ROI vs cost (for sweep). |
2072
+ | `POST` | `/api/wallet/token-balance` | `walletId`, `tokenAddress` | On-chain SPL **uiAmount** for the wallet (same as server `balanceOf`) |
2073
+ | `POST` | `/api/wallet/sweep-dead-tokens` | `walletId` | Optional: `maxLossPct` (default **80**), `slippageBps`, `dryRun`. Sells **100%** of each **open** position with `unrealizedReturnPct` ≤ **-maxLossPct**. **trade:execute** scope. |
2069
2074
  | `GET` | `/api/funding/instructions` | `?walletId=<uuid>` | Deposit instructions |
2070
2075
  | `GET` | `/api/killswitch/status` | `?walletId=<uuid>` | Kill switch state |
2071
2076
  | `POST` | `/api/killswitch` | `walletId`, `enabled` | Toggle kill switch. Optional: `mode` (TRADES_ONLY / TRADES_AND_STREAMS). **Pro tier required** |
@@ -2073,7 +2078,7 @@ All authenticated endpoints use `Authorization: Bearer <accessToken>`.
2073
2078
  | `POST` | `/api/strategy/update` | `walletId`, `featureWeights` | Update weights. Optional: `strategyVersion`, `mode` (HARDENED/DEGEN) |
2074
2079
  | `POST` | `/api/thesis/build` | `walletId`, `tokenAddress` | Build full thesis package |
2075
2080
  | `POST` | `/api/trade/precheck` | `walletId`, `tokenAddress`, `side` (buy/sell), `slippageBps`. Buy: `sizeSol`. Sell: `sellPct` or `sizeTokens` | Risk/policy check, no execution |
2076
- | `POST` | `/api/trade/execute` | `walletId`, `tokenAddress`, `side`, `slippageBps`. Buy: `sizeSol`. Sell: `sellPct` or `sizeTokens` | Execute trade. Optional: `symbol`, `tpLevels[]`, `slPct`, `trailingStopPct`. Header: `x-idempotency-key` |
2081
+ | `POST` | `/api/trade/execute` | `walletId`, `tokenAddress`, `side`, `slippageBps`. Buy: `sizeSol`. Sell: `sellPct` or `sizeTokens` | Execute trade. Optional: `symbol`, `tpLevels[]`, `slPct`, `trailingStopPct`, `trailingStop: { levels: [{ percentage, amount?, triggerAboveATH? }] }` (1–5 levels; **omitted `triggerAboveATH` defaults to 100** = 2× ATH). Header: `x-idempotency-key` |
2077
2082
  | `POST` | `/api/trade/review` | `walletId`, `outcome` (win/loss/neutral), `notes` | Post-trade review. Optional: `tradeId`, `tokenAddress`, `pnlSol`, `tags[]`, `strategyVersion` (strict semver). Status `201` |
2078
2083
  | `POST` | `/api/memory/write` | `walletId`, `notes` | Journal entry. Optional: `tokenAddress`, `outcome` (win/loss/neutral), `tags[]`, `strategyVersion` (strict semver). Status `201` |
2079
2084
  | `POST` | `/api/memory/search` | `walletId`, `query` | Search memory entries |
@@ -2701,8 +2706,10 @@ Each user configures their own X/Twitter API developer account tokens in the plu
2701
2706
  | Thesis | `solana_build_thesis` | Full context package |
2702
2707
  | Trade | `solana_trade_precheck` | Pre-trade risk validation |
2703
2708
  | Trade | `solana_trade_execute` | Execute trade |
2704
- | Monitor | `solana_positions` | Position tracking |
2705
- | Monitor | `solana_capital_status` | Portfolio status |
2709
+ | Monitor | `solana_positions` | Position tracking (USD PnL in DB; use `*PnlSol` fields for SOL) |
2710
+ | Monitor | `solana_capital_status` | Portfolio status (same USD vs SOL split as API) |
2711
+ | Risk | `solana_sweep_dead_tokens` | Full-exit open positions below **-maxLossPct** ROI (default 80%); use `dryRun` first |
2712
+ | Wallet | `solana_wallet_token_balance` | On-chain SPL balance for a mint |
2706
2713
  | Review | `solana_trade_review` | Post-trade review |
2707
2714
  | Memory | `solana_memory_write` | Write journal entry (deployer profiles, filter evolution, convergence) |
2708
2715
  | Memory | `solana_memory_search` | Search memories (check deployer history before profiling) |