From ee54e66dd7890eabcffcc9f63683fa08fea66780 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Thu, 26 Feb 2026 23:31:29 +0800 Subject: [PATCH] update --- .../app/services/bitget_trading_api_sdk.py | 101 +++- backend/app/utils/signal_formatter.py | 1 + backend/test_bitget_trading.py | 472 ++++++++++++++++ gold-agent-plan.md | 518 ------------------ 4 files changed, 565 insertions(+), 527 deletions(-) create mode 100644 backend/test_bitget_trading.py delete mode 100644 gold-agent-plan.md diff --git a/backend/app/services/bitget_trading_api_sdk.py b/backend/app/services/bitget_trading_api_sdk.py index 1207085..05949af 100644 --- a/backend/app/services/bitget_trading_api_sdk.py +++ b/backend/app/services/bitget_trading_api_sdk.py @@ -51,11 +51,19 @@ class BitgetTradingAPI: self.exchange = ccxt.bitget(config) - # 设置测试网(sandbox 模式) + # 设置测试网(手动配置 API 端点) if use_testnet: - if hasattr(self.exchange, 'set_sandbox_mode'): - self.exchange.set_sandbox_mode(True) - logger.info("✅ Bitget 测试网模式已启用") + # Bitget 测试网端点 + self.exchange.urls['api']['swap'] = 'https://capi.bitget.com' + self.exchange.urls['api']['swapPrivate'] = 'https://capi.bitget.com' + self.exchange.urls['api']['swapPublic'] = 'https://capi.bitget.com' + # 同时设置通用的 API URL + self.exchange.urls['api'] = { + 'swap': 'https://capi.bitget.com', + 'swapPrivate': 'https://capi.bitget.com', + 'swapPublic': 'https://capi.bitget.com', + } + logger.info("✅ Bitget 测试网模式已启用 (capi.bitget.com)") logger.info(f"Bitget 交易 API 初始化完成 ({'测试网' if use_testnet else '生产网'})") @@ -84,11 +92,58 @@ class BitgetTradingAPI: # CCXT 标准化交易对格式 ccxt_symbol = self._standardize_symbol(symbol) + # 手动获取合约规格(不依赖 CCXT 的 contractSize) + # Bitget 永续合约规格 + if 'BTC' in symbol: + contract_size = 0.01 # BTC 每张 0.01 BTC + elif 'ETH' in symbol: + contract_size = 0.1 # ETH 每张 0.1 ETH + elif 'SOL' in symbol: + contract_size = 1 # SOL 每张 1 SOL + elif 'BNB' in symbol: + contract_size = 0.1 # BNB 每张 0.1 BNB + elif 'XRP' in symbol: + contract_size = 10 # XRP 每张 10 XRP + elif 'DOGE' in symbol: + contract_size = 100 # DOGE 每张 100 DOGE + elif 'MATIC' in symbol or 'POL' in symbol: + contract_size = 10 # MATIC 每张 10 MATIC + elif 'AVAX' in symbol: + contract_size = 1 # AVAX 每张 1 AVAX + elif 'LINK' in symbol: + contract_size = 1 # LINK 每张 1 LINK + elif 'UNI' in symbol: + contract_size = 1 # UNI 每张 1 UNI + elif 'ATOM' in symbol: + contract_size = 1 # ATOM 每张 1 ATOM + elif 'LTC' in symbol: + contract_size = 0.1 # LTC 每张 0.1 LTC + elif 'BCH' in symbol: + contract_size = 0.1 # BCH 每张 0.1 BCH + elif 'FIL' in symbol: + contract_size = 1 # FIL 每张 1 FIL + elif 'DOT' in symbol: + contract_size = 1 # DOT 每张 1 DOT + else: + # 默认尝试从市场信息获取 + try: + market = self.exchange.market(ccxt_symbol) + contract_size = market.get('contractSize', 1) + logger.info(f"从市场信息获取合约规格: {contract_size}") + except Exception: + contract_size = 1 + logger.warning(f"无法确定 {symbol} 的合约规格,使用默认值 1") + + # 计算实际下单数量(张数 × 合约规格) + # Bitget 的 amount 参数是币的数量,不是张数 + actual_amount = size * contract_size + # 构建订单参数 # 单向持仓模式 + 联合保证金模式 params = { 'tdMode': 'cross', # 联合保证金模式(全仓) 'marginCoin': 'USDT', # 保证金币种 + 'holdMode': 'oneWay', # 单向持仓模式 } if client_order_id: @@ -100,12 +155,19 @@ class BitgetTradingAPI: if take_profit: params['takeProfit'] = str(take_profit) + # Bitget 合约交易特殊参数 + params['holdMode'] = 'oneWay' # 单向持仓模式 + + # 调试:打印下单参数 + logger.info(f"下单参数: symbol={ccxt_symbol}, type={order_type}, side={side}, 张数={size}, 实际amount={actual_amount}") + logger.debug(f"完整参数: {params}") + # 下单 - 直接使用通用 create_order 方法 order = self.exchange.create_order( symbol=ccxt_symbol, type=order_type, side=side, - amount=size, + amount=actual_amount, # 使用实际币数量(张数 × 合约规格) price=price, params=params ) @@ -363,6 +425,27 @@ class BitgetTradingAPI: # 使用独立的止损/止盈计划订单 # 注意:这种方式需要在平仓时也取消这些计划订单 + # 获取合约规格(用于转换张数为币数量) + if 'BTC' in symbol: + contract_size = 0.01 + elif 'ETH' in symbol: + contract_size = 0.1 + elif 'SOL' in symbol: + contract_size = 1 + elif 'BNB' in symbol: + contract_size = 0.1 + elif 'XRP' in symbol: + contract_size = 10 + elif 'DOGE' in symbol: + contract_size = 100 + elif 'MATIC' in symbol or 'POL' in symbol: + contract_size = 10 + else: + contract_size = 1 + + # 将张数转换为币数量 + contracts_amount = contracts * contract_size + orders_created = [] # 止损单 @@ -374,7 +457,7 @@ class BitgetTradingAPI: symbol=ccxt_symbol, type='stop_market', side=sl_side, - amount=contracts, + amount=contracts_amount, # 使用币数量,不是张数 price=None, params={ 'stopPrice': stop_loss, @@ -385,7 +468,7 @@ class BitgetTradingAPI: } ) orders_created.append(('止损', sl_order)) - logger.info(f"✅ 止损单已下: {sl_side} {contracts}张 @ ${stop_loss}") + logger.info(f"✅ 止损单已下: {sl_side} {contracts}张 ({contracts_amount}币) @ ${stop_loss}") except Exception as e: logger.warning(f"下止损单失败: {e}") @@ -398,7 +481,7 @@ class BitgetTradingAPI: symbol=ccxt_symbol, type='limit', side=tp_side, - amount=contracts, + amount=contracts_amount, # 使用币数量,不是张数 price=take_profit, params={ 'tdMode': 'cross', @@ -407,7 +490,7 @@ class BitgetTradingAPI: } ) orders_created.append(('止盈', tp_order)) - logger.info(f"✅ 止盈单已下: {tp_side} {contracts}张 @ ${take_profit}") + logger.info(f"✅ 止盈单已下: {tp_side} {contracts}张 ({contracts_amount}币) @ ${take_profit}") except Exception as e: logger.warning(f"下止盈单失败: {e}") diff --git a/backend/app/utils/signal_formatter.py b/backend/app/utils/signal_formatter.py index d065adf..0405ed8 100644 --- a/backend/app/utils/signal_formatter.py +++ b/backend/app/utils/signal_formatter.py @@ -126,6 +126,7 @@ class SignalFormatter: signal_type_key = 'timeframe' if 'timeframe' in signal else 'type' signal_type = type_map.get(signal.get(signal_type_key), signal.get(signal_type_key)) action = action_map.get(signal['action'], signal['action']) + action_icon = '🟢' if signal['action'] == 'buy' else '🔴' grade = signal.get('grade', 'C') confidence = signal.get('confidence', 0) entry_type = signal.get('entry_type', 'market') diff --git a/backend/test_bitget_trading.py b/backend/test_bitget_trading.py new file mode 100644 index 0000000..c21d217 --- /dev/null +++ b/backend/test_bitget_trading.py @@ -0,0 +1,472 @@ +""" +测试 Bitget 实盘交易 API + +运行前请确保已在 .env 中配置: +- bitget_api_key +- bitget_api_secret +- bitget_passphrase +- bitget_use_testnet = true (建议先在测试网测试) +""" +import sys +import os +import asyncio + +# 添加项目路径 +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) + +from app.services.bitget_trading_api_sdk import BitgetTradingAPI +from app.config import get_settings + + +def print_section(title: str): + """打印分节标题""" + print("\n" + "=" * 60) + print(f" {title}") + print("=" * 60) + + +def test_connection(api: BitgetTradingAPI): + """测试 API 连接""" + print_section("1. 测试 API 连接") + + if api.test_connection(): + print("✅ API 连接成功") + return True + else: + print("❌ API 连接失败") + return False + + +def test_balance(api: BitgetTradingAPI): + """测试查询余额""" + print_section("2. 查询账户余额") + + balance = api.get_balance() + if balance: + print(f"✅ 查询余额成功") + for currency, info in balance.items(): + available = info.get('available', '0') + frozen = info.get('frozen', '0') + print(f" {currency}: 可用={available}, 冻结={frozen}") + return True + else: + print("❌ 查询余额失败") + return False + + +def test_position(api: BitgetTradingAPI, symbol: str = "BTCUSDT"): + """测试查询持仓""" + print_section(f"3. 查询持仓 ({symbol})") + + positions = api.get_position(symbol) + if positions is not None: + if positions: + print(f"✅ 查询到 {len(positions)} 个持仓") + for pos in positions: + pos_side = pos.get('side', 'N/A') + contracts = pos.get('contracts', 0) + unrealized_pnl = pos.get('unrealizedPnl', 0) + print(f" {pos_side}: {contracts}张, 未实现盈亏={unrealized_pnl}") + else: + print("✅ 当前无持仓") + return True + else: + print("❌ 查询持仓失败") + return False + + +def test_leverage(api: BitgetTradingAPI, symbol: str = "BTCUSDT", leverage: int = 10): + """测试设置杠杆""" + print_section(f"4. 设置杠杆 ({symbol} {leverage}x)") + + if api.set_leverage(symbol, leverage): + print(f"✅ 设置杠杆成功: {leverage}x") + return True + else: + print(f"❌ 设置杠杆失败") + return False + + +def test_open_orders(api: BitgetTradingAPI): + """测试查询挂单""" + print_section("5. 查询当前挂单") + + orders = api.get_open_orders() + if orders is not None: + if orders: + print(f"✅ 查询到 {len(orders)} 个挂单") + for order in orders[:5]: # 只显示前5个 + order_id = order.get('id', 'N/A') + symbol = order.get('symbol', 'N/A') + side = order.get('side', 'N/A') + amount = order.get('amount', 'N/A') + price = order.get('price', 'N/A') + print(f" {order_id}: {symbol} {side} {amount} @ {price}") + else: + print("✅ 当前无挂单") + return True + else: + print("❌ 查询挂单失败") + return False + + +def test_place_order(api: BitgetTradingAPI, symbol: str = "BTCUSDT", + side: str = "buy", usdt_value: float = 100, + order_type: str = "market", leverage: int = 20, price: float = None): + """ + 测试下单(按 USDT 价值) + + Args: + api: Bitget API 实例 + symbol: 交易对 + side: 买卖方向 + usdt_value: 下单的 USDT 价值 + order_type: 订单类型 + leverage: 杠杆倍数 + price: 限价单价格(可选) + """ + print_section(f"6. 下单测试 ({symbol} {side} 价值${usdt_value}, {leverage}x杠杆)") + + settings = get_settings() + + # 先设置杠杆 + print(f"设置杠杆: {leverage}x") + api.set_leverage(symbol, leverage) + + # 获取当前价格 + import ccxt + ccxt_symbol = api._standardize_symbol(symbol) + ticker = api.exchange.fetch_ticker(ccxt_symbol) + current_price = ticker['last'] if ticker else None + + if not current_price: + print("❌ 无法获取当前价格") + return None + + print(f"当前价格: ${current_price:.2f}") + + # 选择订单类型 + print("\n选择订单类型:") + print(" 1. 市价单 (立即成交)") + print(" 2. 限价单 (挂单,可测试撤单)") + order_type_choice = input("请选择 (1-2, 默认2): ").strip() + if order_type_choice == '1': + order_type = 'market' + limit_price = None + else: + order_type = 'limit' + # 限价单需要输入价格 + price_input = input("挂单价格 (留空使用默认远离市价的价格): ").strip() + if price_input: + limit_price = float(price_input) + else: + # 默认设置一个远离当前价的价格,确保不会立即成交 + if side == 'buy': + limit_price = current_price * 0.95 # 买单价格低于市价5% + print(f"默认买单价格: ${limit_price:.2f} (低于市价5%)") + else: + limit_price = current_price * 1.05 # 卖单价格高于市价5% + print(f"默认卖单价格: ${limit_price:.2f} (高于市价5%)") + + # 计算合约数量 + # Bitget 合约规格: BTC/USDT 每张 0.01 BTC, ETH/USDT 每张 0.1 ETH + if 'BTC' in symbol: + contract_size = 0.01 # 每张 0.01 BTC + min_size = 1 # Bitget 最小 1 张 + coin_price = current_price + elif 'ETH' in symbol: + contract_size = 0.1 # 每张 0.1 ETH + min_size = 1 # Bitget 最小 1 张 + coin_price = current_price + else: + contract_size = 1 + min_size = 1 + coin_price = current_price + + # 计算需要的数量 (USDT价值 / (币价 * 合约规格)) + size = usdt_value / (coin_price * contract_size) + + # 确保满足最小下单量 + size = max(size, min_size) + + # 计算实际仓位价值和所需保证金 + position_value = size * contract_size * coin_price + required_margin = position_value / leverage + + print(f"合约规格: {contract_size} 币/张") + print(f"下单数量: {size:.3f}张 (最小{min_size}张)") + print(f"仓位价值: ${position_value:.2f}") + print(f"所需保证金: ${required_margin:.2f} ({leverage}x杠杆)") + print(f"模式: {'测试网' if settings.bitget_use_testnet else '生产网'}") + + # 检查余额 + balance = api.get_balance() + available = float(balance.get('USDT', {}).get('available', 0)) + print(f"账户可用余额: ${available:.2f}") + + if required_margin > available: + print(f"\n❌ 余额不足!") + print(f" 需要: ${required_margin:.2f}") + print(f" 可用: ${available:.2f}") + print(f" 缺口: ${required_margin - available:.2f}") + + # 建议更高的杠杆 + suggested_leverage = int(required_margin / available * leverage) + 1 + if suggested_leverage <= 125: # Bitget 最大杠杆 + print(f"\n建议: 使用 {suggested_leverage}x 杠杆或减少下单金额") + return None + + order_type_text = "限价单" if order_type == "limit" else "市价单" + print(f"订单类型: {order_type_text}") + if price: + print(f"挂单价格: ${price:.2f}") + + confirm = input(f"\n⚠️ 即将下单: {symbol} {side} {size:.3f}张 ({order_type_text}, 仓位价值${position_value:.2f}, 保证金${required_margin:.2f}),是否继续?(y/n): ") + if confirm.lower() != 'y': + print("已取消下单") + return None + + order = api.place_order( + symbol=symbol, + side=side, + order_type=order_type, + size=size, + price=price + ) + + if order: + print(f"✅ 下单成功") + print(f" 订单ID: {order.get('id', 'N/A')}") + print(f" 状态: {order.get('status', 'N/A')}") + print(f" 价格: {order.get('price', 'N/A')}") + print(f" 数量: {order.get('amount', 'N/A')}") + fee = order.get('fee') + if fee and isinstance(fee, dict): + print(f" 手续费: {fee.get('cost', 'N/A')}") + else: + print(f" 手续费: N/A") + return order + else: + print("❌ 下单失败") + return None + + +def test_cancel_order(api: BitgetTradingAPI, symbol: str = "BTCUSDT", order_id: str = None): + """测试撤单""" + print_section("7. 撤单测试") + + if not order_id: + # 如果没有提供订单ID,先查询挂单 + orders = api.get_open_orders(symbol) + if not orders: + print("⚠️ 无可撤订单") + return None + order_id = orders[0].get('id') + + print(f"订单ID: {order_id}") + + if api.cancel_order(symbol, order_id=order_id): + print("✅ 撤单成功") + return True + else: + print("❌ 撤单失败") + return False + + +def test_close_position(api: BitgetTradingAPI, symbol: str = "BTCUSDT"): + """测试平仓""" + print_section(f"8. 平仓测试 ({symbol})") + + positions = api.get_position(symbol) + if not positions: + print("⚠️ 无持仓可平") + return None + + print(f"持仓数量: {len(positions)}") + for pos in positions: + pos_side = pos.get('side', 'N/A') + contracts = pos.get('contracts', 0) + print(f" {pos_side}: {contracts}张") + + confirm = input("\n⚠️ 即将平仓,是否继续?(y/n): ") + if confirm.lower() != 'y': + print("已取消平仓") + return None + + result = api.close_position(symbol) + if result: + print("✅ 平仓成功") + return True + else: + print("❌ 平仓失败") + return False + + +def test_modify_sl_tp(api: BitgetTradingAPI, symbol: str = "BTCUSDT"): + """测试修改止损止盈""" + print_section(f"9. 修改止损止盈 ({symbol})") + + positions = api.get_position(symbol) + if not positions: + print("⚠️ 无持仓,跳过止损止盈测试") + return None + + pos = positions[0] + pos_side = pos.get('side') + mark_price = float(pos.get('markPrice', 0)) + + print(f"当前持仓: {pos_side}, 标记价: {mark_price}") + + # 根据持仓方向计算测试用的止损止盈价格 + if pos_side == 'long': + test_sl = mark_price * 0.98 # 止损设为标记价的 98% + test_tp = mark_price * 1.02 # 止盈设为标记价的 102% + else: + test_sl = mark_price * 1.02 # 做空止损设为标记价的 102% + test_tp = mark_price * 0.98 # 做空止盈设为标记价的 98% + + print(f"测试参数: 止损={test_sl:.2f}, 止盈={test_tp:.2f}") + + confirm = input("\n⚠️ 即将设置止损止盈,是否继续?(y/n): ") + if confirm.lower() != 'y': + print("已取消设置") + return None + + if api.modify_sl_tp(symbol, stop_loss=test_sl, take_profit=test_tp): + print("✅ 设置止损止盈成功") + return True + else: + print("❌ 设置止损止盈失败") + return False + + +def test_cancel_all_orders(api: BitgetTradingAPI, symbol: str = "BTCUSDT"): + """测试撤销所有挂单""" + print_section(f"10. 撤销所有挂单 ({symbol})") + + # 先查询挂单 + orders = api.get_open_orders(symbol) + if not orders: + print("⚠️ 无挂单可撤") + return None + + print(f"当前挂单数: {len(orders)}") + + confirm = input("\n⚠️ 即将撤销所有挂单,是否继续?(y/n): ") + if confirm.lower() != 'y': + print("已取消") + return None + + if api.cancel_all_orders(symbol): + print("✅ 撤销所有挂单成功") + return True + else: + print("❌ 撤销所有挂单失败") + return False + + +def main(): + """主测试流程""" + print("\n" + "=" * 60) + print(" Bitget 实盘交易 API 测试") + print("=" * 60) + + # 加载配置 + settings = get_settings() + + # 检查配置 + if not settings.bitget_api_key or not settings.bitget_api_secret: + print("❌ 未配置 Bitget API 密钥") + print("请在 .env 文件中设置:") + print(" bitget_api_key=your_api_key") + print(" bitget_api_secret=your_api_secret") + print(" bitget_passphrase=your_passphrase (可选)") + print(" bitget_use_testnet=true/false (测试网/生产网)") + return + + # 创建 API 实例 + api = BitgetTradingAPI( + api_key=settings.bitget_api_key, + api_secret=settings.bitget_api_secret, + passphrase=settings.bitget_passphrase or "", + use_testnet=settings.bitget_use_testnet + ) + + mode = '测试网' if settings.bitget_use_testnet else '生产网' + print(f"\n模式: {mode}") + print(f"API Key: {settings.bitget_api_key[:8]}...{settings.bitget_api_key[-4:]}") + + try: + # 基础测试(不涉及交易) + if not test_connection(api): + return + test_balance(api) + test_position(api) + test_leverage(api) + test_open_orders(api) + + # 交易相关测试(需要确认) + print("\n" + "=" * 60) + print(" 交易功能测试(需要手动确认)") + print("=" * 60) + + # 检查用户是否要测试交易功能 + test_trading = input("\n是否测试交易功能(下单、平仓等)?(y/n): ") + if test_trading.lower() == 'y': + # 选择交易对 + print("\n选择交易对:") + print(" 1. BTCUSDT") + print(" 2. ETHUSDT") + print(" 3. 自定义") + choice = input("请选择 (1-3): ").strip() + + if choice == '1': + symbol = 'BTCUSDT' + elif choice == '2': + symbol = 'ETHUSDT' + else: + symbol = input("请输入交易对 (如 BTCUSDT): ").strip().upper() + + # 选择买卖方向 + direction = input("方向 (buy/sell, 默认buy): ").strip().lower() + side = direction if direction in ['buy', 'sell'] else 'buy' + + # 输入 USDT 价值 + usdt_input = input("下单价值 (USDT, 默认100): ").strip() + usdt_value = float(usdt_input) if usdt_input else 100 + + # 输入杠杆倍数 + leverage_input = input("杠杆倍数 (默认20, 最大125): ").strip() + leverage = int(leverage_input) if leverage_input else 20 + leverage = min(max(leverage, 1), 125) # 限制在 1-125 之间 + + # 下单测试(函数内部会询问订单类型) + order = test_place_order(api, symbol=symbol, side=side, usdt_value=usdt_value, leverage=leverage) + if order: + import time + print("\n等待 3 秒后撤单...") + time.sleep(3) + # 撤单测试 + test_cancel_order(api, symbol, order_id=order.get('id')) + + # 平仓测试 + test_close_position(api, symbol) + + # 止损止盈测试 + test_modify_sl_tp(api, symbol) + + # 撤销所有挂单 + test_cancel_all_orders(api, symbol) + else: + print("跳过交易功能测试") + + finally: + # 关闭连接 + api.close() + print("\n" + "=" * 60) + print(" 测试完成") + print("=" * 60) + + +if __name__ == "__main__": + main() diff --git a/gold-agent-plan.md b/gold-agent-plan.md deleted file mode 100644 index 4142c9b..0000000 --- a/gold-agent-plan.md +++ /dev/null @@ -1,518 +0,0 @@ -# 黄金交易智能体 (Gold Agent) 技术调研与系统设计 - -## 一、项目概述 - -### 1.1 目标 -构建一个基于 LLM 驱动的黄金 (XAUUSD) 行情分析智能体,对接 MetaTrader 5 (MT5) 进行实盘交易。 - -### 1.2 核心功能 -- 实时获取黄金行情数据(通过 MT5) -- LLM 驱动的市场分析与信号生成 -- 自动化交易执行(MT5 实盘) -- 风险管理与仓位控制 -- 飞书/Telegram 通知推送 - ---- - -## 二、技术调研 - -### 2.1 MetaTrader 5 (MT5) API 调研 - -#### MT5 Python 库 -```python -import MetaTrader5 as mt5 - -# 初始化 -mt5.initialize() - -# 获取行情数据 -rates = mt5.copy_rates_from_pos("XAUUSD", mt5.TIMEFRAME_M15, 0, 100) - -# 获取当前价格 -tick = mt5.symbol_info_tick("XAUUSD") -bid = tick.bid -ask = tick.ask - -# 下单 -request = { - "action": mt5.TRADE_ACTION_DEAL, - "symbol": "XAUUSD", - "volume": 0.01, # 手数 - "type": mt5.ORDER_TYPE_BUY, - "price": ask, - "deviation": 20, - "magic": 234000, - "comment": "Gold Agent", - "type_time": mt5.ORDER_TIME_GTC, - "type_filling": mt5.ORDER_FILLING_IOC, -} -mt5.order_send(request) -``` - -#### MT5 核心概念 -| 概念 | 说明 | -|------|------| -| **手数 (Lot)** | 黄金最小 0.01 手,1 手 = 100 盎司 | -| **点值 (Point)** | 0.01 美元/点,1 点 = 0.01 USD | -| **杠杆** | 通常 1:100 - 1:500,由经纪商设定 | -| **交易时间** | 周一 00:00 - 周六 00:00 (服务器时间) | -| **点差** | 通常 20-50 点 (0.2-0.5 USD) | - -### 2.2 黄金交易特点 - -#### XAUUSD 特性 -| 特性 | 说明 | 交易策略影响 | -|------|------|-------------| -| **波动性高** | 日波动 50-200 点 | 需要宽止损 (30-50 点) | -| **流动性强** | 24 小时交易 | 可设置夜间交易 | -| **美元相关** | 与美元指数负相关 | 需关注 USD 数据 | -| **避险属性** | 市场恐慌时上涨 | 需关注 VIX 指数 | -| **交易时段** | 伦敦盘 (15:00-24:00) 和 纽约盘 (21:00-04:00) 最活跃 | 重点交易时段 | -| **周末停盘** | 周末不交易 | 周五收盘前需要平仓或宽止损 | - -#### 技术指标适用性 -- **趋势类**: MA, EMA, MACD 效果较好 -- **震荡类**: RSI, KDJ 在盘整市有效 -- **波动率类**: ATR 对止损设置重要 -- **支撑阻力**: 黄金的关键整数位 ($2000, $2050, $2100) 效果明显 - ---- - -## 三、系统架构设计 - -### 3.1 整体架构 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Gold Agent 主控制器 │ -│ (gold_agent/gold_agent.py) │ -└─────────────────────────────────────────────────────────────┘ - │ - ┌───────────────┼───────────────┐ - ▼ ▼ ▼ -┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ MT5 服务 │ │ 市场信号分析器 │ │ 交易决策器 │ -│ (mt5_service) │ │ (market_signal_ │ │ (trading_ │ -│ │ │ analyzer) │ │ decision) │ -└─────────────────┘ └─────────────────┘ └─────────────────┘ - │ - ┌───────────────┼───────────────┐ - ▼ ▼ ▼ -┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ -│ 飞书/Telegram │ │ 模拟交易 │ │ 实盘交易 │ -│ 通知 │ │ (paper_ │ │ (mt5_ │ -│ │ │ trading) │ │ trading) │ -└─────────────────┘ └─────────────────┘ └─────────────────┘ -``` - -### 3.2 目录结构 - -``` -backend/app/ -├── gold_agent/ # 黄金智能体模块 -│ ├── __init__.py -│ ├── gold_agent.py # 主控制器 -│ ├── market_signal_analyzer.py # 市场信号分析器 -│ ├── trading_decision_maker.py # 交易决策器 -│ └── strategy.py # 交易策略定义 -│ -├── services/ # 服务层 -│ ├── mt5_service.py # MT5 数据服务 -│ ├── mt5_trading_service.py # MT5 实盘交易服务 -│ └── gold_paper_trading.py # 黄金模拟交易服务 -│ -├── models/ # 数据模型 -│ └── gold_order.py # 黄金订单模型 -│ -└── api/ # API 接口 - └── gold.py # 黄金智能体 API -``` - -### 3.3 数据流设计 - -``` -MT5 行情数据 - │ - ▼ -┌─────────────────────────┐ -│ 技术指标计算 │ -│ (MA, EMA, RSI, MACD...) │ -└─────────────────────────┘ - │ - ▼ -┌─────────────────────────┐ -│ 市场信号分析 (LLM) │ -│ - 趋势判断 │ -│ - 关键价位 │ -│ - 信号生成 │ -└─────────────────────────┘ - │ - ▼ -┌─────────────────────────┐ -│ 交易决策 (LLM) │ -│ - 开仓/平仓/观望 │ -│ - 仓位大小 │ -│ - 止损止盈 │ -└─────────────────────────┘ - │ - ▼ -┌─────────────────────────┐ -│ 风险检查 │ -│ - 仓位限制 │ -│ - 价格合理性验证 │ -│ - 交易时段检查 │ -└─────────────────────────┘ - │ - ▼ -┌─────────────────────────┐ -│ 执行交易 │ -│ - 模拟交易 (回测) │ -│ - 实盘交易 (MT5) │ -└─────────────────────────┘ - │ - ▼ -┌─────────────────────────┐ -│ 通知推送 │ -│ - 飞书卡片 │ -│ - Telegram 消息 │ -└─────────────────────────┘ -``` - ---- - -## 四、核心模块设计 - -### 4.1 MT5 服务 (mt5_service.py) - -```python -class MT5Service: - """MT5 数据服务 - 获取行情数据""" - - def __init__(self): - self.connected = False - self.symbol = "XAUUSD" - - def initialize(self, account: int, password: str, server: str) -> bool - def get_rates(self, timeframe: str, count: int) -> pd.DataFrame - def get_current_price(self) -> Tuple[float, float] # (bid, ask) - def get_tick(self) -> Dict - def get_positions(self) -> List[Dict] - def get_orders(self) -> List[Dict] - def get_account_info(self) -> Dict -``` - -#### 时间周期映射 -| 代码 | MT5 常量 | 用途 | -|------|----------|------| -| `M1` | `TIMEFRAME_M1` | 短线交易 | -| `M5` | `TIMEFRAME_M5` | 主要分析周期 | -| `M15` | `TIMEFRAME_M15` | 中线交易 | -| `H1` | `TIMEFRAME_H1` | 趋势确认 | -| `H4` | `TIMEFRAME_H4` | 日内趋势 | -| `D1` | `TIMEFRAME_D1` | 长期趋势 | - -### 4.2 市场信号分析器 (market_signal_analyzer.py) - -```python -class GoldMarketSignalAnalyzer: - """黄金市场信号分析器""" - - MARKET_ANALYSIS_PROMPT = """你是一位专业的黄金交易员... - - ## 黄金交易特点 - - XAUUSD 极其活跃,日波动 50-200 点 - - 关键整数位: $2000, $2050, $2100, $2150, $2200 - - 伦敦盘 (15:00-24:00) 和 纽约盘 (21:00-04:00) 最活跃 - - 周五收盘前需要谨慎持仓 - - ## 输出格式 - { - "trend_direction": "uptrend/downtrend/neutral", - "trend_strength": "strong/medium/weak", - "signals": [ - { - "action": "buy/sell", - "entry_zone": 2050.50, - "stop_loss": 2045.00, - "take_profit": 2060.00, - "confidence": 85, - "grade": "A", - "reasoning": "..." - } - ], - "key_levels": { - "support": [2045.00, 2040.00], - "resistance": [2060.00, 2065.00] - } - } - """ - - async def analyze(self, symbol: str, data: Dict) -> Dict -``` - -### 4.3 交易决策器 (trading_decision_maker.py) - -```python -class GoldTradingDecisionMaker: - """黄金交易决策器""" - - TRADING_DECISION_PROMPT = """你是黄金交易执行者... - - ## 账户信息 - - 余额: {balance} - - 持仓: {positions} - - 杠杆: 1:100 - - ## 黄金交易规则 - - 最小手数: 0.01 手 - - 1 手 = 100 盎司 - - 点值: 0.01 USD/点 - - 建议止损: 30-50 点 - - 建议止盈: 1:2 或 1:3 - - ## 输出格式 - { - "decision": "OPEN/CLOSE/HOLD", - "action": "buy/sell", - "quantity": 0.01, # 手数 - "entry_zone": 2050.50, - "stop_loss": 2045.00, - "take_profit": 2060.00, - "reasoning": "..." - } - """ - - async def make_decision(self, market_signal, positions, account) -> Dict -``` - -### 4.4 MT5 实盘交易服务 (mt5_trading_service.py) - -```python -class MT5TradingService: - """MT5 实盘交易服务""" - - def __init__(self): - self.mt5 = mt5 - self.magic_number = 234000 # 识别 Gold Agent 的订单 - - def connect(self, account: int, password: str, server: str) -> bool - def open_order(self, action: str, volume: float, price: float, - sl: float, tp: float) -> Dict - def close_order(self, order_id: int) -> Dict - def close_all_positions(self) -> Dict - def get_positions(self) -> List[Dict] - def modify_position(self, ticket: int, sl: float, tp: float) -> Dict -``` - -#### 订单类型说明 -| 类型 | MT5 常量 | 说明 | -|------|----------|------| -| 市价买单 | `ORDER_TYPE_BUY` | 以 Ask 价格成交 | -| 市价卖单 | `ORDER_TYPE_SELL` | 以 Bid 价格成交 | -| 限价买单 | `ORDER_TYPE_BUY_LIMIT` | 低于当前价挂单 | -| 限价卖单 | `ORDER_TYPE_SELL_LIMIT` | 高于当前价挂单 | - -### 4.5 风险控制规则 - -```python -# 仓位管理 -MAX_POSITIONS = 3 # 最大同时持仓数 -MAX_LOTS_PER_ORDER = 0.1 # 单笔最大手数 -MAX_TOTAL_LOTS = 0.3 # 总持仓上限 - -# 止损止盈规则 -MIN_STOP_LOSS_POINTS = 30 # 最小止损 30 点 (0.30 USD) -TAKE_PROFIT_RATIO = 2.0 # 止盈/止损比 1:2 - -# 价格合理性验证 -MAX_PRICE_DEVIATION = 0.20 # 价格偏离不超过 20% - -# 交易时段 -WEEKEND_CLOSE_HOUR = 20 # 周五 20:00 后不开新仓 -NEWS_FILTER_WINDOW = 30 # 重大新闻前后 30 分钟不开仓 -``` - ---- - -## 五、实现计划 - -### Phase 1: 基础设施 (第 1-2 周) -- [ ] MT5 服务封装 - - [ ] 连接管理 - - [ ] 行情数据获取 - - [ ] 账户信息查询 -- [ ] 数据模型定义 - - [ ] 黄金订单模型 - - [ ] 持仓记录模型 -- [ ] 配置项添加 - - [ ] MT5 账户配置 - - [ ] 飞书 webhook 配置 - -### Phase 2: 分析与决策 (第 3-4 周) -- [ ] 市场信号分析器 - - [ ] 技术指标计算 - - [ ] LLM 提示词设计 - - [ ] 信号生成逻辑 -- [ ] 交易决策器 - - [ ] 持仓状态判断 - - [ ] 开平仓决策 - - [ ] 仓位大小计算 - -### Phase 3: 交易执行 (第 5-6 周) -- [ ] 模拟交易服务 - - [ ] 订单管理 - - [ ] 止损止盈执行 - - [ ] 移动止损逻辑 -- [ ] MT5 实盘交易服务 - - [ ] 订单发送 - - [ ] 持仓查询 - - [ ] 订单修改/平仓 - -### Phase 4: 风险管理与通知 (第 7 周) -- [ ] 风险控制模块 - - [ ] 仓位限制 - - [ ] 价格验证 - - [ ] 交易时段检查 -- [ ] 通知推送 - - [ ] 飞书卡片格式 - - [ ] Telegram 消息推送 - -### Phase 5: 测试与优化 (第 8 周) -- [ ] 模拟盘测试 -- [ ] 实盘小资金测试 -- [ ] 性能优化 -- [ ] 文档完善 - ---- - -## 六、风险考虑 - -### 6.1 技术风险 - -| 风险 | 应对措施 | -|------|----------| -| MT5 连接断开 | 自动重连机制,连接状态监控 | -| 订单执行失败 | 超时重试,失败告警 | -| 数据延迟 | 多时间周期数据验证 | -| 系统崩溃 | 持久化状态,重启恢复 | - -### 6.2 交易风险 - -| 风险 | 应对措施 | -|------|----------| -| 市场剧烈波动 | 宽止损 + 小仓位 | -| 流动性枯竭 | 避开非交易时段 | -| 滑点风险 | 使用限价单,设置最大滑点 | -| 重大新闻事件 | 新闻过滤窗口,避免开仓 | - -### 6.3 LLM 相关风险 - -| 风险 | 应对措施 | -|------|----------| -| 幻觉导致错误价格 | 价格合理性验证 | -| 信号质量不稳定 | 多信号确认,降低单次权重 | -| 延迟影响执行 | 缓存机制,异步处理 | - ---- - -## 七、配置项设计 - -### 7.1 config.py 新增配置 - -```python -# ==================== 黄金交易智能体配置 ==================== -# MT5 连接配置 -mt5_account: int = 0 # MT5 账号 -mt5_password: str = "" # MT5 密码 -mt5_server: str = "" # MT5 服务器地址 - -# 黄金交易配置 -gold_symbol: str = "XAUUSD" # 黄金交易品种 -gold_analysis_interval: int = 300 # 分析间隔(秒) -gold_enabled: bool = False # 是否启用黄金智能体 - -# 仓位管理 -gold_max_positions: int = 3 # 最大持仓数 -gold_max_lots_per_order: float = 0.1 # 单笔最大手数 -gold_max_total_lots: float = 0.3 # 总持仓上限 -gold_default_lots: float = 0.01 # 默认手数 - -# 止损止盈 -gold_min_stop_loss_points: float = 30 # 最小止损(点) -gold_take_profit_ratio: float = 2.0 # 止盈/止损比 - -# 交易时段 -gold_weekend_close_hour: int = 20 # 周五收盘时间 -gold_news_filter_minutes: int = 30 # 新闻过滤窗口(分钟) - -# 通知配置 -feishu_gold_webhook_url: str = "" # 黄金智能体飞书通知 -``` - -### 7.2 环境变量 (.env) - -```bash -# MT5 配置 -MT5_ACCOUNT=12345678 -MT5_PASSWORD=your_password -MT5_SERVER=your_broker_server - -# 黄金智能体 -GOLD_ENABLED=True -GOLD_SYMBOL=XAUUSD - -# 飞书通知 -FEISHU_GOLD_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/... -``` - ---- - -## 八、监控指标 - -### 8.1 系统监控 -- MT5 连接状态 -- 分析执行频率 -- LLM 调用延迟 -- 订单执行成功率 - -### 8.2 交易监控 -- 当前持仓数 -- 总盈亏 (USD) -- 胜率 -- 最大回撤 -- 平均持仓时间 - -### 8.3 信号监控 -- 信号生成频率 -- A/B/C/D 级信号分布 -- 信号执行率 -- 信号盈亏比 - ---- - -## 九、后续优化方向 - -1. **多品种支持** - 扩展到 XAGUSD (白银)、其他贵金属 -2. **智能参数调优** - 基于历史数据自动优化参数 -3. **策略回测** - 使用 MT5 历史数据进行策略回测 -4. **风险模型升级** - VaR 计算、凯利公式仓位管理 -5. **机器学习增强** - 使用 ML 模型辅助 LLM 决策 - ---- - -## 十、总结 - -本设计方案基于现有 Crypto Agent 架构,复用了: -- LLM 驱动的市场分析框架 -- 交易决策框架 -- 风险验证逻辑 -- 通知推送机制 - -主要新增: -- MT5 数据与交易接口 -- 黄金特定的交易规则 -- 适配黄金特点的提示词 - -预计开发周期:**8 周** -风险等级:**中等** (实盘交易需谨慎) -投入建议:**先模拟盘充分测试后再小资金实盘**