見出し画像

仮想通貨bot 勉強記録⑭

~赤三兵・黒三兵botをテストネットで動かしてみる~

◆前回までのあらすじ

画像1

ロジックを使って注文・決済までするテストコードを作り、バックテストを行いました。

画像2

◆今回やること

画像3

・Bybitで動く赤三兵・黒三兵ロジックの自動取引botの試作版の作成

こちらを参考に、Bybitで動く自動取引botの試作版を作成します。

書いたコードはこちら

from datetime import datetime,timedelta
import time
from rich import print as pp
import pybybit

apis = [
'プライベートキー',
'シークレットキー'
]

bybit = pybybit.API(*apis, testnet=True)

#最新ローソク足を取得する関数
def get_price(min,i):
   t = int((datetime.now() - timedelta(hours=1)).timestamp())#1時間前の時刻取得&変換
   d = bybit.rest.inverse.public_kline_list(
       symbol = "BTCUSD",
       interval=min,
       from_=t).json()
   data = d['result'][i]

   #返り値取得
   return { "close_time"  : data['open_time'],
            "open_price"  : float(data['open']),
            "high_price"  : float(data['high']),
            "low_price"   : float(data['low']),
            "close_price" : float(data['close'])}

#画面出力
def print_price(data):
   pp( " 時間: " + datetime.fromtimestamp(data['close_time']).strftime('%Y/%m/%d %H:%M')
     + " 始値: " + str(data['open_price'])
     + " 終値: " + str(data['close_price']))

#ローソク足の条件判別
def check_candle(data,side):
   try:
       #実体割合の算出
       realbody_rate = abs(data["close_price"] - data["open_price"]) / (data["high_price"]-data["low_price"])
   except ZeroDivisionError:
       increase_rate = 0.1
       
   try:
       #実体の大きさの算出
       increase_rate = (data["close_price"] / data["open_price"]) - 1
   except ZeroDivisionError:
       increase_rate = 0.0001

   if side == "buy":
       if data["close_price"] < data["open_price"] : return False #ローソク足が赤だったらFalse
       elif increase_rate < 0.0001 : return False #実体の大きさが現在価格の0.01%未満ならFalse
       elif realbody_rate < 0.1 : return False #実体の割合がローソク足の10%未満ならFalse
       else : return True #上記すべて条件が当てはまらなければTrue

   if side == "sell":
       if data["close_price"] > data["open_price"] : return False #ローソク足が緑だったらFalse
       elif increase_rate > -0.0001 : return False #実体の大きさが現在価格の0.01%未満ならFalse
       elif realbody_rate < 0.1 : return False #実体の割合がローソク足の10%未満ならFalse
       else : return True #上記すべて条件が当てはまらなければTrue

#ローソク足の連続上昇の判別
def check_ascend( data,last_data ):
   #今回の始値が前回の始値を上回っている且つ今回の終値が前回の終値を上回っていればTure
   if data["open_price"] > last_data["open_price"] and data["close_price"] > last_data["close_price"]:
       return True
   else: return False

#ローソク足の連続下降の判別
def check_descend( data,last_data ):
   #今回の始値が前回の始値を下回っている且つ今回の終値が前回の終値を下回っていればTure
   if data["open_price"] < last_data["open_price"] and data["close_price"] < last_data["close_price"]:
       return True
   else: return False

#買いサイン・注文を出す関数
def buy_signal( data,last_data,flag ):
   if flag["buy_signal"] == 0 and check_candle( data,"buy" ):#陽線1本目
       flag["buy_signal"] = 1
   elif flag["buy_signal"] == 1 and check_candle( data,"buy" )  and check_ascend( data,last_data ):#陽線2本目
       flag["buy_signal"] = 2
   elif flag["buy_signal"] == 2 and check_candle( data,"buy" )  and check_ascend( data,last_data ):#陽線3本目
       pp("3本連続で陽線 なので" + str(data["close_price"]) + "で買い指値")
       flag["buy_signal"] = 3

       #指値買い注文コード
       order = bybit.rest.inverse.private_order_create(
                   side='Buy',
                   symbol='BTCUSD',
                   order_type='Limit',
                   qty=1,
                   price=data["close_price"],
                   time_in_force='GoodTillCancel')
       order

       flag["order"]["exist"] = True
       flag["order"]["side"] = "BUY"

   #陽線が途切れたらシグナルリセット
   else:
       flag["buy_signal"] = 0

   return flag

