A Python trading bot I built for Binance Futures Testnet (USDT-M perpetuals). It lets you place market, limit, and stop-market orders through a CLI, with proper input validation, error handling, and logging.
- Market, Limit & Stop-Market orders on Binance Futures Testnet
- Input validation — checks symbols, quantities, prices, and order types before calling the API
- Minimum notional check — fetches the current mark price and makes sure your order is worth at least 100 USDT (Binance's requirement) before sending it
- Error handling — handles empty responses, non-JSON bodies, API errors, and network failures cleanly
- Logging — logs to console (INFO) and rotating log files (DEBUG) so you can trace exactly what happened
- CLI with argparse — straightforward command-line interface
- Type hints and docstrings throughout
trading_bot/
├── __init__.py # Package init, exports main classes
├── api_client.py # Handles HTTP requests to Binance API
├── order_service.py # Order logic, validation, notional checks
├── validation.py # Input validation (symbols, qty, price, etc.)
├── logger.py # Logging setup (console + rotating file)
└── cli.py # CLI argument parsing
main.py # Entry point
examples.py # Usage examples and validation demos
requirements.txt # Dependencies (requests, python-dotenv)
.env.example # Template for API credentials
logs/ # Log files (auto-created)
cd d:\PES\PROJECTS\internship
python -m venv venv
.\venv\Scripts\Activate.ps1 # Windows PowerShell
pip install -r requirements.txtGet your credentials from Binance Futures Testnet:
- Log in → API Management → Create a new key with Futures Trading enabled
- Copy
.env.exampleto.envand paste your keys:
BINANCE_API_KEY=your_testnet_api_key
BINANCE_API_SECRET=your_testnet_api_secretThe bot loads these automatically via python-dotenv.
python main.py --symbol <SYMBOL> --side <BUY|SELL> --type <MARKET|LIMIT|STOP_MARKET> --qty <QUANTITY> [OPTIONS]# Market buy
python main.py --symbol BTCUSDT --side BUY --type MARKET --qty 0.002
# Limit sell
python main.py --symbol ETHUSDT --side SELL --type LIMIT --qty 1 --price 3500
# Stop-market order
python main.py --symbol BTCUSDT --side BUY --type STOP_MARKET --qty 0.002 --stop-price 63000
# Limit order with IOC (Immediate or Cancel)
python main.py --symbol BNBUSDT --side BUY --type LIMIT --qty 5 --price 600 --tif IOC
# Close a position (reduce-only)
python main.py --symbol BTCUSDT --side SELL --type MARKET --qty 0.002 --reduce-only| Option | Required | Default | Description |
|---|---|---|---|
--symbol |
Yes | — | Trading pair (e.g. BTCUSDT) |
--side |
Yes | — | BUY or SELL |
--type |
Yes | — | MARKET, LIMIT, or STOP_MARKET |
--qty |
Yes | — | Order quantity |
--price |
No | None | Required for LIMIT orders |
--stop-price |
No | None | Required for STOP_MARKET orders |
--tif |
No | GTC | Time in Force: GTC, IOC, FOK, GTX |
--position-side |
No | BOTH | BOTH, LONG, or SHORT |
--reduce-only |
No | False | Reduce-only order |
--verbose |
No | False | More detailed console output |
============================================================
ORDER REQUEST SUMMARY
============================================================
Symbol: BTCUSDT
Side: BUY
Type: MARKET
Quantity: 0.002
============================================================
============================================================
✅ ORDER RESPONSE
============================================================
Order ID: 1234567890
Symbol: BTCUSDT
Status: FILLED
Side: BUY
Type: MARKET
Quantity: 0.002
Executed: 0.002
Average Price: 67432.10
============================================================
If notional is too low, you'll see:
============================================================
❌ ORDER REJECTED — Minimum Notional Requirement
============================================================
Symbol: BTCUSDT
Mark Price: 67,257.60 USDT
Entered Quantity: 0.001
Current Notional: 67.26 USDT
Minimum Required: 100 USDT
------------------------------------------------------------
Suggested Min Qty: 0.0016 BTC
============================================================
CLI (main.py → cli.py)
└─> OrderService (order_service.py)
├─> InputValidator (validation.py) — checks user inputs
├─> get_mark_price() — fetches current price for notional check
└─> BinanceAPIClient (api_client.py) — signs & sends API requests
└─> Logger (logger.py) — logs everything
- User provides CLI arguments
- CLI parses them and creates an
OrderRequest OrderServicevalidates the inputs- For MARKET orders, it fetches the mark price and checks notional ≥ 100 USDT
BinanceAPIClientsigns the request (HMAC-SHA256) and sends it- Response is inspected (status code, Content-Type, body) before parsing JSON
- Result is displayed and logged
- Console: real-time INFO-level output
- File: detailed DEBUG logs in
logs/trading_bot_YYYYMMDD.log(10 MB rotating, 5 backups)
The bot catches and reports errors at every level:
| Scenario | What you'll see |
|---|---|
| Invalid symbol / quantity | ❌ VALIDATION ERROR with details |
| Notional too low | ❌ ORDER REJECTED with suggested quantity |
| API returns an error | BinanceAPIError with HTTP status, URL, raw body |
| Empty or non-JSON response | BinanceAPIError with diagnostics |
| Network timeout / failure | RequestException with URL |
from trading_bot.api_client import BinanceAPIClient
from trading_bot.order_service import OrderService, OrderRequest
from decimal import Decimal
client = BinanceAPIClient()
service = OrderService(client)
# Place an order
request = OrderRequest(
symbol="BTCUSDT",
side="BUY",
order_type="MARKET",
quantity=Decimal("0.002")
)
success, message, response = service.place_order(request)
# Other API methods
client.get_mark_price("BTCUSDT")
client.get_order("BTCUSDT", order_id=12345)
client.cancel_order("BTCUSDT", order_id=12345)
client.get_open_orders("BTCUSDT")
client.get_positions()| Problem | Fix |
|---|---|
| "BINANCE_API_KEY … required" | Check .env exists, keys are correct, no trailing whitespace |
| "Invalid symbol" | Use full pair name, e.g. BTCUSDT (not BTC) |
| "Price is required for LIMIT orders" | Add --price |
| Network / connection error | Check internet, verify testnet.binancefuture.com is reachable |
| Orders not appearing on testnet | Log in to testnet dashboard, check API key permissions |
- API keys are loaded from environment variables (never hardcoded)
.envis in.gitignore- Requests are signed with HMAC-SHA256 + timestamp to prevent replay
- API secret is never logged
Any USDT-M perpetual on Binance Testnet — BTCUSDT, ETHUSDT, BNBUSDT, ADAUSDT, etc.
Version: 1.0.0 · Last Updated: 2026-02-20