Ingesting Logs from Bybit

Stream real-time order fills, position updates, and wallet events from Bybit into your BunnyLogs stream via a small Python relay — no public server required.

Two ways to connect

Hosted bot (recommended) — go to Settings, click Connect Bybit, and paste your API key and secret. BunnyLogs opens and maintains the WebSocket connection on your behalf. Nothing to run locally.

Self-hosted relay — run the Python script below on any machine that already has your trading bot. Credentials stay on your own infrastructure. Follow the steps below.


Self-hosted relay — how it works

Bybit exposes real-time account data through a private WebSocket channel. The relay script connects to that channel using your API key, listens for events, and forwards each one to BunnyLogs as a log entry. The script runs anywhere Python runs — your laptop, a VPS, or alongside your trading bot.

Step 1 — Create a read-only API key

Log in to bybit.com, open the user menu in the top-right corner, and go to API Management.

Click Create New Key and choose System-generated API Keys. Give it a name (e.g. bunnylogs-relay) and set the following permissions — everything else can stay off:

CategoryPermissionSet to
OrderRead✓ On
PositionRead✓ On
AccountRead✓ On
Tradeall✗ Off
Withdrawalall✗ Off

Complete the 2FA verification. Bybit shows your API Key and Secret Key — copy both immediately. The secret is shown only once.

Step 2 — Install dependencies
pip install pybit requests
Step 3 — Run the relay

Save the script below and run it. Set the four variables at the top:

import json
import requests
from pybit.unified_trading import WebSocket

BYBIT_API_KEY    = "<your-api-key>"
BYBIT_API_SECRET = "<your-api-secret>"
BUNNYLOGS_UUID   = "<your-uuid>"
PROGRAM          = "bybit"

BUNNYLOGS_URL = f"https://bunnylogs.com/live/{BUNNYLOGS_UUID}"


def ship(message, level="INFO"):
    try:
        requests.post(
            BUNNYLOGS_URL,
            data={"message": message, "level": level, "program": PROGRAM},
            timeout=5,
        )
    except Exception:
        pass  # never let a failed POST crash the relay


def handle_order(msg):
    for order in msg.get("data", []):
        symbol = order.get("symbol", "?")
        side   = order.get("side", "?")
        qty    = order.get("qty", "?")
        price  = order.get("avgPrice") or order.get("price", "?")
        status = order.get("orderStatus", "?")
        level  = "ERROR" if status in ("Cancelled", "Rejected") else "INFO"
        ship(f"Order {status}: {side} {qty} {symbol} @ {price}", level)


def handle_position(msg):
    for pos in msg.get("data", []):
        symbol = pos.get("symbol", "?")
        side   = pos.get("side", "?")
        size   = pos.get("size", "?")
        pnl    = pos.get("unrealisedPnl", "?")
        ship(f"Position update: {side} {size} {symbol}  unrealised PnL={pnl}")


def handle_wallet(msg):
    for coin in msg.get("data", [{}]):
        for balance in coin.get("coin", []):
            name  = balance.get("coin", "?")
            total = balance.get("walletBalance", "?")
            ship(f"Wallet update: {name} balance={total}")


ws = WebSocket(
    testnet=False,
    api_key=BYBIT_API_KEY,
    api_secret=BYBIT_API_SECRET,
    channel_type="private",
)

ws.order_stream(callback=handle_order)
ws.position_stream(callback=handle_position)
ws.wallet_stream(callback=handle_wallet)

print(f"Relay running — streaming Bybit events to BunnyLogs ({BUNNYLOGS_UUID})")
print("Press Ctrl+C to stop.")

import time
try:
    while True:
        time.sleep(1)
except KeyboardInterrupt:
    print("Stopped.")
What you'll see in BunnyLogs

Once the relay is running and you place or fill an order, entries appear in your stream immediately:

INFO   bybit   Order Filled: Buy 0.01 BTCUSDT @ 67420.5
INFO   bybit   Position update: Buy 0.01 BTCUSDT  unrealised PnL=1.23
INFO   bybit   Wallet update: USDT balance=1243.87
ERROR  bybit   Order Rejected: Sell 0.05 ETHUSDT @ 3210.0
Available topics
Stream methodFires when
ws.order_stream()An order is created, filled, partially filled, cancelled, or rejected
ws.position_stream()A position opens, changes size, or closes
ws.wallet_stream()Account balance changes (deposit, withdrawal, trade settlement)
ws.execution_stream()Individual trade executions (every fill tick)
Running as a background service

To keep the relay running continuously on a Linux server, create a systemd unit:

# /etc/systemd/system/bybit-relay.service
[Unit]
Description=Bybit → BunnyLogs relay
After=network.target

[Service]
ExecStart=/usr/bin/python3 /opt/bybit-relay/relay.py
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
systemctl enable --now bybit-relay
Notes
  • The API key needs only read permissions — it cannot place or cancel orders.
  • pybit handles WebSocket reconnection automatically; the relay recovers from dropped connections without restarting.
  • The ship() function swallows HTTP errors so a temporary BunnyLogs outage never crashes the relay.
  • Set testnet=True in the WebSocket constructor to test against Bybit Testnet before going live.
  • Set up an Alert in BunnyLogs matching level=ERROR and program=bybit to get notified on rejected or cancelled orders via Slack, Telegram, or Discord.