見出し画像

SFDbotを狩る・倒す python websocketでSFDbotの動きを疑似解析してみた コードあり

SFDbotによって負けがかさむだけでなく、不要なSFD徴収によって損失が膨らんでいる人も多いのではないでしょうか?

私もSFDによって余計な損失を受け、ダメージを受けた一人です。

tradingviewでpineスクリプトを使い、投資戦略をバックテストし、pythonで実行していたところ、なかなかの運用成績を上げていました。このまま大きく稼げると読んでいたところ、SFDによる波乱相場がスタートしました。稼ぎがすべてSFD徴収に消え、いつの間にやらマイナス収支。

乖離の瀬戸際のSFD取った取らないのあおりをモロに受けました。

早く6%に行くか4%以下に戻るかしてほしいのに、SFDbotの大暴れ相場が続いています。ビットフライヤーによるBANを匂わす発言も効果なく、1円バーガーと呼ばれる1円しか離れていないbest_bidとbest_askに大量の注文が並ぶ異常な板が続いています。

今後もSFDが発生するたびに、SFDbotによる同様の現象が生じると思われるので、個人的な覚書としてSFDbotの動きを模してみた。なお、現状SFDbotはBANされる可能性があるので、実稼働はしません。

また、SFDbotの動きが解析できた際には、SFD狩りbotを作成しようと思います。名前はSFDbotkillerとかSFDbot殺しとか。

SFDbotはリアルタイムAPIで動いている

SFDbotは超高速で板の上を這いまわっているのですが、注文状況などの情報はRealTimeAPIから取得していると思われます。

botによって取引所のtick情報や板情報を得る場合、HTTP APIとRealTimeAPIがあるようです。(私自身専門家ではないので詳しく知らない)HTTP APIは毎回の接続で認証作業を行い、さらに取引所のサーバーを使用するのでコスト制限があります。要するに、遅いし使用制限がある状態。

一方、RealTimeAPIは認証作業が最初の一度だけであり、垂れ流し情報を受け続ける状態になります。ラジオ放送を聞いているような状態です。一度接続してしまえば、無制限に高速で情報が流れてきます。

RealTimeAPIはwebsocketなどの使用が必要

RealTimeAPIは通常のAPIのようなリクエストとレスポンスの形式ではないので、少し複雑な書き方になります。

下記のコードを参考にしてください。

import websocket
import json

CHANNEL = "lightning_ticker_BTC_JPY"
CHANNEL2 = "lightning_ticker_FX_BTC_JPY"

def on_message(ws, message):
    global SFD
    global fx_price
    global btc_price

    message = json.loads(message)
    if message["params"]["channel"] == CHANNEL:
        btc_price = message["params"]["message"]["ltp"]
    elif message["params"]["channel"] == CHANNEL2:
        dt = message["params"]["message"]["timestamp"].replace('T',' ').replace('Z','')
        fx_price = message["params"]["message"]["ltp"]
        
    SFD = fx_price/btc_price * 100 - 100

    if message["params"]["channel"] == CHANNEL2:
        print("Time:{} BTC:{} BTC_FX:{} SFD:{}".format(dt, btc_price, fx_price, round(SFD,5)))

def on_open(ws):
    ws.send(json.dumps({"method": "subscribe",
                        "params": {"channel": CHANNEL}}))
    ws.send(json.dumps({"method": "subscribe",
                        "params": {"channel": CHANNEL2}}))
 
 
if __name__ == "__main__":
    # note: reconnection handling needed.
    ws = websocket.WebSocketApp("wss://ws.lightstream.bitflyer.com/json-rpc",
                                on_message=on_message, on_open=on_open)
    ws.run_forever()

pip install websocket-client を実行して、websocketを入れておきます。

CHANNELを指定してon_openでリクエストを出し、on_messageでレスポンスを受け取ります。json形式で保存し、必要な要素を抜き出します。timeは9時間前の時間を表しており、timestrpやtimedeltaで日本時間に変えることもできるのですが、処理が重くなるので、そのままにしています。

