v4.5.38: 实时数据查询硬规则(回复前必查)+ check_account.py封装
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Crypto Safety Check — verify current positions against 30% utilization cap.
|
||||
|
||||
Usage:
|
||||
python3 safety_check.py [--symbol SYMBOL] [--market-cap 30]
|
||||
|
||||
Reads OKX credentials from ~/.bashrc, queries swap positions, and reports:
|
||||
- Total margin / free balance ratio (utilization %)
|
||||
- Per-symbol: margin, contracts, direction, leverage, liq price
|
||||
- Verdict: SAFE / OVER-CAP / NO-POSITION
|
||||
|
||||
Does NOT place any orders. Read-only diagnostic.
|
||||
|
||||
The 30% cap is the user's explicit safety rule (2026-07-08), overriding the
|
||||
default advisor script value of 45% in config.json.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import ccxt
|
||||
|
||||
# Load OKX creds from bashrc (avoid source; bashrc has non-interactive guard)
|
||||
def load_creds():
|
||||
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 and '...' not in m.group(2):
|
||||
creds[m.group(1)] = m.group(2).strip().strip('"').strip("'")
|
||||
return creds
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--symbol', help='Filter to single symbol (e.g. ETH)')
|
||||
parser.add_argument('--market-cap', type=float, default=40.0,
|
||||
help='Safety utilization %% (default 40)')
|
||||
args = parser.parse_args()
|
||||
|
||||
creds = load_creds()
|
||||
if not all(k in creds for k in ['OKX_API_KEY', 'OKX_SECRET', 'OKX_PASSPHRASE']):
|
||||
print('ERROR: OKX credentials missing in ~/.bashrc', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
ex = ccxt.okx({
|
||||
'apiKey': creds['OKX_API_KEY'],
|
||||
'secret': creds['OKX_SECRET'],
|
||||
'password': creds['OKX_PASSPHRASE'],
|
||||
'proxies': {'http': 'http://127.0.0.1:7890',
|
||||
'https': 'http://127.0.0.1:7890'},
|
||||
'timeout': 30000,
|
||||
})
|
||||
ex.options['defaultType'] = 'swap'
|
||||
|
||||
# Query positions
|
||||
positions = ex.fetch_positions()
|
||||
active = [p for p in positions if abs(float(p.get('contracts', 0))) > 0]
|
||||
|
||||
if args.symbol:
|
||||
active = [p for p in active if args.symbol.upper() in p['symbol'].upper()]
|
||||
|
||||
# Query balance
|
||||
bal = ex.fetch_balance()
|
||||
free = float(bal.get('USDT', {}).get('free', 0))
|
||||
total_eq = float(bal.get('USDT', {}).get('total', 0))
|
||||
|
||||
# Compute total margin
|
||||
total_margin = 0.0
|
||||
print(f'\n=== {args.symbol or "ALL"} Positions ===')
|
||||
print(f'{"Symbol":<12} {"Side":<6} {"Qty":<8} {"Entry":<10} {"Mark":<10} '
|
||||
f'{"Margin":<10} {"Lever":<6} {"UPL":<10}')
|
||||
print('-' * 80)
|
||||
for p in active:
|
||||
sym = p['symbol']
|
||||
contracts = float(p['contracts'])
|
||||
side = 'long' if contracts > 0 else 'short'
|
||||
entry = float(p.get('entryPrice', 0))
|
||||
mark = float(p.get('markPrice', 0))
|
||||
margin = float(p.get('initialMargin', 0))
|
||||
lever = p.get('leverage', '?')
|
||||
upl = float(p.get('unrealizedPnl', 0))
|
||||
total_margin += margin
|
||||
print(f'{sym:<12} {side:<6} {contracts:<8.2f} {entry:<10.2f} '
|
||||
f'{mark:<10.2f} {margin:<10.2f} {str(lever):<6} {upl:<+10.2f}')
|
||||
|
||||
print('-' * 80)
|
||||
util = (total_margin / free * 100) if free > 0 else 999.0
|
||||
print(f'\nTotal margin: {total_margin:.2f} USDT')
|
||||
print(f'Free balance: {free:.2f} USDT')
|
||||
print(f'Total equity: {total_eq:.2f} USDT')
|
||||
print(f'Utilization: {util:.1f}% (cap: {args.market_cap:.0f}%)')
|
||||
|
||||
if util > args.market_cap:
|
||||
over_by = total_margin - (free * args.market_cap / 100)
|
||||
print(f'\n⚠️ OVER SAFETY CAP by {over_by:.2f} USDT')
|
||||
print(f' Reduce positions or top up balance.')
|
||||
sys.exit(2)
|
||||
elif not active:
|
||||
print('\n✅ No active positions.')
|
||||
sys.exit(0)
|
||||
else:
|
||||
headroom = free * args.market_cap / 100 - total_margin
|
||||
print(f'\n✅ Within safety cap. Headroom: {headroom:.2f} USDT')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user