PremiumGuardHQ
Methodology

How the math gets to your screen.

This is the PremiumGuardHQ calculation reference. Every formula the platform runs on your broker data is documented here, with the source-of-truth in production code. No black box, no proprietary fudge factors. If a number is on your dashboard, it came from one of these formulas.

Last updated 2026-07 8 sections decimal.js precision
The Three Numbers

Premium P/L. Equity P/L. Net P/L.

These are the only three numbers a wheel trader needs to trust. Every cycle PremiumGuard detects produces exactly these three values, computed from your raw trade data.

01

Premium P/L

Formula totalPremiumReceived − totalPremiumCosts

Sum of credits from sold options, minus debits from bought options. Includes both opening and closing legs.

Why it matters The unearned-income meter. Tells you what the market paid you to take risk, before any assignment math.

cycle-detector.ts
02

Equity P/L

Formula equityProceeds − equityCost

Sale proceeds of shares sold minus the cost basis of shares acquired (via buy, put assignment, or call exercise).

Why it matters What the underlying did to your book. Captures whether assignments hurt you or whether shares appreciated through the cycle.

cycle-detector.ts
03

Net P/L

Formula premiumPl + equityPl

The cycle’s real outcome. Combines what you earned from options with what the underlying cost or gave you.

Why it matters The single number a wheel trader can trust. Brokers obscure this by adjusting cost basis for premiums received and wash sales. PremiumGuard never does.

cycle-detector.ts:44

Each value is computed in decimal.js arbitrary-precision arithmetic. No floating-point drift, no rounding errors at scale.

The cycle

The cycle is the unit of measurement.

PremiumGuard doesn’t track individual trades. It tracks cycles: every option sale, every assignment, every closing leg gets stitched into the position it belongs to, whether that is a wheel, a bought contract held outright, or a spread the broker filled as one order. P/L lives on the cycle, never on the trade.

Primary case wheel

Wheel

A multi-leg cycle that holds shares plus the option activity tied to them. Created when a put is assigned or shares are bought into an open option position. Closes when shares fall below 100 (the call-writing floor).

Common zero_duration

Zero-duration

A cycle that opens and closes without shares ever changing hands. The classic case: sell a put, it expires worthless, premium booked. No equity leg, no assignment.

Edge case standalone

Standalone

A bought-option position not tied to an existing wheel. Long calls and long puts held outright. Tracked separately so hedges and speculation never pollute wheel P/L. A standalone stays open until every contract is closed, expired, or exercised. Scaling out across multiple orders keeps all fills in one cycle.

Breakeven at expiration is the strike plus the premium paid per share for a long call, and the strike minus it for a long put. Maximum loss is the premium paid: a bought option cannot lose more than its debit. Both figures are exact at expiration and take no view on volatility or time value. The contract itself (type, strike, expiration, contract count) is reconstructed from the cycle’s own legs, because the cycle record stores position totals rather than contract terms.

Defined risk combo

Multi-leg

Several option legs the broker filled as one order, held as one position: vertical spreads, iron condors, straddles, strangles, synthetics, collars, calendars. Grouping keys on the broker’s own order identifier and on nothing else, so several orders on one ticker in a day stay several positions. There is no inference from timing, and deliberately so: a covered call written in the morning and an unrelated contract bought that afternoon are two positions, and reading them as one diagonal would take the short call away from the wheel it was covering. Legs that arrive with no order identifier, as they do from most plain CSV exports, stay the individual positions they were reported as. The cycle stays open until every leg is flat, so closing one side early leaves the rest showing as the live position they still are.

Capital at risk is the worst the NET payoff can reach at expiration, never the sum of each leg’s notional. That figure is exact rather than modeled: the net payoff of these positions at expiration is piecewise linear in the underlying with corners only at the strikes, so evaluating it at zero, at every strike, and once past the highest strike finds the true worst case with no sampling and no volatility assumption. Two shapes have no such worst case, and are labelled on the position rather than handed a fabricated one. A position that is net short calls has no ceiling on its loss as the underlying rises. A calendar or diagonal has legs expiring on different dates, so it has no single expiration payoff to evaluate at all. Both fall back to the same conservative convention the rest of the engine uses: short notional less long debits, floored at zero.

