前々回、前回に続いて3連休企画第三弾です。
本日は昨日、一昨日と3日間準備してきた自動売買の集大成として、実際にアルゴリズムを動かしてみた結果を公表したいと思います。
ちなみに、初日に掲げた目標は大きく3つありました。
- 米国株高配当ディフェンシブ投資を実践している管理人にとって、アルゴリズムトレードによる安定的な収益基盤を確立できるのか
- ビットコインは投機ブームが終焉に向かい、今後は価格が調整し続けていく可能性が高いが、マーケットマイクロストラクチャーに着目したトレードは有効か
- 最後に3連休の初日の課題として自己研鑽の一貫で分析能力向上が目的です。
1、2番目はそのままですが、個人的には、この3日間でpythonという言語を使い込んで分析能力を養えたというものが一番大きい成果だったのかもしれません。
スクリプト言語は使いこなして始めて意味があるので、使ったことがある、動かしてみたことがあるだけでは何の意味もありません。
正直、このブログを書きながら検証を進めていると、アルゴで収益化を図るのは難しそうだなという思う場面もありましたが、その度にデータをよく見ることで、pythonをある程度自由自在に使いこなせるようになっていきました。
最初は実行環境を整えるところから始まり、エディターも今メインで使っているpycharmのほかにもatomやjupyterなども試してみました。
当然、言語の特徴や文法もゼロベースで覚えつつ、3日間でアルゴリズムで取引するレベルまで持っていくのは少し大変な作業でもありました。
その反面、Pythonの便利なデータ分析・集計用、グラフ描画用のライブラリのnumpyやpandasの習得により、今後、様々な分析作業が楽になると思えば有意義な時間の過ごし方だったかもしれません。
言語の習得や分析能力という小手先の技術力向上はぶっちゃけどうでもよくて、短期間で新しいことに挑戦し、結果を出すということが重要だと思っています。
前置きが長くなってしまいましたが、昨日までの二日間で準備してきた、アルゴリズムのざっくりとした流れ(1日目)と統計的手法によるプライシングやタイミング(2日目)を用いた実証研究の結果報告をしたいと思います。
実際の場に注文を出して約定できたかどうかをシミュレーションしてみた結果が以下です。
横軸は裁定取引の往復売買の回数で、シミュレーション期間としては約30分程度です。
また投資金額は1btcなのでこの時の価格が40万円程度でした。
約40万円の元手を使って30分で累計リターンとして2.5%が獲得できたことになります。
シミュレーションを実施して思ったこととして、指値金額を出してから約定するまでに時間がかかることが多かったです。
売買を記録したログを見ると、1回の裁定で長い時では2分程度かかっていた場合もあります。
これは指値で注文を出してから2分間約定できなかったことを表しています。
これ以上長くなるとアルゴでやる意味もないので、損切りをしたほうがいいかもしれませんね。
今回のアルゴリズムでは3分経過しても約定できなければ注文をキャンセルしています。
買い注文が約定したあとに売り注文が成立しなかった場合はポジションをクローズしています。
グラフが下がることもあるのはこうした損切りによるものです。
現状の裁定取引では買い注文の指値を簡単のため過去の30tickの平均約定単価と標準偏差(と直近高値と安値のスプレッド)で決定しているため待機時間が多く、時間効率が低いです。
こうした買い注文の指値をより精緻に決めることで待機時間を短縮したり、売り注文についても価格の変動方向からより高い売り注文に動的に修正をかけるなど工夫の余地は山ほどあります。
最終的には東証のコロケーションサービスを使っている業者のようにapi提供サーバーの近くでアルゴリズムトレードを実施するなど、物理的な距離が問題にせざるを得ないほどアルゴリズムを洗練させていきたいですね。
最後にアルゴリズムのコアとなる裁定注文を掲載しておきます。
#この値段を場に出してから実際の直近のcloseが下回れば約定した事になる wait_time = 5#注文出してから約定を待つまでのシミュレーション上の時間 trial_num = 30 sigma_magnification = 1 trial_buy = 0 sum_buy=0 sum_success = 0 sum_profit_loss = 0 df_profit = pd.DataFrame() #時系列で損益を保存するdf #df_profit.append(pd.DataFrame(datetime=0,)) for i in range(trial_num): trial_buy += 1 print("買い注文 = " + str(trial_buy)) ps = get_ticks() # tick now_price = int(ps.price.tail(1)) mean_price = int(ps.price.tail(30).mean()) std_price = int(ps.price.tail(30).std()) buy_price = float(now_price - std_price * sigma_magnification) print("buy_price = " + str(buy_price) + ", against now price = " + str(now_price) + ", diff = " + str(now_price - buy_price)) buy_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S+09:00") success_buy = False for buy_trial in range(trial_num): if success_buy: break print("try to buy , wait(" + str(wait_time) + "sec)...") sleep(wait_time)#sec ps2 = get_ticks() ps2 = ps2[ps2.time >= buy_time] if len(ps2.index) == 0: print("no transaction after buy order") continue # now_low2 = float(ps2.low.tail(1)) now_low2 = float(ps2.price.min()) print("low_price = " + str(now_low2)) if buy_price >= now_low2:# 約定した場合 success_buy = True success_sell = False sum_buy += 1#購入回数 print("success to buy at " + str(buy_price)) #買付時刻 buy_tr_time = ps2.time[ps2.price<=buy_price].min() sell_price = buy_price + std_price * sigma_magnification / 2 sell_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S+09:00") for sell_trial in range(10): sleep(wait_time) #ps3 = get_minutes_price(arg_chart_type=60) ps3 = get_ticks() #ps3 = ps3[ps3.time >= sell_time] ps3 = ps3[ps3.time >= buy_tr_time] if len(ps3.index) == 0: print("no transaction after sell order") continue print("try to sell(wait {0}sec) : at price = {1}, against now = {2}".format(str(wait_time),str(sell_price), str(float(ps3.price.tail(1))))) #now_high3 = int(ps3.high.tail(1)) now_high3 = int(ps3.price.max()) #利確したかどうか if sell_price <= now_high3: profit = sell_price - buy_price sum_profit_loss = sum_profit_loss + profit print("arbitrage success! : profit = " + str(profit)) success_sell = True sum_success += 1 sell_tr_time = ps3[(ps3.time > buy_tr_time) & (ps3.price <= sell_price)].time.min() break if not success_sell: loss = buy_price - float(ps3.price.head(1)) #<0 sum_profit_loss = sum_profit_loss + loss print("arbitrage failed. loss = " + str(loss) + ", buy=" + str(buy_price) + ", now=" + str(float(ps3.price.head(1)))) df_tmp = pd.DataFrame({ 'buy_time' : buy_time, 'sell_time' : sell_time, 'buy_tr_time' : buy_tr_time, 'sell_tr_time': sell_tr_time, 'buy' : pd.Series(buy_price,index=list(range(1)),dtype='float32'), 'sell' : sell_price, 'profit': profit, 'sum_profit' : sum_profit_loss}) df_profit = df_profit.append(df_tmp, ignore_index=True)
この記事を読んだ人は以下も読んでいます...

パウエル五郎

最新記事 by パウエル五郎 (全て見る)
- 【ポストコロナの世界】様々な民主化の流れが加速する - 2020年4月25日
- コロナを受け保有銘柄の入れ替えを行う - 2020年4月23日
- コロナを受けてポートフォリオ戦略を変更する! - 2020年4月22日