浏览代码

view模式

skyfffire 2 月之前
父节点
当前提交
394088a10f
共有 3 个文件被更改,包括 110 次插入80 次删除
  1. 11 8
      checker/c_erc20_to_mexc.py
  2. 97 71
      checker/c_mexc_to_erc20.py
  3. 2 1
      toto.readme

+ 11 - 8
checker/c_erc20_to_mexc.py

@@ -42,11 +42,14 @@ ARB_EXECUTOR_URL = arb["ARB_EXECUTOR_URL"]
 # IN_AMOUNT_TO_QUERY 将在循环中动态确定
 BASE_TOKEN_TRADE_AMOUNT = decimal.Decimal(str(arb["BASE_TOKEN_TRADE_AMOUNT"])) # 确保是Decimal
 CEX_TRADE_AMOUNT = decimal.Decimal(str(arb["COIN_TOKEN_TRADE_AMOUNT"])) # 确保是Decimal
-OPEN_LIMIT = decimal.Decimal(str(arb["OPEN_LIMIT"])) # 确保是Decimal
-CLOSE_LIMIT = decimal.Decimal(str(arb["CLOSE_LIMIT"])) # 确保是Decimal
+
 IN_TOKEN_ADDRESS = arb["BASE_TOKEN_ADDRESS"]
 IN_TOKEN_DECIMALS = web3_client.get_erc20_decimals(IN_TOKEN_ADDRESS)
 OUT_TOKEN_ADDRESS = arb["COIN_TOKEN_ADDRESS"]
+
+OPEN_LIMIT = decimal.Decimal(str(arb["OPEN_LIMIT"])) # 确保是Decimal
+CLOSE_LIMIT = decimal.Decimal(str(arb["CLOSE_LIMIT"])) # 确保是Decimal
+
 SLIPPAGE = arb["SLIPPAGE"]
 CEX_TARGET_PAIR_USDT = arb["CEX_PAIR"]
 CHAIN_ID = arb["CHAIN_ID"]
@@ -166,15 +169,15 @@ latest_values_for_table = {
 }
 data_lock = threading.Lock()
 
-def calculate_percentage_diff(price_a_base_per_target, price_b_base_per_target):
+def calculate_percentage_diff(sell_price, buy_price):
     # price_a: CEX卖价 (USDT/TARGET) - 链上买的目标币,拿到CEX卖掉
     # price_b: 链上买价 (USDT/TARGET) - 链上用USDT买目标币
     # 期望 price_a > price_b
-    if price_a_base_per_target is not None and price_b_base_per_target is not None and \
-       isinstance(price_a_base_per_target, decimal.Decimal) and \
-       isinstance(price_b_base_per_target, decimal.Decimal) and price_b_base_per_target != 0:
+    if sell_price is not None and buy_price is not None and \
+       isinstance(sell_price, decimal.Decimal) and \
+       isinstance(buy_price, decimal.Decimal) and buy_price != 0:
         # (卖价 - 买价) / 买价
-        rst = (price_a_base_per_target - price_b_base_per_target) / price_b_base_per_target
+        rst = (sell_price - buy_price) / buy_price
         rst = rst.quantize(decimal.Decimal('1e-6'), rounding=decimal.ROUND_DOWN) # 提高精度
         return rst
     return None
@@ -466,7 +469,7 @@ if __name__ == "__main__":
         # IN_AMOUNT_TO_QUERY 会动态变化,初始值从配置读取,但循环中会基于CEX的trade_value更新
         # logger.info(f"链上查询初始金额: {arb['IN_AMOUNT_TO_QUERY']} {BASE_CURRENCY_SYMBOL} -> {TARGET_ASSET_SYMBOL}")
         logger.info(f"CEX期望卖出量 (用于计算深度和价值): {CEX_TRADE_AMOUNT} {TARGET_ASSET_SYMBOL}")
