فهرست منبع

日志一階段

skyfffire 5 ماه پیش
والد
کامیت
16f5d55352
8فایلهای تغییر یافته به همراه274 افزوده شده و 194 حذف شده
  1. 1 0
      .gitignore
  2. 27 25
      as.py
  3. 70 0
      checker/logger_config.py
  4. 36 32
      checker/ok_chain_client.py
  5. 34 32
      checker/price_checker.py
  6. 68 68
      erc20_to_mexc_first_sell.py
  7. 1 1
      toto.readme
  8. 37 36
      web3_py_client.py

+ 1 - 0
.gitignore

@@ -1,5 +1,6 @@
 /.idea
 signals/
 __pycache__/
+logs/
 
 config.py

+ 27 - 25
as.py

@@ -9,6 +9,7 @@ import erc20_to_mexc_first_sell
 import web3_py_client
 import traceback
 import copy
+import sys
 
 from flask import Flask, request, jsonify
 from flask_cors import CORS # 导入
@@ -19,6 +20,7 @@ from binance.client import Client # 用于获取ETH价格
 from checker import ok_chain_client
 from pprint import pprint
 from pprint import pformat
+from checker.logger_config import get_logger
 
 ok_chain_client.api_config = {
   "api_key": 'a05643ab-fb17-402b-94a8-a886bd343301',  # 请替换为您的真实 API Key
@@ -29,7 +31,7 @@ ok_chain_client.api_config = {
 # 配置日志
 log = logging.getLogger('werkzeug')
 log.setLevel(logging.ERROR)
-logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+logger = get_logger('as')
 
 web3 = web3_py_client.EthClient() 
 w3 = web3.w3
@@ -69,20 +71,20 @@ CHAIN_ID = -1
 try:
     if w3.provider:
         CHAIN_ID = w3.eth.chain_id
-        logging.info(f"Web3 已连接。chain_id={CHAIN_ID}")
+        logger.info(f"Web3 已连接。chain_id={CHAIN_ID}")
     else:
-        logging.info("Web3 未连接。")
+        logger.info("Web3 未连接。")
 except Exception as e:
-    logging.info(f"初始化 {USER_WALLET} 的全局 nonce 时出错: {e}")
+    logger.info(f"初始化 {USER_WALLET} 的全局 nonce 时出错: {e}")
 
 # Binance 客户端 (无需API Key/Secret即可获取公开行情数据)
 try:
     binance_client = Client()
     # 测试连接 (可选,但建议)
     binance_client.ping()
-    logging.info("成功连接到 Binance API。")
+    logger.info("成功连接到 Binance API。")
 except Exception as e:
-    logging.error(f"初始化 Binance Client 时发生错误: {e}")
+    logger.error(f"初始化 Binance Client 时发生错误: {e}")
     binance_client = None
 
 # --- Flask 应用 ---
@@ -120,10 +122,10 @@ def move_completed_process_to_history(process_id_to_move: str) -> bool:
             # arbitrage_process.add_state_flow_entry(item_to_move, "MOVED_TO_HISTORY", f"流程处理完毕,移至历史记录。最终状态: {item_to_move.get('currentState', 'N/A')}", "info")
             
             history_process_list.append(item_to_move) # 添加到 history_process_list
-            logging.info(f"已将 process_id: {process_id_to_move} 从 processing_list 移动到 history_process_list。")
+            logger.info(f"已将 process_id: {process_id_to_move} 从 processing_list 移动到 history_process_list。")
             moved_successfully = True
         else:
-            logging.warning(f"尝试移动到 history_list 时,在 processing_list 中未找到 process_id: {process_id_to_move}")
+            logger.warning(f"尝试移动到 history_list 时,在 processing_list 中未找到 process_id: {process_id_to_move}")
             
     return moved_successfully
 
@@ -188,7 +190,7 @@ def update_core_data_periodically():
     global core_data # 明确表示我们要修改全局的 core_data
 
     if not USER_WALLET or USER_WALLET == "你的钱包地址":
-        logging.error("USER_WALLET 未正确配置。nonce 更新将无法进行。")
+        logger.error("USER_WALLET 未正确配置。nonce 更新将无法进行。")
         # 如果 USER_WALLET 未配置,可以考虑让线程不执行 nonce 更新,或者直接退出
         # 这里我们选择继续运行,但 nonce 不会被更新
 
@@ -204,9 +206,9 @@ def update_core_data_periodically():
                     ticker = binance_client.get_symbol_ticker(symbol="ETHUSDT")
                     new_eth_price = float(ticker['price'])
                 except Exception as e:
-                    logging.error(f"从 Binance 获取 ETH 价格失败: {e}")
+                    logger.error(f"从 Binance 获取 ETH 价格失败: {e}")
             else:
-                logging.warning("Binance client 未初始化, 无法获取 ETH 价格。")
+                logger.warning("Binance client 未初始化, 无法获取 ETH 价格。")
 
             # 2. 获取最新的 Nonce 和 最新的block_number
             # 确保 w3 已初始化且 USER_WALLET 已配置
@@ -215,11 +217,11 @@ def update_core_data_periodically():
                     new_block_number = w3.eth.block_number
                     new_nonce = w3.eth.get_transaction_count(USER_WALLET, 'latest')
                 except Exception as e:
-                    logging.error(f"为 {USER_WALLET} 获取 Nonce 失败: {e}")
+                    logger.error(f"为 {USER_WALLET} 获取 Nonce 失败: {e}")
             elif not (w3 and w3.is_connected()):
-                logging.warning("Web3 未连接, 无法获取 nonce。")
+                logger.warning("Web3 未连接, 无法获取 nonce。")
             elif not (USER_WALLET and USER_WALLET != "你的钱包地址"):
-                logging.warning("USER_WALLET 配置不正确, 无法获取 nonce。")
+                logger.warning("USER_WALLET 配置不正确, 无法获取 nonce。")
 
             # 3. 更新共享数据 core_data (使用锁)
             # 只有当获取到新数据时才更新,避免不必要的写操作和日志
@@ -237,11 +239,11 @@ def update_core_data_periodically():
                     if new_nonce is not None and core_data["nonce"] != new_nonce:
                         core_data["nonce"] = new_nonce
             
-            # logging.info(f"核心数据已更新: ETH Price = {core_data['eth_price']}, Nonce ({USER_WALLET}) = {core_data['nonce']}, BlockNumber = {core_data['block_number']}")
+            # logger.info(f"核心数据已更新: ETH Price = {core_data['eth_price']}, Nonce ({USER_WALLET}) = {core_data['nonce']}, BlockNumber = {core_data['block_number']}")
 
         except Exception as e:
             # 捕获线程循环中的其他潜在错误
-            logging.error(f"数据更新线程发生未知错误: {e}")
+            logger.error(f"数据更新线程发生未知错误: {e}")
             traceback.print_exc()
         
         # 等待 500ms
@@ -288,7 +290,7 @@ def update_tx_data():
                     if ok_rst['data'] is None:
                         # 每一個之間等待1s
                         time.sleep(1)
-                        
+
                         continue
 
                     # 成功獲取之後直接調用更新
@@ -296,15 +298,15 @@ def update_tx_data():
                         pending_data[tx]['tx_details'] = ok_rst['data']
 
                         formated_data = pformat(ok_rst['data'], indent=2) # indent=2 让格式更整齐
-                        logging.info(f"獲取成功: \n{formated_data}")
+                        logger.info(f"獲取成功: \n{formated_data}")
                 except Exception as e:
-                    logging.error(f"tx數據獲取失敗: {e}")
+                    logger.error(f"tx數據獲取失敗: {e}")
                     traceback.print_exc()
                 
                 # 每一個之間等待1s
                 time.sleep(1)
         except Exception as e:
-            logging.error(f"pending更新线程发生未知错误: {e}")
+            logger.error(f"pending更新线程发生未知错误: {e}")
             traceback.print_exc()
 
 @app.route('/submit_process', methods=['POST'])
@@ -367,7 +369,7 @@ def handle_submit_process():
             processing_list.append(process_item)
 
         last_process_info[symbol] = current_block
-        logging.info(f"已更新 {symbol} 的最后处理信息至区块 {current_block}")
+        logger.info(f"已更新 {symbol} 的最后处理信息至区块 {current_block}")
 
         # 在新线程中开始套利过程
         arb_thread = threading.Thread(target=arbitrage_process_flow, args=(process_item,), daemon=True)
@@ -402,15 +404,15 @@ def get_status():
         })
 
 if __name__ == "__main__":
