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
"""Performance analyzer"""
from collections import defaultdict
from decimal import Decimal
from typing import Any
from ib_sec_mcp.analyzers.base import AnalysisResult, BaseAnalyzer
from ib_sec_mcp.core.calculator import PerformanceCalculator
from ib_sec_mcp.models.trade import Trade
class PerformanceAnalyzer(BaseAnalyzer):
"""
Analyze trading performance
Calculates metrics like win rate, profit factor, ROI, etc.
"""
def analyze(self) -> AnalysisResult:
"""
Run performance analysis
Returns:
AnalysisResult with performance metrics
"""
trades = self.get_trades()
positions = self.get_positions()
# Overall metrics
total_realized_pnl: Decimal = sum((t.fifo_pnl_realized for t in trades), Decimal("0"))
total_unrealized_pnl: Decimal = sum((p.unrealized_pnl for p in positions), Decimal("0"))
total_pnl = total_realized_pnl + total_unrealized_pnl
total_commissions: Decimal = sum((abs(t.ib_commission) for t in trades), Decimal("0"))
total_volume: Decimal = sum((abs(t.trade_money) for t in trades), Decimal("0"))
# Win rate and profit factor
win_rate, winning_trades, losing_trades = PerformanceCalculator.calculate_win_rate(trades)
profit_factor = PerformanceCalculator.calculate_profit_factor(trades)
# Average win/loss
wins = [t.fifo_pnl_realized for t in trades if t.fifo_pnl_realized > 0]
losses = [abs(t.fifo_pnl_realized) for t in trades if t.fifo_pnl_realized < 0]
avg_win: Decimal = sum(wins, Decimal("0")) / len(wins) if wins else Decimal("0")
avg_loss: Decimal = sum(losses, Decimal("0")) / len(losses) if losses else Decimal("0")
# Risk/reward
risk_reward = PerformanceCalculator.calculate_risk_reward_ratio(avg_win, avg_loss)
# Largest win/loss
largest_win = max(wins) if wins else Decimal("0")
largest_loss = max(losses) if losses else Decimal("0")
# Commission rate
commission_rate = PerformanceCalculator.calculate_commission_rate(
total_commissions, total_volume
)
# Trading frequency
if trades:
first_trade_date = min(t.trade_date for t in trades)
last_trade_date = max(t.trade_date for t in trades)
trading_days = (last_trade_date - first_trade_date).days + 1
trades_per_day = (
Decimal(len(trades)) / Decimal(trading_days) if trading_days > 0 else Decimal("0")
)
else:
first_trade_date = None
last_trade_date = None
trading_days = 0
trades_per_day = Decimal("0")
# By symbol analysis
by_symbol = self._analyze_by_symbol(trades)
return self._create_result(
# Overall metrics
total_trades=len(trades),
total_positions=len(positions),
total_realized_pnl=str(total_realized_pnl),
total_unrealized_pnl=str(total_unrealized_pnl),
total_pnl=str(total_pnl),
# Win metrics
winning_trades=winning_trades,
losing_trades=losing_trades,
win_rate=str(win_rate),
profit_factor=str(profit_factor),
# Average metrics
avg_win=str(avg_win),
avg_loss=str(avg_loss),
risk_reward_ratio=str(risk_reward),
# Extreme values
largest_win=str(largest_win),
largest_loss=str(largest_loss),
# Cost metrics
total_commissions=str(total_commissions),
total_volume=str(total_volume),
commission_rate=str(commission_rate),
# Trading frequency
first_trade_date=first_trade_date.isoformat() if first_trade_date else None,
last_trade_date=last_trade_date.isoformat() if last_trade_date else None,
trading_days=trading_days,
trades_per_day=str(trades_per_day),
# By symbol
by_symbol=by_symbol,
)
def _analyze_by_symbol(self, trades: list[Trade]) -> dict[str, dict[str, Any]]:
"""Analyze performance by symbol"""
by_symbol: dict[str, list[Trade]] = defaultdict(list)
for trade in trades:
by_symbol[trade.symbol].append(trade)
results = {}
for symbol, symbol_trades in by_symbol.items():
realized_pnl = sum(t.fifo_pnl_realized for t in symbol_trades)
commissions = sum(abs(t.ib_commission) for t in symbol_trades)
volume = sum(abs(t.trade_money) for t in symbol_trades)
win_rate, wins, losses = PerformanceCalculator.calculate_win_rate(symbol_trades)
profit_factor = PerformanceCalculator.calculate_profit_factor(symbol_trades)
# Quantity analysis
buys = [t for t in symbol_trades if t.is_buy]
sells = [t for t in symbol_trades if t.is_sell]
qty_bought = sum(abs(t.quantity) for t in buys)
qty_sold = sum(abs(t.quantity) for t in sells)
avg_buy_price = sum(t.trade_price for t in buys) / len(buys) if buys else Decimal("0")
avg_sell_price = (
sum(t.trade_price for t in sells) / len(sells) if sells else Decimal("0")
)
results[symbol] = {
"trade_count": len(symbol_trades),
"buy_count": len(buys),
"sell_count": len(sells),
"qty_bought": str(qty_bought),
"qty_sold": str(qty_sold),
"avg_buy_price": str(avg_buy_price),
"avg_sell_price": str(avg_sell_price),
"realized_pnl": str(realized_pnl),
"commissions": str(commissions),
"volume": str(volume),
"win_rate": str(win_rate),
"profit_factor": str(profit_factor),
"winning_trades": wins,
"losing_trades": losses,
}
return results