キジトラのブログ

仮想通貨取引botなどについて書いていきたいと思います

【ポエム】botterはどのように人々の役に立っているか

こんにちは、キジトラです。

qiita.com

仮想通貨botter Advent Calendar 2021の裏面枠がガラ空きだったので、今日は「botterはどのように人々の役に立っているか」というテーマでポエムを書きたいと思います。

人間は、自分の仕事にやりがいを求める生き物です。どうせやるなら、誰の役にも立たない仕事より、誰かの役に立つ仕事をしたいものです。

私は今でこそ専業botterをやっていますが、以前は製造業の会社でエンジニア(ITエンジニアではない)としてサラリーマンをやっていました。 サラリーマン時代はコンシューマ向けの製品開発に携わっていましたが、自分が関わった製品がかっちょいいプロモーション動画とともに全世界に向けて発表され、レビュー記事や口コミで、「あの製品はゲームチェンジャーだ!」「メーカーはよくやった!」などと褒められると、ちょろっと技術検討に参加しただけの自分でもなんだか嬉しくなって、仕事をやってきてよかったなぁと感じたものでした。

一方、botterはどうでしょうか。botは基本的に一人で開発し、勝っても負けても喜怒哀楽を共有する相手もいない。お客様の顔(喜んでいるか怒っているかはさておき)も見えない。誰からもフィードバックもない。やりがいを感じなければ、モチベーションの維持も難しくなります。

そこで本記事では、botterはどのように人々の役に立っているかについて、私の思うところを書きたいと思います。 他にもこんな風に役に立ってるよ!という意見があったらぜひ教えてください。

なお、botにはいくつかの種類があります。 偉大な先人たちがカテゴリー分けしてくれていますので、これに沿って考えていきましょう。

note.com

bot共通 "税"

当たり前ですが、botは利益を出すことを目的として作られます。利益が出ると、当然税金を国に払うことになります。日本では仮想通貨の利益は雑所得に分類され、利益が大きいほど税率が大きくなります。また、損失が出ても給与所得などとは相殺されず、給与の税金はそのまま支払うことになります。つまり、取引がなければどこにも税金は発生しなかったはずなのに、botが利益を出すことによって、(裏で同じ額損失を出している人がいるにもかかわらず、)市場参加者が支払うトータルの税金は増加することになります。利益が大きくなると半分以上税金として支払うことになるので、これはもはや市場参加者からの仮想通貨税の徴収をbotでお手伝いし、一部をお小遣いとしてもらっているようなものです。最近のニュースを見てもわかる通り、税は国にとって非常に重要であり、botで利益を出し納税することは間違いなく社会貢献と言えるでしょう。

なお、国内ではなく海外で利益を出して日本に納税する場合は、日本のお金が増えることになり、さらに社会貢献度が高くなります。 tetoさん(@teto_btc)は、高校生にして、海外メインで2億円稼いで日本に1億円納税するという偉業を成し遂げられています。

以下、botのカテゴリーごとに、税以外にどのように役に立っているかを書いていきたいと思います。

①高頻度

ここでは常に板を出すマーケットマイクとして書きたいと思います。 通常、取引には必ず相手が必要であり、自分一人だけで取引をすることはできません。 マーケットメイカーが常に板を出してくれているおかげで、取引したい人はわざわざ取引相手を都度探さずとも、好きなタイミングでマーケットメイカーの板をtakeすることで取引を行うことができます。 つまり、マーケットメイクbotterは取引機会を市場参加者に提供することで社会貢献を行っていると考えることができるます。 ぜひ急変動時も板を引っ込めず、というかむしろ急変動時こそ流動性が求められるので、しっかり社会貢献を続けてもらえればと思います。

②スイング、⑧モメンタム

よく分からん。 海外取引所でいっぱい儲けていっぱい日本に納税してください。

③裁定

