【仮想通貨bot】 JavaScriptで作る仮想通貨自動取引bot 第4回 初めてのbot作成 (2)

【概要】

・botを作るためのパーツとなる関数を作っていく

・シミュレーションを行う関数のプロトタイプを作る

・実際に売買するbotを作って動かしてみる


前回はAPI経由で売買をするプログラムと、シグナルを出力する関数を書きました。今回は自動売買するbotを作っていきましょう。なお、今回からコードが多くなるので、可能な限り私のGitHubにコードをアップロードしていきます。

前回ではシグナルを返す関数が定義できたので、今回はそのシグナルに従って売買注文を出すようにします。流れとしては、

(1)(前回)bitFlyerからAPI Keyを取得し、設定ファイルに追記

(2) (前回)node.js からAPI経由で売買する機能の実装

(3) (前回)売買のシグナルを出力する関数の実装

(4) (今回)売買のシグナルにしたがって売買注文をだすことを繰り返す

(5) (今回)様子を見て動いていることが確認できたらポジションを解消する注文を入れて終了

のようになります。(4)でbotとしては一応完成ですが、まだ儲かる可能性は低いので止めるのを忘れないようにしましょう。(5)までやりたいのですが、今回は長めなので一旦省略して、最終的にはブラウザからポジションを解消しましょう。

4. 売買のシグナルに従って売買注文を出すことを繰り返す

前回作成したtradebot.jsは買い注文を1回だけ出すだけのプログラムでしたが、今回はシグナルを見て売買判断をするようにしましょう。また、ちょっとsignalを変えて、ランダムで他のポジションに移行するようにしましょう。signalを返す関数を次のようにします。

// 変更点: 関数を追加
function getSimpleSignal (position) {
 if (position === 'LONG') return 'SELL';
 if (position === 'SHORT') return 'BUY';
 if (position === 'CLOSED') { // ノーポジをとりあえずCLOSEDと呼ぶ
   // ポジションを持っていないとき、ランダムで売買かノーポジを続ける
   randomValue = Math.random();
   if (randomValue < 0.3) {
     return 'BUY';
   } else if (randomValue > 0.7) {
     return 'SELL';
   } else {
     return 'HOLD'; // ポジションを変えないことをとりあえずHOLDと呼ぶ
   }
 }
 // ここは通らないはず!
 console.log('Error in getSimpleSignal function!');
}

次に、シグナルと現在のポジションを見て次に取るべきポジションを返す関数 getNextPosition を定義します。

// 変更点: 関数を追加
function getNextPosition (position, signal) {
 if (position === 'LONG') return 'CLOSED';
 if (position === 'SHORT') return 'CLOSED';
 if (position === 'CLOSED' && signal === 'BUY') return 'LONG';
 if (position === 'CLOSED' && signal === 'SELL') return 'SHORT';
 if (signal === 'HOLD') return position;
 // ここは通らないはず!
 console.log('Error in getNextPosition function!');
}

さて、この2つの関数を使ってbotを作るのですが、基本的な方針として、botを実際に動かす前にまずシミュレート用の関数を作って、損益がどの程度か確認をするのが安全です。(とはいえ今回の0.001BTCの範囲では数十円の損しかしないと思います)

そこで、一旦シミュレート用のbotを作ります。本当は実際の現在価格を見て、どのくらいの損益になるかを確認するのが良いですが、今回の記事の範囲を超えるので、別の回に譲ります。

次の関数 simpleBotSimulateを作成してください。

// 変更点: シミュレート用の関数を追加
function simpleBotSimulate () {
 var position = 'CLOSED';
 var signal = 'HOLD';
 // 1分毎にポジションを移行する
 setInterval(() => {
   signal = getSimpleSignal(position);
   position = getNextPosition(position, signal);
   console.log('(simulate) シグナル:', signal, '0.001 BTC');
   console.log('(simulate) ポジション:', position);
 }, 60 * 1000);
}

これは1分ごとにシグナルを取得し、ポジションを移行するかどうか判断して、単にコンソールに出力するだけの関数です。とりあえず実際に取引している様子をイメージしつつこれを動かしてみましょう。一旦firstBot関数から実際の取引を行う処理を削除します。firstBot関数を次のように変更してください。

function firstBot () {
 var mode = process.argv[2];
 if (mode === 'simulate') {
   simpleBotSimulate();
 } else {
   console.log('Invalid args!'); // コマンドライン引数が間違っているとき
 }
}

process.argvというフロントエンドではあまり見かけないものが出てきましたが、これはコマンドラインから引数を渡して、それによって処理を分岐させるものです。

そして、ターミナルから次のようにシミュレーションを実行します。

$ node firstbot.js simulate

次のような出力が1分おきに表示されれば成功です!実際に0.001BTCの範囲でランダムに売買をすることがシミュレートできています。

