スクリーンショット_2018-06-03_20

ビットコイン自動トレードへの道 No.1 (準備編 step0)

色々な方がBitCoinの自動トレードプログラム(通称Bot)を作っている記事を目にする。
多くの方がPythonという言語を使ってプログラムを書いている。
自分としてはPythonも良いんだけど、簡単にWebAPIで公開したり、使い慣れた言語でプログラミングできれば少しは貢献できるのでは?と思って探していたところ、「CCXT」というライブラリを発見した。

CCXTとは「CryptoCurrency eXchange Trading Library」の略らしい。
有志の方々の力たるもの凄い。
せっかく良いライブラリが公開されているので、自分も何か作ってみたくなり、Pythonではなく、JavaScript(ES6/ES7)で記述する試みを始めることにした。これからJavaScriptでプログラムを組んでみようと考えている方々の為になれば幸いである。

今回はまずは開発環境を準備するところから始める。
小生の環境は以下のようになっているが、windowsやLinuxでも動く(んじゃないか?)と思う。
 ・OS: Mac OSX Sierra
 ・開発環境: node.js v9.9.0, npm v5.8.0
 ・IDE: visual studio code
である。 
JavaScriptはES6/ES7の文法を使いたいので、Babelを導入する。その方法は追って書くとする。

準備0.Node.js環境
Node.jsはMacやLinuxでは大方インストール済みだと思うが、最新のNode.jsをインストールすることをお勧めする。Node.jsのバージョンが古いとCCXTが対応していない。ccxtのGithub上の情報では必要なNode.jsバージョンは7.6以降らしい。Node.jsのインストール方法はあちこちのサイトで公開されているので、そちらを参考にしてインストールして欲しい。当方では
 node.js : v9.9.0
 npm : v5.8.0
で始める。

準備1.フォルダの準備
開発するためのフォルダを適当な場所に掘る。今回、ルートとなるフォルダは
 coin_trading_x
というフォルダとする。以後、このフォルダに色々なソースコードを格納する。

mkdir coin_trading_x
cd coin_trading_x
mkdir step0
cd step0

ここでnpm(ノード・バッケージ・マネージャ)で必要なパッケージを取得する。今回最小限のパッケージだけにするが、以降必要に応じて追加していく。

npm init

上記のコマンドをたたくと、npmがいくつかの問い合わせをしてくるが、とりあえず全部リターンキーを連打して、次に進む。
すると、フォルダの下に「package.json」というファイルが出来ているはずだ。中身は以下のような感じになっていると思う。

// package.json
{
 "name": "step0",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC"
}

後で色々修正するが、取り敢えず、このまま進む。
次に必要なモジュールをnpmで取得する。先程のstep0フォルダにカレントディレクトリを移した状態のままで、以下のコマンドを打つ。

準備2.モジュールのロード

npm install --save-dev babel-register babel-preset-env babel-plugin-transform-runtime

多少時間がかかるが、モジュールのロードが終わった後のpackage.jsonの内容は次のようになっていると思う。(モジュールのバージョン部分が実行時期に応じてUpされていると思うが、そこは適宜読み替えて欲しい)

// package.json
{
 "name": "step01",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "babel-plugin-transform-runtime": "^6.23.0",
   "babel-preset-env": "^1.6.1",
   "babel-register": "^6.26.0"
 }
}

babel-register
babel-preset-env
babel-plugin-transform-runtime
といったモジュールが開発依存関係に読み込まれたはずだ。
また、package.jsonと同じディレクトリに「node_modules」というフォルダが出来ているはずだ。このフォルダの中には上記以外にも多量のモジュールがロードされているが、npmが依存関係を処理した結果なので、このフォルダの下は個人で勝手にいじってはいけない。
次に先程紹介した「CCXT」モジュールを読み込ませる。ここで注意したいのは、npmへの指示が「--save-dev」ではなく「--save」である点だ。
実行時に利用されるモジュールなので、以下のコマンドでロードする。

npm install --save ccxt

ワーニングで、descriptionが無いとか、repositoryが無いとか言われるけど、今のところは無視する。package.jsonファイルの中身は以下のようになっているはずだ。