Trade classification

14 trade events. Every broker row classified into one.

Each row from your broker feed is mapped to exactly one of these events before the cycle engine processes it. Everything else (transfers, fees, dividends, splits) is filtered out as non-trading account activity.

Equity
  • equity_buy
  • equity_sell
Sell to open
  • sell_call_to_open
  • sell_put_to_open
Buy to open
  • buy_call_to_open
  • buy_put_to_open
Closing
  • buy_to_close
  • sell_to_close
Settlement
  • call_assigned
  • put_assigned
  • call_expired
  • put_expired
  • call_exercised
  • put_exercised
Settlement order

Same-day trades, settled in the right order.

Brokers report a day’s fills in whatever order they please, and the wheel’s two most common days are the ones that suffer for it: the assignment that is followed by a sale, and the contract that expires and is rewritten the same session. The engine applies a fixed settlement order before it reads any of it, so shares always register before they can be traded and an expiring contract always settles before the next one is written. Shares that leave on an assignment are settled with the contract that called them away, not alongside whatever else happened to share the day — brokers often post a Friday assignment under Monday’s date, which is exactly when a position gets rebuilt. A single equity order the broker filled in pieces is aggregated into one logical trade first, so a position is attributed in full before it can cross the 100-share floor. The result is that a busy day reconciles the same way a quiet one does.

Linked chains

Recovery chains count once, when they resolve.

When shares are called away below basis and the operator rebuys to keep selling calls, the wheels can be linked into a single recovery chain (Advanced Loss Mitigation, a Pro feature). The cycle stays the base unit: linked cycles are never modified, and unlinking restores their individual numbers exactly. But results treat the chain as one position with one breakeven, all capital in minus all cash back per share held, and one recorded outcome in the month the chain finally closes.

Capital at Risk

The most you could lose at any point in the cycle.

Not your current exposure. Not your average exposure. The peak dollar amount the platform observed at any moment between the cycle’s open and close. PremiumGuard walks each cycle’s trades chronologically and tracks the running notional, recording the maximum.

Algorithm

For each trade in the cycle, ordered by date + action priority, apply the delta. Track the running total. Clamp at zero (CAR is never negative). Record the peak.

Event Delta Note
sell_put_to_open + strike × qty × 100 Full notional obligation to buy if assigned.
sell_call_to_open + strike × uncovered × 100 Covered contracts add nothing. Only naked / uncovered exposure counts.
put_assigned − strike × qty × 100 Obligation fulfilled; shares received.
call_assigned − strike × qty × 100 Shares called away.
buy + total cash deployed Equity bought outright.
sell − proceeds Equity sold; clamps at zero, never negative.
Worked example

AAPL wheel · May 2026

Sell a $180 put. Get assigned. Cover with a $185 call. Get called away. The peak observed exposure becomes the cycle’s maxCapitalAtRisk.

  1. Day 1 2026-05-01
    sell_put_to_open 1× AAPL put, strike $180
    Δ + 180 × 1 × 100 = +$18,000
    Running CAR $18,000 Peak
  2. Day 14 2026-05-15
    put_assigned Put exercised, 100 shares received
    Δ − 180 × 1 × 100 = −$18,000
    Running CAR $0
  3. Day 14 2026-05-15
    sell_call_to_open 1× covered call, strike $185
    Δ + $0 (covered — no notional)
    Running CAR $0
  4. Day 30 2026-05-31
    call_assigned Shares called away at $185
    Δ − 185 × 1 × 100 (clamped at 0)
    Running CAR $0
Cycle maxCapitalAtRisk $18,000
Multi-leg positions

