- Complete MVP for tracking Fidelity brokerage account performance - Transaction import from CSV with deduplication - Automatic FIFO position tracking with options support - Real-time P&L calculations with market data caching - Dashboard with timeframe filtering (30/90/180 days, 1 year, YTD, all time) - Docker-based deployment with PostgreSQL backend - React/TypeScript frontend with TailwindCSS - FastAPI backend with SQLAlchemy ORM Features: - Multi-account support - Import via CSV upload or filesystem - Open and closed position tracking - Balance history charting - Performance analytics and metrics - Top trades analysis - Responsive UI design Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
92 lines
2.5 KiB
Python
92 lines
2.5 KiB
Python
"""Option symbol parsing utilities."""
|
|
import re
|
|
from datetime import datetime
|
|
from typing import Optional, NamedTuple
|
|
from decimal import Decimal
|
|
|
|
|
|
class OptionInfo(NamedTuple):
|
|
"""
|
|
Parsed option information.
|
|
|
|
Attributes:
|
|
underlying_symbol: Base ticker symbol (e.g., "AAPL")
|
|
expiration_date: Option expiration date
|
|
option_type: "CALL" or "PUT"
|
|
strike_price: Strike price
|
|
"""
|
|
underlying_symbol: str
|
|
expiration_date: datetime
|
|
option_type: str
|
|
strike_price: Decimal
|
|
|
|
|
|
def parse_option_symbol(option_symbol: str) -> Optional[OptionInfo]:
|
|
"""
|
|
Parse Fidelity option symbol format into components.
|
|
|
|
Fidelity format: -SYMBOL + YYMMDD + C/P + STRIKE
|
|
Example: -AAPL260116C150 = AAPL Call expiring Jan 16, 2026 at $150 strike
|
|
|
|
Args:
|
|
option_symbol: Fidelity option symbol string
|
|
|
|
Returns:
|
|
OptionInfo object if parsing successful, None otherwise
|
|
|
|
Examples:
|
|
>>> parse_option_symbol("-AAPL260116C150")
|
|
OptionInfo(
|
|
underlying_symbol='AAPL',
|
|
expiration_date=datetime(2026, 1, 16),
|
|
option_type='CALL',
|
|
strike_price=Decimal('150')
|
|
)
|
|
|
|
>>> parse_option_symbol("-TSLA251219P500")
|
|
OptionInfo(
|
|
underlying_symbol='TSLA',
|
|
expiration_date=datetime(2025, 12, 19),
|
|
option_type='PUT',
|
|
strike_price=Decimal('500')
|
|
)
|
|
"""
|
|
# Regex pattern: -SYMBOL + YYMMDD + C/P + STRIKE
|
|
# Symbol: one or more uppercase letters
|
|
# Date: 6 digits (YYMMDD)
|
|
# Type: C (call) or P (put)
|
|
# Strike: digits with optional decimal point
|
|
pattern = r"^-([A-Z]+)(\d{6})([CP])(\d+\.?\d*)$"
|
|
|
|
match = re.match(pattern, option_symbol)
|
|
if not match:
|
|
return None
|
|
|
|
symbol, date_str, option_type, strike_str = match.groups()
|
|
|
|
# Parse date (YYMMDD format)
|
|
try:
|
|
# Assume 20XX for years (works until 2100)
|
|
year = 2000 + int(date_str[:2])
|
|
month = int(date_str[2:4])
|
|
day = int(date_str[4:6])
|
|
expiration_date = datetime(year, month, day)
|
|
except (ValueError, IndexError):
|
|
return None
|
|
|
|
# Parse option type
|
|
option_type_full = "CALL" if option_type == "C" else "PUT"
|
|
|
|
# Parse strike price
|
|
try:
|
|
strike_price = Decimal(strike_str)
|
|
except (ValueError, ArithmeticError):
|
|
return None
|
|
|
|
return OptionInfo(
|
|
underlying_symbol=symbol,
|
|
expiration_date=expiration_date,
|
|
option_type=option_type_full,
|
|
strike_price=strike_price,
|
|
)
|