#売りサイン・注文を出す関数
def sell_signal( data,last_data,flag ):
   if flag["sell_signal"] == 0 and check_candle( data,"sell" ):#陰線1本目
       flag["sell_signal"] = 1
   elif flag["sell_signal"] == 1 and check_candle( data,"sell" )  and check_descend( data,last_data ):#陰線2本目
       flag["sell_signal"] = 2
   elif flag["sell_signal"] == 2 and check_candle( data,"sell" )  and check_descend( data,last_data ):#陰線3本目
       pp("3本連続で陽線 なので" + str(data["close_price"]) + "で売り指値")

       #指値売り注文コード
       order = bybit.rest.inverse.private_order_create(
                   side='Sell',
                   symbol='BTCUSD',
                   order_type='Limit',
                   qty=1,
                   price=data["close_price"],
                   time_in_force='GoodTillCancel')
       order

       flag["order"]["exist"] = True
       flag["order"]["side"] = "SELL"

   #陰線が途切れたらシグナルリセット
   else:
       flag["sell_signal"] = 0

   return flag

#決済用の関数
def close_position( data,last_data,flag ):

   if flag["position"]["side"] == "BUY":
       if data["close_price"] < last_data["close_price"]:
           pp("前回の終値を下回ったので" + str(data["close_price"]) + "あたりで成行で決済します")

           #成行売り注文コード
           order = bybit.rest.inverse.private_order_create(
                       side='Sell',
                       symbol='BTCUSD',
                       order_type='Market',
                       qty=1,
                       price=data["close_price"],
                       time_in_force='GoodTillCancel')
           order

           flag["position"]["exist"] = False

   if flag["position"]["side"] == "SELL":
       if data["close_price"] > last_data["close_price"]:
           pp("前回の終値を上回ったので" + str(data["close_price"]) + "あたりで成行で決済します")

           #成行買い注文コード
           order = bybit.rest.inverse.private_order_create(
                       side='Buy',
                       symbol='BTCUSD',
                       order_type='Market',
                       qty=1,
                       price=data["close_price"],
                       time_in_force='GoodTillCancel')
           order

           flag["position"]["exist"] = False

   return flag

#注文状況確認用の関数
def check_order( flag ):

   position = bybit.rest.inverse.private_position_list(symbol = 'BTCUSD').json()
   position = position['result']['side']

   orders = bybit.rest.inverse.private_order_list(symbol = 'BTCUSD').json()
   orders = orders['result']['data']

   if position != 'None':
       pp("注文が約定しました!")
       flag["order"]["exist"] = False
       flag["order"]["count"] = 0
       flag["position"]["exist"] = True
       flag["position"]["side"] = flag["order"]["side"]
   else:
       if orders[0]['order_status'] == "New":
           pp("まだ未約定の注文があります")
           for o in orders:
               if o['order_status'] == "New":
                   pp(o['order_id'])

           flag["order"]["count"] += 1
           if flag["order"]["count"] > 6:
               flag = cancel_order( orders,flag )
       else:
           pp("注文が遅延しているようです")
   return flag

#注文をキャンセルする関数
def cancel_order( orders,flag ):
   orders = bybit.rest.inverse.private_order_list(symbol = 'BTCUSD').json()
   orders = orders['result']['data']

   if orders[0]['order_status'] == "New":
       for o in orders:
           if o['order_status'] == "New":
               bybit.rest.inverse.private_order_cancel(
                   symbol = 'BTCUSD',
                   order_id = o['order_id'])
   pp("約定していない注文をキャンセルしました")
   flag["order"]["count"] = 0
   flag["order"]["exist"] = False

   time.sleep(20)
   position = bybit.rest.inverse.private_position_list(symbol = 'BTCUSD').json()
   position = position['result']['side']

   if not position == 'None':
       pp("現在、未決済の建玉はありません")
   else:
       pp
       ("現在、まだ未決済の建玉があります")
       flag["position"]["exist"] = True
       flag["position"]["side"] = position
   return flag

#メイン関数
def main():
   last_data = get_price(1,-2)

   print_price( last_data )

   flag = {
       "buy_signal":0,
       "sell_signal":0,
       "order":{
           "exist" : False,
           "side" : "",
           "count" : 0},
       "position":{
           "exist" : False,
           "side" : ""}}

   time.sleep(10)

   while True:
       if flag["order"]["exist"]:
           flag = check_order( flag )
       data = get_price(1,-2)
       if data["close_time"] != last_data["close_time"]:
           print_price( data )
           if flag["position"]["exist"]:
               flag = close_position( data,last_data,flag )
           else:
               flag = buy_signal( data,last_data,flag )
               flag = sell_signal( data,last_data,flag )
           last_data["close_time"] = data["close_time"]
           last_data["open_price"] = data["open_price"]
           last_data["close_price"] = data["close_price"]

       time.sleep(10)

