kabuステーション®APIのプログラムの書き方【初心者向け】

※この文章は、Pythonにてご説明させていただきます。

こんにちは!システム開発部のLUと申します。よろしくお願いいたします。

kabuステーション®APIをリリースしてすでに半年以上たちました。プログラムで自由にトレードできることが特徴で、多くのお客様にご利用いただいております。その中、ITリテラシーの高いユーザが多い一方、プログラミング経験のないお客様には敬遠されているのも実情です。プログラミング無経験のお客様でも「使いたいですが、どうすればいいでしょうか」というお声を多数いただいておりますので、このブログでは、APIの仕組みないしプログラムレベルでのkabuステーション®APIの使い方をご紹介いたします。

このブログで得られるスキル:

■サンプルコード抜きで、リファレンスだけで、最低限のプログラムが書けるようになること
■効率的なサンプルコードの使い方を習得できること

1. APIとは

Wikipeidaによりますと、APIは以下のように定義されています。

「アプリケーションプログラミングインタフェース(API、英: Application Programming Interface)とは、広義ではソフトウェアコンポーネント同士が互いに情報をやりとりするのに使用するインタフェースの仕様である。

さっぱりわかりませんね。では、ラーメン屋さんの例でご説明いたします。

まず結論からですが、APIとは、ラーメンへの好みやこだわりを反映できる自由な注文方式です。ラーメンを注文する時に、お店側が提供するメニューから好きなラーメンを選択するというのが一般的です。また、麺の硬さやトッピングの種類などをお店に伝える場合もあります。しかし、このような注文方式では、麺のゆで時間等に対し強いこだわりを持つお客様にとっては、満足できないかもしれません。「xxがもっとxxにできたら完璧ですね」と思う人が必ずいるでしょう。そのようなお客様には、麺の種類、ゆで時間、チャーシューを作る肉の部位、作り方など、より豊かな選択肢を与えることで、その人にとっての唯一無二の最高のラーメンが出来上がるでしょう。このようなオリジナリティ注文方式は、ITの世界においてAPIというものになります。

kabuステーション®に戻って再度考えてみましょう。今皆様はkabuステーション®というラーメン屋さんに来ました。先ほどのラーメンは、kabuステーション®で注文を出すことまたは銘柄情報等を確認することに相当します。例えば、xx銘柄にビッグニュースが発生したときに、当該銘柄をすぐにトレードしたいとします。通常のやり方では、発注パネル等の画面を開いて、成行や指値等の執行条件を指定し、「確認」ボタンをクリックし、パスワードを入力して初めて、発注という行為が完了となります。この一連の操作をしたら、望んでいるトレードタイミングが過ぎてしまう可能性があります。一方、API(オリジナリティ注文方式)では、トレードタイミングが出現した間もない頃、当該銘柄に対する注文はプログラムで自動的に行うというような独特な注文方法ができるようになるのです。APIの活躍シーンは想像力の数だけありますので、ぜひマスターしていただきたいと思います。

2. プログラムを書きましょう

早速ですが、トークン発行のサンプルコード(kabusapi_token.py)で、プログラムの書き方をご説明いたします。

f:id:dragonminion:20210329184815p:plain
プログラムの書き方
一言で説明しますと、①のツールを使い、②のデータを③のところへ持っていき、④の方法で処理させた後、望んだ形の処理結果を返してもらう、ということになります。これはプログラムを書くための基本的な考え方です。

2-0. リファレンス

コードを書く前に、まずリファレンスを開き、赤枠の情報を確認してください。これらの情報は、これから書くプログラムの内容を決めるための重要な情報です。

f:id:dragonminion:20210225181203p:plain
リファレンス
①データタイプ

②データ

③URL(データの処理場所)

2-1. ツール

すでに気付かれているかと思いますが、kabusapi_websocket.py以外のどのサンプルコードを開いても、冒頭に必ず次の3行のコードが書かれています。この「import xxx」は、別のファイルに記述されたPythonコードを取り込む機能のことを意味します。理解しやすくするために、ここであえて「ツール」と呼んでいます。

