# Solana Wallet PnL & Smart-Money Profiler (`metallic_pastry/solana-wallet-pnl-profiler`) Actor

Solana wallet PnL, win rate, holding times and a transparent smart-money score from raw on-chain data via your own RPC (Helius, Triton, QuickNode). No scraping. Errors are free.

- **URL**: https://apify.com/metallic_pastry/solana-wallet-pnl-profiler.md
- **Developed by:** [Simon Liarsgård](https://apify.com/metallic_pastry) (community)
- **Categories:** Developer tools, Integrations, AI
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 wallet profileds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Solana Wallet PnL & Smart-Money Profiler

**Realized and unrealized PnL, win rate, holding times, top wins/losses and a transparent smart-money score for any Solana wallet, computed straight from on-chain data through your own RPC.**

Paste wallet addresses, plug in your Helius / Triton / QuickNode URL (or use the public endpoint for a quick try), and get one clean row per wallet. Every number can be traced back to on-chain transactions: the scoring formula is documented below, and each result carries its own score breakdown and diagnostics.

**$0.005 per profiled wallet. Invalid addresses and RPC failures are free.**

### Who it is for

- **Copy-trading and alpha research:** shortlist wallets that actually make money, with win rate and holding time next to PnL.
- **Bot and sniper detection:** seconds-long median holds and extreme trade counts stand out immediately.
- **Dashboards and agents:** call it from the Apify API, Make, n8n, Zapier or any MCP-capable AI agent and get structured JSON back.
- **Due diligence:** check a KOL's or a fund's on-chain track record before you trust their calls.

### How to use it

1. Add one or more wallet addresses in **Wallet addresses**.
2. Paste your RPC URL in **Solana RPC URL** (recommended), or leave it empty to try the public endpoint (capped at 50 transactions per wallet).
3. Optionally change the time window, the transaction cap and the smart-money thresholds.
4. Click **Start**. Results appear in the **Overview** and **Detail** dataset views; export as JSON, CSV or Excel.

### What it does

For every wallet and time window (default: last 30 days) the actor:

1. reads the wallet's transaction history over standard Solana JSON-RPC (`getSignaturesForAddress` + `getTransaction`);
2. detects swaps on **any DEX or aggregator**: Jupiter, Pump.fun, PumpSwap, Raydium, Orca, Meteora and others, multi-hop routes included. Detection works from balance changes, not from program-specific decoders;
3. runs an **average-cost PnL ledger** per token, in SOL (SOL + wSOL) and separately in USD (USDC + USDT);
4. computes **win rate, number of trades, average/median holding time, top wins and losses, most traded tokens, first/last trade**;
5. scores the wallet with a **documented smart-money formula** and sets a `smartMoney` flag based on thresholds **you** choose.

### Why on-chain and bring-your-own RPC?

- **No scraping.** The actor only talks to a Solana RPC node, so there is no website layout to break and no third-party terms to worry about.
- **Your RPC, your limits.** Use the RPC plan you already pay for. Every provider exposing standard JSON-RPC works. The URL is stored as an encrypted secret input, and it's redacted in logs.
- **Transparent methodology.** No black-box "smart score". You get each score component, its weight, its inputs and the formula, and every threshold check behind `smartMoney`.
- **Read-only.** The actor never signs or sends transactions and never touches private keys.

### Input

```json
{
    "wallets": ["FEdz1g8HfaAUSoJbSB1sXfcweh3qzye4XJAmaafUmA96", "HHEF5WjjKnM9xAxdMjEH2mNFBHSfUtxq79dkZXVCJ7fM"],
    "rpcUrl": "https://mainnet.helius-rpc.com/?api-key=YOUR_KEY",
    "lookbackDays": 30,
    "maxTransactionsPerWallet": 500,
    "maxRequestsPerSecond": 20,
    "minWinRate": 0.55,
    "minRealizedPnlSol": 1,
    "minClosedPositions": 5,
    "includeTokenBreakdown": true,
    "includeTrades": false
}
```

| Field | Default | Notes |
|---|---|---|
| `wallets` | (required) | Base58 addresses. Duplicates are removed; invalid ones give a free error item. |
| `rpcUrl` | public mainnet | Secret field. Strongly recommended: your own Helius/Triton/QuickNode URL. On the public endpoint, history is capped at **50 tx per wallet**. |
| `lookbackDays` / `startDate` / `endDate` | 30 days | `startDate`/`endDate` (UTC, `YYYY-MM-DD`) override the lookback. |
| `maxTransactionsPerWallet` | 500 (max 5000) | Newest first. If a wallet has more inside the window, the item gets `truncated: true`. |
| `maxRequestsPerSecond`, `concurrency` | 5, 3 | Upper bounds. The actor also slows itself down when the RPC rate limits. |
| `useBatchRequests` | true | JSON-RPC batches, with automatic fallback to single requests if the endpoint rejects them. |
| `requestTimeoutSecs`, `maxRetries` | 30, 6 | Per-request timeout; retries with exponential backoff and jitter, honoring `Retry-After`. |
| `minWinRate`, `minRealizedPnlSol`, `minClosedPositions` | 0.55, 1, 5 | Thresholds for the `smartMoney` flag. |
| `includeTokenBreakdown`, `includeTrades` | true, false | Per-token ledgers / every classified swap. |
| `maxWallets` | 100 | Safety limit per run. |

### Output

One dataset item per wallet. Here is a real item from a test run (2026-10-29, public RPC, 50 tx), trimmed to one token:

```json
{
  "wallet": "HHEF5WjjKnM9xAxdMjEH2mNFBHSfUtxq79dkZXVCJ7fM",
  "status": "ok",
  "truncated": true,
  "truncationReason": "max_transactions_per_wallet",
  "windowStart": "2026-09-29T01:47:51.000Z",
  "windowEnd": "2026-10-29T01:47:51.000Z",
  "realizedPnlSol": 2.41935883,
  "unrealizedPnlSol": 0,
  "totalPnlSol": 2.41935883,
  "realizedPnlSolAfterFees": 2.416972827,
  "swapFeesSol": 0.002386003,
  "realizedPnlUsd": 0,
  "unrealizedPnlUsd": 0,
  "volumeSol": 27.721901982,
  "winRate": 0.6667,
  "closedPositions": 6,
  "winningPositions": 4,
  "trades": 13,
  "buys": 6,
  "sells": 7,
  "tokensTraded": 6,
  "tokensWithUnknownCostBasis": 0,
  "avgHoldingTimeSec": 1,
  "medianHoldingTimeSec": 1,
  "firstTradeAt": "2026-10-29T00:20:22.000Z",
  "lastTradeAt": "2026-10-29T01:01:28.000Z",
  "smartMoneyScore": 49.8,
  "scoreComponents": {
    "winRate": { "value": 0.625, "weight": 0.35, "points": 21.88, "formula": "(winningPositions + 1) / (closedPositions + 2)", "inputs": { "winningPositions": 4, "closedPositions": 6 } },
    "realizedPnl": { "value": 0.1947, "weight": 0.3, "points": 5.84, "inputs": { "realizedPnlSolAfterFees": 2.416973 } },
    "activity": { "value": 0.6, "weight": 0.15, "points": 9, "inputs": { "closedPositions": 6, "tradesPerDay": 13 } },
    "consistency": { "value": 0.6558, "weight": 0.2, "points": 13.12, "inputs": { "winningSolPositions": 4, "largestWinSol": 1.062164, "grossWinsSol": 3.085804 } }
  },
  "smartMoney": true,
  "smartMoneyCriteria": {
    "winRate": { "required": 0.55, "actual": 0.6667, "pass": true },
    "realizedPnlSolAfterFees": { "required": 1, "actual": 2.416973, "pass": true },
    "closedPositions": { "required": 5, "actual": 6, "pass": true }
  },
  "topWins": { "sol": [{ "mint": "CX437jnJpHhQEscuf9fB1bbX73mRh7afoEcm84Uypump", "realizedPnl": 1.062163617 }], "usd": [] },
  "topLosses": { "sol": [{ "mint": "BLoBoDntf68U172TpR5z1jRWCSww3eTHE9JU7VeUpump", "realizedPnl": -0.638908892 }], "usd": [] },
  "mostTradedTokens": [{ "mint": "CX437jnJpHhQEscuf9fB1bbX73mRh7afoEcm84Uypump", "trades": 3, "buys": 1, "sells": 2, "volumeSol": 5.076854977, "volumeUsd": 0 }],
  "unrealizedPriceSource": "last_observed_wallet_swap",
  "pnlMethod": "average_cost",
  "tokens": [
    {
      "mint": "BLoBoDntf68U172TpR5z1jRWCSww3eTHE9JU7VeUpump",
      "trades": 2, "buys": 1, "sells": 1, "remainingQty": 0, "unknownCostBasisQty": 0,
      "sol": { "spent": 2.038381386, "received": 1.399472494, "matchedQty": 46958769.19543, "realizedPnl": -0.638908892, "remainingQty": 0, "lastPrice": 2.980215449e-8, "unrealizedPnl": 0 },
      "usd": null
    }
  ],
  "diagnostics": {
    "signaturesScanned": 51, "transactionsFetched": 50, "failedTxSkipped": 0, "nullTransactions": 0,
    "swapsClassified": 13, "tokenToTokenSwaps": 0, "quoteToQuoteSwaps": 0,
    "unclassified": { "no_wallet_balance_change": 35, "transfer_or_single_sided": 2 },
    "rpcCalls": 76, "rpcRetries": 0, "batchMode": "supported", "durationMs": 116950
  }
}
```

`status` values: `ok`, `no_swaps` (activity but no classified swap), `no_activity` (no signatures in the window), `invalid_input`, `error` (with `errorCode` and `errorMessage`).

The dataset has two views: **Overview** (wallet, status, realized/unrealized SOL PnL, win rate, trades, score, flag, first/last trade) and **Detail** (everything above). A `RUN_SUMMARY` record in the key-value store lists counts, wallets skipped because of the charge limit, and RPC statistics.

### Pricing

Pay per event: **$0.005 per profiled wallet** (`wallet-profiled`), plus Apify's standard actor-start event of $0.00005 (one per GB of memory; the default 256 MB run counts as one).

- Charged once per wallet with status `ok`, `no_swaps` or `no_activity`. The RPC work was done and the answer is valid.
- **Not charged:** invalid addresses, wallets that failed because of RPC errors, duplicates.
- The actor respects your *max total charge per run*: it stops before profiling a wallet it can't bill, and lists the skipped wallets in `RUN_SUMMARY`. The lowest max charge you can set is **$0.50**, which covers 100 wallets (the default `maxWallets`).
- Your RPC usage is billed by your RPC provider. Roughly: signatures pages + 1 `getTransaction` per transaction.

| Wallets profiled | Cost |
|---|---|
| 10 | $0.05 |
| 1,000 | $5.00 |
| 10,000 | $50.00 |

### FAQ

**Which RPC should I use?** Any standard Solana JSON-RPC endpoint: Helius, Triton, QuickNode, Alchemy, your own node. Free tiers work, just set `maxRequestsPerSecond` to what your plan allows. The public `api.mainnet-beta.solana.com` allows about 10 `getTransaction` calls per 10 seconds, so it's only good for a quick look (capped at 50 tx per wallet).

**Is my RPC key safe?** `rpcUrl` is a secret input, stored encrypted by Apify, and the actor only ever logs the host (`https://host/***`).

**Why is unrealized PnL sometimes 0 on an open position?** There's no external price API. Open positions are marked at the **last price this wallet itself paid or received** for the token in the analyzed data. If the last trade was the buy, unrealized PnL is 0 by construction. See Limitations.

**Why SOL and USD separately?** Converting between SOL and USD needs a historical SOL price, which pure on-chain data can't provide reliably. So SOL-quoted trades (SOL/wSOL) and stable-quoted trades (USDC/USDT, counted 1:1 as USD) run in separate ledgers, and both are reported.

**Does it detect bots?** Only lightly: the activity component halves above 200 trades/day. Bundlers and snipers can still score well, so look at `avgHoldingTimeSec` / `medianHoldingTimeSec` (seconds-long holds are a strong bot signal).

**Can I run it on a schedule or from code?** Yes. Use Apify Schedules for daily snapshots, or call the actor through the Apify API / client libraries and read the dataset. Webhooks can notify your system when a run finishes.

**Can an AI agent use it?** Yes. Every public Apify actor is reachable through Apify's MCP server (https://mcp.apify.com), so Claude, ChatGPT and other MCP clients can profile wallets directly.

**Does it trade or need my private key?** No. It is strictly read-only and only needs public wallet addresses.

**Does it work with Pump.fun?** Yes. Bonding-curve and PumpSwap trades are plain balance changes, so they're picked up like any other swap; no special casing.

### How PnL is calculated (average cost)

Each mint has two cost pools: SOL-quoted and USD-quoted (USDC/USDT 1:1).

- **Buy:** adds the quantity and its cost to the pool of its quote ledger, and updates the pool's quantity-weighted average acquisition time.
- **Sell:** draws from the pool of its own ledger at average cost. Realized PnL = proceeds for that quantity − its average cost.
  - If that pool runs out, the rest is drawn from the other ledger's pool. The quantity leaves the position, but no PnL is computed because the units differ (`crossLedgerQty`).
  - Anything still left has an **unknown cost basis**. It's reported as `unknownCostBasisQty`, and its proceeds as `unmatchedProceeds`; it never inflates PnL.
- **Unrealized:** remaining quantity × the last swap price seen for that mint in that ledger, minus the remaining cost.
- **Order:** transactions are processed oldest first. Same-slot trades keep their on-chain order (signatures arrive newest first and are reversed), so a buy and a sell in the same slot match correctly.
- **Dust:** quantities are floats derived from integer on-chain amounts. Leftovers below half of the token's smallest unit (`0.5 × 10^-decimals`) are treated as zero, so fully sold positions don't linger.
- **Fees:** `swapFeesSol` sums network fees on classified swaps. `stableSwapSolOverheadSol` sums SOL the wallet *spent* next to stable-quoted swaps (tips); SOL a relayer puts into the wallet is ignored. `realizedPnlSolAfterFees = realizedPnlSol − swapFeesSol − stableSwapSolOverheadSol`.
- A **trade** is one classified swap.
- **Win rate** = closed positions with realized PnL > 0 / closed positions. A closed position is a (mint, ledger) pair with at least one sell matched against a known cost basis, whether fully or partially sold.
- **Holding time:** one sample per sell = sell time − the pool's quantity-weighted average acquisition time, which is the average-cost analogue of lot age. `avgHoldingTimeSec` and `medianHoldingTimeSec` summarize these samples.

### Smart-money score (0–100)

`score = 100 × (0.35·W + 0.30·P + 0.15·A + 0.20·C)`. Every component is in \[0, 1] and is reported with its inputs:

| Component | Formula | Why |
|---|---|---|
| W, win rate | `(wins + 1) / (closed + 2)` | Laplace-smoothed, so 1/1 doesn't count as 100%. |
| P, realized PnL | `max(0, pnl) / (max(0, pnl) + 10)`, with `pnl = realizedPnlSolAfterFees` | Saturating: 10 SOL gives 0.5, 90 SOL gives 0.9. Losses give 0. |
| A, activity sanity | `min(closed / 10, 1) × (tradesPerDay > 200 ? 0.5 : 1)` | Needs a sample size; damps obvious high-frequency bots. |
| C, consistency | `1 − largestWinSol / grossWinsSol` if ≥ 2 winning SOL positions, else 0 | Penalizes one lucky trade. |

`smartMoney` is `true` only if win rate ≥ `minWinRate`, `realizedPnlSolAfterFees` ≥ `minRealizedPnlSol` **and** closed positions ≥ `minClosedPositions`. Each check is reported in `smartMoneyCriteria`.

### Limitations (please read)

- **Unrealized PnL is not a market price.** It uses the last swap price observed in the wallet's own trades within the fetched data (`unrealizedPriceSource: "last_observed_wallet_swap"`). A token that has since gone to zero, or 10×'d, isn't reflected.
- **SOL-denominated.** USD-quoted PnL is reported separately and never converted. If a token is bought with USDC and sold for SOL, the quantity is closed out but no PnL is computed for that part (`crossLedgerQty`).
- **Transfers break cost basis.** Tokens that arrive by transfer, airdrop or before the window have no known cost. Sells of them only realize PnL on the quantity bought inside the window; the rest is `unknownCostBasisQty`. Tokens sent away stay "open" at their cost.
- **Fees inside the swap transaction count as trade cost.** Tips, bot/platform fees and priority transfers paid in the same transaction are part of the price paid or received. This is right for PnL, but it can make the per-trade `price` (and therefore the unrealized mark) look off for tiny trades with large fees. Network fees (`meta.fee`) are tracked separately in `swapFeesSol`.
- **Token-to-token swaps** (no SOL or stablecoin leg) are recorded (`tokenToTokenSwaps`, and in `tokenToTokenSwapList` with `includeTrades`) but excluded from PnL.
- **Not swaps:** pure transfers, LP adds/removes, a token leaving while SOL also leaves (e.g. a tip bigger than the proceeds), and single-transaction arbitrage round trips. These are counted under `diagnostics.unclassified` by reason.
- **History depth.** Results cover at most `maxTransactionsPerWallet` of the newest successful transactions in the window. `truncated: true` tells you there was more. Signature scanning stops after 30 pages (30,000 signatures).
- **Public RPC is slow and rate-limited**, measured at about 2.2–2.3 s per transaction including backoff. Bring your own RPC for real work.
- **Relayed / gasless transactions** (e.g. Jupiter Ultra) are handled: the wallet doesn't need to be the fee payer. Rent a relayer pays into the wallet's new token accounts appears as a small `unattributedSolDelta` on stable-quoted trades.
- **Only transactions that reference the wallet address** are returned by `getSignaturesForAddress`. Tokens pushed to the wallet's token accounts without the wallet itself in the transaction are not seen. These are transfers anyway and don't affect swap detection.

### Disclaimer

Results are computed from public on-chain data and are provided for research and information only. They are not financial or investment advice, and past performance of a wallet says nothing certain about future results.

### Support

Found a wallet where the numbers look wrong? Open an issue on the actor's **Issues** tab with the wallet address and the time window, and attach the `diagnostics` object from the result. Maintained by **northbit**.

# Changelog

This Actor's version history is a separate document: https://apify.com/metallic_pastry/solana-wallet-pnl-profiler/changelog.md

# Actor input Schema

## `wallets` (type: `array`):

Solana wallet addresses (base58 public keys) to profile. Duplicates are removed. Invalid addresses produce an error item and are not charged.

## `rpcUrl` (type: `string`):

Standard Solana JSON-RPC endpoint (HTTPS). Strongly recommended: your own Helius, Triton or QuickNode URL. Provider URLs usually embed an API key, so this field is stored encrypted. If left empty, the public endpoint https://api.mainnet-beta.solana.com is used; it allows roughly 1 getTransaction per second and is only suitable for a few wallets.

## `lookbackDays` (type: `integer`):

Analyze transactions from the last N days. Ignored when a start date is set.

## `startDate` (type: `string`):

Window start (UTC, inclusive). Overrides the lookback when set.

## `endDate` (type: `string`):

Window end (UTC, inclusive end of day). Defaults to now.

## `maxTransactionsPerWallet` (type: `integer`):

Cap on successful transactions fetched per wallet (newest first). If a wallet has more inside the window, its result is marked truncated: true. When the public RPC endpoint is used this is limited to 50.

## `maxRequestsPerSecond` (type: `number`):

Upper bound for request rate (each call inside a JSON-RPC batch counts as one). The actor slows down automatically when the endpoint rate limits. Keep about 5 for the public endpoint; paid plans can go much higher.

## `concurrency` (type: `integer`):

Maximum number of HTTP requests in flight at the same time.

## `useBatchRequests` (type: `boolean`):

Send getTransaction calls in JSON-RPC batches. If the endpoint rejects batches, the actor falls back to single requests automatically.

## `requestTimeoutSecs` (type: `integer`):

Timeout for one HTTP request to the RPC endpoint.

## `maxRetries` (type: `integer`):

Retries for HTTP 429/5xx, timeouts and JSON-RPC rate-limit errors (exponential backoff with jitter, Retry-After honored). A wallet whose data cannot be fetched after retries returns an error item and is not charged.

## `maxWallets` (type: `integer`):

Safety limit. Wallets beyond this number (after de-duplication) are not processed.

## `minWinRate` (type: `number`):

smartMoney is true only if the wallet's win rate (winning closed positions / closed positions) is at least this value (0-1).

## `minRealizedPnlSol` (type: `number`):

smartMoney requires realized SOL PnL after network fees of at least this amount.

## `minClosedPositions` (type: `integer`):

smartMoney requires at least this many closed (fully or partially sold) positions.

## `includeTokenBreakdown` (type: `boolean`):

Add a tokens\[] array with per-token PnL ledgers (SOL- and USD-quoted).

## `includeTrades` (type: `boolean`):

Add tradeList\[] (every classified swap) and tokenToTokenSwapList\[] to each item. Makes items much larger.

## Actor input object example

```json
{
  "wallets": [
    "FEdz1g8HfaAUSoJbSB1sXfcweh3qzye4XJAmaafUmA96",
    "HHEF5WjjKnM9xAxdMjEH2mNFBHSfUtxq79dkZXVCJ7fM"
  ],
  "lookbackDays": 30,
  "maxTransactionsPerWallet": 500,
  "maxRequestsPerSecond": 5,
  "concurrency": 3,
  "useBatchRequests": true,
  "requestTimeoutSecs": 30,
  "maxRetries": 6,
  "maxWallets": 100,
  "minWinRate": 0.55,
  "minRealizedPnlSol": 1,
  "minClosedPositions": 5,
  "includeTokenBreakdown": true,
  "includeTrades": false
}
```

# Actor output Schema

## `overview` (type: `string`):

Default dataset, Overview view: PnL, win rate, holding time and smart-money score per wallet.

## `detail` (type: `string`):

Default dataset, Detail view: all fields including per-token breakdown and top wins/losses.

## `runSummary` (type: `string`):

RUN_SUMMARY record in the default key-value store: profiled, charged, invalid and failed counts and RPC request stats.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "wallets": [
        "FEdz1g8HfaAUSoJbSB1sXfcweh3qzye4XJAmaafUmA96",
        "HHEF5WjjKnM9xAxdMjEH2mNFBHSfUtxq79dkZXVCJ7fM"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("metallic_pastry/solana-wallet-pnl-profiler").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "wallets": [
        "FEdz1g8HfaAUSoJbSB1sXfcweh3qzye4XJAmaafUmA96",
        "HHEF5WjjKnM9xAxdMjEH2mNFBHSfUtxq79dkZXVCJ7fM",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("metallic_pastry/solana-wallet-pnl-profiler").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "wallets": [
    "FEdz1g8HfaAUSoJbSB1sXfcweh3qzye4XJAmaafUmA96",
    "HHEF5WjjKnM9xAxdMjEH2mNFBHSfUtxq79dkZXVCJ7fM"
  ]
}' |
apify call metallic_pastry/solana-wallet-pnl-profiler --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,metallic_pastry/solana-wallet-pnl-profiler"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hBJHso69vcTWIGXGz/builds/y90OULqgEjtRyUhBS/openapi.json
