ウィブル証券APIで国内株を取引する (PHP版)

eスマート証券のAPIがスマホ認証必須となり、完全自動売買ができなくなりました。

そこで、国内株取引APIを使える証券会社を探していたところ、ウィブル証券がAPIを無料で提供しているらしい、という情報を見つけたので試しに使ってみることにしました。


ドキュメントと仕様

まず、外資系の会社なだけあってAPIドキュメントはすべて英語です。

2026年2月現在、国内向けAPIはまだ開発途中といった印象でドキュメントに誤字があったり仕様と実際のAPIの挙動が異なっている箇所も見受けられました。

また致命的なのは、なぜか株価を取得する機能が用意されていない点です。

自分の場合、株価は別のAPIから取得しているため実運用上は問題ありませんが、正直これは早めに対応してほしいところです。今後の改善に期待といった感じです。

APIの仕様については、認証処理がやや厄介そうでPythonやJava向けにはSDKが用意されているため、それらを使って取引する前提という雰囲気でした。


PHPで認証処理を作る

自分はPHPしか使っていないので必須となる認証処理を自前で作ってみました。ここさえ乗り越えれば、取引部分は仕様書を見ながら普通に実装できそうです。

///=======================================================================
//   *Webull API 用の署名付きヘッダーを生成する関数
///=======================================================================

function _webullHeaders($path , $query_params = [] , $body_ary = []){

	$timestamp = gmdate("Y-m-d\TH:i:s\Z");
	$nonce     = bin2hex(random_bytes(16));
	$host      = parse_url(WB_API_BASEURL , PHP_URL_HOST);

	//---署名対象マップ
	$map = [
		"x-app-key"             => $this->config_app_key,
		"x-signature-algorithm" => "HMAC-SHA1",
		"x-signature-version"   => "1.0",
		"x-signature-nonce"     => $nonce,
		"x-timestamp"           => $timestamp,
		"host"                  => $host,
	];

	//---クエリパラメータも署名対象に追加
	foreach ($query_params as $k => $v) {
		$map[$k] = $v;
	}

	//---POST用のBODYハッシュ
	$s2 = "";
	if (!empty($body_ary)) {
		$s2 = strtoupper(md5(json_encode($body_ary, JSON_UNESCAPED_SLASHES)));
	}

	ksort($map, SORT_STRING);

	$parts = [];
	foreach ($map as $k => $v) {
		$parts[] = $k . "=" . $v;
	}
	$s1 = implode("&", $parts);

	//---署名元文字列
	$source = $path . "&" . $s1;

	if ($s2 !== "") {
		$source .= "&" . $s2;
	}

	$encoded = rawurlencode($source);

	//---HMAC-SHA1 + Base64
	$signKey   = $this->config_secret_key . "&";
	$rawHmac   = hash_hmac("sha1", $encoded, $signKey , true);
	$signature = base64_encode($rawHmac);

	//---リクエストヘッダー
	return [
		"x-app-key: {$this->config_app_key}" ,
		"x-timestamp: {$timestamp}" ,
		"x-signature-version: 1.0" ,
		"x-signature-algorithm: HMAC-SHA1" ,
		"x-signature-nonce: {$nonce}" ,
		"x-signature: {$signature}"
	];
}

PHP以外の言語を使っている方でも、処理の流れや考え方については参考になると思います。

$path = "/trade/orders/list-open";

$params_ary = [
	"account_id" => $this->config_account_id ,
	"page_size" => 100 ,
];

$header_ary = $this->_webullHeaders($path , $params_ary , $body_ary);

HTTP通信時に使用する専用のヘッダーを生成するというイメージです。

株価取得などの取得系APIでは、bodyは空になるケースがほとんどですが、発注系APIではbodyに銘柄情報や数量などのデータが含まれます。

この関数で生成したヘッダーをそのまま使ってcURLで通信すれば、APIは問題なく通ります。


日本株(現物)発注時のパラメータ例

$body_ary["new_orders"] = [[

	"instrument_type" => "EQUITY" ,
	"symbol" => $p_code ,
	"market" => "JP" ,
	"side" => ($p_side === 'buy') ? "BUY" : "SELL" ,
	"order_type" => "LIMIT" , //指値注文
	"limit_price" => $p_price ,
	"quantity" => $p_qty ,
	"support_trading_session" => "N" , //ザラ場のみ
	"time_in_force" => "GTC" , //最大90日間
	"entrust_type" => "QTY" ,
	"client_order_id" => 20260209010203 ,
	"account_tax_type" =>  ($p_mode) ? "SPECIFIC" : "GENERAL" , //特定口座/一般口座
]];

ハマった点として、なぜかパラメータを二重配列にしないと注文が通りません。理由はよく分かりませんが、現状ではこの形式にしないとエラーになります。


アカウントIDとは?

APIを利用するには「ACCOUNT_ID / APP_KEY / SECRET_KEY」が必要になりますが、最初に悩むのが ACCOUNT_ID とは何を指しているのか、という点です。

APP_ID?アプリケーション名?それとも口座番号?

正解は、ACCOUNT_IDを省略して実行できる /openapi/account/list API のレスポンスに含まれているIDです。

このACCOUNT_IDは、管理画面やアプリ作成時には明示されておらず/openapi/account/list を実行して初めて取得できます。


まとめ

現時点で国内株の取引が可能なAPIを提供している証券会社は以下の3社です。

  • eスマート証券:スマホ認証またはメール認証
  • 立花証券 e支店:初回実行時の電話発信認証
  • ウィブル証券:追加の認証なし

ウィブル証券は外資系なだけあって、署名付きヘッダー + ACCOUNT_ID + APP_KEY + SECRET_KEY という形でAPIレベルの認証はかなりガチガチに固められています。

それでも不正利用されるなら、それは自己責任でしょ、という思考なのかなと思いました。

実際、WEBログインとAPIログインで同じ認証情報を使っている某社や、取引パスワードが4桁の数字だけで通ってしまう某社と比べると安全性は段違いだと思います。

将来的に仕様変更が入る可能性はありますが、現状では一番使い勝手が良いためメインの取引APIとして使っていく予定です!