仮想通貨では取引所が複数あり、同じ通貨ペアでも取引所ごとに価格が異なります。 裁定botterは、価格が安い取引所で買い、高い取引所で売る、という取引をすることになります。 これにより、取引所間の価格の乖離は是正される方向に力が働き、その他の市場参加者はどの取引所でも適正に近い価格で取引を行うことができるようになります。 「価格が不利で取引したくない」という場面が少ないのは裁定botterの社会貢献によるものですので、常に感謝の気持ちを忘れないようにしましょう。

④ヒゲ取り

誤発注などで大きな成り行き注文をした場合、ヒゲがつくことがあります。 この場合、価格は大きく滑り、成り行き注文した人は大きく損をすることになります。 ヒゲ取りbotterは、めったに約定しないのに、わざわざ取引所に資金を入れて、板を出してくれています。 ヒゲ取りbotterがいなかったら10%滑っていた注文が、ヒゲ取りbotterのおかげで5%で止まってくれたのかもしれません。 誤発注した際はヒゲ取りbotterに感謝を忘れないようにしましょう。

金利

取引チャンスの場面では、お金を借りてでも取引したい場面もあると思います。 貸そうとする人が多いほど借りる側に有利になりますので、お金を借りる際は貸してくれる人に感謝しましょう。

⑥ミラトレ

よく分からん。

⑦イナゴ

よく分からん。サーバー重くなるのでやめてもらっていいですか?

⑨SFD

SFDについてはあまり詳しくないですが…
SFDは、bitFlyerにおけるFX価格が現物価格から大きく乖離しすぎないように導入されている手数料体系で、これがあることにより、FXは現物っぽい価格で取引されています。 乖離5%以上で乖離を広げる方向に取引しようとするとペナルティを課されるため、非難されることが多い制度ですが、手数料として海外取引所と比べても顕著に高いわけでもないので(SFDは乖離5%で往復0.25%、bybitはtaker 片道0.075%、前の記事で出てきたBittrexは片道0.25%、GateHubは片道0.2~0.3%)、そんなに文句言わなくても、と個人的には思います。 SFD botterも担がれるリスクを取りながら乖離を是正して社会貢献してるので、優しくしてあげてください。

おわりに

以上、botterがいかに人々の役に立っているかでした。
botの社会貢献度を再確認して、モチベーション高く開発していきましょう!
「こんな社会貢献じゃ満足できん、俺はもっとBIGなことをやりたいんだ!」という方はbotはやめておきましょう。

古き良き時代を振り返る 2017~2018アビトラ編

こんにちは、キジトラです。1年ちょいぶりのブログ更新になります。 今、仮想通貨botter界隈では、「話してもあまり支障なさそうなことをポロリしちゃおう!」という空気が醸成されつつあります。 大きな活動だと、Hohetoさん(@i_love_profit)が「仮想通貨botter Advent Calendar 2021」というクリスマスまで毎日誰かがnoteを書くという活動をされています。

他にも、本日は黒枝さん(@kuroeda_0011)という方が非常に面白いnoteを書かれていました。

この流れに乗って私もちょっと昔の話をポロリして、他のbotterがポロリしたくなる雰囲気の醸成につなげられればなと思います。 (せっかくブログを持っていたことを思い出したので、noteではなくこちらで書くことにしました。Hohetoさんごめんなさい) Advent Calendarは外部サイトの記事でもよいそうです。じゃんじゃん参加しましょう!(勘違いしてごめんなさい)

エッジは消失していて、過去のことを調べなおすのも面倒なので、ほぼ記憶を頼りに書きたいと思います。そもそもの私の理解不足や、細かい数字などで間違いなどあったらごめんなさい。

仮想通貨触り始め

私が仮想通貨を触り始めたのは2017の春でした。当時仕事がひと段落してちょっと時間があったときに、どこぞの親切な人が書いた、APIを叩いてBTCでアービトラージしよう!(サンプルコード付き)みたいなブログ記事を見たのがきっかけでした。私は趣味で少しローカルで数値計算するようなプログラムを書いたことがある程度だったので、そのとき初めてHTTPのGETだのPOSTだの、JSONだのを触って、ふーんこんな仕組みなんだと感心した記憶があります。

