auカブコム kabuステーション自動取引プログラムの作り方(3) 初心者はWeb APIの呼び出しを数珠繋ぎでつなげよう

スポンサーリンク

Web APIの呼び出しは面倒くさい

普通のプログラムであれば

trade()

みたいな感じで、簡単に関数やメソッドの呼び出しが行えます。

しかし、kabuステーションAPIもそうなのですが、最近のトレンドであるOpen APIというものはWeb経由での自分のマシンとは別のサーバに対する呼び出しなので、その呼び出し方法が少し面倒くさいです。

JavaやPythonやJavaScriptやC#など、いろいろな言語の開発者がそこを簡単にしようと日夜頑張っていますが、そこまで簡単にはなっていません。

たとえば、株価を取得する呼び出しだけでも、kabuステーションの公式サンプルでPythonで以下のコードが必要になっています。

import urllib.request
import json
import pprint

url = 'http://localhost:18080/kabusapi/board/5401@1'
req = urllib.request.Request(url, method='GET')
req.add_header('Content-Type', 'application/json')
req.add_header('X-API-KEY', 'ed94b0d34f9441c3931621e55230e402')

try:
    with urllib.request.urlopen(req) as res:
        print(res.status, res.reason)
        for header in res.getheaders():
            print(header)
        print()
        content = json.loads(res.read())
        pprint.pprint(content)
except urllib.error.HTTPError as e:
    print(e)
    content = json.loads(e.read())
    pprint.pprint(content)
except Exception as e:
    print(e)
kabucom/kabusapi
kabuステーションAPI ポータル. Contribute to kabucom/kabusapi development by creating an account on GitHub.

面倒くさいのは18行目以降のexcept以降の記載です。この部分は、非同期通信の異常系の処理といって、サーバとの通信や呼び出しで何らかのエラーが発生した場合に動くロジックです。

普通のプログラムだと

// 株価チェック
board_check()
// 発注
order()

のように、単純に処理を続けてプログラムに書くことができます。

そして、もしシステムに異常が起こったら、プログラムが勝手に終了してくれます。

それは、そういう異常が滅多に起きないので、プログラム言語の仕様として「それが起こったらもうどうしようもない」と割り切ってしまっているからです。

しかし、非同期通信の異常系は比較的よくあることなので、プログラム言語仕様で勝手に終了してくれません。

したがって、順番に上から下に流れない、異常系のジャンプするような処理のことを考えなくてはいけません。

プログラミングの歴史の初期に複雑で分かりにくくなるからと批判された「GOTO文」にちょっと似ています

一つのtry~exceptの中で無理やりつなげると、読みにくくてしょうがない

そこでまず、簡単に思いつく解決策として、

「1つのtry~exceptにすべてのWeb API呼び出しをぶち込む」

というものがあります。

例えば、先ほどの株価取得と発注のWeb API呼び出しをつなげると

import urllib.request
import json
import pprint


try:

    # 株価所得
    url = 'http://localhost:18080/kabusapi/board/5401@1'
    req = urllib.request.Request(url, method='GET')
    req.add_header('Content-Type', 'application/json')
    req.add_header('X-API-KEY', 'ed94b0d34f9441c3931621e55230e402')

    with urllib.request.urlopen(req) as res:
        print(res.status, res.reason)
        for header in res.getheaders():
            print(header)
        print()
        content = json.loads(res.read())
        pprint.pprint(content)

    # 発注
    obj = { 'Password': '123456',
            'Symbol': '9433',
            'Exchange': 1,
            'SecurityType': 1,
            'FrontOrderType': 20,
            'Side': '2',
            'CashMargin': 1,
            'DelivType': 2,
            'FundType': 'AA',
            'AccountType': 2,
            'Qty': 100,
            'Price': 2762.5,
            'ExpireDay': 20200924 }
    json_data = json.dumps(obj).encode('utf-8')

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

    with urllib.request.urlopen(req) as res:
        print(res.status, res.reason)
        for header in res.getheaders():
            print(header)
        print()
        content = json.loads(res.read())
        pprint.pprint(content)
 
except urllib.error.HTTPError as e:
    print(e)
    content = json.loads(e.read())
    pprint.pprint(content)
except Exception as e:
    print(e)

別にこれでも動くには動きます。

しかし、いくらシンプルとはいっても、1つのシステムトレードの中で、WebAPIはいくつも呼び出さなくてはなりません。そうすると、この方式だと、1つのプログラムコードがとても長くなります。

しかし、コードが長すぎるから分割しようとしても、try~exceptの中のため、単純には分割できない。といったことも起こりがちです。

特にPythonには、呼び出し先の関数では例外を処理せず、呼び出し元で処理させる、Javaのメソッドのthrows句のような仕組みはありません

Web API呼び出しプログラミングでは、数珠繋ぎ方式が最も簡単

そこで、私が提案し、自らのトレードシステムでも採用しているのが「数珠繋ぎ」方式です。

この方式、システムトレードではなく普通のWeb APIクライアントでは、日本で結構やってる人がいるみたいで、Googleったら「数珠繋ぎ」でそこそこヒットするのですが、なぜか海外のサイトでは(「chain」とか「linked」とかのキーワードで探したのですが)、見つけられませんでした。

これは、auカブコム証券がgithubで公開している個別のWeb API呼び出しプログラムを、ただ繋げて呼び出すというものです。

上の図で、青い文字の部分だけが自分が作るプログラムになります。

例えば、①と③は同じ株価取得Web API呼び出し。②④⑤は同じ発注WebAPI呼び出しなのですが、自分がやりたいことが違う場合は、重複など気にせず、別ファイルを作ります(どうせほぼコピーなので)。

プログラミングの世界では、冗長化は避けるべきものとされてます。コードが肥大化したり、修正の手間が多くなったりするからです。
しかし、それはシステムがある程度大きく、複雑な場合の話です。初心者が最初から大きく複雑なトレードシステムを作っても、まず上手く行きません。それよりも初心者は挫折しないで開発できることが重要です。そのためには「作りやすさ」を重視し、共通化は気にしなくてもよいと思います。

Web API呼び出しが上手く行った場合のみ、次の処理に移り、上手く行かない場合(exceptに入った場合)は、何もしてないので、処理がそのまま終わります。

基本的に1ファイルで1Web API呼び出しなので、1ファイルあたりのプログラムコードが短く、とても見やすくなります。

また、別の投稿で書きますが、ファイルを別々にすることにより、簡単なテスト(単体テストといいます)を別々に行うことができるメリットもあります。

一般の人が副業や趣味でシステムトレードをする場合、コーディング自体に時間をかけることはできません。トレード自体の戦略やロジックを考えるだけで精一杯なはずです。

私も含めて、そういった方々が、システムトレードのプログラムを作る場合は、この「数珠繋ぎ方式」が最適だと思います。

コメント