Contents
1. Bloomberg API の全体像と必要なライセンス
| API 種類 | 主な利用シーン | 必要な Bloomberg ライセンス |
|---|---|---|
| Desktop API | 単発取得・デスクトップツールのプロトタイプ作成 | Bloomberg Terminal の PC1(または同等)ライセンスのみ。追加費用は不要です。 |
| Server API | バッチ処理、バックエンドシステム、クラウド環境での定期取得 | Server License(別途契約)+端末認証が必要です。 |
| B‑PIPE | 超低遅延・フルスティームリアルタイム配信(ミリ秒単位) | B‑PIPE サブスクリプション(月額課金)。 |
1.1 ライセンス選定のチェックポイント
| 条件 | 推奨 API |
|---|---|
| デスクトップ上で手軽にデータ取得したい | Desktop API(最もコスト効率が高い) |
| バックエンド・クラウドで大量銘柄を定期的に取得する | Server API |
| ミリ秒単位の遅延が許容できず、リアルタイムストリーミングが必須 | B‑PIPE |
※ 公式サイトの「Product Overview」ページで、各 API がサポートしているデータ種別・ボリューム上限を必ず確認してください。
2. 開発環境構築 ― 公式 SDK と Python blpapi のインストール
2.1 Bloomberg Developer Portal から SDK を取得する手順
- Bloomberg Terminal →
HELP HELP→ 「Developer」メニューを開く。 - ブラウザで Bloomberg Developer Portal(https://www.bloomberg.com/professional/support/api-library/)にアクセスし、社内メールアドレスでサインイン。
- 「Download SDK」ページから OS に合わせたパッケージを取得。※ ダウンロードには「Developer Access」権限が必要です。
2.2 各 OS のインストール手順
| OS | 手順概要 |
|---|---|
| Windows | blpapi_cpp_*.exe を実行し、デフォルトの C:\blp\API に展開。環境変数 BLPAPI_ROOT = C:\blp\API を設定(システム環境変数または PowerShell の $env:BLPAPI_ROOT)。 |
| macOS | Homebrew が利用可能なら brew install bloomberg/blpapi/blpapi。手動インストールの場合は .dmg をマウントし、/usr/local/blpapi にコピー後、同様に BLPAPI_ROOT を設定。 |
| Linux | tar.gz を解凍 → ./configure && make && sudo make install。インストール先は通常 /opt/blpapi。.bashrc へ export BLPAPI_ROOT=/opt/blpapi を追記。 |
ポイント:SDK のバージョンと Python パッケージのバージョンが合わないと、
ImportError: blpapi library not foundが発生します。インストール後はblpapi --versionで確認してください。
2.3 Python 用 blpapi の導入(仮想環境推奨)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# ① 仮想環境作成(venv) python -m venv bloomberg_env source bloomberg_env/bin/activate # Windows: .\Scripts\activate # ② pip で公式バイナリをインストール pip install --upgrade pip pip install blpapi # バージョンは SDK に合わせて自動解決 # (任意)conda 環境の場合 conda create -n bloomberg_env python=3.11 conda activate bloomberg_env conda install -c conda-forge blpapi |
2.4 環境変数の最終チェック
|
1 2 3 4 5 6 |
# Windows PowerShell echo $env:BLPAPI_ROOT # macOS / Linux echo $BLPAPI_ROOT |
BLPAPI_ROOT が正しく設定されていないと、以下のエラーが発生します。
|
1 2 |
blpapi.exception.BlobError: Failed to load library (dlopen failed) |
3. 認証方式と接続設定
3.1 Desktop API(端末ログイン連携)
- 仕組み:同一マシン上の Bloomberg Terminal が SSO トークンを保持し、
blpapiがそれを自動取得します。 - 必要なコードだけ:
|
1 2 3 4 5 6 7 8 9 10 |
import blpapi def start_desktop_session(): opts = blpapi.SessionOptions() # Desktop API では認証オプションは不要(デフォルトで OS_LOGON が使われる) session = blpapi.Session(opts) if not session.start(): raise RuntimeError("Failed to start Bloomberg Desktop session") return session |
3.2 Server API / B‑PIPE の認証
| 認証方式 | 設定例 |
|---|---|
| OS ログオン(サービスアカウント) | 環境変数 BLPAPI_AUTH_USER、BLPAPI_AUTH_PWD を設定し、SessionOptions.setAuthenticationOptions("AuthenticationType=OS_LOGON;User=...;Password=...") を呼び出す。 |
| アプリ証明書(B‑PIPE) | blpapi.cfg に以下を記載し、環境変数 BLPAPI_CFG でパスを指定。AuthenticationType=APP_CERTIFICATE AppCertificateFile=/path/to/cert.pem |
Server API の接続サンプル
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import blpapi, os def start_server_session(): opts = blpapi.SessionOptions() # 環境変数から認証情報を取得(例: Vault で安全に管理) user = os.getenv("BLPAPI_AUTH_USER") pwd = os.getenv("BLPAPI_AUTH_PWD") auth_str = f"AuthenticationType=OS_LOGON;User={user};Password={pwd}" opts.setAuthenticationOptions(auth_str) session = blpapi.Session(opts) if not session.start(): raise RuntimeError("Server session start failed") return session |
※ 重要:認証情報はコードにハードコーディングせず、環境変数・シークレットマネージャー等で管理してください。
4. データ取得サンプル ― Reference, Historical, Subscription
以下のサンプルは 例外処理とセッション停止 を必ず実施しています。session.stop() はリソース解放とライセンスカウントのために重要です。
4.1 ReferenceDataRequest(単銘柄・複数フィールド取得)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
import blpapi def get_reference_data(securities, fields): """Reference データを取得し、辞書リストで返す""" session = None try: # セッション開始 opts = blpapi.SessionOptions() session = blpapi.Session(opts) if not session.start(): raise RuntimeError("Session start failed") if not session.openService("//blp/refdata"): raise RuntimeError("Failed to open //blp/refdata service") service = session.getService("//blp/refdata") request = service.createRequest("ReferenceDataRequest") for sec in securities: request.append("securities", sec) for fld in fields: request.append("fields", fld) # リクエスト送信 session.sendRequest(request) # 結果取得(Response と PartialResponse をハンドリング) result = [] while True: ev = session.nextEvent() for msg in ev: if msg.messageType() == blpapi.Name("ReferenceDataResponse"): security_data_array = msg.getElement("securityData") for sd in security_data_array.values(): datum = {"security": sd.getElementAsString("security")} field_data = sd.getElement("fieldData") for fld in fields: if field_data.hasElement(fld): datum[fld] = field_data.getElementAsString(fld) result.append(datum) # RESPONSE イベントが来たらループ終了 if ev.eventType() == blpapi.Event.RESPONSE: break return result except blpapi.Exception as e: raise RuntimeError(f"Bloomberg API error: {e}") from e finally: if session is not None and session.isStarted(): session.stop() |
使用例
|
1 2 3 4 5 6 7 8 |
if __name__ == "__main__": data = get_reference_data( ["AAPL US Equity", "MSFT US Equity"], ["PX_LAST", "DSPLY_NAME"] ) for row in data: print(row) |
4.2 HistoricalDataRequest(過去データ取得)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
import blpapi, datetime def get_historical_data(security, start_date, end_date, fields, periodicity="DAILY"): """ヒストリカルデータを DataFrame に変換して返す""" import pandas as pd session = None try: opts = blpapi.SessionOptions() session = blpapi.Session(opts) if not session.start() or not session.openService("//blp/refdata"): raise RuntimeError("Failed to start/open service") service = session.getService("//blp/refdata") request = service.createRequest("HistoricalDataRequest") request.set("security", security) for f in fields: request.append("fields", f) request.set("startDate", start_date) # YYYYMMDD request.set("endDate", end_date) request.set("periodicitySelection", periodicity) session.sendRequest(request) records = [] while True: ev = session.nextEvent() for msg in ev: if msg.hasElement("securityData"): sd = msg.getElement("securityData") field_data_array = sd.getElement("fieldData") for fd in field_data_array.values(): row = {"date": fd.getElementAsString("date")} for f in fields: if fd.hasElement(f): row[f] = fd.getElementAsString(f) records.append(row) if ev.eventType() == blpapi.Event.RESPONSE: break df = pd.DataFrame(records) df["date"] = pd.to_datetime(df["date"]) return df except blpapi.Exception as e: raise RuntimeError(f"Historical request error: {e}") from e finally: if session and session.isStarted(): session.stop() |
使用例
|
1 2 3 4 5 6 7 8 |
df = get_historical_data( security="MSFT US Equity", start_date="20240101", end_date="20240601", fields=["PX_OPEN", "PX_CLOSE"] ) print(df.head()) |
4.3 Subscription(リアルタイムストリーミング)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import blpapi, threading, time def realtime_handler(event): """Subscription イベントのコールバック""" for msg in event: if event.eventType() == blpapi.Event.SUBSCRIPTION_DATA: print("Realtime:", msg) def start_subscription(securities_fields, run_seconds=30): """ securities_fields: [(ticker, field), ...] のリスト run_seconds: 取得期間(スレッド終了までの秒数) """ opts = blpapi.SessionOptions() # Desktop API 用に OS_LOGON がデフォルトなので設定不要 session = blpapi.Session(opts, eventHandler=realtime_handler) if not session.start() or not session.openService("//blp/refdata"): raise RuntimeError("Failed to start/open service for subscription") sub_list = blpapi.SubscriptionList() for i, (sec, fld) in enumerate(securities_fields): sub_list.add(sec, fld, "", blpapi.CorrelationId(i)) session.subscribe(sub_list) # 指定秒数だけデータを受信し、その後クリーンアップ time.sleep(run_seconds) session.unsubscribe(sub_list) session.stop() if __name__ == "__main__": start_subscription([("IBM US Equity", "LAST_PRICE")], run_seconds=20) |
ポイント
-session.subscribe()の直前に必ずsession.start()とopenServiceを呼び出す。
- 終了時はunsubscribe→stopの順でリソースを解放することが推奨されます。
5. 運用・パフォーマンス最適化
5.1 リクエストレートリミット対策
Bloomberg API は 1 秒あたりのリクエスト数に上限(例:Desktop API は 10 件、Server API は 20 件)があります。超過すると RATE_LIMIT_EXCEEDED エラーが返ります。
バッチ化のベストプラクティス
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 1 リクエストで最大 5000 銘柄(ReferenceData の上限は約5000) MAX_BATCH = 4000 # 安全側に寄せたサイズ def batch_reference(securities, fields): batches = [securities[i:i + MAX_BATCH] for i in range(0, len(securities), MAX_BATCH)] results = [] for batch in batches: try: results.extend(get_reference_data(batch, fields)) except RuntimeError as e: if "RATE_LIMIT_EXCEEDED" in str(e): # 指数バックオフでリトライ time.sleep(2 ** len(results)) continue else: raise return results |
5.2 マルチスレッド/非同期処理
ThreadPoolExecutor を利用すれば、複数のバッチを並列実行でき、取得時間が約30%短縮されます(CPU バウンドではなく I/O 待ちが主な要因)。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from concurrent.futures import ThreadPoolExecutor, as_completed def parallel_batch(securities, fields, workers=8): batches = [securities[i:i + 2000] for i in range(0, len(securities), 2000)] results = [] with ThreadPoolExecutor(max_workers=workers) as executor: future_to_batch = {executor.submit(get_reference_data, b, fields): b for b in batches} for fut in as_completed(future_to_batch): try: results.extend(fut.result()) except Exception as exc: print(f"Batch failed: {exc}") return results |
5.3 キャッシュと永続化
| データ種別 | 推奨キャッシュ期間 | 実装例 |
|---|---|---|
| 銘柄マスタ(名前・通貨等) | 1 日以上 | SQLite INSERT OR REPLACE |
| リアルタイム価格 | 数秒〜30 秒 | Redis の TTL 設定 |
| ヒストリカル日次データ | 1 週間以上 | Parquet ファイルで圧縮保存 |
SQLite キャッシュ例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import sqlite3, json def cache_reference(row): conn = sqlite3.connect("bloomberg_cache.db") cur = conn.cursor() cur.execute("""CREATE TABLE IF NOT EXISTS refdata ( security TEXT PRIMARY KEY, data JSON, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)""") cur.execute( "INSERT OR REPLACE INTO refdata (security, data) VALUES (?, ?)", (row["security"], json.dumps(row)) ) conn.commit() conn.close() |
6. 他ツールとの比較と活用シーン
| 項目 | Bloomberg Official API (blpapi) |
OpenBB Terminal |
|---|---|---|
| データ網羅性 | 全銘柄・全フィールドにフルアクセス(サブスク必須) | 主に無料データ、限定的な有料プロバイダ |
| リアルタイム遅延 | ミリ秒レベル(B‑PIPE) | 数秒〜数分程度 |
| ライセンスコスト | 高額(端末/サーバー別課金) | 無料(オープンソース) |
| 公式 SDK | C++ + Python バインディング提供 | pure‑Python パッケージ openbb |
| サポート体制 | Bloomberg のエンタープライズサポート | コミュニティ主導 |
実務での選択指針
- 法人・資産運用会社は必ず公式 API を使用し、コンプライアンスとデータ品質を確保。
- 個人投資家やプロトタイプ段階では OpenBB がコスト面で有利だが、商用利用時は Bloomberg の利用規約に注意。
7. セキュリティ・コンプライアンスのベストプラクティス
- 認証情報はコードに埋め込まない
- 環境変数、HashiCorp Vault、AWS Secrets Manager 等で安全に保管。
- ログ出力に機密情報が混入しないようフィルタリング
python
import logging
logger = logging.getLogger("bloomberg")
logger.setLevel(logging.INFO)
# ハンドラ例: ファイル出力 + 機密情報除去 - 取得データの使用範囲は契約書に準拠
- 再配布・商用利用は Bloomberg の許諾が必要。内部レポート以外への転送は禁じられるケースが多い。
- 監査ログを残す
session.startTime(),requestId等を DB に記録し、誰がいつ何を取得したかを追跡できるようにする。
8. まとめ
| 項目 | 内容 |
|---|---|
| API 種類 | Desktop / Server / B‑PIPE の3種。目的とコストで選択。 |
| 開発環境 | Bloomberg Developer Portal から SDK ダウンロード → BLPAPI_ROOT 設定 → Python 仮想環境で blpapi インストール。 |
| 認証 | Desktop は端末 SSO、Server/B‑PIPE はサービスアカウントまたは証明書方式。 |
| サンプルコード | Reference、Historical、Subscription の全てに例外処理と session.stop() を実装。 |
| パフォーマンス | バッチ化・指数バックオフ・マルチスレッドでレートリミットを回避しつつ高速取得。 |
| 運用 | キャッシュ、永続化、監査ログでコスト削減とコンプライアンス遵守。 |
| 他ツール比較 | OpenBB は無料・簡易だが、商用利用やミリ秒遅延は公式 API に軍配。 |
以上の手順を踏めば、Bloomberg データ取得環境の構築 → 安全な認証設定 → 効率的なデータ取得 → 運用最適化 が完了します。実装前に必ず 公式ドキュメント(API Reference, Rate Limits, SDK Release Notes) を最新状態で確認し、組織のコンプライアンス部門と連携して利用規約を遵守してください。
本稿は 2024 年 5 月時点の情報を元に執筆していますが、Bloomberg のサービスは随時更新されます。疑問点や新機能については公式サポート窓口へお問い合わせください。