ちなみに、私は学生のときに為替を雰囲気裁量で触って痛い目を見て、「こんなランダムに動くものの上下なんて分かるわけないだろ」という思想が染みついていたので、仮想通貨は最初からbotでアビトラしかしないつもりでスタートしました。

アビトラbot運用

価格のログを取ってみると、取引手数料と送金手数料を引いても利益が出るくらいの乖離(大きいときは数%)が頻繁にあることが分かりました。最初は運用資金数十万円からスタートしましたが、実際に動かして期待通りに動くことがわかってから徐々に入金額を増やし、その年の最後には貯金の大部分(数百万円)を仮想通貨に突っ込んでいました。市場としては、国内取引所も触っていましたが、APIから送金も自動化できる海外取引所もよく使っていました。よく使っていたのはBinanceとBittrexで、メジャー通貨はもちろん、わけの分からない草コインも結構触っていました。

botのアルゴとしては、10秒に1回REST APIでOrderBookを取得して、取引したい量の深さで乖離がしきい値を超えていれば成り行き注文、くらいの非常に原始的なものでした。こんなアルゴで、かつBinance手数料0.075%、Bittrex手数料0.25%を払ってでも利益が出るくらいのチャンスが当時はざらにあったのです。まさにGood Old Days(古き良き時代)です。

こんな、時代がよかっただけのしょうもない話をされても、とお思いの方も多いと思うので、以下では、やってた人は少ないであろう、GateHubを使ったアビトラについて書きたいと思います。

GateHubとは?

このあたり正確に理解している自信がないので、もし興味ある方はご自分でちゃんとしたドキュメントを当たってください。

雰囲気だけ書くと、リップルのネットワークがあって、そこではもちろんXRPが流通しているのですが、XRPだけでなく、他の通貨の引換券(IOU)も流通しています。 GateHubというのは、BTCやETHの引換券を発行しているところです。本物のBTCやETHをGateHubに送金すると引換券を発行してくれて、逆に引換券をGateHubに持っていくと本物のBTCやETHを送金してくれます。 (余談ですが、昔はJPYの引換券を発行しているところもありました。)

また、リップルのネットワーク上では各通貨(の引換券)同士を板取引する機能があり、XRP/BTC(引換券)、XRP/ETH(引換券)などを板取引することができました。

GateHubはウォレットのUI機能も提供していて、web画面からお金を送金したり、板取引をしたりできました。 ただ、このウォレット機能が結構怪しくて、メールアドレスとパスワードでアカウントを作ると、あなたのウォレットの秘密鍵はこれです、みたいな感じで秘密鍵をダウンロードできるのですが、明らかにGateHub側も秘密鍵を保存しており、今思うとセキュリティ的にかなり怖いものです。GateHubに入れてたお金がなくなった、みたいな話もtwitterでちらほら見ました。どこから鍵が漏れたかは調べようもないですが。

また、UI上から本物のBTCやETHを送金しても、その履歴をUIから見ることができず、しかも結構送金が遅れることがあり、すごく不安になることが多々ありました。また、表示されている送金手数料以上に手数料が引かれて送金されるトラブルもありました。結局、私は送金時は宛先アドレスと送金量を入力した時点でスクリーンショットを取り、おかしかったらサポートにメールするという、すごく面倒な運用をしていました。

こんな感じのスクショを延々と保存していました。 f:id:kijitora_2018:20211201174335p:plain

GateHubでのアビトラ

