
本ページにはプロモーションが含まれています。
PythonでFX自動売買を行う場合、注文を出したあとに「実際に約定したのか」「現在も建玉が残っているのか」「最終的にいくらの損益になったのか」を確認する必要があります。
しかし、GMO FX APIを使って注文結果を確認しようとすると、
- 注文情報・約定情報・建玉情報は何が違うのか
- 注文IDからどのように結果を取得すればいいのか
- IFDOCO注文のTP・SLまで確認できるのか
- 決済後の損益もPythonから取得できるのか
といった疑問を持つ方も多いのではないでしょうか。
そこで本記事では、PythonとGMO FX APIを使って、注文後の約定状況・建玉・決済結果・損益を確認する方法を紹介します。
今回使用するtrade_result.pyでは、注文IDを指定して結果を取得できるほか、注文IDが分からない場合でも有効注文や直近の約定情報から確認する注文を選択できます。
Pythonのサンプルコードも掲載しているので、GMO FX APIで自動売買の注文結果まで確認したい方は、ぜひ参考にしてください!
とりあえずコードのみ欲しい方へ。以下がtrade_result.pyのコードです。
"""GMO FX APIから注文・約定・建玉・決済損益を取得するサンプル。"""
import argparse
import hashlib
import hmac
import json
import os
import ssl
import time
from decimal import Decimal, InvalidOperation
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
import certifi
# ============================================================
# 【重要な注意点】
# ============================================================
# 同じGMO FXアカウントで、このスクリプトを複数のターミナルから
# 同時に実行しないでください。
#
# GMO FX Private APIの呼び出し回数は、同一アカウント単位で合算されます。
# 複数のターミナルや別のスクリプトから同時にAPIへアクセスすると、
# 1秒間の呼び出し上限を超えてAPIエラーになる可能性があります。
# 使い方:
# 1. PowerShellを開き、このファイルを保存したフォルダへ移動します。
# cd GMO-API
# 2. APIキーとAPIシークレットをPowerShellへ入力します。
# 実際の値は、このPythonファイルへ直接書かないでください。
#
# $env:GMO_FX_API_KEY="実際のAPIキー"
# $env:GMO_FX_SECRET_KEY="実際のAPIシークレット"
#
# この方法では入力内容がPowerShellの履歴に残る場合があります。
# 共用パソコンなどで履歴へ残したくない場合は、Read-Hostを使用してください。
#
# 3. 注文IDを指定せずに実行すると、GMO FXから有効注文と最新約定を取得し、
# 表示された候補から確認する注文を選択できます。CSVは使用しません。
# latestExecutionsで取得できるのは直近1日分から最新100件までです。
# 数日前などの古い注文は、注文IDを直接指定してください。
# python trade_result.py
# 4. 注文IDが分かっている場合は、実行時に直接指定することもできます。
# python trade_result.py 123456789
# 5. IFDOCOの親注文IDを直接指定する場合は、--rootを付けます。
# python trade_result.py 123456789 --root
# 6. 通貨ペアの初期値はUSD_JPYです。変更する場合は--symbolを付けます。
# python trade_result.py --symbol EUR_USD
# 7. 入力した環境変数は、そのPowerShellウィンドウを閉じると引き継がれません。
# 注文情報、約定情報、建玉情報の取得に使うGMO FX Private APIの接続先です。
# Private APIの利用には、PowerShellで入力したAPIキーとAPIシークレットが必要です。
PRIVATE_URL = "https://forex-api.coin.z.com/private"
# PowerShellでAPIキーとAPIシークレットを設定するときの環境変数名です。
# ここに認証情報そのものは書きません。実際の値はPowerShellから入力します。
# このファイル内に定義しているため、live_config.pyなど別ファイルは必要ありません。
API_KEY_ENV = "GMO_FX_API_KEY"
SECRET_KEY_ENV = "GMO_FX_SECRET_KEY"
# GMO FX Private APIのGET上限へ余裕を持って対応するため、
# 各リクエストの前に0.5秒待機します。
REQUEST_INTERVAL_SECONDS = 0.5
# certifiが持っている証明書一覧を使って、HTTPS通信の証明書を検証します。
# Windows環境でCERTIFICATE_VERIFY_FAILEDになる場合の対策です。
SSL_CONTEXT = ssl.create_default_context(cafile=certifi.where())
def list_items(data):
"""data内の明細をリストへそろえる。"""
# data自体がリストの場合は、そのまま返します。
if isinstance(data, list):
return data
# ordersなどのAPIは、data内のlistに明細が入っています。
if isinstance(data, dict):
rows = data.get("list", [])
return rows if isinstance(rows, list) else []
# データがない場合も、後続処理で安全に繰り返せるよう空リストを返します。
return []
def private_get(path, params, api_key=None, secret_key=None):
"""環境変数の認証情報で署名し、Private APIへGET送信する。"""
# 認証情報の値はコードに保存せず、PowerShellで入力された環境変数から取得します。
api_key = api_key or os.environ.get(API_KEY_ENV)
secret_key = secret_key or os.environ.get(SECRET_KEY_ENV)
# どちらかが未設定なら、認証できないためAPIへアクセスする前に処理を止めます。
if not api_key or not secret_key:
raise RuntimeError(
f"PowerShellで環境変数 {API_KEY_ENV} と "
f"{SECRET_KEY_ENV} を設定してください。"
)
# API-TIMESTAMPへ設定する、現在時刻のミリ秒単位UNIX時刻を作ります。
timestamp = str(int(time.time() * 1000))
method = "GET"
# GMO FXのGET署名にはクエリ文字列を含めません。
# 「時刻 + HTTPメソッド + APIパス」を連結した文字列が署名対象です。
sign_text = timestamp + method + path
# APIシークレットを使い、HMAC-SHA256形式の署名を作ります。
signature = hmac.new(
secret_key.encode("ascii"), sign_text.encode("ascii"), hashlib.sha256
).hexdigest()
# GMO FX Private APIの認証に必要な3項目をHTTPヘッダーへ設定します。
headers = {
"API-KEY": api_key,
"API-TIMESTAMP": timestamp,
"API-SIGN": signature,
}
# 注文IDや通貨ペアなどの検索条件をURLのクエリ文字列へ変換します。
query = "?" + urlencode(params) if params else ""
request = Request(PRIVATE_URL + path + query, headers=headers, method=method)
try:
# GMO FXへ連続でアクセスしすぎないよう、通信前に一定時間待ちます。
# 0.5秒間隔にすることで、このスクリプトからのGETを最大約2回/秒に抑えます。
time.sleep(REQUEST_INTERVAL_SECONDS)
# タイムアウトを20秒に設定してAPIへアクセスし、JSONをPythonの辞書へ変換します。
with urlopen(request, context=SSL_CONTEXT, timeout=20) as response:
payload = json.loads(response.read().decode("utf-8"))
except HTTPError as error:
# HTTPステータスがエラーの場合、APIキーなどを表示せずステータス番号だけ伝えます。
raise RuntimeError(f"GMO FX APIとの通信に失敗しました(HTTP {error.code})。") from error
except (URLError, TimeoutError) as error:
# ネットワーク切断やタイムアウトを、利用者に分かるエラーへ変換します。
raise RuntimeError(f"GMO FX APIへ接続できませんでした: {error}") from error
# GMO FX APIは正常時にstatus=0を返します。0以外なら処理を止めます。
if int(payload.get("status", -1)) != 0:
raise RuntimeError(f"GMO FX APIエラー: {payload.get('messages')}")
# 呼び出し元では共通項目を除いたdata部分だけを使用します。
return payload.get("data")
def get_trade_result(order_id, use_root_order_id=False, private_get_func=private_get):
"""注文IDを起点に、関連する注文・約定・有効建玉を取得する。"""
# --rootが付いていれば親注文ID、なければ通常の注文IDとして検索します。
id_type = "rootOrderId" if use_root_order_id else "orderId"
orders = list_items(private_get_func("/v1/orders", {id_type: order_id}))
# 注文が見つからなければ、約定や建玉も空の結果として返します。
if not orders:
return {"orders": [], "executions": [], "open_positions": []}
# 通常の注文IDが指定された場合も、親注文IDをたどってIFDOCOを構成する
# エントリー・TP・SLの全注文を取得する。
if not use_root_order_id:
root_order_id = orders[0].get("rootOrderId")
if root_order_id is not None:
related_orders = list_items(
private_get_func("/v1/orders", {"rootOrderId": root_order_id})
)
if related_orders:
orders = related_orders
# IFDOCOを構成する各注文について、約定情報を1件ずつ取得してまとめます。
# executions APIはorderIdを1つずつ指定して呼び出します。
executions = []
for order in orders:
current_order_id = order.get("orderId")
# レスポンスに注文IDがない不完全な明細は、誤照会を防ぐため読み飛ばします。
if current_order_id is None:
continue
rows = list_items(
private_get_func("/v1/executions", {"orderId": current_order_id})
)
executions.extend(rows)
# 約定に含まれる建玉IDだけを照合する。対象銘柄が複数でも確認できるよう、
# 銘柄ごとに有効建玉一覧を取得する。
# 約定情報から建玉IDを取り出します。
# 同じ建玉IDが複数回現れても、setにすることで重複を除けます。
position_ids = {
str(row["positionId"])
for row in executions
if row.get("positionId") is not None
}
# 建玉一覧APIは通貨ペアで検索するため、注文から対象通貨ペアを取り出します。
symbols = sorted({row.get("symbol") for row in orders if row.get("symbol")})
open_positions = []
for symbol in symbols if position_ids else []:
# 同じ通貨ペアの有効建玉を最大100件取得します。
rows = list_items(
private_get_func("/v1/openPositions", {"symbol": symbol, "count": 100})
)
# 口座内の別の建玉を混ぜないよう、対象注文の建玉IDと一致するものだけ残します。
open_positions.extend(
row for row in rows if str(row.get("positionId")) in position_ids
)
return {
"orders": orders,
"executions": executions,
"open_positions": open_positions,
}
def find_order_candidates(symbol, private_get_func=private_get):
"""GMO FXから有効注文と最新約定を取得し、注文IDの候補を作る。"""
# activeOrdersには、まだ約定・取消されていない注文が入っています。
active_orders = list_items(
private_get_func("/v1/activeOrders", {"symbol": symbol, "count": 100})
)
# latestExecutionsには、直近1日分から最新100件までの約定が入っています。
# 決済済み注文はactiveOrdersから消えるため、こちらも候補へ加えます。
latest_executions = list_items(
private_get_func("/v1/latestExecutions", {"symbol": symbol, "count": 100})
)
# 注文IDをキーにして重複を除きます。
# 同じ注文が有効注文と約定情報の両方に含まれても、候補には1回だけ表示します。
candidates = {}
for order in active_orders:
order_id = order.get("orderId")
if order_id is None:
continue
candidates[str(order_id)] = {
"order_id": str(order_id),
"root_order_id": str(order.get("rootOrderId", "")),
"symbol": order.get("symbol", symbol),
"side": order.get("side", "-"),
"settle_type": order.get("settleType", "-"),
"status": order.get("status", "有効注文"),
"timestamp": order.get("timestamp", "-"),
}
for execution in latest_executions:
order_id = execution.get("orderId")
if order_id is None or str(order_id) in candidates:
continue
candidates[str(order_id)] = {
"order_id": str(order_id),
# 約定情報には親注文IDがないため、選択後にorders APIから取得します。
"root_order_id": "",
"symbol": execution.get("symbol", symbol),
"side": execution.get("side", "-"),
"settle_type": execution.get("settleType", "-"),
"status": "約定済み",
"timestamp": execution.get("timestamp", "-"),
}
# 新しい候補から確認できるよう、APIの日時文字列で降順に並べます。
return sorted(candidates.values(), key=lambda row: row["timestamp"], reverse=True)
def select_order_id(candidates, input_func=input):
"""候補番号または手入力された注文IDを受け取る。"""
print("\n【GMO FXから取得した注文ID候補】")
print(
"注文IDを省略した場合は、有効注文と直近1日分の最新約定から候補を表示します。"
)
print("過去の注文を確認する場合は、注文IDを直接指定してください。")
if candidates:
for number, row in enumerate(candidates, start=1):
print(
f"{number}. 注文ID={row['order_id']} "
f"親注文ID={row['root_order_id'] or '-'} "
f"{row['symbol']} {row['side']} {row['settle_type']} "
f"{row['status']} {row['timestamp']}"
)
prompt = "候補番号または確認する注文IDを入力してください: "
else:
print("有効注文または最新約定から注文IDを取得できませんでした。")
prompt = "確認する注文IDを入力してください: "
entered = input_func(prompt).strip()
# 1から候補件数までの数字なら、画面に表示した候補番号として扱います。
if entered.isdigit() and 1 <= int(entered) <= len(candidates):
return candidates[int(entered) - 1]["order_id"]
# 候補番号に該当しない数字は、注文IDの直接入力として扱います。
if entered.isdigit():
return entered
raise ValueError("候補番号または数字の注文IDを入力してください。")
def decimal_sum(rows, field):
"""APIの数値文字列をDecimalで安全に合計する。"""
# 金額計算ではfloatの丸め誤差を避けるためDecimalを使います。
total = Decimal("0")
for row in rows:
try:
total += Decimal(str(row.get(field, "0")))
except (InvalidOperation, TypeError):
# 数値へ変換できない項目があっても、ほかの明細の集計を続けます。
pass
return total
def display_trade_result(result):
"""取得結果を、注文・約定・建玉・決済の順に表示する。"""
# get_trade_result()が返した3種類の情報を取り出します。
orders = result["orders"]
executions = result["executions"]
open_positions = result["open_positions"]
if not orders:
print("指定した注文IDの注文情報は見つかりませんでした。")
return
# 注文情報では、受付中・約定・取消など各注文の現在の状態を確認できます。
print("\n【注文情報】")
for order in orders:
print(f"注文ID: {order.get('orderId', '-')}")
print(f" 親注文ID: {order.get('rootOrderId', '-')}")
print(f" 通貨ペア: {order.get('symbol', '-')}")
print(f" 売買: {order.get('side', '-')} / 区分: {order.get('settleType', '-')}")
print(f" 注文方法: {order.get('executionType', '-')}")
print(f" 注文数量: {order.get('size', '-')}")
print(f" 注文価格: {order.get('price', '成行注文のため指定なし')}")
print(f" ステータス: {order.get('status', '-')}")
if order.get("cancelType"):
print(f" 取消理由: {order['cancelType']}")
# 約定情報には、実際に取引が成立した価格・数量・損益が入っています。
print("\n【約定情報】")
if not executions:
print("約定情報はありません。注文が未約定または取消済みの可能性があります。")
for execution in executions:
print(f"約定ID: {execution.get('executionId', '-')}")
print(f" 注文ID: {execution.get('orderId', '-')}")
print(f" 建玉ID: {execution.get('positionId', '-')}")
print(f" 売買: {execution.get('side', '-')} / 区分: {execution.get('settleType', '-')}")
print(f" 約定価格: {execution.get('price', '-')}")
print(f" 約定数量: {execution.get('size', '-')}")
print(f" 決済損益: {execution.get('lossGain', '0')}")
print(f" 決済スワップ: {execution.get('settledSwap', '0')}")
print(f" 取引手数料: {execution.get('fee', '0')}")
print(f" 約定日時: {execution.get('timestamp', '-')}")
# 約定から得た建玉IDが有効建玉一覧に残っているかを表示します。
print("\n【建玉情報】")
if open_positions:
print("対象注文から作られた建玉が残っています。")
for position in open_positions:
print(
f"建玉ID: {position.get('positionId', '-')} / "
f"数量: {position.get('size', '-')} / "
f"建玉価格: {position.get('price', '-')} / "
f"評価損益: {position.get('lossGain', '-')}"
)
else:
print("対象注文に関連する有効建玉はありません。")
# settleType=CLOSEだけを取り出し、決済損益の集計対象にします。
close_executions = [
row for row in executions if row.get("settleType") == "CLOSE"
]
# 約定の注文IDから元の注文方法を引けるよう、注文情報を辞書にします。
order_by_id = {str(row.get("orderId")): row for row in orders}
print("\n【決済結果】")
if not close_executions:
print("決済約定はまだ確認できません。")
return
for execution in close_executions:
order = order_by_id.get(str(execution.get("orderId")), {})
execution_type = order.get("executionType")
# このIFDOCOサンプルでは、決済LIMITがTP、決済STOPがSLです。
# 別の方法で発注した注文では、必ずしもこの判定になるとは限りません。
if execution_type == "LIMIT":
reason = "TP(指値)"
elif execution_type == "STOP":
reason = "SL(逆指値)"
else:
reason = f"{execution_type or '不明'}注文"
print(f"注文ID {execution.get('orderId', '-')}: {reason}で決済")
# 複数回に分かれて約定した場合も、各金額をそれぞれ合計します。
loss_gain_total = decimal_sum(close_executions, "lossGain")
settled_swap_total = decimal_sum(close_executions, "settledSwap")
fee_total = decimal_sum(close_executions, "fee")
# 公式仕様に記載された3項目を分けて表示します。
# feeの符号を使った最終損益の計算方法は公式仕様に明記されていないため、
# このサンプルでは「最終損益」を独自に計算しません。
print(f"決済損益合計: {loss_gain_total}")
print(f"決済スワップ合計: {settled_swap_total}")
print(f"取引手数料合計: {fee_total}")
def parse_args(argv=None):
"""コマンドラインから注文IDと--rootオプションを受け取る。"""
# argparseを使うと、入力方法を示す--helpも自動で利用できます。
parser = argparse.ArgumentParser(
description="GMO FX APIから注文・約定・建玉・決済損益を取得します。"
)
parser.add_argument(
"order_id",
nargs="?",
help="確認する注文ID(省略時はGMO FXから候補を取得)",
)
parser.add_argument(
"--root",
action="store_true",
help="指定値を親注文IDとして扱い、IFDOCOの関連注文をまとめて取得します。",
)
parser.add_argument(
"--symbol",
default="USD_JPY",
help="注文ID候補を取得する通貨ペア(初期値: USD_JPY)",
)
args = parser.parse_args(argv)
# GMO FXの注文IDは数字なので、誤った値をAPIへ送る前にチェックします。
if args.order_id is not None and not args.order_id.isdigit():
parser.error("order_idには数字だけを指定してください。")
if args.root and args.order_id is None:
parser.error("--rootを使う場合は親注文IDも指定してください。")
return args
def main(argv=None):
# PowerShellで指定された注文IDとオプションを読み取ります。
args = parse_args(argv)
# 注文IDが省略された場合は、CSVではなくGMO FX APIから候補を取得します。
order_id = args.order_id
if order_id is None:
candidates = find_order_candidates(args.symbol)
order_id = select_order_id(candidates)
# GMO FX APIから関連情報を取得します。
result = get_trade_result(order_id, use_root_order_id=args.root)
# APIのJSONをそのまま表示せず、確認しやすい日本語へ整理して表示します。
display_trade_result(result)
# このファイルを直接実行したときだけmain()を動かします。
if __name__ == "__main__":
main()
GMO FX APIで取得できる注文結果とは