A spread is bounded by its own strikes, so it is measured that way.

The walk above charges each short leg its full notional, which is right when nothing is standing behind it. In a spread something is: the long legs cap the loss, and the cap is the whole reason the position was opened. So a combo cycle’s capital at risk is the worst its net payoff can reach at expiration, evaluated at zero, at every strike, and once past the highest strike. Nothing is sampled and no volatility is assumed: the net payoff is piecewise linear with corners only at the strikes, so those probes find the true worst case exactly.

Worked example · AAPL iron condor, 2 contracts
  • buy_put_to_open2× $200 put−$336
  • sell_put_to_open2× $205 put+$512
  • sell_call_to_open2× $225 call+$456
  • buy_call_to_open2× $230 call−$290
Net credit taken in 512 + 456 − 336 − 290 $342
Widest gap between a short strike and the long behind it $5 × 2 × 100 $1,000
Cycle maxCapitalAtRisk 1,000 − 342 $658

Walked leg by leg the same position would have recorded $86,000, the notional of the two short strikes. It can lose $658. Every yield that divides by capital at risk depends on which of those two numbers is used.

Two shapes have no worst case to find, and are labelled on the position rather than handed a number that does not exist. A position that is net short calls has no ceiling on its loss as the underlying rises. A calendar or diagonal has legs expiring on different dates, so there is no single expiration payoff to evaluate at all. Both fall back to the conservative convention above: short notional less long debits, floored at zero.

Safe Withdrawal Engine

Three scenarios. One safe withdrawal.

The unique math at the heart of the platform. PremiumGuard takes your closed-cycle profits and nets previous withdrawals. Above target, it caps the draw at the room above target so a withdrawal never erodes the base capital that’s producing your income. Below target, it throttles the draw to a configurable fraction while you rebuild.

Gross Available Closed-cycle profits − Previous withdrawals
Room Above Target Account value − Target equity
Safe To Withdraw max( min(Gross Available, Room Above Target), $0 )
A Above target

Account value sits above target and realised profit fits within the room above target. The full profit is yours.

Setup
Target equity
$50,000
Account value
$65,000
Closed profits
$15,000
Previous withdrawals
$0
What the engine sees
Room above target
$15,000 above target
Gross available
$15,000

Profit ≤ room above target. Take the full gross.

Safe to withdraw $15,000
C Below target

Account value is below target. Withdrawals are throttled to a configurable fraction of profit while you rebuild.

Setup
Target equity
$50,000
Account value
$30,000
Closed profits
$15,000
Previous withdrawals
$0
What the engine sees
Room above target
−$20,000 below target
Gross available
$15,000
Throttle rate
50%

Below target. Throttle to 50%: $15,000 × 0.50.

Safe to withdraw $7,500
Cost basis

Three ways shares enter a cycle. One source of truth.

Brokerages reshape cost basis for wash sales and premiums received, which is why the number on your broker screen often disagrees with what your wheel actually did. PremiumGuard ignores those adjustments and applies one of three deterministic formulas, based on how the shares were acquired.

01 weightedAvgCostBasis

Weighted average — multiple buys

When you add to an existing share position, cost basis re-averages across all shares held. PremiumGuard computes the weighted mean using existing shares + new shares.

Formula (existingShares × existingAvg + newShares × newPrice) ÷ totalShares
Worked

100 sh @ $30 avg. Buy 200 more @ $25.

(100 × 30) + (200 × 25) = 3,000 + 5,000 = 8,000 8,000 ÷ 300 sh = $26.67 / share
Cost basis $26.67
02 assignmentCostBasis

Put assignment — shares received

When a cash-secured put is assigned, the strike price is your cost. The premium you collected stays in Premium P/L — it does not lower the cost basis.

Formula cost = strikePrice
Worked

Sold $50 put for $200 premium. Assigned.

cost basis = $50 / share Premium of $200 stays in totalPremiumReceived
Cost basis $50.00
03 exerciseCostBasis