それだけのリスクをとったり面倒なことをしてまでなぜGateHubを使っていたかというと、そこに乖離があったからの一言に尽きます。板取引機能はネットワーク上にあり、発注にはネットワークにトランザクションを投げる必要があります。普通の取引所のように簡単なAPIが提供されておらず、非常にとっつきづらいです。私も、公式から出ているjavascriptか何かのライブラリをやっとのことで使って注文のトランザクションを投げていました。このとっつきづらさのためか、他の取引所間に比べてGateHubでは乖離が大きい傾向がありました。

ちなみに、今GateHubの板を見るとこんな感じです。 f:id:kijitora_2018:20211201173214p:plain 今となっては見る影もないですね…

2017~2018の成績

GateHub含め、アビトラメインでやっていたのは2017~2018の期間でした。その後は市場の効率化が進み乖離が狭くなったのと、他の手法に注力していたため、アビトラbotは停止しています。当時はヘッジなどという言葉も知らず(そもそも今ほどいろいろ先物市場もなかったと思いますが)、現物を裸で持ってアビトラしていました。2017は裸運用がプラスに働いて、アビトラ+現物益でサラリーマンとしての給与収入を大きく超える利益が出ました。一方2018は裸運用が大きくマイナスに働き、アビトラ機会の減少もあって、トータルで給与を上回る損失を出しました。税制的に赤字は繰り越せないので、2017-2018通算で見ると、正味の利益の7割くらいは税金として持っていかれたことになるのではないかと思います。仮想通貨で一番儲けてるのは国です。間違いありません。

終わりに

記事を書いてて思いましたが、リップルのネットワークの板取引って、今流行りのDEXに通じるところがありますね。知らず知らずのうちに流行を先取りしていたようです。今では完全に出遅れてしまいましたが。どなたかsolanaのDeFi/DEXでバリバリ儲ける方法教えてください! 他のbotterの皆さんも、ぜひこの流れに乗って、思う存分ポロリしちゃってください!

それではまた。

専業botter(≒ニート)になった場合どこまで食いつなげるか

f:id:kijitora_2018:20200923224920p:plain

1年半ぶりくらいにブログを更新します。
ここ数日twitterのTLが専業/兼業トレーダーどちらがいいかという議論でにぎわっています。 私は兼業トレーダー(botter)ですが、会社を辞めて自由を手に入れたいという気持ちがある一方、専業botter(≒ニート)になった後儲からなくなったら野垂れ死ぬのかという恐怖もあります。 せっかくの機会なので簡単な資産推移のシミュレーションをしてみます。
専業になって目指すところは、リソースをトレードに集中させてどんどん利益を増やしていくことだと思いますが、ここでは目論見が外れて儲からなくなってしまうという悲観的なケースについて考えていきます。 なお、私が社会の仕組みに疎いため、税金などの計算が間違っている、想定が甘い、など突っ込みどころが多々あるかもしれません。コメントなどでご指摘いただけると助かります。

前提

以下のように、botで利益が出ているときに調子に乗って会社を辞めたけど、その後利益が目減りしていくという、悲観的なケースを想定します。

  • 専業になる年の利益は10万円/day=3650万円/年とする。(専業を決意しそうなラインはこんなもん?)

  • 専業になる瞬間の貯金(botの運用資産を含まない)は1000万円とする。

  • 競争の激化により、botの利益は1年ごとにある係数で減衰するとする。(減衰係数=0.5なら1年ごとに半分になる)

  • 裁量ギャンブルで爆損などのイベントは発生しないと仮定する。(専業なのでプロ意識をもって心の中のリトルR〇sを抑えましょう)

税金などの計算方法

以下のサイトで、会社の収入を0円、botの利益を副業(雑所得)として入力し、推定社会保険料所得税、住民税を引きます。

副業確定申告シミュレーター | 働くをもっと自由にするならコデアル

本当は法人化などした方が節税になると思いますが、知識がないので簡単のため雑所得想定で計算していきます。

シミュレーション結果

  • 減衰係数=0.5, 一人暮らし想定(生活費17万円/月)の場合

f:id:kijitora_2018:20200923215716p:plain

