Python {Article111}

ようこそ「Python」へ...

ITエンジニアが仮想通貨の自作自動売買システム(bot)で月収7万円のパッシブインカムを得るには [3] BOTのクラスを使用して自動トレードしてみる

ここではITエンジニアがPythonで仮想通貨の自動売買システム(BOT)を作成してパッシブインカム(Passive Income)を得る方法を解説します。 「仮想通貨のボット(BOT)でパッシブインカムを得る」シリースは以下の11回に分けて解説します。 第3回目ではこのシリーズで作成するBOTのクラスを使用して仮想通貨を自動トレードする方法を解説します。 なお、このシリーズで作成するBOTは日本の取引所「GMOコイン」を利用することを前提にしています。 bitFlyer、Binanceなどの取引所を利用するBOTについては後日、別記事にて解説します。

予め断っておきますが、BOTを作成したからといってすぐには稼げるようにはなりません。 3ヶ月から6ヶ月かけて仮想取引とリアル取引をしてBOTのアルゴリズムとパラメータを調整する必要があります。 そうすれば半年後には投資額にもよりますが月5万円から10万円くらいは稼げるようになっているはずです。

半年経っても月10万円稼げないときは次の「座右の銘」を思い出してください。 きっと稼げるようになるはずです。

「上がり始めたら買え(下がっている間は買うな)。 下がり始めたなら売れ(上がっている間は売るな)。 また、そもそも当てられるわけのない天井や底で売買しようとするな。 一番安いところで買ったり、 一番高いところで売れるものだと思うな。」 このシリーズではMicrosoftのVisual Studio Code(VS Code)を使用しますが、Jupyter NotebookなどのツールでもOKです。 説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。

【免責事項】
当記事や当サイトの情報を参考に仮想通貨のBOT(自動トレードプログラム)を動かす場合は、すべて自己責任でお願いいたします。 当サイトの情報を参考にして発生したいかなる損害も責任を負いません。


