Bot

仮想通貨botの開発を本格的に始めてみる#31(2023/11/15)「MMBotの構造を解析する①」

2023年11月15日

前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

今回は、前回の記事で省略していた関数の詳細な解説を具体例を挙げながらまとめていきます。

参考にしたのはこちらの記事です。

口座残高を参照する関数

# JPY残高を参照する関数
def get_asset():

    while True:
        try:
            value = bitflyer.fetch_balance()
            break
        except Exception as e:
            logger.info(e)
            time.sleep(1)
    return value

このコードは、Bitflyer APIを使用して、Bitflyer アカウントの残高情報を取得するための関数です。具体的には、JPY(日本円)の残高を取得しています。

関数の動作は以下の通りです。

  1. bitflyer.fetch_balance() を呼び出して Bitflyer アカウントの残高情報を取得しようとします。
  2. 通信エラーが発生した場合(Exceptionが発生した場合)、エラーログを出力して、1秒待機した後に再試行します。
  3. 成功するかエラーが発生するまで、while ループが継続します。
  4. 成功した場合、取得した残高情報を返します。

この関数は、API通信中にエラーが発生することを考慮して、リトライメカニズムを備えています。

証拠金を参照する関数

# JPY証拠金を参照する関数
def get_colla():

    while True:
        try:
            value = bitflyer.privateGetGetcollateral()
            break
        except Exception as e:
            logger.info(e)
            time.sleep(1)
    return value

このコードは、Bitflyerという取引所でのAPIを使用して、ユーザーのJPY証拠金(証拠金の額)を取得するための関数です。

具体的には、以下の処理が行われています。

  1. bitflyer.privateGetGetcollateral()を呼び出して、ユーザーのJPY証拠金に関する情報を取得します。
  2. エラーが発生した場合には、そのエラーメッセージをログに記録し、1秒待ってから再試行します。これはAPI呼び出しに失敗した場合に、連続して再試行する仕組みを提供しています。
  3. 正常に情報を取得できれば、その情報を返します。

この関数を呼び出すことで、ユーザーのJPY証拠金に関する最新の情報を取得できます。

板情報から指値を入れる基準値を計算する関数

以下のコードを部分ごとに解析していきます。

# 板情報から実効Ask/Bid(=指値を入れる基準値)を計算する関数
def get_effective_tick(size_thru, rate_ask, size_ask, rate_bid, size_bid):

    while True:
        try:
            value = bitflyer.fetchOrderBook(PAIR)
            break
        except Exception as e:
            logger.info(e)
            time.sleep(2)

    i = 0
    s = 0
    while s <= size_thru:
        if value['bids'][i][0] == rate_bid:
            s += value['bids'][i][1] - size_bid
        else:
            s += value['bids'][i][1]
        i += 1

    j = 0
    t = 0
    while t <= size_thru:
        if value['asks'][j][0] == rate_ask:
            t += value['asks'][j][1] - size_ask
        else:
            t += value['asks'][j][1]
        j += 1

    time.sleep(0.5)
    return {'bid': value['bids'][i-1][0], 'ask': value['asks'][j-1][0]}

このコードは、取引所の板情報を使用して、指定された条件に基づいて実効的なAsk(売り注文の価格)およびBid(買い注文の価格)を計算する関数 get_effective_tick を定義しています。

各要素の定義

def get_effective_tick(size_thru, rate_ask, size_ask, rate_bid, size_bid):

この部分では、獲得したデータをsize_thru, rate_ask, size_ask, rate_bid, size_bidの4要素にそれぞれ定義しています。

無限ループ

while True:

while文でループ処理を作ります。関数は無限ループ内にあり、条件が満たされる限り続きます。

板情報取得の試行

try:
    value = bitflyer.fetchOrderBook(PAIR)
    break

bitflyer オブジェクトの fetchOrderBook メソッドを使用して、取引所の板情報を取得しようとします。取得できた場合は、無限ループから脱出します。

エラーハンドリング

except Exception as e:
    logger.info(e)
    time.sleep(2)

何らかの例外が発生した場合、例外の内容をログに記録し (logger.info(e))、2秒待機 (time.sleep(2)) してから再び板情報の取得を試みるようになっています。これにより、一時的な通信エラーや取引所の問題に対処し、安定した板情報を取得できるようにしています。

実効Ask/Bidの計算

i = 0
s = 0
while s <= size_thru:
    if value['bids'][i][0] == rate_bid:
        s += value['bids'][i][1] - size_bid
    else:
        s += value['bids'][i][1]
    i += 1

j = 0
t = 0
while t <= size_thru:
    if value['asks'][j][0] == rate_ask:
        t += value['asks'][j][1] - size_ask
    else:
        t += value['asks'][j][1]
    j += 1