-    logging.info("启动核心数据更新线程...")
+    logger.info("启动核心数据更新线程...")
     updater_thread = threading.Thread(target=update_core_data_periodically, daemon=True)
     updater_thread.start()
 
-    logging.info("启动pending信息獲取线程...")
+    logger.info("启动pending信息獲取线程...")
     pending_thread = threading.Thread(target=update_tx_data, daemon=True)
     pending_thread.start()
 
-    logging.info("主线程继续执行,可以执行其他任务或保持运行以观察数据更新。")
+    logger.info("主线程继续执行,可以执行其他任务或保持运行以观察数据更新。")
 
-    logging.info("启动 Flask 套利执行服务器...")
+    logger.info("启动 Flask 套利执行服务器...")
     app.run(host='0.0.0.0', port=188, debug=False) # 使用与 price_checker 不同的端口

+ 70 - 0
checker/logger_config.py

@@ -0,0 +1,70 @@
+# logger_config.py
+
+import logging
+from logging.handlers import RotatingFileHandler
+import sys
+import os
+
+# 定义日志文件的路径
+LOG_DIR = 'logs'  # 日志文件夹名称
+LOG_FILE = os.path.join(LOG_DIR, 'app.log') # 日志文件名
+
+IS_LOGGOER_CONFIG = False
+
+# 确保日志文件夹存在
+if not os.path.exists(LOG_DIR):
+    os.makedirs(LOG_DIR)
+
+def setup_logging(log_level=logging.INFO):
+    """
+    配置项目的日志记录。
+    """
+    # 获取根日志记录器
+    root_logger = logging.getLogger()
+    root_logger.setLevel(log_level) # 设置根日志记录器的最低级别
+
+    # 避免重复添加处理程序
+    if not root_logger.handlers:
+        # 创建文件处理程序 (使用 RotatingFileHandler 实现日志文件旋转)
+        file_handler = RotatingFileHandler(
+            LOG_FILE,
+            maxBytes=1024 * 1024 * 5,  # 最大 5MB
+            backupCount=5,           # 保留 5 个备份文件
+            encoding='utf-8'         # 指定编码为 UTF-8,解决中文乱码
+        )
+        file_handler.setLevel(log_level) # 设置文件处理程序的最低级别
+
+        # 创建控制台处理程序
+        console_handler = logging.StreamHandler(sys.stdout)
+        console_handler.setLevel(log_level) # 设置控制台处理程序的最低级别
+
+        # 创建一个格式化器
+        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+
+        # 将格式化器添加到处理程序
+        file_handler.setFormatter(formatter)
+        console_handler.setFormatter(formatter)
+
+        # 将处理程序添加到根日志记录器
+        root_logger.addHandler(file_handler)
+        root_logger.addHandler(console_handler)
+    
+    global IS_LOGGOER_CONFIG
+    IS_LOGGOER_CONFIG = True
+
+def get_logger(name=None):
+    """
+    获取一个日志记录器实例。
+    如果 name 为 None,返回根日志记录器。
+    否则,返回指定名称的日志记录器。
+    """
+    # 如果还没有配置日志,先进行配置
+    if not IS_LOGGOER_CONFIG:
+         setup_logging() # 使用默认级别 INFO 进行配置
+
+    return logging.getLogger(name)
+
+# 在模块加载时自动进行一次基本配置
+# 这样即使没有显式调用 setup_logging,第一次调用 get_logger 也会触发配置
+# 但更好的做法是在项目的入口点显式调用 setup_logging
+# setup_logging() # 可以在此处调用,但建议在主脚本中调用

+ 36 - 32
checker/ok_chain_client.py

@@ -7,6 +7,9 @@ import urllib.parse
 import json
 import time # 只是为了在main的例子中演示循环
 
