Skip to main content

REST API manager for Binance API. Manages weights and credentials simply and securely.

Project description

Panzer

Python library for managing Binance REST API connections with automatic rate limiting and secure credential management.

Features

  • Multi-market support: Spot, USDT-M Futures, COIN-M Futures.
  • Automatic rate limiting: Fixed-window limiter synchronized with Binance's X-MBX-USED-WEIGHT-1M header. Sleeps before hitting limits instead of getting banned.
  • Signed requests: HMAC-SHA256 signing for authenticated endpoints (orders, account, trades). Supports GET, POST and DELETE.
  • Secure credential storage: AES-128-CBC encryption tied to the machine identity. Credentials are stored encrypted on disk (~/.panzer_creds) and decrypted only in memory when needed.
  • Dynamic weight calculation: Endpoint weights loaded from weights.py and adjusted by parameters (e.g., depth limit, klines limit).
  • Clock synchronization: Estimates server time offset via /time endpoint samples.
  • Centralized error handling: BinanceAPIException with parsed error codes and messages.
  • Rotating file logs: One log file per module in logs/, with configurable rotation.

Installation

pip install panzer

Or from source:

git clone https://github.com/nand0san/panzer.git
cd panzer
pip install -e .

Requires Python >= 3.11. Runtime dependencies: requests, pycryptodome.

Quick Start — Public Endpoints

from panzer import BinancePublicClient

# Create a client (loads rate limits and syncs clock automatically)
client = BinancePublicClient(market="spot", safety_ratio=0.9)

# Public endpoints — weights are calculated automatically
klines = client.klines("BTCUSDT", "1m", limit=500)
trades = client.trades("BTCUSDT", limit=100)
book   = client.depth("BTCUSDT", limit=100)
info   = client.exchange_info()

Supported Markets

spot = BinancePublicClient(market="spot")    # https://api.binance.com
um   = BinancePublicClient(market="um")      # https://fapi.binance.com
cm   = BinancePublicClient(market="cm")      # https://dapi.binance.com

Quick Start — Authenticated Endpoints

BinanceClient extends BinancePublicClient with signed request support. It manages API keys securely through CredentialManager.

from panzer import BinanceClient

# First run: prompts for api_key and api_secret, encrypts and stores them
# in ~/.panzer_creds. Subsequent runs load them automatically.
client = BinanceClient(market="spot")

# Account info
account = client.account()
print(account["balances"][:3])

# Place an order
order = client.new_order(
    symbol="BTCUSDT",
    side="BUY",
    order_type="LIMIT",
    quantity=0.001,
    price=50000,
    time_in_force="GTC",
)

# Query trades, open orders, cancel
my_trades   = client.my_trades("BTCUSDT", limit=10)
open_orders = client.open_orders("BTCUSDT")
cancelled   = client.cancel_order("BTCUSDT", order_id=12345)
all_orders  = client.all_orders("BTCUSDT", limit=100)

Credential Management

Credentials follow a three-layer lookup: memory -> disk -> prompt.

from panzer import CredentialManager

cm = CredentialManager()   # uses ~/.panzer_creds by default

# Add credentials programmatically (auto-detects sensitive names)
cm.add("api_key", "your_key_here")       # encrypted on disk
cm.add("api_secret", "your_secret_here") # encrypted on disk
cm.add("market", "spot")                 # stored in plain text

# Retrieve
key = cm.get("api_key", decrypt=True)    # decrypted value

Sensitive names (api_key, api_secret, password, *_id) are automatically detected and encrypted with AES-128-CBC. The encryption key is derived from the machine identity (home directory + CPU info), so credentials can only be decrypted on the machine where they were created. No master password is needed.

The credential file ~/.panzer_creds looks like:

# Archivo de credenciales de Panzer
api_key = "U2FsdGVk..."
api_secret = "Y3J5cHRv..."
market = "spot"

Public Endpoints

All wrapper methods share timeout (seconds, default 10) and return parsed JSON.

Method Description Key parameters
ping() Test connectivity
server_time() Server time (also updates clock sync)
exchange_info(symbol=) Exchange metadata and rate limits symbol: optional filter
klines(symbol, interval) Candlestick data limit (default 500), start_time, end_time (ms)
trades(symbol) Recent trades limit (default 500)
agg_trades(symbol) Compressed/aggregate trades limit, from_id, start_time, end_time
depth(symbol) Order book limit (default 100; affects weight)

Bulk / Parallel Requests

Fetch data from multiple symbols simultaneously. Panzer pre-calculates weights, splits into batches that fit the rate limit window, and fires requests in parallel using a thread pool.

symbols = ["BTCUSDT", "ETHUSDT", "SOLUSDT", "XRPUSDT", "BNBUSDT"]

# All return dict[str, data] keyed by symbol
all_trades = client.bulk_trades(symbols, limit=500, max_workers=10)
all_klines = client.bulk_klines(symbols, "1h", limit=100, max_workers=10)
all_books  = client.bulk_depth(symbols, limit=100, max_workers=10)
all_agg    = client.bulk_agg_trades(symbols, limit=500, max_workers=10)

# Generic: mix different endpoints in one parallel call
results = client.parallel_get([
    ("/api/v3/trades", {"symbol": "BTCUSDT", "limit": 100}),
    ("/api/v3/klines", {"symbol": "ETHUSDT", "interval": "1h", "limit": 24}),
    ("/api/v3/depth",  {"symbol": "SOLUSDT", "limit": 20}),
], max_workers=5)
Method Description Weight per call
bulk_trades(symbols) Recent trades, N symbols 25
bulk_klines(symbols, interval) Candlesticks, N symbols 2
bulk_depth(symbols) Order books, N symbols 5-250
bulk_agg_trades(symbols) Aggregate trades, N symbols 4
parallel_get(jobs) Arbitrary mixed endpoints varies