Call exercise — exercising a long call

When you exercise a bought call into shares, your cost per share is the strike plus the premium you paid (amortized across the share count).

Formula cost = strike + (premiumPaidTotal ÷ shareCount)
Worked

Bought call $15 strike for $200 total premium. Exercised.

$15 + ($200 ÷ 100 sh) $15 + $2.00 = $17.00 / share
Cost basis $17.00
Insights

Eighteen rules. Zero models. Every one documented.

Insights is a deterministic rule engine: plain arithmetic over your own fills, detected cycles, live quotes, the earnings calendar, and the strategy profile you declared. The same inputs always produce the same output, and every insight carries the numbers that fired it. It runs after every sync and nightly, and a code-level test bans prescriptive language from every template: an insight reports what crossed a line, never what to do about it.

Inputs your fills + detected cycles live quotes earnings calendar daily price snapshots declared strategy profile withdrawal history
Info

A neutral observation worth knowing. Nothing is wrong; the numbers just say something you might not have noticed.

Watch

Worth attention. A measurement is moving toward a line you or the rule defines, but has not crossed it.

Flag

A defined line has been crossed and the condition is true right now. Flags never age out while they remain true.

Severity describes the state of a measurement. It never encodes a recommendation.

A

Track record

7 rules

Computed over your full closed-cycle history, but reported only for tickers you are still involved with: an open cycle, or cycle activity inside a trailing activity window.

  1. premium_equity_decomposition

    Splits a ticker’s closed-cycle P/L into premium collected versus equity result, so a winner propped up by one stock move (or dragged by one assignment) is visible as such.

  2. win_rate_outlier

    Compares a ticker’s closed-cycle win rate against your account average and reports material outliers in either direction, subject to per-ticker and account sample floors.

  3. ticker_annualized_return

    Annualizes each ticker’s closed-cycle returns and reports meaningful deviation from your account’s own annualized rate.

  4. capital_efficiency

    Return per unit of capital-time deployed, per ticker versus account. Standout tickers are reported.

  5. repeat_offender

    Cumulative closed losses concentrated in a single ticker. Escalates from watch to flag as the cumulative loss deepens.

  6. open_cycle_aging

    Days an open cycle has been running versus a multiple of your own median closed-cycle length.

  7. entry_yield_quality

    Groups closed cycles into entry premium-yield buckets (premium ÷ strike notional at entry) and compares win rates across buckets that meet the sample floor.

B

Open risk

5 rules

Evaluated against open positions at current quotes. Short legs whose expiration has passed but whose outcome the broker has not reported yet are excluded; they are not open risk.

  1. earnings_before_expiration

    An earnings date landing before an open short option’s expiration. Flag when the report is imminent; watch otherwise.

  2. short_put_near_money

    Open short puts near the money at current quotes. In the money is always a flag.

  3. assigned_shares_underwater

    Assigned shares trading below their weighted-average cost basis. Deeper price-to-basis ratios escalate from watch to flag.

  4. expiration_week

    A radar of open contracts expiring within the coming sessions, so expiration week never arrives unannounced.

  5. concentration_snapshot

    Any single ticker’s share of your total open capital at risk. Profile-independent; it fires whether or not you declared a cap.

C

Strategy conformance

6 rules

These rules only run if you declare a strategy profile for the account: target return, concentration cap, strike range, diversification floor, DTE habits. You declare it once; the engine measures drift against it.

  1. concentration_vs_cap

    A ticker’s share of open capital at risk versus the per-position cap you declared. Materially exceeding your own cap escalates to flag.

  2. strike_drift

    Recent short-put openings versus your declared strikes-out-of-the-money range, measured in per-symbol strike increments (see definitions below).

  3. pace_vs_target

    Realized return pace over the trailing window versus the annual target you declared.

  4. diversification_floor

    Distinct tickers deployed versus the minimum you declared.

  5. withdrawal_conformance

    Actual withdrawals over the window versus what the Safe Withdrawal Engine computed as safe.

  6. dte_drift

    Days-to-expiration of recent openings versus the typical and maximum DTE you declared.

