・約3分で読めます

GMO コイン API で FX 自動売買 Bot を作る完全ガイド


PRXサーバー国内シェアNo.1のレンタルサーバー。高速・安定・サポート充実で初心者にもおすすめ。
Xサーバー 公式サイト →

はじめに

GMO コインは外国為替 FX の API を公開しており、Python で自動売買 Bot を構築できます。この記事では、実際に Bot を開発・運用している筆者が、API の使い方を開発フロー順に解説します。

前提知識:

  • Python の基本
  • REST API の概念
  • FX 取引の基本用語(ロング、ショート、SL/TP)

API の全体像

GMO コイン外国為替 FX の API は 3 種類あります:

種類 認証 用途
Public REST API 不要 レート取得、ローソク足、マーケット状態
Private REST API HMAC-SHA256 注文、ポジション管理、口座情報
Public WebSocket 不要 リアルタイム価格配信

ベース URL:

REST (Public):  https://forex-api.coin.z.com/public/v1
REST (Private): https://forex-api.coin.z.com/private/v1
WebSocket:      wss://forex-api.coin.z.com/ws/public/v1

注意: 暗号資産 API (api.coin.z.com) とはサブドメインが異なります。外国為替は forex-api です。

Step 1: 認証 (HMAC-SHA256)

Private API へのリクエストには 3 つのヘッダーが必要です:

import hmac
import hashlib
import time
import requests

API_KEY = os.environ["GMO_API_KEY"]
API_SECRET = os.environ["GMO_API_SECRET"]

def auth_headers(method: str, path: str, body: str = "") -> dict:
    timestamp = str(int(time.time() * 1000))
    text = timestamp + method + path + body
    sign = hmac.new(
        API_SECRET.encode(),
        text.encode(),
        hashlib.sha256,
    ).hexdigest()
    return {
        "API-KEY": API_KEY,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign,
        "Content-Type": "application/json",
    }

ポイント:

  • タイムスタンプはミリ秒time.time() * 1000
  • 署名文字列: タイムスタンプ + HTTPメソッド + パス + ボディ
  • API キーは環境変数から読む(コードに書かない)

Step 2: マーケットデータ取得

レート (Ticker)

def get_ticker(symbol: str = "USD_JPY") -> dict:
    url = f"https://forex-api.coin.z.com/public/v1/ticker?symbol={symbol}"
    resp = requests.get(url, timeout=10).json()
    data = resp["data"][0]
    return {"bid": float(data["bid"]), "ask": float(data["ask"])}

ローソク足 (Klines)

def get_candles(symbol: str, interval: str, date: str) -> list:
    """
    interval: 1min, 5min, 15min, 30min, 1hour, 4hour, 1day
    date: YYYYMMDD 形式
    """
    url = (
        f"https://forex-api.coin.z.com/public/v1/klines"
        f"?symbol={symbol}&priceType=BID&interval={interval}&date={date}"
    )
    resp = requests.get(url, timeout=10).json()
    return resp.get("data", [])

マーケット状態確認

def is_market_open() -> bool:
    url = "https://forex-api.coin.z.com/public/v1/status"
    resp = requests.get(url, timeout=5).json()
    return resp.get("data", {}).get("status") == "OPEN"

取引前に必ず確認。メンテナンス中に注文を出すとエラーになります。

Step 3: 注文を出す

成行注文 (Market Order)

import json

def place_market_order(symbol: str, side: str, size: int) -> str:
    path = "/order"
    data = {
        "symbol": symbol,
        "side": side,       # "BUY" or "SELL"
        "executionType": "MARKET",
        "size": str(size),  # 文字列で渡す
    }
    body = json.dumps(data)
    headers = auth_headers("POST", path, body)
    url = f"https://forex-api.coin.z.com/private/v1{path}"
    resp = requests.post(url, headers=headers, data=body, timeout=10).json()

    if resp.get("status") == 0:
        return str(resp.get("data", ""))  # order_id
    else:
        raise Exception(f"Order failed: {resp.get('messages')}")

注意点:

  • size は文字列で渡す(数値だとエラー)
  • USD/JPY の最小注文単位は 100 通貨
  • レスポンスに約定価格は含まれない。別途 /latestExecutions で取得が必要

最小注文単位

通貨ペア 最小単位
USD/JPY, EUR/JPY 等 100 通貨
TRY/JPY, ZAR/JPY, MXN/JPY 100,000 通貨

約定価格の取得

成行注文のレスポンスには約定価格が入っていません。注文後に取得します:

def get_fill_price(order_id: str, retries: int = 3) -> float:
    for i in range(retries):
        path = f"/latestExecutions?orderId={order_id}"
        headers = auth_headers("GET", path)
        url = f"https://forex-api.coin.z.com/private/v1{path}"
        resp = requests.get(url, headers=headers, timeout=10).json()
        executions = resp.get("data", {}).get("list", [])
        if executions:
            # 部分約定の場合は加重平均
            total_value = sum(float(e["price"]) * float(e["size"]) for e in executions)
            total_size = sum(float(e["size"]) for e in executions)
            return total_value / total_size if total_size > 0 else 0.0
        time.sleep(0.3 * (i + 1))  # バックオフ
    return 0.0

Step 4: ポジション管理

ポジション一覧の取得

def get_open_positions() -> list:
    path = "/openPositions"
    headers = auth_headers("GET", path)
    url = f"https://forex-api.coin.z.com/private/v1{path}"
    resp = requests.get(url, headers=headers, timeout=10).json()
    return resp.get("data", {}).get("list", [])

