# Copy Large Trades

Use this script to mirror larger trades from the public feed.

### What this script does

* listens to the public last trades feed
* filters trades above `$1,000`
* resolves the matching runner
* copies each qualifying trade with `5%` of free USDC balance

Start with [Setup & Helpers](https://docs.outpoll.com/api/rest-api/python-examples/setup-and-helpers) if you still need the shared prerequisites.

{% code title="copy\_large\_trades.py" %}

```python
#!/usr/bin/env python3
"""Copy trades > $1000 from the public feed, each trade = 5% of initial balance."""
import asyncio, json, requests, websockets
import hmac, hashlib, base64, time

API_KEY = "op_k_your_api_key"
API_SECRET = "your_api_secret"
USDC_ID = "078dcd98-928d-479f-8110-ff6d27e44de2"
MIN_TRADE_VALUE = 1000   # only copy trades > $1000
TRADE_FRACTION = 0.05    # 5% of balance per trade

SERVICE_MAP = {
    "/api/events":      "https://event-service.outpoll.com",
    "/api/user-balances": "https://wallet-mutator-view.outpoll.com",
    "/api/history":     "https://history-service.outpoll.com",
    "/orders":          "https://order-service.outpoll.com",
}

class OutpollClient:
    def __init__(self, api_key, api_secret):
        self.api_key = api_key
        self.api_secret = api_secret

    def _host(self, path):
        for prefix, host in SERVICE_MAP.items():
            if path.startswith(prefix):
                return host
        return "https://event-service.outpoll.com"

    def _sign(self, method, path, body=""):
        timestamp = str(int(time.time()))
        message = timestamp + method + path + body
        padded = self.api_secret + "=" * (4 - len(self.api_secret) % 4) if len(self.api_secret) % 4 else self.api_secret
        secret_bytes = base64.urlsafe_b64decode(padded)
        signature = base64.urlsafe_b64encode(
            hmac.new(secret_bytes, message.encode(), hashlib.sha256).digest()
        ).decode().rstrip("=")
        return {
            "OUTPOLL-API-KEY": self.api_key,
            "OUTPOLL-API-SIGNATURE": signature,
            "OUTPOLL-API-TIMESTAMP": timestamp,
            "Content-Type": "application/json",
        }

    def post(self, path, data=None):
        body = json.dumps(data) if data else ""
        headers = self._sign("POST", path, body)
        return requests.post(self._host(path) + path, headers=headers, data=body)


def ws_auth_msg(path):
    timestamp = str(int(time.time()))
    message = timestamp + "GET" + path
    s = API_SECRET
    s += "=" * (4 - len(s) % 4) if len(s) % 4 else ""
    secret_bytes = base64.urlsafe_b64decode(s)
    signature = base64.urlsafe_b64encode(
        hmac.new(secret_bytes, message.encode(), hashlib.sha256).digest()
    ).decode().rstrip("=")
    return {"t": "AUTH", "d": {"apiKey": API_KEY, "signature": signature, "timestamp": timestamp}}


async def run():
    client = OutpollClient(API_KEY, API_SECRET)

    # Step 1 — Get USDC balance
    print("Fetching USDC balance...")
    async with websockets.connect("wss://wallet-mutator-view.outpoll.com/balance/ws") as ws:
        await ws.send(json.dumps(ws_auth_msg("/balance/ws")))
        msg = json.loads(await asyncio.wait_for(ws.recv(), timeout=10))
        usdc_balance = 0.0
        if msg.get("t") == "success":
            for b in msg["d"]["l"]:
                if b["i"] == USDC_ID:
                    usdc_balance = b["f"]
                    break

    spend_per_trade = round(usdc_balance * TRADE_FRACTION, 2)
    print(f"USDC free: ${usdc_balance:.2f}")
    print(f"Per trade: ${spend_per_trade:.2f} (5%)")

    if spend_per_trade < 1:
        print("Insufficient balance. Exiting.")
        return

    # Step 2 — We need runner info per event. Cache event data.
    event_cache = {}

    def get_event_info(event_id):
        if event_id not in event_cache:
            resp = requests.post(
                "https://event-service.outpoll.com/api/events/search",
                params={"page": 0, "size": 50},
                json={"sb": "VOLUME_24H", "sd": "DESC", "l": "en"},
            )
            for ev in resp.json()["content"]:
                event_cache[ev["i"]] = ev
        return event_cache.get(event_id)

    # Step 3 — Watch last trades, copy big ones
    print(f"\nWatching last trades (min ${MIN_TRADE_VALUE})...\n")
    trade_count = 0
    async with websockets.connect("wss://history-service.outpoll.com/last-trades/ws") as ws:
        async for raw in ws:
            data = json.loads(raw)

            # Skip heartbeats
            if data.get("t") == "PING":
                continue

            # Trade value = quantity × price
            qty = data.get("q", 0)
            price = data.get("p", 0)
            value = qty * price

            if value < MIN_TRADE_VALUE:
                continue

            side = data.get("s", "BUY")
            event_id = data.get("e", "")
            outcome_id = data.get("o", "")

            print(f"Whale trade: {side} {qty} @ ${price:.2f} = ${value:.2f}")

            # Look up event to find runner IDs
            event_info = get_event_info(event_id)
            if not event_info:
                print(f"  Event {event_id[:8]}... not found, skipping\n")
                continue

            # Find the matching market and runner
            runner_id = None
            for mkt in event_info.get("ma", []):
                for runner in mkt["r"]:
                    if runner["o"] == outcome_id or mkt["i"] == outcome_id:
                        if runner["ip"]:
                            runner_id = runner["i"]
                            break

            if not runner_id:
                print(f"  Runner not found, skipping\n")
                continue

            # Copy the trade
            order = client.post("/orders/market", {
                "e": event_id,
                "o": outcome_id,
                "ba": runner_id,
                "qa": USDC_ID,
                "s": side,
                "am": spend_per_trade,
            })
            trade_count += 1
            print(f"  Copied #{trade_count}: {order.json()}\n")


asyncio.run(run())
```

{% endcode %}

### Related pages

* [Last Trades Feed](https://docs.outpoll.com/api/rest-api/websockets/account-and-history-streams/last-trades-feed)
* [Place Market Order](https://docs.outpoll.com/api/rest-api/private-endpoints/orders/place-market-order)
* [Search Events](https://docs.outpoll.com/api/rest-api/public-endpoints/search-events)
