Migrating from Binance
Step-by-step guide for Binance traders switching to GaiaEx: header mapping, symbol format differences, endpoint equivalents, and working code examples.
Migrating from Binance
This guide helps Binance Futures API users migrate to GaiaEx. The core concepts are identical — HMAC-SHA256 authentication, REST + WebSocket architecture, and similar order types. The differences are mainly in header names, endpoint paths, and symbol formatting.
QUICK SUMMARY
If you have a working Binance Futures bot, the migration typically takes 30–60 minutes. The main changes are: (1) swap header names, (2) update base URL, (3) adjust symbol format, (4) update endpoint paths.
WHAT'S DIFFERENT FROM BINANCE — FUNDING
Binance lets API keys with a withdrawal scope and whitelisted addresses move funds off the exchange. GaiaEx does not. Because the account is self-custodied, deposits and withdrawals require the user's embedded-wallet signature and a passkey step-up, which are only available in the GaiaEx mobile app. Your trading bot operates entirely within the user's deposited balance — it cannot top up, withdraw, or transfer on-chain. Plan for this: migrate the trading logic, but keep funding as a manual in-app step.
Authentication Mapping
Both exchanges use HMAC-SHA256, but the header names and signature construction differ.
| Concept | Binance | GaiaEx |
|---|---|---|
| API Key Header | X-MBX-APIKEY | X-GAIAEX-APIKEY |
| Timestamp | Query param: timestamp= | Header: X-GAIAEX-TIMESTAMP |
| Signature | Query param: signature= | Header: X-GAIAEX-SIGNATURE |
| Signature Input | query_string | timestamp + METHOD + path + body |
| Recv Window | recvWindow=5000 (query) | Fixed 5-second window (server-side) |
Binance Signature (Before)
# Binance: signature is over the query string
query = f"symbol=BTCUSDT&side=BUY&type=LIMIT×tamp={timestamp}"
signature = hmac.new(secret.encode(), query.encode(), hashlib.sha256).hexdigest()
url = f"https://fapi.binance.com/fapi/v1/order?{query}&signature={signature}"
headers = {"X-MBX-APIKEY": api_key}GaiaEx Signature (After)
# GaiaEx: signature is over timestamp + method + path + body
timestamp = str(int(time.time() * 1000))
body = json.dumps({"user_address": addr, "symbol": "BTC", "is_buy": True, "size": "0.1"})
message = timestamp + "POST" + "/order" + body
signature = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
headers = {
"X-GAIAEX-APIKEY": api_key,
"X-GAIAEX-TIMESTAMP": timestamp,
"X-GAIAEX-SIGNATURE": signature,
}Base URL
| Binance Futures | GaiaEx | |
|---|---|---|
| REST | https://fapi.binance.com | https://openapi.gaiaex.com/v1/trade |
| WebSocket | wss://fstream.binance.com | wss://openapi.gaiaex.com |
Symbol Format
GaiaEx uses a simpler symbol format without the quote asset suffix.
| Asset | Binance | GaiaEx |
|---|---|---|
| Bitcoin perp | BTCUSDT | BTC |
| Ethereum perp | ETHUSDT | ETH |
| Solana perp | SOLUSDT | SOL |
| Apple (RWA) | N/A | xyz:AAPL |
| Gold (RWA) | N/A | xyz:GOLD |
| OpenAI (venture) | N/A | vntl:OPENAI |
Conversion rule: Strip the USDT suffix. All GaiaEx perps are USDC-margined.
# Binance symbol → GaiaEx symbol
def convert_symbol(binance_symbol: str) -> str:
return binance_symbol.replace("USDT", "").replace("USD", "")Endpoint Mapping
Market Data
| Action | Binance | GaiaEx |
|---|---|---|
| List symbols | GET /fapi/v1/exchangeInfo | GET /symbols/list |
| Server time | GET /fapi/v1/time | GET /time |
| Order book | GET /fapi/v1/depth?symbol= | WebSocket: wss://.../ws/market/{symbol} |
Trading
| Action | Binance | GaiaEx |
|---|---|---|
| Place order | POST /fapi/v1/order | POST /order |
| Cancel order | DELETE /fapi/v1/order | POST /order/cancel |
| Cancel all | DELETE /fapi/v1/allOpenOrders | POST /order/cancel-all |
| Modify order | PUT /fapi/v1/order | POST /order/modify |
| Set leverage | POST /fapi/v1/leverage | POST /leverage |
Account Data
| Action | Binance | GaiaEx |
|---|---|---|
| Balance | GET /fapi/v2/balance | GET /user/{address}/balance |
| Positions | GET /fapi/v2/positionRisk | GET /user/{address}/positions |
| Open orders | GET /fapi/v1/openOrders | GET /user/{address}/openOrders |
| Trade fills | GET /fapi/v1/userTrades | GET /user/{address}/fills |
| Funding history | GET /fapi/v1/income?incomeType=FUNDING_FEE | GET /user/{address}/fundingHistory |
WebSocket Streams
| Stream | Binance | GaiaEx |
|---|---|---|
| Order book | wss://.../ws/btcusdt@depth | wss://.../ws/market/BTC |
| User data | wss://.../ws/{listenKey} | wss://.../ws/user/{address} |
KEY DIFFERENCE: WebSocket Auth
Binance uses a listenKey obtained from a REST call. GaiaEx authenticates directly via the Sec-WebSocket-Protocol: Bearer.{token} header — no extra REST call needed.
No Mapping: Funding Endpoints
Binance endpoints like POST /sapi/v1/capital/withdraw/apply, GET /sapi/v1/capital/deposit/address, and internal-transfer APIs have no GaiaEx equivalent in the public API. All deposits and withdrawals happen in the mobile app via the user's embedded wallet — there is no API-key-callable path.
Order Parameter Mapping
| Binance Param | GaiaEx Param | Notes |
|---|---|---|
symbol ("BTCUSDT") | symbol ("BTC") | No quote asset suffix |
side ("BUY"/"SELL") | is_buy (true/false) | Boolean instead of string enum |
type ("LIMIT"/"MARKET") | order_type ("limit"/"market") | Lowercase |
quantity | size | String type |
price | price | String type, omit for market |
timeInForce ("GTC") | N/A | All limit orders are GTC |
reduceOnly | reduce_only | Snake_case |
newClientOrderId | client_id | Optional tracking ID |
| N/A | user_address | Required — your wallet address |
Before (Binance)
order = client.futures_create_order(
symbol="ETHUSDT",
side="BUY",
type="LIMIT",
timeInForce="GTC",
quantity=0.1,
price=3500,
)After (GaiaEx)
import hmac, hashlib, time, json, requests
with open("config.json") as f:
cfg = json.load(f)
API_KEY, API_SECRET = cfg["api_key"], cfg["api_secret"]
ADDRESS = cfg["user_address"]
BASE = "https://openapi.gaiaex.com/v1/trade"
def sign(method, path, body=""):
ts = str(int(time.time() * 1000))
sig = hmac.new(API_SECRET.encode(), (ts + method + path + body).encode(), hashlib.sha256).hexdigest()
return {"X-GAIAEX-APIKEY": API_KEY, "X-GAIAEX-TIMESTAMP": ts, "X-GAIAEX-SIGNATURE": sig, "Content-Type": "application/json"}
body = json.dumps({"user_address": ADDRESS, "symbol": "ETH", "is_buy": True, "size": "0.1", "price": "3500.00", "order_type": "limit"})
order = requests.post(BASE + "/order", headers=sign("POST", "/order", body), data=body).json()Complete Migration Example
A full trading bot migration — from Binance to GaiaEx.
Before (Binance)
from binance.client import Client
client = Client(api_key="...", api_secret="...")
# Get balance
balance = client.futures_account_balance()
usdt = next(b for b in balance if b["asset"] == "USDT")
print(f"USDT: {usdt['balance']}")
# Place order
order = client.futures_create_order(
symbol="ETHUSDT", side="BUY", type="LIMIT",
timeInForce="GTC", quantity=0.1, price=3500,
)
# Set leverage
client.futures_change_leverage(symbol="ETHUSDT", leverage=10)
# Cancel all
client.futures_cancel_all_open_orders(symbol="ETHUSDT")After (GaiaEx)
import hmac, hashlib, time, json, requests
with open("config.json") as f:
cfg = json.load(f)
API_KEY, API_SECRET = cfg["api_key"], cfg["api_secret"]
ADDRESS = cfg["user_address"]
BASE = "https://openapi.gaiaex.com/v1/trade"
def sign(method, path, body=""):
ts = str(int(time.time() * 1000))
sig = hmac.new(API_SECRET.encode(), (ts + method + path + body).encode(), hashlib.sha256).hexdigest()
return {"X-GAIAEX-APIKEY": API_KEY, "X-GAIAEX-TIMESTAMP": ts, "X-GAIAEX-SIGNATURE": sig, "Content-Type": "application/json"}
# Get balance
balance = requests.get(BASE + f"/user/{ADDRESS}/balance", headers=sign("GET", f"/user/{ADDRESS}/balance")).json()
print(f"USDC: {balance.get('available_margin')}")
# Place order
body = json.dumps({"user_address": ADDRESS, "symbol": "ETH", "is_buy": True, "size": "0.1", "price": "3500.00", "order_type": "limit"})
order = requests.post(BASE + "/order", headers=sign("POST", "/order", body), data=body).json()
# Set leverage
body = json.dumps({"user_address": ADDRESS, "symbol": "ETH", "leverage": 10})
requests.post(BASE + "/leverage", headers=sign("POST", "/leverage", body), data=body)
# Cancel all
body = json.dumps({"user_address": ADDRESS, "symbol": "ETH"})
requests.post(BASE + "/order/cancel-all", headers=sign("POST", "/order/cancel-all", body), data=body)GaiaEx ADVANTAGE
GaiaEx is fully non-custodial — your funds stay on-chain. Unlike Binance, there's no KYC requirement for API trading, and the order book settles on MegaETH with single-block finality.