# Portfolio

> The Portfolio screen: five headline figures with trend arrows and a data badge, the positions table, working orders, concentration, framework risk, stress scenarios and covered calls.

Source: https://investi.live/docs/app/portfolio

Portfolio shows what you hold right now and what it would mean if the market moved. Positions come from broker snapshots where you have imported them, and are reconstructed from your fills otherwise. Quotes are delayed about 15 minutes.

Open it from the nav or press `g` then `p`.

## Account tabs

The header line shows the number of positions, working orders and the lot method in use (for example "FIFO"). Tabs on the right switch between **All accounts** and each imported account. Choosing an account loads `/portfolio?account={id}` and filters every figure on the page to that account.

## Header figures

Five large numbers sit at the top (`#kpis`), each with an (i) that explains it and a small trend arrow:

| Figure | Value | Arrow |
| --- | --- | --- |
| **Equity** | Broker-reported equity by default. With Current quotes valuation selected in Settings, cash minus margin debit plus positions at the last quote. Unknown until a complete balance is available. | Today's price move on held positions (the Day P/L), with "today". |
| **Cash** | Broker-reported cash. | The change since the newest balance before today, with "since Nov 4". No arrow when any account has no earlier balance, so a partial sum never shows. |
| **Day P/L** | Shares times today's price change, across held positions. | Green up or red down by its own sign. |
| **Realized today** | Gain or loss on lots closed today; unknown basis is left out. | Its own sign. |
| **Unrealized** | Synced position values against cost basis by default, or quote values when Current quotes valuation is selected. | Its own sign. |

These are the same numbers as the P/L breakdown, `GET /api/v1/portfolio` (`kpis.equity`, `kpis.cash`, `kpis.dayMtm`, `kpis.realizedToday`, `kpis.unrealizedTotal`) and the MCP tools.

## Data status