GMO FX APIでは、注文後の状態を確認するために、主に以下の情報を取得します。
- 注文情報
- 約定情報
- 建玉情報
- 決済結果・損益
それぞれ確認できる内容が異なるため、まずは違いを整理しておきます。
注文情報・約定情報・建玉情報の違い
注文情報では、注文価格や数量、現在の注文ステータスなどを確認できます。
一方、約定情報では、実際に約定した価格や数量を確認します。
建玉情報では、現在保有しているポジションの内容を確認できます。
簡単に整理すると、以下のような違いです。
| 情報 | 確認する内容 |
|---|---|
| 注文情報 | 注文が現在どの状態か |
| 約定情報 | いくら・どの数量で約定したか |
| 建玉情報 | 現在ポジションを保有しているか |
| 決済結果 | いくらで決済され、損益はいくらだったか |
特に注意したいのは、注文が受け付けられたことと、約定したことは別という点です。
指値注文などでは、注文後すぐに約定しない場合もあるため、注文情報と約定情報を分けて確認する必要があります。
エントリーから決済結果を取得するまでの流れ
エントリー後の結果確認は、以下の流れで行います。
注文を送信
↓
注文状況を確認
↓
約定情報を確認
↓
建玉を確認
↓
TP・SLなどで決済
↓
決済結果・損益を確認
今回作成するスクリプトでは、この流れに沿ってGMO FX APIから必要な情報を取得します。
前の記事で注文したデータを使って結果を確認することもできますが、確認したい注文IDを指定すれば、このスクリプト単体でも使用できる構成にします。
注文結果を取得するtrade_result.pyを紹介