レスポンスに含まれる主要フィールド: positionId, symbol, side, size, price(エントリー価格)

ポジション決済 (Market Close)

def close_position(symbol: str, side: str, position_id: int, size: int) -> str:
    path = "/closeOrder"
    # side は「反対売買」の方向
    close_side = "SELL" if side == "BUY" else "BUY"
    data = {
        "symbol": symbol,
        "side": close_side,
        "executionType": "MARKET",
        "settlePosition": [
            {"positionId": position_id, "size": str(size)}
        ],
    }
    body = json.dumps(data)
    headers = auth_headers("POST", path, body)
    url = f"https://forex-api.coin.z.com/private/v1{path}"
    resp = requests.post(url, headers=headers, data=body, timeout=10).json()
    if resp.get("status") == 0:
        return str(resp.get("data", ""))
    raise Exception(f"Close failed: {resp.get('messages')}")

OCO 注文 (SL/TP 同時設定)

Bot の安全装置として最も重要な機能。SL と TP を同時に設定し、どちらか約定したらもう一方をキャンセルします:

def place_oco_close(symbol: str, side: str, position_id: int,
                     size: int, take_profit: float, stop_loss: float) -> str:
    path = "/closeOrder"
    close_side = "SELL" if side == "BUY" else "BUY"
    precision = 3  # JPY ペアは小数点3桁
    data = {
        "symbol": symbol,
        "side": close_side,
        "executionType": "OCO",
        "limitPrice": f"{take_profit:.{precision}f}",
        "stopPrice": f"{stop_loss:.{precision}f}",
        "settlePosition": [
            {"positionId": position_id, "size": str(size)}
        ],
    }
    body = json.dumps(data)
    headers = auth_headers("POST", path, body)
    url = f"https://forex-api.coin.z.com/private/v1{path}"
    resp = requests.post(url, headers=headers, data=body, timeout=10).json()
    if resp.get("status") == 0:
        return str(resp.get("data", ""))
    raise Exception(f"OCO failed: {resp.get('messages')}")

OCO のメリット: Bot がクラッシュしても SL/TP は取引所側で執行されるため、損失が無制限に膨らむリスクを防げます。

Step 5: WebSocket でリアルタイム価格取得

ポーリングだと API レートリミットに引っかかるので、リアルタイム価格は WebSocket で受信します:

import aiohttp
import asyncio

async def stream_prices(symbol: str = "USD_JPY"):
    url = "wss://forex-api.coin.z.com/ws/public/v1"
    async with aiohttp.ClientSession() as session:
        async with session.ws_connect(url, heartbeat=15) as ws:
            await ws.send_json({
                "command": "subscribe",
                "channel": "ticker",
                "symbol": symbol,
            })
            async for msg in ws:
                if msg.type == aiohttp.WSMsgType.TEXT:
                    data = msg.json()
                    bid = float(data.get("bid", 0))
                    ask = float(data.get("ask", 0))
                    print(f"BID: {bid}, ASK: {ask}")

接続断の対策

WebSocket は切断されることがあります。3 層の対策を入れると安定します:

  1. PING/PONG: heartbeat=15 で aiohttp が自動送信
  2. 受信タイムアウト: 30 秒データが来なければ再接続
  3. リコネクトループ: 切断時に指数バックオフで再接続

Step 6: 口座情報の取得

def get_account() -> dict:
    path = "/account/assets"
    headers = auth_headers("GET", path)
    url = f"https://forex-api.coin.z.com/private/v1{path}"
    resp = requests.get(url, headers=headers, timeout=10).json()
    d = resp.get("data", {})
    return {
        "balance": float(d.get("balance", 0)),           # 入金額
        "equity": float(d.get("equity", 0)),              # 純資産額
        "unrealized_pl": float(d.get("positionLossGain", 0)),  # 未決済損益
        "margin_used": float(d.get("margin", 0)),         # 使用証拠金
        "available": float(d.get("availableAmount", 0)),  # 利用可能額
    }

ポジションサイジング(リスク管理)に available を使って、1 トレードあたりのリスク額を算出できます。

実装上のハマりポイント

開発中に遭遇した問題をまとめます:

1. size は文字列

"size": 1000 ではなく "size": "1000" でないとエラー。数値フィールドなのに文字列で渡す必要がある。

2. 約定価格がレスポンスに入っていない

成行注文のレスポンスは order_id のみ。約定価格は /latestExecutions を別途コールして取得する。部分約定の場合は加重平均を自分で計算する。

3. JPY ペアの小数点は 3 桁

OCO 注文の limitPrice / stopPrice は、JPY ペアなら小数点 3 桁(例: 155.123)。USD 系ペアは 5 桁(例: 1.08567)。精度を間違えるとエラー。

4. 暗号資産 API とサブドメインが違う

暗号資産: api.coin.z.com、外国為替: forex-api.coin.z.com。間違えると 404。

5. メンテナンス時間

外国為替は土日・年末年始は取引停止。注文前に /statusOPEN を確認すること。

まとめ

GMO コインの外国為替 FX API は、個人開発者でも本格的な自動売買 Bot を構築できる十分な機能を備えています。特に OCO 注文による SL/TP のサーバーサイド管理は、Bot の安全性に直結する重要機能です。

API ドキュメント: GMO コイン API リファレンス

GMOコインの無料口座開設はこちら →

免責事項: この記事は技術的な解説を目的としており、投資助言ではありません。FX 取引にはリスクが伴います。投資判断はご自身の責任で行ってください。

関連記事