Bot

仮想通貨botの開発を本格的に始めてみる#12(2023/9/11)

前回の内容に続いて、今回も仮想通貨botの開発状況をまとめていきます。

今回はこちらの記事を参考に「三兵の売買ロジックを定義する」ことをテーマに学習を進めていきます。

ロジックを定義する

酒田五法の三兵については過去の記事で解説したので、詳しい説明は省きます。

赤三兵~酒田五法~酒田五法ローソク足チャート

まずは、陽線が3本連続した時と陰線が3本連続した時のデータを取得するコードを書くことが目的です。

3回連続した上昇と3回連続した下降を観測してコードを書けば良いのですが、同時に実体の大きさも定義しておく必要があります。

たとえば、価格の実体があまりにも小さい場合でも、三兵の戦略に正しく合致しないのにbotがエントリーの条件として認識してしまう可能性が考えられます。

「その実体を何分足で観測するか」という点も重要になってくるため、実際に注文を出す時には微調整が必要です。

この点は、システムトレードの本などで学んでいく必要があります。

今回はコードの概要を理解するだけなので、ヒゲの大きさについても仮の設定で進めていきます。

買いシグナルのロジックを実装する

今回書いたコードは以下の通り。

import requests
from datetime import datetime
import time

def get_price(min):
    response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : min })
    data = response.json()
    last_data = data["result"][str(min)][-2]
    
    return{"close_time" : last_data[0],
           "open_price" : last_data[1],
           "high_price" : last_data[2],
           "low_price" : last_data[3],
           "close_price" : last_data[4]}


def print_price( data ):
	print( "時間: " + datetime.fromtimestamp(data["close_time"]).strftime('%Y/%m/%d %H:%M') + " 始値: " + str(data["open_price"]) + " 終値: " + str(data["close_price"]) )
    
    
def check_candle( data ):
    realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"]-data["low_price"])
    increase_rate = data["close_price"] / data["open_price"] - 1
    
    if data["close_price"] < data["open_price"] : return False
    elif increase_rate < 0.0005 : return False
    elif realbody_rate < 0.5 : return False
    else : return True

    
def check_ascend( data,last_data ):
    if data["open_price"] > last_data["open_price"] and data["close_price"] > last_data["close_price"]:
        return True
    else:
        return False
    
    
last_data = get_price(60)
print_price( last_data )
flag = 0

while True:
    data = get_price(60)
    
    if data["close_time"] != last_data["close_time"]:
        print_price( data )
        
        if flag == 0 and check_candle( data ):
            flag = 1
        elif flag == 1 and check_candle( data ) and check_ascend( data,last_data ):
            print("2本連続で陽線")
            flag = 2
        elif flag == 2 and check_candle( data ) and check_ascend( data,last_data ):
            print("3本連続で陽線 なので 買い!")
            flag = 3
        else:
            flag = 0
        
        last_data["close_time"] = data["close_time"]
        last_data["open_price"] = data["open_price"]
        last_data["close_price"] = data["close_price"]
        
    time.sleep(10)     

何度か実行していると「ZeroDivisionError: division by zero」の文字が出力されました。

時間: 2023/09/10 23:19 始値: 3920145 終値: 3919168
時間: 2023/09/10 23:23 始値: 3918564 終値: 3919369
時間: 2023/09/10 23:24 始値: 3919200 終値: 3919200
Traceback (most recent call last):

File ~/opt/anaconda3/lib/python3.9/site-packages/spyder_kernels/py3compat.py:356 in compat_exec
exec(code, globals, locals)

File ~/Downloads/bot/タイトル無し3.py:52
if flag == 0 and check_candle( data ):

File ~/Downloads/bot/タイトル無し3.py:28 in check_candle
realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"] - data["low_price"])

ZeroDivisionError: division by zero

どうやらローソク足の実体を計算するときの処理でエラーが出たようです。

とりあえず、「division by zero」で検索です。

すると「ゼロ除算」というエラーが発生していることが分かりました。

簡単に言うと「0で割る」という計算をしたためプログラムが止まってしまったのです。

division by zero - ゼロ除算【バグ編】Divide by Zero(ゼロ除算)とはゼロ除算とは

つまり、原因は以下の太字部分にあるということですね。

File ~/Downloads/bot/タイトル無し3.py:28 in check_candle
realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"] - data["low_price"])

この式では、「割る数」を計算した時に「最高値-最安値=0」となり「0で割る」というエラーが発生したことが分かりました。

時間: 2023/09/10 23:19 始値: 3920145 終値: 3919168
時間: 2023/09/10 23:23 始値: 3918564 終値: 3919369
時間: 2023/09/10 23:24 始値: 3919200 終値: 3919200

始値と終値が等しいため、最高値と最安値も等しくなっているはず,,,。改めて価格データを取得して検証したいが、この時はクレジット切れで未確認,,,。

これは対策をするためのコードを書いておく必要がありそうです。

【参考】0除算で発生するZeroDivisionErrorを回避する方法を解説

abs関数

abs関数とは、絶対値を求めるためのものです。

def check_candle( data ):
    realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"]-data["low_price"])
    increase_rate = data["close_price"] / data["open_price"] - 1

ここでは、ローソク足の実体=(終値-始値)/(高値-安値)と定義したコードを書いています。

つまり、上ヒゲと下ヒゲの大きさ(=高値と安値の価格差)に対して価格の実体(始値と終値の価格差)を算出しています。

価格の実体(始値と終値の価格差)にだけabs関数を用いているのは、陰線と陽線とでは始値と終値の定義が逆になるためです。

具体的には、陽線ならばローソクの実体の下が始値で上が終値なのに対して、陰線ならローソクの実体の上が始値で下が終値となります。

【参考】Python入門|絶対値を求めるabs関数の使い方ローソク足とは?

無限ループの基礎

以下の部分では、while文で無限ループする基礎を作っています。

last_data = get_price(60)
print_price( last_data )
flag = 0

特に、flag = 0 の部分が重要で、陽線が3本連続で続くという買いシグナルのサインを出す起点を作っています。

if文を書く時には、スタート状態の条件を厳密に設定する必要があります。

まとめ

コードが長くなり、それにあわせてかなり複雑なことを指示できるようになりました。

また、メインの処理に対して各所に設定した関数が重要な役割を果たしていることが分かります。

何を指示したいのかを明確にして、関数を設定し、それらを作動させる条件を設定するということが基本であるため、ロジックは明確であればあるほどと良いということも理解できました。

テクニカル分析とシステムトレードの手法を織り交ぜながら、それらの技・手法が生きる環境を設定することが「勝てるbot」の条件になりそうです。

今回のコードは、エラーが発生する可能性があるため、対策を講じて「ゼロ除算」を回避できるようにしておきたいです。

このままコツコツと作業を進めていきます。

次回は「過去の価格データから売買シグナルを検証する」がテーマです。

-Bot