今回使用するtrade_result.pyでは、GMO FX APIから注文情報・約定情報・建玉情報を取得し、エントリー後の取引状況を確認します。
注文IDを指定して実行できるほか、注文IDが分からない場合は、有効注文と直近の約定情報から候補を表示して選択することも可能です。
また、IFDOCO注文の場合はrootOrderIdをもとに、エントリー・TP・SLに関連する注文をまとめて取得します。
今回使用するtrade_result.pyのコードは以下です。
"""GMO FX APIから注文・約定・建玉・決済損益を取得するサンプル。"""
import argparse
import hashlib
import hmac
import json
import os
import ssl
import time
from decimal import Decimal, InvalidOperation
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
import certifi
# ============================================================
# 【重要な注意点】
# ============================================================
# 同じGMO FXアカウントで、このスクリプトを複数のターミナルから
# 同時に実行しないでください。
#
# GMO FX Private APIの呼び出し回数は、同一アカウント単位で合算されます。
# 複数のターミナルや別のスクリプトから同時にAPIへアクセスすると、
# 1秒間の呼び出し上限を超えてAPIエラーになる可能性があります。
# 使い方:
# 1. PowerShellを開き、このファイルを保存したフォルダへ移動します。
# cd GMO-API
# 2. APIキーとAPIシークレットをPowerShellへ入力します。
# 実際の値は、このPythonファイルへ直接書かないでください。
#
# $env:GMO_FX_API_KEY="実際のAPIキー"
# $env:GMO_FX_SECRET_KEY="実際のAPIシークレット"
#
# この方法では入力内容がPowerShellの履歴に残る場合があります。
# 共用パソコンなどで履歴へ残したくない場合は、Read-Hostを使用してください。
#
# 3. 注文IDを指定せずに実行すると、GMO FXから有効注文と最新約定を取得し、
# 表示された候補から確認する注文を選択できます。CSVは使用しません。
# latestExecutionsで取得できるのは直近1日分から最新100件までです。
# 数日前などの古い注文は、注文IDを直接指定してください。
# python trade_result.py
# 4. 注文IDが分かっている場合は、実行時に直接指定することもできます。
# python trade_result.py 123456789
# 5. IFDOCOの親注文IDを直接指定する場合は、--rootを付けます。
# python trade_result.py 123456789 --root
# 6. 通貨ペアの初期値はUSD_JPYです。変更する場合は--symbolを付けます。
# python trade_result.py --symbol EUR_USD
# 7. 入力した環境変数は、そのPowerShellウィンドウを閉じると引き継がれません。
# 注文情報、約定情報、建玉情報の取得に使うGMO FX Private APIの接続先です。
# Private APIの利用には、PowerShellで入力したAPIキーとAPIシークレットが必要です。
PRIVATE_URL = "https://forex-api.coin.z.com/private"
# PowerShellでAPIキーとAPIシークレットを設定するときの環境変数名です。
# ここに認証情報そのものは書きません。実際の値はPowerShellから入力します。
# このファイル内に定義しているため、live_config.pyなど別ファイルは必要ありません。
API_KEY_ENV = "GMO_FX_API_KEY"
SECRET_KEY_ENV = "GMO_FX_SECRET_KEY"
# GMO FX Private APIのGET上限へ余裕を持って対応するため、
# 各リクエストの前に0.5秒待機します。
REQUEST_INTERVAL_SECONDS = 0.5
# certifiが持っている証明書一覧を使って、HTTPS通信の証明書を検証します。
# Windows環境でCERTIFICATE_VERIFY_FAILEDになる場合の対策です。
SSL_CONTEXT = ssl.create_default_context(cafile=certifi.where())
def list_items(data):
"""data内の明細をリストへそろえる。"""
# data自体がリストの場合は、そのまま返します。
if isinstance(data, list):
return data
# ordersなどのAPIは、data内のlistに明細が入っています。
if isinstance(data, dict):
rows = data.get("list", [])
return rows if isinstance(rows, list) else []
# データがない場合も、後続処理で安全に繰り返せるよう空リストを返します。
return []
def private_get(path, params, api_key=None, secret_key=None):
"""環境変数の認証情報で署名し、Private APIへGET送信する。"""
# 認証情報の値はコードに保存せず、PowerShellで入力された環境変数から取得します。
api_key = api_key or os.environ.get(API_KEY_ENV)
secret_key = secret_key or os.environ.get(SECRET_KEY_ENV)
# どちらかが未設定なら、認証できないためAPIへアクセスする前に処理を止めます。
if not api_key or not secret_key:
raise RuntimeError(
f"PowerShellで環境変数 {API_KEY_ENV} と "
f"{SECRET_KEY_ENV} を設定してください。"
)
# API-TIMESTAMPへ設定する、現在時刻のミリ秒単位UNIX時刻を作ります。
timestamp = str(int(time.time() * 1000))
method = "GET"
# GMO FXのGET署名にはクエリ文字列を含めません。
# 「時刻 + HTTPメソッド + APIパス」を連結した文字列が署名対象です。
sign_text = timestamp + method + path
# APIシークレットを使い、HMAC-SHA256形式の署名を作ります。
signature = hmac.new(
secret_key.encode("ascii"), sign_text.encode("ascii"), hashlib.sha256
).hexdigest()
# GMO FX Private APIの認証に必要な3項目をHTTPヘッダーへ設定します。
headers = {
"API-KEY": api_key,
"API-TIMESTAMP": timestamp,
"API-SIGN": signature,
}
# 注文IDや通貨ペアなどの検索条件をURLのクエリ文字列へ変換します。
query = "?" + urlencode(params) if params else ""
request = Request(PRIVATE_URL + path + query, headers=headers, method=method)
try:
# GMO FXへ連続でアクセスしすぎないよう、通信前に一定時間待ちます。
# 0.5秒間隔にすることで、このスクリプトからのGETを最大約2回/秒に抑えます。
time.sleep(REQUEST_INTERVAL_SECONDS)
# タイムアウトを20秒に設定してAPIへアクセスし、JSONをPythonの辞書へ変換します。
with urlopen(request, context=SSL_CONTEXT, timeout=20) as response:
payload = json.loads(response.read().decode("utf-8"))
except HTTPError as error:
# HTTPステータスがエラーの場合、APIキーなどを表示せずステータス番号だけ伝えます。
raise RuntimeError(f"GMO FX APIとの通信に失敗しました(HTTP {error.code})。") from error
except (URLError, TimeoutError) as error:
# ネットワーク切断やタイムアウトを、利用者に分かるエラーへ変換します。
raise RuntimeError(f"GMO FX APIへ接続できませんでした: {error}") from error
# GMO FX APIは正常時にstatus=0を返します。0以外なら処理を止めます。
if int(payload.get("status", -1)) != 0:
raise RuntimeError(f"GMO FX APIエラー: {payload.get('messages')}")
# 呼び出し元では共通項目を除いたdata部分だけを使用します。
return payload.get("data")
def get_trade_result(order_id, use_root_order_id=False, private_get_func=private_get):
"""注文IDを起点に、関連する注文・約定・有効建玉を取得する。"""
# --rootが付いていれば親注文ID、なければ通常の注文IDとして検索します。
id_type = "rootOrderId" if use_root_order_id else "orderId"
orders = list_items(private_get_func("/v1/orders", {id_type: order_id}))
# 注文が見つからなければ、約定や建玉も空の結果として返します。
if not orders:
return {"orders": [], "executions": [], "open_positions": []}
# 通常の注文IDが指定された場合も、親注文IDをたどってIFDOCOを構成する
# エントリー・TP・SLの全注文を取得する。
if not use_root_order_id:
root_order_id = orders[0].get("rootOrderId")
if root_order_id is not None:
related_orders = list_items(
private_get_func("/v1/orders", {"rootOrderId": root_order_id})
)
if related_orders:
orders = related_orders
# IFDOCOを構成する各注文について、約定情報を1件ずつ取得してまとめます。
# executions APIはorderIdを1つずつ指定して呼び出します。
executions = []
for order in orders:
current_order_id = order.get("orderId")
# レスポンスに注文IDがない不完全な明細は、誤照会を防ぐため読み飛ばします。
if current_order_id is None:
continue
rows = list_items(
private_get_func("/v1/executions", {"orderId": current_order_id})
)
executions.extend(rows)
# 約定に含まれる建玉IDだけを照合する。対象銘柄が複数でも確認できるよう、
# 銘柄ごとに有効建玉一覧を取得する。
# 約定情報から建玉IDを取り出します。
# 同じ建玉IDが複数回現れても、setにすることで重複を除けます。
position_ids = {
str(row["positionId"])
for row in executions
if row.get("positionId") is not None
}
# 建玉一覧APIは通貨ペアで検索するため、注文から対象通貨ペアを取り出します。
symbols = sorted({row.get("symbol") for row in orders if row.get("symbol")})
open_positions = []
for symbol in symbols if position_ids else []:
# 同じ通貨ペアの有効建玉を最大100件取得します。
rows = list_items(
private_get_func("/v1/openPositions", {"symbol": symbol, "count": 100})
)
# 口座内の別の建玉を混ぜないよう、対象注文の建玉IDと一致するものだけ残します。
open_positions.extend(
row for row in rows if str(row.get("positionId")) in position_ids
)
return {
"orders": orders,
"executions": executions,
"open_positions": open_positions,
}
def find_order_candidates(symbol, private_get_func=private_get):
"""GMO FXから有効注文と最新約定を取得し、注文IDの候補を作る。"""
# activeOrdersには、まだ約定・取消されていない注文が入っています。
active_orders = list_items(
private_get_func("/v1/activeOrders", {"symbol": symbol, "count": 100})
)
# latestExecutionsには、直近1日分から最新100件までの約定が入っています。
# 決済済み注文はactiveOrdersから消えるため、こちらも候補へ加えます。
latest_executions = list_items(
private_get_func("/v1/latestExecutions", {"symbol": symbol, "count": 100})
)
# 注文IDをキーにして重複を除きます。
# 同じ注文が有効注文と約定情報の両方に含まれても、候補には1回だけ表示します。
candidates = {}
for order in active_orders:
order_id = order.get("orderId")
if order_id is None:
continue
candidates[str(order_id)] = {
"order_id": str(order_id),
"root_order_id": str(order.get("rootOrderId", "")),
"symbol": order.get("symbol", symbol),
"side": order.get("side", "-"),
"settle_type": order.get("settleType", "-"),
"status": order.get("status", "有効注文"),
"timestamp": order.get("timestamp", "-"),
}
for execution in latest_executions:
order_id = execution.get("orderId")
if order_id is None or str(order_id) in candidates:
continue
candidates[str(order_id)] = {
"order_id": str(order_id),
# 約定情報には親注文IDがないため、選択後にorders APIから取得します。
"root_order_id": "",
"symbol": execution.get("symbol", symbol),
"side": execution.get("side", "-"),
"settle_type": execution.get("settleType", "-"),
"status": "約定済み",
"timestamp": execution.get("timestamp", "-"),
}
# 新しい候補から確認できるよう、APIの日時文字列で降順に並べます。
return sorted(candidates.values(), key=lambda row: row["timestamp"], reverse=True)
def select_order_id(candidates, input_func=input):
"""候補番号または手入力された注文IDを受け取る。"""
print("\n【GMO FXから取得した注文ID候補】")
print(
"注文IDを省略した場合は、有効注文と直近1日分の最新約定から候補を表示します。"
)
print("過去の注文を確認する場合は、注文IDを直接指定してください。")
if candidates:
for number, row in enumerate(candidates, start=1):
print(
f"{number}. 注文ID={row['order_id']} "
f"親注文ID={row['root_order_id'] or '-'} "
f"{row['symbol']} {row['side']} {row['settle_type']} "
f"{row['status']} {row['timestamp']}"
)
prompt = "候補番号または確認する注文IDを入力してください: "
else:
print("有効注文または最新約定から注文IDを取得できませんでした。")
prompt = "確認する注文IDを入力してください: "
entered = input_func(prompt).strip()
# 1から候補件数までの数字なら、画面に表示した候補番号として扱います。
if entered.isdigit() and 1 <= int(entered) <= len(candidates):
return candidates[int(entered) - 1]["order_id"]
# 候補番号に該当しない数字は、注文IDの直接入力として扱います。
if entered.isdigit():
return entered
raise ValueError("候補番号または数字の注文IDを入力してください。")
def decimal_sum(rows, field):
"""APIの数値文字列をDecimalで安全に合計する。"""
# 金額計算ではfloatの丸め誤差を避けるためDecimalを使います。
total = Decimal("0")
for row in rows:
try:
total += Decimal(str(row.get(field, "0")))
except (InvalidOperation, TypeError):
# 数値へ変換できない項目があっても、ほかの明細の集計を続けます。
pass
return total
def display_trade_result(result):
"""取得結果を、注文・約定・建玉・決済の順に表示する。"""
# get_trade_result()が返した3種類の情報を取り出します。
orders = result["orders"]
executions = result["executions"]
open_positions = result["open_positions"]
if not orders:
print("指定した注文IDの注文情報は見つかりませんでした。")
return
# 注文情報では、受付中・約定・取消など各注文の現在の状態を確認できます。
print("\n【注文情報】")
for order in orders:
print(f"注文ID: {order.get('orderId', '-')}")
print(f" 親注文ID: {order.get('rootOrderId', '-')}")
print(f" 通貨ペア: {order.get('symbol', '-')}")
print(f" 売買: {order.get('side', '-')} / 区分: {order.get('settleType', '-')}")
print(f" 注文方法: {order.get('executionType', '-')}")
print(f" 注文数量: {order.get('size', '-')}")
print(f" 注文価格: {order.get('price', '成行注文のため指定なし')}")
print(f" ステータス: {order.get('status', '-')}")
if order.get("cancelType"):
print(f" 取消理由: {order['cancelType']}")
# 約定情報には、実際に取引が成立した価格・数量・損益が入っています。
print("\n【約定情報】")
if not executions:
print("約定情報はありません。注文が未約定または取消済みの可能性があります。")
for execution in executions:
print(f"約定ID: {execution.get('executionId', '-')}")
print(f" 注文ID: {execution.get('orderId', '-')}")
print(f" 建玉ID: {execution.get('positionId', '-')}")
print(f" 売買: {execution.get('side', '-')} / 区分: {execution.get('settleType', '-')}")
print(f" 約定価格: {execution.get('price', '-')}")
print(f" 約定数量: {execution.get('size', '-')}")
print(f" 決済損益: {execution.get('lossGain', '0')}")
print(f" 決済スワップ: {execution.get('settledSwap', '0')}")
print(f" 取引手数料: {execution.get('fee', '0')}")
print(f" 約定日時: {execution.get('timestamp', '-')}")
# 約定から得た建玉IDが有効建玉一覧に残っているかを表示します。
print("\n【建玉情報】")
if open_positions:
print("対象注文から作られた建玉が残っています。")
for position in open_positions:
print(
f"建玉ID: {position.get('positionId', '-')} / "
f"数量: {position.get('size', '-')} / "
f"建玉価格: {position.get('price', '-')} / "
f"評価損益: {position.get('lossGain', '-')}"
)
else:
print("対象注文に関連する有効建玉はありません。")
# settleType=CLOSEだけを取り出し、決済損益の集計対象にします。
close_executions = [
row for row in executions if row.get("settleType") == "CLOSE"
]
# 約定の注文IDから元の注文方法を引けるよう、注文情報を辞書にします。
order_by_id = {str(row.get("orderId")): row for row in orders}
print("\n【決済結果】")
if not close_executions:
print("決済約定はまだ確認できません。")
return
for execution in close_executions:
order = order_by_id.get(str(execution.get("orderId")), {})
execution_type = order.get("executionType")
# このIFDOCOサンプルでは、決済LIMITがTP、決済STOPがSLです。
# 別の方法で発注した注文では、必ずしもこの判定になるとは限りません。
if execution_type == "LIMIT":
reason = "TP(指値)"
elif execution_type == "STOP":
reason = "SL(逆指値)"
else:
reason = f"{execution_type or '不明'}注文"
print(f"注文ID {execution.get('orderId', '-')}: {reason}で決済")
# 複数回に分かれて約定した場合も、各金額をそれぞれ合計します。
loss_gain_total = decimal_sum(close_executions, "lossGain")
settled_swap_total = decimal_sum(close_executions, "settledSwap")
fee_total = decimal_sum(close_executions, "fee")
# 公式仕様に記載された3項目を分けて表示します。
# feeの符号を使った最終損益の計算方法は公式仕様に明記されていないため、
# このサンプルでは「最終損益」を独自に計算しません。
print(f"決済損益合計: {loss_gain_total}")
print(f"決済スワップ合計: {settled_swap_total}")
print(f"取引手数料合計: {fee_total}")
def parse_args(argv=None):
"""コマンドラインから注文IDと--rootオプションを受け取る。"""
# argparseを使うと、入力方法を示す--helpも自動で利用できます。
parser = argparse.ArgumentParser(
description="GMO FX APIから注文・約定・建玉・決済損益を取得します。"
)
parser.add_argument(
"order_id",
nargs="?",
help="確認する注文ID(省略時はGMO FXから候補を取得)",
)
parser.add_argument(
"--root",
action="store_true",
help="指定値を親注文IDとして扱い、IFDOCOの関連注文をまとめて取得します。",
)
parser.add_argument(
"--symbol",
default="USD_JPY",
help="注文ID候補を取得する通貨ペア(初期値: USD_JPY)",
)
args = parser.parse_args(argv)
# GMO FXの注文IDは数字なので、誤った値をAPIへ送る前にチェックします。
if args.order_id is not None and not args.order_id.isdigit():
parser.error("order_idには数字だけを指定してください。")
if args.root and args.order_id is None:
parser.error("--rootを使う場合は親注文IDも指定してください。")
return args
def main(argv=None):
# PowerShellで指定された注文IDとオプションを読み取ります。
args = parse_args(argv)
# 注文IDが省略された場合は、CSVではなくGMO FX APIから候補を取得します。
order_id = args.order_id
if order_id is None:
candidates = find_order_candidates(args.symbol)
order_id = select_order_id(candidates)
# GMO FX APIから関連情報を取得します。
result = get_trade_result(order_id, use_root_order_id=args.root)
# APIのJSONをそのまま表示せず、確認しやすい日本語へ整理して表示します。
display_trade_result(result)
# このファイルを直接実行したときだけmain()を動かします。
if __name__ == "__main__":
main()
trade_result.pyで行う処理
trade_result.pyでは、主に以下の流れで注文後の結果を確認します。
- 確認する注文IDを取得する
- 注文情報を取得する
- IFDOCOの関連注文を取得する
- 各注文の約定情報を取得する
- 関連する建玉が残っているか確認する
- TP・SLなどの決済結果を確認する
- 決済損益・スワップ・手数料を表示する
注文IDを指定した場合は、まずGMO FX APIの注文情報から対象の注文を取得します。
通常の注文IDを指定した場合でも、取得したrootOrderIdを使って関連する注文を再取得するため、IFDOCOを構成する注文をまとめて確認できます。
続いて、それぞれのorderIdを使って約定情報を取得します。
約定情報からは、約定価格・約定数量・約定日時などを確認可能です。
また、positionIdをもとに有効建玉を照合し、対象のポジションが現在も残っているかを確認します。
最後に、決済済みの約定がある場合は、決済方法と損益を表示します。
今回のIFDOCO注文では、決済注文がLIMITならTP、STOPならSLとして表示し、決済損益・決済スワップ・取引手数料もそれぞれ確認が可能です。
処理の流れをまとめると、以下のようになります。
注文IDを取得
↓
注文情報を取得
↓
IFDOCOの関連注文を取得
↓
約定情報を取得
↓
建玉を確認
↓
決済結果・損益を表示
なお、trade_result.pyはlive_config.pyなどの別ファイルを必要とせず、APIキーとAPIシークレットを環境変数へ設定すれば単体で実行できます。
GMO FX APIから注文結果を取得する3ステップ

