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
"""Position data model"""
from datetime import date
from decimal import Decimal
from pydantic import BaseModel, Field, field_validator
from ib_sec_mcp.models.trade import AssetClass
class Position(BaseModel):
"""Current position"""
account_id: str = Field(..., description="Account ID")
symbol: str = Field(..., description="Trading symbol")
description: str | None = Field(None, description="Security description")
asset_class: AssetClass = Field(..., description="Asset class")
cusip: str | None = Field(None, description="CUSIP")
isin: str | None = Field(None, description="ISIN")
quantity: Decimal = Field(..., description="Position quantity")
multiplier: Decimal = Field(Decimal("1"), description="Contract multiplier")
mark_price: Decimal = Field(..., description="Current market price")
position_value: Decimal = Field(..., description="Current position value")
average_cost: Decimal = Field(..., description="Average cost basis")
cost_basis: Decimal = Field(..., description="Total cost basis")
unrealized_pnl: Decimal = Field(Decimal("0"), description="Unrealized P&L")
realized_pnl: Decimal = Field(Decimal("0"), description="Realized P&L to date")
currency: str = Field("USD", description="Currency")
fx_rate_to_base: Decimal = Field(Decimal("1.0"), description="FX rate to base currency")
position_date: date = Field(..., description="Position as of date")
# Bond-specific fields
coupon_rate: Decimal | None = Field(None, description="Coupon rate (for bonds)")
maturity_date: date | None = Field(None, description="Maturity date (for bonds)")
ytm: Decimal | None = Field(None, description="Yield to maturity (for bonds)")
duration: Decimal | None = Field(None, description="Duration (for bonds)")
@field_validator("quantity", "mark_price", "position_value", mode="before")
@classmethod
def convert_to_decimal(cls, v: int | float | str | Decimal) -> Decimal:
"""Convert numeric fields to Decimal"""
if isinstance(v, (int, float, str)):
return Decimal(str(v))
return v
@property
def market_value(self) -> Decimal:
"""Current market value (alias for position_value)"""
return self.position_value
@property
def total_pnl(self) -> Decimal:
"""Total P&L (realized + unrealized)"""
return self.realized_pnl + self.unrealized_pnl
@property
def pnl_percentage(self) -> Decimal:
"""P&L as percentage of cost basis"""
if self.cost_basis == 0:
return Decimal("0")
return (self.unrealized_pnl / self.cost_basis) * 100
@property
def is_long(self) -> bool:
"""Check if position is long"""
return self.quantity > 0
@property
def is_short(self) -> bool:
"""Check if position is short"""
return self.quantity < 0
@property
def is_bond(self) -> bool:
"""Check if position is a bond"""
return self.asset_class == AssetClass.BOND
class Config:
"""Pydantic config"""
json_encoders = {
date: lambda v: v.isoformat(),
Decimal: lambda v: str(v),
}