GaiaExGaiaEx
GaiaEx API로 트레이딩하기: 인증, 주문, 시장 데이터
개발자프로그래밍12 min read

GaiaEx API로 트레이딩하기: 인증, 주문, 시장 데이터

GaiaEx에 프로그래밍 방식으로 연결해 첫 자동화 거래를 실행하기

게시물 공유

GaiaEx API 개요: Hyperliquid L1 위의 REST + WebSocket

GaiaEx는 Hyperliquid L1 위에 구축된 탈중앙화 거래소이며, API를 통해 시세 데이터, 주문 관리, 포지션 추적, 실시간 스트리밍 등 플랫폼이 제공하는 모든 기능에 프로그래밍 방식으로 접근할 수 있습니다. 트레이딩 봇, 포트폴리오 대시보드, 맞춤형 알림 시스템 등 무엇을 만들든 API가 그 출발점입니다.

API는 서로 보완적인 두 프로토콜로 나뉩니다.

  • REST API — 주문 실행, 잔고 조회, 과거 거래 조회, API 키 관리를 위한 요청-응답 엔드포인트입니다. 특정한 것을 실행하거나 요청해야 할 때 REST를 사용하십시오.
  • WebSocket API — 실시간 시세 데이터(거래, 오더북 업데이트, 티커)와 비공개 계정 이벤트(주문 체결, 포지션 변동)를 위한 상시 스트리밍 연결입니다. 어떤 일이 발생하는 즉시 반응해야 할 때 WebSocket을 사용하십시오.

내부적으로 GaiaEx는 Hyperliquid L1의 온체인 오더북에 연결됩니다. 주문은 결정론적 실행으로 온체인에서 매칭되며, 자산은 MPC(다자간 연산, Multi-Party Computation) 지갑으로 보호됩니다 — 즉 어떤 단일 주체도(GaiaEx조차도) 여러분의 완전한 개인키를 보유하지 않습니다. API는 블록체인의 복잡성을 추상화합니다. JSON 요청을 보내 주문을 넣으면, 플랫폼이 서명, 제출, L1 상의 확인을 처리합니다.

REST API의 베이스 URL은 표준 규칙을 따릅니다: https://api.gaiaex.com/v1/. WebSocket 연결은 wss://api.gaiaex.com/ws/v1/에서 수립됩니다. 모든 엔드포인트는 JSON을 반환하고, 모든 타임스탬프는 UTC 기준 에포크 이후 밀리초 단위이며, 부동소수점 정밀도 문제를 피하기 위해 모든 금액 값은 문자열로 표현됩니다.

REST vs WebSocket: when to use each REST (request / response) Place / cancel orders Balances, history, REST tick Best for actions & snapshots WebSocket (stream) Trades, book, account events Push updates, lower latency Best for live strategies Bots usually combine both: WS for signals, REST for execution & reconciliation.
지속적인 시장 상태 파악에는 스트리밍을, 개별 명령이나 스냅샷이 필요할 때는 REST를 사용하십시오.

API 키 관리와 HMAC 인증

비공개 엔드포인트(주문 실행, 잔고 조회)에 접근하려면 API 키 쌍이 필요합니다. GaiaEx 대시보드의 설정 → API 키에서 생성할 수 있습니다. 두 가지 값을 받게 됩니다.

  • API 키(API Key) — 모든 요청과 함께 전송되는 공개 식별자입니다. 사용자 이름이라고 생각하면 됩니다.
  • API 시크릿(API Secret) — 요청을 서명하는 데 사용되는 비공개 키입니다. 절대 공유하지 말고, 버전 관리 시스템에 커밋하지 말고, 요청 헤더에 넣어 전송하지 마십시오.

GaiaEx는 비공개 요청을 인증하기 위해 HMAC-SHA256 서명을 사용합니다. 과정은 다음과 같습니다. 타임스탬프, HTTP 메서드, 요청 경로, 본문을 하나의 문자열로 연결한 뒤, 시크릿을 이용해 HMAC 서명을 계산합니다. 서버는 동일한 연산을 수행하고 서명을 비교합니다.

