仮想通貨取引だけでなくあらゆる取引は取引所間で価格やVolumeに差があるのは当然である。
今回はそれをつかって価格が収束しようとするモメンタムをキャッチしたいという狙いのもとストラテジを制作してみた。
価格は単位が変わっても簡単に変更できるが、そもそもVolumeは取引所によってぜんぜん違うのでどのように差を出すのかという疑問がある。
もうおわかりだと思うがこれも「標準化」を使って差を検出する。
平均が0、分散が1となるようにデータを変換すること。正規化、基準化とも言う。サンプルデータの任意の値は、サンプルの平均値と標準偏差を用いて以下の式により標準化される。
これによりVolume値の桁が大きく違っても同じ土俵で(厳密な数字ではないが)比較が可能になる
ついでに価格も「標準化」で検出する(実際のUSDやJPYの差は使わない)
この価格については取引所によって(なんらかの手数料やペアの関係で)恒常的に安いor高いが続くことも有るので絶対値で比較するより標準化したほうがより「一時的に高くなっているか安くなっているか」が比較しやすいと考えた。
本日も全公開。非常に長いので最下部へ移動。
bitFlyerでもByBitでも良い。1時間足。
ByBitに関してはデフォルトで取引所の差を計測する一覧に入れていない。
これはコード内にもあるが取引所がまだ小さいので一覧に入れるとノイズになると考える。実際にオンにするとPFが減少する。
また、前提としてBitMEXから流出した日本人の受け皿となっており、おおよそbitFlyerの値動きと同じ動きをするため差の検出元はbitFlyerを参照したほうが正確だと考えている。
(下部のコードを全部読む人は少ないと思うが...)
このストラテジの仮説はbitFlyer自体がそれほど大きな取引所でないという前提で、だからこそ「大御所の取引所と差が生まれやすい」という点を利用している。
ByBitもまだ小さな取引所なので取引所の平均値に混ぜて計測してしまうとノイズが増えるだけ。そこで「小さな取引所枠」としているbitFlyerを排除して変わりにByBitを差し込むという手法を取った。
いつも通り取引回数が少ないので実用には注意が必要である。
これもまたサンプル数の問題はあるが不思議。相関だろうか。
ボリュームと価格の差で揺れるところを攻めるので、取る値幅は一瞬。
とは言え1時間足なので多少の滑りは加味できるが、手数料を設定すると・・・
bitFlyerでは5.171 から 3.213。結構痛手であることが分かる。
逆を言えばすぐにポジションを手放すので大きなDDも可能性が低いと言える。
BBでもbFの設定そのままを推奨しているが、bFを計測対象から排除してBB専用にするオプションが
これを選択する(BitMEXはおまけ)
こうすると計測対象からbFが外れメインがBBになる。
トレード回数が激減してしまった。
これは取引所ごとにVolumeの癖があるからだと思われる。つまり閾値を下回ってしまうパターンが多い。
ここをマイナスへ下げてやるとより沢山トレードする(逆にプラスにすると減る)
あらら。
ひどい有様である。
しかし、これはトレンドフォローではないので「取引所ごとにVolumeに対する価格の反応が違う」と考えると納得できないだろうか?
というわけで、お気づきかもしれないがこんなオプションがある。
トレンドフォローなら禁断のコマンド。
ロングするところをショート。ショートするところをロングする。
ボックス相場で無限に負けるトレンドフォローを反転すると一時的に勝てるが、いきなり爆損するので通常はやってはいけない。
しかしこのストラテジはその例ではい(トレンドは関係ない)
オンにしてみよう。
まぁ微妙である。
一応勝ったと言ってしまおう。
取引数が少なすぎるのは取引所の期間が短いからだろうか。
本日も「取引数の少なさ」からロバストかどうかは疑問が残る結果となったが、このままはむとれへ投稿。
また先日の「とにかく明るい八つ墓村」もETHバージョンを作成して投稿。これでトータル何本だろう?忘れてしまった。
はむとれのような複合的に戦略を使ってトレードするタイプのBOTであればトレンドフォローにストラテジが偏っている事が多いと思うのでトレンドに一切左右されないこういうストラテジをエッセンスに加えて見るのもいいかもしれない。
思ったより長い。気がついたら書いてた。
長くても完全無料。お金取るほどのストラテジではない。
おまけで下部のplotのコメントを外すとZ値が描画される。
//@version=4
//bitFlyer or ByBit 1h
strategy("まだ2勝しかしてないオオサンショウウオ", overlay=false,default_qty_type=strategy.cash, initial_capital=100000, default_qty_value=100000,currency="USD")
n = input(type=input.integer,defval=200 ,title="標準化に使用する期間")
entry_threshold = input(title="価格差が生じているかどうかの閾値", defval=4, step=0.1)
entry_volume_threshold = input(title="全取引所Volumeの平均がこの閾値以上でないと取引しない(-1 ~ 1ぐらいの範囲がベスト?)",defval=0,step=0.1)
base_broker = input(title="ベースにする取引所", defval="bitFlyer", options=["bitFlyer", "BitMEX", "ByBit"])
reverse_switch = input(false,title="取引を反転する:取引所によって癖が違うので反転は有効な場合がある")
//closeの比較
bitFlyer_fxbtcjpy_close = security("bitFlyer:FXBTCJPY", timeframe.period, close)
bitFlyer_fxbtcjpy_close_sma = sma(bitFlyer_fxbtcjpy_close,n)
bitFlyer_fxbtcjpy_close_Zscore = ( bitFlyer_fxbtcjpy_close - bitFlyer_fxbtcjpy_close_sma ) / stdev(bitFlyer_fxbtcjpy_close,n) //標準化
bybit_btcusd_close = security("ByBit:BTCUSD", timeframe.period, close)
bybit_btcusd_close_sma = sma(bybit_btcusd_close,n)
bybit_btcusd_close_Zscore = ( bybit_btcusd_close - bybit_btcusd_close_sma ) / stdev(bybit_btcusd_close,n) //標準化
//ByBitを使う場合はbitFlyerの代わりにByBitを差し込む
bitFlyer_fxbtcjpy_close_Zscore := base_broker == "ByBit" ? bybit_btcusd_close_Zscore : bitFlyer_fxbtcjpy_close_Zscore
bitmex_xbtusd_close = security("BitMEX:XBTUSD", timeframe.period, close)
bitmex_xbtusd_close_sma = sma(bitmex_xbtusd_close,n)
bitmex_xbtusd_close_Zscore = ( bitmex_xbtusd_close - bitmex_xbtusd_close_sma ) / stdev(bitmex_xbtusd_close,n) //標準化
binance_btcusdt_close = security("Binance:BTCUSDT", timeframe.period, close)
binance_btcusdt_close_sma = sma(binance_btcusdt_close,n)
binance_btcusdt_close_Zscore = ( binance_btcusdt_close - binance_btcusdt_close_sma ) / stdev(binance_btcusdt_close,n) //標準化
coinbase_btcusd_close = security("Coinbase:BTCUSD", timeframe.period, close)
coinbase_btcusd_close_sma = sma(coinbase_btcusd_close,n)
coinbase_btcusd_close_Zscore = ( coinbase_btcusd_close - coinbase_btcusd_close_sma ) / stdev(coinbase_btcusd_close,n) //標準化
kraken_btcusd_close = security("kraken:BTCUSD", timeframe.period, close)
kraken_btcusd_close_sma = sma(kraken_btcusd_close,n)
kraken_btcusd_close_Zscore = ( kraken_btcusd_close - kraken_btcusd_close_sma ) / stdev(kraken_btcusd_close,n) //標準化
//volumeの比較
bitFlyer_fxbtcjpy_volume = security("bitFlyer:FXBTCJPY", timeframe.period, volume)
bitFlyer_fxbtcjpy_volume_sma = sma(bitFlyer_fxbtcjpy_volume,n)
bitFlyer_fxbtcjpy_volume_Zscore = ( bitFlyer_fxbtcjpy_volume - bitFlyer_fxbtcjpy_volume_sma ) / stdev(bitFlyer_fxbtcjpy_volume,n) //標準化
bybit_btcusd_volume = security("ByBit:BTCUSD", timeframe.period, volume)
bybit_btcusd_volume_sma = sma(bybit_btcusd_volume,n)
bybit_btcusd_volume_Zscore = ( bybit_btcusd_volume - bybit_btcusd_volume_sma ) / stdev(bybit_btcusd_volume,n) //標準化
//ByBitを使う場合はbitFlyerの代わりにByBitを差し込む
bitFlyer_fxbtcjpy_volume_Zscore := base_broker == "ByBit" ? bybit_btcusd_volume_Zscore : bitFlyer_fxbtcjpy_volume_Zscore
bitmex_xbtusd_volume = security("BitMEX:XBTUSD", timeframe.period, volume)
bitmex_xbtusd_volume_sma = sma(bitmex_xbtusd_volume,n)
bitmex_xbtusd_volume_Zscore = ( bitmex_xbtusd_volume - bitmex_xbtusd_volume_sma ) / stdev(bitmex_xbtusd_volume,n) //標準化
binance_btcusdt_volume = security("Binance:BTCUSDT", timeframe.period, volume)
binance_btcusdt_volume_sma = sma(binance_btcusdt_volume,n)
binance_btcusdt_volume_Zscore = ( binance_btcusdt_volume - binance_btcusdt_volume_sma ) / stdev(binance_btcusdt_volume,n) //標準化
coinbase_btcusd_volume = security("Coinbase:BTCUSD", timeframe.period, volume)
coinbase_btcusd_volume_sma = sma(coinbase_btcusd_volume,n)
coinbase_btcusd_volume_Zscore = ( coinbase_btcusd_volume - coinbase_btcusd_volume_sma ) / stdev(coinbase_btcusd_volume,n) //標準化
kraken_btcusd_volume = security("kraken:BTCUSD", timeframe.period, volume)
kraken_btcusd_volume_sma = sma(kraken_btcusd_volume,n)
kraken_btcusd_volume_Zscore = ( kraken_btcusd_volume - kraken_btcusd_volume_sma ) / stdev(kraken_btcusd_volume,n) //標準化
base_Zscore = base_broker == "bitFlyer" ? bitFlyer_fxbtcjpy_close_Zscore
: base_broker == "ByBit" ? bybit_btcusd_close_Zscore : bitmex_xbtusd_close_Zscore
average_Zscore = (bitFlyer_fxbtcjpy_close_Zscore + bitmex_xbtusd_close_Zscore + binance_btcusdt_close_Zscore + coinbase_btcusd_close_Zscore + kraken_btcusd_close_Zscore - base_Zscore) / 4
base_volume_Zscore = base_broker == "bitFlyer" ? bitFlyer_fxbtcjpy_volume_Zscore
: base_broker == "ByBit" ? bybit_btcusd_volume_Zscore : bitmex_xbtusd_volume_Zscore
average_volume_Zscore = (bitFlyer_fxbtcjpy_volume_Zscore + bitmex_xbtusd_volume_Zscore + binance_btcusdt_volume_Zscore + coinbase_btcusd_volume_Zscore + kraken_btcusd_volume_Zscore - base_volume_Zscore) / 4
//plot
plot(average_Zscore / base_Zscore)
plot(average_volume_Zscore / base_volume_Zscore,color=color.red)
// plot(bitFlyer_fxbtcjpy_close_Zscore / base_Zscore, color=color.blue) //bF
// plot(bitmex_xbtusd_close_Zscore / base_Zscore, color=color.red) //BitMEX
// plot(binance_btcusdt_close_Zscore / base_Zscore, color=color.green) //Binance
// plot(coinbase_btcusd_close_Zscore / base_Zscore, color=color.orange) //Coinbase
// plot(kraken_btcusd_close_Zscore / base_Zscore, color=color.teal) //Kraken
if(average_volume_Zscore > entry_volume_threshold)
if(average_Zscore / base_Zscore > entry_threshold)
if(not reverse_switch)
strategy.entry("Long",strategy.long)
else
strategy.entry("Short",strategy.short) //反転
else if(average_Zscore / base_Zscore < entry_threshold * -1)
if(not reverse_switch)
strategy.entry("Short",strategy.short)
else
strategy.entry("Long",strategy.long) //反転
else
strategy.close_all()
else
strategy.close_all()