|
|
@@ -1,396 +0,0 @@
|
|
|
-import requests
|
|
|
-import decimal
|
|
|
-import time
|
|
|
-import threading
|
|
|
-import json
|
|
|
-from flask import Flask, render_template, jsonify
|
|
|
-from collections import deque
|
|
|
-import logging
|
|
|
-import ok_chain_client # 假设这个库存在且配置正确
|
|
|
-import pprint
|
|
|
-
|
|
|
-import plotly.graph_objects as go
|
|
|
-from plotly.utils import PlotlyJSONEncoder
|
|
|
-import argparse
|
|
|
-
|
|
|
-logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
-
|
|
|
-ok_chain_client.api_config = {
|
|
|
- "api_key": 'eb5ebffb-f64e-47d6-a4d8-0e6dd9e278ba', # 请替换为您的真实 API Key
|
|
|
- "secret_key": '9D141982C5952AC4793103D85F67DBBC', # 请替换为您的真实 Secret Key
|
|
|
- "passphrase": 'Qwe123123.', # 请替换为您的真实 Passphrase
|
|
|
-}
|
|
|
-
|
|
|
-# --- 配置 arb_executor.py 的 HTTP 地址和端口 ---
|
|
|
-ARB_EXECUTOR_URL = "http://localhost:5002/submit_process"
|
|
|
-
|
|
|
-# --- 配置部分 ---
|
|
|
-IN_AMOUNT_TO_QUERY = decimal.Decimal('350')
|
|
|
-EXCHANGE_OUT_AMOUNT = decimal.Decimal('13000')
|
|
|
-PROFIT_LIMIT = 0.04 # 触发交易的利润阈值
|
|
|
-IN_TOKEN_ADDRESS = '0xdAC17F958D2ee523a2206206994597C13D831ec7' # USDT on Ethereum
|
|
|
-IN_TOKEN_DECIMALS = 6
|
|
|
-OUT_TOKEN_ADDRESS = '0x26E550AC11B26f78A04489d5F20f24E3559f7Dd9' # out on Ethereum
|
|
|
-USER_WALLET = '0xb1f33026Db86a86372493a3B124d7123e9045Bb4'
|
|
|
-USER_EXCHANGE_WALLET = '0xc71835a042F4d870B0F4296cc89cAeb921a9f3DA'
|
|
|
-SLIPPAGE = 1
|
|
|
-MEXC_TARGET_PAIR_USDT = 'KEKIUS_USDT' # MEXC 现货交易对
|
|
|
-CHAIN_ID = 1
|
|
|
-
|
|
|
-proxies = None # {'http': 'http://proxy_url:port', 'https': 'http://proxy_url:port'}
|
|
|
-decimal.getcontext().prec = 36
|
|
|
-
|
|
|
-mode = None
|
|
|
-oo_price_usdt_per_target = None
|
|
|
-
|
|
|
-app = Flask(__name__)
|
|
|
-log = logging.getLogger('werkzeug')
|
|
|
-log.setLevel(logging.ERROR)
|
|
|
-MAX_HISTORY_POINTS_PLOTLY = 21600
|
|
|
-REFRESH_INTERVAL_SECONDS = 1 # 稍微增加间隔以减少API调用频率
|
|
|
-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)
|
|
|
-
|
|
|
-# --- 链上价格获取函数 (Okx) ---
|
|
|
-# 返回: price_base_per_target (例如 USDT per RATO)
|
|
|
-def get_chain_price_vs_target_currency(chain_id, in_token_addr, out_token_addr, amount, in_token_decimals, slippage, user_wallet_addr, user_exchange_wallet_addr):
|
|
|
- try:
|
|
|
- in_token_amount = amount * (10 ** in_token_decimals)
|
|
|
- data = ok_chain_client.swap(chain_id, in_token_amount, in_token_addr, out_token_addr, slippage, user_wallet_addr, user_exchange_wallet_addr)
|
|
|
-
|
|
|
- if data.get('code') == '0' and data.get('data'):
|
|
|
- d = data['data'][0]
|
|
|
- router_result = d['routerResult']
|
|
|
- in_dec, out_dec = int(router_result['fromToken']['decimal']), int(router_result['toToken']['decimal'])
|
|
|
- atomic_in_base, atomic_out_target = decimal.Decimal(router_result['fromTokenAmount']), decimal.Decimal(router_result['toTokenAmount'])
|
|
|
-
|
|
|
- human_in_base = atomic_in_base / (10 ** in_dec)
|
|
|
- human_out_target = atomic_out_target / (10 ** out_dec)
|
|
|
- if human_out_target == 0: return {"error": f"OO输出目标代币为0 ({CHAIN_ID})"}
|
|
|
- return {"price_base_per_target": human_in_base / human_out_target}, data
|
|
|
- else:
|
|
|
- pprint.pprint(data)
|
|
|
- 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:
|
|
|
- return {"error": f"Okx ({chain_id})请求错误: {e}"}, None
|
|
|
-
|
|
|
-# MEXC 现货 (获取 目标代币/USDT 的 bid 价格)
|
|
|
-# 返回: price_target_per_usdt_bid1 (例如 RATO per USDT)
|
|
|
-def get_mexc_spot_price_target_usdt_bid(pair_symbol):
|
|
|
- url = "https://api.mexc.com/api/v3/depth"
|
|
|
- params = {'symbol': pair_symbol.replace('_', ''), 'limit': 1000}
|
|
|
- try:
|
|
|
- r = requests.get(url, params=params, proxies=proxies, timeout=10)
|
|
|
- r.raise_for_status()
|
|
|
- data = r.json()
|
|
|
- if 'bids' in data:
|
|
|
- bids = data['bids']
|
|
|
- trade_volume_remaining = EXCHANGE_OUT_AMOUNT # 还需要卖出的数量
|
|
|
- trade_value = decimal.Decimal('0') # 累计的总价值
|
|
|
-
|
|
|
- for orderbook in bids:
|
|
|
- price = decimal.Decimal(orderbook[0])
|
|
|
- volume = decimal.Decimal(orderbook[1])
|
|
|
-
|
|
|
- # 当前买单的数量足以吃下所有剩余的待卖数量
|
|
|
- if volume >= trade_volume_remaining:
|
|
|
- trade_value = trade_value + price * trade_volume_remaining
|
|
|
- trade_volume_remaining = decimal.Decimal('0') # 已经全部卖出
|
|
|
- break # 卖单完成,退出循环
|
|
|
- # 当前买单的数量不足以吃下所有剩余的待卖数量
|
|
|
- else:
|
|
|
- trade_value = trade_value + price * volume
|
|
|
- trade_volume_remaining = trade_volume_remaining - volume # 还需要卖出剩余的数量
|
|
|
-
|
|
|
- # 如果循环结束但 trade_volume_remaining 仍然大于 0,
|
|
|
- # 说明市场上的买单不足以完全吃下你的卖单,实际情况是卖不完。
|
|
|
- # 在计算平均成本价的语境下,通常认为你能卖出的量是到你遍历的最后一个买单的数量。
|
|
|
- # 如果要严格按照你能卖出的量来算,需要考虑这个情况。
|
|
|
- # 但根据你的代码意图(计算砸下去的成本价),假设你能卖出 EXCHANGE_OUT_AMOUNT
|
|
|
- # 到 bids 中最后一个能吃下这部分量的价格。
|
|
|
- if EXCHANGE_OUT_AMOUNT == decimal.Decimal('0'):
|
|
|
- sell_price = decimal.Decimal('0') # 避免除以零
|
|
|
- else:
|
|
|
- sell_price = trade_value / EXCHANGE_OUT_AMOUNT
|
|
|
-
|
|
|
- sell_price = sell_price.quantize(decimal.Decimal('1e-10'), rounding=decimal.ROUND_DOWN)
|
|
|
-
|
|
|
- return {
|
|
|
- "price_target_per_usdt_bid1": sell_price
|
|
|
- }, trade_value
|
|
|
- else:
|
|
|
- return {"error": f"MEXC现货({pair_symbol}) bids"}, 0
|
|
|
- except Exception as e:
|
|
|
- return {"error": f"MEXC现货({pair_symbol})请求错误: {e}"}, 0
|
|
|
-
|
|
|
-latest_values_for_table = {
|
|
|
- f"oo_price_usdt_per_target": "N/A",
|
|
|
- f"mexc_price_usdt_per_target_bid1": "N/A", # MEXC Bid1 (converted to USDT/TARGET)
|
|
|
- f"diff_oo_vs_mexc_bid1_percentage": "N/A",
|
|
|
- "oo_error": None, "mexc_error": None,
|
|
|
- "last_updated": "N/A",
|
|
|
- "mexc_pair_usdt_for_display": MEXC_TARGET_PAIR_USDT,
|
|
|
- "target_asset_symbol_for_display": TARGET_ASSET_SYMBOL,
|
|
|
- "base_currency_symbol_for_display": BASE_CURRENCY_SYMBOL # Now this is USDT
|
|
|
-}
|
|
|
-data_lock = threading.Lock()
|
|
|
-
|
|
|
-def calculate_percentage_diff(price_a, price_b):
|
|
|
- if price_a is not None and price_b is not None and isinstance(price_a, decimal.Decimal) and isinstance(price_b, decimal.Decimal) and price_b != 0:
|
|
|
- rst = (price_a - price_b) / price_b
|
|
|
- rst = rst.quantize(decimal.Decimal('1e-4'), rounding=decimal.ROUND_DOWN)
|
|
|
- return rst
|
|
|
- return None
|
|
|
-
|
|
|
-def send_arb_msg(profit, data):
|
|
|
- d = data['data'][0]
|
|
|
- tx = d['tx']
|
|
|
- router_result = d['routerResult']
|
|
|
- in_dec, out_dec = int(router_result['fromToken']['decimal']), int(router_result['toToken']['decimal'])
|
|
|
- atomic_in_base, atomic_out_target = decimal.Decimal(router_result['fromTokenAmount']), decimal.Decimal(router_result['toTokenAmount'])
|
|
|
- human_in_base = atomic_in_base / (10 ** in_dec)
|
|
|
- human_out_target = atomic_out_target / (10 ** out_dec)
|
|
|
-
|
|
|
- """
|
|
|
- 向 arb_executor 服务提交套利处理请求。
|
|
|
- """
|
|
|
- arbitrage_data = {
|
|
|
- "tx": tx,
|
|
|
- "profit": str(profit),
|
|
|
- "profitLimit": str(PROFIT_LIMIT),
|
|
|
- "symbol": MEXC_TARGET_PAIR_USDT,
|
|
|
- "fromToken": IN_TOKEN_ADDRESS,
|
|
|
- "fromTokenAmountHuman": str(human_in_base),
|
|
|
- "fromTokenDecimal": IN_TOKEN_DECIMALS,
|
|
|
- "toToken": OUT_TOKEN_ADDRESS,
|
|
|
- "toTokenAmountHuman": str(human_out_target),
|
|
|
- "exchangeOutAmount": str(EXCHANGE_OUT_AMOUNT)
|
|
|
- }
|
|
|
-
|
|
|
- logging.info(f"正在提交套利数据到 {ARB_EXECUTOR_URL}")
|
|
|
-
|
|
|
- try:
|
|
|
- # 发送 POST 请求
|
|
|
- response = requests.post(ARB_EXECUTOR_URL, json=arbitrage_data)
|
|
|
-
|
|
|
- # 检查响应状态码
|
|
|
- if response.status_code == 201:
|
|
|
- logging.info("\n请求成功! 套利流程已启动。")
|
|
|
- elif response.status_code == 200:
|
|
|
- logging.info("\n请求接收成功,但未达到利润阈值,未启动套利流程。")
|
|
|
- elif response.status_code == 400:
|
|
|
- logging.info("\n请求失败! 无效的请求数据。")
|
|
|
- else:
|
|
|
- logging.info(f"\n请求失败! 状态码: {response.status_code}")
|
|
|
-
|
|
|
- # 打印响应体
|
|
|
- logging.info(response.text)
|
|
|
-
|
|
|
- except requests.exceptions.ConnectionError as e:
|
|
|
- logging.info(f"\n连接错误: 无法连接到 {ARB_EXECUTOR_URL}。请确保 arb_executor.py 正在运行。")
|
|
|
- logging.info(f"错误详情: {e}")
|
|
|
- except Exception as e:
|
|
|
- logging.info(f"\n发送请求时发生未知错误: {e}")
|
|
|
-
|
|
|
- logging.info(f"套利消息已发送, {profit}, {human_in_base}, {human_out_target}")
|
|
|
-
|
|
|
-def update_data_for_plotly_and_table():
|
|
|
- global historical_data_points, latest_values_for_table
|
|
|
- logging.info(f"数据更新线程 ({TARGET_ASSET_SYMBOL}/{BASE_CURRENCY_SYMBOL})...")
|
|
|
- while True:
|
|
|
- fetch_time_full = time.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
- fetch_time_chart = time.strftime("%H:%M:%S")
|
|
|
-
|
|
|
- # 1. MEXC: price_target_per_usdt_bid1 (e.g., RATO / USDT)
|
|
|
- mexc_data, trade_value = get_mexc_spot_price_target_usdt_bid(MEXC_TARGET_PAIR_USDT)
|
|
|
- mexc_price_target_per_usdt_bid1 = mexc_data.get("price_target_per_usdt_bid1") # TARGET/USDT
|
|
|
- mexc_err = mexc_data.get("error")
|
|
|
-
|
|
|
- if trade_value == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- # Convert MEXC price to USDT / TARGET for comparison
|
|
|
- mexc_price_usdt_per_target_bid1 = None
|
|
|
- if mexc_price_target_per_usdt_bid1 is not None and mexc_price_target_per_usdt_bid1 > 0:
|
|
|
- mexc_price_usdt_per_target_bid1 = mexc_price_target_per_usdt_bid1 # TARGET / USDT
|
|
|
- elif not mexc_err and mexc_price_target_per_usdt_bid1 is not None : # Price is 0 or less, but not API error
|
|
|
- mexc_err = mexc_err or "MEXC价格为0或无效"
|
|
|
-
|
|
|
- # 2. 计算链上价格,用交易所的大致卖出价值购入
|
|
|
- IN_AMOUNT_TO_QUERY = trade_value * decimal.Decimal(1 - PROFIT_LIMIT)
|
|
|
- IN_AMOUNT_TO_QUERY = IN_AMOUNT_TO_QUERY.quantize(decimal.Decimal('1'), rounding=decimal.ROUND_DOWN)
|
|
|
-
|
|
|
- oo_data, data = get_chain_price_vs_target_currency(
|
|
|
- CHAIN_ID,
|
|
|
- IN_TOKEN_ADDRESS,
|
|
|
- OUT_TOKEN_ADDRESS,
|
|
|
- IN_AMOUNT_TO_QUERY,
|
|
|
- IN_TOKEN_DECIMALS,
|
|
|
- SLIPPAGE,
|
|
|
- USER_WALLET,
|
|
|
- USER_EXCHANGE_WALLET
|
|
|
- )
|
|
|
- oo_price_usdt_per_target = oo_data.get("price_base_per_target") # USDT/TARGET
|
|
|
- oo_err = oo_data.get("error")
|
|
|
-
|
|
|
- # logging.info(f"交易所卖出{EXCHANGE_OUT_AMOUNT}, 链上大约需要花{IN_AMOUNT_TO_QUERY}去对冲。")
|
|
|
-
|
|
|
- # 3. Calculate Difference
|
|
|
- diff_oo_vs_mexc_bid1_pct = calculate_percentage_diff(
|
|
|
- mexc_price_usdt_per_target_bid1,
|
|
|
- oo_price_usdt_per_target
|
|
|
- )
|
|
|
-
|
|
|
- # 4. 满足利润条件就发送套利消息
|
|
|
- global mode
|
|
|
- if diff_oo_vs_mexc_bid1_pct is not None and diff_oo_vs_mexc_bid1_pct > PROFIT_LIMIT and mode == 'trade':
|
|
|
- send_arb_msg(diff_oo_vs_mexc_bid1_pct, data)
|
|
|
-
|
|
|
- current_point = {
|
|
|
- "time": fetch_time_chart,
|
|
|
- "oo_price_usdt_per_target": float(oo_price_usdt_per_target) if oo_price_usdt_per_target else None,
|
|
|
- "mexc_price_usdt_per_target_bid1": float(mexc_price_usdt_per_target_bid1) if mexc_price_usdt_per_target_bid1 else None,
|
|
|
- "diff_oo_vs_mexc_bid1": float(diff_oo_vs_mexc_bid1_pct) if diff_oo_vs_mexc_bid1_pct is not None else None,
|
|
|
- }
|
|
|
-
|
|
|
- with data_lock:
|
|
|
- historical_data_points.append(current_point)
|
|
|
- latest_values_for_table["oo_price_usdt_per_target"] = str(oo_price_usdt_per_target) if oo_price_usdt_per_target else "N/A"
|
|
|
- latest_values_for_table["mexc_price_usdt_per_target_bid1"] = str(mexc_price_usdt_per_target_bid1) if mexc_price_usdt_per_target_bid1 else "N/A"
|
|
|
- latest_values_for_table["diff_oo_vs_mexc_bid1_percentage"] = f"{diff_oo_vs_mexc_bid1_pct:+.4f}" if diff_oo_vs_mexc_bid1_pct is not None else "N/A"
|
|
|
- latest_values_for_table["oo_error"] = oo_err
|
|
|
- latest_values_for_table["mexc_error"] = mexc_err
|
|
|
- latest_values_for_table["last_updated"] = fetch_time_full
|
|
|
-
|
|
|
- ok_oo = 'OK' if oo_price_usdt_per_target else 'F'
|
|
|
- ok_mexc_bid = 'OK' if mexc_price_usdt_per_target_bid1 else 'F' # Check converted price
|
|
|
- # logging.info(f"{fetch_time_chart} Fetch | OO:{ok_oo} | MEXC Bid1 ({TARGET_ASSET_SYMBOL}/USDT):{ok_mexc_bid}")
|
|
|
- time.sleep(REFRESH_INTERVAL_SECONDS)
|
|
|
-
|
|
|
-@app.route('/')
|
|
|
-def index_plotly():
|
|
|
- return render_template('index_plotly_dynamic_ok.html',
|
|
|
- target_asset=TARGET_ASSET_SYMBOL,
|
|
|
- base_asset=BASE_CURRENCY_SYMBOL, # Should be USDT
|
|
|
- mexc_pair_usdt=MEXC_TARGET_PAIR_USDT,
|
|
|
- refresh_interval_ms=REFRESH_INTERVAL_SECONDS * 1000)
|
|
|
-
|
|
|
-@app.route('/table-data')
|
|
|
-def get_table_data():
|
|
|
- with data_lock:
|
|
|
- return jsonify(latest_values_for_table)
|
|
|
-
|
|
|
-@app.route('/plotly-chart-data')
|
|
|
-def get_plotly_chart_data():
|
|
|
- with data_lock:
|
|
|
- points = list(historical_data_points)
|
|
|
- if not points:
|
|
|
- fig = go.Figure()
|
|
|
- fig.update_layout(title_text="暂无数据")
|
|
|
- empty_json = json.loads(json.dumps(fig, cls=PlotlyJSONEncoder))
|
|
|
- return jsonify({"price_chart": empty_json, "diff_chart": empty_json})
|
|
|
-
|
|
|
- times = [p['time'] for p in points]
|
|
|
- # These display symbols are now taken from the latest_values_for_table for consistency
|
|
|
- display_target_asset = latest_values_for_table["target_asset_symbol_for_display"]
|
|
|
- display_base_asset = latest_values_for_table["base_currency_symbol_for_display"] # This is USDT
|
|
|
- display_mexc_pair_usdt = latest_values_for_table["mexc_pair_usdt_for_display"]
|
|
|
-
|
|
|
- common_xaxis_config = dict(title='时间')
|
|
|
- common_legend_config = dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1)
|
|
|
- if len(times) > 1:
|
|
|
- common_xaxis_config['range'] = [times[0], times[-1]]
|
|
|
- else:
|
|
|
- common_xaxis_config['autorange'] = True
|
|
|
-
|
|
|
- # Price Chart: OO (USDT/TARGET) vs MEXC_converted (USDT/TARGET)
|
|
|
- fig_prices = go.Figure()
|
|
|
- fig_prices.add_trace(go.Scatter(x=times, y=[p['oo_price_usdt_per_target'] for p in points], mode='lines',
|
|
|
- name=f'Okx ({display_base_asset}/{display_target_asset})',
|
|
|
- line=dict(color='rgb(75, 192, 192)'),
|
|
|
- hovertemplate=f'<b>OO</b><br>价格: %{{y:.8f}} {display_base_asset}<extra></extra>'))
|
|
|
- fig_prices.add_trace(go.Scatter(x=times, y=[p['mexc_price_usdt_per_target_bid1'] for p in points], mode='lines',
|
|
|
- name=f'MEXC Bid1 ({display_base_asset}/{display_target_asset})',
|
|
|
- line=dict(color='rgb(255, 99, 132)', dash='dash'),
|
|
|
- hovertemplate=f'<b>MEXC Bid1</b><br>价格: %{{y:.8f}} {display_base_asset}<extra></extra>'))
|
|
|
-
|
|
|
- fig_prices.update_layout(title_text=f'{display_base_asset}/{display_target_asset} 价格历史', # e.g. USDT/RATO Price History
|
|
|
- xaxis=common_xaxis_config.copy(),
|
|
|
- yaxis_title=f'价格 (1 {display_target_asset} = X {display_base_asset})',
|
|
|
- legend_title_text='平台',
|
|
|
- legend=common_legend_config.copy(), hovermode='x unified',
|
|
|
- margin=dict(l=70, r=30, t=80, b=50))
|
|
|
-
|
|
|
- # Difference Chart
|
|
|
- fig_diffs = go.Figure()
|
|
|
- fig_diffs.add_trace(
|
|
|
- go.Scatter(x=times, y=[p['diff_oo_vs_mexc_bid1'] for p in points], mode='lines', name=f'OO vs MEXC Bid1',
|
|
|
- line=dict(color='rgb(255, 159, 64)'),
|
|
|
- hovertemplate=f'<b>OO vs MEXC Bid1</b><br>利润: %{{y:+.4f}}<extra></extra>'))
|
|
|
-
|
|
|
- fig_diffs.update_layout(title_text=f'{display_base_asset}/{display_target_asset} 利润百分比历史',
|
|
|
- xaxis=common_xaxis_config.copy(),
|
|
|
- yaxis_title='利润', legend_title_text='对比', legend=common_legend_config.copy(),
|
|
|
- yaxis_zeroline=True, hovermode='x unified', margin=dict(l=70, r=30, t=80, b=50))
|
|
|
-
|
|
|
- combined_figure_data = {"price_chart": json.loads(json.dumps(fig_prices, cls=PlotlyJSONEncoder)),
|
|
|
- "diff_chart": json.loads(json.dumps(fig_diffs, cls=PlotlyJSONEncoder))}
|
|
|
- return jsonify(combined_figure_data)
|
|
|
-
|
|
|
-if __name__ == "__main__":
|
|
|
- # 1. 创建 ArgumentParser 对象
|
|
|
- parser = argparse.ArgumentParser(
|
|
|
- description='一个示例脚本,演示如何读取命令行参数 "mode"。'
|
|
|
- )
|
|
|
-
|
|
|
- # 2. 添加命令行参数
|
|
|
- # parser.add_argument('mode', help='指定脚本的运行模式 (例如: dev, prod)') # 位置参数 (必须提供)
|
|
|
- # 另一种更灵活的方式:使用可选参数,并标记为 required=True
|
|
|
- parser.add_argument('--mode',
|
|
|
- required=True, # 设置为 True 表示此参数必须提供
|
|
|
- help='指定脚本的运行模式 (例如: dev, prod)')
|
|
|
- # 3. 解析命令行参数
|
|
|
- try:
|
|
|
- args = parser.parse_args()
|
|
|
-
|
|
|
- # 4. 获取参数值
|
|
|
- mode = args.mode
|
|
|
- logging.info(f"脚本运行模式为: {mode}")
|
|
|
-
|
|
|
- # 这里可以根据 mode 的值执行不同的逻辑
|
|
|
- if mode == 'trade':
|
|
|
- logging.info("正在以交易模式运行...")
|
|
|
- # ... 开发模式特有的代码 ...
|
|
|
- elif mode == 'view':
|
|
|
- logging.info("正在以观察模式运行...")
|
|
|
- # ... 生产模式特有的代码 ...
|
|
|
- else:
|
|
|
- logging.info(f"警告: 未知的运行模式 '{mode}'.")
|
|
|
-
|
|
|
- logging.info("应用启动...")
|
|
|
- logging.info(f"目标资产: {TARGET_ASSET_SYMBOL}")
|
|
|
- logging.info(f"计价货币 (Okx输入 / MEXC交易对基础): {BASE_CURRENCY_SYMBOL}") # Should be USDT
|
|
|
- logging.info(f"链上查询: {IN_AMOUNT_TO_QUERY} {BASE_CURRENCY_SYMBOL} -> {TARGET_ASSET_SYMBOL} (ETH chain, using {IN_TOKEN_ADDRESS[-6:]} for {BASE_CURRENCY_SYMBOL} and {OUT_TOKEN_ADDRESS[-6:]} for {TARGET_ASSET_SYMBOL})")
|
|
|
- logging.info(f"MEXC 现货交易对: {MEXC_TARGET_PAIR_USDT} (价格将被转换为 {TARGET_ASSET_SYMBOL}/{BASE_CURRENCY_SYMBOL} 进行比较)")
|
|
|
- data_thread = threading.Thread(target=update_data_for_plotly_and_table, daemon=True)
|
|
|
- data_thread.start()
|
|
|
- logging.info(f"Flask 服务将在 http://0.0.0.0:5000 上运行 (刷新间隔: {REFRESH_INTERVAL_SECONDS}s)")
|
|
|
- app.run(debug=False, host='0.0.0.0', port=5000, use_reloader=False)
|
|
|
- except argparse.ArgumentError as e:
|
|
|
- # 这里捕获 argparse 解析参数时发生的错误,包括 required 参数未提供
|
|
|
- logging.info(f"参数错误: {e}")
|
|
|
- # argparse 默认会在 required 参数未提供时打印错误消息并退出,
|
|
|
- # 但这里我们特意捕获并打印,可以根据需要进行更复杂的处理
|
|
|
- parser.print_help() # 打印帮助信息
|
|
|
-
|
|
|
- except SystemExit:
|
|
|
- # argparse 在 required 参数未提供时会触发 SystemExit 异常并退出程序
|
|
|
- # 如果你想在程序退出前做些什么,可以捕获这个异常
|
|
|
- logging.info("\n脚本由于参数错误而退出。")
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- # 捕获其他可能的异常
|
|
|
- logging.info(f"脚本运行时发生未知错误: {e}")
|