src/tzutrader/portfolio

Search:
Group by:

Portfolio module for tzutrader - Position and portfolio management

This module provides portfolio tracking, position management, and performance analytics for trading strategies.

Features:

  • Cash and position tracking
  • Buy/sell order execution with commissions
  • Portfolio valuation and metrics
  • Performance calculations (returns, Sharpe ratio, drawdown)
  • Transaction history
  • Risk management helpers

Types

PerformanceMetrics = object
  totalReturn*: float64      ## Total return percentage
  annualizedReturn*: float64 ## Annualized return percentage
  sharpeRatio*: float64      ## Sharpe ratio (risk-adjusted return)
  maxDrawdown*: float64      ## Maximum drawdown percentage
  winRate*: float64          ## Percentage of winning trades
  totalTrades*: int          ## Total number of trades
  winningTrades*: int        ## Number of winning trades
  losingTrades*: int         ## Number of losing trades
  avgWin*: float64           ## Average winning trade
  avgLoss*: float64          ## Average losing trade
  profitFactor*: float64     ## Ratio of gross profit to gross loss
Portfolio performance metrics
Portfolio = ref object
  initialCash*: float64      ## Starting cash
  cash*: float64             ## Current available cash
  positions*: Table[string, PositionInfo] ## Open positions by symbol
  transactions*: seq[Transaction] ## Transaction history
  commission*: float64       ## Commission rate (0.001 = 0.1%)
  minCommission*: float64    ## Minimum commission per trade
  totalRealizedPnL*: float64 ## Total realized P&L from all closed trades
Portfolio with cash and position tracking
PositionInfo = object
  symbol*: string            ## Symbol/ticker
  side*: PositionSide        ## Long, Short, or Flat
  quantity*: float64         ## Number of shares/units
  entryPrice*: float64       ## Average entry price
  entryTime*: int64          ## First entry timestamp
  currentPrice*: float64     ## Latest market price
  unrealizedPnL*: float64    ## Unrealized profit/loss
  realizedPnL*: float64      ## Realized profit/loss from partial closes
Information about an open position
PositionSide = enum
  Long = "LONG",            ## Long position (own the asset)
  Short = "SHORT",          ## Short position (borrowed/sold)
  Flat = "FLAT"              ## No position
Position direction

Procs

proc `$`(m: PerformanceMetrics): string {....raises: [], tags: [], forbids: [].}
String representation of PerformanceMetrics
proc `$`(p: Portfolio): string {....raises: [KeyError], tags: [], forbids: [].}
String representation of Portfolio
proc `$`(pos: PositionInfo): string {....raises: [], tags: [], forbids: [].}
String representation of Position
proc buy(p: Portfolio; symbol: string; quantity: float64; price: float64;
         timestamp: int64 = 0): bool {....raises: [KeyError], tags: [TimeEffect],
                                       forbids: [].}

Execute a buy order (open or add to long position)

Args: symbol: Symbol to buy quantity: Number of shares (must be positive) price: Price per share timestamp: Optional transaction timestamp (uses current time if 0)

Returns: True if order executed successfully, False if insufficient cash

proc calculateCommission(p: Portfolio; quantity: float64; price: float64): float64 {.
    ...raises: [], tags: [], forbids: [].}

Calculate commission for a trade

Args: quantity: Number of shares/units price: Price per share

Returns: Commission amount

proc calculatePerformance(p: Portfolio; currentPrices: Table[string, float64] = initTable[
    string, float64](); riskFreeRate: float64 = 0.02): PerformanceMetrics {.
    ...raises: [KeyError], tags: [], forbids: [].}

Calculate comprehensive performance metrics

Args: currentPrices: Current market prices for open positions riskFreeRate: Risk-free rate for Sharpe ratio (default 2%)

Returns: Performance metrics

proc closePosition(p: Portfolio; symbol: string; price: float64;
                   timestamp: int64 = 0): bool {....raises: [KeyError],
    tags: [TimeEffect], forbids: [].}

Close entire position in a symbol

Args: symbol: Symbol to close price: Closing price timestamp: Optional transaction timestamp

Returns: True if position closed, False if no position exists

proc equity(p: Portfolio; currentPrices: Table[string, float64] = initTable[
    string, float64]()): float64 {....raises: [KeyError], tags: [], forbids: [].}

Calculate total portfolio equity (cash + position values)

Args: currentPrices: Optional table of current prices for positions

Returns: Total equity value

proc getPosition(p: Portfolio; symbol: string): PositionInfo {.
    ...raises: [KeyError], tags: [TimeEffect], forbids: [].}
Get position info for a symbol (returns flat position if none exists)
proc hasPosition(p: Portfolio; symbol: string): bool {....raises: [KeyError],
    tags: [], forbids: [].}
Check if portfolio has an open position in symbol
proc marketValue(p: Portfolio): float64 {....raises: [], tags: [], forbids: [].}
Get total market value of all positions (excludes cash)
proc marketValue(pos: PositionInfo): float64 {....raises: [], tags: [], forbids: [].}
Get current market value of position
proc newPortfolio(initialCash: float64 = 100000.0; commission: float64 = 0.0;
                  minCommission: float64 = 0.0): Portfolio {....raises: [],
    tags: [], forbids: [].}

Create a new portfolio with initial cash

Args: initialCash: Starting capital (default $100,000) commission: Commission rate as decimal (default 0.0, e.g., 0.001 = 0.1%) minCommission: Minimum commission per trade (default $0)

Returns: New Portfolio instance

proc realizedPnL(p: Portfolio): float64 {....raises: [], tags: [], forbids: [].}
Get total realized P&L from all closed and partially closed positions
proc sell(p: Portfolio; symbol: string; quantity: float64; price: float64;
          timestamp: int64 = 0): bool {....raises: [KeyError], tags: [TimeEffect],
                                        forbids: [].}

Execute a sell order (close or reduce long position)

Args: symbol: Symbol to sell quantity: Number of shares (must be positive) price: Price per share timestamp: Optional transaction timestamp (uses current time if 0)

Returns: True if order executed successfully, False if insufficient position

proc totalPnL(p: Portfolio): float64 {....raises: [], tags: [], forbids: [].}
Get total P&L (realized + unrealized)
proc totalPnL(pos: PositionInfo): float64 {....raises: [], tags: [], forbids: [].}
Get total P&L (realized + unrealized)
proc unrealizedPnL(p: Portfolio): float64 {....raises: [], tags: [], forbids: [].}
Get total unrealized P&L across all positions
proc updatePrice(pos: var PositionInfo; currentPrice: float64) {....raises: [],
    tags: [], forbids: [].}
Update position with current market price and recalculate P&L
proc updatePrices(p: Portfolio; prices: Table[string, float64]) {.
    ...raises: [KeyError], tags: [], forbids: [].}

Update all position prices with current market prices

Args: prices: Table of symbol -> current price