5年で収入ほぼなしのただのニート、26年くらいで貯金が尽き、bot運用資産で食いつないでいる状態。

  • 減衰係数=0.5, 4人家族想定(生活費34万円/月)の場合

f:id:kijitora_2018:20200923220811p:plain

13年くらいで貯金が尽きます。残りの人生bot運用資産を食いつぶしても足りないでしょう… 奥さんに生活費半分出してもらえると上の一人暮らし想定のカーブと同等になるので、頑張っていい人見つけましょう。

どちらも厳しい結果でした。まあ専業でリソース全てをbotにあてながら減衰係数0.5なんかになってたらダメってことですね。 貯金が尽きるまでの猶予は十年以上あるので、なんとか株などで利益を上げられる体制を構築したいものです。

ここからは、もうちょっとbot頑張って、減衰係数を0.7(1年ごとに利益が0.7倍になるという意味)でキープした場合のシミュレーションです。

  • 減衰係数=0.7, 一人暮らし想定(生活費17万円/月)の場合

f:id:kijitora_2018:20200923221642p:plain

一人暮らしなら贅沢しなければ余裕っぽいですね。

  • 減衰係数=0.7, 4人家族想定(生活費34万円/月)の場合

f:id:kijitora_2018:20200923222555p:plain

21年ほどで貯金が尽きる計算です。やはり家族をbotだけで養っていくのはかなりリスクがありますね。

まとめ

まともな家庭を築いていきたいなら、botだけで食っていこうなどという幻想は捨てましょう。 もちろんうまくいくパターンもあるとは思いますが、うまくいかなかったときのリスクが高いです。
専業botter(≒ニート)諦めますか?それとも家庭諦めますか?

bitFlyer FXの約定履歴から損益グラフを描くpythonプログラム

今日はbitFlyer FXの損益グラフを描くプログラムを公開したいと思います。 bitFlyerにはデフォルトで損益グラフを表示する機能がありますが、現物もFXも全部込みの損益グラフが表示されるため、現物持った状態でFXでbotを動かしていると、純粋なbotの損益を知ることができません。 また、損益しか表示されないので、価格変化との関係性や、取引ごとのポジションの変化もグラフだけからは読み取れません。

今回ここで公開するプログラムは、APIから自分の約定履歴を取得し、価格、損益、ポジションをプロットするものです。 例えばこんなグラフを描くことができます。

f:id:kijitora_2018:20190321103828p:plain

グラフからは、ここで想定以上にポジション掴んでるなとか、ここの急変動で焼かれてるな、などということを読み取れるようになります。

なお、私はtwitterでもたまにこの損益グラフを晒していますが、たいしたbotでもないのでどうせ参考にならんでしょと思って晒しています。 botにおいて重要なのは見ている指標だと思いますが、正直自分でこのグラフだけ見ても自分のbotのロジックを推測できません… 強botterなら推測できるかもしれませんが、そんな人は私ごときのbotは参考にするまでもないはずなので…

というわけで、ロジックばれを恐れず損益を公開してくれる人が増えたらいいなぁということでプログラムを公開します。 どんなbotがいるんだろうという興味本位です(笑)

なお、私は普段pythonはほとんどさわらないので、初心者丸出しのコードになっています。 forとかappendバリバリ使ってますが、温かく見守ってもらえると助かります。

約定履歴取得&csv保存プログラム

指定した期間の自分の約定履歴を取得し、csv形式で保存します。

※Private APIをさわっています。悪意のあるコードは書いていませんが、コードをよく読んで、おかしな挙動をしていないか確認し、自己責任で実行してください。トラブルが起こっても責任は取れません。

import pandas as pd
import pybitflyer
from dateutil.parser import parse
import datetime
import time
from pytz import timezone

#約定履歴取得期間
t_start = parse("2019-03-20 00:00:00" + "+09:00")
t_end = parse("2019-03-21 00:00:00" + "+09:00")

#bitflyer APIキー
api_key = "****"
api_secret = "****"