ここからは、作成したtrade_result.pyを使って、実際にGMO FX APIから注文結果を取得します。
手順は以下の3ステップです。
- 確認する注文IDを用意する
trade_result.pyを実行する- 取得した注文結果を確認する
1つずつ詳しく見ていきましょう。
ステップ1|確認する注文IDを用意する
まずは、結果を確認したい注文IDを用意します。
注文IDが分かっている場合は、そのままtrade_result.pyの実行時に指定できます。
python trade_result.py 123456789
IFDOCOの親注文IDを指定して、関連する注文をまとめて確認したい場合は、--rootを付けて実行します。
python trade_result.py 123456789 --root
一方、注文IDが分からない場合は、注文IDを指定せずに実行することもできます。
python trade_result.py
この場合は、GMO FX APIから有効注文と直近1日分の最新約定を取得し、確認できる注文IDの候補が表示されます。
なお、数日前などの古い注文は候補に表示されない場合があります。
過去の注文を確認する場合は、GMOの取引画面などで注文IDを確認し、実行時に直接指定してください。
ステップ2|trade_result.pyを実行する
注文IDを確認したら、PowerShellを開いてtrade_result.pyを保存したフォルダへ移動します。
cd GMO-API
次に、GMO FX APIのAPIキーとAPIシークレットを環境変数へ設定します。
$env:GMO_FX_API_KEY="実際のAPIキー"
$env:GMO_FX_SECRET_KEY="実際のAPIシークレット"
APIキーとAPIシークレットは、Pythonファイルへ直接記述しないようにしてください。
環境変数を設定したら、trade_result.pyを実行します。
python trade_result.py
注文IDを指定せずに実行した場合は、以下のように注文候補が表示されます。
【GMO FXから取得した注文ID候補】
1. 注文ID=123456789 ...
2. 注文ID=987654321 ...
候補番号または確認する注文IDを入力してください:
確認したい注文の番号を入力すると、その注文をもとに注文情報・約定情報・建玉情報などが取得されます。
なお、USD/JPY以外の通貨ペアから注文候補を取得したい場合は、--symbolを指定します。
python trade_result.py --symbol EUR_USD
今回のスクリプトでは、通貨ペアの初期値を「USD_JPY」に設定しています。
ステップ3|取得した注文結果を確認する
スクリプトを実行すると、取得した結果が以下の4つに分けて表示されます。
- 注文情報
- 約定情報
- 建玉情報
- 決済結果
注文情報では、注文ID・通貨ペア・売買方向・注文価格・注文ステータスなどを確認できます。
約定済みの場合は、約定情報として以下の内容も表示されます。
- 約定ID
- 建玉ID
- 約定価格
- 約定数量
- 決済損益
- 決済スワップ
- 取引手数料
- 約定日時
対象のポジションがまだ残っている場合は、建玉情報に建玉ID・数量・建玉価格・評価損益が表示されます。
すでに決済されている場合は、決済結果からTP・SLのどちらで決済されたのかを確認が可能です。
あわせて、
- 決済損益合計
- 決済スワップ合計
- 取引手数料合計
も表示されます。
これで、エントリー注文を出したあとに、約定したのか・現在も建玉が残っているのか・最終的にどのように決済されたのかをPythonから確認できます。
取得した注文結果の見方