-        logger.info(f"开仓阈值 > {OPEN_LIMIT} %")
+        logger.info(f"开仓阈值 > {OPEN_LIMIT}, 平仓阈值 > {CLOSE_LIMIT}")
         logger.info(f"CEX现货交易对: {CEX_TARGET_PAIR_USDT}")
         
         data_thread = threading.Thread(target=update_data_for_plotly_and_table, daemon=True)

+ 97 - 71
checker/c_mexc_to_erc20.py

@@ -17,6 +17,7 @@ from plotly.utils import PlotlyJSONEncoder
 from config import wallet
 from config import okchain_api
 from config import arb
+from config import rpc_url
 
 # logs
 from logger_config import get_logger
@@ -24,7 +25,7 @@ logger = get_logger('as')
 
 # lite客户端
 from web3_py_client_lite import EthClient
-web3_client = EthClient()
+web3_client = EthClient(rpc_url)
 
 # ok web3的配置
 ok_chain_client.api_config = okchain_api # 假设ok_chain_client有此配置方式
@@ -33,14 +34,18 @@ ok_chain_client.api_config = okchain_api # 假设ok_chain_client有此配置方
 ARB_EXECUTOR_URL = arb["ARB_EXECUTOR_URL"]
 
 # --- 配置部分 ---
-# EXCHANGE_OUT_AMOUNT 将在循环中动态确定
-IN_AMOUNT_TO_QUERY = decimal.Decimal(str(arb["COIN_TOKEN_TRADE_AMOUNT"]))
-PROFIT_LIMIT = decimal.Decimal(str(arb["PROFIT_LIMIT"])) # 确保是Decimal
+BASE_TOKEN_TRADE_AMOUNT = decimal.Decimal(str(arb["BASE_TOKEN_TRADE_AMOUNT"])) # 确保是Decimal
+DEX_QUERRY_AMOUNT = decimal.Decimal(str(arb["COIN_TOKEN_TRADE_AMOUNT"]))
+
 IN_TOKEN_ADDRESS = arb["COIN_TOKEN_ADDRESS"]
 IN_TOKEN_DECIMALS = web3_client.get_erc20_decimals(IN_TOKEN_ADDRESS)
 OUT_TOKEN_ADDRESS = arb["BASE_TOKEN_ADDRESS"]
+
+OPEN_LIMIT = decimal.Decimal(str(arb["OPEN_LIMIT"])) # 确保是Decimal
+CLOSE_LIMIT = decimal.Decimal(str(arb["CLOSE_LIMIT"])) # 确保是Decimal
+
 SLIPPAGE = arb["SLIPPAGE"]
-MEXC_TARGET_PAIR_USDT = arb["CEX_PAIR"]
+CEX_TARGET_PAIR_USDT = arb["CEX_PAIR"]
 CHAIN_ID = arb["CHAIN_ID"]
 STRATEGY = arb["STRATEGY"]
 
@@ -52,6 +57,9 @@ proxies = None # {'http': 'http://proxy_url:port', 'https': 'http://proxy_url:po
 
 # 運行模式【trade、view】
 mode = None
+
+# 该api运行的端口
+api_endpoint_port = 5001
 # dex_price = None # 这个全局变量似乎没有被有效使用,价格在循环内获取
 
 # 配置請求的日志等級
@@ -63,8 +71,8 @@ REFRESH_INTERVAL_SECONDS = 1 # 稍微增加间隔以减少API调用频率
 MAX_HISTORY_POINTS_PLOTLY = 21600
 historical_data_points = deque(maxlen=MAX_HISTORY_POINTS_PLOTLY)
 
-TARGET_ASSET_SYMBOL = MEXC_TARGET_PAIR_USDT.split('_')[0] # e.g., RATO
-BASE_CURRENCY_SYMBOL = MEXC_TARGET_PAIR_USDT.split('_')[1] # e.g., USDT (assumed to be consistent with IN_TOKEN_ADDRESS)
+TARGET_ASSET_SYMBOL = CEX_TARGET_PAIR_USDT.split('_')[0] # e.g., RATO
+BASE_CURRENCY_SYMBOL = CEX_TARGET_PAIR_USDT.split('_')[1] # e.g., USDT (assumed to be consistent with IN_TOKEN_ADDRESS)
 
 # --- 链上价格获取函数 (链上) ---
 # 返回: price_base_per_target (例如 USDT per RATO)
