# 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](/api/rest-api/python-examples/setup-and-helpers.md) 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](/api/rest-api/websockets/account-and-history-streams/last-trades-feed.md)
* [Place Market Order](/api/rest-api/private-endpoints/orders/place-market-order.md)
* [Search Events](/api/rest-api/public-endpoints/search-events.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.outpoll.com/api/rest-api/python-examples/copy-large-trades.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