The last cell of the header is the **Data** badge: the Schwab [connection state](/docs/getting-started/connect-schwab#connection-state) of your positions and balances as a large chip, **LIVE**, **DELAYED**, **STALE**, **FAILED**, **REAUTH** (Schwab sign-in needed) or **SAMPLE**, with the source and its age under it. Its (i) lists both parts, which are never merged:

- **Quotes**: the feed (real-time Schwab, or Nasdaq delayed 15 minutes) and the worst freshness among the quotes on the page.
- **Positions and balances**: where the share counts, cash and cost basis came from (the Schwab sync, a positions file or the sample) and how old they are.

It also gives your history coverage (first and last fill, how many, from which sources) and the quote source.

While positions are stale, failed or waiting on a sign-in, a short notice says how old the share counts are; its (i) says which sync or file they came from. Long market value is then marked with an asterisk: current prices times share counts that may have changed.

If the ledger produced data checks (for example a history gap), they are listed under the header.

## More

A collapsed **More** row under the header holds the secondary figures. Open it for:

- **Long market value**: shares times last price for long positions.
- **Buying power**: Schwab's figure from the synced balance. An account whose balance came from a CSV is counted at its cash, and the (i) says how many.
- **Margin debit**: owed to the broker, from Schwab's balance.
- **Equity %**: equity divided by gross positions.
- **Interest accrued**: lifetime margin interest. The (i) names the last charge and the margin debit on the balance it was charged against.
- **Est. ongoing cost**: margin debit times your annual rate divided by 360, per day; "Set your margin rate in Settings" until you enter one.
- **Deposits** and **Withdrawals**: lifetime totals, kept apart from returns.
- **Dividends**: from your first imported fill on.
- **Open buys** and **Open sells**: remaining quantity times limit price for working orders, probe orders left out. When the order list is stale, both carry an asterisk and the (i) gives the list's age.
- **Exposure if buys fill**: long value plus open buys.
- **Net economic P/L**: realized plus unrealized, dividends and interest, minus account fees.

The order and fill freshness line sits at the bottom of the row. Any value the app cannot compute honestly reads "Unknown" rather than an estimate. See [/docs/concepts/canonical-numbers](/docs/concepts/canonical-numbers).

## Framework risk

The **Framework risk** panel (`#framework-risk`) checks the portfolio against the strategy's risk limits. Each line carries a status tag: **Within**, **Watch**, **Over** or **Unknown**. Thresholds are editable in [Settings](/docs/app/settings#strategy-rules); see [/docs/strategy/rules](/docs/strategy/rules#portfolio-risk) for the defaults.

- **Crash-cap ratio**: open buy orders plus margin debt, divided by equity, drawn as a meter with the strict and loose reference lines. Choose which line the account is held to on the [Action list](/docs/app/actions#crash-cap); the chosen line is drawn solid and labeled "chosen", and the status then follows that line alone. Until you choose, both lines are shown. A blue tick marks the ratio after every open buy fills when it differs. Without account equity from a broker balance it reads "Needs account equity from a broker balance."
- **Unrealized-loss band**: losses on losing positions as a share of equity, plus equity as a share of holdings, each against its band. A breach pauses new buys; it never forces a sale.
- **Underwater over N days**: the share of open cost that has been below cost for longer than the set number of days.
- **Concentration clusters**: one row each for **Consumer discretionary**, the **Rate-sensitive cluster** (equity REITs, banks, asset managers and utilities counted as one exposure), **Gaming (Las Vegas and Macau)**, **Miners** (two names at most) and **Latin American financials** (one name at most). Each row shows the cluster's share of equity, its limit and the names in it.

## Positions

A sortable, filterable table, largest value first by default. Hover any symbol for its hover card. **Holdings** in the panel header opens the full holdings view at `/holdings`.

| Column | Meaning |
| --- | --- |
| Last, Day % | Delayed price and day change, updated in place from the quote stream. |
| Shares | Current quantity. |
| Value, Day P/L | Shares times last, and shares times day change. |
| Cost basis | Schwab-reported where a Schwab sync or positions export exists (unrealized P/L uses it), otherwise reconstructed from fills. An `R` marks a reconstructed basis. "Unknown" means some shares have no known basis. |
| Basis from fills | The basis Investi rebuilds from your fills, beside Schwab's. Drawn in the warning color when it differs. |
| Unrealized, Unr. % | Value minus cost basis, and that as a share of cost. |
| Target sell | The exit target price: the higher of the dollar floor and a percentage on full positions, a larger percentage on half-size positions. Hover for the percentage on cost and the rule used. "No basis" when cost basis is unknown. |
| Realized life | Verified realized P/L from all closed lots, matched with your lot method (FIFO by default). |
| Trips | Closed round trips. |
| Weight | Share of gross market value. |
| Orders | Working orders, for example `B 10@42.50`. |
| Basis check | Schwab's basis against the basis from fills, flagged when they differ by more than 1% or $100. "Matched at old snapshot" when the snapshot is too old to rely on. |
| Record | How the position reconciles. See below. |

The Record column:

- **Reconciled**: the broker's share count and your fills agree, the broker snapshot is Live or Delayed, and fills were synced (or imported) through the snapshot. All three, or it does not say Reconciled.
- **Unverified: broker data X old**: the counts agree, but the snapshot is stale, failed or waiting on a sign-in (or fills are not synced through it), so the agreement proves nothing about today.
- **Gap in history**: they disagree. Hover to see what your fills imply. Usually an export is missing.
- **Broker only**: the broker reports it but you have no fills for it.
- **From fills**: no broker snapshot, so the position comes from your fills alone.

Learn how lots and reconciliation work in [/docs/concepts/ledger](/docs/concepts/ledger).

## Scenarios

The **Scenarios** panel (`#risk`) carries a **Simulation** tag. It runs a fixed set of what-ifs against your current positions and working orders: no shock, market down 5, 10 and 20 percent, all or half of open buys filling, and all buys filling followed by a 10 or a 20 percent drop.

For each scenario you see Long value, Equity, Change, Equity %, Margin debit, Requirement, Margin call and Forced sale, in a table you can sort and filter by any column. Shocks are applied per position as beta times the market move. Investi does not have betas in this view, so in the shocked scenarios every position assumes a beta of 1.0, and an assumption note says so. Open buys fill at their limit price, paid from cash first, then margin.

Below the table, in a few words with an (i) each:

- **Maintenance** gives the rate in use: the one you entered in [Settings](/docs/app/settings#preferences), or Schwab's when you chose **Use Schwab's requirement when synced** and your synced balance carries it. Schwab's rate is its reported maintenance requirement in dollars divided by the gross position value on the same balance.
- **Margin call at** gives the beta-weighted market drop at which equity falls to the requirement, and the drop if all open buys fill.
- Without a rate, Requirement, Margin call and Forced sale read Unknown and the panel asks you to enter one.

The three margin columns use these formulas, listed in the panel's **How this works** drawer:

- Maintenance requirement = rate x gross position value (long + short).
- Margin call = max(0, maintenance requirement - equity).
- Forced-liquidation estimate = margin call / rate. Selling shares pays down the margin debit, so equity stays the same while the requirement falls by rate x the amount sold; selling margin call / rate of market value restores the requirement exactly. With equity at or below zero the estimate is everything held.

Example: $100,000 of stock on a $70,000 debit at a 30% rate. After a 20% drop, positions are $80,000, equity $10,000 and the requirement $24,000, so the margin call is $14,000 and the forced-sale estimate $46,667. Selling that leaves $33,333 of stock against $10,000 of equity, exactly 30%.
- Assumption notes list exactly what each scenario assumed. If no broker balance is imported, cash and margin debit are treated as zero and a note says so.

> **Warning:** Scenarios are estimates. Schwab house requirements can be higher for individual securities than the single maintenance rate you enter.

## Covered calls

The **Covered calls** panel (`#covered-calls`) screens your held names for covered-call contracts to research. The criteria are in its **How this works** drawer.

- Names with at least 100 shares are screened, one contract per 100 shares. Names under 100 shares are listed as chips under the table.
- Calls only, with a strike at or above your average cost and an expiry before the next earnings date, up to 90 days out. A name with no upcoming earnings date is skipped and says so rather than guessing.
- One table across names: Symbol, Expiry, Days, Strike, Bid, Ask, Mid, Premium (mid x 100 x contracts), % of position (premium / position market value), Annualized (% of position x 365 / days to expiry) and Open interest, best annualized first, sortable and filterable. Names with no ideas are listed as chips; hover one for the reason.
- Chains come only from your own Schwab market data, cached for a minute. Without a Schwab connection the panel reads **Connect Schwab for option chains**, lists the names it would screen and links to the connection; no other source is used.

## Working orders

A compact summary of working orders (status working, partially filled or pending activation), with **All orders** linking to the full Open Orders page at `/orders`:

- **Open**: how many, split into buys and sells, with probe orders counted separately.
- **Buys** and **Sells**: open buy and sell dollars (remaining quantity times limit), probe orders left out. When the list is stale it says how old.
- **Earnings**: how many working buy orders rest through a report within the earnings call-out window (7 days by default), with their symbols. The same list is in the weekly review and on each research verdict as `timing.earnings_blackout`.

With none it reads "No working orders" with an **Import orders** button.

## Concentration

Bars for up to six sectors by share of gross value (names with no sector are grouped as "Unclassified"). The panel header gives your largest position and its share; its (i) adds the HHI (the sum of squared position weights; 1.0 means a single name).

## Empty state

With no data you see "No positions yet" and an **Import Schwab history** button to `/settings#data`. See [/docs/getting-started/import-history](/docs/getting-started/import-history) or [/docs/getting-started/connect-schwab](/docs/getting-started/connect-schwab).