// package.json
{
 "name": "step01",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "babel-plugin-transform-runtime": "^6.23.0",
   "babel-preset-env": "^1.6.1",
   "babel-register": "^6.26.0"
 },
 "dependencies": {
   "ccxt": "^1.12.55"
 }
}

準備3. Babelの準備
JavaScriptは進化が早い。以前はすべて関数で定義しないとならなかったが、最近はClass定義が出来たり、async/awaitなどの非同期処理を簡潔に書く文法も導入された。しかし、ブラウザがすべて対応していなかったりして、最新の記述をそのまま解釈してくれるとは限らない。
そのために「トランスパイラ」と呼ばれる機構を利用して最新の記述を古い記述に動的に変換してもらう必要がある。それを可能にするモジュールがBabelである。最初に導入したモジュールがそれに当たる。

Babelを使うには「.babelrc」という定義ファイルを作成して、Babelに指示を出す。フォルダに「.babelrc」ファイルを作成し、以下のように記述しよう。

// .babelrc
{
   "presets": [
       "env"
   ],
   "plugins": [
       [
           "transform-runtime",
           {
               "polyfill": false,
               "regenerator": true
           }
       ]
   ],
   "sourceMaps": true,
   "retainLines": true
}

細かい説明は省くが、これでBabelを介して、最新のJavaScriptの文法が記述できる。

準備4.サンプルプログラムの記述
さて、何かプログラムを書いて、情報を取得してみよう。
対象はBitflyerで、取得する情報はマーケット一覧で良いだろう。
フォルダ直下に「index.js」ファイルを作成し、中身を以下のように記述する。

// index.js
// ①ccxtライブラリ
import ccxt from 'ccxt';

// ②bitflyer ccxt取得
let exchange = new ccxt.bitflyer();

// ③bitflyer と表示される。
console.log(exchange.id);

// ④market一覧
(async () => {
   let res = await exchange.loadMarkets();
   console.log(res);
})();

①ではccxtライブラリをインポートしている。このimport文もES6というバージョンから採用になったJavaScriptの文法なので、通常に起動するとエラーとして弾かれてしまう。

②でCCXTライブラリからbitflyerオブジェクトを作成している。今回はpublicなAPIを呼び出すのでapiKey, Secretの指定はしていない。

③交換所のIDを表示する。このコマンドでは「bitflyer」と表示される。

④マーケットの一覧を取得してコンソールにLogとして出力している。
async/awaitなどの見慣れないコマンドが付いているが、ccxtで取得した交換所のオブジェクトで提供されるメソッドの多くがPromiseオブジェクトを戻す。よって、非同期処理の記述が相当に増えるので、async/awaitを多用することになる。

実行.
では、上記のプログラムを実行してみよう。

node index.js

上記のようにコマンドを実行すると、以下のエラーが表示されると思う。

import ccxt from 'ccxt';
^^^^^^

SyntaxError: Unexpected token import
・・・・・・(以下略)

nodeのコマンドを実行しただけでは、Babelがプログラムを認識しない。「import」などという識別子は知らん、と怒られる。
そこで次のようにコマンドを変更する。

node -r babel-register index.js

すると、以下のように応答があるはずだ。

bitflyer
{ 'BTC/JPY':
  { limits: undefined,
    precision: undefined,
    tierBased: undefined,
    percentage: undefined,
    taker: 0.0025,
    maker: 0.0025,
    id: 'BTC_JPY',
    symbol: 'BTC/JPY',
    base: 'BTC',
    quote: 'JPY',
    info: { product_code: 'BTC_JPY' } },
 FX_BTC_JPY:
  { limits: undefined,
    precision: undefined,
    tierBased: undefined,
    percentage: undefined,
    taker: 0.0025,
    maker: 0.0025,
    id: 'FX_BTC_JPY',
    symbol: 'FX_BTC_JPY',
    base: 'BTC',
    quote: 'JPY',
    info: { product_code: 'FX_BTC_JPY' } },

・・・・・(以下略)

「BTC/JPY」から続く情報がマーケット一覧として取得された情報である。
次回以降はもう少しマシなプログラムを作っていき、visual studio code(以降、vscと略す)でのデバッグなどを紹介する。

ソフトウェア・エンジニアを40年以上やってます。 「Botを作りたいけど敷居が高い」と思われている方にも「わかる」「できる」を感じてもらえるように頑張ります。 よろしくお願い致します。