import hmac, hashlib, time, requests, json

API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
BASE_URL = "https://api.gaiaex.com/v1"

def signed_request(method, path, body=None):
    timestamp = str(int(time.time() * 1000))
    body_str = json.dumps(body) if body else ""
    message = timestamp + method.upper() + path + body_str
    signature = hmac.new(
        API_SECRET.encode(), message.encode(), hashlib.sha256
    ).hexdigest()

    headers = {
        "X-API-Key": API_KEY,
        "X-Timestamp": timestamp,
        "X-Signature": signature,
        "Content-Type": "application/json",
    }

    resp = requests.request(method, BASE_URL + path, headers=headers,
                            data=body_str if body else None)
    return resp.json()

API 시크릿은 환경 변수나 시크릿 관리자에 저장하십시오 — 절대 하드코딩하지 마십시오. 대시보드에서 API 키에 IP 화이트리스트를 설정해 서버의 IP 주소로만 사용을 제한하십시오. 키가 유출되었다면 대시보드에서 즉시 폐기하고 새 키를 생성하십시오.

타임스탬프 구성 요소는 재전송 공격(replay attack)을 방지합니다. 서버는 타임스탬프가 서버 시계와 30초 이상 차이 나는 요청을 거부합니다. 여러분의 시스템 시계가 NTP를 통해 동기화되어 있는지 확인하십시오.

HMAC request signing (conceptual) Client sign(ts + method + path + body) HMAC-SHA256 with API secret GaiaEx verifies Secret never travels on the wire — only the signature + key id + timestamp. Clock skew window blocks stale replays
서버는 다이제스트를 다시 계산하며, 값이 일치하지 않으면 시크릿을 노출하지 않고 호출을 거부합니다.

시세 데이터 가져오기: 오더북, 거래, 티커

시세 데이터 엔드포인트는 공개되어 있어 인증이 필요하지 않습니다. 거래 결정을 내리는 데 필요한 원시 정보를 제공합니다.

오더북 — 특정 심볼에 대한 현재 매수·매도 호가를 반환합니다. depth 매개변수로 반환할 가격 단계 수를 조절합니다(기본값 20, 최대 100).

# Fetch the BTC-USD order book (top 10 levels)
resp = requests.get(f"{BASE_URL}/orderbook/BTC-USD?depth=10")
book = resp.json()

best_bid = book["bids"][0]  # [price, quantity]
best_ask = book["asks"][0]
spread = float(best_ask[0]) - float(best_bid[0])
print(f"Spread: ${spread:.2f}")

최근 거래 — 특정 심볼의 최근 체결 N건을 반환합니다. 각 거래에는 가격, 수량, 방향(테이커가 매수했는지 매도했는지), 타임스탬프가 포함됩니다.

# Fetch the last 50 ETH-USD trades
resp = requests.get(f"{BASE_URL}/trades/ETH-USD?limit=50")
trades = resp.json()["trades"]
avg_price = sum(float(t["price"]) for t in trades) / len(trades)
print(f"Average of last 50 trades: ${avg_price:.2f}")

티커 — 현재 시장 상태의 요약입니다. 최종가, 24시간 최고/최저, 24시간 거래량, 최우선 매수/매도 호가, 등락률을 포함합니다. 관심 목록을 구성하거나 변동성을 스캔하는 데 이상적입니다.

# Fetch all tickers
resp = requests.get(f"{BASE_URL}/tickers")
for ticker in resp.json():
    if float(ticker["change24h"]) > 5.0:
        print(f"{ticker['symbol']}: +{ticker['change24h']}%")

실시간 데이터가 필요하다면 이 엔드포인트를 폴링하는 대신 WebSocket 피드를 사용하십시오. REST 엔드포인트는 레이트 리밋이 걸려 있고 지연을 유발하지만, WebSocket은 Hyperliquid L1에서 발생하는 순간 즉시 업데이트를 전달합니다.

