Skip to content

feat: upgrade margin socket to use websocket api#1670

Merged
carlosmiei merged 1 commit intosammchardy:masterfrom
pcriadoperez:margin-ws-update
Feb 13, 2026
Merged

feat: upgrade margin socket to use websocket api#1670
carlosmiei merged 1 commit intosammchardy:masterfrom
pcriadoperez:margin-ws-update

Conversation

@pcriadoperez
Copy link
Collaborator

@pcriadoperez pcriadoperez commented Feb 8, 2026

Fix #1668

  • Upgrade margin socket
  • Add deprecation warnings of old endpoints

Note: awaiting key to perform testing, don't merge yet.

@pcriadoperez pcriadoperez self-assigned this Feb 8, 2026
@pcriadoperez pcriadoperez marked this pull request as ready for review February 13, 2026 02:39
@pcriadoperez
Copy link
Collaborator Author

Test ran

""Test: place a tiny margin order on ETH/USDT and confirm the event arrives on the margin WebSocket.

Set environment variables:
- BINANCE_API_KEY
- BINANCE_API_SECRET
"""
import asyncio
import os

from binance.async_client import AsyncClient
from binance.ws.streams import BinanceSocketManager


async def main():
    api_key = os.getenv(
        "BINANCE_API_KEY",
        "",
    )
    api_secret = os.getenv(
        "BINANCE_API_SECRET",
        "",
    )

    client = await AsyncClient.create(api_key=api_key, api_secret=api_secret)
    bm = BinanceSocketManager(client)

    # --- 0. Show margin account balances ---
    print("Fetching margin account balances ...")
    margin_account = await client.get_margin_account()
    print(f"  Margin level: {margin_account.get('marginLevel', '?')}")
    print(f"  Total asset (BTC): {margin_account.get('totalAssetOfBtc', '?')}")
    print(f"  Total liability (BTC): {margin_account.get('totalLiabilityOfBtc', '?')}")
    for asset in margin_account.get("userAssets", []):
        free = float(asset["free"])
        locked = float(asset["locked"])
        borrowed = float(asset["borrowed"])
        if free > 0 or locked > 0 or borrowed > 0:
            print(f"  {asset['asset']:>6s}  free={asset['free']}  locked={asset['locked']}  borrowed={asset['borrowed']}")
    print()

    # --- 1. Connect margin websocket ---
    print("Connecting margin websocket ...")
    margin_ws = bm.margin_socket()
    await margin_ws.connect()
    print(f"  connected  (subscription_id={margin_ws._subscription_id})")

    # --- 2. Place a small LIMIT BUY far below market so it won't fill ---
    symbol = "ETHUSDT"
    # Ensure notional > $10.  0.007 ETH * 1500 = $10.50
    # Price well below market to avoid a fill.
    quantity = "0.007"
    price = "1500.00"

    print(f"Placing limit buy: {quantity} {symbol} @ {price} ...")
    order = await client.create_margin_order(
        symbol=symbol,
        side="BUY",
        type="LIMIT",
        timeInForce="GTC",
        quantity=quantity,
        price=price,
        sideEffectType="MARGIN_BUY",
    )
    order_id = order["orderId"]
    print(f"  order placed  (orderId={order_id})")

    # --- 3. Wait for the executionReport event on the websocket ---
    print("Waiting for margin websocket event ...")
    try:
        msg = await asyncio.wait_for(margin_ws.recv(), timeout=10)
        print(f"  received event: {msg.get('e', '?')}  status={msg.get('X', '?')}")
        print(f"  full payload:\n  {msg}")
    except asyncio.TimeoutError:
        print("  TIMEOUT: no event received within 10 s")

    # --- 4. Cancel the order ---
    print(f"Cancelling order {order_id} ...")
    await client.cancel_margin_order(symbol=symbol, orderId=order_id)
    print("  cancelled")

    # Try to catch the cancel event too
    try:
        msg = await asyncio.wait_for(margin_ws.recv(), timeout=10)
        print(f"  cancel event: {msg.get('e', '?')}  status={msg.get('X', '?')}")
    except asyncio.TimeoutError:
        print("  no cancel event received (timeout)")

    # --- 5. Clean up ---
    await margin_ws.__aexit__(None, None, None)
    await client.close_connection()
    print("Done.")


if __name__ == "__main__":
    asyncio.run(main())

Result

  Margin level: 999
  Total asset (BTC): 0.00076733
  Total liability (BTC): 0
     SOL  free=0.000832  locked=0  borrowed=0
    USDT  free=1.64539391  locked=48.57252  borrowed=0

Connecting margin websocket ...
  connected  (subscription_id=0)
Placing limit buy: 0.007 ETHUSDT @ 1500.00 ...
  order placed  (orderId=43509602069)
Waiting for margin websocket event ...
  received event: balanceUpdate  status=?
  full payload:
  {'e': 'balanceUpdate', 'E': 1770928545675, 'a': 'USDT', 'd': '8.85460609', 'T': 1770928545675}
Cancelling order 43509602069 ...
  cancelled
  cancel event: outboundAccountPosition  status=?

@carlosmiei carlosmiei merged commit bbf04cd into sammchardy:master Feb 13, 2026
2 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Margin Data Stream using ListenKey will be deprecated on 2026-02-20 07:00 UTC:

2 participants