main()

いや~、激しく長くなりました。
めっちゃ苦戦したけど、慣れたらサクサク書けるようになるんだろうか。。。

それじゃ、解説していくぞい!

◆解説

画像4

・関数一覧

画像5

画像6

今回使った関数一覧です。
1つずつ見ていきまっせ~

※サブ関数の中に何度も出てくる変数flagは、main関数で定義しています。

・def get_price(min,i)

画像7

def get_price(min,i)
   #1時間前の時刻取得&変換
   t = int((datetime.now() - timedelta(hours=1)).timestamp())
   d = bybit.rest.inverse.public_kline_list(
       symbol = "BTCUSD",
       interval=min,
       from_=t).json()
   data = d['result'][i]

   #返り値取得
   return { "close_time"  : data['open_time'],
            "open_price"  : float(data['open']),
            "high_price"  : float(data['high']),
            "low_price"   : float(data['low']),
            "close_price" : float(data['close'])}

いつも出てくる関数です。
2つの引数を設定しており、min:何分足か、i:何番目か を指定して呼び出します。
returnでローソク足情報を返します。
勉強記録⑪で解説してます。

・def print_price(data)

画像8

def print_price(data):
   pp( " 時間: " + datetime.fromtimestamp(data['close_time']).strftime('%Y/%m/%d %H:%M')
     + " 始値: " + str(data['open_price'])
     + " 終値: " + str(data['close_price']))

これも毎回出てくる関数です。
引数dataを指定すると、時間・始値・終値を画面出力します。
勉強記録⑪で解説してます。

・def check_candle(data,side)

画像9

def check_candle(data,side):
   #実体割合の算出
   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 side == "buy":
       if data["close_price"] < data["open_price"] : return False #ローソク足が赤だったらFalse
       elif increase_rate < 0.0001 : return False #実体の大きさが現在価格の0.01%未満ならFalse
       elif realbody_rate < 0.1 : return False #実体の割合がローソク足の10%未満ならFalse
       else : return True #上記すべて条件が当てはまらなければTrue

   if side == "sell":
       if data["close_price"] > data["open_price"] : return False #ローソク足が緑だったらFalse
       elif increase_rate > -0.0001 : return False #実体の大きさが現在価格の0.01%未満ならFalse
       elif realbody_rate < 0.1 : return False #実体の割合がローソク足の10%未満ならFalse
       else : return True #上記すべて条件が当てはまらなければTrue

コメントアウトで全部書いてます(笑)
勉強記録⑪で解説してます。
呼び出す際はdata,sideを指定する必要があります。

・def check_ascend( data,last_data )

画像10

#ローソク足の連続上昇の判別
def check_ascend( data,last_data ):
   #今回の始値が前回の始値を上回っている且つ今回の終値が前回の終値を上回っていればTure
   if data["open_price"] > last_data["open_price"] and data["close_price"] > last_data["close_price"]:
       return True
   else: return False

こちらも勉強記録⑪で解説してます。
呼び出す際はdata,last_dataを指定する必要があります。

・def check_descend( data,last_data )

画像11

#ローソク足の連続下降の判別
def check_descend( data,last_data ):
   #今回の始値が前回の始値を下回っている且つ今回の終値が前回の終値を下回っていればTure
   if data["open_price"] < last_data["open_price"] and data["close_price"] < last_data["close_price"]:
       return True
   else: return False

def check_ascend( data,last_data )の逆バージョンです。割愛。

・def buy_signal( data,last_data,flag )

画像12

#買いサイン・注文を出す関数
def buy_signal( data,last_data,flag ):
   if flag["buy_signal"] == 0 and check_candle( data,"buy" ):#陽線1本目
       flag["buy_signal"] = 1
   elif flag["buy_signal"] == 1 and check_candle( data,"buy" )  and check_ascend( data,last_data ):#陽線2本目
       flag["buy_signal"] = 2
   elif flag["buy_signal"] == 2 and check_candle( data,"buy" )  and check_ascend( data,last_data ):#陽線3本目
       pp("3本連続で陽線 なので" + str(data["close_price"]) + "で買い指値")
       flag["buy_signal"] = 3

       #指値買い注文コード
       order = bybit.rest.inverse.private_order_create(
                   side='Buy',
                   symbol='BTCUSD',
                   order_type='Limit',
                   qty=1,
                   price=data["close_price"],
                   time_in_force='GoodTillCancel')
       order

       flag["order"]["exist"] = True
       flag["order"]["side"] = "BUY"

   #陽線が途切れたらシグナルリセット
   else:
       flag["buy_signal"] = 0

   return flag

