デリバティブ偏愛家の日記

インタラクティブ・ブローカーズ証券のAPIをPythonで操作する データ取得編

前回の準備編に続き、今回は実際にコードを書いてヒストリカルデータを取得します。

※前回はこちら

インタラクティブ・ブローカーズ証券のAPIをPythonで操作する 準備編

 

前提として

本来、APIのパッケージをIB証券のサイトからダウンロードしても、ゼロから何か作ろうとすると、大量の関数を定義したりと諸々面倒なんですが、IBPyだとパッケージの中に組み込まれているので、結構楽です。筆者はIBPyを知る前にC#で実装を試みましたが、最初から面倒過ぎて萎えました。

また、この記事だけでなく公式のマニュアルも参照されることをお勧めします。

http://interactivebrokers.github.io/tws-api/index.html

 

API側の制約条件

いきなりですが、これこそIBPy関係無いので公式マニュアルが一番確実です。

 

足種の条件

データ取得量が極端に大きくならないように以下のような制約があります。

取得期間に応じた足のサイズ
取得期間 最小 最大
1分 1秒 1分
2分 1秒 2分
30分 1秒 30分
1時間 5秒 1時間
4時間 10秒 3時間
8時間 30秒 8時間
1日 1分 1日
2日 2分 1日
1週 3分 1週
1月 30分 1月
1年 1日 1月

 

時間内取得上限

以下に抵触するとデータ取得が停止するので要注意です。

  1. 同一の銘柄の同一データを15秒以内に要求する
  2. 同一銘柄、取引所、ティックタイプのデータで、2秒以内に6回以上要求する
  3. 10分以内に60回以上データを要求する

1、2は「お前、それならヒストリカルデータじゃなくてリアルタイムデータを取得しろよ」というところでしょうか。定期的にバッチでヒストリカルデータを取る際に最も問題となるのは3です。BidとAskは別物扱いなので、同一銘柄でそれぞれ取ると2回とカウントされるのも要注意。

 

大まかな流れ

概要的な説明ですが。流れとしては、

  1. IB証券に接続
  2. 銘柄の定義
  3. ヒストリカルデータ要求
  4. ヒストリカルデータ受信
  5. 切断

となります。要求と受信が別工程なのがポイントです。以下で各項毎に説明していきますが、末尾に全体のまとめを置いておきます。結論だけコピペしたい方はそちらへ。

 

1.IB証券に接続

ここで使うポート番号とクライアントidですが、これはTWSの「グローバルコンフィグ/API/設定」の以下の欄で確認できます(若干関係無いところも囲われてますが…)。

 

2.銘柄の定義

取得する対象となる銘柄を定義する訳ですが、取扱銘柄が膨大ということもあって、かなりきちんと定義してあげる必要があります。また、株や先物、為替といったアセットクラス毎に若干異なるので、厳密にはIB証券のAPIマニュアルを参照する方が安全ですが。基本的には、

  • symbol:銘柄の名称※
  • sec_type:アセットクラス(為替の場合、”CASH”になるので注意)
  • currency:原通貨
  • exchange:そのまんま

※「symbol」には「localSymbol」という別の定義方法もあります。先物の銘柄指定において、満期を別途パラメータで定義せずに、一気に銘柄名の中に組み込んでしまう方法で、TWS上で「金融商品情報」で下のような画面が出てきます。ここの赤枠で囲った「シンボル」が「localSymbol」です(分かり難いですが、これは「symbol」としては使えません)。

で、非常に厄介なんですが、この例(米2Y国債先物)で表示されている「ZT  SEP 18」ですが、この文字列の間のスペースの数まで正確に再現してパラメータとして渡さないとエラーになります(この場合、ZTとSEPの間にスペース×2)。なので、一旦コピペすることをオススメします。筆者はこの「localSymbol」を使っていますが、人によっては満期を別途パラメータで渡す方式の方が楽に感じるかもしれません。