Insight lifecycle

One insight per condition
Insights deduplicate on account, rule, and entity. Refreshes update the existing row instead of stacking duplicates, so the “since” date is the day the condition first became true and survives every refresh and cycle rebuild.
Auto-resolve
If a rule stops being true, its insight resolves on the next refresh. Nothing lingers by inertia.
Acknowledge
Acknowledging an insight collapses it out of the list and every contextual badge while the engine keeps tracking it. It resurfaces on its own only if the severity escalates.
Info aging
Info-severity observations quietly self-acknowledge after sitting unacknowledged for a stretch. Watch and flag never age out: an active flag is a currently-true condition.

Definitions that matter

open capital at risk

The concentration denominator

Concentration rules divide by your total open capital at risk, not account equity. On a margin account, equity understates what is actually deployed; capital at risk is the true allocation base. “31% of open capital at risk” means 31% of the dollars currently exposed, not 31% of your account value.

strike increment

Measuring drift in strikes, per symbol

Your strike range is declared the way traders speak: “I sell 1 to 3 strikes out.” The engine infers each symbol’s strike increment from the gaps in your own traded strikes, snapped to the standard 0.50 / 1 / 2.50 / 5 / 10 ladder, with a price-based fallback for symbols you have not traded. Drift classification allows half-strike tolerance.

entry premium yield

Yield at the moment you sold

Premium received divided by strike notional at entry. It captures how rich the entry was independent of what happened afterward, which is what makes cross-bucket win-rate comparison meaningful.

Trigger thresholds are versioned in code, set conservatively, and tuned as live data accumulates. The rules themselves, and everything on this page, hold regardless of tuning.

Option modeling

The one place we model instead of measure.

Everything else on this page is arithmetic over trades that actually happened. This section is different, and it is worth being explicit about the difference. For calls and puts you bought outright, and for multi-leg positions such as spreads, condors and straddles, PremiumGuardHQ can project what the position is worth over time and across prices. Those are estimates from a model, not quotes, and they never touch your recorded P/L, cost basis, yields or withdrawal figures. The expiration payoff is the exception: it is exact arithmetic rather than a model, which is why it is shown whether or not you have given us a contract price.

01 impliedVol

Volatility comes from you, not from us

We start from what the contract is actually trading at. With a supported broker connected we read that price off your own position; otherwise you type it in. Either way we solve backwards for the volatility that reprices it, using a safeguarded Newton method with a bisection fallback. Every modeled figure is anchored to an observed price rather than a house assumption. When no price is available, nothing is modeled: no default volatility is ever substituted.

If the price cannot be explained at any volatility between 0.1% and 500%, meaning it sits below intrinsic value or above what the contract could possibly be worth, we say the price looks wrong rather than showing a number.

02 fetchOptionMarks

Read from your account, not bought from a vendor

Where the broker supports it, the contract price is read from your own open position over the same read-only connection that imports your trades, and re-read every time you open the position. That is your account data, not a redistributed market feed, which is why this carries no data subscription and no per-quote cost.

Brokers differ, and some serve a once-daily cache rather than live prices. A broker-supplied price is timestamped and expires on exactly the same schedule as one you typed, because treating it as fresher would be a guess. Every price is also checked against the bounds arbitrage puts on it before it is used.

03 bsPrice

Black-Scholes-Merton, European exercise

The pricing model is Black-Scholes-Merton with a continuous dividend yield. It assumes European exercise: settlement only at expiration. US equity options are American and can be exercised early.

For a long call on a stock paying no dividend the difference is exactly zero, because early exercise is never optimal. For a long put it is real but small at the moneyness and rates this covers. We state the approximation rather than hiding it behind a more elaborate model whose error would still be smaller than the bid-ask spread you calibrated against.