trade_result.pyを実行すると、「注文情報」「約定情報」「建玉情報」「決済結果」が順番に表示されます。
ここでは、それぞれの結果から確認しておきたいポイントを解説します。
注文が約定したか確認する
まずは「注文情報」のステータスを確認します。
trade_result.pyでは、注文ごとに以下のような情報が表示されます。
【注文情報】
注文ID: 123456789
親注文ID: 987654321
通貨ペア: USD_JPY
売買: BUY / 区分: OPEN
注文方法: LIMIT
注文数量: 10000
注文価格: 150.000
ステータス: EXECUTED
特に確認したいのが「ステータス」です。
EXECUTEDになっていれば注文は約定しています。
一方、まだ注文が有効な状態であれば、注文は受け付けられていても約定していない可能性があるのです。
また、注文が約定している場合は、後述する「約定情報」にも実際の約定内容が表示されます。
trade_result.pyでは、注文価格や数量、注文方法、ステータスなどをまとめて確認が可能です。
約定価格と約定数量を確認する
注文が約定している場合は、「約定情報」を確認しましょう。
【約定情報】
約定ID: 111111111
注文ID: 123456789
建玉ID: 222222222
売買: BUY / 区分: OPEN
約定価格: 150.002
約定数量: 10000
決済損益: 0
決済スワップ: 0
取引手数料: 0
約定日時: 2026-08-07T10:00:00.000Z
ここでは主に、
- 約定価格
- 約定数量
- 約定日時
を確認します。
指値価格と実際の約定価格が必ず同じになるとは限らないため、実際にどの価格で取引が成立したのかは「約定価格」で確認しましょう。
また、1つの注文が複数回に分かれて約定した場合は、複数の約定情報が表示されます。
スクリプトでは、それぞれの注文IDから約定情報を取得して表示しています。
建玉が残っているか確認する
エントリー注文が約定したあとは、「建玉情報」を確認しましょう。
対象のポジションがまだ決済されていない場合は、以下のように表示されます。
【建玉情報】
対象注文から作られた建玉が残っています。
建玉ID: 222222222 / 数量: 10000 / 建玉価格: 150.002 / 評価損益: 1500
ここでは、
- 建玉ID
- 保有数量
- 建玉価格
- 評価損益
を確認できます。
一方、すでにTP・SLなどで決済されている場合は、
対象注文に関連する有効建玉はありません。
と表示されます。
trade_result.pyでは、約定情報から取得したpositionIdと現在の有効建玉を照合して、対象のポジションが残っているか確認しています。
TP・SLで決済されたか確認する
ポジションが決済されている場合は、「決済結果」を確認しましょう。
今回のIFDOCO注文では、決済注文の種類からTP・SLを判定します。
【決済結果】
注文ID 333333333: TP(指値)で決済
決済注文がLIMITの場合は「TP(指値)」、STOPの場合は「SL(逆指値)」として表示します。
これにより、IFDOCOで発注した注文が最終的に利確されたのか、損切りされたのかを確認が可能です。
なお、この判定は今回使用しているIFDOCO注文を前提としています。
別の方法で注文した場合は、LIMITが必ずTP、STOPが必ずSLになるとは限らないため注意してください。
決済損益を確認する
最後に、決済後の損益を確認しましょう。
決済が完了している場合は、以下の3項目が表示されます。
決済損益合計: 4000
決済スワップ合計: 0
取引手数料合計: 0
それぞれの意味は以下のとおりです。
| 項目 | 内容 |
|---|---|
| 決済損益 | エントリー価格と決済価格による損益 |
| 決済スワップ | 決済時に確定したスワップ |
| 取引手数料 | 約定に対して発生した手数料 |
trade_result.pyでは、複数回に分かれて決済された場合にも対応できるよう、それぞれの決済約定から金額を取得して合計しています。
なお、今回のサンプルでは「最終損益」を独自に計算せず、GMO FX APIから取得した決済損益・決済スワップ・取引手数料をそれぞれ分けて表示しています。
注文結果を取得する際の注意点