+from logger_config import get_logger
+logger = get_logger('as')
+
 # 定义 API 凭证
 api_config = {
   "api_key": 'a05643ab-fb17-402b-94a8-a886bd343301',  # 请替换为您的真实 API Key
@@ -83,12 +86,12 @@ def send_get_request(request_path, params_dict=None):
         response.raise_for_status() # 如果HTTP请求返回了不成功的状态码 (4xx or 5xx),则抛出HTTPError异常
         return response.json() # 假设返回的是JSON
     except requests.exceptions.HTTPError as http_err:
-        print(f"HTTP error occurred: {http_err}")
-        print(f"Response content: {response.content.decode()}")
+        logger.error(f"HTTP error occurred: {http_err}")
+        logger.error(f"Response content: {response.content.decode()}")
     except requests.exceptions.RequestException as req_err:
-        print(f"Request exception occurred: {req_err}")
+        logger.error(f"Request exception occurred: {req_err}")
     except json.JSONDecodeError:
-        print(f"Failed to decode JSON. Response content: {response.text}")
+        logger.error(f"Failed to decode JSON. Response content: {response.text}")
     return None
 
 def send_post_request(request_path, body_params_dict=None):
@@ -111,12 +114,13 @@ def send_post_request(request_path, body_params_dict=None):
         response.raise_for_status()
         return response.json()
     except requests.exceptions.HTTPError as http_err:
-        print(f"HTTP error occurred: {http_err}")
-        print(f"Response content: {response.content.decode()}")
+        # 首先把這裏的報錯輸出到文件,params也要
+        logger.error(f"HTTP error occurred: {http_err}")
+        logger.error(f"Response content: {response.content.decode()}")
     except requests.exceptions.RequestException as req_err:
-        print(f"Request exception occurred: {req_err}")
+        logger.error(f"Request exception occurred: {req_err}")
     except json.JSONDecodeError:
-        print(f"Failed to decode JSON. Response content: {response.text}")
+        logger.error(f"Failed to decode JSON. Response content: {response.text}")
     return None
 
 def swap(chain_id, amount, from_token_address, to_token_address, slippage, user_wallet_address, receiver_address=None, gas_level='average'):
@@ -202,10 +206,10 @@ def orders(chain_id, address, tx_status=None, order_id=None):
 
 if __name__ == "__main__":
     import decimal
-    import pprint
+    from pprint import pprint
 
-    pprint.pprint(swap(1, decimal.Decimal('1000') * (10 ** 6), '0xdAC17F958D2ee523a2206206994597C13D831ec7', '0xf816507E690f5Aa4E29d164885EB5fa7a5627860', 1, '0xf816507E690f5Aa4E29d164885EB5fa7a5627860'))
-    # pprint.pprint(approve(1, '0xdAC17F958D2ee523a2206206994597C13D831ec7', '1000000'))
+    # pprint(swap(1, decimal.Decimal('1000') * (10 ** 6), '0xdAC17F958D2ee523a2206206994597C13D831ec7', '0xf816507E690f5Aa4E29d164885EB5fa7a5627860', 1, '0xf816507E690f5Aa4E29d164885EB5fa7a5627860'))
+    # # pprint(approve(1, '0xdAC17F958D2ee523a2206206994597C13D831ec7', '1000000'))
 
     # print("测试时间戳格式:", get_timestamp())
     # print("-" * 30)
@@ -217,7 +221,7 @@ if __name__ == "__main__":
     # 并且您的 API Key 拥有 Web3 API 的权限。
     # 如果是普通 CEX API,BASE_URL 通常是 https://www.okx.com
     
-    # print("发送 GET 请求示例:")
+    # logger.info("发送 GET 请求示例:")
     # get_request_path = '/api/v5/dex/aggregator/quote'
     # get_params = {
     #     'chainId': '42161', # Arbitrum One
@@ -227,22 +231,22 @@ if __name__ == "__main__":
     # }
     # # 确保 API key, secret, passphrase 是针对 web3.okx.com (如果这是你测试的 endpoint)
     # # 或者,如果你测试的是 CEX API, 确保 endpoint 和 API key 对应
-    # print(f"请求路径: {get_request_path}")
-    # print(f"请求参数: {get_params}")
+    # logger.info(f"请求路径: {get_request_path}")
+    # logger.info(f"请求参数: {get_params}")
     # response_data_get = send_get_request(get_request_path, get_params)
     # if response_data_get:
-    #     print("GET 请求成功,响应:")
-    #     print(json.dumps(response_data_get, indent=2))
+    #     logger.info("GET 请求成功,响应:")
+    #     logger.info(json.dumps(response_data_get, indent=2))
     # else:
-    #     print("GET 请求失败。")
+    #     logger.info("GET 请求失败。")
 
-    # print("-" * 30)
+    # logger.info("-" * 30)
 
     # POST 请求示例 (这里用一个CEX API的例子,因为Web3 API 大部分是GET)
     # 例如,下单 (Trade API: /api/v5/trade/order)
     # BASE_URL 应为 "https://www.okx.com"
     # 注意:以下POST示例需要 CEX API 权限,并且请求体结构特定于此接口。仅作演示。
-    # print("\n发送 POST 请求示例 (CEX Trade API - 下单):")
+    # logger.info("\n发送 POST 请求示例 (CEX Trade API - 下单):")
     # BASE_URL_CEX = "https://www.okx.com" # 切换到CEX
     # # 重新设置 BASE_URL 以便 send_post_request 使用正确的域
     # original_base_url = BASE_URL
@@ -257,34 +261,34 @@ if __name__ == "__main__":
     #     "sz": "0.0001", # 数量
     #     "px": "20000"   # 价格
     # }
-    # print(f"请求路径: {post_request_path_trade}")
-    # print(f"请求体: {post_params_trade}")
+    # logger.info(f"请求路径: {post_request_path_trade}")
+    # logger.info(f"请求体: {post_params_trade}")
     # # 确保 API key 对 www.okx.com 有交易权限
-    # print("--- 警告: 此POST请求会实际下单,请谨慎测试 ---")
+    # logger.info("--- 警告: 此POST请求会实际下单,请谨慎测试 ---")
     # # response_data_post = send_post_request(post_request_path_trade, post_params_trade)
     # # if response_data_post:
-    # #     print("POST 请求成功,响应:")
-    # #     print(json.dumps(response_data_post, indent=2))
+    # #     logger.info("POST 请求成功,响应:")
+    # #     logger.info(json.dumps(response_data_post, indent=2))
     # # else:
-    # #     print("POST 请求失败。")
+    # #     logger.info("POST 请求失败。")
     #
     # BASE_URL = original_base_url # 恢复原始 BASE_URL
-    # print("-" * 30)
+    # logger.info("-" * 30)
 
     # 如果您想测试 Node.js 代码中注释掉的 POST 示例:
     # /api/v5/mktplace/nft/ordinals/listings (这是一个 NFT 市场的 API,也属于 Web3 API)
     # BASE_URL 应为 "https://web3.okx.com"
-    # print("\n发送 POST 请求示例 (Web3 Marketplace Ordinals):")
+    # logger.info("\n发送 POST 请求示例 (Web3 Marketplace Ordinals):")
     # post_request_path_ordinals = '/api/v5/mktplace/nft/ordinals/listings'
     # post_params_ordinals = {
     #     'slug': 'sats' # 注意:此参数可能不完整或不正确,请参照最新API文档
     #                    # 通常获取listings需要更多参数,比如分页,排序等
     # }
-    # print(f"请求路径: {post_request_path_ordinals}")
-    # print(f"请求体: {post_params_ordinals}")
+    # logger.info(f"请求路径: {post_request_path_ordinals}")
+    # logger.info(f"请求体: {post_params_ordinals}")
     # response_data_post_ordinals = send_post_request(post_request_path_ordinals, post_params_ordinals)
     # if response_data_post_ordinals:
-    #     print("POST 请求成功,响应:")
-    #     print(json.dumps(response_data_post_ordinals, indent=2))
+    #     logger.info("POST 请求成功,响应:")
+    #     logger.info(json.dumps(response_data_post_ordinals, indent=2))
     # else:
-    #     print("POST 请求失败。")
+    #     logger.info("POST 请求失败。")

+ 34 - 32
checker/price_checker.py

@@ -18,6 +18,10 @@ from config import wallet
 from config import okchain_api
 from config import arb
 
+# logs
+from logger_config import get_logger
+logger = get_logger('as')
+
 # ok web3的配置
 ok_chain_client.api_config = okchain_api # 假设ok_chain_client有此配置方式
 
@@ -39,8 +43,6 @@ CHAIN_ID = arb["CHAIN_ID"]
 USER_WALLET = wallet["user_wallet"]
 USER_EXCHANGE_WALLET = wallet["user_exchange_wallet"]
 
-# 日志格式配置
-logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 proxies = None # {'http': 'http://proxy_url:port', 'https': 'http://proxy_url:port'}
 
 # 運行模式【trade、view】
@@ -82,7 +84,7 @@ def get_chain_price_vs_target_currency(chain_id, in_token_addr, out_token_addr,
             return {
                 "error": f"Okx API错误({chain_id}) - Code:{data.get('code', 'N/A')}, Msg:{data.get('msg', data.get('message', 'N/A')) if isinstance(data, dict) else '格式错误'}"}, None
     except Exception as e:
-        logging.error(f"Okx ({chain_id})请求错误详情: ", exc_info=True)
+        logger.error(f"Okx ({chain_id})请求错误详情: ", exc_info=True)
         return {"error": f"Okx ({chain_id})请求错误: {e}"}, None
 
 # MEXC 现货 (获取 目标代币/USDT 的 bid 价格)
@@ -113,7 +115,7 @@ def get_mexc_spot_price_target_usdt_bid(pair_symbol):
                 trade_volume_remaining -= can_fill
             
             if accumulated_volume == decimal.Decimal('0'): # 如果一点都没卖出去
-                 # logging.warning(f"MEXC无法以EXCHANGE_OUT_AMOUNT={EXCHANGE_OUT_AMOUNT}获取任何 efectiva 卖出价格,累积量为0")
+                 # logger.warning(f"MEXC无法以EXCHANGE_OUT_AMOUNT={EXCHANGE_OUT_AMOUNT}获取任何 efectiva 卖出价格,累积量为0")
                 return {"error": f"MEXC订单簿深度不足以卖出{EXCHANGE_OUT_AMOUNT} {TARGET_ASSET_SYMBOL}"}, decimal.Decimal('0')
 
             # 计算平均卖出价格
@@ -126,13 +128,13 @@ def get_mexc_spot_price_target_usdt_bid(pair_symbol):
                 "price_target_per_usdt_bid1": sell_price # 这个名字其实是 RATO/USDT,所以可以叫 price_target_per_base
             }, trade_value # 返回的是实际能卖出 EXCHANGE_OUT_AMOUNT (或更少,如果深度不足) 所得的 USDT 总额
         else:
-            # logging.warning(f"MEXC现货({pair_symbol}) bids 数据不存在或为空: {data}")
+            # logger.warning(f"MEXC现货({pair_symbol}) bids 数据不存在或为空: {data}")
             return {"error": f"MEXC现货({pair_symbol}) bids 数据不存在或为空"}, decimal.Decimal('0')
     except requests.exceptions.RequestException as e:
-        # logging.error(f"MEXC现货({pair_symbol})请求错误: {e}")
+        # logger.error(f"MEXC现货({pair_symbol})请求错误: {e}")
         return {"error": f"MEXC现货({pair_symbol})请求错误: {e}"}, decimal.Decimal('0')
     except Exception as e:
-        # logging.error(f"MEXC现货({pair_symbol})处理错误: {e}", exc_info=True)
+        # logger.error(f"MEXC现货({pair_symbol})处理错误: {e}", exc_info=True)
         return {"error": f"MEXC现货({pair_symbol})处理错误: {e}"}, decimal.Decimal('0')
 
 latest_values_for_table = {
@@ -164,7 +166,7 @@ def calculate_percentage_diff(price_a_base_per_target, price_b_base_per_target):
 def send_arb_msg(profit_amount, chain_swap_data, mexc_price_usdt_per_target, in_amount_to_query_human):
     # chain_swap_data 是从 get_chain_price_vs_target_currency 返回的第二个值
     if not (chain_swap_data and chain_swap_data.get('data') and chain_swap_data['data']):
-        logging.error(f"套利消息发送失败:链上交易数据不完整 {chain_swap_data}")
+        logger.error(f"套利消息发送失败:链上交易数据不完整 {chain_swap_data}")
         return
 
     d = chain_swap_data['data'][0]
@@ -194,24 +196,24 @@ def send_arb_msg(profit_amount, chain_swap_data, mexc_price_usdt_per_target, in_
         "exchangeOutAmount": str(EXCHANGE_OUT_AMOUNT.quantize(decimal.Decimal(f'1e-{out_dec}'))) # CEX上期望卖出的目标币数量
     }
 
-    logging.info(f"正在提交套利数据到 {ARB_EXECUTOR_URL}, profit {arbitrage_data["profit"]}, profitLimit {arbitrage_data["profitLimit"]}")
+    logger.info(f"正在提交套利数据到 {ARB_EXECUTOR_URL}, profit {arbitrage_data["profit"]}, profitLimit {arbitrage_data["profitLimit"]}")
 
     try:
         response = requests.post(ARB_EXECUTOR_URL, json=arbitrage_data, timeout=10)
-        logging.info(f"套利执行器响应状态码: {response.status_code}")
+        logger.info(f"套利执行器响应状态码: {response.status_code}")
         try:
             response_data = response.json()
-            logging.info(f"套利执行器响应内容: {response_data}")
+            logger.info(f"套利执行器响应内容: {response_data}")
         except requests.exceptions.JSONDecodeError:
-            logging.error(f"套利执行器响应无法解析为JSON: {response.text}")
+            logger.error(f"套利执行器响应无法解析为JSON: {response.text}")
     except requests.exceptions.RequestException as e:
-        logging.error(f"连接套利执行器 {ARB_EXECUTOR_URL} 失败: {e}")
+        logger.error(f"连接套利执行器 {ARB_EXECUTOR_URL} 失败: {e}")
     except Exception as e:
-        logging.error(f"发送套利消息未知错误: {e}", exc_info=True)
+        logger.error(f"发送套利消息未知错误: {e}", exc_info=True)
 
 def update_data_for_plotly_and_table():
     global historical_data_points, latest_values_for_table # IN_AMOUNT_TO_QUERY
-    logging.info(f"数据更新线程 ({TARGET_ASSET_SYMBOL}/{BASE_CURRENCY_SYMBOL})...")
+    logger.info(f"数据更新线程 ({TARGET_ASSET_SYMBOL}/{BASE_CURRENCY_SYMBOL})...")
     
     # local_in_amount_to_query = decimal.Decimal(str(arb["IN_AMOUNT_TO_QUERY"])) # 从配置初始化,后续动态调整
 
@@ -234,7 +236,7 @@ def update_data_for_plotly_and_table():
              mexc_err = mexc_err or "MEXC价格为0或无效"
         
         if mexc_err or trade_value_usdt == decimal.Decimal('0'): # 如果MEXC有问题或无法确定砸盘价值,则跳过本次循环
-            logging.warning(f"MEXC数据获取问题: {mexc_err}, trade_value_usdt: {trade_value_usdt}. 跳过本次循环。")
+            logger.warning(f"MEXC数据获取问题: {mexc_err}, trade_value_usdt: {trade_value_usdt}. 跳过本次循环。")
             with data_lock: # 依然更新错误信息
                 latest_values_for_table["mexc_error"] = mexc_err
                 latest_values_for_table["oo_error"] = latest_values_for_table.get("oo_error") # 保持上次的oo_error
@@ -247,7 +249,7 @@ def update_data_for_plotly_and_table():
         # 作为链上购买目标币时花费的USDT数量 (in_amount_to_query_human)
         in_amount_to_query_human = trade_value_usdt.quantize(decimal.Decimal('1.00'), rounding=decimal.ROUND_DOWN) # 保留两位小数,向下取整
         if in_amount_to_query_human <= decimal.Decimal('0'):
-            logging.warning(f"计算出的链上查询金额为0或负数 ({in_amount_to_query_human} USDT),跳过。trade_value_usdt: {trade_value_usdt}")
+            logger.warning(f"计算出的链上查询金额为0或负数 ({in_amount_to_query_human} USDT),跳过。trade_value_usdt: {trade_value_usdt}")
             time.sleep(REFRESH_INTERVAL_SECONDS)
             continue
 
@@ -301,7 +303,7 @@ def update_data_for_plotly_and_table():
             if chain_swap_full_response: # 确保有完整的链上数据
                 send_arb_msg(actual_profit_usdt, chain_swap_full_response, mexc_price_usdt_per_target_bid1_for_calc, in_amount_to_query_human)
             else:
-                logging.warning("利润满足但链上数据不完整,无法发送套利消息。")
+                logger.warning("利润满足但链上数据不完整,无法发送套利消息。")
 
         current_point = {
             "time": fetch_time_chart,
@@ -322,9 +324,9 @@ def update_data_for_plotly_and_table():
             latest_values_for_table["last_updated"] = fetch_time_full
             latest_values_for_table["in_amount_for_query_display"] = f"{in_amount_to_query_human:.2f} {BASE_CURRENCY_SYMBOL}" if in_amount_to_query_human > 0 else "N/A"
 
-        # logging.info(f"{fetch_time_chart} Price Query: Chain Input {in_amount_to_query_human:.2f} {BASE_CURRENCY_SYMBOL} | OKX Price: {oo_price_usdt_per_target_display} | MEXC Price: {mexc_price_usdt_per_target_bid1_display} | Diff: {diff_display} | Profit: {profit_display}")
+        # logger.info(f"{fetch_time_chart} Price Query: Chain Input {in_amount_to_query_human:.2f} {BASE_CURRENCY_SYMBOL} | OKX Price: {oo_price_usdt_per_target_display} | MEXC Price: {mexc_price_usdt_per_target_bid1_display} | Diff: {diff_display} | Profit: {profit_display}")
         if oo_err or mexc_err :
-             logging.warning(f"{fetch_time_chart} Errors: OO:{oo_err}, MEXC:{mexc_err}")
+             logger.warning(f"{fetch_time_chart} Errors: OO:{oo_err}, MEXC:{mexc_err}")
 
         time.sleep(REFRESH_INTERVAL_SECONDS)
 
@@ -339,14 +341,14 @@ def index_plotly():
 @app.route('/table-data')
 def get_table_data():
     with data_lock:
-        # logging.info(f"Table data requested: {latest_values_for_table}")
+        # logger.info(f"Table data requested: {latest_values_for_table}")
         return jsonify(latest_values_for_table)
 
 @app.route('/plotly-chart-data')
 def get_plotly_chart_data():
     with data_lock:
         points = list(historical_data_points)
-        # logging.info(f"Chart data requested, {len(points)} points.")
+        # logger.info(f"Chart data requested, {len(points)} points.")
         if not points:
             fig = go.Figure() # Create an empty figure
             fig.update_layout(title_text="暂无数据")
@@ -432,25 +434,25 @@ if __name__ == "__main__":
     try:
         args = parser.parse_args()
         mode = args.mode
-        logging.info(f"脚本运行模式为: {mode}")
+        logger.info(f"脚本运行模式为: {mode}")
 
-        logging.info("应用启动...")
-        logging.info(f"目标资产: {TARGET_ASSET_SYMBOL}, 计价货币: {BASE_CURRENCY_SYMBOL}")
+        logger.info("应用启动...")
+        logger.info(f"目标资产: {TARGET_ASSET_SYMBOL}, 计价货币: {BASE_CURRENCY_SYMBOL}")
         # IN_AMOUNT_TO_QUERY 会动态变化,初始值从配置读取,但循环中会基于MEXC的trade_value更新
-        # logging.info(f"链上查询初始金额: {arb['IN_AMOUNT_TO_QUERY']} {BASE_CURRENCY_SYMBOL} -> {TARGET_ASSET_SYMBOL}")
-        logging.info(f"MEXC期望卖出量 (用于计算深度和价值): {EXCHANGE_OUT_AMOUNT} {TARGET_ASSET_SYMBOL}")
-        logging.info(f"利润阈值: {PROFIT_LIMIT} {BASE_CURRENCY_SYMBOL}")
-        logging.info(f"MEXC现货交易对: {MEXC_TARGET_PAIR_USDT}")
+        # logger.info(f"链上查询初始金额: {arb['IN_AMOUNT_TO_QUERY']} {BASE_CURRENCY_SYMBOL} -> {TARGET_ASSET_SYMBOL}")
+        logger.info(f"MEXC期望卖出量 (用于计算深度和价值): {EXCHANGE_OUT_AMOUNT} {TARGET_ASSET_SYMBOL}")
+        logger.info(f"利润阈值: {PROFIT_LIMIT} {BASE_CURRENCY_SYMBOL}")
+        logger.info(f"MEXC现货交易对: {MEXC_TARGET_PAIR_USDT}")
         
         data_thread = threading.Thread(target=update_data_for_plotly_and_table, daemon=True)
         data_thread.start()
 
         port = arb.get("PORT", 5001) # 从配置获取端口,如果没有则默认5001
-        logging.info(f"Flask 服务将在 http://0.0.0.0:{port} 上运行 (刷新间隔: {REFRESH_INTERVAL_SECONDS}s)")
+        logger.info(f"Flask 服务将在 http://0.0.0.0:{port} 上运行 (刷新间隔: {REFRESH_INTERVAL_SECONDS}s)")
         app.run(debug=False, host='0.0.0.0', port=port, use_reloader=False)
 
     except SystemExit: # argparse 在参数错误时会引发 SystemExit
         # parser.print_help() # argparse 默认会打印帮助信息
-        logging.info("脚本因参数错误而退出。请提供 '--mode' 参数 ('trade' 或 'view')。")
+        logger.info("脚本因参数错误而退出。请提供 '--mode' 参数 ('trade' 或 'view')。")
     except Exception as e:
-        logging.critical(f"主程序发生严重错误: {e}", exc_info=True)
+        logger.critical(f"主程序发生严重错误: {e}", exc_info=True)

+ 68 - 68
erc20_to_mexc_first_sell.py

@@ -1,17 +1,17 @@
 import time
-import logging
 import traceback
 import copy
 from web3_py_client import EthClient
 from mexc_client import MexcClient
 from decimal import Decimal, ROUND_DOWN
 from as_utils import add_state_flow_entry
+from checker.logger_config import get_logger
 
 web3 = EthClient()
 mexc = MexcClient()
 
 # 配置日志
-logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+logger = get_logger('as')
 
 class ArbitrageProcess:
     def __init__(self, tx, gas_limit_multiplier, gas_price_multiplier, process_item, 
@@ -119,11 +119,11 @@ class ArbitrageProcess:
         设置系统状态,并打印日志
         """
         if state in self.STATES:
-            logging.info(f"状态变更:{self.current_state} -> {state}")
-            logging.info('')
+            logger.info(f"状态变更:{self.current_state} -> {state}")
+            logger.info('')
             self.current_state = state
         else:
-            logging.error(f"尝试设置无效状态:{state}")
+            logger.error(f"尝试设置无效状态:{state}")
 
     def run_arbitrage_step(self):
         """
@@ -163,17 +163,17 @@ class ArbitrageProcess:
 
         elif self.current_state == self.STATE_COMPLETED:
             msg = "套利流程成功完成!"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
         elif self.current_state == self.STATE_REJECT:
             msg = "套利流程被程序拒绝"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
         elif self.current_state == self.STATE_FAILED:
             msg = "套利流程失败!"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
     def _execute_check(self):
@@ -191,13 +191,13 @@ class ArbitrageProcess:
                 if balance['asset'] == self.coin:
                     if Decimal(balance['free']) < pseudo_amount_to_sell:
                         msg = f"交易所剩余{self.coin}: {balance['free']}, 交易所准备卖出:{pseudo_amount_to_sell}, 不能触发套保交易。"
-                        logging.info(msg)
+                        logger.info(msg)
                         add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                         self._set_state(self.STATE_REJECT)
                         return
                     else:
                         msg = f"交易所剩余{self.coin}: {balance['free']}, 交易所准备卖出:{pseudo_amount_to_sell}, 余额校验通过(可以套保)。"
-                        logging.info(msg)
+                        logger.info(msg)
                         add_state_flow_entry(self.process_item, self.current_state, msg, "success")
                         break
 
@@ -217,7 +217,7 @@ class ArbitrageProcess:
             estimated_eth = estimated_eth.quantize(Decimal('1e-8'), rounding=ROUND_DOWN)
 
             msg = f"估算的燃气量: {estimated_gas}, eth消耗: {estimated_eth}, gas price: {gas_price_gwei} gwei, gas估算通過"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
             # step3, 費用與利潤比較
@@ -226,12 +226,12 @@ class ArbitrageProcess:
             cost = estimated_eth_value + self.WITHDRAW_FEE          # 成本
             if self.profit < cost:
                 msg = f"費用判斷不通過! profit: {self.profit}, eth_value:{estimated_eth_value}, eth: {estimated_eth}, eth_price: {self.eth_price}"
-                logging.info(msg)
+                logger.info(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                 self._set_state(self.STATE_REJECT)
                 return
             msg = f"費用判斷通過! profit: {self.profit}, eth_value:{estimated_eth_value}, eth: {estimated_eth}, eth_price: {self.eth_price}"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
             # step4, 與賬戶eth餘額比對(至少留0.001,不然沒gas了)
@@ -241,19 +241,19 @@ class ArbitrageProcess:
             eth_balance = eth_balance.quantize(Decimal('1e-6'), rounding=ROUND_DOWN)
             if eth_balance - estimated_eth < MARGIN:
                 msg = f"gas餘額判斷不通過! MARGIN:{MARGIN}, estimated_eth: {estimated_eth}, eth_balance: {eth_balance}"
-                logging.info(msg)
+                logger.info(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                 self._set_state(self.STATE_REJECT)
                 return
             msg = f"gas餘額判斷通過! MARGIN:{MARGIN}, estimated_eth: {estimated_eth}, eth_balance: {eth_balance}"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
             # final, 設定交易狀態,開始交易
             self._set_state(self.STATE_SELLING_ON_EXCHANGE)
         except Exception as e:
             msg = f"前置檢查未通過:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_REJECT)
 
@@ -265,7 +265,7 @@ class ArbitrageProcess:
         在中心化交易所卖出现货
         """
         msg = "执行:中心化交易所卖出现货..."
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
         try:
             # 第一步直接卖出,这个数量用固定数量
@@ -279,11 +279,11 @@ class ArbitrageProcess:
                 "type": "MARKET",
                 "quantity": int(pseudo_amount_to_sell),
             }
-            logging.info(order_params)
+            logger.info(order_params)
             exchange_sell_order = mexc.trade.post_order(order_params)
             if 'orderId' not in exchange_sell_order:
                 msg = f"交易所现货卖出下单失败:{exchange_sell_order}, {order_params}"
-                logging.error(msg)
+                logger.error(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                 self._set_state(self.STATE_FAILED)
 
@@ -292,13 +292,13 @@ class ArbitrageProcess:
             self.exchange_sell_order_id = exchange_sell_order['orderId']
             
             msg = f"交易所现货卖出订单已发送, 订单ID: {self.exchange_sell_order_id}"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
             self._set_state(self.STATE_WAITING_SELL_CONFIRM)
         except Exception as e:
             msg = f"交易所现货卖出下单失败:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_FAILED)
 
@@ -310,7 +310,7 @@ class ArbitrageProcess:
         """
         exchange_sell_order_id = self.exchange_sell_order_id
         msg = f"等待交易所现货卖出订单确认:{exchange_sell_order_id}"
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
 
         last_order = None
@@ -333,7 +333,7 @@ class ArbitrageProcess:
                     self.sell_price = self.sell_price.quantize(Decimal('1e-8'), rounding=ROUND_DOWN)
 
                     msg = f"交易所现货卖出订单已完成, 价格:{self.sell_price}, money: {money}, {order}"
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                     self.exchange_withdrawal_amount = money
@@ -345,12 +345,12 @@ class ArbitrageProcess:
                     waiting_times = waiting_times - 1
 
             msg = f"交易所现货卖出订单失敗, 最後狀態:{last_order}。"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_FAILED)
         except Exception as e:
             msg = f"查询交易所现货卖出订单状态时发生错误:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_FAILED)
 
@@ -361,7 +361,7 @@ class ArbitrageProcess:
         在链上执行买入操作
         """
         msg = "执行:链上买入操作..."
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
         try:
             # 交易前nonce
@@ -388,13 +388,13 @@ class ArbitrageProcess:
 
             # 交易成功
             msg = f"链上买入交易已发送, 交易哈希:{self.chain_tx_hash}"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
             self._set_state(self.STATE_WAITING_CHAIN_CONFIRM)
 
         except Exception as e:
             msg = f"链上买入失败:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)
 
@@ -407,7 +407,7 @@ class ArbitrageProcess:
 
         chain_tx_hash = self.chain_tx_hash
         msg = f"等待链上交易确认:{chain_tx_hash}"
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
         try:
             # 給300秒時間進行確認
@@ -429,7 +429,7 @@ class ArbitrageProcess:
                 # 交易失敗的邏輯處理,直接進行回滾
                 if tx_details['status'] != 'success':
                     msg = f"链上交易失敗。{tx_details}"
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
                     self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)                    
@@ -437,7 +437,7 @@ class ArbitrageProcess:
                     break
 
                 msg = f"链上交易已确认。{tx_details}"
-                logging.info(msg)
+                logger.info(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                 # 獲取交易信息
@@ -459,7 +459,7 @@ class ArbitrageProcess:
                 rate = rate.quantize(Decimal('1e-4'), rounding=ROUND_DOWN)
 
                 msg = f"【比率{rate}】。用{from_token_amount_human}买入{to_token_amount_human},价格{self.buy_price}。"
-                logging.info(msg)
+                logger.info(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                 # 判斷快速二賣條件
@@ -467,7 +467,7 @@ class ArbitrageProcess:
                 value = diff * self.sell_price
                 if value > 2:
                     msg = f"滿足二賣條件,{diff}*{self.sell_price} = {value}"
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                     order_params = {
@@ -476,11 +476,11 @@ class ArbitrageProcess:
                         "type": "MARKET",
                         "quantity": int(diff),
                     }
-                    logging.info(order_params)
+                    logger.info(order_params)
                     exchange_sell_order = mexc.trade.post_order(order_params)
                     if 'orderId' not in exchange_sell_order:
                         msg = f"交易所现货二卖下单失败:{exchange_sell_order}, {order_params}"
-                        logging.error(msg)
+                        logger.error(msg)
                         add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                     else:
                         oid = exchange_sell_order['orderId']
@@ -499,7 +499,7 @@ class ArbitrageProcess:
                                 money = Decimal(order['cummulativeQuoteQty'])
 
                                 msg = f"交易所现货二卖订单已完成。money: {money}"
-                                logging.info(msg)
+                                logger.info(msg)
                                 add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                                 self.exchange_withdrawal_amount = self.exchange_withdrawal_amount + money
@@ -511,11 +511,11 @@ class ArbitrageProcess:
 
                         if waiting_times_inner <= 0:
                             msg = f"交易所现货二卖订单失敗, 最後狀態:{last_order}。"
-                            logging.info(msg)
+                            logger.info(msg)
                             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")     
                 else:
                     msg = f"不滿足二賣條件,{diff}*{self.sell_price} = {value}"
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
                 self._set_state(self.STATE_WAITING_TRANSFER_ARRIVE)
@@ -528,12 +528,12 @@ class ArbitrageProcess:
                     tx_details = copy.deepcopy(self.pending_data[chain_tx_hash]['tx_details'])
                 
                 msg = f"链上交易确认失败:{chain_tx_hash}, {tx_details}"
-                logging.error(msg)
+                logger.error(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                 self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)
         except Exception as e:
             msg = f"查询链上确认状态时发生错误:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_WAITING_EXCHANGE_ROLLBACK)
 
@@ -544,7 +544,7 @@ class ArbitrageProcess:
         市价进行交易所交易回滚
         """
         msg = "执行:中心化交易所买入现货回滚..."
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
         try:
             # 使用预提现数量进行回滚
@@ -560,13 +560,13 @@ class ArbitrageProcess:
 
                     if pseudo_amount_to_buy < Decimal('10'):
                         msg = f"交易所剩余{self.base_coin}: {balance['free']}, 小于10, 不能触发回滚交易。"
-                        logging.info(msg)
+                        logger.info(msg)
                         add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                         self._set_state(self.STATE_FAILED)
                         return
                     else:
                         msg = f"交易所剩余{self.base_coin}: {balance['free']}, 交易所准备使用:{pseudo_amount_to_buy}, 余额校验通过(可以回滚)。"
-                        logging.info(msg)
+                        logger.info(msg)
                         add_state_flow_entry(self.process_item, self.current_state, msg, "success")
                         break
             
@@ -576,11 +576,11 @@ class ArbitrageProcess:
                 "type": "MARKET",
                 "quoteOrderQty": int(pseudo_amount_to_buy),
             }
-            logging.info(order_params)
+            logger.info(order_params)
             exchange_buy_order = mexc.trade.post_order(order_params)
             if 'orderId' not in exchange_buy_order:
                 msg = f"【回滚】交易所现货买入下单失败:{exchange_buy_order}"
-                logging.error(msg)
+                logger.error(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
                 self._set_state("FAILED")
 
@@ -589,7 +589,7 @@ class ArbitrageProcess:
             exchange_buy_order_id = exchange_buy_order['orderId']
             
             msg = f"【回滚】交易所现货买入订单已发送, 订单ID: {exchange_buy_order_id}"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
             # 查询交易所订单状态
@@ -611,7 +611,7 @@ class ArbitrageProcess:
 
                     msg = f"【回滚】交易所现货买入订单已完全成交, 价格:{price}。{order}"
 
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                     self._set_state(self.STATE_FAILED)
@@ -624,13 +624,13 @@ class ArbitrageProcess:
                 waiting_times = waiting_times - 1
             
             msg = f"【回滚】回滚交易订单查询超时, 订单ID: {exchange_buy_order_id},最终状态:{last_query_rst}"
-            logging.info(msg)
+            logger.info(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
             self._set_state(self.STATE_FAILED)
         except Exception as e:
             msg = f"【回滚】交易所回滚交易失败:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_FAILED)
 
@@ -641,7 +641,7 @@ class ArbitrageProcess:
         等待资产在交易所内到账
         """
         msg = f"等待资产在交易所到账..."
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
 
         try:
@@ -688,13 +688,13 @@ class ArbitrageProcess:
                     # 最終判斷
                     if exchange_sell_amount + asset_balance > pending_amount:
                         msg = f"【flash】资产可以進行快速提現。{last_deposit_state}"
-                        logging.info(msg)
+                        logger.info(msg)
                         add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                         self._set_state(self.STATE_TRANSFERRING_TO_CHAIN)
                         return
                 
-                logging.info(f"正在檢查快速提現條件...({waiting_times}/10)")
+                logger.info(f"正在檢查快速提現條件...({waiting_times}/10)")
                 waiting_times = waiting_times - 1
 
             # 最多等待30分钟
@@ -708,13 +708,13 @@ class ArbitrageProcess:
 
                     last_deposit_state = deposit
 
-                    logging.info(f"等待资产在交易所到账...({deposit['confirmTimes']}/{deposit['unlockConfirm']})")
+                    logger.info(f"等待资产在交易所到账...({deposit['confirmTimes']}/{deposit['unlockConfirm']})")
                     if Decimal(deposit['confirmTimes']) >= Decimal(deposit['unlockConfirm']):
                         is_arrived = True
 
                 if is_arrived:
                     msg = f"资产已在交易所到账。{last_deposit_state}"
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                     self._set_state(self.STATE_TRANSFERRING_TO_CHAIN)
@@ -724,13 +724,13 @@ class ArbitrageProcess:
                 waiting_times = waiting_times - 1
 
             msg = f"等待充值到账超时(超过30分钟): {last_deposit_state}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
             self._set_state(self.STATE_FAILED)
         except Exception as e:
             msg = f"查询交易所到账状态时发生错误:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
             self._set_state(self.STATE_FAILED)
@@ -742,7 +742,7 @@ class ArbitrageProcess:
         将交易后获得的计价资产(例如USDT)转账回链上
         """
         msg = "执行:交易所计价资产转账回链上..."
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
 
         try:
@@ -757,20 +757,20 @@ class ArbitrageProcess:
             withdrawal_rst = mexc.wallet.post_withdraw(withdrawal_params)
             if "id" not in withdrawal_rst:
                 msg = f"交易所提现失败\n參數: {withdrawal_params}\n響應: {withdrawal_rst}"
-                logging.error(msg)
+                logger.error(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
                 self._set_state(self.STATE_FAILED)
             else:
                 self.exchange_withdrawal_id = withdrawal_rst["id"]
                 msg = f"交易所提现已发送, 提现ID: {self.exchange_withdrawal_id}"
-                logging.info(msg)
+                logger.info(msg)
                 add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                 self._set_state(self.STATE_WAITING_WITHDRAWAL_CONFIRM)
         except Exception as e:
             msg = f"转账回链上失败: {e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
             self._set_state(self.STATE_FAILED)
@@ -784,7 +784,7 @@ class ArbitrageProcess:
         exchange_withdrawal_id = self.exchange_withdrawal_id
 
         msg = f"等待交易所提现确认:{exchange_withdrawal_id}"
-        logging.info(msg)
+        logger.info(msg)
         add_state_flow_entry(self.process_item, self.current_state, msg, "pending")
         try:
             is_arrived = False
@@ -797,7 +797,7 @@ class ArbitrageProcess:
 
                 if not isinstance(withdrawal_list, list):
                     msg = f"查询交易所提现状态时发生错误:{withdrawal_list}"
-                    logging.error(msg)
+                    logger.error(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
                     self._set_state("FAILED")
@@ -814,7 +814,7 @@ class ArbitrageProcess:
 
                 if is_arrived:
                     msg = f"提现请求已上链: {last_deposit_state}"
-                    logging.info(msg)
+                    logger.info(msg)
                     add_state_flow_entry(self.process_item, self.current_state, msg, "success")
 
                     self._set_state(self.STATE_COMPLETED)
@@ -824,13 +824,13 @@ class ArbitrageProcess:
                 waiting_times = waiting_times - 1
 
             msg = f"等待提现到账超时(超过30分钟): {last_deposit_state}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
 
             self._set_state(self.STATE_FAILED)
         except Exception as e:
             msg = f"查询交易所提现状态时发生错误:{e}"
-            logging.error(msg)
+            logger.error(msg)
             add_state_flow_entry(self.process_item, self.current_state, msg, "fail")
             self._set_state(self.STATE_FAILED)
 
@@ -901,8 +901,8 @@ if __name__ == "__main__":
         # else:
         #     time.sleep(1)
 
-    logging.info(process_item)
+    logger.info(process_item)
     if ap.current_state == "COMPLETED":
-        logging.info("套利流程执行成功!")
+        logger.info("套利流程执行成功!")
     else:
-        logging.info("套利流程执行失败!")
+        logger.info("套利流程执行失败!")

+ 1 - 1
toto.readme

@@ -4,11 +4,11 @@
 
 2025-06-04
 [-] 緊急檢修ok api超頻問題
+[-] 日志輸出到文件
 [ ] 成本統計,計算純利潤
 [ ] 解密HASH進行鑒權
 [ ] json用pprint美化后輸出
 [ ] 查询交易所到账状态时发生错误:'balances'
-[ ] 日志輸出到文件
 
 2025-06-05
 [ ] 做另一個方向之前,需要先整理策略層架構,當前架構如何兼容多策略

+ 37 - 36
web3_py_client.py

@@ -7,10 +7,11 @@ from web3 import Web3
 from web3.middleware import ExtraDataToPOAMiddleware # For PoA networks like Goerli, Sepolia, BSC etc.
 from eth_account import Account
 from dotenv import load_dotenv
+from checker.logger_config import get_logger
 
 
 # 配置日志
-logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+logger = get_logger('as')
 
 # 加载环境变量
 load_dotenv()
@@ -137,7 +138,7 @@ class EthClient:
 
         self.account = Account.from_key(_hash)
         self.address = self.account.address
-        logging.info(f"EthClient initialized. Address: {self.address}, RPC: {self.rpc_url}, Connected: {self.w3.is_connected()}")
+        logger.info(f"EthClient initialized. Address: {self.address}, RPC: {self.rpc_url}, Connected: {self.w3.is_connected()}")
 
     def _get_nonce(self) -> int:
         """获取账户的下一个 nonce"""
@@ -152,7 +153,7 @@ class EthClient:
         try:
             # 填充 gas 和 nonce (如果未提供)
             if 'nonce' not in tx:
-                logging.info('TODO nonce应该提前管理好')
+                logger.info('TODO nonce应该提前管理好')
                 tx['nonce'] = self._get_nonce()
             
             '''
@@ -178,7 +179,7 @@ class EthClient:
 
             return signed_tx
         except Exception as e:
-            logging.info(f"Error signing transaction: {e}")
+            logger.info(f"Error signing transaction: {e}")
 
     def _sign_and_send_transaction(self, tx: dict, gas_limit_multiplier: float = 1.2) -> str:
         """签署并发送交易,返回交易哈希"""
@@ -187,7 +188,7 @@ class EthClient:
             tx_hash = self.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
             return self.w3.to_hex(tx_hash)
         except Exception as e:
-            logging.info(f"Error signing or sending transaction: {e}")
+            logger.info(f"Error signing or sending transaction: {e}")
             # 可以进一步处理特定错误,例如 nonce 过低,余额不足等
             raise
 
@@ -197,7 +198,7 @@ class EthClient:
             receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout, poll_latency=poll_latency)
             return receipt
         except Exception as e: # Web3.exceptions.TimeExhausted as e
-            logging.info(f"Transaction {tx_hash} timed out after {timeout} seconds.")
+            logger.info(f"Transaction {tx_hash} timed out after {timeout} seconds.")
             raise
 
     def send_eth(self, to_address: str, amount_ether: float, gas_limit: int = None, gas_price_gwei: float = None) -> str:
@@ -216,7 +217,7 @@ class EthClient:
         if gas_price_gwei:
             tx['gasPrice'] = self.w3.to_wei(gas_price_gwei, 'gwei')
 
-        logging.info(f"Preparing to send {amount_ether} ETH to {to_address}...")
+        logger.info(f"Preparing to send {amount_ether} ETH to {to_address}...")
         return self._sign_and_send_transaction(tx)
 
     def _get_erc20_contract(self, token_address: str):
@@ -274,7 +275,7 @@ class EthClient:
         if gas_price:
             tx_data['gasPrice'] = gas_price
 
-        logging.info(f"Preparing to transfer {amount_readable} of token {token_address} to {to_address}...")
+        logger.info(f"Preparing to transfer {amount_readable} of token {token_address} to {to_address}...")
         return self._sign_and_send_transaction(tx_data, 1.2, 2)
 
     def approve_erc20(self, token_address: str, spender_address: str, amount_readable: float,
@@ -307,7 +308,7 @@ class EthClient:
         if gas_price_gwei:
             tx_data['gasPrice'] = self.w3.to_wei(gas_price_gwei, 'gwei')
 
-        logging.info(f"Preparing to approve {amount_readable} of token {token_address} for spender {spender_address}...")
+        logger.info(f"Preparing to approve {amount_readable} of token {token_address} for spender {spender_address}...")
         return self._sign_and_send_transaction(tx_data)
 
     def get_erc20_balance(self, token_address: str, owner_address: str = None) -> Decimal:
@@ -457,13 +458,13 @@ if __name__ == "__main__":
         # estimated_gas = client.w3.eth.estimate_gas(tx)
         # estimated_wei = estimated_gas * (tx['maxPriorityFeePerGas'] + tx['maxFeePerGas'])
         # estimated_eth = estimated_wei / (10 ** 18)
-        # logging.info(f"估算的燃气量: {estimated_gas}, eth消耗: {estimated_eth}")
+        # logger.info(f"估算的燃气量: {estimated_gas}, eth消耗: {estimated_eth}")
 
-        # logging.info(f"餘額:{client.w3.eth.get_balance(USER_WALLET) / Decimal('1e18')}")
+        # logger.info(f"餘額:{client.w3.eth.get_balance(USER_WALLET) / Decimal('1e18')}")
 
         # tx_hash = client._sign_and_send_transaction(tx)
         # receipt = client.wait_for_transaction_receipt(tx_hash)
-        # logging.info(f"{tx_hash} 交易已确认! Status: {'Success' if receipt.status == 1 else 'Failed'}")
+        # logger.info(f"{tx_hash} 交易已确认! Status: {'Success' if receipt.status == 1 else 'Failed'}")
 
 
         # # ok api發交易測試
@@ -506,44 +507,44 @@ if __name__ == "__main__":
     # try:
     #     client = EthClient() # RPC_URL 和 HASH 会从 .env 文件加载
 
-    #     logging.info(f"\nMy ETH Balance: {client.get_eth_balance()} ETH")
+    #     logger.info(f"\nMy ETH Balance: {client.get_eth_balance()} ETH")
 
     #     # 1. 发送 ETH (取消注释以测试, 确保接收地址正确且你有足够ETH)
-    #     # logging.info(f"\nAttempting to send ETH...")
+    #     # logger.info(f"\nAttempting to send ETH...")
     #     # eth_tx_hash = client.send_eth(TEST_RECIPIENT_ADDRESS, 0.0001) # 发送 0.0001 ETH
-    #     # logging.info(f"ETH transaction sent! Hash: {eth_tx_hash}")
+    #     # logger.info(f"ETH transaction sent! Hash: {eth_tx_hash}")
     #     # receipt = client.wait_for_transaction_receipt(eth_tx_hash)
-    #     # logging.info(f"ETH transaction confirmed! Status: {'Success' if receipt.status == 1 else 'Failed'}")
+    #     # logger.info(f"ETH transaction confirmed! Status: {'Success' if receipt.status == 1 else 'Failed'}")
 
     #     # --- ERC20 操作示例 ---
     #     # 使用 Sepolia LINK 代币进行演示
     #     token_address = TEST_ERC20_TOKEN_ADDRESS_SEPOLIA_LINK
     #     if not client.w3.is_address(token_address): # 简单检查
-    #          logging.info(f"Warning: {token_address} does not look like a valid address. Skipping ERC20 tests.")
+    #          logger.info(f"Warning: {token_address} does not look like a valid address. Skipping ERC20 tests.")
     #     else:
-    #         logging.info(f"\n--- ERC20 Token Operations for: {token_address} ---")
+    #         logger.info(f"\n--- ERC20 Token Operations for: {token_address} ---")
     #         token_name = client.get_erc20_name(token_address)
     #         token_symbol = client.get_erc20_symbol(token_address)
     #         token_decimals = client.get_erc20_decimals(token_address)
-    #         logging.info(f"Token: {token_name} ({token_symbol}), Decimals: {token_decimals}")
+    #         logger.info(f"Token: {token_name} ({token_symbol}), Decimals: {token_decimals}")
 
     #         # ERC20余额查询以及基础功能测试(总供应量)
     #         my_token_balance = client.get_erc20_balance(token_address)
-    #         logging.info(f"My {token_symbol} Balance: {my_token_balance} {token_symbol}")
+    #         logger.info(f"My {token_symbol} Balance: {my_token_balance} {token_symbol}")
     #         total_supply = client.get_erc20_total_supply(token_address)
-    #         logging.info(f"Total Supply of {token_symbol}: {total_supply} {token_symbol}")
+    #         logger.info(f"Total Supply of {token_symbol}: {total_supply} {token_symbol}")
 
     #         # # 2. ERC20 转账 (取消注释以测试, 确保你有该代币且接收地址正确)
     #         # amount_to_transfer = 0.01 # 转移 0.01 个代币
     #         # if my_token_balance >= Decimal(str(amount_to_transfer)):
-    #         #     logging.info(f"\nAttempting to transfer {amount_to_transfer} {token_symbol}...")
+    #         #     logger.info(f"\nAttempting to transfer {amount_to_transfer} {token_symbol}...")
     #         #     erc20_tx_hash = client.transfer_erc20(token_address, TEST_RECIPIENT_ADDRESS, amount_to_transfer)
-    #         #     logging.info(f"{token_symbol} transfer transaction sent! Block: {client.w3.eth.block_number} Hash: {erc20_tx_hash}")
+    #         #     logger.info(f"{token_symbol} transfer transaction sent! Block: {client.w3.eth.block_number} Hash: {erc20_tx_hash}")
     #         #     receipt = client.wait_for_transaction_receipt(erc20_tx_hash)
-    #         #     logging.info(f"{token_symbol} transfer transaction confirmed! Block: {client.w3.eth.block_number} Status: {'Success' if receipt.status == 1 else 'Failed'}")
-    #         #     logging.info(f"My new {token_symbol} Balance: {client.get_erc20_balance(token_address)} {token_symbol}")
+    #         #     logger.info(f"{token_symbol} transfer transaction confirmed! Block: {client.w3.eth.block_number} Status: {'Success' if receipt.status == 1 else 'Failed'}")
+    #         #     logger.info(f"My new {token_symbol} Balance: {client.get_erc20_balance(token_address)} {token_symbol}")
     #         # else:
-    #         #     logging.info(f"Insufficient {token_symbol} balance to transfer {amount_to_transfer} {token_symbol}.")
+    #         #     logger.info(f"Insufficient {token_symbol} balance to transfer {amount_to_transfer} {token_symbol}.")
 
     #         # # 3. ERC20 Approve 和 Allowance (取消注释以测试)
     #         # spender_for_allowance = '0x156ACd2bc5fC336D59BAAE602a2BD9b5e20D6672' # 可以是任何你想授权的地址
@@ -551,25 +552,25 @@ if __name__ == "__main__":
     #         # token_address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"
             
     #         # # current_allowance = client.get_erc20_allowance(token_address, spender_for_allowance)
-    #         # # logging.info(f"\nCurrent allowance for {spender_for_allowance} to spend my {token_symbol}: {current_allowance} {token_symbol}")
+    #         # # logger.info(f"\nCurrent allowance for {spender_for_allowance} to spend my {token_symbol}: {current_allowance} {token_symbol}")
             
     #         # # if my_token_balance >= Decimal(str(amount_to_approve)): # 确保有足够的代币去授权(虽然授权本身不消耗代币)
-    #         # logging.info(f"\nAttempting to approve {amount_to_approve} {token_symbol} for spender {spender_for_allowance}...")
+    #         # logger.info(f"\nAttempting to approve {amount_to_approve} {token_symbol} for spender {spender_for_allowance}...")
     #         # approve_tx_hash = client.approve_erc20(token_address, spender_for_allowance, amount_to_approve)
-    #         # logging.info(f"{token_symbol} approve transaction sent! Hash: {approve_tx_hash}")
+    #         # logger.info(f"{token_symbol} approve transaction sent! Hash: {approve_tx_hash}")
     #         # receipt = client.wait_for_transaction_receipt(approve_tx_hash)
-    #         # logging.info(f"{token_symbol} approve transaction confirmed! Status: {'Success' if receipt.status == 1 else 'Failed'}")
+    #         # logger.info(f"{token_symbol} approve transaction confirmed! Status: {'Success' if receipt.status == 1 else 'Failed'}")
         
     #         # new_allowance = client.get_erc20_allowance(token_address, spender_for_allowance)
-    #         # logging.info(f"New allowance for {spender_for_allowance}: {new_allowance} {token_symbol}")
+    #         # logger.info(f"New allowance for {spender_for_allowance}: {new_allowance} {token_symbol}")
     #         # else:
-    #         #      logging.info(f"Not enough balance to consider approving {amount_to_approve} {token_symbol} (though approval itself doesn't spend tokens).")
+    #         #      logger.info(f"Not enough balance to consider approving {amount_to_approve} {token_symbol} (though approval itself doesn't spend tokens).")
 
     # except ValueError as ve:
-    #     logging.info(f"Configuration Error: {ve}")
+    #     logger.info(f"Configuration Error: {ve}")
     # except ConnectionError as ce:
-    #     logging.info(f"Connection Error: {ce}")
+    #     logger.info(f"Connection Error: {ce}")
     # except Exception as e:
-    #     logging.info(f"An unexpected error occurred: {e}")
+    #     logger.info(f"An unexpected error occurred: {e}")
     #     import traceback
-    #     traceback.logging.info_exc()
+    #     traceback.logger.info_exc()