04 RISK_FREE_DEFAULT

A stated, constant interest rate

The risk-free rate is held constant at 4%. Rate sensitivity is by far the smallest influence on a single option at the holding periods this is built for.

A live treasury feed would add a network dependency and a staleness failure mode to buy an accuracy improvement well below one cent per share. A stated assumption is more honest than implied precision.

05 observed_at

Calibration expires out loud

The price is stored against the contract and its age is shown next to it, along with where it came from. Past two days the modeled sections switch themselves off and ask for a fresh price.

A stale mark on a fast-moving option is precisely the misleading case. Expiring loudly is the fix; quietly reusing a three-week-old price is not.

06 positionValue

Every leg carries its own volatility

A multi-leg position is priced leg by leg, each from its own contract price and its own solved volatility, then summed with the short legs subtracting. It is never priced from one blended volatility for the position.

Skew is real: the wings of a condor genuinely trade at different implied volatilities. Averaging them misprices both sides in opposite directions, and the two errors then largely cancel in the total, which hides the mistake rather than removing it. The consequence is that a position is only modeled once EVERY leg has a fresh price. Three legs of a condor is not an approximate condor, it is a different position.

07 positionHorizonDays

Projections stop at the first expiration

When the legs of a position expire on different dates, as in a calendar or a diagonal, every leg is still priced with its own remaining time, but the projections run only as far as the nearest expiration.

Past that date the position is a different position: once the near leg is gone what remains is a naked long. Drawing the curve through it would describe a trade that was never put on. The expiration payoff is not drawn at all for these, because there is no single expiration to draw it at.

What gets modeled

Five projections, one input.

Payoff at expiration

What the position is worth on expiration day at every price the underlying could be, with each breakeven marked. Alone among the surfaces here this is not modeled at all: the payoff of European options at expiration is exact arithmetic on the strikes and the cash paid or received, so it needs no volatility, no rate and no contract price. It is the one figure on this page that cannot be wrong for the reasons the others can.

Greeks

Delta, gamma, vega and theta, computed in closed form and reported in the units a trader reads: theta per calendar day, vega per one point of volatility. Each one is verified against a numerical derivative of the pricing function in the test suite.

Time decay

What the position is worth on each date between now and expiration if the underlying never moves. This is the shape of theta, and it is the least volatility-sensitive thing on the page.

Breakeven by date

The underlying price that would return the position to exactly what you paid, on each future date. It converges to the plain strike-plus-premium arithmetic at expiration and sits inside it before then, because the contract still carries time value. This is the most volatility-sensitive figure we publish, which is why it never renders without a fresh price from you.

Profit map

Modeled profit and loss across underlying price and date at once. The price axis spans two standard deviations of the contract’s own remaining life, so the range shown is the range that is actually plausible for that stock rather than a fixed percentage.

No market-data vendor is involved in any of this. The contract price is your own, read from your broker position or entered by hand; the underlying price comes from the quote feed already used across the platform, and the mathematics runs locally. Nothing modeled here is ever written into a cycle, a yield, or a withdrawal figure.

Precision & sources

Reproducible math. Auditable inputs.

Every number on your dashboard traces back to a formula on this page and a row in your broker history. If a calculation surprises you, the source is recoverable.

Precision
decimal.js arithmetic
No floating-point drift. No rounding errors at scale.
Determinism
Same trades, same numbers
Action-priority ordering means a re-sync produces identical cycles.
Source of truth
Your broker, read-only
OAuth (Schwab), Flex token (IBKR), or SnapTrade (Robinhood, Fidelity, tastytrade). No writes.
Edge cases
Explicit, not silent
Missing equity returns null. Negative withdrawal clamps to zero.
See the math on your own book
Connect a broker. PremiumGuard backfills your cycles and runs every formula on this page against your real trade history.
Start free trial

Methodology questions? Email support@premiumguardhq.com. Engineering answers, not marketing.