取得した板情報を元に、指定された条件に基づいて実効的なAsk/Bidを計算しています。rate_ask および rate_bid は、既存の注文の価格を指定します。size_ask および size_bid は、それぞれAsk/Bid注文の数量を指定します。

この部分は、板情報をもとにして実効的なAsk(売り注文の価格)とBid(買い注文の価格)を計算しています。以下に具体例を挙げて説明します。

具体例

假定している板情報が以下のような場合:

value = {
    'bids': [
        [100.0, 1.0],   # 価格: 100.0, 数量: 1.0
        [99.5, 2.0],    # 価格: 99.5, 数量: 2.0
        [98.0, 3.0],    # 価格: 98.0, 数量: 3.0
    ],
    'asks': [
        [101.0, 1.5],   # 価格: 101.0, 数量: 1.5
        [102.0, 2.0],   # 価格: 102.0, 数量: 2.0
        [103.0, 1.0],   # 価格: 103.0, 数量: 1.0
    ]
}

そして、rate_bid99.0rate_ask102.0size_bid0.5size_ask1.0 とすると、以下のように計算されます:

i = 0
s = 0
while s <= size_thru:
    if value['bids'][i][0] == rate_bid:
        s += value['bids'][i][1] - size_bid
    else:
        s += value['bids'][i][1]
    i += 1

このループは、size_thru(指定された条件)が満たされるまで、買い注文(Bid)の価格と数量を順番に見ていきます。rate_bid(指定された価格)と一致する場合、size_bid(指定された数量)を差し引いて累計数量 s に加えます。一致しない場合はそのまま数量を加えます。この例では、rate_bid99.0 なので、value['bids'][1] の価格 99.5 が一致し、2.0 - 0.5 = 1.5s に加えられます。

同様に、rate_asksize_ask を用いて実効的なAsk(売り注文の価格)を計算する部分も同様に動作します。この例では、rate_ask102.0 で、value['asks'][1] の価格 102.0 が一致するので、2.0 - 1.0 = 1.0t に加えられます。

結果的に、この計算によって実効的なAskの価格は 102.0 に、実効的なBidの価格は 99.5 になります。

さらに詳細な解析

i = 0
    s = 0
    while s <= size_thru:
        if value['bids'][i][0] == rate_bid:
            s += value['bids'][i][1] - size_bid
        else:
            s += value['bids'][i][1]

このコードは、板情報(value)から指定した条件(size_thrurate_bidsize_bid)に基づいて、実効的なBid(買い注文の価格)を計算しています。以下に具体例を挙げながら説明します。

考え方:

  • value['bids'] は買い注文(Bid)の情報を含むリストです。
  • rate_bid は指定されたBidの価格です。
  • size_bid は指定されたBidの数量です。
  • size_thru は指定された条件を満たすまでの累計数量です。

例として、以下の板情報があるとしましょう。

value = {
    'bids': [
        [100.0, 1.0],   # 価格: 100.0, 数量: 1.0
        [99.5, 2.0],    # 価格: 99.5, 数量: 2.0
        [98.0, 3.0],    # 価格: 98.0, 数量: 3.0
    ]
}

そして、rate_bid99.0size_bid0.5size_thru4.0 と仮定します。

  1. ループが始まるとき、i = 0 および s = 0 です。
  2. 条件 s <= size_thru を確認します。初回では 0 <= 4.0 が成り立つので、ループに入ります。
  3. value['bids'][i][0]100.0、つまり板上のBidの価格です。
  4. value['bids'][i][0]rate_bid99.0)が一致しないので、s には value['bids'][i][1]1.0)がそのまま加えられます。
  5. ループが回るたびに i が増え、次のBid情報に移ります。次のBidの価格は 99.5 です。
  6. このBidの価格は rate_bid99.0)と一致しないので、s には value['bids'][i][1]2.0)がそのまま加えられます。
  7. これを繰り返し、ssize_thru4.0)以上になるまで続けます。

結果的に、上記の例では s4.0 に達するまでのBidの実効数量が計算されます。この計算に基づいて、条件を満たすBidの価格と数量が見つかります。

結果の返却

return {'bid': value['bids'][i-1][0], 'ask': value['asks'][j-1][0]}

計算された実効的なAsk/Bidの価格を返します。Askは value['asks'][j-1][0]、Bidは value['bids'][i-1][0] です。

最終的に、この関数は指定した条件に基づいて取引所の板情報から実効的なAsk/Bidを計算し、その結果を返す役割を果たします。

まとめ

MMBotの根幹となる価格取得とその後の処理についての解析をしました。

Botの基本戦略となる部分で何が行われているのかを理解することができました。

次回は、他の関数についても掘り下げて解析していきます。

「MMBotの構造解析②」へ続きます。

-Bot