
Bybit Account
- 34 installs
- 21 repo stars
- Updated August 3, 2026
- starchild-ai-agent/official-skills
Helps with ai & agent building tasks during AI-assisted development.
About
bybit-account is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- bybit-account
- AI & Agent Building
- AI-coding skill
Bybit Account by the numbers
- 34 all-time installs (skills.sh)
- +4 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #8,855 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/starchild-ai-agent/official-skills --skill bybit-accountAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 34 |
|---|---|
| repo stars | ★ 21 |
| Last updated | August 3, 2026 |
| Repository | starchild-ai-agent/official-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Bybit Account (Read-Only)
Read-only Bybit account tracker built on the official pybit library. Use it for account tracking, daily/weekly reports, risk alerts, and cashflow attribution.
How to Get a Bybit API Key (Read-Only)
1. Sign in at bybit.com, top-right avatar → API
- Direct link: https://www.bybit.com/app/user/api-management
2. Create New Key → System-generated API Keys 3. Fill the form:
- API key usage: API Transaction
- Name: anything
- Permissions: under Read-Only tick
Wallet,Positions,Trade (read only). Do not enable Withdraw or any write permission - IP whitelist: leave empty
4. Complete 2FA → submit 5. Copy API Key + Secret Key immediately (Secret is shown only once) 6. Set them into this skill's environment variables
Reference: Bybit official tutorial
Prerequisites
1) API key
In Bybit API Management create a key with Read only.
2) Environment variables
BYBIT_RO_API_KEY=...
BYBIT_RO_SECRET=...3) Geo restriction (required)
Bybit geo-blocks server IPs. Scripts default to the SC internal HK proxy:
HK_PROXY = "http://hk:x@sc-vpn.internal:8080"Injection style: session.client.proxies.update({'http': HK, 'https': HK}). Do not pass HTTP(proxies=...) — pybit doesn't accept that constructor argument.
Important: FUND account is separate
Bybit v5's get_wallet_balance only supports `accountType=UNIFIED`. The Funding (FUND) account balance must be fetched via get_coins_balance(accountType='FUND'). The summary and portfolio_snapshot actions automatically query both and merge.
For positions, linear requires per-settleCoin queries (USDT / USDC) and inverse uses BTC. The summary and perp_risk actions automatically scan all three settlement coins.
Scripts
python3 skills/bybit-account/scripts/bybit_account.py <action> [options]
python3 skills/bybit-account/scripts/account_scenarios.py <scenario> [options]Actions
summary: one-shot summary (UNIFIED + FUND + multi-settle positions)wallet_balance/coin_balance/funding_balance/account_info/fee_rates/collateral_infopositions/open_orders/order_history/executionsdeposits/withdrawals/internal_transfers/universal_transferstransaction_log/borrow_history/server_time
Scenarios
portfolio_snapshot: full account snapshot (wallet + positions)perp_risk: derivatives risk monitoring (IM / MM ratio + unrealized loss)cashflow: deposits + withdrawals + transfers + transaction logtrading_activity: recent fills activity by category
Common usage
python3 skills/bybit-account/scripts/bybit_account.py summary
python3 skills/bybit-account/scripts/account_scenarios.py portfolio_snapshot
python3 skills/bybit-account/scripts/account_scenarios.py perp_risk --loss-threshold 5000
python3 skills/bybit-account/scripts/account_scenarios.py cashflow --limit 100
python3 skills/bybit-account/scripts/account_scenarios.py trading_activity --categories spot,linearImportant parameters
--account-type:UNIFIED(default) /CONTRACT/SPOT/FUND/INVESTMENT/OPTION--category:spot/linear/inverse/option--settle: settle coin forlinear/inversepositions (defaultUSDT)
Notes
- pybit's
HTTPconstructor does not acceptproxies; you must inject viaclient.proxiesafter construction. linearpositions require eithersettleCoinorsymbol.- Use time-windowed pagination for high-volume fills.
#!/usr/bin/env python3
"""
Common Bybit account analysis scenarios (read-only).
Generates structured JSON for tracking/reporting/alerts.
"""
import os, json, argparse
from datetime import datetime, timezone
from collections import defaultdict
from dotenv import load_dotenv
load_dotenv('/data/workspace/.env')
from pybit.unified_trading import HTTP
HK_PROXY = 'http://hk:x@sc-vpn.internal:8080'
def session():
s = HTTP(testnet=False,
api_key=os.environ.get('BYBIT_RO_API_KEY', ''),
api_secret=os.environ.get('BYBIT_RO_SECRET', ''))
s.client.proxies.update({"http": HK_PROXY, "https": HK_PROXY})
return s
def print_json(d): print(json.dumps(d, ensure_ascii=False, indent=2))
def scenario_portfolio_snapshot(args):
"""Scenario 1: full portfolio snapshot (UNIFIED wallet + FUND + positions across categories)"""
s = session()
# UNIFIED wallet
bal = s.get_wallet_balance(accountType='UNIFIED')
wlist = bal['result']['list'][0] if bal['result'].get('list') else {}
coins = [c for c in wlist.get('coin', []) if float(c.get('walletBalance', 0) or 0) > 0]
# FUND account — get_wallet_balance only supports UNIFIED, must use get_coins_balance
fund_rows = []
try:
fr = s.get_coins_balance(accountType='FUND')
fund_rows = [c for c in fr.get('result', {}).get('balance', []) if float(c.get('walletBalance', 0) or 0) > 0]
fund_rows = sorted(fund_rows, key=lambda x: -float(x.get('walletBalance', 0) or 0))
except Exception:
pass
# Positions across linear (USDT/USDC) + inverse (BTC)
open_pos = []
for cat, sc in [('linear', 'USDT'), ('linear', 'USDC'), ('inverse', 'BTC')]:
try:
r = s.get_positions(category=cat, settleCoin=sc)
for p in r.get('result', {}).get('list', []):
if float(p.get('size', 0) or 0) != 0:
p['_category'] = cat
open_pos.append(p)
except Exception:
pass
out = {
'scenario': 'portfolio_snapshot',
'timestamp_utc': datetime.now(timezone.utc).isoformat(),
'unified_wallet': {
'totalEquity': wlist.get('totalEquity'),
'totalWalletBalance': wlist.get('totalWalletBalance'),
'totalAvailableBalance': wlist.get('totalAvailableBalance'),
'accountIMRate': wlist.get('accountIMRate'),
'accountMMRate': wlist.get('accountMMRate'),
'coins_nonzero_count': len(coins),
'coins_nonzero': sorted(coins, key=lambda x: -float(x.get('usdValue', 0) or 0)),
},
'funding_account': {
'nonzero_count': len(fund_rows),
'balances': fund_rows,
},
'open_positions_count': len(open_pos),
'open_positions': open_pos,
}
print_json(out)
def scenario_perp_risk(args):
"""Scenario 2: perpetual risk monitoring"""
s = session()
bal = s.get_wallet_balance(accountType='UNIFIED')
wlist = bal['result']['list'][0] if bal['result'].get('list') else {}
im = float(wlist.get('accountIMRate', 0) or 0)
mm = float(wlist.get('accountMMRate', 0) or 0)
open_pos = []
upl = 0.0
for cat, sc in [('linear', 'USDT'), ('linear', 'USDC'), ('inverse', 'BTC')]:
try:
r = s.get_positions(category=cat, settleCoin=sc)
for p in r.get('result', {}).get('list', []):
if float(p.get('size', 0) or 0) != 0:
p['_category'] = cat
open_pos.append(p)
upl += float(p.get('unrealisedPnl', 0) or 0)
except Exception:
pass
out = {
'scenario': 'perp_risk',
'timestamp_utc': datetime.now(timezone.utc).isoformat(),
'account_im_rate': im,
'account_mm_rate': mm,
'total_unrealized_pnl': upl,
'risk_alert': {
'mm_rate_above_0_6': mm > 0.6,
'im_rate_above_0_8': im > 0.8,
'unrealized_loss_gt_threshold': upl < -abs(float(args.loss_threshold)),
},
'positions': open_pos,
}
print_json(out)
def scenario_cashflow(args):
"""Scenario 3: deposits/withdrawals/transfers + transaction log"""
s = session()
def safe(fn, **kw):
try:
return fn(**kw), None
except Exception as e:
return None, str(e)[:120]
dep, dep_err = safe(s.get_deposit_records)
wd, wd_err = safe(s.get_withdrawal_records)
it, it_err = safe(s.get_internal_transfer_records)
ut, ut_err = safe(s.get_universal_transfer_records)
tx, tx_err = safe(s.get_transaction_log)
def rows(r): return r.get('result', {}).get('list', []) if r else []
by_type = defaultdict(lambda: {'count': 0, 'sum': 0.0})
for t in rows(tx):
typ = t.get('type', 'UNKNOWN')
by_type[typ]['count'] += 1
try:
by_type[typ]['sum'] += float(t.get('change', 0) or 0)
except (TypeError, ValueError):
pass
out = {
'scenario': 'cashflow',
'timestamp_utc': datetime.now(timezone.utc).isoformat(),
'deposit_count': len(rows(dep)),
'withdraw_count': len(rows(wd)),
'internal_transfer_count': len(rows(it)),
'universal_transfer_count': len(rows(ut)),
'tx_log_count': len(rows(tx)),
'tx_log_by_type': dict(by_type),
'deposits': rows(dep)[:args.limit],
'withdraws': rows(wd)[:args.limit],
'errors': {
'deposit': dep_err, 'withdraw': wd_err,
'internal_transfer': it_err, 'universal_transfer': ut_err, 'tx_log': tx_err,
}
}
print_json(out)
def scenario_trading_activity(args):
"""Scenario 4: recent executions (fills) by category"""
s = session()
cats = [c.strip() for c in (args.categories or 'spot,linear').split(',') if c.strip()]
out_rows = []
for cat in cats:
try:
r = s.get_executions(category=cat, limit=args.limit or 100)
fills = r.get('result', {}).get('list', [])
except Exception as e:
out_rows.append({'category': cat, 'error': str(e)[:120]})
continue
by_sym = defaultdict(lambda: {'count': 0, 'buy_qty': 0.0, 'sell_qty': 0.0, 'buy_quote': 0.0, 'sell_quote': 0.0})
for f in fills:
sym = f.get('symbol')
qty = float(f.get('execQty', 0) or 0)
quote = float(f.get('execValue', 0) or 0)
by_sym[sym]['count'] += 1
if (f.get('side') or '').lower() == 'buy':
by_sym[sym]['buy_qty'] += qty
by_sym[sym]['buy_quote'] += quote
else:
by_sym[sym]['sell_qty'] += qty
by_sym[sym]['sell_quote'] += quote
out_rows.append({'category': cat, 'fills_total': len(fills), 'symbols': dict(by_sym)})
out = {
'scenario': 'trading_activity',
'timestamp_utc': datetime.now(timezone.utc).isoformat(),
'rows': out_rows,
}
print_json(out)
SCENARIOS = {
'portfolio_snapshot': scenario_portfolio_snapshot,
'perp_risk': scenario_perp_risk,
'cashflow': scenario_cashflow,
'trading_activity': scenario_trading_activity,
}
if __name__ == '__main__':
p = argparse.ArgumentParser(description='Bybit account analysis scenarios (read-only)')
p.add_argument('scenario', choices=SCENARIOS.keys())
p.add_argument('--limit', type=int, default=100)
p.add_argument('--loss-threshold', type=float, default=5000.0)
p.add_argument('--categories', default='', help='comma-separated, e.g. spot,linear,inverse')
args = p.parse_args()
SCENARIOS[args.scenario](args)
#!/usr/bin/env python3
"""
Bybit Read-Only Account Query Tool
Uses official pybit library with HK VPN proxy.
Supports Unified Trading Account (spot/derivatives/options).
"""
import os, sys, json, argparse
from dotenv import load_dotenv
load_dotenv("/data/workspace/.env")
from pybit.unified_trading import HTTP
HK_PROXY = "http://hk:x@sc-vpn.internal:8080"
def session():
s = HTTP(testnet=False,
api_key=os.environ.get("BYBIT_RO_API_KEY", ""),
api_secret=os.environ.get("BYBIT_RO_SECRET", ""))
s.client.proxies.update({"http": HK_PROXY, "https": HK_PROXY})
return s
def fmt(d): print(json.dumps(d, ensure_ascii=False, indent=2))
# ── Actions ────────────────────────────────────────────────────────────────────
def wallet_balance(args):
"""统一账户钱包余额(含每币种权益)"""
kw = {'accountType': (args.account_type or 'UNIFIED').upper()}
if args.asset: kw['coin'] = args.asset.upper()
fmt(session().get_wallet_balance(**kw))
def coin_balance(args):
"""指定币种的精确余额"""
fmt(session().get_coin_balance(
accountType=(args.account_type or 'UNIFIED').upper(),
coin=(args.asset or 'USDT').upper()))
def funding_balance(args):
"""资金账户(FUND)所有币种余额。
注意:get_wallet_balance 只支持 UNIFIED,FUND 必须用 get_coins_balance。"""
s = session()
r = s.get_coins_balance(accountType=(args.account_type or 'FUND').upper())
rows = r.get('result', {}).get('balance', [])
nonzero = [c for c in rows if float(c.get('walletBalance', 0) or 0) > 0]
fmt({
'accountType': (args.account_type or 'FUND').upper(),
'nonzero_count': len(nonzero),
'balances': sorted(nonzero, key=lambda x: -float(x.get('walletBalance', 0) or 0)),
})
def account_info(args):
"""账户配置(统一账户模式、保证金模式等)"""
fmt(session().get_account_info())
def fee_rates(args):
"""手续费率(默认 linear 永续合约)"""
kw = {'category': (args.category or 'linear')}
if args.symbol: kw['symbol'] = args.symbol.upper()
fmt(session().get_fee_rates(**kw))
def collateral_info(args):
"""抵押品信息(统一账户每币种抵押率)"""
fmt(session().get_collateral_info())
def positions(args):
"""合约持仓"""
cat = (args.category or 'linear')
kw = {'category': cat}
if args.symbol:
kw['symbol'] = args.symbol.upper()
else:
# linear/inverse 必须传 symbol/settleCoin/baseCoin 之一
kw['settleCoin'] = (args.settle or 'USDT').upper()
fmt(session().get_positions(**kw))
def open_orders(args):
"""当前挂单"""
cat = (args.category or 'linear')
kw = {'category': cat}
if args.symbol: kw['symbol'] = args.symbol.upper()
elif cat in ('linear', 'inverse'):
kw['settleCoin'] = (args.settle or 'USDT').upper()
fmt(session().get_open_orders(**kw))
def order_history(args):
"""历史订单"""
fmt(session().get_order_history(
category=(args.category or 'linear'),
symbol=(args.symbol or '').upper() or None,
limit=args.limit or 50))
def executions(args):
"""成交明细"""
fmt(session().get_executions(
category=(args.category or 'linear'),
symbol=(args.symbol or '').upper() or None,
limit=args.limit or 50))
def deposits(args):
"""充值记录"""
fmt(session().get_deposit_records())
def withdrawals(args):
"""提币记录"""
fmt(session().get_withdrawal_records())
def internal_transfers(args):
"""内部转账记录(账户间)"""
fmt(session().get_internal_transfer_records())
def universal_transfers(args):
"""子账户间转账记录"""
fmt(session().get_universal_transfer_records())
def transaction_log(args):
"""统一账户交易流水(资金费/手续费/盈亏)"""
fmt(session().get_transaction_log())
def borrow_history(args):
"""借币历史(统一账户保证金借币)"""
fmt(session().get_borrow_history())
def server_time(args):
"""服务器时间(公共,用于诊断网络)"""
fmt(session().get_server_time())
def summary(args):
"""一键汇总:UNIFIED 钱包 + FUND 资金账户 + 持仓(USDT/USDC/BTC) + 挂单"""
s = session()
# UNIFIED wallet
bal = s.get_wallet_balance(accountType='UNIFIED')
if bal.get('retCode') == 0 and bal['result'].get('list'):
wlist = bal['result']['list'][0]
coins = [c for c in wlist.get('coin', []) if float(c.get('walletBalance', 0) or 0) > 0]
unified = {
'totalEquity': wlist.get('totalEquity'),
'totalWalletBalance': wlist.get('totalWalletBalance'),
'totalAvailableBalance': wlist.get('totalAvailableBalance'),
'accountIMRate': wlist.get('accountIMRate'),
'accountMMRate': wlist.get('accountMMRate'),
'coins_nonzero': sorted(coins, key=lambda x: -float(x.get('usdValue', 0) or 0)),
}
else:
unified = bal
# FUND account (separate API)
fund_acct = []
try:
fr = s.get_coins_balance(accountType='FUND')
rows = fr.get('result', {}).get('balance', [])
fund_acct = sorted(
[c for c in rows if float(c.get('walletBalance', 0) or 0) > 0],
key=lambda x: -float(x.get('walletBalance', 0) or 0)
)
except Exception as e:
fund_acct = {'error': str(e)[:200]}
# Positions across linear (USDT/USDC) + inverse (BTC)
open_pos = []
for cat, sc in [('linear', 'USDT'), ('linear', 'USDC'), ('inverse', 'BTC')]:
try:
r = s.get_positions(category=cat, settleCoin=sc)
for p in r.get('result', {}).get('list', []):
if float(p.get('size', 0) or 0) != 0:
p['_category'] = cat
open_pos.append(p)
except Exception:
pass
orders_linear = s.get_open_orders(category='linear', settleCoin='USDT')
spot_orders = s.get_open_orders(category='spot')
fmt({
'unified_wallet': unified,
'funding_account': fund_acct,
'open_positions': open_pos,
'open_orders_linear': orders_linear.get('result', {}).get('list', []),
'open_orders_spot': spot_orders.get('result', {}).get('list', []),
})
ACTIONS = {
'summary': summary,
'wallet_balance': wallet_balance,
'coin_balance': coin_balance,
'funding_balance': funding_balance,
'account_info': account_info,
'fee_rates': fee_rates,
'collateral_info': collateral_info,
'positions': positions,
'open_orders': open_orders,
'order_history': order_history,
'executions': executions,
'deposits': deposits,
'withdrawals': withdrawals,
'internal_transfers': internal_transfers,
'universal_transfers': universal_transfers,
'transaction_log': transaction_log,
'borrow_history': borrow_history,
'server_time': server_time,
}
if __name__ == "__main__":
p = argparse.ArgumentParser(description='Bybit Read-Only Account Tool')
p.add_argument('action', choices=ACTIONS.keys())
p.add_argument('--asset', default=None, help='Coin, e.g. USDT, BTC')
p.add_argument('--symbol', default=None, help='Symbol, e.g. BTCUSDT')
p.add_argument('--account-type', default=None, dest='account_type', help='UNIFIED/CONTRACT/SPOT/FUND/INVESTMENT/OPTION')
p.add_argument('--category', default=None, help='spot/linear/inverse/option')
p.add_argument('--settle', default=None, help='Settle coin for linear/inverse')
p.add_argument('--limit', type=int, default=None)
args = p.parse_args()
try:
ACTIONS[args.action](args)
except Exception as e:
print(json.dumps({'error': str(e)}, ensure_ascii=False))
sys.exit(1)