noteのタイトル画像

[アービトラージ] 取引所内取引で得られる差益を計算する

ずいぶんと時間が経ってしまいましたが、アビトラの続きです。

前回は liquidという取引所にて

1. BTCでETHを買う (ETH/BTC)
2. ETHでONTを買う (ONT/ETH)
3. ONTでBTCを買う→ONTを売ってBTCを得る (ONT/BTC)

という取引所内ロジックを考えました。
今回は、上記の内容で差益が得られるかどうかを実際にプログラムを組んで確かめてみます。

確認するためのプログラムは以下のようにしました。

// いつものccxt 
const ccxt = require('ccxt');

// sleep関数
const sleep = async time => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, time);
  });
};

// 切り捨て関数(桁指定)
const floor = (value, precision) => {
  return Math.floor(value * (10 ** precision)) / (10 ** precision);
}

(async () => {
  const ex = new ccxt.liquid();

  while (true) {

    try {
      // 買う
      const eth_btc = await ex.fetchTicker('ETH/BTC');
      // 買う
      const ont_eth = await ex.fetchTicker('ONT/ETH');

      // 売る
      const ont_btc = await ex.fetchTicker('ONT/BTC');

      console.log('-- calc ---');
      // 1ONTを買うには x(=ONT/ETH)のETHが必要とすると、xのETHを買うには y(=ETH/BTC)のBTCが必要
      // 必要なBTCは = ONT/ETH * ETH/BTC
      console.log(`1ONT/BTC buy  = ONT/ETH * ETH/BTC: ${floor(ont_eth.ask * eth_btc.ask, 8)}`);
      // 1ONTを売って得られるBTCは、ONT/BTC
      console.log(`1ONT/BTC sell = ONT/BTC          : ${floor(ont_btc.bid, 8)}`);
      // 差益を得るには、
      // 1ONT/BTC sell > 1ONT/BTC buy でなければならない。
      if(ont_btc.bid > ont_eth.ask * eth_btc.ask) {
        // 差益がある
        console.log(`差益; ${floor(ont_btc.bid - ont_eth.ask * eth_btc.ask, 8)}`);
      }
    } catch(e) {
      console.log(e.message);
    }
    // 5秒待つ
    await sleep(5000);
  }
})();

1ONTを買う、売るに着目すると、

1ONTを買うために必要なETHはticker
 ONT/ETH
の「ask値」で確認できます。また、
上記のETHを買うために必要なBTCはticker
 ETH/BTC
の「ask値」で確認できます。
ということで、1ONTを買うために必要なBTCは
 ONT/ETH * ETH/BTC
で算出できますね。

逆に、1ONTを売って得られるBTCはticker
 ONT/BTC
の「bid値」で確認できます。

差益を得るには、
 ONT/BTC.bid > ONT/ETH.ask * ETH/BTC.ask
の関係が成り立つ必要があります。

では実際に上記のロジックを動かして見ましょう。

結果は以下のようになりました。

-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
-- calc ---
1ONT/BTC buy  = ONT/ETH * ETH/BTC: 0.00019458
1ONT/BTC sell = ONT/BTC          : 0.00010525
・・・(以下略)・・・

稼働中、ほとんど値に変化がなかったです。(ときどき最後の桁のあたりの数値が動く程度)

あまり旨味がありません。
そこで前回も書きましたが、QASHという通貨でも同様な感じで確認できそうだったので、

// いつものccxt 
const ccxt = require('ccxt');

// sleep関数
const sleep = async time => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, time);
  });
};

// 切り捨て関数(桁指定)
const floor = (value, precision) => {
  return Math.floor(value * (10 ** precision)) / (10 ** precision);
}

(async () => {
  const ex = new ccxt.liquid();

  while (true) {

    try {
      // 買う
      const eth_btc = await ex.fetchTicker('ETH/BTC');
      // 買う
      const qash_eth = await ex.fetchTicker('QASH/ETH');

      // 売る
      const qash_btc = await ex.fetchTicker('QASH/BTC');

      console.log('-- calc ---');
      // 1QASHを買うには x(=QASH/ETH)のETHが必要とすると、xのETHを買うには y(=ETH/BTC)のBTCが必要
      // 必要なBTCは = QASH/ETH * ETH/BTC
      console.log(`1QASH/BTC buy  = QASH/ETH * ETH/BTC: ${floor(qash_eth.ask * eth_btc.ask, 8)}`);
      // 1QASHを売って得られるBTCは、QASH/BTC
      console.log(`1QASH/BTC sell = QASH/BTC          : ${floor(qash_btc.bid, 8)}`);
      // 差益を得るには、
      // 1QASH/BTC sell > 1QASH/BTC buy でなければならない。
      if(qash_btc.bid > qash_eth.ask * eth_btc.ask) {
        // 差益がある
        console.log(`差益; ${floor(qash_btc.bid - qash_eth.ask * eth_btc.ask, 8)}`);
      }
    } catch(e) {
      console.log(e.message);
    }
    // 5秒待つ
    await sleep(5000);
  }
})();

にプログラムを変更して確認しました。
結果は以下のようになりました。

-- calc ---
1QASH/BTC buy  = QASH/ETH * ETH/BTC: 0.00003925
1QASH/BTC sell = QASH/BTC          : 0.00003909
-- calc ---
1QASH/BTC buy  = QASH/ETH * ETH/BTC: 0.00003925
1QASH/BTC sell = QASH/BTC          : 0.00003909
-- calc ---
1QASH/BTC buy  = QASH/ETH * ETH/BTC: 0.00003925
1QASH/BTC sell = QASH/BTC          : 0.00003909
-- calc ---
1QASH/BTC buy  = QASH/ETH * ETH/BTC: 0.0000392
1QASH/BTC sell = QASH/BTC          : 0.00003909
-- calc ---
1QASH/BTC buy  = QASH/ETH * ETH/BTC: 0.0000392
1QASH/BTC sell = QASH/BTC          : 0.00003909

多少、2つの値は近い値ではありますが、値が動くまでじっと我慢で機会を待つ以外になさそうです。

もっとも、上記のロジックで差益が得られるタイミングが検出できても、そのままの差益が得られるとは限りません。
上記のロジックでは、直近のtickerからbid/ask値を得ていましたが、この価格で売り買いできるとは限らないのです。

実際に板に売り買い分の通貨が積まれていなければ、成り行きで発行しても価格滑り(必要な通貨の量が確保できずに、想定よりも高い値段で買ったり、低い値段で売ったりする)が発生しますし、指値の場合は指値が刺さりません。

よって、売り買いしたい数量(通貨の枚数)分を確実に確保できるbid/ask値を算出して売買指示を発行する必要があります。

次回は価格滑りを防止(完全には無理ですが)するためのロジックに変更していきます。

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