api = pybitflyer.API(api_key=api_key, api_secret=api_secret)

product_code = "FX_BTC_JPY"

list_executions = []

executions = api.getexecutions(product_code=product_code, count=500)
count = 0
while len(executions) > 0:
    for execution in executions:
        dt = parse(execution["exec_date"] + "+00:00").astimezone(timezone("Asia/Tokyo"))
        if t_start <= dt < t_end: #取得期間内なら
            list_executions.append([dt, execution["side"], execution["price"], execution["size"]])
    
    if dt < t_start:
        break
    else:
        last_id = executions[len(executions) - 1]["id"]
        print("取得中..." + dt.strftime("%Y-%m-%d %H:%M:%S"))
        time.sleep(2)
        executions = api.getexecutions(product_code=product_code, count=500, before=last_id)

df = pd.DataFrame(list_executions[::-1], columns=["date", "side", "price", "size"])

df.to_csv("executions.csv")

上のプログラムは愚直に最新の約定履歴から順番に取得するので、昔の約定履歴を取得する場合は工夫が必要です。 Nagiさん(@Nagi7692)のnoteが参考になるかと思います。

note.mu

損益プロットプログラム

上のプログラムで保存したcsvから、損益をプロットします。なお、bitFlyerの丸め処理やSFDは考慮していないので、厳密な精度はありません。 また、約定履歴保存期間の初期ポジションを手動で入力する必要があります(約定履歴から知る術を思いつきません…)。 ポジションが0に収束するタイプのbotであれば、ポジションの平均値が0になるようにすればある程度正しいと思います。

また、コード中にコメントで書いていますが、損益を正規化して絶対値を隠したり、ポジションのプロットの線を太くして細かい情報を隠したりできます。 差支えない範囲でいいので、損益を公開するbotterが増えたら嬉しいです。

import pandas as pd
import statistics
import matplotlib
import matplotlib.pyplot as plt
import pylab
import matplotlib.dates as mdates

init_position_BTC = 0 #初期ポジションを手動で指定

df = pd.read_csv("executions.csv")

date = pd.to_datetime(df["date"])
side = df["side"]
price = df["price"]
size = df["size"]

position_BTC = init_position_BTC
position_JPY = -init_position_BTC * price[0]
list_price = []
list_position = []
list_profit = []
list_date = []

#計算
for i in range(len(date)):
    list_date.append(date[i])
    list_price.append(price[i])
    if side[i] == "SELL":
        delta_BTC = -size[i]
        delta_JPY = size[i] * price[i]
    else:
        delta_BTC = size[i]
        delta_JPY = -size[i] * price[i]
    
    position_BTC += delta_BTC
    position_JPY += delta_JPY

    list_position.append(position_BTC)
    list_profit.append(position_BTC * price[i] + position_JPY)

ave_position = statistics.mean(list_position)
print("average position : {0}".format(ave_position))

print("profit : {0}".format(list_profit[len(list_profit) - 1]))

#正規化したかったら
#profit_max = max(list_profit)
#list_profit = list(map(lambda x: x / profit_max, list_profit))

#グラフ
matplotlib.rcParams["timezone"] = "Asia/Tokyo"

fig = plt.figure(figsize=(10, 4))
fig.subplots_adjust(left=0.1, bottom=0.15, right=0.9, top=0.95)

#price
ax1 = fig.add_subplot(2, 1, 1)
ax1.plot(list_date, list_price, "C0", label="Price")

#profit
#第2Y軸
ax2 = ax1.twinx()
ax2.plot(list_date, list_profit, "C1", label="Profit")

h1, l1 = ax1.get_legend_handles_labels()
h2, l2 = ax2.get_legend_handles_labels()
ax1.legend(h1+h2, l1+l2, loc='lower right')

ax1.set_ylabel("Price [JPY/BTC]")
ax1.grid(True)
ax2.set_ylabel("Profit [JPY]")

