> For the complete documentation index, see [llms.txt](https://docs.outpoll.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.outpoll.com/api/rest-api/python-examples/copy-large-trades.md).

# Copy Large Trades

Listen to the public trade feed and copy trades above a chosen value threshold

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
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