勉強記録⑬で解説してます。一応買い注文の部分だけ解説↓

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

   elif flag["buy_signal"] == 2 and check_candle( data,"buy" )  and check_ascend( data,last_data ):#陽線3本目
       pp("3本連続で陽線 なので" + str(data["close_price"]) + "で買い指値")
       flag["buy_signal"] = 3

       #指値買い注文コード
       order = bybit.rest.inverse.private_order_create(
                   side='Buy',
                   symbol='BTCUSD',
                   order_type='Limit',
                   qty=1,
                   price=data["close_price"],
                   time_in_force='GoodTillCancel')
       order

       flag["order"]["exist"] = True
       flag["order"]["side"] = "BUY"

3本連続でcheck_candleの条件を満たしたローソク足が出現すると、flag["buy_signal"] を 3に書き換え、bybitに指値で注文を出します。
注文を出したら、flag["order"]["exist"] を Trueに、flag["order"]["side"] を "BUY"に書き換えます。

買い注文コードは勉強記録⑥で使ったコードと同じです。
ちなみにexistっていうのは存在するっていう意味です。
プログラミングやってると英語の勉強にもなるんだぜ。

・def sell_signal( data,last_data,flag )

画像13

#売りサイン・注文を出す関数
def sell_signal( data,last_data,flag ):
   if flag["sell_signal"] == 0 and check_candle( data,"sell" ):#陰線1本目
       flag["sell_signal"] = 1
   elif flag["sell_signal"] == 1 and check_candle( data,"sell" )  and check_descend( data,last_data ):#陰線2本目
       flag["sell_signal"] = 2
   elif flag["sell_signal"] == 2 and check_candle( data,"sell" )  and check_descend( data,last_data ):#陰線3本目
       pp("3本連続で陰線 なので" + str(data["close_price"]) + "で売り指値")

       #指値売り注文コード
       order = bybit.rest.inverse.private_order_create(
                   side='Sell',
                   symbol='BTCUSD',
                   order_type='Limit',
                   qty=1,
                   price=data["close_price"],
                   time_in_force='GoodTillCancel')
       order

       flag["order"]["exist"] = True
       flag["order"]["side"] = "SELL"

   #陰線が途切れたらシグナルリセット
   else:
       flag["sell_signal"] = 0

   return flag

def buy_signal( data,last_data,flag )の売りバージョンです。割愛。

・def close_position( data,last_data,flag )

画像14

#決済用の関数
def close_position( data,last_data,flag ):

   if flag["position"]["side"] == "BUY":
       if data["close_price"] < last_data["close_price"]:
           pp("前回の終値を下回ったので" + str(data["close_price"]) + "あたりで成行で決済します")

           #成行売り注文コード
           order = bybit.rest.inverse.private_order_create(
                       side='Sell',
                       symbol='BTCUSD',
                       order_type='Market',
                       qty=1,
                       price=data["close_price"],
                       time_in_force='GoodTillCancel')
           order

           flag["position"]["exist"] = False

   if flag["position"]["side"] == "SELL":
       if data["close_price"] > last_data["close_price"]:
           pp("前回の終値を上回ったので" + str(data["close_price"]) + "あたりで成行で決済します")

           #成行買い注文コード
           order = bybit.rest.inverse.private_order_create(
                       side='Buy',
                       symbol='BTCUSD',
                       order_type='Market',
                       qty=1,
                       price=data["close_price"],
                       time_in_force='GoodTillCancel')
           order

           flag["position"]["exist"] = False

   return flag

決済注文用の関数です。
買いポジションの時は売り注文、売りポジションの時は買い注文を出します。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

   if flag["position"]["side"] == "BUY":
       if data["close_price"] < last_data["close_price"]:
           pp("前回の終値を下回ったので" + str(data["close_price"]) + "あたりで成行で決済します")

           #成行売り注文コード
           order = bybit.rest.inverse.private_order_create(
                       side='Sell',
                       symbol='BTCUSD',
                       order_type='Market',
                       qty=1,
                       price=data["close_price"],
                       time_in_force='GoodTillCancel')
           order

           flag["position"]["exist"] = False