$ node firstbot.js simulate
(simulate) シグナル: HOLD 0.001 BTC
(simulate) ポジション: CLOSED
(simulate) シグナル: SELL 0.001 BTC
(simulate) ポジション: SHORT
(simulate) シグナル: BUY 0.001 BTC
(simulate) ポジション: CLOSED
(simulate) シグナル: BUY 0.001 BTC
(simulate) ポジション: LONG
(simulate) シグナル: SELL 0.001 BTC
(simulate) ポジション: CLOSED
(simulate) シグナル: SELL 0.001 BTC
(simulate) ポジション: SHORT
(simulate) シグナル: BUY 0.001 BTC
(simulate) ポジション: CLOSED

このプログラムは何もしないと永遠に動き続けるので、Control + Cを押して終了させましょう。

ここまで作ってきた関数のポイントは、ソースコードが意図しない動作になることを警戒して、シミュレート用の関数を作ったり、console.logを頻繁に入れていることです。実際は更に例外処理などを使うべきなのですが、しばらくは省略します。

さて、1分おきに売買判断をするプログラムがかけたので、実際のbotを作りましょう。firstBot関数に全部入れると見通しが悪いので、次のような関数simpleBotTradeを作成しましょう。

// 変更点: メインの処理を関数に切り出し
function simpleBotTrade (signal) {
 var position = 'CLOSED';
 var signal = 'HOLD';
 var order = {};
 order.product_code = 'FX_BTC_JPY';
 order.child_order_type = 'MARKET';
 order.price = 0; // 成行のときは0を指定
 order.size = 0.001;
 // 1分毎にポジションを移行する
 setInterval(() => {
   signal = getSimpleSignal(position);
   if (signal === 'BUY' || signal === 'SELL') {
     order.side = signal;
     var timestamp = Date.now().toString();
     var method = 'POST';
     var path = '/v1/me/sendchildorder';
     var body = JSON.stringify(order);
     var text = timestamp + method + path + body;
     var sign = crypto.createHmac('sha256', API_SECRET).update(text).digest('hex');
     var options = {
       url: 'https://api.bitflyer.jp' + path,
       method: method,
       body: body,
       headers: {
         'ACCESS-KEY': API_KEY,
         'ACCESS-TIMESTAMP': timestamp,
         'ACCESS-SIGN': sign,
         'Content-Type': 'application/json'
       }
     };
     request(options, function (err, response, payload) {
       console.log('シグナル:', signal, '0.001 BTC');
       console.log('ポジション:', position);
       console.log(JSON.parse(payload));
     });
   }
 }, 60 * 1000);
}

詳細は今回は割愛しますが、前回作成した買い注文を入れるだけのプログラムをsetInterval関数を使って、シグナルに従って売買しているだけです。注意点としては、setInterval関数の最後の引数はミリ秒単位なので、間違えて60などを指定しないようにしてください

そして、最終的にfirstBot関数を次のように変更すれば、初めてのbotの完成です。

function firstBot () {
 var mode = process.argv[2];
 if (mode === 'simulate') {
   simpleBotSimulate();
 } else if (mode === 'trade') {
   simpleBotTrade();
 } else {
   console.log('Invalid args!'); // コマンドライン引数が間違っているとき
 }
}

firstBot();

では、実際に動かします。下記のコマンドを入力してください。

$ node firstbot.js trade

0.001BTCを1分に1回動かすだけですが、念のため実際にブラウザを見ながら注文が通っていることを確認しましょう。次のようなメッセージがでていれば成功です!

$ node firstbot.js trade
シグナル: BUY  0.001 BTC
ポジション: LONG
{ child_order_acceptance_id: 'JRF20180409-141931-430255' }
シグナル: SELL  0.001 BTC
ポジション: CLOSED
{ child_order_acceptance_id: 'JRF20180409-142031-838137' }
シグナル: SELL  0.001 BTC
ポジション: SHORT
{ child_order_acceptance_id: 'JRF20180409-142131-926007' }
シグナル: BUY  0.001 BTC
ポジション: CLOSED
{ child_order_acceptance_id: 'JRF20180409-142231-838299' }
シグナル: BUY  0.001 BTC
ポジション: LONG
{ child_order_acceptance_id: 'JRF20180409-142331-680211' }

ようやく無事初めてのbotを作ることができました。これもCtrl+Cを押して終了させましょう。

なお、サーバの稼動状態が悪いと約定までに時間がかかるか、次のようなメッセージが出て注文が通らないようです。

error_message: 'Order is not accepted. Please try again later.'

この問題の対策についてはいくつか考えられますが、今後の記事で説明したいと思います。今回はブラウザから稼動状態を見て、安定している時間に実行するようにしましょう。

今回のコードは私のGitHubにあげておくので、ダウンロードするだけで動作確認は可能なようになっています。(できれば自力で書ける方がいいですが)ただしsecret.jsonは勿論上げていないので、各自ダウンロードしたら入れるようにしておいてください。

次回以降はこのbotのシグナルを改善し、終値などの履歴を見て、少しだけ儲かる可能性のあるbotを作っていく予定です。

Twitterはこちらです。 https://twitter.com/tonacoin BitMEXのアフィリンクあるので踏んでくれると喜びます。 https://www.bitmex.com/register/1zrLfZ