BOTのクラスを使用して仮想通貨を自動トレードしてみる

  1. Debugクラスのprint_log(), trace_write(), trace_warn(), trace_error(), sound_alert()メソッドを使ってみる

    ここで解説するDebugクラスの各種メソッドは仮想通貨の取引の履歴をログとして保存するために使用します。 Debugクラスのメソッドは「print系」と「trace系」に分類されています。 print系の「print_log()」はGvarクラスのdebug_modeプロパティの値(True/False)にかかわらず常に表示されます。 しかし、trace系の「trace_write(), trace_warn(), trace_error()」は「debug_mode=True」のときのみ表示されます。 つまり、BOTをデバッグ中のときは「debug_mode=True」で実行させてデバッグ情報を表示させます。 そして本番で実行させるときは「debug_mode=False」にして「print_log()」のデータのみ表示させます。 trace系のコードはPythonのプログラムから削除する必要はありません。 どちらのメソッドを使用してもデータは画面とログファイル双方に出力されます。

    Visual Studio Code (VS Code)を起動したら新規ファイルを作成して行1-70を入力(コピペ)します。 行2-27ではPythonのライブラリを取り込んでいます。 行28ではPythonの警告メッセージを抑止しています。

    行42ではGvarクラスのインスタンスを生成しています。 行43-46ではGvarクラスのプロパティ(属性)を設定しています。 ちなみにGvarとは「Global Variables」の略称です。

    行52ではDebugクラスのインスタンスを生成しています。 行54ではGvarクラスのdebug_modeプロパティに「True」を設定しています。 行56-59ではDebugクラスの各種メソッドを使用してメッセージを表示しています。 Debugクラスのメソッドを使用したときはメッセージが画面とログファイルに出力されます。 print_log()とtrace_write()は白色、trace_warn()は黄色、trace_error()は赤色で表示されます。

    行63ではGvarクラスのdebug_modeプロパティに「False」を設定しています。 行65-68ではDebugクラスのprint系とtrace系のメソッドでメッセージを出力していますが、 「debug_mode=False」なのでprint系のメッセージのみ表示されます。

    行60, 69ではDebugクラスのsound_alert()メソッドで警告音を鳴らしています。 このメソッドの引数には警告音の回数を指定します。 sound_alert()はBOTで深刻なエラーが発生したときや、 注文が約定したときなどに鳴らすといった使い方ができます。

    demo1.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    ################################################################################################################
    ### MAIN : Demo [1] Debug class: print_log(), trace_write(), trace_warn(), trace_error(), sound_alert() 
    ################################################################################################################
    
    #############################################################
    # instantiate gvar/debug classes and initialize properties
    #############################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    ######################################################################################
    # Debug class: print_log(), trace_write(), trace_warn(), trace_error(), sound_alert()  
    ######################################################################################
    gvar.callers_method_name = 'Demo1():'
    debug = Debug(gvar)
    debug.print_log(f'{Bcolors.OKGREEN}Demo1 Started{Bcolors.ENDC}')
    gvar.debug_mode = True
    debug.print_log(f'.... {Bcolors.HEADER}{gvar.debug_mode=}{Bcolors.ENDC}')
    debug.print_log('.... Debug: print_log(1)...')
    debug.trace_write('.... Debug: trace_write(1)...')
    debug.trace_warn('.... Debug: trace_warn(1)...')
    debug.trace_error('.... Debug: trace_error(1)...')
    debug.sound_alert(1)
    debug.print_log('.... ' + '.'*50)
    
    gvar.debug_mode = False
    debug.print_log(f'.... {Bcolors.HEADER}{gvar.debug_mode=}{Bcolors.ENDC}')
    debug.print_log('.... Debug: print_log(2)...')
    debug.trace_write('.... Debug: trace_write(2)...')
    debug.trace_warn('.... Debug: trace_warn(2)...')
    debug.trace_error('.... Debug: trace_error(2)...')
    debug.sound_alert(2)
    debug.print_log(f'{Bcolors.OKGREEN}Demo1 Ended{Bcolors.ENDC}')

    click image to zoom!
    図1-1
    図1-1は実行結果です。 Gvarのdebug_modeが「False」のときは、trace_write(), trace_warn(), trace_error()のメッセージが表示されません。


    click image to zoom!
    図1-2
    図1-2はログファイルの内容です。 画面と同様、debug_modeが「False」のときはtrace系のメソッドはメッセージがファイルに出力されません。

    ちなみになぜ画面だけでなくファイルにも出力するかと言えば、VS Codeにはすべてのメッセージが表示されないバグがあるからです。 また、画面だと後で見たいときにその都度コピペしてファイルに保存しておく必要があります。 このような不都合を回避するためにメッセージをログとしてファイルにも出力しています。


  2. Gmailクラスのsend_gmail_order()メソッドを使用して「買い注文」「売り注文」をGmailに送信してみる

    ここではGoogleのGmailにメールを送信するGmailクラスの使い方を説明します。 Gmailクラスには通常のメールを送信するsend_gmail()メソッドと、 注文に関連するメールを送信するsend_gmail_order()メソッドの2種類あります。 ここでは「send_gmail_order()」を使って「買い注文」と「売り注文」をGmailに送信します。

    Gmailを使用するには、2段階認証を設定してアプリ専用の16桁のパスワードを取得する必要があります。 Gmailの16桁のパスワードを取得する方法については 「記事(Article050)」で詳しく解説しています。 パスワードを取得したらVisual Studio Code (VS Code)を起動して新規ファイル「gmail_config.py」を作成して行1-7を入力します。 行5-7にはご自分のメールアドレスとパスワードを入力してください。

    gmail_config.py:
    ################## GmailConfig class
    class GmailConfig:
        GMAIL_SERVER = 'smtp.gmail.com'    # your smtp server
        GMAIL_PORT = 587                   # your port number
        GMAIL_FROM = '●●●@gmail.com'    # your from email id
        GMAIL_TO = '●●●@gmail.com'      # your to email ids  
        GMAIL_PASS = '●●●'              # your email id's password

    新規ファイルを作成したら行1-66を入力(コピペ)します。 行2-27ではPythonのライブラリを取り込んでいます。 行16-19では今回使用するGvar, Debug, Gamail, GmailConfigクラスを取り込んでいます。 行28ではPythonの警告メッセージを抑止しています。

    行42-46ではGvarクラスのインスタンスを生成して各種プロパティを設定しています。 行53ではDebugクラスのインスタンスを生成しています。 行60ではGmailクラスのインスタンスを生成しています。 行61, 63ではGmailクラスのsend_gmail_order()メソッドを使用して「買い注文」と「売り注文」のメールを送信しています。 このメソッドの引数1には仮想通貨のシンボル(BTC_JPY)を指定します。 引数2には「BUY」「SELL」のいずれかを指定します。 引数3にはメールの本文を指定します。 行56-57ではメールの本文を定義しています。

    demo2.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    ############################################################################
    ### MAIN Demo [2] Gmail class : send_gmail_order() 
    ############################################################################
    
    ##########################################################
    # instantiate gvar/coin class and initialize properties
    ##########################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    ###########################################################
    # Gmail class : send_gmail_order()  
    ###########################################################
    gvar.callers_method_name = 'Demo2():'
    gvar.debug_mode = True
    debug = Debug(gvar)
    debug.print_log(f'{Bcolors.OKGREEN}Demo2 {gvar.debug_mode=} Started{Bcolors.ENDC}')
    
    buy_order = f"create_buy_order(2022-09-20 01:15:00, BTC_JPY, qty=0.01, price=999999)"
    sell_order = f"create_sell_order(2022-09-20 01:20:00, BTC_JPY, qty=0.01, price=999999)"
    
    # send_gmail(symbol: str, side: str, order: str) -> None: 
    gmail = Gmail(gvar, debug)
    gmail.send_gmail_order('BTC_JPY', 'BUY', buy_order)
    debug.sound_alert(1)
    gmail.send_gmail_order('BTC_JPY', 'SELL', sell_order)
    debug.sound_alert(1)
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo2 Ended{Bcolors.ENDC}')

    click image to zoom!
    図2-1
    図2-1は実行結果です。


    click image to zoom!
    図2-2
    図2-2はGmailの受信画面です。 2件の受信メールの件名が表示されています。


    click image to zoom!
    図2-3
    図2-3はメールの本文を開いた画像です。 メールの本文はHTML形式で送信します。


  3. Apiクラスのget_crypto_try()メソッドを使ってビットコイン(BTC_JPY)の取引データを取得してみる

    ここではBOTの肝となるApiクラスの各種クラスのうち取引データを取得するget_crypto_try()メソッドについて説明します。 get_crypto_try()メソッドはget_crypto()メソッドの親メソッドです。 子メソッドのget_crypto()でタイムアウト等のエラーが発生したときは5回再試行します。

    VS Codeを起動したら新規ファイルを作成して行1-81を入力(コピペ)します。 行16ではGvar, Coinのクラスを取り込んでいます。 行17ではDebugのクラスを取り込んでします。 行20ではApiクラスを取り込んでいます。

    行39ではBOTが使用するフォルダ名を定義します。

    行42ではGvarクラスのインスタンスを生成しています。 行43-46ではGvarの各種プロパティを設定しています。

    行56-57ではCoinクラスのインスタンスを生成してsymbolプロパティにビットコインのシンボル「BTC_JPY」を設定しています。 ちなみに現物取引のシンボルは「BTC」、レバレッジ取引のシンボルは「BTC_JPY」となります。

    行58ではApiクラスのインスタンスを生成しています。 Apiクラスの引数1にはGvarクラスのオブジェクトを指定します。 引数2にはCoinクラスのオブジェクトを指定します。 ここではビットコイン(レバレッジ取引用)のCoinクラスを指定しています。

    行61ではApiクラスのget_crypto_try()メソッドでビットコインの取引データ(決済データ)を取得しています。 このメソッドの引数1にはページ番号を指定します。 引数2にはページ当たりのデータ件数を指定します。 ここでは1ページ当たり100件のデータを取得することを指定しています。 つまり、ビットコインの直近100件の取引データ(レバレッジ取引)を取得しています。

    get_crypto_try()メソッドからは、ステータスコード(status)と取引データがPandasのDataFrameに格納されて返されます。 このメソッドではタイムアウトなどのエラーが発生したときは5回再試行します。 行77ではDataFrameの先頭5件のデータを表示しています。 行79ではDataFrameの終端5件のデータを表示しています。

    demo3.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    #######################################################################################
    ### MAIN Demo [3] Api class : get_crypto_try(self, page: int, count: int) -> tuple:
    #######################################################################################
    
    ###########################################################
    # instantiate gvar/coin class and initialize properties
    ###########################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    ######################################################################
    # Api class : get_crypto_try(self, page: int, count: int) -> tuple:
    ######################################################################
    gvar.callers_method_name = 'Demo3():'
    gvar.debug_mode = True
    debug = Debug(gvar)
    debug.print_log(f'{Bcolors.OKGREEN}Demo3 ({gvar.debug_mode=}) Started{Bcolors.ENDC}')
    
    coin = Coin()              
    coin.symbol = 'BTC_JPY'
    api = Api(gvar, coin)       
    
    # get_crypto_try(page: int, count: int) -> tuple: return (status, df)
    status, df = api.get_crypto_try(page=1, count=100)    # get crypto (BTC_JPY)
    df = pd.DataFrame(df)   # cast(df)
    debug.print_log(f".... {gvar.callers_method_name} get_crypto_try(page=1, count=100) ▶ {status=}, {df.shape=} ")
    
    # error ?
    if status != 0:
        debug.trace_error(f"get_crypto_try(page=1, count=5) ▶ {status=}, quit python... ")
        quit()
    
    # empty dataframe ?
    if df.shape[0] == 0:
        debug.trace_error(f"get_crypto_try(page=1, count=5) ▶ dataframe is empty: {df.shape[0]=}, quit python... ")
        quit()
    
    # no errors & no empty dataframe
    print('-'*60)
    print(df.head(5))
    print('-'*60)
    print(df.tail(5))
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo3 Ended{Bcolors.ENDC}')

    click image to zoom!
    図3
    図3は実行結果です。 GMO Coinからビットコインの取引データ(決済データ)が100件返されています。 決済データには価格、売買区分(BUY/SELL)、数量、タイムスタンプ(UTC)が格納されています。 BOTはこれらの決済データを元に自動取引します。


  4. Csvクラスのwrite_buy_order(), get_buy_order(), update_buy_order()メソッドを使って注文ファイルを作成してみる

    ここで紹介するメソッドは、BOTに標準的に用意されているメソッドを使用するのではなく、 独自の手法で自動トレードを行うときに使います。 ちなみに、BOTには簡単に自動トレードを行うためにbuy_sell()、sell_buy()などのメソッドが用意されています。 これらのメソッドを使えばGMOとの売買取引から取引ごとの損益の計算までをすべて自動化することができます。

    ここではCsvクラスの各種メソッドの内、 write_buy_order(), get_buy_order(), update_buy_order()メソッドの使い方について説明します。

    行42-46ではGvarクラスのインスタンスを生成して各種プロパティを設定しています。 行53ではDebugクラスのインスタンスを生成しています。 行56-58ではCoin, Api, Csvクラスのインスタンスを生成しています。 ちなみに、Coin()クラスはデフォルトでビットコイン(BTC_JPY)のクラスを生成します。 仮想通貨のシンボルには「BTC_JPY」が設定されるのでレバレッジ用の取引になります。

    行61ではApiクラスのget_crypto_try()メソッドでGMOからビットコインの10件の取引データ(レバレッジ取引)を取得しています。

    行70-73ではビットコインの直近の取引データから最新の取引価格、タイムスタンプを取得しています。 行76ではCsvクラスのwrite_buy_order()メソッドで買い注文のデータをCSVファイルに保存しています。 CSVファイルの名称は「buy_order(BTC_JPY).csv」になります。

    行79ではCsvクラスのget_buy_order()メソッドで買い注文のCSVファイル「buy_order(BTC_JPY).csv」をPandasのDataFrameに取り込んでいます。 行87ではDataFrameの先頭から10件のデータを表示しています。

    行90-94ではCsvクラスのupdate_buy_order()メソッドで買い注文の約定数量(real_qty)、約定価格(real_price)を更新しています。

    行96-105ではCsvクラスのget_buy_order()メソッドで更新後の買い注文のデータをPandasのDataFrameに取り込んで先頭の10件を表示しています。

    demo4.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    #####################################################################################
    ### MAIN Demo [4] Csv class: write_buy_order(), get_buy_order(), update_buy_order()  
    #####################################################################################
    
    ###########################################################
    # instantiate gvar/coin class and initialize properties
    ###########################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    ######################################################################
    # Csv class: write_buy_order(), get_buy_order(), update_buy_order()     
    ###################################################################### 
    gvar.callers_method_name = 'Demo4():'
    gvar.debug_mode = True
    debug = Debug(gvar)
    debug.print_log(f'{Bcolors.OKGREEN}Demo4 ({gvar.debug_mode=}) Started{Bcolors.ENDC}')
    
    coin = Coin()               # Coin('BTC_JPY')
    api = Api(gvar, coin)       
    csv = Csv(gvar, coin)      
    
    ### get crypto data from gmo via api
    status, df = api.get_crypto_try(page=1, count=10)    # get crypto (BTC_JPY)
    debug.print_log(f".... {gvar.callers_method_name} get_crypto_try(page=1, count=10) ▶ {status=}, {df.shape[0]=} ")
    if status != 0 or df.shape[0] == 0:
        debug.trace_error(f"get_crypto_try(page=1, count=10) ▶ {status=}, {df.shape[0]=}: quit python... ")
        quit()
    
    ### no errors and no empty dataframe
    
    # get last timestamp and price from gmo dataframe
    buy_time = df.iloc[-1]['timestamp'] 
    sell_time = buy_time 
    qty = coin.qty 
    price = df.iloc[-1]['price']
    
    ### write_buy_order(buy_time: dt.datetime.utcnow, sell_time: dt.datetime.utcnow, qty: float, price: float, real_qty=0.0, real_price=0.0, real_fee=0.0) -> None:
    csv.write_buy_order(buy_time, sell_time, qty, price)  
    
    ### get_buy_order() -> pd.DataFrame:
    df = csv.get_buy_order()  
    # empty dataframe ?
    if df.shape[0] == 0:
        debug.trace_error(f"get_buy_order() ▶ dataframe is empty: {df.shape[0]=}. quit python... ")
        quit()
    
    ### no errors    
    print('-'*190)
    print(df.head())
    print('-'*190)
    
    col_name_list = ['real_qty', 'real_price']
    col_value_list = [qty, price + 100]
    
    ### update_buy_order(buy_time: dt.datetime.utcnow, col_name_list: list, col_value_list: list) -> None:
    csv.update_buy_order(buy_time, col_name_list, col_value_list)       
    
    df = csv.get_buy_order() 
    # empty dataframe ?
    if df.shape[0] == 0:
        debug.trace_error(f"get_buy_order() ▶ dataframe is empty: {df.shape[0]=}. quit python... ")
        quit()
    
    ### no errors 
    print('-'*190)
    print(df.head())
    print('-'*190)
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo4 Ended{Bcolors.ENDC}')

    click image to zoom!
    図4-1
    図4-1は実行結果です。 Csvクラスのwrite_buy_order()メソッドを実行して買い注文のCSVファイルを作成しています。 さらにupdate_buy_order()メソッドを実行して買い注文の約定数量と約定価格を更新しています。


    click image to zoom!
    図4-2
    図4-2は買い注文のCSVファイル「buy_order(BTC_JPY).csv」をExcelで開いた画面です。 注文の履歴をCSVファイルに保存しておくと後で確認するときに便利です。


  5. BOTのcreate_buy_order(), create_sell_order(), update_order()メソッドを使用してトレードしてみる

    ここではBuySellクラスの各種メソッドを使用してトレードする方法を説明します。 create_buy_order()メソッドは「買い注文」を自動的に行います。 内部的にはGMO CoinのAPI経由で実際の買い注文を出します。 ちなみに買い注文は「成行き」を使います。 成行きの買い注文が約定すると「買いポジション」を保持することになります。 さらに注文の履歴を残すために注文データをCSVファイルに保存します。

    create_sell_order()メソッドは「売り注文」を自動的に出します。 内部的にはGMO CoinのAPI経由で買いポジションを決済します。 ちなみに買いポジションの決済は「指値」を使います。 さらに注文の履歴を残すために注文データをCSVファイルに保存します。

    update_order()メソッドは、買いポジションの決済注文(売り注文)が約定したかどうか調べます。 約定しているときは損益ファイルに履歴を保存します。 まだ約定していないときは一定の時間待って再度約定しているか調べます。 これら一覧の処理を注文が約定するかストップロスの処理を行うまで繰り返します。

    行58-62ではCoin, Api, Csv, Trade, BuySellクラスのインスタンスを生成しています。 Coinクラスはデフォルトでビットコイン(BTC_JPY)用に生成されます。

    行70ではCsvクラスのdelete_file_driver()メソッドで「buy_sell」と「sell_buy」フォルダのすべてのファイルを削除します。

    行81-86のforループではGMO Coinから取引データを100件単位で5回取得しています。 合計500件の取引データを取得しています。 行89では取引データが格納されている5個のDataFrameを連結してマージしています。 これでPandasのDataFrameには500件の取引データが格納されます。

    行97ではPandasのDataFrameのsort_values()メソッドで取引データを「timestamp」の昇順に並べ替えています。 行100ではDataFrameのdrop_duplicates()メソッドで「taimestamp」が重複する取引データを削除しています。 重複しているときは最後の取引データを有効にします。

    行104-106ではDataFrameの取引データをCSVファイル「master(BTC_JPY).csv」に保存しています。 行107ではCoinクラスのset_master_df()メソッドでCoinクラスのプロパティ「master_df」にDataFrameを保存しています。

    行110ではCsvクラスのget_gmo_master()メソッドで行106で保存したCSVファイルをPandasのDataFrameに取り込んでいます。 行118-122ではDataFrameに新規のカラム名「symbol, buy_price, sell_price」を追加しています。 行125ではカラム値が空のとき前のデータで埋め込むようにしています。 行126ではDataFrameのカラム値が空のとき行を削除しています。

    行133-135ではDataFrameに格納されている取引データを「秒」単位で丸めています。 つまり、1秒間隔の取引データを生成しています。 行138ではDataFrameのカラム「timestamp」が重複する行を削除しています。 このとき重複する最後の行を有効にしています。

    行145-149ではDataFrameに新規カラム「open, close, low, high, size」を追加しています。 行155ではDataFrameのインデックスをリセットして採番しています。

    行158ではDataFrameのカラム名「timestamp」を「time」に変更しています。 行159ではDataFrameのカラム名(列名)を並べ替えています。 行162ではCoinクラスのset_master2_df()メソッドでCoinクラスのプロパティ「master2_df」にDataFrameを保存しています。

    行168ではBuySellクラスのreset_restart_process()メソッドで各種CSVファイルを初期化しています。

    行179-180では取引データが格納されているDataFrame(mas_df)から「BUY」の取引データのみ抽出して「mas_buy_df」に保存しています。 行186-187では取引データ(買注文)から最終行のカラム値「time, buy_price」を取得しています。 行188ではCoinクラスのプロパティから「qty(数量)」を取得しています。 qtyプロパティにはデフォルトでビットコインの最小値(0.01)が設定されています。

    行190ではBuySellクラスのcreate_buy_order()メソッドを実行して買い注文を出しています。 行198ではCsvクラスのget_buy_order()メソッドで買い注文のCSVファイルをPandasのDataFrameに取り込んでいます。

    行206-207では取引データ(mas_df)から「SELL」のデータのみ抽出して「mas_sell_df」に保存しています。 行213-214では売りの取引データから最終行のカラム値「time, sell_price」を取得しています。 行215ではTradeクラスのget_sell_price()メソッドで売値を取得しています。 売値は買値に利益率を掛けて計算しています。

    行218ではBuySellクラスのcreate_sell_order()メソッドで売り注文を出しています。 この場合、create_buy_order()で取得した買いポジションを決済(売り注文)していることになります。 ここでは利大損小になるように直近のマーケットの売値が計算した売値より高いときは、 マーケットの売値で指値の注文を出します。

    行228ではBuySellクラスのupdate_order()メソッドで売り注文が約定したかどうか調べます。 約定しているときは損益のExcelファイルに履歴を保存します。 約定していないときは一定時間経過してから再度約定しているかどうか調べます。 Gvarクラスのstop_lossプロパティに「True」を設定すると自動的にストップロスの処理も行います。

    demo5.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    ##############################################################################################################################################
    ### MAIN  Demo [5]  BuySell class: delete_file_driver(), reset_restart_process(), create_buy_order(), create_sell_order(), update_order()   
    ##############################################################################################################################################
    
    ###########################################################
    # instantiate gvar/coin class and initialize properties
    ###########################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    ##########################################################################################################################
    # BuySell class: delete_file_driver(), reset_restart_process(), create_buy_order(), create_sell_order(), update_order()    
    ########################################################################################################################## 
    gvar.real_mode = False    
    gvar.reset_mode = True
    gvar.debug_mode = True 
    gvar.callers_method_name = 'Demo5():'
    debug = Debug(gvar)
    debug.print_log(f'{Bcolors.OKGREEN}Demo5 ({gvar.real_mode=}, {gvar.reset_mode=}, {gvar.debug_mode=}) Started{Bcolors.ENDC}')
      
    coin = Coin()                       # Coin('BTC_JPY')
    api = Api(gvar, coin)           
    csv = Csv(gvar, coin)           
    trade = Trade(gvar, coin)       
    buysell = BuySell(gvar, coin)   
    
    symbol = coin.symbol
    
    ########################################################################
    ### 1: delete all csv files from buy_sell, sell_buy folders
    ########################################################################
    # delete_file_driver() -> None:  
    csv.delete_file_driver() 
    # debug.trace_warn(f".... delete_file_driver() ▶ completed... ")
    
    ########################################################################
    ### 2: load crypto data from GMO Coin
    ########################################################################
    
    # load crypto data from GMO
    df_list = []    # append 10 dataframe (GMO) 
    
    ### get crypto market data from GMO 1-5 pages
    for page in range(1, 6):   # (1,2,...5)        
        ### get_crypto_try(page: int, count: int) -> tuple:   return (status, df)
        status, df = api.get_crypto_try(page, count=100)      
        debug.trace_write(f".... get_crypto_try({page=}, count=100) ▶ {status=} {df.shape[0]=} ") 
        if status == 0: df_list.append(df)
        sleep(5)    # sleep 5 seconds
    
    # concatinate 10 dataframes 
    df = pd.concat(df_list, axis=0) # price, side, size, timestamp(UTC) descending order
    debug.trace_warn(f".... pd.concat(df_list={len(df_list)}, axis=0) ▶ {df.shape[0]=} ")
    
    ########################################################################
    ### 3: sort & drop duplicate data
    ########################################################################
    
    # sort by timestamp (ascending order of timestamp) 
    df.sort_values('timestamp', ascending=True, inplace=True)
        
    # drop duplicate time from the master dataframe
    df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True)   
    # debug.trace_warn(f".... df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) ▶ {df.shape[0]=} ")
    
    # save gmo master to disk
    csv_file = csv.folder_trading_type + f'master({symbol}).csv'
    # decktop-pc/bot/buy_sell/master(BTC_JPY).csv      
    df.to_csv(csv_file, index=False)    # overwrite 'master(BTC_JPY).csv' file 
    coin.set_master_df(df) # sorted by ascending order of timestamp   
    
    # get_gmo_master() -> pd.DataFrame:  
    df = csv.get_gmo_master()
    # debug.trace_warn(f".... get_gmo_master() ▶ {df.shape[0]=} ")
    
    ##########################################################################################
    ### 4: add columns into the master dataframe: symbol, buy_price, sell_price
    ##########################################################################################
    
    # add a symbol column into the master_df
    df['symbol'] = symbol  
    
    # add buy_price, sell_price into the master_df ★
    df['buy_price'] = df.apply(lambda row: row['price'] if row['side'] == 'BUY' else np.NaN, axis=1)
    df['sell_price'] = df.apply(lambda row: row['price'] if row['side'] == 'SELL' else np.NaN, axis=1) 
    
    # fill null with previous price from the master_df
    df.fillna(method='ffill', inplace=True)
    df.dropna(inplace=True)    
    # debug.trace_warn(f".... df.fillna(method='ffill', inplace=True) ▶ df.dropna(inplace=True) ▶ {df.shape[0]=} ")
    
    ######################################################################
    ### 5: round the timestamp column to 1S (1 second) or 1T (1 minute)
    ######################################################################
    # get a round timestamp freq 
    freq = coin.round_timestamp_freq # 1S or 1T      
    df['timestamp'] = df['timestamp'].apply(lambda x: x.round(freq=freq))       # round timestamp   
    df['timestamp'] = df['timestamp'].apply(lambda x: x.round(freq='S'))        # round seconds       
    
    # drop duplicate timestamp from the master dataframe
    df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) 
    # debug.trace_warn(f".... df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) ▶ {df.shape[0]=} ")
    
    ###############################################################################################
    ### 6: add open/close, low/high columns into the master dataframe : price => buy/sell price
    ###############################################################################################
    
    df['open']  = df.groupby('timestamp')['price'].transform('first')
    df['close'] = df.groupby('timestamp')['price'].transform('last')
    df['low']   = df.groupby('timestamp')['price'].transform('min')
    df['high']  = df.groupby('timestamp')['price'].transform('max')
    df['size']  = df.groupby('timestamp')['size'].transform('sum')
    
    ###################################################################################################################################################
    ### 7: rename timestamp to time and reorder columns => 'time','open','close','low','high','price','buy_price','sell_price','side','size','symbol' 
    ###################################################################################################################################################
    
    df.reset_index(drop=False, inplace=True) 
    
    # rename and reorder columns of the master_df
    df.rename(columns={'timestamp': 'time'}, inplace=True)  # ★        
    df = df[['time','open','close','low','high','price','buy_price','sell_price','side','size','symbol']]
    
    # save master_df to coin class 
    coin.set_master2_df(df)    # save final master_df to coin class   
    debug.trace_warn(f".... coin.set_master2_df(df) ▶ after round({freq=}) {df.shape[0]=} ")
    
    #############################################################################################################
    ### 8: reset_restart_process() -> None: 
    #############################################################################################################
    buysell.reset_restart_process()
    # debug.trace_warn(f".... reset_restart_process() completed...") 
    
    #############################################################################################################
    ### 9: create_buy_order(buy_time: dt.datetime.utcnow, qty: float, price: float) -> int:  # return status
    #############################################################################################################
    _q_ = coin.qty_decimal; _p_ = coin.price_decimal
    
    mas_df = df.copy()
    
    # filter gmo master
    filter_mask = mas_df['side'] == 'BUY'
    mas_buy_df = mas_df[filter_mask]
    if mas_buy_df.shape[0] == 0: 
        debug.trace_error(f".... buy master dataframe is empty: {mas_buy_df.shape[0]=}. quit python... ")
        quit()
    
    # get last buy_time, buy_price from gmo buy master 
    buy_time = mas_buy_df.iloc[-1]['time']
    buy_price = mas_buy_df.iloc[-1]['buy_price']
    qty = coin.qty
    
    status = buysell.create_buy_order(buy_time, qty, buy_price) 
    # debug.trace_warn(f".... create_buy_order({buy_time=:%Y-%m-%d %H:%M:%S}, {qty=:,.{_q_}f}, {buy_price=:,.{_p_}f}) ▶ {status=} ")
    # error ?
    if status != 0:
        debug.trace_error(f".... create_buy_order({buy_time=:%Y-%m-%d %H:%M:%S}, {qty=:,.{_q_}f}, {buy_price=:,.{_p_}f}) ▶ {status=}: quit python... ")
        quit()
    
    # get_buy_order()
    buy_df = csv.get_buy_order()
    # debug.trace_warn(f".... get_buy_order() ▶ {buy_df.shape[0]=} ")
    
    ###################################################################################################################
    ### 10: create_sell_order(sell_time: dt.datetime.utcnow, ms_price: float, buy_time: dt.datetime.utcnow) -> int:
    ###################################################################################################################
    
    ### filter gmo master
    filter_mask = mas_df['side'] == 'SELL'
    mas_sell_df = mas_df[filter_mask]
    if mas_sell_df.shape[0] == 0: 
        debug.trace_error(f".... sell master dataframe is empty: {mas_sell_df.shape[0]=}. quit python... ")
        quit()
    
    # get last sell_time and sell_price from gmo sell master
    sell_time = mas_sell_df.iloc[-1]['time']
    mas_sell_price = mas_sell_df.iloc[-1]['sell_price'] 
    new_sell_price = trade.get_sell_price(buy_price)
    if mas_sell_price > new_sell_price: new_sell_price = mas_sell_price
    
    status = buysell.create_sell_order(sell_time, new_sell_price, buy_time)
    # debug.trace_warn(f".... create_sell_order({sell_time=:%Y-%m-%d %H:%M:%S}, {new_sell_price=:,.{_p_}f}, {buy_time=:%Y-%m-%d %H:%M:%S}) ▶ {status=} ")
    # error ?
    if status != 0:
        debug.trace_error(f".... create_sell_order({sell_time=:%Y-%m-%d %H:%M:%S}, {new_sell_price=:,.{_p_}f}, {buy_time=:%Y-%m-%d %H:%M:%S}) ▶ {status=}: quit python... ")
        quit()
    
    #############################################
    ### 11: update_order() -> None:
    #############################################    
    buysell.update_order()
    # debug.trace_warn(f".... update_order() completed...")
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo5 Ended{Bcolors.ENDC}')

    click image to zoom!
    図5-1
    図5-1は実行結果です。 Csvクラスのdelete_file_driver()メソッドでは「buy_sell]と「sell_buy」フォルダからすべてのファイルを削除します。

    Apiクラスのget_crypto_try()メソッドでは取引所のGMO Coinからビットコイン(BTC_JPY)の取引データを500件取得してPandasのDataFrameに格納します。

    BuySellクラスのreset_restart_process()メソッドでは各種CSVファイルを初期化します。

    BuySellクラスのcreate_buy_order()メソッドではGMO Coinに対して買い注文(成行注文)を実行して各種注文ファイルに履歴を作成します。 この時点で買いのポジションを保持することになります。

    BuySellクラスのcreate_sell_order()メソッドでは買いのポジションを決済(売りの指値注文)します。

    BuySellクラスのupdate_order()メソッドでは買いポジションの決済が約定したかどうか監視して、 約定したときは各種CSVファイルを作成・更新します。 さらに損益のExcelファイルも作成します。


    click image to zoom!
    図5-2
    図5-2はBOTのフォルダ構成です。フォルダ「desktop-pc」直下にサブフォルダ「bot」を作成します。 さらにフォルダ「bot」の直下にサブフォルダ「buy_sell」と「sell_buy」を作成します。 フォルダ「buy_sell」には「買い注文▶売り注文」の取引履歴がCSVファイルに作成されます。 フォルダ「sell_buy」には「空売り注文▶買戻し注文」の取引履歴がCSVファイルに作成されます。

    ここでは「買い▶売り」注文を行っているので「buy_sell」フォルダに各種CSVファイルが作成されています。 損益のファイル「order(BTC_JPY).xlsx」はExcelの形式で作成されます。


  6. BOTのbuy_sell(), update_order()メソッドを使用してビットコイン(BTC_JPY)を自動トレードしてみる(ストップロス機能なし)

    ここではBuySellクラスの各種メソッドを使用してビットコイン(BTC_JPY)を自動トレードする方法を説明します。 前出のデモプログラムは修正して関数「auto_trade()」を作成します。 auto_trade()関数は前出のデモプログラムと類似しているので解説を省略します。

    auto_trade() function:
    ###############################
    def auto_trade(i: int) -> None:
        gvar.callers_method_name = f'auto_trade({i}):'
        debug.trace_warn(f".... auto_trade({i=})")
        symbol = coin.symbol
        
        ########################################################################
        ### 1: load crypto data from GMO Coin
        ########################################################################
    
        # load crypto data from GMO
        df_list = []    # append 10 dataframe (GMO) 
    
        ### get crypto market data from GMO 1-10 pages
        for page in range(1, 11):   # (1,2,...10)        
            ### get_crypto_try(page: int, count: int) -> tuple:   # return (status, df)
            status, df = api.get_crypto_try(page, count=100)    # (n, 100)  
            # debug.trace_write(f".... get_crypto_try({page=}, count=100) ▶ {status=} {df.shape[0]=} ") 
            if status == 0: df_list.append(df)
            sleep(5)    # sleep 5 seconds
    
        # concatinate 10 dataframes 
        current_df = pd.concat(df_list, axis=0) # price, side, size, timestamp(UTC) descending order
        debug.trace_warn(f".... pd.concat(df_list={len(df_list)}, axis=0) ▶ {current_df.shape[0]=} ")
    
        ### load gmo master
        # get_gmo_master() -> pd.DataFrame:  
        master_df = csv.get_gmo_master()
        # desktop-pc/bat/buysell/master(BTC_JPY).csv
    
        # merge master_df and current_df to df
        df = pd.concat([master_df, current_df], axis=0)
        debug.trace_warn(f".... pd.concat([master_df, current_df], axis=0) ▶ {df.shape[0]=} ")
    
        if df.shape[0] > 16_000:        
            start_row = df.shape[0] - 16_000
            # drop N rows from gmo master
            df = df.iloc[start_row:,:]  # keep max 16,000 rows (4 hours)   
    
        ########################################################################
        ### 2: sort & drop duplicate data
        ########################################################################
    
        # sort by timestamp (ascending order of timestamp) 
        df.sort_values('timestamp', ascending=True, inplace=True)
            
        # drop duplicate time from the master dataframe
        df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True)   
        # debug.trace_warn(f".... df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) ▶ {df.shape[0]=} ")
    
        # save gmo master to disk
        csv_file = csv.folder_trading_type + f'master({symbol}).csv'
        # decktop-pc/bot/buy_sell/master(BTC_JPY).csv  
        # decktop-pc/bot/sell_buy/master(BTC_JPY).csv        
        df.to_csv(csv_file, index=False)    # overwrite 'master(BTC_JPY).csv' file 
        coin.master_df = df # sorted by ascending order of timestamp   
    
        # get_gmo_master(self) -> pd.DataFrame:  
        df = csv.get_gmo_master()
        # debug.trace_warn(f".... get_gmo_master() ▶ {df.shape[0]=} ")
    
        ##########################################################################################
        ### 3: add columns into the master dataframe: symbol, buy_price, sell_price
        ##########################################################################################
    
        # add a symbol column into the master_df
        df['symbol'] = symbol  
    
        # add buy_price, sell_price into the master_df ★
        df['buy_price'] = df.apply(lambda row: row['price'] if row['side'] == 'BUY' else np.NaN, axis=1)
        df['sell_price'] = df.apply(lambda row: row['price'] if row['side'] == 'SELL' else np.NaN, axis=1) 
    
        # fill null with previous price from the master_df
        df.fillna(method='ffill', inplace=True)
        df.dropna(inplace=True)    
        # debug.trace_warn(f".... df.fillna(method='ffill', inplace=True) ▶ df.dropna(inplace=True) ▶ {df.shape[0]=} ")
    
        #####################################################################
        ### 4: round the timestamp column to 1S(1 second) or 1T (1 minute)
        #####################################################################
        # get a round timestamp freq 
        freq = coin.round_timestamp_freq       
        df['timestamp'] = df['timestamp'].apply(lambda x: x.round(freq=freq))       # round timestamp   
        df['timestamp'] = df['timestamp'].apply(lambda x: x.round(freq='S'))        # round seconds       
    
        # drop duplicate timestamp from the master dataframe
        df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) 
        # debug.trace_warn(f".... df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) ▶ {df.shape[0]=} ")
    
        ###############################################################################################
        ### 5: add open/close, low/high columns into the master dataframe : price => buy/sell price
        ###############################################################################################
    
        df['open']  = df.groupby('timestamp')['price'].transform('first')
        df['close'] = df.groupby('timestamp')['price'].transform('last')
        df['low']   = df.groupby('timestamp')['price'].transform('min')
        df['high']  = df.groupby('timestamp')['price'].transform('max')
        df['size']  = df.groupby('timestamp')['size'].transform('sum')
    
        ###################################################################################################################################################
        ### 6: rename timestamp to time and reorder columns => 'time','open','close','low','high','price','buy_price','sell_price','side','size','symbol' 
        ###################################################################################################################################################
    
        df.reset_index(drop=False, inplace=True) 
    
        # rename and reorder columns of the master_df
        df.rename(columns={'timestamp': 'time'}, inplace=True)  # ★        
        df = df[['time','open','close','low','high','price','buy_price','sell_price','side','size','symbol']]
    
        # save master_df to coin class 
        coin.master2_df = df    # save final master_df to coin class   
        debug.trace_warn(f".... coin.master2_df = df ▶ after round({freq=}) {df.shape[0]=} ")
    
        ###################################################################################################################
        ### 7: buy_sell(algorithm_id: int) -> None:
        ###################################################################################################################  
    
        # buy_sell(algorithm_id: int) -> None:
        buysell.buy_sell(algorithm_id=0)
        # debug.trace_warn(f".... buy_sell(algorithm_id=0) completed... ")
    
        ###################################################################################################################
        ### 10: update_order() -> None:
        ###################################################################################################################    
    
        buysell.update_order()
        # debug.trace_warn(f".... update_order() completed...")
        debug.print_log('.... ' + '.'*180)
    
        return

    デモプログラムのメインでは関数「auto_trade()」を呼び込むように修正します。

    行44-58ではGvarクラスのインスタンスを生成して各種プロパティを設定しています。 行60-65ではDebug, Coin, Api, Csv, Trade, BuySellクラスのインスタンスを生成しています。

    行70-90ではGvarクラスのreset_modeプロパティが「True」のとき初期化処理を行います。 行75ではCsvクラスのdelete_file_driver()メソッドを呼び出してフォルダ「buy_sell」と「sell_buy」のすべてのファイルを削除します。 行83ではApiクラスのload_master_driver()メソッドを呼び出してGMOから取引データを取り込んでCSVファイルに保存します。 行88ではBuySellクラスのreset_restart_process()メソッドを呼び出して各種CSVファイルを初期化します。

    行96-99のwhileループでは関数「auto_trade()」を呼び出してビットコインの自動トレードを行います。 無限ループさせるときは、行99のbreakをコメントアウトして実行してください。

    demo6.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    ### <= insert auto_trade() function here
    
    #################################################################################################################################
    ### MAIN  Demo [6]  BuySell class: BuySell class: delete_file_driver(), reset_restart_process(), buy_sell(), update_order()
    #################################################################################################################################
    
    ############################################################################
    # instantiate gvar/coin class and initialize properties
    ############################################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    #####################################################################################################################
    # Demo [6]  BuySell class: BuySell class: delete_file_driver(), reset_restart_process(), buy_sell(), update_order()     
    #################################################################################################################### 
    ### start Demo6
    gvar.real_mode = False    
    gvar.reset_mode = True
    gvar.stop_loss = False 
    gvar.debug_mode = True 
    gvar.callers_method_name = 'Demo6():'
    
    debug = Debug(gvar)
    coin = Coin()                   # Coin('BTC_JPY')
    api = Api(gvar, coin)           
    csv = Csv(gvar, coin)           
    trade = Trade(gvar, coin)       
    buysell = BuySell(gvar, coin)   
    symbol = coin.symbol
    
    debug.print_log(f"{Bcolors.OKGREEN}Demo6 ({gvar.real_mode=}, {gvar.reset_mode=}, {gvar.stop_loss=}, {gvar.debug_mode=}) Started{Bcolors.ENDC}")
    
    if gvar.reset_mode:
        ###############################################################
        ### 1: delete all csv files from buy_sell, sell_buy folder
        ###############################################################
        # delete_file_driver() -> None:  
        csv.delete_file_driver() 
        # debug.trace_warn(f".... delete_file_driver() ▶ completed... ")
    
        ###################################################
        ### 2: load the master data from GMO
        ###################################################
        gvar.callers_method_name = 'load_master_data():'
        # load_master_driver(symbol_list: list, coin_list: list, page: int, count: int) -> None:
        api.load_master_driver([coin.symbol], [coin], page=1, count=10) 
    
        #########################################
        ### 3: reset_restart_process() -> None: 
        #########################################
        buysell.reset_restart_process()
        # debug.trace_warn(f".... reset_restart_process() completed...") 
        debug.print_log('.... ' + '.'*180)
    
    ###########################
    ### auto trade
    ###########################
    i = 0
    while True:    
        i += 1
        auto_trade(i)
        break # <= comment out a break statement
    # end of while True:
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo6 Ended{Bcolors.ENDC}')

    click image to zoom!
    図6
    図6は実行結果です。 画面には「auto_trade(i=1)」が表示されていますが、「i=1」は1回目のループであることを意味します。 これで自動トレードが何回繰り返し実行されているかがわかります。


  7. BOTのbuy_sell(), update_order()メソッドを使用してビットコイン(BTC_JPY)を自動トレードしてみる(ストップロス機能付き)

    ここでは前出のデモプログラムにストップロスの機能を追加しています。 ストップロスの機能を追加するにはGvarクラスのstop_lossプロパティに「True」を設定します。 これでBuySellクラスのupdate_order()メソッドを呼び出すと自動的にストップロスの処理が行われます。

    ここではさらにGvarクラスのreset_modeプロパティに「False」を設定しています。 この場合、前出のデモ6の状態を引き継いで処理を継続します。

    demo7.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')    
    
    ###############################
    def auto_trade(i: int) -> None:
        :::
        return
    
    
    ##############################################################################################################################################
    ### MAIN  Demo [7]  BuySell class: BuySell class: delete_file_driver(), reset_restart_process(), buy_sell(), update_order(), stop_loss=True
    ##############################################################################################################################################
    
    ############################################################################
    # instantiate gvar/coin class and initialize properties
    ############################################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    
    ######################################################################################################################################
    # Demo [7]  BuySell class: BuySell class: delete_file_driver(), reset_restart_process(), buy_sell(), update_order(), stop_loss=True     
    ##################################################################################################################################### 
    ### start Demo7
    gvar.real_mode = False    
    gvar.reset_mode = False         # ★
    gvar.stop_loss = True           # ★
    gvar.debug_mode = True 
    gvar.callers_method_name = 'Demo7():'
    
    debug = Debug(gvar)
    coin = Coin()                   # Coin('BTC_JPY')
    api = Api(gvar, coin)           
    csv = Csv(gvar, coin)           
    trade = Trade(gvar, coin)       
    buysell = BuySell(gvar, coin)   
    symbol = coin.symbol
    
    debug.print_log(f"{Bcolors.OKGREEN}Demo7 ({gvar.real_mode=}, {gvar.reset_mode=}, {gvar.stop_loss=}, {gvar.debug_mode=}) Started{Bcolors.ENDC}")
    
    if gvar.reset_mode:
        :::
    
    ###########################
    ### auto trade
    ###########################
    i = 0
    while True:    
        i += 1
        auto_trade(i)
        break # <= comment out a break statement
    # end of while True:
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo7 Ended{Bcolors.ENDC}')

    click image to zoom!
    図7
    図7は実行結果です。 画面に「stop_loss(0)」が表示されています。


  8. BOTの各種クラスを使用してビットコイン(BTC_JPY)を2種類の方法(「買い▶売り」「空売り▶買戻し」)で自動トレードしてみる

    ここでは前出のデモプログラムを改善してビットコイン(BTC_JPY)を2種類の方法(「買い▶売り」「空売り▶買戻し」)で自動トレードする方法を説明します。

    前出の関数「auto_trade()」をBuySellクラスとSellBuyクラスの双方に対応するように修正します。

    行119のPythonのeval()では、BuySellクラスのbuy_sell()メソッドか、SellBuyクラスのsell_buy()メソッドのいずれかを呼び出します。

    行130ではBuySellクラス、またはSellBuyクラスのいずれかのupdate_order()メソッドを呼び出します。

    auto_trade() function:
    ###############################
    def auto_trade(i: int) -> None:
        gvar.callers_method_name = f'auto_trade({i}):'
        debug.trace_warn(f".... auto_trade({i=})")
        symbol = coin.symbol
    
        #######################################
        ### 1: load crypto data from GMO Coin
        #######################################
    
        # load crypto data from GMO
        df_list = []    # append 10 dataframe (GMO) 
    
        ### get crypto market data from GMO 1-10 pages
        for page in range(1, 11):   # (1,2,...10)        
            ### get_crypto_try(page: int, count: int) -> tuple:   # return (status, df)
            status, df = api.get_crypto_try(page, count=100)    # (n, 100)  
            # debug.trace_write(f".... get_crypto_try({page=}, count=100) ▶ {status=} {df.shape[0]=} ") 
            if status == 0: df_list.append(df)
            sleep(5)    # sleep 5 seconds
    
        # concatinate 10 dataframes 
        current_df = pd.concat(df_list, axis=0) # price, side, size, timestamp(UTC) descending order
        debug.trace_warn(f".... pd.concat(df_list={len(df_list)}, axis=0) ▶ {current_df.shape[0]=} ")
    
        ### load gmo master
        # get_gmo_master() -> pd.DataFrame:  
        master_df = csv.get_gmo_master()
        # desktop-pc/bot/buysell/master(BTC_JPY).csv
        # desktop_pc/bot/sellbuy/master(BTC_JPY).csv
    
        # merge master_df and current_df to df
        df = pd.concat([master_df, current_df], axis=0)
        debug.trace_warn(f".... pd.concat([master_df, current_df], axis=0) ▶ {df.shape[0]=} ")
    
        if df.shape[0] > 16_000:        
            start_row = df.shape[0] - 16_000
            # drop N rows from gmo master
            df = df.iloc[start_row:,:]  # keep max 16,000 rows    
    
        ########################################
        ### 2: sort & drop duplicate data
        ########################################
    
        # sort by timestamp (ascending order of timestamp) 
        df.sort_values('timestamp', ascending=True, inplace=True)
            
        # drop duplicate time from the master dataframe
        df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True)   
        # debug.trace_warn(f".... df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) ▶ {df.shape[0]=} ")
    
        # save gmo master to disk
        csv_file = csv.folder_trading_type + f'master({symbol}).csv'
        # decktop-pc/bot/buy_sell/master(BTC_JPY).csv  
        # decktop-pc/bot/sell_buy/master(BTC_JPY).csv        
        df.to_csv(csv_file, index=False)    # overwrite 'master(BTC_JPY).csv' file 
        coin.master_df = df # sorted by ascending order of timestamp   
    
        # get_gmo_master(self) -> pd.DataFrame:  
        df = csv.get_gmo_master()
        # debug.trace_warn(f".... get_gmo_master() ▶ {df.shape[0]=} ")
    
        ##########################################################################################
        ### 3: add columns into the master dataframe: symbol, buy_price, sell_price
        ##########################################################################################
    
        # add a symbol column into the master_df
        df['symbol'] = symbol  
    
        # add buy_price, sell_price into the master_df ★
        df['buy_price'] = df.apply(lambda row: row['price'] if row['side'] == 'BUY' else np.NaN, axis=1)
        df['sell_price'] = df.apply(lambda row: row['price'] if row['side'] == 'SELL' else np.NaN, axis=1) 
    
        # fill null with previous price from the master_df
        df.fillna(method='ffill', inplace=True)
        df.dropna(inplace=True)    
        # debug.trace_warn(f".... df.fillna(method='ffill', inplace=True) ▶ df.dropna(inplace=True) ▶ {df.shape[0]=} ")
    
        #####################################################################
        ### 4: round the timestamp column to 1S (1second) or 1T (1 minute)
        #####################################################################
        # get a round timestamp freq 
        freq = coin.round_timestamp_freq       
        df['timestamp'] = df['timestamp'].apply(lambda x: x.round(freq=freq))       # round timestamp   
        df['timestamp'] = df['timestamp'].apply(lambda x: x.round(freq='S'))        # round seconds       
    
        # drop duplicate timestamp from the master dataframe
        df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) 
        # debug.trace_warn(f".... df.drop_duplicates(subset=['timestamp'], keep='last', inplace=True) ▶ {df.shape[0]=} ")
    
        ###############################################################################################
        ### 5: add open/close, low/high columns into the master dataframe : price => buy/sell price
        ###############################################################################################
    
        df['open']  = df.groupby('timestamp')['price'].transform('first')
        df['close'] = df.groupby('timestamp')['price'].transform('last')
        df['low']   = df.groupby('timestamp')['price'].transform('min')
        df['high']  = df.groupby('timestamp')['price'].transform('max')
        df['size']  = df.groupby('timestamp')['size'].transform('sum')
    
        ###################################################################################################################################################
        ### 6: rename timestamp to time and reorder columns => 'time','open','close','low','high','price','buy_price','sell_price','side','size','symbol' 
        ###################################################################################################################################################
    
        df.reset_index(drop=False, inplace=True) 
    
        # rename and reorder columns of the master_df
        df.rename(columns={'timestamp': 'time'}, inplace=True)  # ★        
        df = df[['time','open','close','low','high','price','buy_price','sell_price','side','size','symbol']]
    
        # save master_df to coin class 
        coin.master2_df = df    # save final master_df to coin class   
        debug.trace_warn(f".... coin.master2_df = df ▶ after round({freq=}) {df.shape[0]=} ")
        
        ##############################################
        ### 7: call buy_sell() or sell_buy()
        ##############################################  
    
        eval(f'tradeBoth.{coin.trade_type}')(0)    # call 'tradeBoth.buy_sell' or 'tradeBoth.sell_buy' method
    
        # if coin.trade_type == 'buy_sell':
        #     tradeBoth.buy_sell(algorithm_id=0)
        # else:   # 'sell_buy'
        #     tradeBoth.sell_buy(algorithm_id=0)        
    
        ##############################################
        ### 8: update_order() -> None:
        ##############################################    
    
        tradeBoth.update_order()
        # debug.trace_warn(f".... update_order() completed...")
    
        return
    デモプログラム(demo8.py)の行42ではビットコインのシンボル「BTC_JPY」をペアで定義します。 行46では「buy_sell」と「sell_buy」を定義します。 行51では2個のCoinクラスのインスタンスを生成して格納します。

    行70-102のforループではビットコインのCoinクラスに各種プロパティを設定しています。 行153-167のwhileループでは関数「auto_trade()」を呼び出して自動トレードしています。 行166ではCoinクラスの「trade_type」プロパティを調べてBuySell, SellBuyクラスのインスタンスを生成して「tradeBoth」に保存します。 行167では関数「auto_trade()」を呼び出しています。 これで自動的に「buy_sell」と「sell_buy」の自動トレードが実行されます。 行170をコメントアウトすれば無限ループします。 つまり、24時間365日自動トレードできます。

    demo8.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore') 
    
    ###############################
    def auto_trade(i: int) -> None:
        :::
        return
    
    ################################################################################
    ### MAIN Demo [8]  BuySell(), SellBuy() classes  
    ################################################################################
    
    # -----------------------------------------------------------------------------                              
    #                             1             2                              
    # -----------------------------------------------------------------------------
    symbol_list                 = ['BTC_JPY',   'BTC_JPY']      # crypto symbol for leverage trade
    round_timestamp_list        = ['1S',        '1S']           # gmo master freq: H-hour, T-minute, S-seconds, L-milliseconds 
    suspend_list                = [False,       False]          # active(BTC_JPY)      
    master_not_found_list       = [False,       False]          # used to add coins
    trade_type_list             = ['buy_sell',  'sell_buy'] 
    qty_list                    = [0.01,        0.01]           # min qty            
    profit_rate_list            = [1.0015,      1.0015]        
    leverage_fee_list           = [0.0004,      0.0004]         
    stop_loss_rate_list         = [0.0200,      0.0200]          
    coin_list                   = [Coin(),      Coin()]  
    
    ############################################################################
    # instantiate gvar/coin class and initialize properties
    ############################################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    gvar.coin_list = coin_list
    
    ### update Coin class properties
    active_coin_list = []
    for i, symbol in enumerate(symbol_list):     
        coin = coin_list[i]  
        coin.symbol = symbol      
        coin.suspend = suspend_list[i]  
    
        if not coin.suspend: 
            active_coin_list.append(coin)               
        
        coin.round_timestamp_freq = round_timestamp_list[i]  
        coin.master_csv_not_found = master_not_found_list[i] 
        coin.master_df = pd.DataFrame()   
        coin.master2_df = pd.DataFrame()  
    
        coin.real_mode = gvar.real_mode   
        coin.debug_mode = gvar.debug_mode
    
        coin.fake_or_real = 'real' if gvar.real_mode else 'fake'    # 'real' or 'fake'
        coin.trade_type = trade_type_list[i]                        # 'buy_sell' or 'sell_buy'                                  
    
        coin.qty = qty_list[i]                       
       
        coin.profit_rate = profit_rate_list[i]                             
        coin.leverage_fee_rate = leverage_fee_list[i]      
        coin.stop_loss_rate = stop_loss_rate_list[i]                   
        
        coin.price_decimal = 3 if coin.symbol == 'XRP_JPY' else 0
    
        if coin.symbol in 'BTC_JPY' :
            coin.qty_decimal = 2 
        elif coin.symbol in 'ETH_JPY,BCH_JPY':
            coin.qty_decimal = 1 
        else: # 'LTC_JPY,XRP_JPY'
            coin.qty_decimal = 0   
    
    ############################################################################
    # BuySell(), SellBuy() classes    
    ############################################################################ 
    
    ### start Demo8
    gvar.real_mode = False    
    gvar.reset_mode = True
    gvar.debug_mode = True 
    gvar.stop_loss = True  
    gvar.callers_method_name = 'Demo8():'
    
    debug = Debug(gvar)
    coin = coin_list[0]             
    api = Api(gvar, coin)           
    csv = Csv(gvar, coin)           
    trade = Trade(gvar, coin)       
    
    debug.print_log(f"{Bcolors.OKGREEN}Demo8 ({gvar.real_mode=}, {gvar.reset_mode=}, {gvar.stop_loss=}, {gvar.debug_mode=}) Started{Bcolors.ENDC}")
    
    if gvar.reset_mode:
        ########################################################################
        ### 1: delete all csv files from buy_sell, sell_buy folder
        ########################################################################
        # delete_file_driver() -> None:  
        csv.delete_file_driver() 
    
        ########################################################################
        ### 2: load crypto data from GMO
        ########################################################################
        gvar.callers_method_name = 'load_master_data():'
        # load_master_driver(symbol_list: list, coin_list: list, page: int, count: int) -> None:
        api.load_master_driver(symbol_list, coin_list, page=1, count=10) 
    
    #######################################################################
    ### 3: reset_restart_process() -> None: 
    #######################################################################
    gvar.callers_method_name = 'reset_restart_process():'
    for i, _ in enumerate(symbol_list):       
        coin = coin_list[i] 
        if not coin.suspend:                                     
            if gvar.reset_mode or coin.master_csv_not_found: 
                tradeBoth = BuySell(gvar, coin) if coin.trade_type == 'buy_sell' else SellBuy(gvar, coin) 
                tradeBoth.reset_restart_process()        
    # end of for i, _ in enumerate(symbol_list):  
    
    #######################################################
    ### 4: auto_trade() 
    #######################################################
    i = 0
    while True:    
        i += 1
    
        for j, symbol in enumerate(symbol_list):      
            # suspend coin ?                          
            if coin_list[j].suspend: continue  
    
            ### get or instantiate classes : Coin, Api, Csv, Trade, BuySell, SellBuy
        
            coin = coin_list[j]             # get coin class  
            api = Api(gvar, coin)             
            csv = Csv(gvar, coin)           
            trade = Trade(gvar, coin)       
            tradeBoth = BuySell(gvar, coin) if coin.trade_type == 'buy_sell' else SellBuy(gvar, coin)
            auto_trade(i)
        # end of for j, symbol in enumerate(symbol_list): 
    
        break   # <= comment out 
    # end of while True:
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo8 Ended{Bcolors.ENDC}')

    click image to zoom!
    図8-1
    図8-1は実行結果です。 画面には「BuySell()」のログが表示されています。


    click image to zoom!
    図8-2
    図8-2は実行結果です。 画面には「SellBuy()」のログが表示されています。


  9. 前出のBOTに仮想通貨ごとの利益、約定件数、ロスカットの件数を表示する

    ここでは前出のデモプログラムに仮想通貨ごとの利益、約定件数、ロスカットの件数を表示する機能を追加しています。

    行172ではTradeクラスのprint_profit_driver()メソッドを呼び出して仮想通貨ごとの損益を表示します。 行176ではTradeクラスのprint_order_count_driver()メソッドを呼び出して仮想通貨ごとの約定件数を表示します。 行180ではTradeクラスのprint_loss_cut_count_driver()メソッドを呼び出して仮想通貨ごとのロスカット件数を表示します。

    demo9.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')    
        
    ###############################
    def auto_trade(i: int) -> None:
        :::
        return
    
    ################################################################################
    ### MAIN Demo [9]  profit, order count, loss cut count  
    ################################################################################
    
    # -----------------------------------------------------------------------------                              
    #                             1             2                              
    # -----------------------------------------------------------------------------
    symbol_list                 = ['BTC_JPY',   'BTC_JPY']      # crypto symbol for leverage trade
    round_timestamp_list        = ['1S',        '1S']           # gmo master freq: H-hour, T-minute, S-seconds, L-milliseconds 
    suspend_list                = [False,       False]          # active(BTC_JPY)      
    master_not_found_list       = [False,       False]          # used to add coins
    trade_type_list             = ['buy_sell',  'sell_buy'] 
    qty_list                    = [0.01,        0.01]           # min qty            
    profit_rate_list            = [1.0015,      1.0015]        
    leverage_fee_list           = [0.0004,      0.0004]         
    stop_loss_rate_list         = [0.0200,      0.0200]          
    coin_list                   = [Coin(),      Coin()]  
    
    ############################################################################
    # instantiate gvar/coin class and initialize properties
    ############################################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    gvar.coin_list = coin_list
    
    ### update Coin class properties
    active_coin_list = []
    for i, symbol in enumerate(symbol_list):     
        coin = coin_list[i]  
        coin.symbol = symbol      
        coin.suspend = suspend_list[i]  
    
        if not coin.suspend: 
            active_coin_list.append(coin)               
        
        coin.round_timestamp_freq = round_timestamp_list[i]  
        coin.master_csv_not_found = master_not_found_list[i] 
        coin.master_df = pd.DataFrame()   
        coin.master2_df = pd.DataFrame()  
    
        coin.real_mode = gvar.real_mode   
        coin.debug_mode = gvar.debug_mode
    
        coin.fake_or_real = 'real' if gvar.real_mode else 'fake'    # 'real' or 'fake'
        coin.trade_type = trade_type_list[i]                        # 'buy_sell' or 'sell_buy'                                  
    
        coin.qty = qty_list[i]                       
       
        coin.profit_rate = profit_rate_list[i]                             
        coin.leverage_fee_rate = leverage_fee_list[i]      
        coin.stop_loss_rate = stop_loss_rate_list[i]                   
        
        coin.price_decimal = 3 if coin.symbol == 'XRP_JPY' else 0
    
        if coin.symbol in 'BTC_JPY' :
            coin.qty_decimal = 2 
        elif coin.symbol in 'ETH_JPY,BCH_JPY':
            coin.qty_decimal = 1 
        else: # 'LTC_JPY,XRP_JPY'
            coin.qty_decimal = 0   
    
    ############################################################################
    # BuySell(), SellBuy() classes    
    ############################################################################ 
    
    ### start Demo9
    gvar.real_mode = False    
    gvar.reset_mode = True
    gvar.debug_mode = True 
    gvar.stop_loss = True  
    gvar.callers_method_name = 'Demo9():'
    
    debug = Debug(gvar)
    coin = coin_list[0]             # Coin('BTC_JPY')
    api = Api(gvar, coin)           
    csv = Csv(gvar, coin)           
    trade = Trade(gvar, coin)       
    
    debug.print_log(f"{Bcolors.OKGREEN}Demo9 ({gvar.real_mode=}, {gvar.reset_mode=}, {gvar.stop_loss=}, {gvar.debug_mode=}) Started{Bcolors.ENDC}")
    
    if gvar.reset_mode:
        ########################################################################
        ### 1: delete all csv files from buy_sell, sell_buy folder
        ########################################################################
        # delete_file_driver() -> None:  
        csv.delete_file_driver() 
    
        ########################################################################
        ### 2: load crypto data from GMO
        ########################################################################
        gvar.callers_method_name = 'load_master_data():'
        # load_master_driver(symbol_list: list, coin_list: list, page: int, count: int) -> None:
        api.load_master_driver(symbol_list, coin_list, page=1, count=10) 
    
    #######################################################################
    ### 3: reset_restart_process() -> None: 
    #######################################################################
    gvar.callers_method_name = 'reset_restart_process():'
    for i, _ in enumerate(symbol_list):       
        coin = coin_list[i] 
        if not coin.suspend:                                     
            if gvar.reset_mode or coin.master_csv_not_found: 
                tradeBoth = BuySell(gvar, coin) if coin.trade_type == 'buy_sell' else SellBuy(gvar, coin) 
                tradeBoth.reset_restart_process()        
    # end of for i, _ in enumerate(symbol_list):  
    
    #######################################################
    ### 4: auto_trade() 
    #######################################################
    i = 0
    while True:    
        i += 1
    
        for j, _ in enumerate(symbol_list):      
            # suspend coin ?                          
            if coin_list[j].suspend: continue  
    
            ### get or instantiate classes : Coin, Api, Csv, Trade, BuySell, SellBuy
        
            coin = coin_list[j]             # get coin class  
            api = Api(gvar, coin)             
            csv = Csv(gvar, coin)           
            trade = Trade(gvar, coin)       
            tradeBoth = BuySell(gvar, coin) if coin.trade_type == 'buy_sell' else SellBuy(gvar, coin)
            auto_trade(i)
        # end of for j, _ in enumerate(symbol_list): 
    
        ### print monthly, weekly, daily profit  
        # print_profit_driver(symbol_list: list, coin_list: list) -> None:
        trade.print_profit_driver(symbol_list, coin_list)
    
        ### print monthly, weekly, daily closed order count 
        # print_order_count_driver(symbol_list: list, coin_list: list) -> None:
        trade.print_order_count_driver(symbol_list, coin_list)
    
        ### print loss cut count    
        # print_loss_cut_count_driver(symbol_list: list, coin_list: list) -> None:
        trade.print_loss_cut_count_driver(symbol_list, coin_list)
    
        break   # <= comment out 
    # end of while True:
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo9 Ended{Bcolors.ENDC}')

    click image to zoom!
    図9-1
    図9-1は実行結果です。「BuySell」の注文が約定しています。


    click image to zoom!
    図9-2
    図9-2は実行結果です。 「BuySell」と「SellBuy」を22回繰り返した時点の損益、約定件数、ロスカットの件数が表示されています。 この画面では「BuySell」が1件約定しています。


  10. BOTの各種クラスを使用して5種類の仮想通貨(BTC_JPY, ETH_JPY, BCH_JPY, LTC_JPY, XRP_JPY)を自動トレードしてみる

    ここでは前出のデモプログラムを修正して5種類全ての仮想通貨を自動トレードするようにしています。 自動トレードは「buy_sell」と「sell_buy」の2種類行います。

    行43では5種類の仮想通貨のシンボルをペアで定義します。 行45ではすべての仮想通貨に対して「False」を定義します。 行47では1~5までは「buy_sell」を、6~10までは「sell_buy」を定義します。

    行157-168のforループでは全ての仮想通貨に対して「buy_sell」と「sell_buy」の注文を自動で行います。 もちろん無条件に注文を出すのではなく、一定のアルゴリズムに従って利大損小になるようにします。 無限ループさせるときは、行183をコメントアウトしてください。

    demo10.py:
    ### Import the libraries 
    import os
    import os.path
    
    import time
    from time import sleep    
    import datetime as dt
    from datetime import timedelta
    
    import numpy as np
    import pandas as pd
    import pandas_ta as pa  
    
    import matplotlib.pyplot as plt
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug                 # dependencies Gvar
    from lib.gmail import Gmail                 # dependencies Gvar, Debug, GmailConfig
    from lib.gmail_config import GmailConfig      
    from lib.api import Api                     # dependencies Gvar, Coin
    from lib.csv import Csv                     # dependencies Gvar, Coin
    from lib.trade import Trade                 # dependencies Gvar, Coin
    from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import argparse
    import warnings
    warnings.simplefilter('ignore')
    
    ###############################
    def auto_trade(i: int) -> None:    
        :::
        return
        
    
    ################################################################################
    ### MAIN Demo [10]  add all coins (buy_sell, sell_buy)   
    ################################################################################
    
    # -----------------------------------------------------------------------------------------------------------------------------------------------------------                               
    #                             1             2            3          4           5           6           7           8           9           10                   
    # -----------------------------------------------------------------------------------------------------------------------------------------------------------
    symbol_list                 = ['BTC_JPY',  'ETH_JPY',  'BCH_JPY',   'LTC_JPY',  'XRP_JPY',  'BTC_JPY',  'ETH_JPY',  'BCH_JPY',   'LTC_JPY',  'XRP_JPY']     # crypto symbol for leverage trade
    round_timestamp_list        = ['1S',        '1T',       '1T',       '1T',       '1T',       '1S',        '1T',       '1T',       '1T',       '1T']          # gmo master freq: H-hour, T-minute, S-seconds, L-milliseconds 
    suspend_list                = [False,       False,      False,      False,      False,      False,       False,      False,      False,      False]           
    master_not_found_list       = [False,       False,      False,      False,      False,      False,       False,      False,      False,      False]         # used to add coins
    trade_type_list             = ['buy_sell', 'buy_sell', 'buy_sell', 'buy_sell', 'buy_sell',  'sell_buy', 'sell_buy', 'sell_buy', 'sell_buy', 'sell_buy'] 
    qty_list                    = [0.01,        0.1,        0.1,        1,          10,         0.01,        0.1,        0.1,        1,          10]            # min qty            
    profit_rate_list            = [1.0015,      1.0015,     1.0015,     1.0015,     1.0035,     1.0015,      1.0015,     1.0015,     1.0015,     1.0035]        
    leverage_fee_list           = [0.0004,      0.0004,     0.0004,     0.0004,     0.0004,     0.0004,      0.0004,     0.0004,     0.0004,     0.0004]         
    stop_loss_rate_list         = [0.0200,      0.0200,     0.0200,     0.0200,     0.0200,     0.0200,      0.0200,     0.0200,     0.0200,     0.0200]          
    coin_list                   = [Coin(),      Coin(),     Coin(),     Coin(),     Coin(),     Coin(),      Coin(),     Coin(),     Coin(),     Coin()]  
    
    ############################################################################
    # instantiate gvar/coin class and initialize properties
    ############################################################################
    
    ### define constants
    FOLDER_NAME = 'bot'
    
    ### initiate Gvar class
    gvar = Gvar()
    gvar.exchange = FOLDER_NAME                             # bot
    gvar.domain = os.environ['USERDOMAIN'].lower()          # 'desktop-pc' or 'note-pc'
    gvar.folder_gmo =  f'{gvar.domain}/{gvar.exchange}/'    # 'desktop-pc/bot/'   
    gvar.callers_method_name = '_main_:'
    gvar.coin_list = coin_list
    
    ### update Coin class properties
    active_coin_list = []
    for i, symbol in enumerate(symbol_list):     
        coin = coin_list[i]  
        coin.symbol = symbol      
        coin.suspend = suspend_list[i]  
    
        if not coin.suspend: 
            active_coin_list.append(coin)               
        
        coin.round_timestamp_freq = round_timestamp_list[i]  
        coin.master_csv_not_found = master_not_found_list[i] 
        coin.master_df = pd.DataFrame()   
        coin.master2_df = pd.DataFrame()  
    
        coin.real_mode = gvar.real_mode   
        coin.debug_mode = gvar.debug_mode
    
        coin.fake_or_real = 'real' if gvar.real_mode else 'fake'    # 'real' or 'fake'
        coin.trade_type = trade_type_list[i]                        # 'buy_sell' or 'sell_buy'                                  
    
        coin.qty = qty_list[i]                       
       
        coin.profit_rate = profit_rate_list[i]                             
        coin.leverage_fee_rate = leverage_fee_list[i]      
        coin.stop_loss_rate = stop_loss_rate_list[i]                   
        
        coin.price_decimal = 3 if coin.symbol == 'XRP_JPY' else 0
    
        if coin.symbol in 'BTC_JPY' :
            coin.qty_decimal = 2 
        elif coin.symbol in 'ETH_JPY,BCH_JPY':
            coin.qty_decimal = 1 
        else: # 'LTC_JPY,XRP_JPY'
            coin.qty_decimal = 0   
    
    ############################################################################
    # BuySell(), SellBuy() classes    
    ############################################################################ 
    
    ### start Demo10
    gvar.real_mode = False    
    gvar.reset_mode = True
    gvar.debug_mode = True 
    gvar.stop_loss = True  
    gvar.callers_method_name = 'Demo10():'
    
    debug = Debug(gvar)
    coin = coin_list[0]             # Coin('BTC_JPY')
    api = Api(gvar, coin)           
    csv = Csv(gvar, coin)           
    trade = Trade(gvar, coin)       
    
    debug.print_log(f"{Bcolors.OKGREEN}Demo10 ({gvar.real_mode=}, {gvar.reset_mode=}, {gvar.stop_loss=}, {gvar.debug_mode=}) Started{Bcolors.ENDC}")
    
    if gvar.reset_mode:
        ########################################################################
        ### 1: delete all csv files from buy_sell, sell_buy folder
        ########################################################################
        # delete_file_driver() -> None:  
        csv.delete_file_driver() 
    
        ########################################################################
        ### 2: load crypto data from GMO
        ########################################################################
        gvar.callers_method_name = 'load_master_data():'
        # load_master_driver(symbol_list: list, coin_list: list, page: int, count: int) -> None:
        api.load_master_driver(symbol_list, coin_list, page=1, count=10) 
    
    #######################################################################
    ### 3: reset_restart_process() -> None: 
    #######################################################################
    gvar.callers_method_name = 'reset_restart_process():'
    for i, _ in enumerate(symbol_list):       
        coin = coin_list[i] 
        if not coin.suspend:                                     
            if gvar.reset_mode or coin.master_csv_not_found: 
                tradeBoth = BuySell(gvar, coin) if coin.trade_type == 'buy_sell' else SellBuy(gvar, coin) 
                tradeBoth.reset_restart_process()        
    # end of for i, _ in enumerate(symbol_list):  
    
    #######################################################
    ### 4: auto_trade() 
    #######################################################
    i = 0
    while True:    
        i += 1
    
        for j, _ in enumerate(symbol_list):      
            # suspend coin ?                          
            if coin_list[j].suspend: continue  
    
            ### get or instantiate classes : Coin, Api, Csv, Trade, BuySell, SellBuy
        
            coin = coin_list[j]             # get coin class  
            api = Api(gvar, coin)             
            csv = Csv(gvar, coin)           
            trade = Trade(gvar, coin)       
            tradeBoth = BuySell(gvar, coin) if coin.trade_type == 'buy_sell' else SellBuy(gvar, coin)
            auto_trade(i)
        # end of for j, _ in enumerate(symbol_list): 
    
        ### print monthly, weekly, daily profit  
        # print_profit_driver(symbol_list: list, coin_list: list) -> None:
        trade.print_profit_driver(symbol_list, coin_list)
    
        ### print monthly, weekly, daily closed order count 
        # print_order_count_driver(symbol_list: list, coin_list: list) -> None:
        trade.print_order_count_driver(symbol_list, coin_list)
    
        ### print loss cut count    
        # print_loss_cut_count_driver(symbol_list: list, coin_list: list) -> None:
        trade.print_loss_cut_count_driver(symbol_list, coin_list)
    
        break   # <= comment out 
    # end of while True:
    
    debug.print_log(f'{Bcolors.OKGREEN}Demo10 Ended{Bcolors.ENDC}')

    click image to zoom!
    図10-1
    図10-1は実行結果です。 これは自動トレードを11回繰り返した時点の画像です。 合計12件が約定しています。 「BTC_JPY(buy_sell)」と「LTC_JPY(sell_buy)」がともに3件でトップとなっています。

    このデモでは注文時の数量を最小値にしているので利益の金額は無視してください。 画面から「SellBuy(空売り▶買戻し)」の注文が多く約定しているのがわかります。 ちなみに当日は仮想通貨が暴落したときでした。 この画面からも分かるようにレバレッジ取引は空売りの注文ができるので、 相場が上がっても下がっても利益を出すことができます。


    click image to zoom!
    図10-2
    図10-2は仮想通貨(BCH_JPY)の「BuySell」の取引の損益をExcelで開いた画像です。 図10-1の利益額(29円)と一致しています。 注文数が最小値なので金額の大小は無視してください。


    click image to zoom!
    図10-3
    図10-3は仮想通貨(LTC_JPY)の「SellBuy」の取引の損益をExcelで開いた画像です。 図10-1の利益額(132円)と一致しています。 注文数が最小値なので金額の大小は無視してください。