f:id:dragonminion:20210225181516p:plain
import
ラーメンの例に戻って説明しますと、ラーメンを作るための鍋、ガスコンロ、食材等は、すべて種類ごとの箱にしまっていると考えてください。ラーメンを作る時、それぞれの箱を開けて必要なものを取り出さなければなりません。importは「箱を開ける」ことに相当し、箱の中の物を使って初めて、ラーメンが作れます。

Importの後ろにあるもの(ライブラリ)の意味の説明はここで割愛させていただきますが、調べてもわからない方はそのままプログラムを書いてください。

2-2. データ

ラーメンを注文するときに、まず食べたいラーメンをお店側に伝え、その後ラーメンが出されます。ITの世界では、食べたいラーメンをお店側に伝えることは「Request(リクエスト)」、ラーメンが出されることは「Response(レスポンス)」といいます。ここで、Requestする内容をあえて「データ」と呼んでいます。では、2-0のリファレンスの「②データ」を見ながら、この部分のプログラムの書き方をご紹介いたします。

f:id:dragonminion:20210329185651p:plain
データの書き方
リファレンスの「APIPassword」というものに実際の「APIパスワード」を付与する必要がありますので、上図の書き方をしています。リファレンスの「②-2」のような書き方でも問題ございません(全く同じものです)。ここでは、文字列や辞書型、代入等の概念が潜んでいますが、その説明は割愛させていただきます。

「お店に注文したいもの」が用意できましたが、このステップはまだ終わっていません。食券機を導入するお店に行って、口頭で「xxxラーメンをください」と言っても、注文が受け付けられません。つまり、注文内容をお店側が認めた形に変換しなければなりません。

再度リファレンスに戻って、①の「application/json」を見てください。これはkabuステーション®APIが認めるデータのタイプです。もっと説明しますと、上記の辞書型のobjをJSON形式に変換するプログラムが必要なのです。これを実現するプログラムは下記です。

f:id:dragonminion:20210225183522p:plain
データ型変換
これで、トークンを発行するための「データ」のプログラムがすべて完了となります。

しかし、objとjson_dataが書かれていないサンプルコード(例:kabusapi_symbol.py)も存在しますが、これはなぜでしょうか?リファレンスの③にある「POST」は原因です。

kabuステーション®APIのリクエストには、「xxxをxxxしてください」という能動的なPOST/PUT形式と、「xxxを送ってきてください」という受身的なGET形式が存在します。ラーメン屋さんに入って、注文をしなければラーメンが出てこないのですが、これはPOST/PUT形式のリクエストです。一方、何も注文しなくても、店内に座るだけで、お冷(セルフサービスのお店は考慮せず)が運ばれてきますよね。これはGET形式のリクエストです。POST/PUT形式のリクエストをする際に、必ずルール(つまり、注文内容をお店側が認めた形に変換すること)に従わなければなりませんが、GET形式のリクエストをする際に出てきたものをそのまま受け取ればいいです。

2-3. 処理場所

麺をゆでるために、必ず麺をガスコンロへ持っていき、そこで調理しなければなりません。同様で、データが用意できましたので、次は適切な宛先へ持っていくのです。リファレンスを見ながらプログラムを書きましょう。

f:id:dragonminion:20210225215341p:plain
URL
本番用URLあるいは検証用URLのいずれかを書いてください。宛先を書いた後、2-2の章で定義したjson_dataを添付して、リクエスト文を書きましょう。一番後ろにmethodがありますが、何を付与すればいいかはリファレンスを確認してください。
f:id:dragonminion:20210225215557p:plain
req
次のプログラムは、レスポンス形式をAPIサーバーに指定するためのものです。JSON形式で返してね、という意味です。
f:id:dragonminion:20210225215732p:plain
req.add_header

2-4. 処理実行及びレスポンス形式の指定

サンプルコードの12行目から25行目を書きましょう。

f:id:dragonminion:20210226094151p:plain
try except
ちなみに、上記赤枠の部分は省略可能です。赤枠を含めてプログラムを実行したときに、レスポンス文は下記のように、レスポンス状態を示す内容が記載されます。トークン発行をする際や銘柄情報を取得する際など、欲しい情報のみもらえばいいわけですので、レスポンス状態がなくても問題ないと考えております。一方、レスポンス状態が欲しい方は当然このプログラムを含める必要がありますので、ご自身で判断していただければと思います。
f:id:dragonminion:20210401094919p:plain
レスポンス状態文
以上、プログラムの基本の書き方をご紹介いたしました。リファレンスのみでプログラムが書けるようになりましたでしょうか?

