Python {Article117}

ようこそ「Python」へ...

ITエンジニアが仮想通貨の自作自動売買システム(bot)で月収7万円のパッシブインカムを得るには [9] BOTのTradeクラスを作成する

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

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

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

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

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

BOTのTradeクラスを作成する前に、予め以下の「オブジェクト指向プログラミング」のシリーズを読んでクラスの基本を理解してください。

BOTのTradeクラスを作成する

  1. Tradeクラスを作成して__init__(), __str__()メソッドを追加する

    ここではTradeクラスを作成して__init__(), __str__()メソッドを追加します。 Tradeクラスには、 後述するBuySellクラス、SellBuyクラスで使用する共通の各種メソッドがまとめて登録されています。

    __init__()メソッドはTradeクラスのインスタンスを生成したときに自動的に呼ばれます。 __str__()メソッドはprint()等でTradeクラスを表示したときに呼ばれます。 __init__()、__str__()の詳しいことは、 「記事(Article085)」、 「記事(Article087)」で詳しく解説しています。

    trade.py:
    # trade.py
    
    """
    Trade class
    """
    
    # import the libraries
    from time import sleep  
    import datetime as dt
    from datetime import timedelta
    
    import math
    import statistics
    from decimal import Decimal
    
    import numpy as np
    import pandas as pd
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug
    from lib.csv import Csv
    
    import warnings
    warnings.simplefilter('ignore')
    
    
    ############ trade libraries  class
    class Trade:
        """
        __init__(self, gvar, coin), __str__()  
        df_empty(), find_order()
        get_buy_price(), get_sell_price()
        get_order_status(), get_closed_order_count(), get_order_close_count()
        convert_float_qty_to_str(), convert_float_price_to_str() 
        calculate_profit()
        print_profit_driver(), print_order_count_driver(), print_loss_cut_count_driver()
        maintenance_time(), time_to_charge_leverage_fee()
        update_get_price_response_for_debug1_1(), update_get_price_response_for_debug1_2(), update_get_price_response_for_debug2()    
        """              
                
        #######################################################
        def __init__(self, gvar: object, coin: object) -> None: 
            self.gvar = gvar                                 
            self.coin = coin                            
            self.debug = Debug(gvar)                    
            self.csv = Csv(self.gvar, self.coin)        
    
            self.folder_gmo =  f'{self.gvar.domain}/{self.gvar.exchange}/'  # desktop-pc/bot/            
            self.folder_trading_type =  f'{self.gvar.domain}/{self.gvar.exchange}/{self.coin.trade_type}/'  
            # desktop-pc/bot/buy_sell/            
            # desktop-pc/bot/sell_buy/
    
            return
    
        #########################
        def __str__(self) -> str:
            return f"Trade({self.folder_gmo=}, {self.folder_trading_type=})"

    click image to zoom!
    図1
    図1はデモプログラムの実行結果です。 Tradeクラスの各種プロパティが表示されています。


  2. Tradeクラスにmaintenance_time()メソッドを追加する



    trade.py:
        ###################################
        def maintenance_time(self) -> bool:
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            ### check GMO maintenance wed 15:00 - 16:30 (14:45 - 17:00) 
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            today = dt.datetime.today()
            day_of_week = today.strftime('%A')  # Wednesday
            if day_of_week == 'Wednesday':
                now_time = dt.datetime.now().time()            
                tocompare = dt.datetime.strptime('14:45:00', '%H:%M:%S')
                from_time = dt.time(tocompare.hour, tocompare.minute, tocompare.second)
                tocompare = dt.datetime.strptime('17:00:00', '%H:%M:%S')   
                to_time = dt.time(tocompare.hour, tocompare.minute, tocompare.second)        
                # between 14:45 ~ 17:00 ?    
                if now_time >= from_time and now_time <= to_time:
                    return True
            
            return False  

  3. Tradeクラスにtime_to_charge_leverage_fee()メソッドを追加する



    trade.py:
        ##############################################
        def time_to_charge_leverage_fee(self) -> bool:
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            ### set a close_pending_order : 05:00 - 06:00 (04:55 - 06:05)
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            local_timezone = dt.timezone(dt.timedelta(hours=+9))  # adjust to JP local timezone 
            current_time = dt.datetime.now().astimezone(local_timezone).time()
            from_time = dt.datetime.strptime("04:55AM", "%I:%M%p").time()   
            to_time = dt.datetime.strptime("06:05AM", "%I:%M%p").time()         
            if current_time >= from_time and current_time <= to_time:
                # print('current time is between 04:55AM - 06:05AM')
                return True
            else:
                # print('current time is NOT between 04:55AM - 06:05AM')
                return False
            # end of if current_time >= from_time and current_time <= to_time:        
    
            return

  4. Tradeクラスにprint_profit_driver()メソッドを追加する



    trade.py:
        ##########################################################################
        def print_profit_driver(self, symbol_list: list, coin_list: list) -> None:
    
            ##########################################################
            ### print monthly, weekly, daily profit
            ##########################################################
            
            ### calculate monthly, weekly, daily profit for each coin : REAL MODE
            d_profit_list = []; w_profit_list = []; m_profit_list = []
            for i, _ in enumerate(symbol_list):   
                coin = coin_list[i] # Coin(coin_list[i])
                if coin.suspend: 
                    d_profit_list.append(0); w_profit_list.append(0); m_profit_list.append(0)
                else:
                    trade = Trade(self.gvar, coin)
                    d_profit = trade.calculate_profit(term='D')
                    w_profit = trade.calculate_profit(term='W')
                    m_profit = trade.calculate_profit(term='M')
                    d_profit_list.append(d_profit)
                    w_profit_list.append(w_profit)
                    m_profit_list.append(m_profit)            
            # end of for i, _ in enumerate(symbol_list):
    
            # print monthly profit
            profit = round(sum(m_profit_list), 0) 
            self.debug.print_log(f"{Bcolors.OKGREEN}monthly profit{Bcolors.ENDC}: {profit:,.0f} Yen ")       
            
            profit_list = []
            for i in range(0, len(symbol_list)):       
                profit = m_profit_list[i]   
                profit_list.append(profit)        
    
            symbol_len = len(symbol_list)   # 1,2,3,4,5...10
            
            profit_msg = f"{Bcolors.OKGREEN}monthly profit by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f}), "
                else:    
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f})"
            self.debug.print_log(profit_msg)   
    
            # print weekly profit
            profit = round(sum(w_profit_list), 0) 
            self.debug.print_log(f"{Bcolors.OKGREEN}weekly profit{Bcolors.ENDC}: {profit:,.0f} Yen ")         
            
            profit_list = []
            for i in range(0, len(symbol_list)):      
                profit = w_profit_list[i]   
                profit_list.append(profit)  
    
            profit_msg = f"{Bcolors.OKGREEN}weekly profit by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f}), "
                else:    
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f})"
            self.debug.print_log(profit_msg)                          
         
            # print daily profit
            profit = round(sum(d_profit_list), 0) 
            self.debug.print_log(f"{Bcolors.OKGREEN}daily profit{Bcolors.ENDC}: {profit:,.0f} Yen ")         
            
            profit_list = []
            for i in range(0, len(symbol_list)):    
                profit = d_profit_list[i]   
                profit_list.append(profit)        
    
            profit_msg = f"{Bcolors.OKGREEN}daily profit by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f}), "
                else:    
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f})"
            self.debug.print_log(profit_msg)         
    
            self.debug.print_log('-'*175)
    
            return

  5. Tradeクラスにprint_order_count_driver()メソッドを追加する



    trade.py:
        ###############################################################################
        def print_order_count_driver(self, symbol_list: list, coin_list: list) -> None:
    
            #######################################################################
            ### print monthly, weekly, daily closed order count 
            #######################################################################
    
            ### get monthly, weekly, daily closed order count for each coin  
            d_count_list = []; w_count_list = []; m_count_list = []
            for i, _ in enumerate(symbol_list):   
                coin = coin_list[i] # Coin(coin_list[i])
                if coin.suspend: 
                    d_count_list.append(0); w_count_list.append(0); m_count_list.append(0)
                else:
                    trade = Trade(self.gvar, coin)
                    d_cnt = trade.get_closed_order_count(term='D')
                    w_cnt = trade.get_closed_order_count(term='W')
                    m_cnt = trade.get_closed_order_count(term='M')
                    d_count_list.append(d_cnt)
                    w_count_list.append(w_cnt)
                    m_count_list.append(m_cnt)                    
            # end of for i, _ in enumerate(symbol_list):
    
            symbol_len = len(symbol_list)   # 1,2,3,4,5
    
            # print monthly order count
            count_sum = sum(m_count_list) 
            self.debug.print_log(f"{Bcolors.OKGREEN}monthly order count{Bcolors.ENDC}: {count_sum} ")                  
            count_list = []
            for i in range(0, len(symbol_list)):        
                cnt = m_count_list[i]       
                count_list.append(cnt)
            
            count_msg = f"{Bcolors.OKGREEN}monthly order count by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    count_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    count_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(count_msg) 
    
            # print weekly order count
            count_sum = sum(w_count_list) 
            self.debug.print_log(f"{Bcolors.OKGREEN}weekly order count{Bcolors.ENDC}: {count_sum} ")                  
            count_list = []
            for i in range(0, len(symbol_list)):        
                cnt = w_count_list[i]       
                count_list.append(cnt)
            
            count_msg = f"{Bcolors.OKGREEN}weekly order count by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    count_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    count_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(count_msg)       
    
            # print daily order count
            count_sum = sum(d_count_list) 
            self.debug.print_log(f"{Bcolors.OKGREEN}daily order count{Bcolors.ENDC}: {count_sum} ")                  
            count_list = []
            for i in range(0, len(symbol_list)):        
                cnt = d_count_list[i]       
                count_list.append(cnt)
    
            count_msg = f"{Bcolors.OKGREEN}daily order count by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    count_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    count_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(count_msg) 
         
            self.debug.print_log('-'*175)     
    
            return

  6. Tradeクラスにprint_loss_cut_count_driver()メソッドを追加する



    trade.py:
        ##################################################################################
        def print_loss_cut_count_driver(self, symbol_list: list, coin_list: list) -> None:
    
            #############################################
            ### print loss cut count    
            #############################################
    
            lc5_list = []; lc10_list = []; lc15_list = []; lc18_list = []; lc20_list = [] 
            for i, _ in enumerate(symbol_list):       
                coin = coin_list[i] # Coin(coin_list[i])         
                if coin.suspend: 
                    lc5_list.append(0); lc10_list.append(0); lc15_list.append(0); lc18_list.append(0); lc20_list.append(0) 
                else:
                    # o_coin = coin_list[i]   # get the current coin class  
                    lc5_list.append(coin.buy_sell_lc5)
                    lc10_list.append(coin.buy_sell_lc10)
                    lc15_list.append(coin.buy_sell_lc15)
                    lc18_list.append(coin.buy_sell_lc18)
                    lc20_list.append(coin.buy_sell_lc20)
            # end of for i, _ in enumerate(symbol_list):  
    
            symbol_len = len(symbol_list)   # 1,2,3,4,5
    
            # print loss cut count    
            self.debug.print_log(f"{Bcolors.OKGREEN}loss cut by % {Bcolors.ENDC}: ")                  
            count_list = []
            for i in range(0, len(symbol_list)):      
                cnt = lc5_list[i]           
                count_list.append(cnt)
    
            loss_cut_msg = f"{Bcolors.OKGREEN}05% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)               
    
            count_list = []
            for i in range(0, len(symbol_list)):   
                cnt = lc10_list[i]          
                count_list.append(cnt)
            
            loss_cut_msg = f"{Bcolors.OKGREEN}10% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)     
    
            count_list = []
            for i in range(0, len(symbol_list)):      
                cnt = lc15_list[i]          
                count_list.append(cnt)
            
            loss_cut_msg = f"{Bcolors.OKGREEN}15% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)  
    
            count_list = []
            for i in range(0, len(symbol_list)):       
                cnt = lc18_list[i]          
                count_list.append(cnt)
    
            loss_cut_msg = f"{Bcolors.OKGREEN}18% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)  
    
            count_list = []
            for i in range(0, len(symbol_list)):      
                cnt = lc20_list[i]         
                count_list.append(cnt)
            
            loss_cut_msg = f"{Bcolors.OKGREEN}20% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)  
    
            return

  7. Tradeクラスにget_order_status()メソッドを追加する



    trade.py:
        ################################################# get a order status from the order csv file
        def get_order_status(self, exclude=True) -> bool: # return order_completed      
            symbol = self.coin.symbol
    
            # open order csv file
            # get_order_csv() -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot//buy_sell/order(BTC_JPY).csv    
            # desktop-pc/bot//sell_buy/order(BTC_JPY).csv 
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------         
    
            order_completed = False       
    
            while True:
                # empty order csv file ?     
                if df.shape[0] == 0:         
                    order_completed = True
                    # self.debug.trace_warn(f".... DEBUG: {order_completed=}, {df.shape[0]=} ")
                    break   # exit while true
    
                # get a stop_loss/cancelled/order_closed flag
                ord_order_closed = df.iloc[-1]['order_closed']
                ord_stop_loss = df.iloc[-1]['stop_loss']
                ord_cancelled = df.iloc[-1]['cancelled']
                
                # self.debug.trace_warn(f".... DEBUG: {ord_order_closed=}, {ord_stop_loss=}, {ord_cancelled=}, {order_completed=}")
    
                # exclude stop_loss, cancelled order info
                if exclude:
                    if ord_stop_loss or ord_cancelled:
                        order_completed = False
                    elif ord_order_closed:
                        order_completed = True
                else: # include stop_loss, cancelled order info
                    if ord_order_closed or ord_stop_loss or ord_cancelled:
                        order_completed = True 
                  
                break   # exit while true
            # end of while true                                  
            
            # self.debug.trace_warn(f".... DEBUG: get_order_status(exclude={exclude}) ▶ order_completed={order_completed}, df.shape={df.shape} ")
            return order_completed

  8. Tradeクラスにcalculate_profit()メソッドを追加する



    trade.py:
        ############################################### calculate profit for each coin : order csv file
        def calculate_profit(self, term: str) -> float:  # return net profit
            symbol = self.coin.symbol   
    
            if term == 'D':
                day1=1; day2=0; day3=1
            elif term == 'W':
                day1=7; day2=6; day3=1
            elif term == 'M':
                day1=31; day2=30; day3=1
            else:
                return 0          
    
            ################################################################# DEBUG
            # date_str = '2022-05-16 05:59:59'
            # date_str = '2022-05-16 06:00:01'
            # now = dt.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
            ################################################################# DEBUG
            now = dt.datetime.now()
            now_time = now.time()
            # print(now_time)
            tocompare = dt.datetime.strptime('06:00:00', '%H:%M:%S')
            tocompare = dt.time(tocompare.hour, tocompare.minute, tocompare.second)
            # print(tocompare)
    
            if now_time < tocompare:
                # print(f'now_time({now_time}) < tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day1), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now, '%Y-%m-%d' + ' 06:00:00')                              # 2022-05-17 06:00:00
            else: # greater than or equal to 06:00:00
                # print(f'now_time({now_time}) >= tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day2), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now + dt.timedelta(days=day3), '%Y-%m-%d' + ' 06:00:00')    # 2022-05-17 06:00:00
                
            # print(start_date_str, '~', end_date_str)
    
            start_date = dt.datetime.strptime(start_date_str, '%Y-%m-%d %H:%M:%S')
            end_date = dt.datetime.strptime(end_date_str, '%Y-%m-%d %H:%M:%S')
    
            # print(start_date,'~', end_date)
    
            # get_order_csv(self) -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot//buy_sell/order(BTC_JPY).csv         
        
            if df.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): #0 order info csv file not found ▶ date range={start_date}~{end_date}, net_profit=0 ")
                return 0
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------             
           
            ### 1: filter order csv by date range (daily, weekly, monthly)
            filter_mask = (df['log_time'] >= start_date) & (df['log_time'] < end_date) 
            dfx = df[filter_mask]        
                 
            # empty datafarame ? => return 
            if dfx.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): #1 filterd order info is empty ▶ date range={start_date}~{end_date}, net_profit=0 ")
                return 0
    
            ### 2: calculate accumulated leverage fee
            leverage_fee_sum = dfx['accumulated_leverage_fee'].sum()
    
            ### 3: filter closed order csv : buy_real_qty == sell_real_qty
    
            # filter closed order info by date range  (daily, weekly, monthly)
            filter_mask = (df['log_time'] >= start_date) & (df['log_time'] < end_date) & (df['buy_real_qty'] == df['sell_real_qty'])
            dfx = df[filter_mask]
              
            # empty datafarame ? => return 
            if dfx.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): #2 filterd order info is empty ▶ date range={start_date}~{end_date}, net_profit=0 ")
                return 0
           
            ### 4: calculate net profit : profit = rounddown((sell_real_price - buy_real_price) * sell_real_qty)
            dfx['rate_diff'] = dfx.apply(lambda row: row['sell_real_price'] - row['buy_real_price'], axis=1)    
            dfx['real_profit'] = dfx.apply(lambda row: math.floor(row['rate_diff'] * row['sell_real_qty']) , axis=1)  # IMPORTANT: do not used math.ceil() for negative value => use math.floor()     
             
            profit = dfx['real_profit'].sum() 
            net_profit = math.floor(profit - leverage_fee_sum)                 
    
            # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): net_profit({net_profit:,.0f}) = profit({profit:,.0f}) - leverage_fee({leverage_fee_sum:,.0f}) ")
            return net_profit   

  9. Tradeクラスにupdate_get_price_response_for_debug1_1(), update_get_price_response_for_debug1_2()メソッドを追加する



    trade.py:
        ######################################################################################################## update get_price() response for debug1_1  
        def update_get_price_response_for_debug1_1(self, res_df: pd.DataFrame, loop_count: int) -> pd.DataFrame: # called from create_buy_order()
            ### creates two buy order subs for each buy order header
            symbol = self.coin.symbol
    
            if loop_count == 1:
                ### loop_count == 1: return 2 rows => add 2 buy order subs 
                qty1_1 = 0.0; qty1_2 = 0.0
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01], [0.02]                             
                    qty1_1 = 0.01; qty1_2 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1], [0.2]
                    qty1_1 = 0.1; qty1_2 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1], [0.2]
                    qty1_1 = 0.1; qty1_2 = 0.1 
                elif symbol.startswith('LTC'):          # 4 [1, 1], [2]
                    qty1_1 = 1; qty1_2 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10], [20]
                    qty1_1 = 10; qty1_2 = 10                         
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
    
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id + '-1', 
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'BUY',         
                                    'size': qty1_1,     # XRP_JPY: 10
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id + '-2', 
                                    'price': res_price, 
                                    'settleType': 'OPEN',   
                                    'side': 'BUY',         
                                    'size': qty1_2,     # XRP_JPY: 10
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                        
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()                          
            else: # loop_count > 1
                ### loop_count == 2: return 1 row  => add 1 buy order sub 
                qty2 = 0.0
                if symbol.startswith('BTC'):        # 0.04 [0.01, 0.01], [0.02]                             
                    qty2 = 0.02                         
                elif symbol.startswith('ETH'):      # 0.4 [0.1, 0.1], [0.2]
                    qty2 = 0.2 
                elif symbol.startswith('BCH'):      # 0.4 [0.1, 0.1], [0.2]
                    qty2 = 0.2 
                elif symbol.startswith('LTC'):      # 4 [1, 1], [2]
                    qty2 = 2 
                elif symbol.startswith('XRP'):      # 40 [10, 10], [20]
                    qty2 = 20                  
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
                               
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']            
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id + '-3',
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'BUY',         
                                    'size': qty2,   # XRP_JPY:20 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                        
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()                           
            # end of if loop_count == 1:     
             
            return res_df            
    
        ################################################################################################################ update get_price() response for debug1_2  
        def update_get_price_response_for_debug1_2(self, res_df: pd.DataFrame, sell_order_sub_seq: int) -> pd.DataFrame: # called form update_order()
            ### creates two sell order subs for each sell order header
            symbol = self.coin.symbol
    
            # first sell order sub ?
            if sell_order_sub_seq == 1:
                qty1 = 0.0         
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01, 0.01, 0.01]                             
                    qty1 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty1 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty1 = 0.1  
                elif symbol.startswith('LTC'):          # 4 [1, 1, 1, 1]
                    qty1 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10, 10, 10]
                    qty1 = 10 
                else:
                    pass     
                # end of if symbol.startswith('BTC'):                                                                                          
                qty = qty1
            elif sell_order_sub_seq == 2:
                qty2 = 0.0         
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01, 0.01, 0.01]                             
                    qty2 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty2 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty2 = 0.1  
                elif symbol.startswith('LTC'):          # 4 [1, 1, 1, 1]
                    qty2 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10, 10, 10]
                    qty2 = 10 
                else:
                    pass                                                                              
                # end of if symbol.startswith('BTC'):   
                qty = qty2                        
            elif sell_order_sub_seq == 3:
                qty3_1 = 0.0; qty3_2 = 0.0         
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01, 0.01, 0.01]                             
                    qty3_1 = 0.01; qty3_2 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty3_1 = 0.1; qty3_2 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty3_1 = 0.1; qty3_2 = 0.1  
                elif symbol.startswith('LTC'):          # 4 [1, 1, 1, 1]
                    qty3_1 = 1; qty3_2 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10, 10, 10]
                    qty3_1 = 10; qty3_2 = 10 
                else:
                    pass                                                                              
                # end of if symbol.startswith('BTC'):                                                                  
            # end of if sell_order_sub_seq == 3:           
                 
            if sell_order_sub_seq < 3:           
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id +'-'+str(sell_order_sub_seq),
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                      
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()          
            elif sell_order_sub_seq == 3:
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id +'-'+str(sell_order_sub_seq),
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty3_1, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id +'-'+str(sell_order_sub_seq),
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty3_2, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                                                    
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()  
            # end of if sell_order_sub_seq < 3:
    
            return res_df    

  10. Tradeクラスにupdate_get_price_response_for_debug2()メソッドを追加する



    trade.py:
        ###########################################################################################################  update get_price() response for debug2 
        def update_get_price_response_for_debug2(self, res_df: pd.DataFrame, get_price_count: int) -> pd.DataFrame:  # called form update_order()
            ### creates outstanding sell order subs for each sell order header depending on get_price_count
            symbol = self.coin.symbol
    
            # get_price_count is less than 2 => return empty res_df
            if get_price_count < 2:                     # =0,1
                res_df = pd.DataFrame()   
            # get_price_count is equal to 2 => return outstanding res_df (1/2) : 
            elif get_price_count == 2:                  # =2                            
                qty1 = 0.0      #;qty2 = 0.0
                if symbol.startswith('BTC'):            # 0.04 [0.02, 0.02]                            
                    qty1 = 0.02 #; qty2 = 0.02                         
                elif symbol.startswith('ETH'):          # 0.4 [0.2, 0.2]
                    qty1 = 0.2 #; qty2 = 0.2 
                elif symbol.startswith('BCH'):          # 0.4 [0.2, 0.2]
                    qty1 = 0.2 #; qty2 = 0.2 
                elif symbol.startswith('LTC'):          # 4 [2, 2]
                    qty1 = 2 #; qty2 = 2 
                elif symbol.startswith('XRP'):          # 40 [20, 20]
                    qty1 = 20 #; qty2 = 20 
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
    
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty1,   # XRP_JPY: 20
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                      
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()                                            
            # get_price_count is greater than 2 => return remaining ref_df (2/2) : 
            else: # get_price_count > 2                 # =3,4,5...
                qty1=0.0; qty2_1=0.0; qty2_2=0.0
                if symbol.startswith('BTC'):            # 0.02 [0.01, 0.01]                             
                    qty1=0.02; qty2_1=0.01; qty2_2=0.01                         
                elif symbol.startswith('ETH'):          # 0.2 [0.1, 0.1]
                    qty1=0.2; qty2_1=0.1; qty2_2=0.1 
                elif symbol.startswith('BCH'):          # 0.2 [0.1, 0.1]
                    qty1=0.2; qty2_1=0.1; qty2_2=0.1 
                elif symbol.startswith('LTC'):          # 2 [1, 1]
                    qty1=2; qty2_1=1; qty2_2=1 
                elif symbol.startswith('XRP'):          # 20 [10, 10]
                    qty1=20; qty2_1=10; qty2_2=10 
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
    
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [     
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'CLOSE',  
                                    'side': 'SELL',         
                                    'size': qty1,       # XRP_JPY: 20
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },                                    
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'CLOSE',  
                                    'side': 'SELL',         
                                    'size': qty2_1,     # XRP_JPY: 10
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '0', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'CLOSE',  
                                    'side': 'SELL',         
                                    'size': qty2_2,     # XRP_JPY: 10
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                                                      
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()        
                        
            # end of if get_price_count < 2:         
    
            return res_df

    click image to zoom!
    図10



  11. Tradeクラスにget_order_close_count()メソッドを追加する



    trade.py:
        ####################################### get a close count from the order csv file
        def get_order_close_count(self) -> int:    # return close_count 
            # symbol = self.coin.symbol
    
            # get_order_csv(self) -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot/buy_sell/order(BTC_JPY).csv            
        
            if df.shape[0] == 0: return 0
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------            
           
            # close_count_pos = df.columns.get_loc('close_count') 
            close_count = df.iloc[-1]['close_count']
    
            # self.debug.trace_warn(f".... DEBUG: get_order_close_count() ▶ {close_count} ")
            return close_count    

  12. Tradeクラスにget_closed_order_count()メソッドを追加する



    trade.py:
        ################################################### get closed order count for each coin
        def get_closed_order_count(self, term: str) -> int:       
            symbol = self.coin.symbol
    
            if term == 'D':
                day1=1; day2=0; day3=1
            elif term == 'W':
                day1=7; day2=6; day3=1
            elif term == 'M':
                day1=31; day2=30; day3=1
            else:
                return 0          
    
            ################################################################### DEBUG
            # date_str = '2022-05-16 05:59:59'
            # date_str = '2022-05-16 06:00:01'
            # now = dt.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
            ################################################################### DEBUG
            now = dt.datetime.now()
            now_time = now.time()
            # print(now_time)
            tocompare = dt.datetime.strptime('06:00:00', '%H:%M:%S')
            tocompare = dt.time(tocompare.hour, tocompare.minute, tocompare.second)
            # print(tocompare)
    
            if now_time < tocompare:
                # print(f'now_time({now_time}) < tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day1), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now, '%Y-%m-%d' + ' 06:00:00')                              # 2022-05-17 06:00:00
            else: # greater than or equal to 06:00:00
                # print(f'now_time({now_time}) >= tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day2), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now + dt.timedelta(days=day3), '%Y-%m-%d' + ' 06:00:00')    # 2022-05-17 06:00:00
                
            # print(start_date_str, '~', end_date_str)
    
            start_date = dt.datetime.strptime(start_date_str, '%Y-%m-%d %H:%M:%S')
            end_date = dt.datetime.strptime(end_date_str, '%Y-%m-%d %H:%M:%S')
    
            # print(start_date,'~', end_date)
    
            # get_order_csv() -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot/buy_sell/order(BTC_JPY).csv    
            # desktop-pc/bot/sell_buy/order(BTC_JPY).csv         
        
            if df.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: get_order_count(term={term}) ▶ empty order csv file : order_count({order_count})  ")
                return 0
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------         
         
            ### filter closed order csv file : buy_real_qty == sell_real_qty
    
            # filter closed order csv file by date range  (daily, weekly, monthly)
            filter_mask = (df['log_time'] >= start_date) & (df['log_time'] < end_date) & (df['order_closed']) & (~df['stop_loss']) & (~df['cancelled'])     
            dfx = df[filter_mask]                       
            order_count = dfx.shape[0]
            # self.debug.trace_warn(f".... DEBUG: get_order_count(symbol={symbol}, term={term}) ▶ order_count({order_count})  ")
            return order_count     

  13. Tradeクラスの全てを掲載

    ここではTradeクラスの全てのソースコードを掲載しています。

    trade.py:
    
    # trade.py
    
    """
    Trade class
    """
    
    # import the libraries
    from time import sleep  
    import datetime as dt
    from datetime import timedelta
    
    import math
    import statistics
    from decimal import Decimal
    
    import numpy as np
    import pandas as pd
    
    from lib.base import Bcolors, Gvar, Coin, Gmo_dataframe
    from lib.debug import Debug
    from lib.csv import Csv
    
    # from lib.buy_sell import BuySell            # dependencies Gvar, Coin
    # from lib.sell_buy import SellBuy            # dependencies Gvar, Coin
    
    import warnings
    warnings.simplefilter('ignore')
    
    
    ############ trade libraries  class
    class Trade:
        """
        __init__(self), __init__(self, gvar, coin), __str__()  
        df_empty(), find_order()
        get_buy_price(), get_sell_price()
        get_order_status(), get_closed_order_count(), get_order_close_count()
        convert_float_qty_to_str(), convert_float_price_to_str() 
        calculate_profit()
        print_profit_driver(), print_order_count_driver(), print_loss_cut_count_driver()
        maintenance_time(), time_to_charge_leverage_fee()
        update_get_price_response_for_debug1_1(), update_get_price_response_for_debug1_2(), update_get_price_response_for_debug2()    
        """    
        ###################   
        def __init__(self) -> None: 
            self.gvar = Gvar()                      # Gvar     
            self.coin = Coin()                      # Coin
            self.debug = Debug(self.gvar)           # dependent class       
            self.csv = Csv(self.gvar, self.coin)    # dependent class       
            
            self.folder_gmo =  f'{self.gvar.domain}/{self.gvar.exchange}/'  # desktop-pc/bot/            
            self.folder_trading_type =  f'{self.gvar.domain}/{self.gvar.exchange}/{self.coin.trade_type}/'  # desktop-pc/bot/buy_sell/           
                
        #######################################################
        def __init__(self, gvar: object, coin: object) -> None: 
            self.gvar = gvar                        # Gvar         
            self.coin = coin                        # Coin    
            self.debug = Debug(gvar)                # dependent class    
            self.csv = Csv(self.gvar, self.coin)    # dependent class    
    
            self.folder_gmo =  f'{self.gvar.domain}/{self.gvar.exchange}/'  # desktop-pc/bot/            
            self.folder_trading_type =  f'{self.gvar.domain}/{self.gvar.exchange}/{self.coin.trade_type}/'  # desktop-pc/bot/buy_sell/            
    
        #########################
        def __str__(self) -> str:
            return f"Trade({self.folder_gmo=}, {self.folder_trading_type=})"  
    
        ###################################
        def maintenance_time(self) -> bool:
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            ### check GMO maintenance wed 15:00 - 16:30 (14:45 - 17:00) 
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            today = dt.datetime.today()
            day_of_week = today.strftime('%A')  # Wednesday
            if day_of_week == 'Wednesday':
                now_time = dt.datetime.now().time()            
                tocompare = dt.datetime.strptime('14:45:00', '%H:%M:%S')
                from_time = dt.time(tocompare.hour, tocompare.minute, tocompare.second)
                tocompare = dt.datetime.strptime('17:00:00', '%H:%M:%S')   
                to_time = dt.time(tocompare.hour, tocompare.minute, tocompare.second)        
                # between 14:45 ~ 17:00 ?    
                if now_time >= from_time and now_time <= to_time:
                    return True
            
            return False                
    
        ##############################################
        def time_to_charge_leverage_fee(self) -> bool:
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            ### set a close_pending_order : 05:00 - 06:00 (04:55 - 06:05)
            ### ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
            local_timezone = dt.timezone(dt.timedelta(hours=+9))  # adjust to JP local timezone 
            current_time = dt.datetime.now().astimezone(local_timezone).time()
            from_time = dt.datetime.strptime("04:55AM", "%I:%M%p").time()   
            to_time = dt.datetime.strptime("06:05AM", "%I:%M%p").time()         
            if current_time >= from_time and current_time <= to_time:
                # print('current time is between 04:55AM - 06:05AM')
                return True
            else:
                # print('current time is NOT between 04:55AM - 06:05AM')
                return False
            # end of if current_time >= from_time and current_time <= to_time:        
    
            return
     
        ##########################################################################
        def print_profit_driver(self, symbol_list: list, coin_list: list) -> None:
    
            ##########################################################
            ### print monthly, weekly, daily profit for real mode 
            ##########################################################
            
            ### calculate monthly, weekly, daily profit for each coin : REAL MODE
            d_profit_list = []; w_profit_list = []; m_profit_list = []
            for i, _ in enumerate(symbol_list):   
                coin = coin_list[i] # Coin(coin_list[i])
                if coin.suspend: 
                    d_profit_list.append(0); w_profit_list.append(0); m_profit_list.append(0)
                else:
                    trade = Trade(self.gvar, coin)
                    d_profit = trade.calculate_profit(term='D')
                    w_profit = trade.calculate_profit(term='W')
                    m_profit = trade.calculate_profit(term='M')
                    d_profit_list.append(d_profit)
                    w_profit_list.append(w_profit)
                    m_profit_list.append(m_profit)            
            # end of for i, _ in enumerate(symbol_list):
    
            # print monthly profit
            profit = round(sum(m_profit_list), 0) 
            self.debug.print_log(f"{Bcolors.OKGREEN}monthly profit{Bcolors.ENDC}: {profit:,.0f} Yen ")       
            
            profit_list = []
            for i in range(0, len(symbol_list)):       
                profit = m_profit_list[i]   
                profit_list.append(profit)        
    
            symbol_len = len(symbol_list)   # 1,2,3,4,5...10
            
            profit_msg = f"{Bcolors.OKGREEN}monthly profit by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f}), "
                else:    
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f})"
            self.debug.print_log(profit_msg)   
    
            # print weekly profit
            profit = round(sum(w_profit_list), 0) 
            self.debug.print_log(f"{Bcolors.OKGREEN}weekly profit{Bcolors.ENDC}: {profit:,.0f} Yen ")         
            
            profit_list = []
            for i in range(0, len(symbol_list)):      
                profit = w_profit_list[i]   
                profit_list.append(profit)  
    
            profit_msg = f"{Bcolors.OKGREEN}weekly profit by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f}), "
                else:    
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f})"
            self.debug.print_log(profit_msg)                          
         
            # print daily profit
            profit = round(sum(d_profit_list), 0) 
            self.debug.print_log(f"{Bcolors.OKGREEN}daily profit{Bcolors.ENDC}: {profit:,.0f} Yen ")         
            
            profit_list = []
            for i in range(0, len(symbol_list)):    
                profit = d_profit_list[i]   
                profit_list.append(profit)        
    
            profit_msg = f"{Bcolors.OKGREEN}daily profit by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f}), "
                else:    
                    profit_msg += f"{symbol_list[i]}({profit_list[i]:,.0f})"
            self.debug.print_log(profit_msg)         
    
            self.debug.print_log('-'*175)
    
            return
    
        ###############################################################################
        def print_order_count_driver(self, symbol_list: list, coin_list: list) -> None:
    
            #######################################################################
            ### print monthly, weekly, daily closed order count 
            #######################################################################
    
            ### get monthly, weekly, daily closed order count for each coin  
            d_count_list = []; w_count_list = []; m_count_list = []
            for i, _ in enumerate(symbol_list):   
                coin = coin_list[i] # Coin(coin_list[i])
                if coin.suspend: 
                    d_count_list.append(0); w_count_list.append(0); m_count_list.append(0)
                else:
                    trade = Trade(self.gvar, coin)
                    d_cnt = trade.get_closed_order_count(term='D')
                    w_cnt = trade.get_closed_order_count(term='W')
                    m_cnt = trade.get_closed_order_count(term='M')
                    d_count_list.append(d_cnt)
                    w_count_list.append(w_cnt)
                    m_count_list.append(m_cnt)                    
            # end of for i, _ in enumerate(symbol_list):
    
            symbol_len = len(symbol_list)   # 1,2,3,4,5
    
            # print monthly order count
            count_sum = sum(m_count_list) 
            self.debug.print_log(f"{Bcolors.OKGREEN}monthly order count{Bcolors.ENDC}: {count_sum} ")                  
            count_list = []
            for i in range(0, len(symbol_list)):        
                cnt = m_count_list[i]       
                count_list.append(cnt)
            
            count_msg = f"{Bcolors.OKGREEN}monthly order count by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    count_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    count_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(count_msg) 
    
            # print weekly order count
            count_sum = sum(w_count_list) 
            self.debug.print_log(f"{Bcolors.OKGREEN}weekly order count{Bcolors.ENDC}: {count_sum} ")                  
            count_list = []
            for i in range(0, len(symbol_list)):        
                cnt = w_count_list[i]       
                count_list.append(cnt)
            
            count_msg = f"{Bcolors.OKGREEN}weekly order count by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    count_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    count_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(count_msg)       
    
            # print daily order count
            count_sum = sum(d_count_list) 
            self.debug.print_log(f"{Bcolors.OKGREEN}daily order count{Bcolors.ENDC}: {count_sum} ")                  
            count_list = []
            for i in range(0, len(symbol_list)):        
                cnt = d_count_list[i]       
                count_list.append(cnt)
    
            count_msg = f"{Bcolors.OKGREEN}daily order count by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    count_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    count_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(count_msg) 
         
            self.debug.print_log('-'*175)     
    
            return
    
        ##################################################################################
        def print_loss_cut_count_driver(self, symbol_list: list, coin_list: list) -> None:
    
            #############################################
            ### print loss cut count    
            #############################################
    
            lc5_list = []; lc10_list = []; lc15_list = []; lc18_list = []; lc20_list = [] 
            for i, _ in enumerate(symbol_list):       
                coin = coin_list[i] # Coin(coin_list[i])         
                if coin.suspend: 
                    lc5_list.append(0); lc10_list.append(0); lc15_list.append(0); lc18_list.append(0); lc20_list.append(0) 
                else:
                    # o_coin = coin_list[i]   # get the current coin class  
                    lc5_list.append(coin.buy_sell_lc5)
                    lc10_list.append(coin.buy_sell_lc10)
                    lc15_list.append(coin.buy_sell_lc15)
                    lc18_list.append(coin.buy_sell_lc18)
                    lc20_list.append(coin.buy_sell_lc20)
            # end of for i, _ in enumerate(symbol_list):  
    
            symbol_len = len(symbol_list)   # 1,2,3,4,5
    
            # print loss cut count    
            self.debug.print_log(f"{Bcolors.OKGREEN}loss cut by % {Bcolors.ENDC}: ")                  
            count_list = []
            for i in range(0, len(symbol_list)):      
                cnt = lc5_list[i]           
                count_list.append(cnt)
    
            loss_cut_msg = f"{Bcolors.OKGREEN}05% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)               
    
            count_list = []
            for i in range(0, len(symbol_list)):   
                cnt = lc10_list[i]          
                count_list.append(cnt)
            
            loss_cut_msg = f"{Bcolors.OKGREEN}10% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)     
    
            count_list = []
            for i in range(0, len(symbol_list)):      
                cnt = lc15_list[i]          
                count_list.append(cnt)
            
            loss_cut_msg = f"{Bcolors.OKGREEN}15% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)  
    
            count_list = []
            for i in range(0, len(symbol_list)):       
                cnt = lc18_list[i]          
                count_list.append(cnt)
    
            loss_cut_msg = f"{Bcolors.OKGREEN}18% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)  
    
            count_list = []
            for i in range(0, len(symbol_list)):      
                cnt = lc20_list[i]         
                count_list.append(cnt)
            
            loss_cut_msg = f"{Bcolors.OKGREEN}20% loss cut by symbol{Bcolors.ENDC}: " 
            for i, _ in enumerate(symbol_list): 
                if i < symbol_len-1:
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]}), "
                else:    
                    loss_cut_msg += f"{symbol_list[i]}({count_list[i]})"
            self.debug.print_log(loss_cut_msg)  
    
            return
            
        ############################################# 
        def df_empty(self, df: pd.DataFrame) -> bool:
            df = pd.DataFrame(df) # cast dataframe()
            return (True if df.shape[0] == 0 else False)
    
        ##################################################################  
        def find_order(self, df: pd.DataFrame, col: str, val=any) -> bool: 
            # find buy or sell order
            find_mask = df[col] == val 
            dfx = pd.DataFrame(df[find_mask])   # cast Pandas DataFrame                                       
            return (True if dfx.shape[0] > 0 else False)    
            
        ################################################################# get buy price
        def get_buy_price(self, sell_price: float, trace=False) -> float: # sell_price => sell_real_price 
            _q_ = self.coin.qty_decimal; _p_ = self.coin.price_decimal
            
            buy_price = sell_price - (sell_price * (self.coin.profit_rate - 1)) 
            # buy_price = 99.123 - (99.123 * (1.0010 - 1)) => 99.123 - (99.123 * 0.0010)
            
            if trace: self.debug.trace_write(f".... {self.gvar.callers_method_name} get_buy_price({sell_price=:,.{_p_}f}): ▶ {buy_price=:,.{_p_}f} ")
                    
            return buy_price    
    
        ################################################################## get sell price
        def get_sell_price(self, buy_price: float, trace=False) -> float : # buy_price => buy_real_price ★        
            _q_ = self.coin.qty_decimal; _p_ = self.coin.price_decimal
    
            sell_price = buy_price * self.coin.profit_rate  
            # sell_price = buy_price * 1.0010 
            
            if trace: self.debug.trace_write(f".... {self.gvar.callers_method_name} get_sell_price({buy_price=:,.{_p_}f}): ▶ {sell_price=:,.{_p_}f} ")        
               
            return sell_price      
            
        ###################################################### convert float qty to str by coin
        def convert_float_qty_to_str(self, qty: float) -> str:  
            _q_ = self.coin.qty_decimal     # 0, 1, 2
            return f'{qty:.{_q_}f}'         # 1, 0.1, 0.01
     
        ########################################################## convert float price to str by coin
        def convert_float_price_to_str(self, price: float) -> str: 
            _p_ = self.coin.price_decimal   # 0, 3
            return f'{price:.{_p_}f}'   # 123456.789 => 123456 or 12.345678 => 12.345 
        
        ################################################# get a order status from the order csv file
        def get_order_status(self, exclude=True) -> bool: # return order_completed      
            symbol = self.coin.symbol
    
            # open order csv file
            # get_order_csv() -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot//buy_sell/order(BTC_JPY).csv    
            # desktop-pc/bot//sell_buy/order(BTC_JPY).csv 
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------         
    
            order_completed = False
            log_day = 0
    
            while True:
                # empty order csv file ?     
                if df.shape[0] == 0:         
                    order_completed = True
                    break   # exit while true
    
                # get a stop_loss/cancelled/order_closed flag
                ord_order_closed = df.iloc[-1]['order_closed']
                ord_stop_loss = df.iloc[-1]['stop_loss']
                ord_cancelled = df.iloc[-1]['cancelled']
    
                # exclude stop_loss, cancelled order info
                if exclude:
                    if ord_stop_loss or ord_cancelled:
                        order_completed = False
                    elif ord_order_closed:
                        order_completed = True
                else: # include stop_loss, cancelled order info
                    if ord_order_closed or ord_stop_loss or ord_cancelled:
                        order_completed = True 
                  
                break   # exit while true
            # end of while true                                  
    
            # self.debug.trace_warn(f".... DEBUG: get_order_status(exclude={exclude}) ▶ order_completed={order_completed}, df.shape={df.shape} ")
            return order_completed
    
        ################################################### get closed order count for each coin
        def get_closed_order_count(self, term: str) -> int:       
            symbol = self.coin.symbol
    
            if term == 'D':
                day1=1; day2=0; day3=1
            elif term == 'W':
                day1=7; day2=6; day3=1
            elif term == 'M':
                day1=31; day2=30; day3=1
            else:
                return 0          
    
            ################################################################### DEBUG
            # date_str = '2022-05-16 05:59:59'
            # date_str = '2022-05-16 06:00:01'
            # now = dt.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
            ################################################################### DEBUG
            now = dt.datetime.now()
            now_time = now.time()
            # print(now_time)
            tocompare = dt.datetime.strptime('06:00:00', '%H:%M:%S')
            tocompare = dt.time(tocompare.hour, tocompare.minute, tocompare.second)
            # print(tocompare)
    
            if now_time < tocompare:
                # print(f'now_time({now_time}) < tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day1), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now, '%Y-%m-%d' + ' 06:00:00')                              # 2022-05-17 06:00:00
            else: # greater than or equal to 06:00:00
                # print(f'now_time({now_time}) >= tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day2), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now + dt.timedelta(days=day3), '%Y-%m-%d' + ' 06:00:00')    # 2022-05-17 06:00:00
                
            # print(start_date_str, '~', end_date_str)
    
            start_date = dt.datetime.strptime(start_date_str, '%Y-%m-%d %H:%M:%S')
            end_date = dt.datetime.strptime(end_date_str, '%Y-%m-%d %H:%M:%S')
    
            # print(start_date,'~', end_date)
    
            # get_order_csv() -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot/buy_sell/order(BTC_JPY).csv    
            # desktop-pc/bot/sell_buy/order(BTC_JPY).csv         
        
            if df.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: get_order_count(term={term}) ▶ empty order csv file : order_count({order_count})  ")
                return 0
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------         
         
            ### filter closed order csv file : buy_real_qty == sell_real_qty
    
            # filter closed order csv file by date range  (daily, weekly, monthly)
            filter_mask = (df['log_time'] >= start_date) & (df['log_time'] < end_date) & (df['order_closed']) & (~df['stop_loss']) & (~df['cancelled'])     
            dfx = df[filter_mask]                       
            order_count = dfx.shape[0]
            # self.debug.trace_warn(f".... DEBUG: get_order_count(symbol={symbol}, term={term}) ▶ order_count({order_count})  ")
            return order_count      
        
        ####################################### get a close count from the order csv file
        def get_order_close_count(self) -> int:    # return close_count 
            # symbol = self.coin.symbol
    
            # get_order_csv(self) -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot/buy_sell/order(BTC_JPY).csv            
        
            if df.shape[0] == 0: return 0
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------            
           
            # close_count_pos = df.columns.get_loc('close_count') 
            close_count = df.iloc[-1]['close_count']
    
            # self.debug.trace_warn(f".... DEBUG: get_order_close_count() ▶ {close_count} ")
            return close_count    
        
        ############################################### calculate profit for each coin : order csv file
        def calculate_profit(self, term: str) -> float:  # return net profit
            symbol = self.coin.symbol   
    
            if term == 'D':
                day1=1; day2=0; day3=1
            elif term == 'W':
                day1=7; day2=6; day3=1
            elif term == 'M':
                day1=31; day2=30; day3=1
            else:
                return 0          
    
            ################################################################# DEBUG
            # date_str = '2022-05-16 05:59:59'
            # date_str = '2022-05-16 06:00:01'
            # now = dt.datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
            ################################################################# DEBUG
            now = dt.datetime.now()
            now_time = now.time()
            # print(now_time)
            tocompare = dt.datetime.strptime('06:00:00', '%H:%M:%S')
            tocompare = dt.time(tocompare.hour, tocompare.minute, tocompare.second)
            # print(tocompare)
    
            if now_time < tocompare:
                # print(f'now_time({now_time}) < tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day1), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now, '%Y-%m-%d' + ' 06:00:00')                              # 2022-05-17 06:00:00
            else: # greater than or equal to 06:00:00
                # print(f'now_time({now_time}) >= tocompare({tocompare}) ')
                start_date_str = dt.datetime.strftime(now - dt.timedelta(days=day2), '%Y-%m-%d') + ' 06:00:00'  # 2022-05-16 06:00:00
                end_date_str = dt.datetime.strftime(now + dt.timedelta(days=day3), '%Y-%m-%d' + ' 06:00:00')    # 2022-05-17 06:00:00
                
            # print(start_date_str, '~', end_date_str)
    
            start_date = dt.datetime.strptime(start_date_str, '%Y-%m-%d %H:%M:%S')
            end_date = dt.datetime.strptime(end_date_str, '%Y-%m-%d %H:%M:%S')
    
            # print(start_date,'~', end_date)
    
            # get_order_csv(self) -> pd.DataFrame:  # return df  
            df = self.csv.get_order_csv()
            # desktop-pc/bot//buy_sell/order(BTC_JPY).csv         
        
            if df.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): #0 order info csv file not found ▶ date range={start_date}~{end_date}, net_profit=0 ")
                return 0
    
            # order info file: order(BTC_JPY).csv
            # -------------------------------------------------------------------------------------------------------
            #  #   Column                    Dtype
            # -------------------------------------------------------------------------------------------------------
            #  1   buy_time                  datetime64[utc]    ★ PK1
            #  2   sell_time                 datetime64[utc]      
            #  3   buy_order_id              object             ★ PK2
            #  4   sell_order_id             object             list of sell_order_id : 'orderId1;orderId2;orderId3'      
            #  5   buy_real_qty              float64    
            #  6   sell_real_qty             float64                
            #  7   buy_real_price            float64
            #  8   sell_real_price           float64
            #  9   buy_real_fee              float64
            # 10   sell_real_fee             float64              
            # 11   real_profit               float64
            # 12   accumulated_leverage_fee  float64            
            # 13   close_count               int                leverage fee close count         
            # 14   close_update_date         datetime64[ns]     leverage fee close date   
            # 15   order_closed              bool                                 
            # 16   stop_loss                 bool
            # 17   cancelled                 bool
            # 18   order_open_date           datetime64[ns]     
            # 19   order_close_date          datetime64[ns]     
            # 20   log_time                  datetime64[ns]     => update evert time
            # -----------------------------------------------------------------------------------------------------             
           
            ### 1: filter order csv by date range (daily, weekly, monthly)
            filter_mask = (df['log_time'] >= start_date) & (df['log_time'] < end_date) 
            dfx = df[filter_mask]        
                 
            # empty datafarame ? => return 
            if dfx.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): #1 filterd order info is empty ▶ date range={start_date}~{end_date}, net_profit=0 ")
                return 0
    
            ### 2: calculate accumulated leverage fee
            leverage_fee_sum = dfx['accumulated_leverage_fee'].sum()
    
            ### 3: filter closed order csv : buy_real_qty == sell_real_qty
    
            # filter closed order info by date range  (daily, weekly, monthly)
            filter_mask = (df['log_time'] >= start_date) & (df['log_time'] < end_date) & (df['buy_real_qty'] == df['sell_real_qty'])
            dfx = df[filter_mask]
              
            # empty datafarame ? => return 
            if dfx.shape[0] == 0: 
                # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): #2 filterd order info is empty ▶ date range={start_date}~{end_date}, net_profit=0 ")
                return 0
           
            ### 4: calculate net profit : profit = rounddown((sell_real_price - buy_real_price) * sell_real_qty)
            dfx['rate_diff'] = dfx.apply(lambda row: row['sell_real_price'] - row['buy_real_price'], axis=1)    
            dfx['real_profit'] = dfx.apply(lambda row: math.floor(row['rate_diff'] * row['sell_real_qty']) , axis=1)  # IMPORTANT: do not used math.ceil() for negative value => use math.floor()     
             
            profit = dfx['real_profit'].sum() 
            net_profit = math.floor(profit - leverage_fee_sum)                 
    
            # self.debug.trace_warn(f".... DEBUG: calculate_profit(symbol={symbol}, term={term}): net_profit({net_profit:,.0f}) = profit({profit:,.0f}) - leverage_fee({leverage_fee_sum:,.0f}) ")
            return net_profit   
    
        ######################################################################################################## update get_price() response for debug1_1  
        def update_get_price_response_for_debug1_1(self, res_df: pd.DataFrame, loop_count: int) -> pd.DataFrame: # called from create_buy_order()
            ### creates two buy sub orders for each buy order header
            symbol = self.coin.symbol
    
            if loop_count == 1:
                qty1_1 = 0.0; qty1_2 = 0.0
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01], [0.02]                             
                    qty1_1 = 0.01; qty1_2 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1], [0.2]
                    qty1_1 = 0.1; qty1_2 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1], [0.2]
                    qty1_1 = 0.1; qty1_2 = 0.1 
                elif symbol.startswith('LTC'):          # 4 [1, 1], [2]
                    qty1_1 = 1; qty1_2 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10], [20]
                    qty1_1 = 10; qty1_2 = 10                         
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
    
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id + '-1', 
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'BUY',         
                                    'size': qty1_1, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id + '-2', 
                                    'price': res_price, 
                                    'settleType': 'OPEN',   
                                    'side': 'BUY',         
                                    'size': qty1_2, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                        
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()                          
            else: # loop_count > 1
                qty2 = 0.0
                if symbol.startswith('BTC'):        # 0.04 [0.01, 0.01], [0.02]                             
                    qty2 = 0.02                         
                elif symbol.startswith('ETH'):      # 0.4 [0.1, 0.1], [0.2]
                    qty2 = 0.2 
                elif symbol.startswith('BCH'):      # 0.4 [0.1, 0.1], [0.2]
                    qty2 = 0.2 
                elif symbol.startswith('LTC'):      # 4 [1, 1], [2]
                    qty2 = 2 
                elif symbol.startswith('XRP'):      # 40 [10, 10], [20]
                    qty2 = 20                  
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
                               
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']            
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id + '-3',
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'BUY',         
                                    'size': qty2, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                        
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()                           
            # end of if loop_count == 1:     
             
            return res_df            
    
        ################################################################################################################ update get_price() response for debug1_2  
        def update_get_price_response_for_debug1_2(self, res_df: pd.DataFrame, sell_sub_order_seq: int) -> pd.DataFrame: # called form update_order()
            ### creates two sell sub orders for each sell order header
            symbol = self.coin.symbol
    
            # first sell sub order ?
            if sell_sub_order_seq == 1:
                qty1 = 0.0         
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01, 0.01, 0.01]                             
                    qty1 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty1 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty1 = 0.1  
                elif symbol.startswith('LTC'):          # 4 [1, 1, 1, 1]
                    qty1 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10, 10, 10]
                    qty1 = 10 
                else:
                    pass     
                # end of if symbol.startswith('BTC'):                                                                                          
                qty = qty1
            elif sell_sub_order_seq == 2:
                qty2 = 0.0         
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01, 0.01, 0.01]                             
                    qty2 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty2 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty2 = 0.1  
                elif symbol.startswith('LTC'):          # 4 [1, 1, 1, 1]
                    qty2 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10, 10, 10]
                    qty2 = 10 
                else:
                    pass                                                                              
                # end of if symbol.startswith('BTC'):   
                qty = qty2                        
            elif sell_sub_order_seq == 3:
                qty3_1 = 0.0; qty3_2 = 0.0         
                if symbol.startswith('BTC'):            # 0.04 [0.01, 0.01, 0.01, 0.01]                             
                    qty3_1 = 0.01; qty3_2 = 0.01                         
                elif symbol.startswith('ETH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty3_1 = 0.1; qty3_2 = 0.1 
                elif symbol.startswith('BCH'):          # 0.4 [0.1, 0.1, 0.1, 0.1]
                    qty3_1 = 0.1; qty3_2 = 0.1  
                elif symbol.startswith('LTC'):          # 4 [1, 1, 1, 1]
                    qty3_1 = 1; qty3_2 = 1 
                elif symbol.startswith('XRP'):          # 40 [10, 10, 10, 10]
                    qty3_1 = 10; qty3_2 = 10 
                else:
                    pass                                                                              
                # end of if symbol.startswith('BTC'):                                                                  
            # end of if sell_sub_order_seq == 3:           
                 
            if sell_sub_order_seq < 3:           
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id +'-'+str(sell_sub_order_seq),
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                      
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()          
            elif sell_sub_order_seq == 3:
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id +'-'+str(sell_sub_order_seq),
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty3_1, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id +'-'+str(sell_sub_order_seq),
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty3_2, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                                                    
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()  
            # end of if sell_sub_order_seq < 3:
    
            return res_df        
    
        ###########################################################################################################  update get_price() response for debug2 
        def update_get_price_response_for_debug2(self, res_df: pd.DataFrame, get_price_count: int) -> pd.DataFrame:  # called form update_order()
            ### creates outstanding sell sub orders for each sell order header depending on get_price_count
            symbol = self.coin.symbol
    
            # get_price_count is less than 2 => return empty res_df
            if get_price_count < 2:                     # =0,1
                res_df = pd.DataFrame()   
            # get_price_count is equal to 2 => return outstanding res_df (1/2) : 
            elif get_price_count == 2:                  # =2                            
                qty1 = 0.0      #;qty2 = 0.0
                if symbol.startswith('BTC'):            # 0.04 [0.02, 0.02]                            
                    qty1 = 0.02 #; qty2 = 0.02                         
                elif symbol.startswith('ETH'):          # 0.4 [0.2, 0.2]
                    qty1 = 0.2 #; qty2 = 0.2 
                elif symbol.startswith('BCH'):          # 0.4 [0.2, 0.2]
                    qty1 = 0.2 #; qty2 = 0.2 
                elif symbol.startswith('LTC'):          # 4 [2, 2]
                    qty1 = 2 #; qty2 = 2 
                elif symbol.startswith('XRP'):          # 40 [20, 20]
                    qty1 = 20 #; qty2 = 20 
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [                         
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'OPEN',  
                                    'side': 'SELL',         
                                    'size': qty1, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                      
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()                                            
            # get_price_count is greater than 2 => return remaining ref_df (2/2) : 
            else: # get_price_count > 2                 # =3,4,5...
                qty1=0.0; qty2_1=0.0; qty2_2=0.0
                if symbol.startswith('BTC'):            # 0.02 [0.01, 0.01]                             
                    qty1=0.02; qty2_1=0.01; qty2_2=0.01                         
                elif symbol.startswith('ETH'):          # 0.2 [0.1, 0.1]
                    qty1=0.2; qty2_1=0.1; qty2_2=0.1 
                elif symbol.startswith('BCH'):          # 0.2 [0.1, 0.1]
                    qty1=0.2; qty2_1=0.1; qty2_2=0.1 
                elif symbol.startswith('LTC'):          # 2 [1, 1]
                    qty1=2; qty2_1=1; qty2_2=1 
                elif symbol.startswith('XRP'):          # 20 [10, 10]
                    qty1=20; qty2_1=10; qty2_2=10 
                else:
                    pass                                                                                
                # end of if symbol.startswith('BTC'):
    
                res_execution_id = res_df.loc[0, 'executionId']                
                res_order_id = res_df.loc[0, 'orderId']
                res_position_id = res_df.loc[0, 'positionId']  
                res_price = res_df.loc[0, 'price']
                res_timestamp = res_df.loc[0, 'timestamp']               
                order_list = [     
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'CLOSE',  
                                    'side': 'SELL',         
                                    'size': qty1, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },                                    
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'CLOSE',  
                                    'side': 'SELL',         
                                    'size': qty2_1, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                },
                                {
                                    'executionId': res_execution_id, 
                                    'fee': '1', 
                                    'lossGain': '0', 
                                    'orderId': res_order_id, 
                                    'positionId': res_position_id,
                                    'price': res_price, 
                                    'settleType': 'CLOSE',  
                                    'side': 'SELL',         
                                    'size': qty2_2, 
                                    'symbol': symbol, 
                                    'timestamp': res_timestamp
                                }                                                                      
                            ]
                                                        
                df = pd.DataFrame(order_list)
                # convert data types
                df['timestamp'] = pd.to_datetime(df['timestamp'], utc=True, errors='coerce')   # UTC (aware)
                df['executionId'] = df['executionId'].astype(str)   # int64 => string
                df['orderId'] = df['orderId'].astype(str)           # int64 => string
                df['positionId'] = df['positionId'].astype(str)     # int64 => string ★
                df = df.astype({'fee': 'float', 'lossGain': 'float', 'price': 'float', 'size': 'float'})                     
                res_df = df.copy()        
                        
            # end of if get_price_count < 2:         
    
            return res_df