주문 실행하기: 시장가, 지정가, 스톱

주문 실행은 모든 트레이딩 시스템의 핵심 동작입니다. GaiaEx는 POST /orders 엔드포인트를 통해 세 가지 주문 유형을 지원합니다.

시장가 주문(Market order) — 즉시 이용 가능한 최우선 가격에 체결됩니다. 가격 정밀도보다 실행 속도가 중요할 때 사용합니다.

# Buy 0.1 BTC at market price
order = signed_request("POST", "/orders", {
    "symbol": "BTC-USD",
    "side": "buy",
    "type": "market",
    "quantity": "0.1",
})
print(f"Filled at {order['avgPrice']}")

지정가 주문(Limit order) — 지정한 가격 또는 그보다 유리한 가격에서만 체결됩니다. 체결되거나, 취소되거나, 만료될 때까지 오더북에 대기합니다.

# Sell 2 ETH at $3,500 or higher
order = signed_request("POST", "/orders", {
    "symbol": "ETH-USD",
    "side": "sell",
    "type": "limit",
    "price": "3500.00",
    "quantity": "2.0",
    "timeInForce": "GTC",  # Good Till Cancelled
})

스톱 주문(Stop order) — 시장이 트리거 가격에 도달할 때 활성화되는 조건부 주문입니다. 스톱로스나 브레이크아웃 진입에 사용됩니다.

# Stop-loss: sell 0.5 BTC if price drops to $58,000
order = signed_request("POST", "/orders", {
    "symbol": "BTC-USD",
    "side": "sell",
    "type": "stop_market",
    "stopPrice": "58000.00",
    "quantity": "0.5",
})

기존 주문을 관리하려면 GET /orders?status=open으로 미체결 주문을 조회하고, DELETE /orders/{orderId}로 특정 주문을 취소하거나, DELETE /orders?symbol=BTC-USD로 특정 심볼의 모든 미체결 주문을 취소하십시오. 포지션 관리에는 GET /positions가 진입가, 수량, 미실현 손익, 청산 가격을 포함한 모든 오픈 포지션을 반환합니다.

WebSocket을 통한 실시간 데이터 스트리밍

GaiaEx WebSocket API는 구독/구독 취소 모델을 사용합니다. 연결 후, 수신하고자 하는 채널을 지정해 구독 메시지를 전송합니다. 공개(시세 데이터) 채널과 비공개(계정 이벤트) 채널을 모두 같은 연결에서 이용할 수 있습니다.

import asyncio, json, hmac, hashlib, time
import websockets

async def connect_gaiaex():
    uri = "wss://api.gaiaex.com/ws/v1"
    async with websockets.connect(uri) as ws:
        # Authenticate for private channels
        ts = str(int(time.time() * 1000))
        sig = hmac.new(API_SECRET.encode(),
                       (ts + "websocket_auth").encode(),
                       hashlib.sha256).hexdigest()
        await ws.send(json.dumps({
            "method": "auth",
            "apiKey": API_KEY,
            "timestamp": ts,
            "signature": sig,
        }))

        # Subscribe to public + private channels
        await ws.send(json.dumps({
            "method": "subscribe",
            "channels": [
                "trades.BTC-USD",
                "orderbook.BTC-USD",
                "account.orders",
                "account.positions",
            ]
        }))

        async for msg in ws:
            data = json.loads(msg)
            ch = data.get("channel", "")
            if ch == "account.orders":
                print(f"Order update: {data['status']} {data['orderId']}")
            elif ch == "trades.BTC-USD":
                print(f"Trade: {data['price']} x {data['quantity']}")

asyncio.run(connect_gaiaex())

