Skip to content

Instantly share code, notes, and snippets.

@Niek
Last active January 23, 2026 16:00
Show Gist options
  • Select an option

  • Save Niek/5e1f9101221fd93175e8df22107d248c to your computer and use it in GitHub Desktop.

Select an option

Save Niek/5e1f9101221fd93175e8df22107d248c to your computer and use it in GitHub Desktop.
Interactive Brokers tracker report
#!/bin/bash
# Configuration
# Run IBeam (https://github.com/Voyz/ibeam) on the same host to keep the Client Portal Gateway logged in
API_BASE="https://localhost:5000/v1/api"
CURL_OPTS="-sk -X GET"
POST_OPTS="-sk -X POST"
# Set locale to ensure printf uses commas for thousands separators
export LC_NUMERIC=en_US.UTF-8
# Colors for UI
GREEN='\033[0;32m'
RED='\033[0;31m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
BOLD='\033[1m'
DIM='\033[2m'
echo -e "${BOLD}${CYAN}IBKR Portfolio Status Report${NC}"
echo -e "${BLUE}========================================================================================================${NC}"
# 1. Fetch all accounts
ACCOUNTS_JSON=$(curl $CURL_OPTS "$API_BASE/portfolio/accounts")
if [[ -z "$ACCOUNTS_JSON" || "$ACCOUNTS_JSON" == "null" ]]; then
echo -e "${RED}Error: Could not fetch accounts. Is the Client Portal Gateway running?${NC}"
exit 1
fi
# Parse account IDs into an array
ACCOUNT_IDS=$(echo "$ACCOUNTS_JSON" | jq -r '.[].accountId')
for ACCT in $ACCOUNT_IDS; do
# Get Account Metadata (Title)
ACCT_TITLE=$(echo "$ACCOUNTS_JSON" | jq -r ".[] | select(.accountId==\"$ACCT\") | .accountTitle")
echo -e "\n${YELLOW}Account: ${BOLD}$ACCT ($ACCT_TITLE)${NC}"
# 2. Get Net Liquidation Value
SUMMARY=$(curl $CURL_OPTS "$API_BASE/portfolio/$ACCT/summary")
NET_LIQ=$(echo "$SUMMARY" | jq -r '.netliquidation.amount // "0"')
CURRENCY=$(echo "$SUMMARY" | jq -r '.netliquidation.currency // ""')
# Format Net Liquidation as a whole number with thousand separators
FORMATTED_LIQ=$(printf "%'d" "${NET_LIQ%.*}" 2>/dev/null || echo "$NET_LIQ")
echo -e "${BOLD}Net Liquidation:${NC} ${GREEN}$FORMATTED_LIQ $CURRENCY${NC}"
echo -e "${BLUE}--------------------------------------------------------------------------------------------------------${NC}"
# 3. Get and Display Positions
printf "${BOLD}%-20s %12s %20s %16s %16s %12s${NC}\n" "Symbol" "Pos" "Value" "Realized" "Unrealized" "Perf %"
POSITIONS=$(curl $CURL_OPTS "$API_BASE/portfolio/$ACCT/positions")
# Iterate through positions
echo "$POSITIONS" | jq -r '.[] |
.contractDesc as $desc |
.position as $pos |
.mktValue as $val |
.currency as $cur |
.realizedPnl as $rpnl |
.unrealizedPnl as $upnl |
(if ($val - $upnl) != 0 then ($upnl / ($val - $upnl)) * 100 else 0 end) as $perc |
"\($desc)|\($pos)|\($val)|\($cur)|\($rpnl)|\($upnl)|\($perc)"' | while IFS='|' read -r DESC POS VAL CUR RPNL UPNL PERC; do
# Determine color for PnL
COLOR=$NC
if (( $(echo "$UPNL > 0" | bc -l) )); then COLOR=$GREEN; fi
if (( $(echo "$UPNL < 0" | bc -l) )); then COLOR=$RED; fi
# Format output
printf "%-20s %'12.2f %'16.2f %-3s ${COLOR}%'16.2f %'16.2f %11.2f%%${NC}\n" \
"$DESC" "$POS" "$VAL" "$CUR" "$RPNL" "$UPNL" "$PERC"
done
# 4. Performance History (Last 7 Days)
echo -e "\n${BOLD}Performance History (Last 7 Days):${NC}"
PERF_DATA=$(curl $POST_OPTS "$API_BASE/pa/performance" -d "{\"acctIds\": [\"$ACCT\"],\"period\":\"7D\"}" -H 'Content-Type: application/json')
if [[ ! -z "$PERF_DATA" && "$PERF_DATA" != "null" ]]; then
printf "%-12s %18s %12s\n" "Date" "NAV ($CURRENCY)" "Return %"
echo -e "${BLUE}---------------------------------------------${NC}"
# Extract Start NAV baseline
START_DATE=$(echo "$PERF_DATA" | jq -r '.nav.data[0].startNAV.date')
START_VAL=$(echo "$PERF_DATA" | jq -r '.nav.data[0].startNAV.val')
if [[ "$START_DATE" != "null" ]]; then
F_START_DATE="${START_DATE:0:4}-${START_DATE:4:2}-${START_DATE:6:2}"
printf "%-12s %'18.2f %12s ${DIM}(Start)${NC}\n" "$F_START_DATE" "$START_VAL" "---"
fi
# Use jq to zip dates, returns, and navs into a processable format
echo "$PERF_DATA" | jq -r '
.nav.dates as $dates |
.cps.data[0].returns as $rets |
.nav.data[0].navs as $navs |
range(0; $dates | length) |
"\($dates[.])|\($navs[.])|\($rets[.])"
' | while IFS='|' read -r P_DATE P_NAV P_RET; do
# Format date from YYYYMMDD to YYYY-MM-DD
F_DATE="${P_DATE:0:4}-${P_DATE:4:2}-${P_DATE:6:2}"
# Format return to percentage
P_RET_PERC=$(echo "$P_RET * 100" | bc -l)
# Color logic for performance
P_COLOR=$NC
if (( $(echo "$P_RET > 0" | bc -l) )); then P_COLOR=$GREEN; fi
if (( $(echo "$P_RET < 0" | bc -l) )); then P_COLOR=$RED; fi
printf "%-12s %'18.2f ${P_COLOR}%11.2f%%${NC}\n" "$F_DATE" "$P_NAV" "$P_RET_PERC"
done
else
echo -e "${RED}No performance data available.${NC}"
fi
done
echo -e "\n${BLUE}========================================================================================================${NC}"
echo -e "${CYAN}Report Complete.${NC}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment