ATR(Average True Range)を使ってビットコイン自動売買アルゴリズム(買いのみ)をpythonで組んで、bitflyerで自動トレードしてみた。
TR(True Range)は、
・ 当日高値-当日安値
・ 当日高値-前日終値
・ 前日終値-当日安値
以上のうち値が最大のものを採用。それらの移動平均がATR(Average True Range)
テクニカル分析(チャート分析)の手法。
ATRが何を意味しているかというと、変動幅のMAXを表していると考える。
1. 始値-(ATR/2)だと、これ以下には下がらないと考えて購入(BUY)
2. 始値+(ATR/2)だと、これ以上は上がらないと考えて利確(SELL)
※割る2しているのは、最大変動幅なので始値±(ATR/2)と考える
これを繰り返せば、利益が得られるはず。
空売りも出来るなら、逆パターンも使える
3. 始値+(ATR/2)だと、これ以上は上がらないと考えて、空売りでイン
4. 始値-(ATR/2)だと、これ以下には下がらないと考えて、利確
bitflyer lightningでFX(信用取引)をするには、単純に入金(銀行振込)するだけじゃダメで、さらに証拠金口座に移動させる必要がある。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
import requests from datetime import datetime import pandas as pd # import talib # Technical Analysis LIBrary import time import ccxt from pprint import pprint bitflyer = ccxt.bitflyer() bitflyer.apiKey = '' bitflyer.secret = '' # ctr+cでキャンセルするまで、自動売買を無限ループ while True: # Cryptowatchから価格データ取得。1分足(60秒)で過去1000分(16時間40分)がもらえる response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : 60 }).json() df_columns = [ "CloseTime", "OpenPrice", "HighPrice", "LowPrice", "ClosePrice", "Volume", "QuoteVolume" ] # ベクトル化(pandasのデータフレーム化)して、for文を使わなくても、SQLのUPDATE文みたいに一気に更新できるのが便利! df = pd.DataFrame(response['result']['60'], columns=df_columns) # tablibを使って、ATR(Average True Range)を算出してカラムに追加(過去14件からTRを算出して、移動平均値としたのがATR) df["ATR"] = talib.ATR(df["HighPrice"], df["LowPrice"], df["ClosePrice"], timeperiod=14) # 最初の14行のATRでNaNなレコードなので除外する(NaNに端数切り捨てしようとするとエラーになるので) df = df.dropna() # 始値-(ATR/2)だと、これ以下には下がらないと考えて購入(BUY)する指値を決定 df["buy_price"] = df["OpenPrice"] - (df["ATR"].round().astype(int)/2) # 始値+(ATR/2)だと、これ以上は上がらないと考えて売りでイン(SELL)する指値を決定 df["sell_price"] = df["OpenPrice"] + (df["ATR"].round().astype(int)/2) # 最新のビットコインFX情報を取得 last_df = df.tail(1) # ATRで算出した指値で注文する buy_price = int(last_df["buy_price"]) print("買いの指値", buy_price, "円") order = bitflyer.create_order( symbol = 'BTC/JPY', type='limit', # limit=指値 market=成行 side='buy', price=buy_price, amount='0.01', # 最低0.01btc params = { "product_code" : "FX_BTC_JPY" }) # FXで買う # pprint( order ) # 注文時のidを記録しておく order_id = order["id"] print("買いの注文ID", order_id) # 最後の注文状況を取得。完了するまでループ # 約定するまで無限ループで待つ。ある程度待って買えなかったらキャンセルする? sec = 0 buy_cancel = False while True: orders = bitflyer.private_get_getchildorders(params = {"product_code" : "FX_BTC_JPY", "count" : 1}) # activeが無くなったら約定で終了 if orders[0]["child_order_state"] != "ACTIVE": break # 10分待っても買えなかったらキャンセルして、指値をやり直し elif sec >= 600: bitflyer.cancel_order( symbol = "BTC/JPY", id = order_id, params = { "product_code" : "FX_BTC_JPY" }) # キャンセル成功したかどうかは戻り値では分からない。private_get_getchildordersで存在しないかどうか確認する必要がある print(order_id, "をキャンセル") # 新しい指値でやり直し buy_cancel = True break else: time.sleep(10) sec += 10 print("まだ買えてない", sec, "秒経過") # 指値で買えなかったのでキャンセルして最初からやり直し if buy_cancel: continue # 購入完了! buy_sec = sec print(buy_price, "円で約定(buy)しました。", buy_sec, "秒かかりました") # 約定できたら、売って利確させる(買うのと同じような処理を行う) # Cryptowatchから価格データ取得。1分足(60秒)で過去1000分(16時間40分)がもらえる response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : 60 }).json() df_columns = [ "CloseTime", "OpenPrice", "HighPrice", "LowPrice", "ClosePrice", "Volume", "QuoteVolume" ] # ベクトル化(pandasのデータフレーム化)して、for文を使わなくても、SQLのUPDATE文みたいに一気に更新できるのが便利! df = pd.DataFrame(response['result']['60'], columns=df_columns) # tablibを使って、ATR(Average True Range)を算出してカラムに追加(過去14件からTRを算出して、移動平均値としたのがATR) df["ATR"] = talib.ATR(df["HighPrice"], df["LowPrice"], df["ClosePrice"], timeperiod=14) # 最初の14行のATRでNaNなレコードなので除外する(NaNに端数切り捨てしようとするとエラーになるので) df = df.dropna() # 始値-(ATR/2)だと、これ以下には下がらないと考えて購入(BUY)する指値を決定 df["buy_price"] = df["OpenPrice"] - (df["ATR"].round().astype(int)/2) # 始値+(ATR/2)だと、これ以上は上がらないと考えて売りでイン(SELL)する指値を決定 df["sell_price"] = df["OpenPrice"] + (df["ATR"].round().astype(int)/2) # 最新のビットコインFX情報を取得 last_df = df.tail(1) # ATRで算出した指値で注文する sell_price = int(last_df["sell_price"]) # もし売値より買った値段より安かったら、買値を指値にして売る if sell_price < buy_price: sell_price = buy_price print("売りの指値", sell_price, "円") print("安く買って高く売れれば", sell_price - buy_price, "円の利益") order = bitflyer.create_order( symbol = 'BTC/JPY', type='limit', # limit=指値 market=成行 side='sell', price=sell_price, amount='0.01', # 最低0.01btc params = { "product_code" : "FX_BTC_JPY" }) # FXで売る pprint( order ) # 注文時のidを記録しておく order_id = order["id"] print(order_id) # 約定するまで無限ループで待つ。ある程度待って売れなかったら、諦めてマイナス覚悟の成行して、最初からやり直す sec = 0 while True: orders = bitflyer.private_get_getchildorders(params = {"product_code" : "FX_BTC_JPY", "count" : 1}) # activeが無くなったら約定で終了 if orders[0]["child_order_state"] != "ACTIVE": break # 10分待っても売れなかったら elif sec >= 600: # 諦めてキャンセルする。 bitflyer.cancel_order( symbol = "BTC/JPY", id = order_id, params = { "product_code" : "FX_BTC_JPY" }) # キャンセル成功したかどうかは戻り値では分からない。private_get_getchildordersで存在しないかどうか確認する必要がある print(order_id, "をキャンセル") # そしてマイナス覚悟の成行で精算。最初からやり直す order = bitflyer.create_order( symbol = 'BTC/JPY', type='market', # limit=指値 market=成行 side='sell', # price=sell_price, amount='0.01', # 最低0.01btc params = { "product_code" : "FX_BTC_JPY" }) # FXで売る pprint( order ) # 注文履歴から、売値を取得 market_orders = bitflyer.private_get_getchildorders(params = {"product_code" : "FX_BTC_JPY", "count" : 1}) sell_price = int(float(market_orders[0]['average_price'])) break else: time.sleep(10) sec += 10 print("まだ売れてない", sec, "秒経過") sell_sec = sec print(sell_price, "円で約定(sell)しました。", sell_sec, "秒かかりました") print(buy_price, "円で買っていたので") print(sell_price - buy_price, "円の損益です。", buy_sec + sell_sec, "秒かかりました") |
実装しながら試してたら、コーディング中に買い注文が約定してしまった~。とりあえず売っておこう。
数秒前 FX BTC/JPY 売り 0.02 2269468 0 取引済
6分前 FX BTC/JPY 買い 0.01 2269078 0 取引済
11分前 FX BTC/JPY 買い 0.01 2269867 0 取引済
(2269468*2) – (2269867+2269078) = マイナス9円
0.01*9円=0.09円の損(苦笑)
証拠金口座には、0.01btc買えるだけの金額に制限しておこう。3万円もあれば良いか。
実際に動作させてみると、ボックス圏ならいいけど、アップトレンド(急に上がったりする)だと全く買えない…。
実際に売買させてみると
買いの指値 2306578 円
買いの注文ID
まだ買えてない 10 秒経過
まだ買えてない 20 秒経過
….
まだ買えてない 90 秒経過
2306578 円で約定(buy)しました。
売りの指値 2307276 円
まだ売れてない 10 秒経過
まだ売れてない 20 秒経過
….
まだ売れてない 310 秒経過
まだ売れてない 320 秒経過
2307276 円で約定(sell)しました。
2306578 円で買っていたので
698 円の利益です
1btcで買っていても698 円の利益だから、0.01btcだと6円の利益(苦笑)
もう一回実行してみたら+31円の利益。
う~ん、1時間にプラス100円でも24時間動かしつづければ2400円/日。一ヶ月で7万2000円。1年で86.4万円
夢が広がりんぐだけど、まあ「コツコツドカン」になるんだろうな~。
もう一回やったら+28円。
やっぱり、最低単位の0.01ビットコイン(2.3万円)だと効率が悪い…。
0.1ビットコイン(23万円)でやるべきか?
そうすれば
一日で2.4万円
一月で72万円
一年で864万円
・・・と思ったけど、やっぱり取らぬ狸の皮算用だよな~。
都合の良い上げトレンドならプラスになるけど、下げトレンドになると、どうやってもマイナスになるよな~。