Skip to main content
POST
/
v1
/
portfolio
/
analyze
Analyze Portfolio
curl --request POST \
  --url https://api.chicago.global/v1/portfolio/analyze \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "start_date": "2024-01-01",
  "end_date": "2024-11-01",
  "base_currency": "USD",
  "benchmark": "ACWI",
  "initial_value": 10000,
  "portfolio": [
    {
      "date": "2024-01-01",
      "symbol": "AAPL.O",
      "weight": 0.25
    },
    {
      "date": "2024-01-01",
      "symbol": "MSFT.O",
      "weight": 0.25
    },
    {
      "date": "2024-01-01",
      "symbol": "GOOGL.O",
      "weight": 0.25
    },
    {
      "date": "2024-01-01",
      "symbol": "AMZN.O",
      "weight": 0.25
    }
  ]
}
'
{
  "job_id": "port-a3522a92-87ed-4be0-a912-ad56ed6a8806",
  "status": "pending",
  "check_url": "/v1/jobs/port-a3522a92-87ed-4be0-a912-ad56ed6a8806",
  "estimated_duration_seconds": 90,
  "message": "Portfolio analysis job created",
  "portfolio_summary": {
    "positions": 4,
    "start_date": "2024-01-01",
    "end_date": "2024-11-01"
  }
}

How It Works

This endpoint uses async job processing for handling large portfolios:
  1. Submit Job: POST your portfolio data to /v1/portfolio/analyze
  2. Receive Job ID: Get a job ID and polling URL immediately
  3. Poll for Status: Check /v1/jobs/{job_id} until status is completed
  4. Get Results: The completed job response contains the full analysis
Processing typically takes 60-120 seconds depending on the date range and number of holdings.

Request Body

FieldTypeRequiredDefaultDescription
portfolioarrayYes-List of holdings (see format below)
start_datestringNoFirst rebalance dateAnalysis start date (YYYY-MM-DD)
end_datestringNoYesterdayAnalysis end date (YYYY-MM-DD)
base_currencystringNoUSDBase currency (USD, SGD, EUR, etc.)
benchmarkstringNoACWIBenchmark for comparison (e.g., ACWI, SPY)
initial_valuenumberNo10000Starting portfolio value
include_transaction_costsbooleanNofalseApply market-specific transaction costs
transaction_cost_configobjectNoDefault ratesCustom transaction cost rates by market
fieldsarrayNoAll fieldsSelect specific response fields

Portfolio Holdings Format

Each item in the portfolio array:
FieldTypeRequiredDescription
datestringYesRebalance date (YYYY-MM-DD)
symbolstringYesStock symbol (e.g., AAPL.O for Apple Inc)
weightnumberYesPortfolio weight as decimal (0.25 = 25%)
Weights should sum to 1.0 for each date. They will be normalized if not.

Field Selection

Use the optional fields parameter to return only specific data sections. If omitted, all fields are returned.
{
  "portfolio": [...],
  "fields": ["portfolio_summary", "performance_metrics", "latest_holdings"]
}

Response Fields

The completed analysis includes:
FieldDescription
portfolio_summaryFinal value, total return, P&L breakdown, transaction costs
turnover_analysisTurnover metrics, rebalance frequency, costs by market
performance_metricsSharpe, Sortino, VaR, volatility, drawdown
rolling_metrics30/60/90-day rolling Sharpe, beta, correlation
drawdown_analysisDrawdown episodes and recovery times
portfolio_scoresQuant factor scores (value, quality, momentum)
latest_holdingsCurrent positions with company info
transactionsAll buy/sell trades
market_allocationMarket weights over time
sector_allocationSector weights over time
currency_allocationCurrency weights over time
company_contributionP&L attribution by company
sector_contributionP&L attribution by sector
market_contributionP&L attribution by market
time_period_returnsMTD, YTD, 1Y, inception returns
daily_summaryEquity curve with benchmark comparison

Example Response