SFDはBTC現物の最終約定価格(ltp)を使用して計算されているそうなので、BTCとBTC_FXの最終約定価格を取り出しました。

pythonで走らした結果はこんな感じ。

上記のコードを走らせると、図のような数値情報が流れてきます。

9:39:47.8754562まで、SFDは5%以上。

9:39:47.9223305から、SFDは5%以下になっています。

SFDbotはBTCの最終約定価格からBUYエントリーを計算する

SFDbotはBTC現物の最終約定価格から105%乖離した価格を計算し、BUYエントリーを撒いています。そこで、考えられるエントリー価格は以下の2つです。

パターンA : BTC現物最終約定価格 x 1.04999

最終約定価格から104.999%乖離した価格を計算してエントリーに使用している。

パターンB : BTC現物最終約定価格 x 1.05 - 1

105%の乖離価格を計算し、1円低い値でエントリーしている。

それぞれを上記のコードに詰め込み、一切のビットフライヤーのチャートと照らし合わせて検討してみました。

import websocket
import json
import math

CHANNEL = "lightning_ticker_BTC_JPY"

def on_message(ws, message):

    global btc_price

    message = json.loads(message)
    if message["params"]["channel"] == CHANNEL:
        btc_price = message["params"]["message"]["ltp"]

    if message["params"]["channel"] == CHANNEL:   
        print("BTC_ltp:{} A:{} B:{}".format(int(btc_price), math.ceil(btc_price*1.04999), math.ceil(btc_price*1.05-1)))

def on_open(ws):
    ws.send(json.dumps({"method": "subscribe",
                        "params": {"channel": CHANNEL}}))

 
 
if __name__ == "__main__":
    # note: reconnection handling needed.
    ws = websocket.WebSocketApp("wss://ws.lightstream.bitflyer.com/json-rpc",
                                on_message=on_message, on_open=on_open)
    ws.run_forever()

小数点以下の丸めに注意です。

intだと切り捨て、roundだと四捨五入、math.ceilだと切り上げです。実際の板を見ながら検討したのですが、パターンBとmath.ceilの組み合わせが一番しっくりきました。

つまり、BTC現物最終約定価格 x 1.05 - 1 です。

SFDbotの売値はどこ?

1円バーガーゆえに、上記の買値の1円上、つまり

BTC現物最終約定価格 x 1.05 が売値です。

これを高頻度に回すことによって利益を得ているようです。

ltpの変化に応じてcancel_orderとcreate_orderで注文を移動

BTC現物の最終約定価格は刻々と変化します。最終約定価格に合わせて買値と売値を移動させる必要があります。

そこで、fetch_open_ordersで現在の注文状況を調べ、注文があり価格が変化した場合cancel_orderで注文を削除、さらにcreate_orderで新たにorderを立てる必要があります。

ポイントは値段が変化しない限り注文を動かさないことです。cancelとcreateを繰り返すことは、行列の最後尾に並びなおすことと同じです。

SFDbotの問題点

このエントリーなどの価格が分かったところで、結局椅子取りゲームです。

いかに他より早くSFDが徴収されない5%以下の値で、買いを約定させることが出来るかが勝負になります。現状150BTCくらいの注文がSFDbotとして並んでいますが、そのすべてが約定してはいません。SFDbotの性能の差や、回線速度の差などが影響しているのかもしれません。

もしSFDbotを狩るなら、この出遅れ悪性能botを手始めにつぶす方法を考えるべきでしょうね。

最終約定価格が動いた時に遅れたbotを狩る

最終約定価格が下がった時に、cancel_orderが遅いbotに売りをぶつければ、板が厚い分確実に売ることができそうです。あとは買いのタイミングをどうするか、検討中です。

また追記、もしくは別noteにて書く予定です。

今日はここまで。読んでいただいてありがとうございます。


この記事が気に入ったらサポートをしてみませんか?