#!/usr/bin/env python3 """港股日内交易监控+自动下单 - 北京时间9:30-15:45运行""" import os, json, time from datetime import datetime # Force SDK to use international endpoint (bypass 602315 mainland CN geo-block) os.environ['LONGBRIDGE_REGION'] = 'ap' # Load LongBridge credentials config = {} with open(os.path.expanduser('~/.bashrc'), 'r') as f: for line in f: if line.startswith('export LONGPORT_'): key, value = line.strip().split('=', 1) config[key.replace('export ', '')] = value os.environ['LONGPORT_APP_KEY'] = config.get('LONGPORT_APP_KEY', '') os.environ['LONGPORT_APP_SECRET'] = config.get('LONGPORT_APP_SECRET', '') os.environ['LONGPORT_ACCESS_TOKEN'] = config.get('LONGPORT_ACCESS_TOKEN', '') from longport import openapi cfg = openapi.Config.from_env() ctx = openapi.QuoteContext(config=cfg) trade_ctx = openapi.TradeContext(config=cfg) # 读取盘前筛选结果 screen_file = os.path.expanduser('~/.hermes/skills/trading/quant-factor-mining/artifacts/hk_intraday_latest.json') if not os.path.exists(screen_file): print("❌ 未找到盘前筛选结果") exit(1) with open(screen_file) as f: screen_data = json.load(f) candidates = screen_data.get('results', [])[:3] # 取TOP3 # 账户信息 balance = trade_ctx.account_balance() buying_power = 0 for acc in balance: if acc.currency == 'HKD': buying_power = float(acc.buy_power) position_size = buying_power * 0.25 # 25%仓位 print(f"📊 日内交易监控启动") print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M')}") print(f"购买力: {buying_power:,.0f} HKD") print(f"单笔仓位: {position_size:,.0f} HKD") print() print("🎯 监控标的:") for c in candidates: print(f" {c['ticker']}: 现价 {c['price']} | ADR {c['avg_adr']}% | 评分 {c['score']}") print() # 读取已入场记录 entry_file = os.path.expanduser('~/.hermes/trading/hk_intraday_entries.json') entries = {} if os.path.exists(entry_file): with open(entry_file) as f: entries = json.load(f) # 获取实时行情 tickers = [c['ticker'] for c in candidates] quotes = ctx.quote(tickers) for q in quotes: ticker = q.symbol current = float(q.last_done) prev_close = float(q.prev_close) change_pct = (current - prev_close) / prev_close * 100 # 找到对应候选 candidate = next((c for c in candidates if c['ticker'] == ticker), None) if not candidate: continue # 获取5分钟K线计算入场信号 try: candles = ctx.candlesticks(ticker, openapi.Period.Min_5, 20, openapi.AdjustType.ForwardAdjust) if not candles: continue closes = [float(c.close) for c in candles] highs = [float(c.high) for c in candles] lows = [float(c.low) for c in candles] # 计算SMA sma5 = sum(closes[-5:]) / 5 sma10 = sum(closes[-10:]) / 10 sma20 = sum(closes) / len(closes) # 计算ATR atr = sum(max(highs[i]-lows[i], abs(highs[i]-closes[i-1]), abs(lows[i]-closes[i-1])) for i in range(1, len(candles))) / (len(candles)-1) # 入场条件 entry_price = None side = None # 做多条件: 价格突破SMA5且SMA5>SMA10 if current > sma5 and sma5 > sma10 and current > closes[-2]: entry_price = current side = 'buy' stop_loss = max(min(lows[-5:]), current - atr * 2) take_profit = current + atr * 3 # 做空条件: 价格跌破SMA5且SMA5= entry['take_profit']: print(f"🎯 {ticker} 触发止盈! {current:.2f} >= {entry['take_profit']:.2f}") # 只平我们开的仓位数量 try: trade_ctx.submit_order( symbol=ticker, order_type=openapi.OrderType.MO, side=openapi.OrderSide.Sell, submitted_quantity=entry_shares, time_in_force=openapi.TimeInForceType.Day, ) print(f" ✅ 平仓成功: 卖出 {entry_shares}股") del entries[ticker] except Exception as e: print(f" ❌ 平仓失败: {e}") elif entry['side'] == 'sell': if current >= entry['stop_loss']: print(f"🛑 {ticker} 触发止损! {current:.2f} >= {entry['stop_loss']:.2f}") # 只平我们开的仓位数量 try: trade_ctx.submit_order( symbol=ticker, order_type=openapi.OrderType.MO, side=openapi.OrderSide.Buy, submitted_quantity=entry_shares, time_in_force=openapi.TimeInForceType.Day, ) print(f" ✅ 平仓成功: 买入 {entry_shares}股") del entries[ticker] except Exception as e: print(f" ❌ 平仓失败: {e}") elif current <= entry['take_profit']: print(f"🎯 {ticker} 触发止盈! {current:.2f} <= {entry['take_profit']:.2f}") # 只平我们开的仓位数量 try: trade_ctx.submit_order( symbol=ticker, order_type=openapi.OrderType.MO, side=openapi.OrderSide.Buy, submitted_quantity=entry_shares, time_in_force=openapi.TimeInForceType.Day, ) print(f" ✅ 平仓成功: 买入 {entry_shares}股") del entries[ticker] except Exception as e: print(f" ❌ 平仓失败: {e}") else: print(f"⏳ {ticker}: 等待信号 | 现价 {current:.2f} | SMA5 {sma5:.2f} | SMA10 {sma10:.2f}") except Exception as e: print(f"❌ {ticker}: {e}") # 保存更新后的记录 with open(entry_file, 'w') as f: json.dump(entries, f, indent=2) print() if entries: print("📊 当前持仓:") for ticker, entry in entries.items(): print(f" {ticker}: {entry['side']} @ {entry['entry_price']:.2f} | 止损 {entry['stop_loss']:.2f} | 止盈 {entry['take_profit']:.2f}") else: print("📊 当前无持仓")