#!/usr/bin/env python3 """ 持仓做T价格监控 - 支撑位低吸、阻力位高抛 监控所有持仓(OKX+长桥),价格接近关键位时提醒 无提醒时静默输出(cron no_agent模式不推送) """ import os, sys, json, math, subprocess, re from datetime import datetime # Load creds okx_creds = {} with open(os.path.expanduser('~/.bashrc')) as f: for line in f: m = re.match(r'export\s+(OKX_\w+)=(.*)', line.strip()) if m: okx_creds[m.group(1)] = m.group(2).strip().strip('"').strip("'") line = line.strip() if line.startswith('export LONGPORT_') or line.startswith('export LONGBRIDGE_'): parts = line.replace('export ', '').split('=', 1) if len(parts) == 2: os.environ[parts[0]] = parts[1] def okx_get(endpoint, params=""): import hmac, base64, hashlib ts = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.') + f"{datetime.utcnow().microsecond // 1000:03d}Z" path = endpoint + ('?' + params if params else '') msg = ts + 'GET' + path sig = base64.b64encode(hmac.new(okx_creds['OKX_SECRET'].encode(), msg.encode(), hashlib.sha256).digest()).decode() cmd = ['curl', '-s', '--proxy', 'http://127.0.0.1:7890', '-H', f'OK-ACCESS-KEY: {okx_creds["OKX_API_KEY"]}', '-H', f'OK-ACCESS-SIGN: {sig}', '-H', f'OK-ACCESS-TIMESTAMP: {ts}', '-H', f'OK-ACCESS-PASSPHRASE: {okx_creds["OKX_PASSPHRASE"]}', '-H', 'Content-Type: application/json', f'https://www.okx.com{path}'] r = subprocess.run(cmd, capture_output=True, text=True, timeout=15) return json.loads(r.stdout) def monitor(): alerts = [] # OKX positions try: pos = okx_get('/api/v5/account/positions', 'instType=SWAP') for p in pos.get('data', []): if float(p.get('pos', 0)) == 0: continue sym = p['instId'].replace('-USDT-SWAP', '') try: ticker = okx_get('/api/v5/market/ticker', f'instId={sym}-USDT-SWAP') price = float(ticker['data'][0]['last']) candles = okx_get('/api/v5/market/candles', f'instId={sym}-USDT-SWAP&bar=4H&limit=20') data = candles.get('data', []) if len(data) >= 10: closes = [float(d[4]) for d in data] highs = [float(d[2]) for d in data] lows = [float(d[3]) for d in data] atr_sum = sum(max(highs[-i]-lows[-i], abs(highs[-i]-closes[-i-1]), abs(lows[-i]-closes[-i-1])) for i in range(1, min(15, len(data)))) atr = atr_sum / min(14, len(data)-1) support = min(lows[-5:]) resistance = max(highs[-5:]) sma20 = sum(closes) / len(closes) buy_zone = min(support, sma20) + atr * 0.2 sell_zone = max(resistance, sma20) - atr * 0.2 dist_buy = abs(price - buy_zone) / price * 100 dist_sell = abs(price - sell_zone) / price * 100 if dist_buy < 1.5: alerts.append(f"🟢 {sym} 接近低吸位! 现价{price:.2f} → 低吸{buy_zone:.2f} (差{dist_buy:.1f}%)") elif dist_sell < 1.5: alerts.append(f"🔴 {sym} 接近高抛位! 现价{price:.2f} → 高抛{sell_zone:.2f} (差{dist_sell:.1f}%)") elif price < support: alerts.append(f"⚠️ {sym} 跌破支撑! 现价{price:.2f} < 支撑{support:.2f}") elif price > resistance: alerts.append(f"🚀 {sym} 突破阻力! 现价{price:.2f} > 阻力{resistance:.2f}") except: pass except: pass # LongBridge positions try: from longport import openapi cfg = openapi.Config.from_env() trade_ctx = openapi.TradeContext(config=cfg) quote_ctx = openapi.QuoteContext(config=cfg) resp = trade_ctx.stock_positions() lb_syms = [] lb_pos = {} for ch in resp.channels: for p in ch.positions: if int(p.quantity) > 0: lb_syms.append(p.symbol) lb_pos[p.symbol] = {'cost': float(p.cost_price), 'qty': int(p.quantity)} if lb_syms: quotes = quote_ctx.quote(lb_syms) for q in quotes: price = float(q.last_done) cost = lb_pos[q.symbol]['cost'] buy_zone = cost * 0.95 sell_zone = cost * 1.05 dist_buy = abs(price - buy_zone) / price * 100 dist_sell = abs(price - sell_zone) / price * 100 if dist_buy < 2: alerts.append(f"🟢 {q.symbol} 接近低吸位! 现价{price:.2f} → 低吸{buy_zone:.2f}") elif dist_sell < 2: alerts.append(f"🔴 {q.symbol} 接近高抛位! 现价{price:.2f} → 高抛{sell_zone:.2f}") except: pass if alerts: print("📊 做T监控提醒\n") print("\n".join(alerts)) print(f"\n⏰ {datetime.now().strftime('%H:%M')}") # 无输出=静默 if __name__ == '__main__': monitor()