Portfolio Management¶
The Portfolio is the top-level container that holds your Account (cash balances) and Positions.
Creating a Portfolio¶
Using Presets¶
import qlcore as qc
# Crypto trading setup (USDT base)
portfolio = qc.crypto_portfolio(
base_currency="USDT",
initial_balance=10_000,
)
# Traditional spot/equity setup (USD base)
portfolio = qc.spot_portfolio(
base_currency="USD",
initial_balance=100_000,
)
Manual Construction¶
from decimal import Decimal
account = qc.Account(
base_currency="USDT",
balances={"USDT": Decimal("10000")},
)
portfolio = qc.Portfolio(account=account)
Multi-Currency Account¶
account = qc.Account(
base_currency="USD",
balances={
"USD": Decimal("50000"),
"EUR": Decimal("10000"),
"BTC": Decimal("0.5"),
},
)
portfolio = qc.Portfolio(account=account)
Applying Fills¶
When trades execute, apply fills to update positions:
fill = qc.Fill.create(
order_id="order-001",
instrument_id="BTC-USDT-PERP",
side=qc.OrderSide.BUY,
quantity="0.1",
price="45000",
fee="4.5",
timestamp_ms=1701849600000,
)
# Apply fill (returns new portfolio, original unchanged)
portfolio = portfolio.apply_fill(fill)
Batch Processing¶
fills = [fill1, fill2, fill3]
# Apply multiple fills
# Apply multiple fills
for fill in fills:
portfolio = portfolio.apply_fill(fill)
# Or with validation
validated_fills = qc.validate_fill_sequence(fills)
for fill in validated_fills:
portfolio = portfolio.apply_fill(fill)
Accessing Positions¶
# Get specific position
btc_position = portfolio.positions.get("BTC-USDT-PERP")
if btc_position:
print(btc_position.summary())
# Iterate all positions
for instrument_id, position in portfolio.positions.items():
print(f"{instrument_id}: {position.side} {position.size}")
Portfolio Summary¶
Output:
Portfolio Summary
=================
Account:
Base Currency: USDT
Balances: {'USDT': Decimal('9995.50')}
Positions (1):
BTC-USDT-PERP: LONG 0.1 @ 45000
Portfolio PnL¶
Calculate aggregate PnL across all positions:
# Current prices for each instrument
prices = {
"BTC-USDT-PERP": Decimal("46000"),
"ETH-USDT-PERP": Decimal("2600"),
}
portfolio_pnl = qc.calculate_portfolio_pnl(portfolio, prices)
print(f"Total Realized: {portfolio_pnl.realized_pnl}")
print(f"Total Unrealized: {portfolio_pnl.unrealized_pnl}")
print(f"Total Fees: {portfolio_pnl.total_fees}")
print(f"Net PnL: {portfolio_pnl.net_pnl}")
Portfolio Weights¶
Calculate allocation weights:
prices = {
"BTC-USDT-PERP": Decimal("46000"),
"ETH-USDT-PERP": Decimal("2600"),
}
weights = qc.weights(portfolio, prices)
# Returns dict: {"BTC-USDT-PERP": Decimal("0.64"), "ETH-USDT-PERP": Decimal("0.36")}
Account Operations¶
Check Balances¶
Update Balances¶
# Account is immutable, create new one
new_account = qc.Account(
base_currency=portfolio.account.base_currency,
balances={**portfolio.account.balances, "BTC": Decimal("0.5")},
)
portfolio = qc.Portfolio(account=new_account, positions=portfolio.positions)
Ledger Tracking¶
Track all balance changes:
ledger = qc.Ledger()
# Record entries
entry = qc.LedgerEntry(
currency="USDT",
amount=Decimal("100"),
entry_type="TRADE_PNL",
timestamp_ms=1701849600000,
reference_id="fill-001",
)
ledger = ledger.add_entry(entry)
# Query ledger
usdt_entries = ledger.entries_for_currency("USDT")
Configuration Presets¶
Use presets for common scenarios:
# Backtesting optimization
config = qc.backtest_config()
# {'cost_basis_method': 'AVERAGE', 'track_lots': False, 'audit_logging': False, ...}
# Live trading safety
config = qc.live_config()
# {'cost_basis_method': 'FIFO', 'track_lots': True, 'audit_logging': True, ...}