trade_result.pyを使用する際は、IFDOCO注文の仕組みやGMO FX APIの利用制限に注意が必要です。
ここでは、今回のスクリプトを使用する前に確認しておきたいポイントを以下の4つ紹介します。
- IFDOCOでは複数の注文IDが発生する
- Private APIの呼び出し上限に注意する
- TP・SLの判定は今回のIFDOCO注文を前提とする
- APIキーとAPIシークレットを公開しない
1つずつ詳しく見ていきましょう。
IFDOCOでは複数の注文IDが発生する
IFDOCO注文では、1回の発注でも複数の注文IDが発生します。
たとえば今回の構成では、
エントリー注文
├ TPの決済注文
└ SLの決済注文
のように、エントリー・TP・SLそれぞれに注文IDが割り当てられます。
さらに、これらの注文をまとめるためのrootOrderIdも存在します。
今回のtrade_result.pyでは、通常のorderIdを指定した場合でも、その注文からrootOrderIdを取得し、IFDOCOに関連する注文をまとめて確認が可能です。
親注文IDが分かっている場合は、以下のように--rootを付けて直接指定もできます。
python trade_result.py 123456789 --root
Private APIの呼び出し上限に注意する
GMO FXのPrivate APIには、APIを呼び出せる回数に上限があります。
現在の公式仕様では、同一アカウントからのPrivate API呼び出しは、
- GET:1秒間に6回まで
- POST:1秒間に1回まで
となっています。
また、システムの負荷状況によって一時的に制限が変更される場合もあるのです。
今回のtrade_result.pyではGET APIを複数回使用するため、連続アクセスを避ける目的で、各リクエストの前に0.5秒待機するようにしています。
REQUEST_INTERVAL_SECONDS = 0.5
なお、APIの呼び出し上限は同一アカウント単位です。
そのため、trade_result.pyだけでなく、同じGMO FXアカウントを使用する別のPythonスクリプトを同時に実行している場合も注意してください。
TP・SLの判定は今回のIFDOCO注文を前提とする
今回のtrade_result.pyでは、決済注文の種類からTP・SLを判定しています。
具体的には、
LIMIT → TP
STOP → SL
として表示します。
これは、今回使用しているIFDOCO注文で、
- TPを指値注文(LIMIT)
- SLを逆指値注文(STOP)
として発注しているためです。
実際のコードでも、決済注文がLIMITなら「TP(指値)」、STOPなら「SL(逆指値)」として表示しています。
ただし、これはすべての注文方法で共通する判定ではありません。
別の方法で決済注文を作成している場合は、LIMITが必ずTP、STOPが必ずSLになるとは限らないため、使用している注文方法に合わせて判定処理を変更してください。
APIキーとAPIシークレットを公開しない
GMO FXのPrivate APIを使用するには、APIキーとAPIシークレットが必要です。
これらが第三者に漏れると、口座情報を取得されたり、意図しない注文や取消などを実行されたりする可能性があります。
そのため、APIキーとAPIシークレットをPythonファイルへ直接書くのは避けましょう。
$env:GMO_FX_API_KEY="実際のAPIキー"
$env:GMO_FX_SECRET_KEY="実際のAPIシークレット"
今回のtrade_result.pyでは、上記のようにPowerShellの環境変数から認証情報を取得します。
これにより、GitHubやブログへコードを公開する場合でも、実際の認証情報をコード内に含めずに済むのです。
GMO FX APIの注文結果取得に関するよくある質問

