Paper Trading First
Use is_live: false to test strategies before real money.
Create portfolios, manage positions, and track performance metrics.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /portfolios | Yes | Create portfolio |
GET | /portfolios | Yes | List portfolios |
GET | /portfolios/{id} | Yes | Get portfolio |
PUT | /portfolios/{id} | Yes | Update portfolio |
DELETE | /portfolios/{id} | Yes | Delete portfolio |
POST | /portfolios/{id}/cash | Yes | Adjust cash balance |
GET | /portfolios/{id}/positions | Yes | Get positions |
POST | /portfolios/{id}/positions | Yes | Add position |
PUT | /portfolios/{id}/positions/{pos_id} | Yes | Update position |
DELETE | /portfolios/{id}/positions/{pos_id} | Yes | Close position |
GET | /portfolios/{id}/performance | Yes | Get performance metrics |
POST /api/v1/portfoliosAuthorization: Bearer <token>Content-Type: application/json
{ "name": "Growth Portfolio", "description": "Long-term tech growth stocks", "strategy_id": "550e8400-e29b-41d4-a716-446655440000", "cash_balance": 100000.00, "is_live": false}{ "id": "990e8400-e29b-41d4-a716-446655440000", "name": "Growth Portfolio", "description": "Long-term tech growth stocks", "strategy_id": "550e8400-e29b-41d4-a716-446655440000", "cash_balance": 100000.00, "is_live": false, "created_at": "2025-12-17T10:30:00Z", "updated_at": "2025-12-17T10:30:00Z"}| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Portfolio name (1-200 chars) |
description | string | No | - | Portfolio description |
strategy_id | UUID | No | - | Associated strategy |
cash_balance | decimal | No | 100000 | Initial cash ($) |
is_live | boolean | No | false | Paper vs live trading |
Add a new position to a portfolio.
POST /api/v1/portfolios/990e8400-.../positionsAuthorization: Bearer <token>Content-Type: application/json
{ "symbol": "AAPL", "quantity": 50, "avg_price": 185.50}{ "id": "aa0e8400-e29b-41d4-a716-446655440000", "portfolio_id": "990e8400-e29b-41d4-a716-446655440000", "symbol": "AAPL", "quantity": 50, "avg_price": 185.50, "opened_at": "2025-12-17T10:30:00Z", "closed_at": null, "current_price": 192.00, "market_value": 9600.00, "cost_basis": 9275.00, "unrealized_pnl": 325.00, "unrealized_pnl_pct": 3.50}| Field | Type | Description |
|---|---|---|
symbol | string | Stock ticker |
quantity | decimal | Shares (positive=long, negative=short) |
avg_price | decimal | Average entry price |
opened_at | datetime | Position open time |
current_price | decimal | Latest market price |
market_value | decimal | Current market value |
cost_basis | decimal | Total cost |
unrealized_pnl | decimal | Unrealized profit/loss ($) |
unrealized_pnl_pct | decimal | Unrealized P&L (%) |
Get comprehensive portfolio performance metrics.
GET /api/v1/portfolios/990e8400-.../performanceAuthorization: Bearer <token>{ "portfolio_id": "990e8400-e29b-41d4-a716-446655440000", "portfolio_name": "Growth Portfolio", "cash_balance": 70725.00, "total_market_value": 29400.00, "total_portfolio_value": 100125.00, "total_cost_basis": 28825.00, "total_unrealized_pnl": 575.00, "total_unrealized_pnl_pct": 1.99, "open_positions_count": 3, "closed_positions_count": 2, "positions": [ { "id": "aa0e8400-...", "symbol": "AAPL", "quantity": 50, "avg_price": 185.50, "current_price": 192.00, "market_value": 9600.00, "cost_basis": 9275.00, "unrealized_pnl": 325.00, "unrealized_pnl_pct": 3.50 }, { "id": "aa0e8400-...", "symbol": "MSFT", "quantity": 25, "avg_price": 420.00, "current_price": 425.00, "market_value": 10625.00, "cost_basis": 10500.00, "unrealized_pnl": 125.00, "unrealized_pnl_pct": 1.19 }, { "id": "aa0e8400-...", "symbol": "GOOGL", "quantity": 30, "avg_price": 175.00, "current_price": 178.50, "market_value": 5355.00, "cost_basis": 5250.00, "unrealized_pnl": 105.00, "unrealized_pnl_pct": 2.00 } ], "calculated_at": "2025-12-17T10:30:00Z"}| Metric | Description |
|---|---|
cash_balance | Available cash |
total_market_value | Sum of all position values |
total_portfolio_value | Cash + market value |
total_cost_basis | Total invested amount |
total_unrealized_pnl | Unrealized profit/loss |
total_unrealized_pnl_pct | P&L as percentage |
open_positions_count | Active positions |
closed_positions_count | Closed positions |
Deposit or withdraw cash from a portfolio.
POST /api/v1/portfolios/990e8400-.../cashAuthorization: Bearer <token>Content-Type: application/json
{ "amount": 5000.00, "note": "Monthly deposit"}POST /api/v1/portfolios/990e8400-.../cashAuthorization: Bearer <token>Content-Type: application/json
{ "amount": -2000.00, "note": "Partial withdrawal"}Modify an existing position (e.g., add to position).
PUT /api/v1/portfolios/990e8400-.../positions/aa0e8400-...Authorization: Bearer <token>Content-Type: application/json
{ "quantity": 75, "avg_price": 187.50}Close a position (marks it as closed, doesn’t delete).
DELETE /api/v1/portfolios/990e8400-.../positions/aa0e8400-...Authorization: Bearer <token>const api = axios.create({ baseURL: 'http://localhost:8501/api/v1', headers: { 'Authorization': `Bearer ${token}` }});
// Create portfolioasync function createPortfolio(name, initialCash = 100000) { const { data } = await api.post('/portfolios', { name, cash_balance: initialCash, is_live: false }); return data;}
// Add positionasync function addPosition(portfolioId, symbol, quantity, price) { const { data } = await api.post(`/portfolios/${portfolioId}/positions`, { symbol, quantity, avg_price: price }); return data;}
// Get portfolio summaryasync function getPortfolioSummary(portfolioId) { const { data } = await api.get(`/portfolios/${portfolioId}/performance`);
console.log(`\n${data.portfolio_name}`); console.log(`${'='.repeat(40)}`); console.log(`Cash: $${data.cash_balance.toLocaleString()}`); console.log(`Positions: $${data.total_market_value.toLocaleString()}`); console.log(`Total: $${data.total_portfolio_value.toLocaleString()}`); console.log(`P&L: $${data.total_unrealized_pnl.toLocaleString()} (${data.total_unrealized_pnl_pct.toFixed(2)}%)`);
console.log(`\nPositions:`); for (const pos of data.positions) { const pnlSign = pos.unrealized_pnl >= 0 ? '+' : ''; console.log(` ${pos.symbol}: ${pos.quantity} @ $${pos.avg_price} → $${pos.current_price} (${pnlSign}$${pos.unrealized_pnl.toFixed(2)})`); }
return data;}
// Usageconst portfolio = await createPortfolio('Tech Growth');await addPosition(portfolio.id, 'AAPL', 50, 185.50);await addPosition(portfolio.id, 'MSFT', 25, 420.00);await getPortfolioSummary(portfolio.id);import requestsfrom typing import Optionalfrom decimal import Decimal
class PortfolioManager: def __init__(self, base_url: str, token: str): self.base_url = base_url self.headers = {"Authorization": f"Bearer {token}"}
def create_portfolio( self, name: str, initial_cash: float = 100000, description: str = "" ) -> dict: """Create a new portfolio.""" response = requests.post( f"{self.base_url}/portfolios", headers=self.headers, json={ "name": name, "description": description, "cash_balance": initial_cash, "is_live": False } ) response.raise_for_status() return response.json()
def add_position( self, portfolio_id: str, symbol: str, quantity: float, price: float ) -> dict: """Add a position to portfolio.""" response = requests.post( f"{self.base_url}/portfolios/{portfolio_id}/positions", headers=self.headers, json={ "symbol": symbol, "quantity": quantity, "avg_price": price } ) response.raise_for_status() return response.json()
def get_performance(self, portfolio_id: str) -> dict: """Get portfolio performance metrics.""" response = requests.get( f"{self.base_url}/portfolios/{portfolio_id}/performance", headers=self.headers ) response.raise_for_status() return response.json()
def adjust_cash( self, portfolio_id: str, amount: float, note: str = "" ) -> dict: """Deposit (positive) or withdraw (negative) cash.""" response = requests.post( f"{self.base_url}/portfolios/{portfolio_id}/cash", headers=self.headers, json={"amount": amount, "note": note} ) response.raise_for_status() return response.json()
def print_summary(self, portfolio_id: str): """Print portfolio summary.""" perf = self.get_performance(portfolio_id)
print(f"\n{perf['portfolio_name']}") print("=" * 50) print(f"Cash: ${perf['cash_balance']:,.2f}") print(f"Positions: ${perf['total_market_value']:,.2f}") print(f"Total: ${perf['total_portfolio_value']:,.2f}")
pnl_sign = "+" if perf['total_unrealized_pnl'] >= 0 else "" print(f"P&L: {pnl_sign}${perf['total_unrealized_pnl']:,.2f} ({pnl_sign}{perf['total_unrealized_pnl_pct']:.2f}%)")
print("\nPositions:") for pos in perf['positions']: pnl_sign = "+" if pos['unrealized_pnl'] >= 0 else "" print(f" {pos['symbol']:6} {pos['quantity']:>6} @ ${pos['avg_price']:.2f} → ${pos['current_price']:.2f} ({pnl_sign}${pos['unrealized_pnl']:.2f})")
# Usagemanager = PortfolioManager("http://localhost:8501/api/v1", token)
# Create portfolioportfolio = manager.create_portfolio("Tech Growth", 100000)print(f"Created portfolio: {portfolio['id']}")
# Add positionsmanager.add_position(portfolio['id'], "AAPL", 50, 185.50)manager.add_position(portfolio['id'], "MSFT", 25, 420.00)manager.add_position(portfolio['id'], "GOOGL", 30, 175.00)
# View summarymanager.print_summary(portfolio['id'])
# Deposit more cashmanager.adjust_cash(portfolio['id'], 5000, "Monthly deposit")Paper Trading First
Use is_live: false to test strategies before real money.
Track Cost Basis
Always record accurate entry prices for proper P&L tracking.
Regular Reviews
Periodically review portfolio performance and rebalance.
Diversification
Don’t put all capital in one position.