pylab.setp(ax1.get_xticklabels(), visible=False) 

#position
ax3 = fig.add_subplot(2, 1, 2)
ax3.plot(list_date, list_position) #線を太くしたかったらlinewidth=5とか
ax3.set_ylabel("Position [BTC]")
ax3.grid(True)
ax3.set_xlabel("Date")
ax3.xaxis.set_major_formatter(mdates.DateFormatter("%m/%d %H:%M"))

plt.show()

バグなどありましたら、コメントかtwitterで教えていただけると助かります。

遅延があるときのmmbotの挙動

今日は、遅延があるときのmmbotの挙動について書いていきたいと思います。 前回の記事と同じく、簡単なSimをして挙動を見ています。

(参考)前回の記事 mmbotにおけるポジションと注文サイズについて - キジトラのブログ

Sim条件

基本的に前回と同じです。

項目 内容
価格データ bitFlyer FXの適当に選んだ期間のデータ
mmbotロジック 何も考えず現在価格から上下に一定値(50円)離れた価格に注文を出す
注文サイズ 微小 (マーケットインパクトや部分約定を考慮しない。便宜上max_position=0.01BTCでSim&プロット)
ポジション管理 前回の記事でいうlinear
発注→キャンセルの最小時間 約1sec

また、注文/キャンセルが反映されるまでの時間を変数delayとして振ってSimしています。

Sim結果

  • delay=0 f:id:kijitora_2018:20181229123843p:plain ほとんどがmakerとして約定しています。ポジションは0付近に収束しています。利益がほぼ単調増加しており、理想的な形です。

  • delay=約0.3sec f:id:kijitora_2018:20181229123939p:plain delay=0に比べ、takerになってしまう場合が増えます。ポジションはたまに想定最大ポジションを超えます。利益もdelay=0に比べ落ちてきます。

  • delay=約0.8sec f:id:kijitora_2018:20181229124000p:plain さらにtakerになる場合が増えます。ポジションはそこそこはみ出します。利益が出る時間帯もありますが、じわじわ損していきます。

  • delay=約1.5sec f:id:kijitora_2018:20181229124028p:plain さらにtaker約定が増え、じわじわ損します。ポジションもかなりはみ出します。

  • delay=約3sec f:id:kijitora_2018:20181229124045p:plain taker率高いです。そして、ポジションが発振しています。ポジションが0になるようにフィードバック制御しているので、想定外の遅延が入ると発振するのは当たり前ですね。何か対策しないと大事故につながるでしょう。損益はほぼ単調減少です。

まとめ

遅延が大きくなるとtaker率が増えてじわじわ損失を出す挙動をSimで再現できました。めでたしめでたし。

内容で誤りや改善点などなどありましたら、twitterやコメントでご指摘いただけると幸いです。

mmbotにおけるポジションと注文サイズについて

先日スナフキンさん(@snufkin0866)が公開された以下の記事

sshuhei.com

に触発されて、mmbotにおけるポジションと注文サイズについて簡単なシミュレーションを行ったので、共有したいと思います。 それほど精度の高いSimをしているわけでもないので、結果が現実と異なっている点も多々あると思います。 何か気づいた点などあればご指摘いただいて、一緒に議論していければと思います。

検討の目的

スナフキンさんの記事の前半部分にある、現在の保有ポジションと注文サイズの関係って、どうするのがいいんだっけ、というのを簡単なSimで検討してみました。

ポジション管理方法

いろいろパターンはあるかと思いますが、とりあえず以下の図に示す4パターンでやってみました。 買い注文時の図で、横軸は保有ポジションposition、縦軸は注文サイズorder_size、それぞれ想定最大ポジションmax_positionで正規化しています。 売り注文時は横軸の符号を反転します。

f:id:kijitora_2018:20181222232814p:plain