ここでは、GMO FX APIから注文結果を取得する際によくある疑問をまとめます。
注文結果の取得にAPIキーは必要ですか?
はい、必要です。
今回使用する注文情報・約定情報・建玉情報はGMO FXのPrivate APIから取得するため、APIキーとAPIシークレットを使った認証が必要です。
trade_result.pyでは、APIキーとAPIシークレットをPowerShellの環境変数から取得する構成にしています。
注文IDが分からなくても結果を確認できますか?
はい、直近の注文であれば確認できます。
注文IDを指定せずに、
python trade_result.py
を実行すると、有効注文と直近1日分の最新約定から注文候補が表示されます。
表示された候補から確認したい注文を選択すれば、その注文結果を取得できます。
ただし、数日前などの古い注文は候補に表示されない場合があるため、その場合は注文IDを直接指定してください。
決済後の損益は取得できますか?
はい、取得できます。
今回のtrade_result.pyでは、決済済みの約定情報から以下の項目を取得して表示します。
- 決済損益
- 決済スワップ
- 取引手数料
複数回に分かれて決済された場合は、それぞれの値を合計して表示します。
まとめ

今回は、GMO FX APIを使って注文後の結果を取得する方法を紹介しました。
作成したtrade_result.pyでは、注文IDをもとに以下の情報を確認できます。
- 注文状況
- 約定価格・約定数量
- 建玉の有無
- TP・SLによる決済結果
- 決済損益・スワップ・取引手数料
また、注文IDが分からない場合でも、有効注文や直近の約定情報から候補を表示して確認できます。
これまでに作成してきたローソク足取得・バックテスト・エントリー処理と組み合わせることで、
ローソク足取得
↓
バックテスト
↓
リアルタイム判定・エントリー
↓
注文結果・決済損益の確認
という、Pythonを使ったFX自動売買の一連の流れを確認できるようになります。
ローソク足取得・バックテスト・エントリー処理の作成がまだの人は、以下の記事を参考に作ってみてください。
実際に運用する際は、Private APIの呼び出し上限やAPIキー・APIシークレットの管理にも注意しながら使用してください。
