国内発 仮想通貨のモナーコインが熱いです。 その価格は、年初から600倍以上にもなったとか! 私は乗り遅れまいと先月末あたりに買ってみました。 値動きが激しく持っているだけで面白いです。 なにより、日本の仮想通貨という誇りとモナーのかわいさが最高ですね。
で、値動きが激しいのでチャートが気になってしかたないわけです。 しかし(あることはあるんですが)よさげなチャートがないのが残念です。 そこで、自分で作ってしまおう!というのが今回のモチベーションです。 第一歩として取引情報を取得するところです。
Zaifは、仮想通貨の数多くある取引所のひとつです。 ここでは便利なAPIが提供されています。 ドキュメントを眺めてみると、 現物公開APIのストリーミングAPIが提供されているようなので、これを今回は使います。 公開APIなのでAPIキーなどが不要で、すぐに使い始めることができます。
WebScoketで下記URLに接続すれば、取引情報が流れてきます。
wss://ws.zaif.jp/stream?currency_pair=mona_jpy
すぐにこのAPIを試したいならwscatを使うとよいでしょう。 jqを併用すれば加工したり整形したりすることもできます。
$ wscat -c wss://ws.zaif.jp/stream?currency_pair=mona_jpy | jq '.trades[] | { price: .price, date: (.date | .+32400) | todate }' { "price": 1900, "date": "2017-12-08T19:23:20Z" } { "price": 1899.6, "date": "2017-12-08T19:23:17Z" } ...
さて、本記事タイトルのとおり、このAPIをKotlinプログラムから呼び出します。 WebSocketクライアントとして、tyrusを使います。 JSR 356のリファレンス実装のようです。
今回はこんな感じで依存性を追加しました。
def tyrusVersion = '1.13.1' compile "org.glassfish.tyrus.bundles:tyrus-standalone-client-jdk:$tyrusVersion" compile "org.glassfish.tyrus:tyrus-container-grizzly-client:$tyrusVersion"
最小限のコードはこんな感じになります(インポートは省略)。
fun main(args: Array<String>) { val config = ClientEndpointConfig.Builder.create().build() val client = ClientManager.createClient() val session = client.connectToServer(object : Endpoint() { override fun onOpen(session: Session, config: EndpointConfig) { session.addMessageHandler(MessageHandler.Whole<String> { message -> println(message) }) } }, config, URI.create("wss://ws.zaif.jp/stream?currency_pair=mona_jpy")) while (session.isOpen) { Thread.sleep(1000) } }
自信ないけど最後のループは、じっと待つためです。 サーバからのデータを非同期で受信するため、これがないと最初のデータを受け取る前にプログラムが終了してしまうからです。 正しいやり方があれば、コメントで教えてくださいm( )m
まぁ、これだけであとはJacksonとか使っていい感じにやればOKです。 で終わりだと面白くないので、せっかくだからKotlinのコルーチン機能を使って書き直してみます。
// v サスペンド関数 v チャネルを返す suspend fun ClientManager.connectingChannel(config: ClientEndpointConfig, uri: URI): Channel<String> { val channel = Channel<String>() // チャネルの生成 try { connectToServer(object : Endpoint() { override fun onOpen(session: Session, config: EndpointConfig) { session.addMessageHandler(MessageHandler.Whole<String> { message -> // コールバックで受け取ったメッセージをチャネルに送信する channel.sendBlocking(message) }) } }, config, uri) } catch (e: Throwable) { channel.close(e) } return channel }
この拡張関数connectingChannel
が返すチャネルを使って、メッセージの到着を監視することができます。
fun main(args: Array<String>) = runBlocking { val config = ClientEndpointConfig.Builder.create().build() val client = ClientManager.createClient() val channel = client.connectingChannel(config, URI.create("wss://ws.zaif.jp/stream?currency_pair=mona_jpy")) while (isActive) { val message = channel.receive() println(message) } }
いい感じに整えて動かすとこんな感じです。
ちょっと地味すぎでしたね。。 まぁこれでデータを取れるので、あとはかっこよく見せるだけです。 おわり。