mmbotはpositionが0を中心にして動きますが、position=0付近を見ると、order_sizeはquadratic1>linear≒step>quadratic2となり、実効的なロットはこの順になりそうです。比較するときは、この実効的なロットの違いを考慮する必要があると思われます。

数式で書くと以下の通りです。 各係数は上のグラフを見ながら適当に決めています。

  • step
order\_size =  \begin{cases} max\_position / 2 & ( position \lt max\_position ) \\\\
0 & ( max\_position \leq position )  \end{cases}
  • linear
order\_size =  \begin{cases} -1 / 2 \times (position - max\_position) & ( position \lt max\_position ) \\\\
0 & ( max\_position \leq position )  \end{cases}
  • quadratic1
order\_size =  \begin{cases} max\_position & ( position \lt -max\_position ) \\\\
-max\_position / 4 \times (\frac{position + max\_position}{max\_position})^2 + max\_position & ( position \leq max\_position ) \\\\
0 & ( max\_position \leq position )  \end{cases}
  • quadratic2
order\_size =  \begin{cases} max\_position / 4 \times (\frac{position - max\_position}{max\_position})^2 & ( position \leq max\_position ) \\\\
0 & ( max\_position \leq position )  \end{cases}

Sim方法・Sim条件

bitFlyer FXの適当に選んだ期間の約定履歴をもとに、単純なmmbotのシミュレーションをしています。 mmbotのロジックとしては、簡単のため、何も考えず現在価格から上下に一定値(100円)離れた価格に注文を出すものにしています。 この単純なロジックでは実運用ではボコボコにされるでしょうが、今回はポジション管理方法ごとに相対的な比較ができればいいかなと思っています。 また、簡単のため、注文サイズは微小であるという仮定でSimしています。つまり、自分の出した注文は相場に影響を与えず、かつ、約定価格が自分の注文をまたいだら注文量全部が約定すると仮定しています。部分約定判定しませんが、便宜上max_position=0.01BTCでSim&プロットしています。 発注/キャンセル→板に乗るまでの遅延は0.3秒程度、発注後1秒程度はキャンセルしない設定にしています。

Sim結果

  • step f:id:kijitora_2018:20181223011443p:plain ポジションのプロットが階段状になります。本当は部分約定するのできれいな階段にはなりません。 max_positionよりはみ出しているのは、遅延の影響です。 もっと遅延を大きくし、遅延を待たずに次を発注すると、もっと盛大にはみ出します。 ポジションのRMS(Root Mean Square)を計算してみると0.00777。利益/(ポジションのRMS)は21200くらい。 今回のSimでは、利益もポジションのRMSもロットに比例し、利益/(ポジションのRMS)はロットに依存しなくなるので、これで考えてみたいと思います。

  • linear f:id:kijitora_2018:20181223011501p:plain stepよりmax_positionをはみ出しづらくなっているようです。 ポジションのRMSは0.00680。利益/(ポジションのRMS)は26700くらい。

  • quadratic1 f:id:kijitora_2018:20181223011512p:plain stepやlinearよりはみ出し気味です。 利益はこの中では一番大きいです。 ポジションのRMSは0.00853。利益/(ポジションのRMS)は28300くらい。

  • quadratic2 f:id:kijitora_2018:20181223011522p:plain ポジションが一番0付近に収束しています。上で予想した通り、実効的なロットが小さいようです。 利益も一番小さいです。 ポジションのRMSは0.00398。利益/(ポジションのRMS)は22300くらい。

まとめ

今回の簡単なSimでは、利益/(ポジションのRMS)はquadratic1>linear>quadratic2>stepの順でした。 もちろん今回のSimはmmbotのロジックが単純、Simモデルもいい加減、Sim期間も適当に選んだ数時間だけなので、この結果がそのまま現実に当てはまるとは思っていませんが、私は今まで何も考えずにstepで実装していたので、考え直すいい機会になりました。 今回の内容で、ここおかしいんじゃない?、こう考えた方がいいんじゃない?などなどありましたらフィードバックいただけると幸いです。