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 from /exchangeInfo automatically)
client = BinancePublicClient(market="spot", safety_ratio=0.9)

# Synchronize clock with Binance server (recommended before heavy usage)
client.ensure_time_offset_ready(min_samples=3)

# 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)

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.1.0.tar.gz (41.6 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.1.0-py3-none-any.whl (36.1 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for panzer-2.1.0.tar.gz
Algorithm Hash digest
SHA256 171ce29c042fed320c886715d25234118bc8cde43cd4f4c0b4233a3d54cf4d5c
MD5 b7a70e4f51037c7e36115b1a5b45abb1
BLAKE2b-256 67f76195776cbbbd005c972c536f9a9474c6c25b7c0b31d393e9ff9347c6fcd0

See more details on using hashes here.

File details

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

File metadata

  • Download URL: panzer-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 36.1 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 58e3652e890e743c7639b311811ed63b723148b79aea0f7e39a6959c571b0683
MD5 1553f0ebf562add49e5b330483cce699
BLAKE2b-256 1921617a99ba2688cf09ef6ebff8b3b36f308ccf7e3c4ab8b57ac271bde79fe5

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