Value a stock

A spreadsheet or Excel DCF into Margin

Connects
SpreadsheetMargin
Writes
Saves a forward projection against one stock
Updated
17 September 2026 · 5 min read

If you value stocks, the model is probably already in Excel or another spreadsheet, with years of assumptions in a layout you trust. Moving one of those into Margin by hand is an hour of typing per company, which is why valuations stay in the sheet and the portfolio never sees them.

An agent can read the sheet and make the calls, as long as it computes nothing itself.

The agent never computes the valuation

Margin computes the DCF:

POST /web/projection/dcf

This turns assumptions into every derived figure and saves nothing, so an agent can call it freely to check a mapping or compare two scenarios. Revenue per year, PAT, EPS, present values, intrinsic value and the implied return all come back from that one call.

The save endpoint stores rows verbatim. An agent that computes EPS itself and saves its own number produces a projection that disagrees with what the app shows when you open it, and nothing flags the disagreement. Reimplementing the sheet’s formulas in the skill leads to the same place by a longer route. The skill carries the assumptions across and the server derives the rest.

What the compute call needs

The body has four parts, and the units are where a mapping usually goes wrong:

  • baseYear, the trailing twelve month year zero everything grows from, with revenue, operatingProfit, otherIncome, depreciation, interest, tax and eps. Absolute figures in one consistent unit, and the share count is derived as PAT divided by EPS, so EPS has to sit on the same unit basis as the profit figures.
  • years, one row per projected year with revenueGrowthRate, operatingMargin, otherIncomeRatio, depreciationRatio, interestRatio, taxRate, cashFlowMultiplier and numberOfSharesGrowth. Rates and ratios are whole percents here, so 15 means fifteen percent, while cashFlowMultiplier is a plain multiplier where 0.8 means eighty percent of profit converts to cash.
  • discountRates, one rate per five year band, as decimals. Ten projected years take two entries.
  • terminalGrowthRate and terminalDiscountRate, decimals, optional, and the two travel together. Sending one without the other is a 400 naming the one you left out. Terminal growth has to be below the terminal discount rate, because a perpetuity growing at or above its discount rate has no finite value, and a pair breaking that rule is rejected rather than valued as though the terminal were worth nothing.

symbol is required and the server prices the valuation from its own last synced quote, so there is no price field and the skill should not look a price up.

Saving it

Saving needs a stockOfInterestId and not a stock id, and one call resolves it:

POST /web/stockOfInterest/track/{stockId}
POST /web/projection/stockOfInterest

The track call returns alreadyTracked, which is false when the stock was not in any list, holding or trade and has just been added to the account. Tell the user when this happens, since it means the skill changed more than a valuation.

What to report back

The compute response carries terminalValuePercentage on each intrinsic value. A valuation that is mostly terminal value rests on the growth assumption and not on the years you forecast, so report that share alongside the intrinsic value. priceAsOf is worth reading too, because a quote can be several days old for a thinly traded stock and the implied return is only as current as the price it was compared against.

A skill to start from

---
name: spreadsheet-dcf-to-margin
description: Read a DCF from a spreadsheet and save it as a valuation on the
  matching stock in Margin (go.marginapp.in). Use when asked to push, sync or
  recreate a spreadsheet valuation in Margin.
allowed-tools: Bash(bash *), Bash(jq *), Bash(curl *), AskUserQuestion, Read, Write
---

Read a DCF from a spreadsheet and save it as a forward projection in Margin.

Read `https://go.marginapp.in/llms.txt` before building any payload. It is the
authority on endpoints, fields, units and errors. Never build a payload from
memory or from this file.

**Margin computes the DCF. This skill never does.** `POST /web/projection/dcf`
turns the assumptions into every derived figure. Do not compute revenue, PAT,
EPS, present values or intrinsic value, and do not reimplement the sheet's
formulas. The save endpoint stores rows verbatim, so anything computed here
disagrees silently with what the app shows.

## 1. Read the sheet

Pull the base year figures and the per-year assumptions. Convert to one consistent
unit and check EPS sits on the same basis as the profit figures, because the share
count is derived as PAT divided by EPS.

Rates and ratios go in as whole percents. `cashFlowMultiplier` is a plain
multiplier. Discount rates and the terminal pair are decimals. Mixing the two
conventions is the most common failure.

## 2. Compute, and show the user

    POST /web/projection/dcf

Saves nothing, so call it as often as needed. Show the user the intrinsic values,
`terminalValuePercentage`, `price` and `priceAsOf` before asking whether to save.

Report `terminalValuePercentage`. A valuation that is mostly terminal value rests
on the growth assumption and not on the forecast years.

## 3. Resolve the stock

    POST /web/stockOfInterest/track/{stockId}

Resolve the symbol with `GET /web/stock/find/{text}` first. When `alreadyTracked`
comes back false the stock has just been added to the account, so say so.

## 4. Save, once the user says go ahead

    POST /web/projection/stockOfInterest

Send the rows the compute call returned. Do not adjust them.

Reading the live contract on every run matters more for this recipe than for the upload ones, because the payload has more fields and two of them were once spelled differently. A skill carrying a stale field list gets back a 400 naming a field its author never wrote.

Share

Also under value a stock

Try it

You need a token to start

Create one in Margin under Settings, on the API Tokens tab. Tokens never expire and you can revoke any of them at any time.

Create an API token