Authenticated Endpoints

Available via BinanceClient. All require valid API credentials.

Method HTTP Description Key parameters
account() GET Account info (balances, permissions) recv_window
my_trades(symbol) GET Own trade history limit, from_id
new_order(symbol, side, order_type) POST Place an order quantity, price, time_in_force, **extra
cancel_order(symbol) DELETE Cancel an order order_id or orig_client_order_id
open_orders(symbol=) GET Current open orders symbol (optional)
all_orders(symbol) GET All orders (open + closed) limit, order_id

Using signed_request() for any authenticated endpoint

# Generic signed request for endpoints without a wrapper
data = client.signed_request(
    "GET",
    "/api/v3/myTrades",
    params=[("symbol", "BTCUSDT"), ("limit", 10)],
)

Using get() for any public endpoint

# Spot 24h ticker — no wrapper needed
ticker = client.get("/api/v3/ticker/24hr", params={"symbol": "BTCUSDT"})

# Futures mark price
mark = client.get("/fapi/v1/premiumIndex", params={"symbol": "BTCUSDT"})

Weights are calculated automatically from weights.py tables. If an endpoint is not in the table, it defaults to weight 1. You can also override manually:

data = client.get("/api/v3/depth", params={"symbol": "BTCUSDT", "limit": 5000}, weight=250)

Rate Limiting

The limiter works transparently. When accumulated weight approaches the limit (controlled by safety_ratio), the client sleeps until the next minute window. This means your code may block for up to ~60 seconds — it won't raise an error, it just waits.

# safety_ratio=0.9 means sleep when reaching 90% of the limit (e.g., 5400/6000 for spot)
client = BinancePublicClient(market="spot", safety_ratio=0.9)

# Inspect limiter state at any time
print(client.limiter.used_local)        # Weight used in current window
print(client.limiter.last_server_used)  # Last value from X-MBX-USED-WEIGHT-1M
print(client.limiter.max_per_minute)    # Limit from /exchangeInfo (e.g., 6000)

The limiter synchronizes with Binance's X-MBX-USED-WEIGHT-1M response header after every request, so it stays accurate even if other processes share the same IP.

Clock Synchronization

ensure_time_offset_ready() calls /time multiple times to estimate the offset between your local clock and Binance's server. This is recommended before loops that run many requests, because the limiter uses server time to align with Binance's rate limit windows.

client.ensure_time_offset_ready(min_samples=3)

# After sync, you can get the estimated server time
server_ms = client.now_server_ms()

If you skip this step, the limiter still works — it just uses your local clock, which may be slightly off from Binance's window boundaries.

Error Handling

from panzer.errors import BinanceAPIException

try:
    client.klines("INVALID", "1m")
except BinanceAPIException as e:
    print(e.status_code)        # 400
    print(e.error_payload.code)  # -1121
    print(e.error_payload.msg)   # "Invalid symbol."

All API errors (HTTP 4xx/5xx and Binance-specific error codes) raise BinanceAPIException with the parsed error payload when available.

The library does not retry failed requests automatically. If a request fails, the exception is raised immediately. Retry logic is left to the caller.

Logging

Each module writes to its own rotating log file in logs/:

logs/
  binance_public_spot.log
  binance_client_spot.log
  binance_fixed_limiter.log
  binance_signer.log
  credentials.log
  errors.log
  http.log

Logs also print to stdout. The logs/ directory is created automatically and is gitignored.

Architecture

panzer/
  __init__.py                   # Exports BinanceClient, BinancePublicClient, CredentialManager
  crypto.py                     # AesCipher (AES-128-CBC, machine-derived key)
  credentials.py                # CredentialManager (memory -> disk -> prompt)
  errors.py                     # BinanceAPIException, handle_response
  log_manager.py                # LogManager (rotating file + stdout)
  time_sync.py                  # TimeOffsetEstimator
  exchanges/binance/
    client.py                   # BinanceClient (authenticated, extends BinancePublicClient)
    config.py                   # Parses /exchangeInfo rate limits
    public.py                   # BinancePublicClient (public endpoints only)
    signer.py                   # BinanceRequestSigner (HMAC-SHA256)
    weights.py                  # Endpoint weight tables per market
  http/
    client.py                   # Low-level HTTP + header sync (public & signed)
  rate_limit/
    binance_fixed.py            # Fixed-window rate limiter

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

panzer-2.2.0.tar.gz (43.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

panzer-2.2.0-py3-none-any.whl (38.2 kB view details)

Uploaded Python 3

File details

Details for the file panzer-2.2.0.tar.gz.

File metadata

  • Download URL: panzer-2.2.0.tar.gz
  • Upload date:
  • Size: 43.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for panzer-2.2.0.tar.gz
Algorithm Hash digest
SHA256 2c11d178e7783b45b12fa4ff02ff8c44d76295a021bd6d6e2cf6889ca80fd7e3
MD5 ebefe4e841c8e0c9b224a10a20323bb3
BLAKE2b-256 4e27393a6ceeca224607cf3671f116c3d92afe3e2f07fdaa3cf1ceda6e21996a

See more details on using hashes here.

File details

Details for the file panzer-2.2.0-py3-none-any.whl.

File metadata

  • Download URL: panzer-2.2.0-py3-none-any.whl
  • Upload date:
  • Size: 38.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for panzer-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 954d5f275307de33eb2259b63add3cb8e364137385a812dfbda46c83f7043861
MD5 c3ced3f9c0258bf04d92a20c7288aec0
BLAKE2b-256 64a95eadd3ed4bd210bc42b063e9ec8250ce5c008547b12e3fe93cf1739b11b7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page