先に関数で銘柄情報を定義しています。先物だけは先程の「localSymbol」を使う影響で、「sec_type」による条件分岐が必要になります。さらに先物側では逆に「symbol」は空にしておかないとエラーになるので(ループ等で前の銘柄の「symbol」が残る可能性がある)、「None」を入れます。

また、ヒストリカルデータを取る際に、既に満期を迎えた先物はデフォルトでは取得対象になりません。なので、先物に関しては「m_includeExpired」を「True」にしておきます。結局この例ではUSDJPYを銘柄として指定してますが。

※「FXは取引所どこやねん!」という話ですが、「IDealPRO」がIB証券のFXプラットフォームのようなので、これを指定してあげます。

 

3.ヒストリカルデータ要求

まず先に要求するデータのタイプを指定する必要がありますが、先物には最終取引価格(TRADES)がありますが、FXにはその概念が無いので、ここでは「MIDPOINT」を取得対象としています。ここはお好みで。それよりも重要なのは、返ってくるのは「指定したデータの四本値」ということです。つまり「Bid」と指定するとBidのOpen/High/Low/Close(と取引量)が返ってきます。

基本的には、「ある特定の日時から、特定の期間遡って、特定の足のデータを取ってくる」という遡及型の取り方になります。上記の例では当日から過去3日間の30分足を要求しています。「ib_conn.reqHistoricalData」関数の細かいパラメータはAPIマニュアルにも書いてありますが、ここでも順番に説明します。

  1. ticker Id:データ取得に使う固有の番号です。注文番号のようなものでしょうか。好き勝手に決めて良いですが、ループする際に重複しないように。未検証ですが、切断するまで重複不可な気がします(たぶん前のデータが出てくる)。
  2. 銘柄:先程定義したものです。
  3. 終了日時:上の例では現在の日時を入れています。
  4. 取得期間:そのまんまですが、「3」と「D」の間の謎のスペースも再現して下さい。そうしないとエラーになります。シビアです。
  5. 足のサイズ:上と同じく。
  6. 取得対象データ:この他にはBidやAskは勿論、Implied volatilityも取れるようですが、個別のオプションを指定しないと取れない(「日経平均」という銘柄に対していきなりIVは取れず、「日経平均オプション2018年9月限22,500円Call」のIVなら取れる模様?)ようです。
  7. 通常取引時間以外を含めるか:「1」で”含む”、「0」で”含まない”です。夜間取引をわざわざ取り除きたいケースがあるのか不明ですが、普通は1で良いかと。
  8. 日時表示のフォーマット:なんか忘れましたが(おい)、ここでは受信したデータをこちらで変換しているので「0」でデフォルトにしていた気がします。
  9. 最終四本値の処理:例えば日足で、まだその日が終わっていないのに、その日の今時点での四本値を取るか否か指定します。

 

4.ヒストリカルデータ受信

ここでは要求したデータが返ってきた時に受信する関数(historical_data_handler)を作っておきます。返ってきたデータは全て「msg.」の後ろにパラメータを指定してあげることで特定できます(全然メッセージっぽくないですが、システム的にはメッセージ扱いらしい)。上記の例では、まず「msg.date」で日時を取得し、ごちゃごちゃと操作して日付をDBに入れる型に変換していますが、ここはお好みで。

その先では、Open/High/Low/Close/Volumeを個別で取ってnumpyの配列に突っ込んでいます。因みにFXのVolumeは全て「-1」で返ってきます。FXしかやらない方は「msg.volume」はスルーで良いかと。

結構な銘柄数でループする場合は、この「ib_conn.register」の後に「time.sleep」を入れて調整してあげた方が良いかと思います。というのも、先に記載した時間内取得上限に抵触する恐れがあるので。

 

5.切断

流石に簡単ですね。

 

全体像の確認

細切れではない、最終的なコードが以下です。

 

次回は発注編です。

Tagged on: ,

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です