※買いポジションの時
flag["position"]["side"] が "BUY"で、今回の終値 < 前回の終値の時、画面出力と成行の売り注文を出します。
注文を出したら、flag["position"]["exist"] を Falseに書き換えます。

※売りポジションの時も同様です。

・def check_order( flag )

画像15

#注文状況確認用の関数
def check_order( flag ):

   position = bybit.rest.inverse.private_position_list(symbol = 'BTCUSD').json()
   position = position['result']['side']

   orders = bybit.rest.inverse.private_order_list(symbol = 'BTCUSD').json()
   orders = orders['result']['data']

   if position != 'None':
       pp("注文が約定しました!")
       flag["order"]["exist"] = False
       flag["order"]["count"] = 0
       flag["position"]["exist"] = True
       flag["position"]["side"] = flag["order"]["side"]
   else:
       if orders[0]['order_status'] == "New":
           pp("まだ未約定の注文があります")
           for o in orders:
               if o['order_status'] == "New":
                   pp(o['order_id'])

           flag["order"]["count"] += 1
           if flag["order"]["count"] > 6:
               flag = cancel_order( orders,flag )
       else:
           pp("注文が遅延しているようです")
           
   return flag

Bybitに出した注文の状況を確認するための関数です。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

   position = bybit.rest.inverse.private_position_list(symbol = 'BTCUSD').json()
   position = position['result']['side']

   orders = bybit.rest.inverse.private_order_list(symbol = 'BTCUSD').json()
   orders = orders['result']['data']

まずBybitからポジションリストを取得し、positionに'Buy'か'Sell'か'None'のどれかの結果を入れておきます。
次にオーダーリストを取得し、ordersに入れておきます。

   if position != 'None':
       pp("注文が約定しました!")
       flag["order"]["exist"] = False
       flag["order"]["count"] = 0
       flag["position"]["exist"] = True
       flag["position"]["side"] = flag["order"]["side"]

positionが'None'ではない場合、BUYかSELLどちらかのポジションを持っているということなので、注文が約定したということになります。
そのため、flagの各変数にオーダー無し・注文ありと判断できるよう値を上書きします。

   else:
       if orders[0]['order_status'] == "New":
           pp("まだ未約定の注文があります")
           for o in orders:
               if o['order_status'] == "New":
                   pp(o['order_id'])

           flag["order"]["count"] += 1
           if flag["order"]["count"] > 6:
               flag = cancel_order( orders,flag )
       else:
           pp("注文が遅延しているようです")
           
   return flag

ポジションが'None'で、注文履歴の最初の注文のorder_statusが'New'の場合、まだ未約定の注文が存在しています。
その場合、order_statusが'New'になっている注文のIDを画面出力します。
また、flag["order"]["count"]の値を+1して、繰り返し処理の中でflag["order"]["count"]が6になったらcancel_order( orders,flag )を呼び出して注文をキャンセルします。

ポジションが'None'で、注文履歴の最初の注文のorder_statusが'New'ではない場合、約定はしているがポジションはまだ解消されていない=遅延が発生しているということになり、"注文が遅延しているようです"と画面出力します。

・def cancel_order( orders,flag )

画像16

#注文をキャンセルする関数
def cancel_order( orders,flag ):
   orders = bybit.rest.inverse.private_order_list(symbol = 'BTCUSD').json()
   orders = orders['result']['data']

   if orders[0]['order_status'] == "New":
       for o in orders:
           if o['order_status'] == "New":
               bybit.rest.inverse.private_order_cancel(
                   symbol = 'BTCUSD',
                   order_id = o['order_id'])
   pp("約定していない注文をキャンセルしました")
   flag["order"]["count"] = 0
   flag["order"]["exist"] = False

   time.sleep(20)
   
   position = bybit.rest.inverse.private_position_list(symbol = 'BTCUSD').json()
   position = position['result']['side']

   if not position == 'None':
       pp("現在、未決済の建玉はありません")
   else:
       pp
       ("現在、まだ未決済の建玉があります")
       flag["position"]["exist"] = True
       flag["position"]["side"] = position[0]["side"]
       
   return flag

最後のサブ関数です!
注文をキャンセルするための関数です。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

   orders = bybit.rest.inverse.private_order_list(symbol = 'BTCUSD').json()
   orders = orders['result']['data']

   if orders[0]['order_status'] == "New":
       for o in orders:
           if o['order_status'] == "New":
               bybit.rest.inverse.private_order_cancel(
                   symbol = 'BTCUSD',
                   order_id = o['order_id'])
   pp("約定していない注文をキャンセルしました")
   flag["order"]["count"] = 0
   flag["order"]["exist"] = False

   time.sleep(20)