@@ -82,7 +90,7 @@ def get_dex_price_vs_target_currency(chain_id, in_token_addr, out_token_addr, am
 
             human_in_target = atomic_in_base / (10 ** in_dec)
             human_out_base = atomic_out_target / (10 ** out_dec)
-            if human_out_base == 0: return {"error": f"ERC20输出目标代币为0 ({CHAIN_ID})"}, data, 0 # data 也返回
+            if human_out_base == 0: return {"error": f"DEX输出目标代币为0 ({CHAIN_ID})"}, data, 0 # data 也返回
 
             # 1target = x usdt,这个价格
             return {"price_base_per_target": human_out_base / human_in_target }, data, human_out_base
@@ -94,11 +102,10 @@ def get_dex_price_vs_target_currency(chain_id, in_token_addr, out_token_addr, am
         logger.error(f"链上 ({chain_id})请求错误详情: ", exc_info=True)
         return {"error": f"链上 ({chain_id})请求错误: {e}"}, None, 0
 
-# MEXC 现货 (获取 目标代币/USDT 的 bid 价格)
-# human_out_base: 需要买入大概多少价值的target
-def get_mexc_spot_price_target_usdt_ask(human_out_base):
+# CEX 现货 (获取 目标代币/USDT 的 bid 价格)
+def get_cex_spot_price_target_usdt_ask():
     url = "https://api.mexc.com/api/v3/depth"
-    params = {'symbol': MEXC_TARGET_PAIR_USDT.replace('_', ''), 'limit': 1000} 
+    params = {'symbol': CEX_TARGET_PAIR_USDT.replace('_', ''), 'limit': 1000} 
 
     try:
         r = requests.get(url, params=params, proxies=proxies, timeout=5) # 减少超时
@@ -106,7 +113,7 @@ def get_mexc_spot_price_target_usdt_ask(human_out_base):
         data = r.json()
         if 'asks' in data and data['asks']: # 确保asks存在且不为空
             asks = data['asks']
-            trade_value_remaining = human_out_base # 还需要买入的价值(USDT)
+            trade_value_remaining = BASE_TOKEN_TRADE_AMOUNT # 还需要买入的价值(USDT)
             trade_value = decimal.Decimal('0') # 累计的总价值 (Decimal)
             accumulated_volume = decimal.Decimal('0') # 累计吃单量
 
@@ -127,7 +134,7 @@ def get_mexc_spot_price_target_usdt_ask(human_out_base):
             # print('\n\n')
             
             if accumulated_volume == decimal.Decimal('0'): # 如果一点都没买入去
-                return {"error": f"MEXC订单簿深度不足以买入{human_out_base} {BASE_CURRENCY_SYMBOL}"}, decimal.Decimal('0')
+                return {"error": f"CEX订单簿深度不足以买入{human_out_base} {BASE_CURRENCY_SYMBOL}"}, decimal.Decimal('0')
 
             # 计算平均买入价格
             # buy_price 代表 1 TARGET_ASSET = X USDT
@@ -139,23 +146,23 @@ def get_mexc_spot_price_target_usdt_ask(human_out_base):
                 "price_target_per_base": buy_price
             }, trade_value # 返回的是实际能买入 EXCHANGE_OUT_AMOUNT (或更少,如果深度不足) 所得的 USDT 总额
         else:
-            # logger.warning(f"MEXC现货({MEXC_TARGET_PAIR_USDT}) asks 数据不存在或为空: {data}")
-            return {"error": f"MEXC现货({MEXC_TARGET_PAIR_USDT}) asks 数据不存在或为空"}, decimal.Decimal('0')
+            # logger.warning(f"CEX现货({CEX_TARGET_PAIR_USDT}) asks 数据不存在或为空: {data}")
+            return {"error": f"CEX现货({CEX_TARGET_PAIR_USDT}) asks 数据不存在或为空"}, decimal.Decimal('0')
     except requests.exceptions.RequestException as e:
-        # logger.error(f"MEXC现货({MEXC_TARGET_PAIR_USDT})请求错误: {e}")
-        return {"error": f"MEXC现货({MEXC_TARGET_PAIR_USDT})请求错误: {e}"}, decimal.Decimal('0')
+        # logger.error(f"CEX现货({CEX_TARGET_PAIR_USDT})请求错误: {e}")
+        return {"error": f"CEX现货({CEX_TARGET_PAIR_USDT})请求错误: {e}"}, decimal.Decimal('0')
     except Exception as e:
-        # logger.error(f"MEXC现货({MEXC_TARGET_PAIR_USDT})处理错误: {e}", exc_info=True)
-        return {"error": f"MEXC现货({MEXC_TARGET_PAIR_USDT})处理错误: {e}"}, decimal.Decimal('0')
+        # logger.error(f"CEX现货({CEX_TARGET_PAIR_USDT})处理错误: {e}", exc_info=True)
+        return {"error": f"CEX现货({CEX_TARGET_PAIR_USDT})处理错误: {e}"}, decimal.Decimal('0')
 
 latest_values_for_table = {
     f"dex_price": "N/A",
-    f"cex_price": "N/A", # MEXC price (converted to USDT/TARGET)
+    f"cex_price": "N/A", # CEX price (converted to USDT/TARGET)
     f"diff_dex_vs_cex_percentage": "N/A",
     "profit_value_for_table": "N/A", # 新增:用于表格的利润值
     "dex_error": None, "cex_error": None,
     "last_updated": "N/A",
-    "mexc_pair_usdt_for_display": MEXC_TARGET_PAIR_USDT,
+    "cex_pair_usdt_for_display": CEX_TARGET_PAIR_USDT,
     "target_asset_symbol_for_display": TARGET_ASSET_SYMBOL,
     "base_currency_symbol_for_display": BASE_CURRENCY_SYMBOL
 }
@@ -172,7 +179,7 @@ def calculate_percentage_diff(sell_price, buy_price):
         return rst
     return None
 
-def send_arb_msg(profit_amount, chain_swap_data, human_in_base, human_out_base, dex_price, cex_price):
+def send_arb_msg(pct, chain_swap_data, cex_price, dex_price):
     # chain_swap_data 是从 get_dex_price_vs_target_currency 返回的第二个值
     if not (chain_swap_data and chain_swap_data.get('data') and chain_swap_data['data']):
         logger.error(f"套利消息发送失败:链上交易数据不完整 {chain_swap_data}")
@@ -185,25 +192,44 @@ def send_arb_msg(profit_amount, chain_swap_data, human_in_base, human_out_base,
     to_token_info = router_result['toToken']
 
     in_dec, out_dec = int(from_token_info['decimal']), int(to_token_info['decimal'])
-    # human_in_target 根据实际传入的 IN_AMOUNT_TO_QUERY (trade_value) 确定
+    # human_in_target 根据实际传入的 DEX_QUERRY_AMOUNT (trade_value) 确定
     # human_out_base 是链上swap的实际输出
     atomic_out_target = decimal.Decimal(router_result['toTokenAmount'])
     human_out_base = atomic_out_target / (10 ** out_dec)
 
+    '''
+    def get_public_ip_ipify():
+        """
+        通过 api.ipify.org 获取公网 IP 地址。
+        这个服务返回 JSON 格式数据。
+        """
+        try:
+            response = requests.get('https://api.ipify.org?format=json')
+            response.raise_for_status()
+            data = response.json()
+            return data.get('ip')
+        except requests.exceptions.RequestException as e:
+            print(f"Error fetching IP from api.ipify.org: {e}")
+            return None
+        except ValueError:
+            print("Error decoding JSON from api.ipify.org")
+            return None
+    '''
+
+    ip = 'http://127.0.0.1'
+    url = '/table-data'
+    query_price_endpoint = f'{ip}:{api_endpoint_port}{url}'
+
     arbitrage_data = {
-        "tx": tx, # 预签名交易
-        "profit": str(profit_amount.quantize(decimal.Decimal('0.001'))),
-        "profitLimit": str(PROFIT_LIMIT.quantize(decimal.Decimal('0.001'))),
-        "symbol": MEXC_TARGET_PAIR_USDT,
-        "fromToken": IN_TOKEN_ADDRESS,
-        "fromTokenAmountHuman": str(human_in_base.quantize(decimal.Decimal(f'1e-{in_dec}'))),
-        "fromTokenDecimal": str(in_dec),
-        "toToken": OUT_TOKEN_ADDRESS,
-        "toTokenAmountHuman": str(human_out_base.quantize(decimal.Decimal(f'1e-{out_dec}'))),
-        "toTokenDecimal": str(out_dec),
-        "chainPrice": str(dex_price),
+        "pct": str(pct),
+        "openLimit": str(OPEN_LIMIT.quantize(decimal.Decimal('0.00001'))),
+        "closeLimit": str(CLOSE_LIMIT.quantize(decimal.Decimal('0.00001'))),
         "cexPrice": str(cex_price),
+        "dexPrice": str(dex_price),
+        "symbol": CEX_TARGET_PAIR_USDT,
+        "exchangeBuyValue": str(BASE_TOKEN_TRADE_AMOUNT.quantize(decimal.Decimal(f'1e-4'))), # CEX上期望卖出的目标币数量
         "strategy": STRATEGY,
+        "queryPriceUrl": query_price_endpoint,
     }
 
     logger.info(f"正在提交套利数据到 {ARB_EXECUTOR_URL}, profit {arbitrage_data["profit"]}, profitLimit {arbitrage_data["profitLimit"]}")
@@ -222,21 +248,21 @@ def send_arb_msg(profit_amount, chain_swap_data, human_in_base, human_out_base,
         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
+    global historical_data_points, latest_values_for_table # DEX_QUERRY_AMOUNT
     logger.info(f"数据更新线程 ({TARGET_ASSET_SYMBOL}/{BASE_CURRENCY_SYMBOL})...")
     
-    # local_in_amount_to_query = decimal.Decimal(str(arb["IN_AMOUNT_TO_QUERY"])) # 从配置初始化,后续动态调整
+    # local_in_amount_to_query = decimal.Decimal(str(arb["DEX_QUERRY_AMOUNT"])) # 从配置初始化,后续动态调整
 
     while True:
         fetch_time_full = time.strftime("%Y-%m-%d %H:%M:%S")
         fetch_time_chart = time.strftime("%H:%M:%S")
 
-        # 1. 获取链上价格:卖出 IN_AMOUNT_TO_QUERY 这么多的TARGET去卖成USDT,能卖到多少,以及价格 (USDT/TARGET)
+        # 1. 获取链上价格:卖出 DEX_QUERRY_AMOUNT 这么多的TARGET去卖成USDT,能卖到多少,以及价格 (USDT/TARGET)
         erc20_data, chain_swap_full_response, human_out_base = get_dex_price_vs_target_currency(
             CHAIN_ID,
             IN_TOKEN_ADDRESS,      # TARGET
             OUT_TOKEN_ADDRESS,     # USDT
-            IN_AMOUNT_TO_QUERY,     # 链上卖出代币量
+            DEX_QUERRY_AMOUNT,     # 链上卖出代币量
             IN_TOKEN_DECIMALS,     # 链上卖出代币的精度
             SLIPPAGE,
             USER_WALLET,
@@ -245,32 +271,32 @@ def update_data_for_plotly_and_table():
         dex_price = erc20_data.get("price_base_per_target") # USDT/TARGET
         erc20_err = erc20_data.get("error")
 
-        # 2. MEXC: 获取 price_target_per_base (例如 RATO/USDT)
-        # trade_value_usdt 是指如果以 EXCHANGE_OUT_AMOUNT 的目标代币在MEXC上砸盘卖出,能获得的USDT估值
-        mexc_data, trade_value_usdt = get_mexc_spot_price_target_usdt_ask(human_out_base)
-        cex_price = mexc_data.get("price_target_per_base") # TARGET/USDT
-        mexc_err = mexc_data.get("error")
+        # 2. CEX: 获取 price_target_per_base (例如 RATO/USDT)
+        # trade_value_usdt 是指如果以 EXCHANGE_OUT_AMOUNT 的目标代币在CEX上砸盘卖出,能获得的USDT估值
+        cex_data, trade_value_usdt = get_cex_spot_price_target_usdt_ask()
+        cex_price = cex_data.get("price_target_per_base") # TARGET/USDT
+        cex_err = cex_data.get("error")
 
         # 3. 计算百分比差异
-        # diff = (链上卖价 - MEXC买价) / MEXC买价
-        diff_erc20_vs_mexc_pct = calculate_percentage_diff(
+        # diff = (链上卖价 - CEX买价) / CEX买价
+        diff_erc20_vs_cex_pct = calculate_percentage_diff(
             dex_price,                   # 链上卖价 (USDT/TARGET)
-            cex_price,                 # MEXC买价 (USDT/TARGET)
+            cex_price,                 # CEX买价 (USDT/TARGET)
         )
 
         # 4. 计算实际利润额 (以USDT计价)
         # 简化:利润百分比 * 投入的USDT金额
         actual_profit_usdt = None
-        if diff_erc20_vs_mexc_pct is not None and dex_price is not None and dex_price > 0:
+        if diff_erc20_vs_cex_pct is not None and dex_price is not None and dex_price > 0:
             # 基于百分比和投入金额
-            actual_profit_usdt = diff_erc20_vs_mexc_pct * human_out_base
+            actual_profit_usdt = diff_erc20_vs_cex_pct * human_out_base
 
         # 5. 满足利润条件,发送套利消息, PROFIT_LIMIT + 3的3是提前計算的成本,否則一直提交
         global mode
-        if actual_profit_usdt is not None and actual_profit_usdt > PROFIT_LIMIT + 3 and mode == 'trade':
+        if diff_erc20_vs_cex_pct is not None and diff_erc20_vs_cex_pct > OPEN_LIMIT and mode == 'trade':
             if chain_swap_full_response: # 确保有完整的链上数据
-                human_in_base = IN_AMOUNT_TO_QUERY
-                send_arb_msg(actual_profit_usdt, chain_swap_full_response, human_in_base, human_out_base, dex_price, cex_price)
+                human_in_base = DEX_QUERRY_AMOUNT
+                send_arb_msg(diff_erc20_vs_cex_pct, chain_swap_full_response, cex_price, dex_price)
             else:
                 logger.warning("利润满足但链上数据不完整,无法发送套利消息。")
 
@@ -278,7 +304,7 @@ def update_data_for_plotly_and_table():
             "time": fetch_time_chart,
             "dex_price": float(dex_price) if dex_price else None,
             "cex_price": float(cex_price) if cex_price else None,
-            "diff_erc20_vs_mexc": float(diff_erc20_vs_mexc_pct) if diff_erc20_vs_mexc_pct is not None else None,
+            "diff_erc20_vs_cex": float(diff_erc20_vs_cex_pct) if diff_erc20_vs_cex_pct is not None else None,
             "profit_value": float(actual_profit_usdt) if actual_profit_usdt is not None else None, # 新增:用于图表的实际利润额
         }
 
@@ -286,16 +312,16 @@ def update_data_for_plotly_and_table():
             historical_data_points.append(current_point)
             latest_values_for_table["dex_price"] = f"{dex_price:.8f}" if dex_price else "N/A"
             latest_values_for_table["cex_price"] = f"{cex_price:.8f}" if cex_price else "N/A"
-            latest_values_for_table["diff_dex_vs_cex_percentage"] = f"{diff_erc20_vs_mexc_pct:+.4%}" if diff_erc20_vs_mexc_pct is not None else "N/A" # 显示为百分比
+            latest_values_for_table["diff_dex_vs_cex_percentage"] = f"{diff_erc20_vs_cex_pct:+.4%}" if diff_erc20_vs_cex_pct is not None else "N/A" # 显示为百分比
             latest_values_for_table["profit_value_for_table"] = f"{actual_profit_usdt:.2f} {BASE_CURRENCY_SYMBOL}" if actual_profit_usdt is not None else "N/A" # 新增
             latest_values_for_table["dex_error"] = erc20_err
-            latest_values_for_table["cex_error"] = mexc_err
+            latest_values_for_table["cex_error"] = cex_err
             latest_values_for_table["last_updated"] = fetch_time_full
             latest_values_for_table["in_amount_for_query_display"] = f"{human_out_base:.2f} {BASE_CURRENCY_SYMBOL}" if human_out_base > 0 else "N/A"
 
-        # logger.info(f"{fetch_time_chart} Price Query: Chain Input {human_out_base:.2f} {BASE_CURRENCY_SYMBOL} | OKX Price: {dex_price_display} | MEXC Price: {cex_price_display} | Diff: {diff_display} | Profit: {profit_display}")
-        if erc20_err or mexc_err :
-             logger.warning(f"{fetch_time_chart} Errors: erc20:{erc20_err}, MEXC:{mexc_err}")
+        # logger.info(f"{fetch_time_chart} Price Query: Chain Input {human_out_base:.2f} {BASE_CURRENCY_SYMBOL} | OKX Price: {dex_price_display} | CEX Price: {cex_price_display} | Diff: {diff_display} | Profit: {profit_display}")
+        if erc20_err or cex_err :
+             logger.warning(f"{fetch_time_chart} Errors: erc20:{erc20_err}, CEX:{cex_err}")
 
         time.sleep(REFRESH_INTERVAL_SECONDS)
 
@@ -304,7 +330,7 @@ def index_plotly():
     return render_template('index_plotly_dynamic_ok.html',
                            target_asset=TARGET_ASSET_SYMBOL,
                            base_asset=BASE_CURRENCY_SYMBOL,
-                           mexc_pair_usdt=MEXC_TARGET_PAIR_USDT,
+                           cex_pair_usdt=CEX_TARGET_PAIR_USDT,
                            refresh_interval_ms=REFRESH_INTERVAL_SECONDS * 1000)
 
 @app.route('/table-data')
@@ -347,9 +373,9 @@ def get_plotly_chart_data():
                                         hovertemplate=f'<b>链上价</b><br>价格: %{{y:.8f}} {display_base_asset}<extra></extra>',
                                         connectgaps=True)) # 处理None值不画线
         fig_prices.add_trace(go.Scatter(x=times, y=[p['cex_price'] for p in points], mode='lines',
-                                        name=f'MEXC价 ({display_base_asset}/{display_target_asset})',
+                                        name=f'CEX价 ({display_base_asset}/{display_target_asset})',
                                         line=dict(color='rgb(255, 99, 132)', dash='dash'),
-                                        hovertemplate=f'<b>MEXC价</b><br>价格: %{{y:.8f}} {display_base_asset}<extra></extra>',
+                                        hovertemplate=f'<b>CEX价</b><br>价格: %{{y:.8f}} {display_base_asset}<extra></extra>',
                                         connectgaps=True))
         fig_prices.update_layout(title_text=f'{display_base_asset}/{display_target_asset} 价格历史',
                                  xaxis=common_xaxis_config.copy(),
@@ -361,9 +387,9 @@ def get_plotly_chart_data():
         # Percentage Difference Chart
         fig_diffs = go.Figure()
         fig_diffs.add_trace(
-            go.Scatter(x=times, y=[p['diff_erc20_vs_mexc'] for p in points], mode='lines', name=f'价差百分比 (MEXC卖价 vs 链上买价)',
+            go.Scatter(x=times, y=[p['diff_erc20_vs_cex'] for p in points], mode='lines', name=f'价差百分比 (CEX卖价 vs 链上买价)',
                        line=dict(color='rgb(255, 159, 64)'),
-                       hovertemplate=f'<b>(MEXC卖价-链上买价)/链上买价</b><br>百分比: %{{y:+.4%}}<extra></extra>', # 显示为百分比
+                       hovertemplate=f'<b>(CEX卖价-链上买价)/链上买价</b><br>百分比: %{{y:+.4%}}<extra></extra>', # 显示为百分比
                        connectgaps=True))
         fig_diffs.update_layout(title_text=f'价差百分比历史曲线',
                                 xaxis=common_xaxis_config.copy(),
@@ -412,18 +438,18 @@ if __name__ == "__main__":
 
         logger.info("应用启动...")
         logger.info(f"目标资产: {TARGET_ASSET_SYMBOL}, 计价货币: {BASE_CURRENCY_SYMBOL}, 获取到的Decimal: {IN_TOKEN_DECIMALS}")
-        # IN_AMOUNT_TO_QUERY 会动态变化,初始值从配置读取,但循环中会基于MEXC的trade_value更新
-        # logger.info(f"链上查询初始金额: {arb['IN_AMOUNT_TO_QUERY']} {BASE_CURRENCY_SYMBOL} -> {TARGET_ASSET_SYMBOL}")
-        logger.info(f"链上期望卖出量 (用于计算深度和价值): {IN_AMOUNT_TO_QUERY} {TARGET_ASSET_SYMBOL}")
-        logger.info(f"利润阈值: {PROFIT_LIMIT} {BASE_CURRENCY_SYMBOL}")
-        logger.info(f"MEXC现货交易对: {MEXC_TARGET_PAIR_USDT}")
+        # DEX_QUERRY_AMOUNT 会动态变化,初始值从配置读取,但循环中会基于CEX的trade_value更新
+        # logger.info(f"链上查询初始金额: {arb['DEX_QUERRY_AMOUNT']} {BASE_CURRENCY_SYMBOL} -> {TARGET_ASSET_SYMBOL}")
+        logger.info(f"链上期望卖出量 (用于计算深度和价值): {DEX_QUERRY_AMOUNT} {TARGET_ASSET_SYMBOL}")
+        logger.info(f"开仓阈值 > {OPEN_LIMIT}, 平仓阈值 > {CLOSE_LIMIT}")
+        logger.info(f"CEX现货交易对: {CEX_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
-        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)
+        api_endpoint_port = arb.get("PORT", 5001) # 从配置获取端口,如果没有则默认5001
+        logger.info(f"Flask 服务将在 http://0.0.0.0:{api_endpoint_port} 上运行 (刷新间隔: {REFRESH_INTERVAL_SECONDS}s)")
+        app.run(debug=False, host='0.0.0.0', port=api_endpoint_port, use_reloader=False)
 
     except SystemExit: # argparse 在参数错误时会引发 SystemExit
         # parser.print_help() # argparse 默认会打印帮助信息

+ 2 - 1
toto.readme

@@ -22,8 +22,9 @@
 
 2025-08-05
 [-] reject不要放进日志去了
+[-] 优化前端monitor,用表格形式展示,总利润加一下进去
 
 待定
-[ ] 优化前端monitor,用表格形式展示,总利润加一下进去
+[ ] 平仓逻辑
 [ ] 日志细化
 [ ] 价差变动了0.0005了才重新挂单