Managing Your Portfolio¶
What is Portfolio Management?¶
Portfolio management involves tracking capital, positions, and trades. A portfolio starts with initial cash and changes as trades are executed - cash decreases when buying, positions are opened, and both adjust when selling.
Effective portfolio management includes: - Tracking available cash and open positions - Calculating profit and loss (realized and unrealized) - Managing commission costs - Measuring performance - Recording transaction history
In TzuTrader, the Portfolio object handles all these responsibilities.
Creating a Portfolio¶
Create a portfolio with initial capital and commission settings:
import tzutrader
let portfolio = newPortfolio(
initialCash = 100000.0, # Starting with $100,000
commission = 0.001, # 0.1% commission rate
minCommission = 0.0 # No minimum commission
)
Parameters: - initialCash: Starting capital (default $100,000) - commission: Commission rate as decimal (0.001 = 0.1%) - minCommission: Minimum commission per trade (default $0)
The portfolio tracks both cash and positions. Initially, all capital is in cash with no positions.
Understanding Commission¶
Every trade incurs commission costs that reduce profitability. TzuTrader supports two commission models:
Percentage Commission¶
Most common for stocks. Pay a percentage of trade value:
# 0.1% commission
let portfolio = newPortfolio(initialCash = 100000.0, commission = 0.001)
# Buying $10,000 worth of stock costs $10 commission
# Selling $10,000 worth of stock costs another $10 commission
Minimum Commission¶
Some brokers charge a flat fee per trade (e.g., $1 minimum):
let portfolio = newPortfolio(
initialCash = 100000.0,
commission = 0.001, # 0.1% rate
minCommission = 1.0 # But at least $1
)
# Small trade: $500 * 0.001 = $0.50, but charged $1.00 (minimum)
# Large trade: $50,000 * 0.001 = $50.00, charged $50.00 (above minimum)
Impact on strategy: - High-frequency strategies pay more commission - Small position sizes become economically unviable with high commissions - Always use realistic commission assumptions in backtests
Executing Trades¶
Buying Securities¶
Open or increase a position:
import tzutrader
let portfolio = newPortfolio(initialCash = 100000.0, commission = 0.001)
# Buy 100 shares of AAPL at $150
let success = portfolio.buy(
symbol = "AAPL",
quantity = 100.0,
price = 150.0
)
if success:
echo "Purchase successful"
echo "Cash remaining: $", portfolio.cash
else:
echo "Purchase failed (insufficient funds)"
The buy() method: - Returns true if successful, false if insufficient cash - Deducts cost plus commission from cash - Creates or increases position - Records transaction in history
Cost calculation:
Total cost = (quantity × price) + commission
Commission = max(quantity × price × commission_rate, min_commission)
Selling Securities¶
Close or reduce a position:
# Sell 50 shares of AAPL at $160
let success = portfolio.sell(
symbol = "AAPL",
quantity = 50.0,
price = 160.0
)
if success:
echo "Sale successful"
echo "Cash now: $", portfolio.cash
else:
echo "Sale failed (insufficient position)"
The sell() method: - Returns true if successful, false if insufficient shares - Adds proceeds minus commission to cash - Reduces or closes position - Records transaction and realized P&L
Proceeds calculation:
Closing Positions¶
Close an entire position at once:
# Close entire AAPL position at current price
let success = portfolio.closePosition(
symbol = "AAPL",
price = 160.0
)
This is equivalent to selling all shares of the position.
Position Tracking¶
Check current positions:
# Check if we have a position
if portfolio.hasPosition("AAPL"):
let position = portfolio.getPosition("AAPL")
echo "Quantity: ", position.quantity
echo "Entry price: $", position.entryPrice
echo "Current price: $", position.currentPrice
echo "Unrealized P&L: $", position.unrealizedPnL
Position information includes: - quantity: Number of shares held - entryPrice: Average purchase price - currentPrice: Latest market price - unrealizedPnL: Profit/loss if sold at current price - realizedPnL: Profit/loss from partial sales
Updating Market Prices¶
Positions need current prices to calculate unrealized P&L:
import std/tables
# Update prices for all positions
var prices = initTable[string, float64]()
prices["AAPL"] = 165.0
prices["MSFT"] = 310.0
portfolio.updatePrices(prices)
# Now position.currentPrice and unrealizedPnL are updated
Capital Allocation¶
Available Cash¶
Check available cash before buying:
echo "Available: $", portfolio.cash
if portfolio.cash >= targetCost:
# Can afford the trade
discard portfolio.buy(symbol, quantity, price)
Position Sizing¶
The amount invested in each trade affects risk and returns. Common approaches:
Fixed Dollar Amount¶
Invest the same dollar amount in each trade:
let targetAmount = 10000.0 # $10,000 per position
let shares = targetAmount / price
discard portfolio.buy(symbol, shares, price)
Pros: Simple, consistent exposure Cons: Doesn't adapt to account size changes
Fixed Percentage¶
Invest a percentage of current capital:
let pctToInvest = 0.10 # 10% of portfolio
let amount = portfolio.equity(prices) * pctToInvest
let shares = amount / price
discard portfolio.buy(symbol, shares, price)
Pros: Adapts to account size, compounds gains Cons: Position sizes vary over time
All-In¶
Invest all available cash (used by quickBacktest):
Pros: Maximum exposure, simple Cons: High risk, no diversification
Choose based on risk tolerance and strategy type. Conservative traders use smaller percentages (5-10%), aggressive traders use larger allocations.
Profit and Loss (P&L)¶
Realized P&L¶
Profit or loss from closed trades (trades that have been sold):
This only includes completed round-trips (buy then sell).
Unrealized P&L¶
Profit or loss from open positions (not yet sold):
This shows what you would gain or lose if you closed all positions at current prices.
Total Equity¶
Total portfolio value (cash + position values):
Calculation:
This is the bottom line - what the portfolio is worth right now.
Performance Metrics¶
Calculate comprehensive performance statistics:
let metrics = portfolio.calculatePerformance(prices)
echo "Total Return: ", metrics.totalReturn, "%"
echo "Annualized Return: ", metrics.annualizedReturn, "%"
echo "Sharpe Ratio: ", metrics.sharpeRatio
echo "Max Drawdown: ", metrics.maxDrawdown, "%"
echo "Win Rate: ", metrics.winRate, "%"
echo "Total Trades: ", metrics.totalTrades
echo "Profit Factor: ", metrics.profitFactor
Key metrics explained:
Total Return¶
Percentage gain or loss:
Annualized Return¶
Average yearly return (useful for comparing different time periods):
Sharpe Ratio¶
Risk-adjusted returns (return per unit of volatility):
Higher is better. Values above 1.0 indicate good risk-adjusted performance.
Maximum Drawdown¶
Largest peak-to-valley decline:
Measures worst-case scenario. Lower is better.
Win Rate¶
Percentage of profitable trades:
Profit Factor¶
Ratio of gross profits to gross losses:
Values above 1.0 indicate profitability. Above 1.5 is good.
Transaction History¶
Access complete transaction history:
Each transaction includes: - Timestamp - Symbol - Action (Buy or Sell) - Quantity - Price - Commission
This history is useful for: - Audit trails - Tax reporting - Strategy analysis - Debugging
Example: Manual Portfolio Management¶
Here's a complete example managing a portfolio manually:
import tzutrader
import std/tables
# Create portfolio
let portfolio = newPortfolio(
initialCash = 50000.0,
commission = 0.001
)
# Buy two positions
discard portfolio.buy("AAPL", 100.0, 150.0)
discard portfolio.buy("MSFT", 50.0, 300.0)
echo "Cash after purchases: $", portfolio.cash
echo "Positions: ", portfolio.positions.len
# Update prices
var prices = initTable[string, float64]()
prices["AAPL"] = 160.0 # Gained $10
prices["MSFT"] = 295.0 # Lost $5
portfolio.updatePrices(prices)
echo "Unrealized P&L: $", portfolio.unrealizedPnL()
echo "Total Equity: $", portfolio.equity(prices)
# Close one position
discard portfolio.closePosition("AAPL", 160.0)
echo "Realized P&L: $", portfolio.totalRealizedPnL
echo "Remaining positions: ", portfolio.positions.len
# Calculate final metrics
let metrics = portfolio.calculatePerformance(prices)
echo "Total Return: ", metrics.totalReturn, "%"
echo "Win Rate: ", metrics.winRate, "%"
Position Management Considerations¶
Concentration Risk¶
Holding too much in one position increases risk:
# Check position concentration
let totalValue = portfolio.equity(prices)
let applePosition = portfolio.getPosition("AAPL")
let appleValue = applePosition.quantity * applePosition.currentPrice
let concentration = (appleValue / totalValue) * 100
echo "AAPL represents ", concentration, "% of portfolio"
Most traders limit single positions to 10-20% of the portfolio.
Diversification¶
Spreading capital across multiple positions reduces risk:
echo "Number of positions: ", portfolio.positions.len
# Generally want 5-15 positions for retail accounts
Too few positions = high concentration risk Too many positions = diluted returns, harder to manage
Integration with Backtesting¶
When using quickBacktest, portfolio management is handled automatically:
let report = quickBacktest(
symbol = "AAPL",
strategy = strategy,
data = data,
initialCash = 100000.0,
commission = 0.001
)
The backtester: - Creates a portfolio - Executes buy/sell signals - Updates prices each bar - Tracks performance - Generates the report
For custom control, build your own backtest loop with explicit portfolio management.
Next Steps¶
The next chapter covers comparing strategies across multiple symbols using the Scanner module. This helps identify robust strategies that work across different securities.
Key Takeaways¶
- Portfolios track cash, positions, and transaction history
- Commission costs reduce profitability - use realistic assumptions
- Use
buy(),sell(), andclosePosition()to execute trades - Track realized P&L (closed trades) and unrealized P&L (open positions)
- Total equity = cash + position values at current prices
- Position sizing affects risk - consider fixed dollars, fixed percentages, or all-in
- Performance metrics provide comprehensive strategy evaluation
- Concentration risk matters - avoid putting all capital in one position
- Diversification reduces risk but requires more capital
- Portfolio management integrates with backtesting automatically