h3i(ldZddlZddlmZmZmZmZddlmZeje Z GddZ y)zy Transaction Management Module. Handles BUY, SELL, and DIVIDEND transactions. Updates portfolio holdings automatically. N)ListDictTupleOptional)datetimeceZdZdZdZ ddedededededd f d Z ddedededededeeeff d Z dded edededd f d Z dde ede ede e fdZdededededef dZdedd fdZdde edefdZdde edefdZy )TransactionManagerz4Manages portfolio transactions and updates holdings.c ||_||_y)z Initialize transaction manager. Args: db_manager: DBManager instance portfolio: Portfolio instance N) db_manager portfolio)selfr r s B/mnt/ssd/data/python-lab/portfolio-manager/src/core/transaction.py__init__zTransactionManager.__init__s%"tickerquantitypricedatenotesreturnNc @||z}|jj|}|r|d}|d} ||z} |j|| ||} |jj|| | |jj || | t jd|d|d| d| n9t jd|d |jj||d || |jj|d ||||| t jd|d|d|d|y)aK Process a BUY transaction. Updates holding quantity and average price using weighted average. Args: ticker: Stock ticker quantity: Number of shares bought price: Price per share date: Transaction date (YYYY-MM-DD) notes: Optional notes r avg_price)rrzUpdated holding :  ->  @ z)BUY transaction for non-existent holding z, creating new holdingStock)rname asset_typerrBUYrtx_typerrramountrzProcessed BUY:   = N) r get_holdingcalculate_new_avg_priceupdate_holdingr update_holding_quantityloggerinfowarning add_holdingadd_transaction) r rrrrrr" holding_dataold_qty old_avg_pricenew_qty new_avg_prices r process_buyzTransactionManager.process_buysT(E!226: ":.G(5M(G 88%M OO * * ' +  NN 2 267M R KK*6("WIT'#m_] ^ NNFvhNde f NN & &"! '  '' (   ofXQxjE7#fXNOrc||z}|jj|}|std|d|d}|d} ||kDrtd|d|d|d|| z} || z } | dkDr| | z d znd } ||z } | dkDrY|jj|| |jj || | t jd |d |d| n|jj||jjDcgc]}|j|k7s|c}|j_ |jjt jd|d|jj|d||||d| dd| dd|jt jd|d|d|d|d| dd | | fScc}w)a Process a SELL transaction. Updates holding quantity and calculates realized P&L. Args: ticker: Stock ticker quantity: Number of shares sold price: Price per share date: Transaction date notes: Optional notes Returns: Tuple of (realized_pnl_amount, realized_pnl_percent) Raises: ValueError: If insufficient quantity to sell z Cannot sell z: holding not foundrrz shares of z: only z availablerd)rz Partial sell rrzComplete sell z: holding removedSELLzRealized P&L: z+.2f (z+.1fz%). r zProcessed SELL: r#rr$z (P&L: ))r r% ValueErrorr'r r(r)r*delete_holdingholdingsrcalculate_weightsr-strip)r rrrrrr"r.r/r cost_basis realized_pnlrealized_pnl_pctr1hs r process_sellzTransactionManager.process_selles 4E!226: |F83FGH Hz* - g |H:[PWyXbcd d )  * @JQL:5z8TransactionManager.delete_transaction..sHag.G1Hs NzDeleting transaction rtransaction_typer#rz* (manual holding adjustment may be needed))r rInextr)r+delete_transaction)r rS transactionstxs ` rr]z%TransactionManager.delete_transactions|779 HlH$ O NN2>2B"RHZE[D\\]^`ai^j]klVW X **>:rc|jj|d}td|D}tj d|d|xsdd|S)z Get total dividends received. Args: ticker: Filter by ticker (None for all) Returns: Total dividend amount rErHc3&K|] }|d yw)r"NrW)rXr_s rrZz9TransactionManager.get_total_dividends..#s8RBxL8szTotal dividends: (ticker=allr9)r rIsumr)rO)r rr^totals rget_total_dividendsz&TransactionManager.get_total_dividendssS77vz7Z 8<88 (y58IKL rc|jj|d}d}|D]^}|jdd}d|vs |jddjdd j }t |}||z }`tjd |d|xsdd|S#t tf$r!tjd |d d |YwxYw)a  Get total realized P&L from SELL transactions. Note: This parses P&L from transaction notes (format: "Realized P&L: +123.45") Args: ticker: Filter by ticker (None for all) Returns: Total realized P&L r7rHr6rz Realized P&L:(rz%Failed to parse P&L from transaction rVrzTotal realized P&L: rbrcr9) r rIgetsplitr>floatr: IndexErrorr)r+rO)r rr^ total_pnlr_rpnl_strpnls rget_realized_pnlz#TransactionManager.get_realized_pnl(s77vv7V   `BFF7B'E%'`#kk/:1=CCCHKQQSG.C$I `  +I;i%?PPQRS #J/`NN%J2d8*TVW\V]#^_`sAB%%-CC)rh)NN)N)__name__ __module__ __qualname____doc__rstrrmr3rrCrFrrrrJr&intr]rfrrrWrrr r s> #" FPFPFP FP  FP  FP FP\ I0I0I0 I0  I0  I0 ue| I0` "H"H"H "H  "H  "HL!%!%P P#P d P"     @;;;&(3-5 x}rr ) rvloggingtypingrrrrr getLoggerrsr)r rWrrr|s6..   8 $uur