Skip to main content
Glama
knishioka

IB Analytics MCP Server

by knishioka
analyze_performance.py9.86 kB
#!/usr/bin/env python3 """ Interactive Brokers Trading Performance Analysis Analyzes 2025 trading data from IB Flex Query """ import csv from datetime import datetime from collections import defaultdict from typing import Dict, List, Any def parse_csv_sections(filepath: str) -> Dict[str, List[Dict[str, str]]]: """Parse multi-section CSV file from IB Flex Query""" sections = {} current_section = None headers = [] with open(filepath, 'r', encoding='utf-8') as f: reader = csv.reader(f) for row in reader: if not row or not row[0]: continue # Detect new section by first column name if row[0] == 'ClientAccountID': headers = row # Identify section type from subsequent columns if 'Name' in headers: current_section = 'account_info' elif 'StartingCash' in headers: current_section = 'cash_summary' elif 'Quantity' in headers and 'MarkPrice' in headers: current_section = 'positions' elif 'TradeID' in headers: current_section = 'trades' if current_section: sections[current_section] = [] elif current_section and headers: # Parse data row row_dict = dict(zip(headers, row)) sections[current_section].append(row_dict) return sections def analyze_cash_flow(cash_summary: List[Dict]) -> Dict[str, float]: """Analyze cash flow metrics""" if not cash_summary: return {} data = cash_summary[0] return { 'starting_cash': float(data.get('StartingCash', 0)), 'ending_cash': float(data.get('EndingCash', 0)), 'deposits': float(data.get('Deposits', 0)), 'withdrawals': float(data.get('Withdrawals', 0)), 'internal_transfers': float(data.get('InternalTransfers', 0)), 'commissions': float(data.get('CommissionsYTD', 0)), 'dividends': float(data.get('Dividends', 0)), 'broker_interest': float(data.get('BrokerInterest', 0)), 'broker_fees': float(data.get('BrokerFees', 0)), 'net_trades_sales': float(data.get('NetTradesSales', 0)), 'net_trades_purchases': float(data.get('NetTradesPurchases', 0)), 'other_fees': float(data.get('OtherFees', 0)), 'transaction_tax': float(data.get('TransactionTax', 0)), } def analyze_positions(positions: List[Dict]) -> Dict[str, Any]: """Analyze current positions""" if not positions: return {} total_value = 0 total_cost = 0 total_unrealized_pnl = 0 asset_classes = defaultdict(float) position_details = [] for pos in positions: value = float(pos.get('PositionValue', 0)) cost = float(pos.get('CostBasisMoney', 0)) unrealized = float(pos.get('FifoPnlUnrealized', 0)) asset_class = pos.get('AssetClass', 'Unknown') total_value += value total_cost += cost total_unrealized_pnl += unrealized asset_classes[asset_class] += value position_details.append({ 'symbol': pos.get('Symbol', ''), 'description': pos.get('Description', ''), 'asset_class': asset_class, 'quantity': float(pos.get('Quantity', 0)), 'mark_price': float(pos.get('MarkPrice', 0)), 'position_value': value, 'cost_basis': cost, 'unrealized_pnl': unrealized, 'percent_of_nav': float(pos.get('PercentOfNAV', 0)), }) return { 'total_position_value': total_value, 'total_cost_basis': total_cost, 'total_unrealized_pnl': total_unrealized_pnl, 'asset_allocation': dict(asset_classes), 'positions': position_details, } def calculate_performance_metrics(cash_flow: Dict, positions: Dict) -> Dict[str, Any]: """Calculate key performance metrics""" # Net deposits/withdrawals net_deposits = cash_flow.get('deposits', 0) - abs(cash_flow.get('withdrawals', 0)) net_internal_transfers = cash_flow.get('internal_transfers', 0) # Total invested capital total_invested = net_deposits + net_internal_transfers # Current total value (cash + positions) current_cash = cash_flow.get('ending_cash', 0) current_positions_value = positions.get('total_position_value', 0) total_value = current_cash + current_positions_value # Profit/Loss calculations unrealized_pnl = positions.get('total_unrealized_pnl', 0) # Trading activity gross_sales = cash_flow.get('net_trades_sales', 0) gross_purchases = abs(cash_flow.get('net_trades_purchases', 0)) trading_volume = gross_sales + gross_purchases # Costs total_commissions = abs(cash_flow.get('commissions', 0)) total_fees = abs(cash_flow.get('broker_fees', 0)) + abs(cash_flow.get('other_fees', 0)) total_costs = total_commissions + total_fees # Income dividends = cash_flow.get('dividends', 0) interest = cash_flow.get('broker_interest', 0) total_income = dividends + interest # Overall P&L realized_pnl = total_value - total_invested - total_income + total_costs total_pnl = realized_pnl + unrealized_pnl # Return percentage roi_pct = (total_pnl / total_invested * 100) if total_invested != 0 else 0 return { 'total_invested': total_invested, 'current_value': total_value, 'current_cash': current_cash, 'current_positions_value': current_positions_value, 'realized_pnl': realized_pnl, 'unrealized_pnl': unrealized_pnl, 'total_pnl': total_pnl, 'roi_percentage': roi_pct, 'trading_volume': trading_volume, 'gross_sales': gross_sales, 'gross_purchases': gross_purchases, 'total_commissions': total_commissions, 'total_fees': total_fees, 'total_costs': total_costs, 'dividends': dividends, 'interest': interest, 'total_income': total_income, } def generate_report(sections: Dict, metrics: Dict, cash_flow: Dict, positions: Dict): """Generate comprehensive performance report""" print("=" * 80) print("INTERACTIVE BROKERS - 2025 TRADING PERFORMANCE ANALYSIS") print("=" * 80) print() # Account Info if 'account_info' in sections and sections['account_info']: acc = sections['account_info'][0] print(f"Account ID: {acc.get('ClientAccountID', 'N/A')}") print(f"Account Holder: {acc.get('Name', 'N/A')}") print(f"Account Type: {acc.get('AccountType', 'N/A')}") print(f"Base Currency: {acc.get('CurrencyPrimary', 'N/A')}") print() print("-" * 80) print("PORTFOLIO SUMMARY") print("-" * 80) print(f"Total Invested Capital: ${metrics['total_invested']:,.2f}") print(f"Current Cash: ${metrics['current_cash']:,.2f}") print(f"Current Positions Value: ${metrics['current_positions_value']:,.2f}") print(f"Total Portfolio Value: ${metrics['current_value']:,.2f}") print() print("-" * 80) print("PROFIT & LOSS") print("-" * 80) print(f"Realized P&L: ${metrics['realized_pnl']:,.2f}") print(f"Unrealized P&L: ${metrics['unrealized_pnl']:,.2f}") print(f"Total P&L: ${metrics['total_pnl']:,.2f}") print(f"Return on Investment: {metrics['roi_percentage']:.2f}%") print() print("-" * 80) print("TRADING ACTIVITY") print("-" * 80) print(f"Gross Sales: ${metrics['gross_sales']:,.2f}") print(f"Gross Purchases: ${metrics['gross_purchases']:,.2f}") print(f"Total Trading Volume: ${metrics['trading_volume']:,.2f}") print() print("-" * 80) print("COSTS & INCOME") print("-" * 80) print(f"Commissions: -${abs(metrics['total_commissions']):,.2f}") print(f"Fees: -${abs(metrics['total_fees']):,.2f}") print(f"Total Costs: -${abs(metrics['total_costs']):,.2f}") print(f"Dividends: ${metrics['dividends']:,.2f}") print(f"Interest: ${metrics['interest']:,.2f}") print(f"Total Income: ${metrics['total_income']:,.2f}") print() # Asset Allocation if positions.get('asset_allocation'): print("-" * 80) print("ASSET ALLOCATION") print("-" * 80) total_pos_value = positions['total_position_value'] for asset_class, value in positions['asset_allocation'].items(): pct = (value / total_pos_value * 100) if total_pos_value > 0 else 0 print(f"{asset_class:20s} ${value:>12,.2f} ({pct:>5.2f}%)") print() # Current Positions if positions.get('positions'): print("-" * 80) print("CURRENT POSITIONS") print("-" * 80) print(f"{'Symbol':<15} {'Asset':<8} {'Quantity':>12} {'Value':>15} {'Unrealized P&L':>15}") print("-" * 80) for pos in positions['positions']: print(f"{pos['symbol']:<15} {pos['asset_class']:<8} {pos['quantity']:>12,.0f} " f"${pos['position_value']:>13,.2f} ${pos['unrealized_pnl']:>13,.2f}") print() print("=" * 80) def main(): filepath = '/Users/ken/Developer/private/ib-sec/trades_2025.csv' # Parse CSV sections = parse_csv_sections(filepath) # Analyze data cash_flow = analyze_cash_flow(sections.get('cash_summary', [])) positions = analyze_positions(sections.get('positions', [])) metrics = calculate_performance_metrics(cash_flow, positions) # Generate report generate_report(sections, metrics, cash_flow, positions) if __name__ == '__main__': main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/knishioka/ib-sec-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server