account.orders 채널은 여러분의 주문이 체결, 부분 체결, 또는 취소될 때마다 업데이트를 전송해 REST 엔드포인트를 폴링할 필요를 없애줍니다. account.positions 채널은 실시간 손익과 마진 업데이트를 스트리밍합니다. 공개 시세 데이터 채널과 결합하면, 하나의 WebSocket 연결만으로 트레이딩 봇이 필요로 하는 모든 것을 제공받을 수 있습니다.

항상 하트비트(heartbeat) 메커니즘을 구현하십시오. GaiaEx는 주기적으로 핑 프레임을 전송하며, 클라이언트는 퐁 프레임으로 응답해야 합니다. 30초 내에 퐁을 받지 못하면 서버가 연결을 종료합니다. 여러분 쪽에서도 30초간 데이터가 오지 않으면 연결이 끊긴 것으로 간주하고 재연결하십시오.

간단한 트레이딩 봇 만들기: 모니터링, 실행, 관리

지금까지의 내용을 하나로 묶어 최소한이지만 실제로 동작하는 트레이딩 봇을 만들어 보겠습니다. 이 봇은 WebSocket을 통해 BTC-USD 가격을 모니터링하며, 가격이 목표가 이하로 떨어지면 지정가 매수 주문을 넣습니다. 포지션이 열려 있고 가격이 익절 수준 위로 오르면 포지션을 청산합니다.

import asyncio, json
import websockets

TARGET_BUY = 60000.0
TAKE_PROFIT = 63000.0
QUANTITY = "0.05"
position_open = False

async def trading_bot():
    global position_open
    uri = "wss://api.gaiaex.com/ws/v1"

    async with websockets.connect(uri) as ws:
        # Auth + subscribe (omitted for brevity)
        await ws.send(json.dumps({
            "method": "subscribe",
            "channels": ["trades.BTC-USD"]
        }))

        async for msg in ws:
            data = json.loads(msg)
            if data.get("channel") != "trades.BTC-USD":
                continue

            price = float(data["price"])

            if not position_open and price <= TARGET_BUY:
                order = signed_request("POST", "/orders", {
                    "symbol": "BTC-USD", "side": "buy",
                    "type": "limit", "price": str(TARGET_BUY),
                    "quantity": QUANTITY,
                })
                print(f"BUY order placed: {order['orderId']}")
                position_open = True

            elif position_open and price >= TAKE_PROFIT:
                order = signed_request("POST", "/orders", {
                    "symbol": "BTC-USD", "side": "sell",
                    "type": "market", "quantity": QUANTITY,
                })
                print(f"SELL order placed: {order['orderId']}")
                position_open = False

asyncio.run(trading_bot())

이 예제는 의도적으로 단순하게 만들었습니다. 실제 운영용 봇이라면 다음을 추가해야 합니다. 모든 API 호출에 대한 try/except 기반 에러 처리와 자동 재연결, 일시적 실패에 대한 지수 백오프 재시도 로직, 불리언 플래그 대신 account.positions WebSocket 채널을 이용한 포지션 추적, 일일 최대 손실 이후 거래를 중단시키는 리스크 한도, 그리고 거래 후 분석을 위해 모든 결정과 API 응답을 기록하는 로깅입니다.

GaiaEx의 MPC 지갑 아키텍처 덕분에 봇은 원시 개인키를 전혀 다루지 않습니다 — 서명은 플랫폼의 분산 키 인프라가 처리합니다. 이는 자체적으로 지갑 키를 관리하는 봇들에 비해 보안 취약 영역을 줄여줍니다. 그런 봇들은 단 한 번의 키 유출로 모든 자금을 잃을 수 있습니다. API 키 IP 화이트리스트와 HMAC 인증 계층까지 결합하면, 자동화된 트레이딩을 위한 다층 방어를 갖추게 됩니다.

작게 시작하십시오. 최소 포지션 규모로 배포하고, 48시간 동안 모니터링하며, 체결이 예상과 일치하는지 확인한 뒤 점차 규모를 늘려 가십시오. 최고의 트레이딩 봇은 한 번의 코딩 스프린트가 아니라 점진적으로 만들어집니다.