ラズパイでC#からbitFlyerのAPIを呼び出す~ビットコイン自動売買の準備~

ラズパイでビットコインの自動トレードができたら楽しそうなので、ちょっと試してみました。

記事の概要:ラズパイ3に最新のC#(Mono)をインストールしてbitFlyerのAPIサンプルを実行
ビットコイン取引所:bitFlyer
OS:Raspbian GNU/Linux 8.0 (jessie)
言語:C#

取引所は僕が今口座を持っているbitFlyerです。
最近はほとんどの取引所がAPIを公開していますね。
プログラマには楽しい時代になりました。

※自分の備忘録を兼ねて実施した順番通りに書いていますが、1~4は失敗手順です。時間の無い方は5以降を参考にしてください。

1.Monoのインストール

まずは一般的な手順通りに最新のMonoをインストールします。

$ sudo apt-get update
$ sudo apt-get install mono-complete

2.バージョン確認

3.2.8になりました。

$ mono -V
Mono JIT compiler version 3.2.8 (Debian 3.2.8+dfsg-10)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
TLS: __thread
SIGSEGV: normal
Notifications: epoll
Architecture: armel,vfp+hard
Disabled: none
Misc: softdebug
LLVM: supported, not enabled.
GC: sgen

3.HelloWorld

とりあえずHelloWorld.csを書いて実行してみます。

$ cat HelloWorld.cs
using System;
public class HelloWorld
{
    public static void Main()
    {
        Console.WriteLine("Hello World!");
    }
}
$ gmcs HelloWorld.cs
$ mono HelloWorld.exe
Hello World!

とりあえず動きました。

4.APIのサンプルを実行

ビットコイン取引所【bitFlyer Lightning】
から、一番上にあるgetmarketsのサンプルを実行してみます。

オリジナルのサンプルコード

こちらはサンプルそのままです。

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

class Sample
{
    static readonly Uri endpointUri = new Uri("https://api.bitflyer.jp");

    public static async Task Main()
    {
        var method = "GET";
        var path = "/v1/getmarkets";
        var query = "";

        using (var client = new HttpClient())
        using (var request = new HttpRequestMessage(new HttpMethod(method), path + query))
        {
            client.BaseAddress = endpointUri;
            var message = await client.SendAsync(request);
            var response = await message.Content.ReadAsStringAsync();

            Console.WriteLine(response);
        }
    }
}

修正したサンプルコード

"public static async Task Main()"の"Main"を"GetMarkets"に変更し、
"static void Main(string[] args)"から呼び出すように変更しています。

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

class Sample
{
    static readonly Uri endpointUri = new Uri("https://api.bitflyer.jp");

    public static async Task GetMarkets()
    {
        var method = "GET";
        var path = "/v1/getmarkets";
        var query = "";

        using (var client = new HttpClient())
        using (var request = new HttpRequestMessage(new HttpMethod(method), path + query))
        {
            client.BaseAddress = endpointUri;
            var message = await client.SendAsync(request);
            var response = await message.Content.ReadAsStringAsync();

            Console.WriteLine(response);
        }
    }

    static void Main(string[] args)
    {
        GetMarkets().Wait();
    }
}

これをgetmarkets.csに保存してコンパイルしてみると……。

$ gmcs getmakets.cs -r:/usr/lib/mono/4.5/System.Net.Http.dll,/usr/lib/mono/4.5/Facades/System.Threading.Tasks.dll
getmakets.cs(10,25): error CS0731: The type forwarder for type `System.Threading.Tasks.Task' in assembly `mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' has circular dependency
getmakets.cs(10,30): error CS1983: The return type of an async method must be void, Task, or Task<T>
getmakets.cs(10,30): warning CS0028: `Sample.Main()' has the wrong signature to be an entry point
Compilation failed: 2 error(s), 1 warnings
pi@raspberrypi:~/bf $

ということで、全然動かないですね。
サンプルで使っているSystem.Threading.Tasksのasync/awaitはC#5.0系から使えるとのことで、先ほど最新化したMonoではバージョンが低いんですね。

5.Monoを公式よりアップデート

ということで、Mono Project公式からラズパイ用の最新版Monoを取得することにします。

まずは公式ページを参照してください。
http://www.mono-project.com/download/#download-lin-raspbian
5.2.0の安定板をダウンロードできますね。(2017/09/02現在)

ダウンロードページにあるこちらのコマンドを順番に実行します。

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
$ echo "deb http://download.mono-project.com/repo/debian raspbianjessie main" | sudo tee /etc/apt/sources.list.d/mono-official.list
$ sudo apt-get update

6.インストールされるバージョンの確認

こんどはインストール前にちゃんと確認します。

$ apt-cache policy mono-complete
mono-complete:
インストールされているバージョン: 3.2.8+dfsg-10
候補: 5.2.0.215-0xamarin10+raspbian8b1
バージョンテーブル:
5.2.0.215-0xamarin10+raspbian8b1 0
500 http://download.mono-project.com/repo/debian/ raspbianjessie/main armhf Packages
*** 3.2.8+dfsg-10 0
500 http://mirrordirector.raspbian.org/raspbian/ jessie/main armhf Packages
100 /var/lib/dpkg/status

5.2.0が入りそうですね。

7.Mono5.2のインストール

そして再びapt-getです。

$ sudo apt-get install mono-complete

僕の場合は先に3系をインストールしていたので、途中で警告が出てインストールが止まってしまいましたが、そのときにメッセージに出たコマンドを実行したところ、問題なくインストールできました。
3系を入れなかった人はすんなりインストールできると思います。

8.改めてバージョン確認

5.2.0が入りました!

$ mono -V
Mono JIT compiler version 5.2.0.215 (tarball Mon Aug 14 16:59:51 UTC 2017)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
TLS: __thread
SIGSEGV: normal
Notifications: epoll
Architecture: armel,vfp+hard
Disabled: none
Misc: softdebug
LLVM: supported, not enabled.
GC: sgen (concurrent by default)

9.コンパイル

コンパイラが変わっています。
gmcsでもdmcsでもなくmcsなんですね。
再度サンプルコードをコンパイルしてみます。

$ mcs getmakets.cs -r:/usr/lib/mono/4.6.1-api/System.Net.Http.dll,/usr/lib/mono/4.6.1-api/Facades/System.Threading.Tasks.dll

エラーが出なくなりました!

10.実行

いよいよ実行です!

$ ./getmakets.exe
[{"product_code":"BTC_JPY"},{"product_code":"FX_BTC_JPY"},{"product_code":"ETH_BTC"},{"product_code":"BCH_BTC"},{"product_code":"BTCJPY08SEP2017","alias":"BTCJPY_MAT1WK"},{"product_code":"BTCJPY15SEP2017","alias":"BTCJPY_MAT2WK"}]

取れました!
ただの市場マスタなのでちょっと面白くはないですが、とりあえずAPIを叩いて結果を取得できました!

これで遊ぶための準備が整ったので、これからいろいろ試してみようと思います。