> ## Documentation Index
> Fetch the complete documentation index at: https://docs.predexon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Backtesting Predexon signals

> Validate smart-money, top-holders, and pending-trade signals against historical trades and orderbook state before going live.

Predexon ships several derived signals out of the box — smart-money flow, top-holders, pending-trade detection. The honest question before you build a strategy around any of them is: **did this signal actually predict anything historically?** This page walks the workflow for answering that.

The pattern is the same for every signal:

1. Pull the signal's historical state at decision time `t`.
2. Pull the price/orderbook state at `t + horizon` from market data.
3. Compute realized PnL if you had acted on the signal at `t`.

***

## Signal 1 — smart-money flow

[`GET /v2/polymarket/market/{condition_id}/smart-money`](/api-reference/smart-money/smart-money-market) tells you whether profitable wallets are net buyers or sellers in a market over a window. The natural backtest: **does smart-money net-buying predict price up over the next N hours?**

The smart-money endpoint reflects current state, not historical state. To backtest, you reconstruct the signal from raw trade data:

```python theme={null}
import requests
from datetime import datetime, timezone

BASE = "https://api.predexon.com"
HEADERS = {"x-api-key": "YOUR_API_KEY"}

def smart_wallets():
    # Top-100 wallets by realized profit
    return requests.get(
        f"{BASE}/v2/polymarket/leaderboard",
        headers=HEADERS,
        params={"sort_by": "realized_profit", "limit": 100},
    ).json()

def smart_net_flow(token_id, start_sec, end_sec, wallet_set):
    trades = requests.get(
        f"{BASE}/v2/polymarket/trades",
        headers=HEADERS,
        params={
            "token_id": token_id,
            "start_time": start_sec,
            "end_time": end_sec,
            "limit": 1000,
        },
    ).json()
    net = 0.0
    for t in trades:
        if t["maker"] not in wallet_set and t["taker"] not in wallet_set:
            continue
        size = float(t["size"])
        net += size if t["side"] == "BUY" else -size
    return net
```

Then for each decision time:

```python theme={null}
import pandas as pd

smart = {w["wallet"] for w in smart_wallets()["wallets"]}

results = []
for t0 in decision_times:                  # e.g. every hour
    pre  = smart_net_flow(TOKEN, t0 - 3600, t0, smart)   # last hour
    p_t0 = price_at(TOKEN, t0)
    p_t1 = price_at(TOKEN, t0 + 14400)     # 4h horizon
    results.append({"t": t0, "flow": pre, "ret": p_t1 - p_t0})

df = pd.DataFrame(results)
print(df.groupby(pd.qcut(df["flow"], 5))["ret"].mean())
```

A monotonic relationship between flow quintile and forward return is the signal you're hoping to see. Flat means the signal isn't predictive at that horizon.

***

## Signal 2 — top-holders concentration

[`GET /v2/polymarket/markets/{condition_id}/top-holders`](/api-reference/analytics/top-holders) shows position concentration. The hypothesis: **when one side is held by a few large wallets, it's vulnerable to a flush.**

Reconstruct from snapshots of positions over time:

* For each `condition_id` in your universe, sample top-holders periodically (e.g. daily).
* Compute a concentration metric (HHI, top-5 share, etc.).
* Pair with the same-day [orderbook](/data-signals/backtesting/orderbook-replay) snapshot to know what depth was sitting against that concentration.
* Look at forward price moves over a 1d / 1w horizon, bucketed by concentration.

This is a slow signal — daily decisions, weekly horizons — so candle data plus periodic snapshots are usually enough. No need for tick-by-tick orderbook replay.

***

## Signal 3 — pending-trade leading indicator

The [pending-trades WebSocket](/websocket/pending-trades) detects fills from the Polygon mempool 3–5 seconds before confirmation. The backtest question: **does the pending side predict the next confirmed-trade direction tight enough to act on?**

Pending events are real-time only — there's no historical replay endpoint for them. To backtest, you have two options:

1. **Run a recorder for a week.** Connect to the pending-trades channel and dump every event to disk. Then pair against the confirmed [trades endpoint](/api-reference/trading/trades) for the same window. Compute hit rate, average lead time, and PnL under realistic latency assumptions.
2. **Proxy with confirmed trades + book delta.** For each confirmed trade, look at the orderbook snapshot \~3 seconds before. Did the best bid/ask shift in the direction of the trade? Use that as a proxy for what pending-trade detection would have told you.

The recorder approach is more honest. Plan on a week of paper-collection before you trust the signal enough to size into it.

***

## What to actually measure

Three numbers matter more than total PnL:

| Metric                  | Why                                                                                                                                                                                                    |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Hit rate by horizon** | Does the signal predict at 5min, 1h, 4h, 1d? Often the edge only exists in one band.                                                                                                                   |
| **Slippage realism**    | After paying spread + walking the book for your size (see [orderbook replay](/data-signals/backtesting/orderbook-replay)), does the PnL survive?                                                       |
| **Capacity**            | What's the max position size before the signal's edge equals your market impact? Reconcile against [trade-tape](/data-signals/backtesting/candle-trade-reconciliation) volume to answer this honestly. |

A signal with a 55% hit rate that survives realistic slippage at $10k/trade is more valuable than a 70% hit rate that collapses at $1k.

***

## Going live with the same code

If the backtest holds up, the live version connects to:

* [WebSocket trades](/websocket/trades) and [activity](/websocket/activity) for real-time flow
* [WebSocket pending-trades](/websocket/pending-trades) for the mempool edge
* [Place Order](/trading-api/accounts/place-order) for execution when your signal fires

The data shapes are the same in REST and WebSocket, so your decision function should rarely need to change.