When the job completes, GET /v1/jobs/{job_id} returns:
{
  "job_id": "port-9730dcc9-7a06-495c-85a9-4a405d2140e4",
  "job_type": "portfolio_analysis",
  "status": "completed",
  "result": {
    "success": true,
    "result": {
      "portfolio_parameters": {
        "start_date": "2025-07-01",
        "end_date": "2025-07-31",
        "base_currency": "USD",
        "benchmark": "ACWI",
        "initial_value": 10000.0,
        "include_transaction_costs": false
      },
      "portfolio_summary": {
        "final_value": 9890.37,
        "total_return": -0.0110,
        "total_price_pl": 122.79,
        "total_fx_pl": -232.32,
        "total_pl": -109.63,
        "total_transaction_cost": 0.0,
        "include_transaction_costs": false
      },
      "turnover_analysis": {
        "summary": {
          "days_in_period": 31,
          "num_rebalances": 0,
          "annualized_turnover_pct": 0.0,
          "total_transaction_cost": 0.0,
          "include_transaction_costs": false
        },
        "by_market": {
          "India": { "total_turnover": 0.0, "transaction_cost": 0.0 },
          "Japan": { "total_turnover": 0.0, "transaction_cost": 0.0 },
          "Taiwan": { "total_turnover": 0.0, "transaction_cost": 0.0 },
          "United States": { "total_turnover": 0.0, "transaction_cost": 0.0 }
        }
      },
      "performance_metrics": {
        "portfolio": {
          "total_return": -0.0110,
          "annualized_return": -0.1217,
          "annualized_volatility": 0.1335,
          "max_drawdown": -0.0383,
          "sharpe_ratio": -0.71,
          "sortino_ratio": -1.67,
          "var_95": -0.0093,
          "win_rate": 0.26
        },
        "benchmark": {
          "total_return": 0.0111,
          "sharpe_ratio": 1.28,
          "max_drawdown": -0.0147
        },
        "relative": {
          "beta": 1.52,
          "alpha_annualized": -0.32,
          "correlation": 0.67,
          "information_ratio": -1.67,
          "tracking_error": 0.103
        }
      },
      "portfolio_scores": {
        "value": 42,
        "quality": 65,
        "momentum": 85,
        "defensive": 90,
        "tactical": 37,
        "total": 71
      },
      "latest_holdings": [
        {
          "ric": "2330.TW",
          "weight": 0.295,
          "ending_value": 2918.49,
          "market": "Taiwan",
          "sector": "Technology",
          "recommendation": "STRONG BUY"
        },
        {
          "ric": "RELI.NS",
          "weight": 0.275,
          "ending_value": 2722.05,
          "market": "India",
          "sector": "Energy",
          "recommendation": "HOLD"
        },
        {
          "ric": "7203.T",
          "weight": 0.224,
          "ending_value": 2219.77,
          "market": "Japan",
          "sector": "Consumer Cyclicals",
          "recommendation": "HOLD"
        },
        {
          "ric": "AAPL.O",
          "weight": 0.205,
          "ending_value": 2030.06,
          "market": "United States",
          "sector": "Technology",
          "recommendation": "BUY"
        }
      ],
      "daily_summary": [
        {
          "date": "2025-07-01",
          "portfolio_value": 10000.0,
          "daily_return": 0.0,
          "cumulative_return": 0.0
        },
        {
          "date": "2025-07-31",
          "portfolio_value": 9890.37,
          "daily_return": -0.0097,
          "cumulative_return": -0.0110
        }
      ]
    }
  }
}
Response shown is abbreviated. Full response includes all fields listed above, plus detailed timeseries for allocations, drawdowns, rolling metrics, and more.

Example: Polling for Results

const jobId = response.job_id;
const checkUrl = `https://api.chicago.global/v1/jobs/${jobId}`;

// Poll every 3 seconds
const interval = setInterval(async () => {
  const status = await fetch(checkUrl, {
    headers: { 'Authorization': `Bearer ${API_KEY}` }
  }).then(r => r.json());

  if (status.status === 'completed') {
    clearInterval(interval);
    console.log('Analysis:', status.result);
  } else if (status.status === 'failed') {
    clearInterval(interval);
    console.error('Failed:', status.error);
  } else {
    console.log(`Progress: ${status.progress?.percent}%`);
  }
}, 3000);

Authorizations

Authorization
string
header
required

API key passed as Bearer token

Body

application/json

Request body for portfolio analysis

portfolio
object[]
required

List of holdings with date, symbol, and weight. Weights should sum to 1.0 for each rebalance date. Multiple dates supported for rebalancing.

Minimum array length: 1
start_date
string<date>

Analysis start date (YYYY-MM-DD). If not provided, defaults to first rebalance date in portfolio.

Example:

"2024-01-01"

end_date
string<date>

Analysis end date (YYYY-MM-DD). If not provided, defaults to yesterday. Future dates are auto-capped to yesterday.

Example:

"2024-11-01"

base_currency
string
default:USD

Base currency for portfolio valuation. Supports USD, SGD, EUR, GBP, JPY, etc.

Example:

"USD"

benchmark
string
default:ACWI

Benchmark for comparison (e.g., ACWI, SPY)

Example:

"ACWI"

initial_value
number
default:10000

Initial portfolio value in base currency. Used to calculate absolute P&L and position sizes.

Example:

10000

include_transaction_costs
boolean
default:false

Apply market-specific transaction costs during rebalancing

Example:

false

transaction_cost_config
object

Custom transaction cost rates by market. Format: {'market_name': {'buy': rate, 'sell': rate}}. If not provided, uses default rates.

Example:
{
"Singapore": { "buy": 0.14, "sell": 0.14 },
"United States": { "buy": 0.1, "sell": 0.1 }
}
fields
enum<string>[]

Optional field selection. If omitted, all fields are returned. Use this to reduce response size.

Available options:
portfolio_parameters,
portfolio_input,
data_quality,
portfolio_summary,
turnover_analysis,
performance_metrics,
rolling_metrics,
drawdown_analysis,
portfolio_scores,
concentration_metrics,
transactions,
company_info,
latest_holdings,
market_allocation,
sector_allocation,
currency_allocation,
company_contribution,
sector_contribution,
market_contribution,
time_period_returns,
monthly_returns,
annual_returns,
benchmark_prices,
daily_summary
Example:
[
"portfolio_summary",
"performance_metrics",
"latest_holdings"
]

Response

Job created successfully. Poll the check_url for results.

job_id
string

Unique job identifier

status
enum<string>

Initial job status

Available options:
pending
check_url
string

URL to poll for job status

estimated_duration_seconds
integer

Estimated processing time in seconds

message
string

Human-readable status message

portfolio_summary
object