3. オリジナルのロジックを組みましょう

冒頭に申した通り、APIの利用シーンは想像力の数だけありますので、ここではすべてのシーンを網羅することが不可能です。ただし、こうすればより効率的にサンプルコードを使えますよという角度で、次のサンプルコードをご紹介したいと思います。

結論から申しますと、このサンプルコードを使えば、発行したトークンを他のサンプルコードにコピーペーする手間を省けることが可能です。銘柄情報取得(kabusapi_symbol.py)を例としてご説明いたします。

プログラム初心者にとって、次のような使い方でサンプルコードを利用することが多いのではないかと思います。例えば、銘柄情報を取得する時に、

■kabusapi_token.pyを実行し、トークンを発行する
■生成されたトークンをコピーする
■kabusapi_symbol.pyを開き、トークンをペーストする
■kabusapi_symbol.pyを実行し、銘柄情報を取得する

このように、kabuステーション®を再起動、再ログインするたびに、トークンを発行し直し、他のサンプルコードの間で行ったり来たりしなければなりません。このような利用方法では、kabuステーション®APIの強みを全く発揮していないのです。実は、プログラムを少し変えるだけで、上記の手間がなくなります。

難易度によって、2種類のプログラムを用意しましたので、ご自身のスキルに合わせて、一番理解しやすいサンプルコードをご利用ください。

3-1. シンプルバージョン

考え方としては、トークン発行のサンプルコード(kabusapi_token.py)と他のサンプルコードを合併するだけです。 ここの重要な変更点としては、「token_value」という変数を定義し、それを銘柄情報取得のサンプルコードのトークンを記載する部分に代入することです。

import urllib.request
import json
import pprint

# トークン発行
obj = { 'APIPassword': 'xxxxxx' }
json_data = json.dumps(obj).encode('utf8')

url = 'http://localhost:18080/kabusapi/token'
req = urllib.request.Request(url, json_data, method='POST')
req.add_header('Content-Type', 'application/json')

try:
    with urllib.request.urlopen(req) as res:
        content = json.loads(res.read())
        token_value = content.get('Token')
        pprint.pprint(token_value)
except urllib.error.HTTPError as e:
    print(e)
    content = json.loads(e.read())
    pprint.pprint(content)
# トークン発行

# 銘柄情報取得
url_symbol = 'http://localhost:18080/kabusapi/symbol/1450@1'
req_symbol = urllib.request.Request(url_symbol, method='GET')
req_symbol.add_header('X-API-KEY', token_value)

try:
    with urllib.request.urlopen(req_symbol) as res_symbol:
        content_symbol = json.loads(res_symbol.read())
        pprint.pprint(content_symbol)
except urllib.error.HTTPError as e_symbol:
    print(e_symbol)
    content_symbol = json.loads(e_symbol.read())
    pprint.pprint(content_symbol)
# 銘柄情報取得

3-2. アドバンスバージョン

トークン発行の関数と銘柄情報取得の関数を定義することにより、構文がより簡潔になります。

import urllib.request
import pprint
import json


def generate_token():
    obj = {'APIPassword': 'xxxxxx'}
    json_data = json.dumps(obj).encode('utf8')
    url = 'http://localhost:18080/kabusapi/token'
    req = urllib.request.Request(url, json_data, method='POST')
    req.add_header('Content-Type', 'application/json')
    try:
        with urllib.request.urlopen(req) as res:
            content = json.loads(res.read())    
            token_value = content.get('Token')
    except urllib.error.HTTPError as e:
        print(e)
    return token_value

def get_symbol(token):
    url_symbol = 'http://localhost:18080/kabusapi/symbol/1450@1'
    req_symbol = urllib.request.Request(url_symbol, method='GET')   
    req_symbol.add_header('X-API-KEY', token)
    try:
        with urllib.request.urlopen(req_symbol) as res_symbol:
            content_symbol = json.loads(res_symbol.read())
    except urllib.error.HTTPError as e_symbol:
        print(e_symbol)
        content_symbol = json.loads(e_symbol.read())
    return content_symbol

token_value = generate_token()
pprint.pprint(get_symbol(token_value))