まずBybitからオーダーリストを取得します。
リストの1番目の'order_status'が"New"の場合、リスト中の'order_status'が"New"になっている注文を全てキャンセルします。
その後キャンセルしたことを画面出力し、flag["order"]["count"] を 0、
flag["order"]["exist"] を Falseに書き換え、20秒待機します。

   position = bybit.rest.inverse.private_position_list(symbol = 'BTCUSD').json()
   position = position['result']['side']

   if position == 'None':
       pp("現在、未決済の建玉はありません")
   else:
       pp("現在、まだ未決済の建玉があります")
       flag["position"]["exist"] = True
       flag["position"]["side"] = position
       
   return flag

次にポジションの確認をします。
Bybitからポジションリストを取得し、
position が 'None'の場合、"現在、未決済の建玉はありません"の画面出力します。
それ以外の場合、"現在、まだ未決済の建玉があります"と画面出力し、flag["position"]["exist"] を True、flag["position"]["side"] を positionの値に書き換えます。

・def main()

画像17

やっとメイン関数まで来ました。

#メイン関数
def main():
   last_data = get_price(1,-2)

   print_price( last_data )

   flag = {
       "buy_signal":0,
       "sell_signal":0,
       "order":{
           "exist" : False,
           "side" : "",
           "count" : 0},
       "position":{
           "exist" : False,
           "side" : ""}}

   time.sleep(10)

   while True:
       if flag["order"]["exist"]:
           flag = check_order( flag )
       data = get_price(1,-2)
       if data["close_time"] != last_data["close_time"]:
           print_price( data )
           if flag["position"]["exist"]:
               flag = close_position( data,last_data,flag )
           else:
               flag = buy_signal( data,last_data,flag )
               flag = sell_signal( data,last_data,flag )
           last_data["close_time"] = data["close_time"]
           last_data["open_price"] = data["open_price"]
           last_data["close_price"] = data["close_price"]

       time.sleep(10)

main()

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

   last_data = get_price(1,-2)

   print_price( last_data )

   flag = {
       "buy_signal":0,
       "sell_signal":0,
       "order":{
           "exist" : False,
           "side" : "",
           "count" : 0},
       "position":{
           "exist" : False,
           "side" : ""}}
   
    time.sleep(10)

まずlast_dataにget_price(1,-2)から得た返り値を入れて、print_price( last_data )で確定済みの最新ローソク足情報を画面出力します。

次にflagの初期値を定義しておきます。ここ重要です!!
サブ関数で何度もreturn flagと出てきましたが、ここのflagに値を入力するための返り値です。

   while True:
       if flag["order"]["exist"]:
           flag = check_order( flag )
       data = get_price(1,-2)
       if data["close_time"] != last_data["close_time"]:
           print_price( data )
           if flag["position"]["exist"]:
               flag = close_position( data,last_data,flag )
           else:
               flag = buy_signal( data,last_data,flag )
               flag = sell_signal( data,last_data,flag )
           last_data["close_time"] = data["close_time"]
           last_data["open_price"] = data["open_price"]
           last_data["close_price"] = data["close_price"]

       time.sleep(10) 

メインのループ部分です。
まず、flag["order"]["exist"]を確認し、Trueなら flag に check_order( flag )からの返り値を入れます。Falseなら何もしません。

次に、data に get_price(1,-2)からの返り値(最新のローソク足)を入れます。

last_dataとdataの"close_time"が違う場合(ローソク足の時間が更新された時)、print_price( data )で最新のローソク足を画面出力します。
更にflag["position"]["exist"]がTrueの場合、flag に close_position( data,last_data,flag )からの返り値を入れます。
flag["position"]["exist"]がFalseの場合、flag に buy_signal( data,last_data,flag )とsell_signal( data,last_data,flag )からの返り値を入れ、last_dataの各値をdataの値に書き換えます。

フローチャート作ってみました↓

画像19

解説終わり!!
最後のmain()でメイン関数が実行されます。
実行結果はこんな感じ↓

画像19

・・・・・・
エラー出るんかいッ!

一応動くんですが、check_candle関数の計算の部分でZeroDivisionErrorというエラーが出てしまうことがあります。初めて見た。
少し調べたら原因が分かったので、次回このエラー対策を施したコードを書きます。

長くなってしまったので今回はここまで。

この記事が気に入ったらサポートをしてみませんか?