TaxBullUK capital gains tax

Changelog

What changed in the calculator

Every report is stamped with the engine version that worked it out. This is what each version changed, newest first. The engine today is 2026.09.44.

2026.09.44

  • Five broker imports fixed after every published sample export we could find was run through the calculator and held to the figure an independent engine computes from the same file (KapJI/capital-gains-calculator for eight brokers, mattjgalloway/cgtcalc for 17 HMRC-rule worked examples, alexpung's Interactive Investor example). Freetrade, Hargreaves Lansdown, Revolut, Schwab, Trading 212 and the generic CSV already agreed to the penny; the 17 worked examples agree once cgtcalc's whole-pound rounding is allowed for. These five did not:
  • MORGAN STANLEY: the Withdrawals report lists each sale twice, the shares and then the proceeds wired out as a "Sale" of the "Cash" plan at $1.00. The wire was read as a disposal of 4,218.95 "shares" of CASH with nothing behind it, so on the published example £3,074.81 and £2,558.85 of pure invention sat beside the real sales. Cash leaving an account is not a disposal and is now a note. Sales are booked at the report's Net Amount, which is the cash after Morgan Stanley's fee, so the fee is applied once (£3,075.54 on the first sale, not £3,075.58). The report's own footnote about pre- and post-split quantities is repeated to you rather than reported as a row with a bad date.
  • VANGUARD: the download Vanguard UK actually produces, one file with a Cash Transactions table and an Investment Transactions table, was not recognised at all: its title is your account's name and the word Vanguard appears nowhere. It is read now: the trades from the Investment table (Cost is the all-in figure; £2.20 on the published example), the dividends and cash interest from the Cash table, with a "Reversal of" row cancelling the payment it names.
  • TRADING 212: a stock split arrives as two rows, "Stock split close" with the shares before and "Stock split open" with the shares after. Both were reported as unread and the pool kept the OLD count. For a 10-for-1 the engine's own split check caught it; for a 1-for-9 REVERSE split it cannot (you never sell more than you bought), so selling the 10 new shares for £1,200 against a pool of 90 at £10 showed £1,100 of gain where £300 is due, plausibly and silently. The two rows now give the ratio exactly and the pooled cost spreads over the new count (TCGA 1992 s126-s127). If your export is cut between the two rows, the half it holds is named and the pool is left alone.
  • REVOLUT: a STOCK SPLIT row (the extra shares that arrived) was reported and not applied, so a later sale of the post-split shares found most of them unmatched. The ratio is now worked from the holding on the day and applied only when the file accounts for the shares: something was held before the split, the quotient is a recognised split ratio (NVDA: 1.90970896 held, 5.72912688 arrived, 4-for-1), and with it applied every later sale in the file is covered. A clean-looking quotient is not enough on its own: 3 held of a true 8, plus the 24 a 4-for-1 adds, reads as a 9-for-1. When the file does not account for the shares NOTHING is applied, and the report asks you for the ratio, with the date the file gave already filled in.
  • SCHWAB: a cash takeover is two rows, "Cash Merger" with the money and "Cash Merger Adj" with the shares cancelled, and both were "not recognised", so the holding stayed in the pool and the cash was never a disposal. Paired by symbol and date they are one sale (£711.69 for shares that cost £1,783.50 on the published example, a £1,071.81 loss that never reached the return). A half on its own is reported, never guessed at.
  • ONE SPLIT, APPLIED ONCE. The calculator carries a table of well-known splits (NVDA 10-for-1 on 10 June 2024 among them) and applies it for you, and it also applies any split you enter. Nothing checked whether the two were the same event, so NVDA's 2024 split entered on the Splits panel, or confirmed from the "possible split" question, was applied TWICE: 10 shares bought for £10,000 and sold as 100 for £12,000 showed £11,000 of gain where £2,000 is due, and left 900 shares in the pool that you never owned. That was true of the version before this one for anyone who typed a split the table already held. The Trading 212 and Revolut fixes above would have made it common, because those files now carry their splits in. A split with the same ticker and ratio as one already in force, dated within 7 days of it, is now applied once, and the report names both copies and which one stood. A different ratio, or the same one further apart, is kept and applied (it may be a second real split) and the report says the two sit close together so you can check.
  • The 17 sample files and the 17 worked examples are now test/broker-samples.test.mjs, run through the very detectBroker and parseByBroker in src/cgt-tool.jsx, so a parser that drifts from a real layout fails a test rather than a filer.

2026.09.43

  • Fixed: a covered call could be reported as a NAKED call, with its maximum loss shown as "Unbounded", in four different ways. No tax figure moves. The premium, the matching, the assignments and every gain are the engine's and are untouched; what was wrong is what the options page and the printed report tell you about your own risk. All four were wrong in the same, dangerous direction: they described a position whose loss is capped as one with no limit at all.
  • Measured on a real 1,777-row Robinhood export of one ticker: 71 positions labelled "Naked call!", covering 260 contracts. One contract is naked. 50 of those positions are poor man's covered calls, which is a name this report did not have before, and the rest are covered calls or spreads that were already fenced.
  • 1. A SAME-DAY ROLL WAS COUNTED AS CONTRACTS HELD AT ONCE. A Robinhood export carries no order number and no time of day, so 30 contracts written and 17 bought back on one day look exactly like 30 held together. On 22 September 2026 that left 13 open against 1,300 shares, exactly covered, and the last calls written that day still read naked. Cover now goes to the contracts still open at the CLOSE of the day first, and the ones written and closed the same day are allocated after them, because a roll is a close and an open on one day. The file cannot prove the order, so every position on such a day carries a note naming the reading used and the contracts it turns on.
  • 2. A SPREAD TAKEN APART BY THE SPLIT LOST ITS OWN LONG LEG. Legs opened together that match no standard shape are reported leg by leg, and a written call on its own was then checked against SHARES ONLY. On 23 March 2026 a 32-lot bull call spread with one stray put beside it came apart, and its 32 written calls were reported naked although the 32 bought calls that cap them sat in the same group, on the same expiry, at a lower strike. Such a group is now reduced by its exactly matching pairs before it is split, so a 32-lot spread beside a one-lot put is a spread and a put rather than 65 bare positions.
  • 3. A BOUGHT CALL NEVER COUNTED AS COVER AT ALL. Holding 14 calls at 20 expiring next January and writing 11 at 40 expiring in October is a poor man's covered call: the bought call delivers the shares, so no shares are needed and the loss cannot exceed the net debit. Every one of those read as naked. They are named now, with a maximum loss and a maximum profit worked from the two strikes and the two premiums. On that example, with $1,000 paid a contract and $300 received, the most it can lose is 11 x (1,000 - 300) = $7,700 and the most it can make is 11 x ((40 - 20) x 100 - 700) = $14,300. A bought call at a HIGHER strike or an EARLIER expiry is still not cover and still says so, because neither of them can deliver the shares when the written call is called.
  • 4. A CALL ASSIGNED THE DAY IT WAS WRITTEN. The share position was read at the close of the day, which is after the delivery the assignment itself produced. On 14 March 2025, 304 shares were bought and three same-day-expiry calls written, and two were assigned that afternoon: the close is 104 shares, so two of the three read naked on the strength of the sale those very calls caused. Shares are now read as the close of the previous day plus that day's purchases, and where that reading was used the position says so.
  • A REAL SHORTFALL STILL READS AS NAKED, with its loss stated as unbounded and never as a number. 199.99 shares against two contracts is one covered call and one naked one. More written calls than bought calls plus whole hundred-share lots is still naked whatever else is in the file, and the warning still quotes the numbers it used. Cover is never assumed: where the day's order cannot be read out of the file, the reading taken is printed rather than taken for granted. And where the bought call behind a written call was itself sold first, the position now says on which day that happened and that from that day there was nothing behind it.
  • Each of the four was reproduced with a failing test before it was fixed, every figure worked by hand from the strikes and the premiums first: test/covered-call-cover.test.mjs, 31 of whose 55 assertions were red against the old code.

2026.09.42

  • Five faults in how option positions are NAMED on the options page. No tax figure moves: the premium, the matching and every gain are the engine’s and are untouched, and the golden comparison is unchanged. What these got wrong is what the page tells you about your own risk.
  • A LONG holding with more calls written against it than it can cover was being read as a SHORT one, because the shares-free figure goes negative when it is over-promised and the test for a short position is just “is this negative”. On a real 1,777-row file that produced 12 covered puts and 26 protected short sales against a holding that was never short at any point. Those labels said a bare position was covered, which is the dangerous direction. They are a plain short put and a plain long call now.
  • A written call hedged by a BOUGHT call of the same expiry, which is what a vertical spread is, was still reserving a hundred shares per contract that it can never use. The genuinely covered call written afterwards was then reported NAKED with an unbounded loss. On the same file, 11 fewer calls are naked, 7 more are covered, and 92 contracts stop carrying an unbounded loss they never had. The same fault on the put side cost two protective puts their name, and a collar its own.
  • A written call and a bought put at the SAME strike over a holding was called a collar. A collar has a ceiling above a floor; with one strike there is no gap and the position is a synthetic short, which locks the price exactly. docs/options-classification.md gives one strike to the synthetic and different strikes to the collar, and the strike test now runs first.
  • Every one of the five was reproduced with a failing test before it was fixed: test/option-detection-bugs.test.mjs.

2026.09.41

  • New in the take-home pay calculator: a workplace pension (auto-enrolment) option for 2026/27. Your and your employer's percentages (5% and 3% to start) are taken of qualifying earnings, pay between £6,240 and £50,270, or of your full salary, and it works with net pay, relief at source and salary sacrifice. The employer's contribution and the total going into the pension are shown apart from your take-home pay. £30,000 on qualifying earnings under relief at source: you pay £1,188 gross (£950.40 from your pay) and your employer £712.80.
  • Nothing changes for the existing pension options: the same inputs give the same take-home pay, to the penny.

2026.09.40

  • No CGT figure moves. Fixed: the take-home calculator's marginal rate (and the pence-kept strip under its chart) could average two rates across a threshold that sat within £100 above your salary. It was worst in Scotland, where the starter and intermediate band edges move the rate by one point and were never caught: £16,487 in 2026/27 showed 27.5% where the next £1 costs 19p of tax and 8p of NI, 27p. It also hit a threshold near the far end of the £100 (£20,915 with a postgraduate loan showed 28.9% where 28% is due). And in 2023/24, whose NI rate is HMRC's annualised 11.5%, it showed 31% or 32% where 31.5% is true.
  • The rate is now the cost of the next £1 over figures that are not rounded to the penny first, so it is exact at every salary and needs no test for whether a threshold is near. With a percentage pension it scales as it should: £16,487 in Scotland with a 5% salary sacrifice is 0.95 × 27 = 25.65p, 5p goes to the pension and 69.35p is kept. Take-home pay, tax, NI and loan figures are unchanged.

2026.09.39

  • Fixed: a tax year the engine does not hold a rate table for was taxed at a hard-coded 10% and 20% on a £37,700 band, the rates before 30 October 2024. A 2027/28 gain is now taxed at the newest held year's rates (2026/27: 18% and 24%), and a year before the table at the earliest held year's (2018/19), with a note saying which and asking you to check gov.uk. The exemption for such a year is still nil, as before. £10,000 of 2027/28 gain on £20,000 of income: £1,800, not £1,000.
  • A sale with a NEGATIVE quantity is now refused by name. It used to become a disposal at nil cost, with the whole proceeds reported as gain and no warning.
  • A holding named like a built-in (constructor, toString, __proto__) is calculated like any other instead of failing the whole calculation.

2026.09.38

  • No tax figure moves. The matching is unchanged in what it decides and in what order; it is now found through indexes instead of by re-reading every purchase for every sale, so a large file is worked out in well under a second instead of taking up to half a minute. The golden comparison is identical across 433 calculations.
  • A text field longer than 1,000 characters, or a declared split with no ticker, is now refused with a message naming the row, and a calculation request is limited to ten a minute from one address.

2026.09.37

  • Fixed: the foreign tax credit on a foreign dividend came out too low when you also had UK dividends. The credit is limited to the UK tax on the foreign income, which is the tax with it less the tax without it (TIOPA 2010 s42), so the foreign dividends sit on top and the dividend allowance goes against the UK ones first. The calculation used the average rate across all your dividends instead, spreading the allowance over the foreign income as well. Example: a £40,000 salary, £2,000 of UK dividends and £1,000 of US dividends with £150 withheld. In 2025/26 the credit is £87.50, not £72.92; in 2026/27 £107.50, not £89.58; in 2021/22, when the allowance was £2,000, £75.00, not £25.00.
  • Where several foreign dividends bore different rates of foreign tax, the one taxed hardest abroad is now the top slice, which lets the most foreign tax be credited. The total credit never exceeds the UK tax on the foreign income. The dividend tax itself is unchanged; only the credit and the SA106 figures move.

2026.09.36

  • Fixed: the stamp duty calculator charged too little Additional Dwelling Supplement on a Scottish second home or buy-to-let. ADS was 4% until 15 December 2022, 6% from 16 December 2022 and 8% from 5 December 2024 (Revenue Scotland); the calculator had 4% until 4 December 2024 and 6% after, one step behind. On a £300,000 purchase completing in June 2025 it said £22,600 where £28,600 is due, and on one completing in 2023 it said £16,600 where £22,600 is due. The /rates/stamp-duty page printed the same wrong history and now prints three schedules.
  • No CGT figure moves. England and Wales are untouched.

2026.09.35

  • Fixed: a bought PUT that you exercised overstated the gain on the shares by twice what the put cost. Exercising a put is selling the shares at the strike, and the price you paid for the put is a cost of that sale (TCGA 1992 s144(3)), so it comes off the proceeds. The engine added it instead. Worked example: shares bought for £800, a put bought for £240, the shares sold under the put for £1,600. The gain is £560; the report said £1,040.
  • Only that one case moves. An exercised call, an assigned call and an assigned put were already right and have a test each that holds them.

2026.09.34

  • Share cover is now shared correctly across every written call open at the same time. 2026.09.34 finishes what 2026.09.33 started: that release split a partly covered call in two, but only when the call stood alone in its group, and a Robinhood export puts every option row from one day in the SAME group because the file carries no order number. So the fix reached almost none of a real Robinhood file.
  • What the old code did with four calls written on one day against 1300 shares, for 3, 1, 10 and 3 contracts: it allocated in date order, which is right, and then took all or nothing per call, which is not. The first two took 400 shares. The ten-contract call could not cover all ten on the 900 left, so it took NONE of them, was reported wholly naked, and left those 900 shares idle for the call behind it. The result read 7 covered and 10 naked on a holding that covers 13.
  • A call now takes the cover it can: the ten-contract call is nine covered and one naked, and the fourth call is naked because nothing is left. 13 covered and 4 naked, and the covered contracts account for exactly the 1300 shares held, with no hundred shares doing the work twice and none sitting idle.
  • Shares stay committed for as long as the call is open and are freed when it closes, which was already right and now has a test either way: a call bought back in March does not hold its shares against one written in June, and a call still open does.
  • No tax figure moves. This is the label on the options analysis and the unbounded-loss count, not the calculation: the engine, the matching and every parser are untouched, and the golden comparison is unchanged across 342 rows.

2026.09.33

  • Share cover on written calls is now worked out contract by contract, and this CHANGES LABELS on the options analysis. No tax figure moves: the calculation, the matching and the engine are untouched.
  • Before, cover was all or nothing. A written call was covered only if you held enough shares for every contract of it, so 104 shares against two written contracts was reported as a NAKED pair, with a loss described as unlimited, and 1300 shares against fourteen contracts was reported the same way. Both were wrong in the alarming direction: one of those two contracts was covered, and thirteen of those fourteen were.
  • A partly covered call is now two positions, a covered call for the contracts the shares cover and a naked call for the rest, with the premium divided between them in proportion. Coverage is allocated oldest first at a hundred shares a contract, so two written calls over one hundred shares are one covered and one naked rather than both of either. Fractional shares count as held but cannot cover a contract on their own.
  • The warning now quotes the numbers it actually used: "1 of 14 written contracts have no shares behind them; 1300 shares cover 13" rather than "only 1300 shares behind it".
  • Three reporting faults went with it. The list of positions could appear twice, because every leg split out of one group carried the same internal id. Identical warnings appeared once per affected position, so one group of three said the same sentence three times. And folding a group of naked calls together with "show multi-leg positions together" made the unbounded-loss count read zero, which was an unearned reassurance rather than a miscount; a folded position now inherits its legs’ unbounded loss.

2026.09.32

  • The options analysis names more positions and stops lumping the rest together. NO TAX FIGURE CHANGES: this is the analysis page and the printed report's options summary, not the calculation.
  • The rule is now that a group of legs either matches a standard strategy exactly or is reported leg by leg. There is no "Unclassified" any more. Four legs that are two separate spreads used to appear as one unnamed block; they now appear as four positions, each named for what it is. Splitting is exact: every leg already carried its own premium and its own closing trades, so the legs add up to what the block showed, to the penny.
  • A new button, "Show multi-leg positions together", folds those legs back into one row labelled by what it is, for example "Custom - 3 legs - calls and puts - 2 expiries". The money is identical in both views.
  • A written call that was split out of a larger group now says so. On its own such a leg is naked and its loss is unbounded; if one of the legs beside it hedges it, the position as a whole is not. The warning says which, and points at the button that puts them back together. Naming the group after the part you recognise would have been worse: that is how a hedged book reads as a directional one.
  • Nine more shapes are named: protected short sale, strap, strip, ratio calendar, ratio diagonal, reverse iron condor, reverse iron butterfly, double calendar and double diagonal. The reverse iron butterfly in particular used to be refused by name on the grounds that calling it an iron butterfly would understate its loss, which was an argument about mislabelling it rather than about naming it.

2026.09.31

  • Fixed: a covered call could be reported as a NAKED call, with its maximum loss shown as "Unbounded", when the shares behind it had been bought in fractional lots. No tax figure moves. What was wrong is the risk label on the Options page and in the printed report, and it was wrong in the worst direction: it described a position with a limited loss as one with no limit at all.
  • The cause is that a share count is not a whole number any more. Brokers sell fractional shares, and three lots written to two decimal places do not always add up to what they obviously add up to: 68.53 + 74.74 + 56.73 comes to 199.99999999999997 in binary floating point, not to 200. Two contracts need 200 shares, the comparison was an exact "is it at least 200", and it said no. The warning then rounded the same number for display, so it printed a sentence that contradicted itself: "a written call with only 200 share(s) behind it, and 0 contract(s) of that holding already written against". 200 shares with nothing else written against them is exactly covered.
  • The share position is now rounded where it is counted, so the number shown is the number compared, and "enough shares" allows for a millionth of a share either way. A real shortfall still reads as uncovered: 199.99 shares against two contracts is a naked call and is still shown as one, with the loss still stated as unbounded, because it is. Whole-share holdings were never affected, and no gain, cost, proceeds or tax figure changes in either case.

2026.09.30

  • The marginal rate on the take-home pay calculator was being rounded to the nearest whole percent, and is now exact. It is the figure that answers "what does my next pound cost me", and it was worked out by pricing one extra pound of salary. Every figure it is built from is held to the penny, so a change measured over a single pound could only ever come out in whole pennies, and the rate in whole points. On a GBP62,000 salary with a 5% pension sacrifice and a Plan 2 student loan it showed 49% where 48.45% is right. It now prices a larger step, which is precise, and falls back to the single pound wherever that larger step would cross a tax threshold and blur two rates together. Most salaries are unaffected: where the true answer is already a whole number, which is the ordinary case without a percentage pension contribution, nothing moves. Nothing else on the page changes, and no tax figure changes: this is the rate shown beside your take-home pay, not a figure used to work it out.

2026.09.29

  • NO FIGURE MOVED IN THIS ONE. Three things the calculators said have changed, and none of them is a number. The dividend tax notes named a file inside this application instead of telling you where to go; they now point at the take-home pay calculator. The stamp duty page answered its first load with a developer's error about a missing field; it now asks for the completion date in plain words, and every other refusal still says exactly what it said before. And the mortgage no longer warns that your last payment left money over.
  • That last one is worth a sentence, because the warning was alarming and wrong. The final payment on a repayment mortgage is not the standard monthly amount: it is whatever clears the debt, which is the balance still owed plus that month's interest, and it is almost always a little smaller. The figures always had that right. The page then warned that the difference was "money to spare" that was "not in the totals", under a heading telling you to check before relying on it. Nothing was missing. The final payment is now printed on the year it falls in, so you can see it, and the totals are to the penny what they were: on the default mortgage, GBP 500,248.80 paid and GBP 200,248.80 of interest, before and after.

2026.09.28

  • Fixed: a Trading 212 trade that settled in a currency other than sterling was charged its dealing costs twice. Trading 212's Total column is all-in: the charge, the stamp duty and the currency conversion fee are already inside the figure it shows. On a sterling trade the app knew that and added nothing further. On a dollar or euro trade it added the same charge on top, so the cost of buying was too high and the proceeds of selling were too low, and the gain came out short by twice the charge on every round trip. That understates tax, which is the direction that matters: it is the return that is wrong, not just the report. On a 10-share round trip with a £5 charge each way the gain was £480.00 where £490.00 is due. Sterling trades, and every other broker, are unaffected. If you have filed a return using a Trading 212 export from a dollar or euro account, check whether the export carried a Charge amount, a Stamp duty or a Currency conversion fee column with figures in it, and if it did, run that year again. The column layout was read from Trading 212's own documented export and the arithmetic is certain; what has not been seen here is a real dollar or euro export with those columns populated, so the check is worth a minute before the re-run.
  • Behind that: a broker can now tell the engine that its money column already contains the fee whatever currency the trade settled in, and the engine believes it. It only listened to that on sterling trades before, which is how this got through. A fee that is in the file must be applied exactly once.

2026.09.27

  • The PDF now shows the part of the annual exempt amount actually used, so the summary column adds up. Taxable gains are unchanged.

2026.09.26

  • Fixed: a sale of shares you didn't yet hold, bought back more than 30 days later, now uses the later purchase's cost (TCGA 1992 s105(2)). Before this fix the gain was overstated. If you short-sold shares and generated a report before 26 September 2026, please run it again.
  • The purchase can fall in a later tax year than the sale, and then the cost still belongs to the year of the sale. If that year has already been filed it needs amending, and the report now says so with both deadlines: twelve months after the filing date for a self-amendment, and four years after the end of the tax year for an overpayment relief claim.
  • Where there is no later purchase at all, the sale is still reported with no cost, and the row now says why: you sold more than you held on that date, so either a purchase is missing from your files or it was a short sale.

2026.09.25

  • Income tax on dividends and interest used one year's figures for every year. The income side of the report worked from a personal allowance of £12,570 and a basic rate band of £37,700 whatever tax year it was reporting. Those are the current figures. For 2018/19 the real ones were £11,850 and £34,500, and for 2019/20 and 2020/21 they were £12,500 and £37,500. The effect was to leave more of a basic rate band than there was, so dividend and interest tax for those three years came out too low. On a £45,000 salary with £5,000 of dividends in 2018/19 the tax shown was £225.00 where £975.00 is due, because £3,000 of the dividend was charged at 7.5% when it belonged above the basic rate limit at 32.5%. Capital gains tax was never affected: that side has always read its own dated table. If you have filed a return for 2018/19, 2019/20 or 2020/21 with dividends or interest on it, re-run those years.
  • Every income tax rate now comes from one dated table with a gov.uk citation on each row, instead of being decided by a stack of conditions on the year. A year the table does not hold is answered with the nearest year it does hold, and the report says which year's rates were used rather than quietly using this year's.
  • An administrator can now enter a rate change before the release that carries it. When a Budget moves an allowance or a rate, the new figure can go in the same day with the gov.uk page it came from, the date that page was read and the address of whoever entered it. Every report that uses one says so on its engine line, naming the table, the tax year and the citation, so a figure that came from somewhere other than the release is visible on the report itself. Nothing is stored without a citation on gov.uk, legislation.gov.uk or parliament.uk, and a year has to carry exactly the fields the shipped year carries, so a figure that went missing cannot quietly become zero. With no override in use the engine line is exactly what it was.
  • The capital gains estimate on screen and the sell simulator now use the same rates and the same annual exempt amount as the report. They held their own copies of the allowance and the rates, which is how a copy comes to disagree with the thing it was copied from. Where a year has not been priced they refuse rather than guess, and say which year it is.
  • The take-home pay calculator holds 2023/24, 2024/25, 2025/26 and 2026/27, each with the gov.uk page its figures were read from, and a tax year selector to pick between them. It refuses a year it does not hold instead of answering with a neighbouring year's bands. 2023/24 carries a note of its own: the National Insurance main rate fell from 12% to 10% on 6 January 2024, so HMRC charge that year at an annualised 11.5% (NIM01625), which is £1,310.05 less on a £50,000 salary than a flat 12% would be.

2026.09.24

  • An airdrop is no longer assumed to be income. HMRC's guidance (CRYPTO21250) draws a line: tokens you received for doing something, or in expectation of doing something, are taxed as income when they arrive and that value becomes their cost. Tokens that simply turned up, in a personal capacity and outside any trade, may not be income at all, and then there is nothing to count as cost when you sell. A broker export cannot tell the two apart. Until now every Binance airdrop was treated the first way. Now you are asked which it was, and until you answer the whole holding is left out of the figures, because the answer changes the cost of every later sale of that coin. Answer that you received them for nothing and the income disappears from your return, the sale is taxed on the whole proceeds, and the report says so on the row. Staking, mining and interest rewards are not affected: those are income on receipt and always were.

2026.09.23

  • Excess reportable income now converts at the rate for the month the income arises, not the month the fund's reporting period ended. The two are six months apart by law. SI 2009/3001 reg 94(4) treats the excess as distributed on the fund distribution date, which is the period end plus six months, while reg 94(3) decides who is charged. The sterling figure was being struck at a rate from a month the income did not belong to. Across the 7,395 figures this app holds in a currency other than sterling, the two rates differ by 3.50% on average and by as much as 17.3%. On the worked example in the previous release, 1,000 units of VWRL over the period ending 30 June 2024, the foreign income is £16.98 rather than £16.92, and the pool uplift moves with it. If you filed on a figure this app produced for a fund that reports in a currency other than sterling, re-run it. Which way it moves, and by how much, depends on the rate over those six months.
  • The ERI lookup and your report now take that month from the same place, so a figure on a fund's page and the figure on your report cannot disagree. They could before.

2026.09.22

  • A naked call is no longer reported as a covered call. The options page found every written call and labelled them all covered, without looking at whether you held the shares, so the one position whose loss has no limit was shown as the safest thing there is. It now counts the shares you held on the day the call was written. Where they are not there it says NAKED, and the maximum loss is stated as unbounded rather than printed as a number.
  • A written put is called a short put, not a cash-secured put. Whether the strike was set aside in cash cannot be seen in a transaction export, so it is no longer asserted.
  • The options page names the structure you actually traded. Butterflies, iron condors, iron butterflies, verticals, calendars, diagonals, straddles, strangles, collars, ratio spreads and the rest are each identified from their own geometry: the strikes, the expiries and the ratio between the legs. Legs that were opened together but form no shape it can name are shown as they are, with the reason, rather than pushed into the nearest one.
  • Each structure says which tax year its money landed in. A position straddling 5 April does not have one answer. A written leg is charged in the year it was granted (TCGA 1992 s144(1)) and the cost of buying it back belongs to that same grant (CG55545), while a bought leg is charged when you dispose of it. Maximum profit, maximum loss and break-even are shown where the geometry defines them. Where it does not, the figure is withheld and named.
  • Concentration counted disposals rather than holdings. Every disposal was treated as its own investment, because the figure it grouped on included the share count. One holding sold twice read as two separate investments, and a portfolio of a single stock sold ten times would have read as a well-spread one. The spread of your results is now measured across holdings, which is what it was always meant to describe.
  • Dates under the charts were a day early for half the year. They were converted through UTC while every trade here carries a calendar date, so between late March and late October each one printed as the day before. A disposal on 6 April, the first day of a tax year, appeared under the year before it.
  • The stamp duty screen said 278%. An effective rate of 2.78% on a £450,000 purchase was multiplied by a hundred a second time, so the caption read "278% of the price, and 500% on the next pound". The tax figure itself was right throughout. The sentence under it was not.
  • The Performance page now opens with the year's realised result: what the best and worst of it were, how it compares with your other tax years, and which holdings drove it, with the detail behind disclosures. It used to be seven charts of equal weight in the order they were built, with no figure larger than any other. Two charts have gone. One drew the same two variables as the chart above it, and the other plotted a percentage and a pound figure on one pair of axes with no scale for either. Every figure they showed is still on the page.
  • The Performance figures were scoped to two different things at once. Most of them covered the whole import while the heading named one tax year. They now all follow the year you have selected.
  • "Not a tax figure" and "sold holdings only" are marks beside the number itself instead of a grey paragraph above it. The Performance figure and the tax figure genuinely differ, and the difference has to be visible where it is read.
  • One set of colours, spacing and controls across the whole site. The calculators, the sign-in panel, the disclaimer and the report were each built with their own idea of a heading size, a card and a button. Sixty-eight emoji were replaced by drawn icons that take the colour of the theme, which an emoji cannot do.
  • Text on the gold buttons was below the legibility standard everywhere and far below it in dark mode, as were the filled badges and the year selector. All of it was measured and corrected.

2026.09.21

  • Two-step verification shows a QR code. It never did before. The setup screen gave you the secret as text and expected you to type thirty-two characters into your phone, which is miserable and easy to get wrong. Scan it instead, or tap "Open in my authenticator app" if you are setting this up on the phone itself. The key is still printed underneath for anyone who would rather type it. No figure changes.

2026.09.20

  • A dealing commission on a trade settled in sterling is an allowable cost again. It was being read off the file and then dropped: the engine applied a fee correctly on a foreign-currency trade and, one branch away, threw it away on a sterling one. Interactive Brokers charges commission on London trades and reports it in sterling, so every IBKR sterling trade lost it on both legs. On a £200 purchase and a £300 sale at £6 each way the gain came out £100.00 where £88.00 is due, and the statement's own Realized P/L column says 88. A commission is an incidental cost of acquisition and of disposal (TCGA 1992 s38(1)(b), s38(1)(c)).
  • Where a broker's money column already contains the charge, the charge is no longer sent separately as well, so nothing is counted twice. Trading 212 and Freetrade both report the all-in cash figure. Where a sterling row carries a fee and gives no way to tell which convention it used, the fee is applied and the report says it has been assumed, naming the rows to check against a contract note.
  • A share split nobody told us about is now spotted and asked about. If you sold more shares than your files account for, or shares left your account with no money against them, the report says which split ratio the numbers fit and asks you to confirm it. It never applies one itself. A missed 2-for-1 leaves half the shares with no cost at all. On a worked example that reported a £1,000 loss for 2024/25 and an £11,000 gain for 2025/26 where the true figures are gains of £4,000 and £6,000. A report cannot call itself complete while the question is open.
  • A consolidation (a reverse split) that your broker recorded as shares leaving for nothing was being treated as a sale at £0, inventing a loss you are not entitled to. On a 1-for-10 of a £1,000 holding that is £900 of allowable loss. It is now flagged, with what to delete and what to enter instead.
  • A split you entered yourself could be applied to a trade made on the split date, doubling a share count that was already doubled, if your computer was not set to UTC. Split dates are now read as calendar dates like every other date here.
  • Funds your broker names only by ticker now find their excess reportable income. A holding shown as VWRL is matched to IE00B3RBWM25 from a sourced table of 1,528 London listings, and the report says so, so you can disagree. On 1,000 units held over the period ending 30 June 2024 that is £16.92 of foreign income that was missing from the return, and £16.92 more cost in the pool: a £4,000.00 gain becomes £3,983.08. Where a name answers to more than one share class, nothing is applied and the report asks which you hold. They have different income per unit.
  • Barclays Smart Investor, AJ Bell and Lightyear files can be imported. Each was written against a real export.
  • A sale whose dealing charge exceeds what it raised no longer reports negative proceeds. The gain was right; the figure beside it looked like a fault. The charge is now capped at the consideration and the excess shown as what it is, an allowable cost.
  • The disclaimer is a page of its own with a box you tick, instead of a wall of red between the heading and the upload box. Nothing is calculated until it is ticked, and if the wording changes you are asked again.
  • One colour scheme, in light and dark, following whatever your computer is set to. Figures that were hard to read against their background have been darkened until they are not. That includes white text on the gold buttons, which was below the legibility standard everywhere and far below it in dark.
  • The admin dashboard is behind a sign-in with two-factor authentication rather than a key in the address bar, and every change made in it is recorded.

2026.09.19

  • Excess reportable income is applied automatically again for funds that report in a currency other than sterling, which is 90.8% of the 11,896 figures this app ships. The lookup that converts them asked for the dollar rate alone, and asked for it in a shape that stopped existing when the rate store started holding every currency HMRC publish. So it applied to the 9.2% of funds already reporting in pounds and nothing else, and said "no HMRC rate was loaded for that month" about the rest. That was not true: the rates were loaded, nothing could read them. ERI is taxable income in the year the fund reports it and it lifts the pool cost, so leaving it out both understates the income and overstates the gain on every later disposal of that fund. Anyone holding an offshore ETF should re-run. Most London-listed ETFs are one, being domiciled in Ireland or Luxembourg.
  • A fund reporting in euros, Swiss francs, yen, yuan, Mexican pesos, Australian or Singapore dollars or Swedish krona now converts at its own currency's HMRC rate. Only the dollar was ever attempted.
  • The offshore yuan (CNH) is still refused by name rather than converted at the onshore (CNY) rate, because HMRC do not publish CNH. That is 0.5% of the dataset, and it is named rather than guessed.
  • The upload screen names every broker it reads instead of four of them followed by "and eleven more". No figure changes. What changes is that you can see Hargreaves Lansdown, Interactive Investor, Vanguard, Fidelity, Revolut, Schwab, Morgan Stanley, Interactive Brokers, Coinbase and Binance are all there.

2026.09.18

  • Exchange rates fetched from HMRC now actually reach the screen. The rate lookup was changed on 2026.09.16 to hold every currency HMRC publish, keyed by ISO code. The button that fetches them was still testing each month against "is this number between 0.5 and 3", which is false for a set of rates rather than a single one. Every month the server retrieved was discarded, and the screen reported it as not found. Rates had to be typed in by hand, and a mistyped rate is a wrong return.
  • Months before January 2021 can be fetched at all. The service this app asks, trade-tariff.service.gov.uk, holds nothing earlier, and it answers a 2019 or 2020 month with the same "not found" it gives for a month that has not been published yet. So an older disposal looked like a gap at HMRC rather than a gap on one website, and the instructions on screen sent you to download a file that is not there. HMRC publish those years themselves, as XML, and those are now read: every month back to February 2015. Nothing about the rates changes, since they are HMRC's own published figures, but a 2019/20 or 2020/21 return that was filled in by hand should be checked against them.
  • A rate is never taken from anywhere but HMRC. A third-party mirror sat at the end of the lookup, read for its Bermudian dollar, which is pegged one-for-one to the US dollar, and labelled "mirror, verify". A label is not a source, and CG78310 asks for the published rate. It is gone. It could never have run in the browser anyway, so no figure moves.
  • The instructions for entering a rate by hand now name the US dollar row. They named the Bermudian dollar, which carries the same number because of the peg, but is not the currency being converted.

2026.09.17

  • Same-day option trades are now settled for every disposal before any 30-day matching runs. s106A is expressly "subject to" s105, so the same-day rule ranks first across the whole set. The share side has worked that way for months and the option side did not, matching each disposal in turn instead, so an earlier disposal could take a contract a later same-day disposal owned by law. On the worked example that was £720 of tax where £480 was due, with both years' returns wrong. Any report containing options bought and sold on the same day should be re-run.
  • Option contracts bought on the same day are pooled at that day's average cost, as s105(1)(a) requires, instead of being drawn on in the order they appear in the file.
  • Buy-backs, assignments and expiries of written options are now applied in date order against one queue of grants. Each used to get its own complete pass, in the order the code happened to run them, so an April buy-back could consume a grant that a March assignment was entitled to. That moves cost between tax years.
  • The cost of a pooled option is now carried in sterling from the moment it is acquired, at the HMRC rate for the month of acquisition. It was being averaged in dollars and converted at the disposal's rate, which charges the currency movement between the two dates as if it were part of the gain.
  • The 30-day bed-and-breakfast window is measured in calendar days. It was measured in elapsed hours, so a window spanning the March clock change was an hour short and a repurchase made exactly 30 days later fell outside the rule, changing which acquisition a disposal matched against.
  • TWTR is no longer merged into X automatically. Twitter was taken private for cash in 2022. That is a disposal at the cash price, not a change of name, and treating it as a rename carried the old cost base into an unrelated holding. A rename is also refused now whenever the new ticker is already held, because merging two real holdings silently averages their cost.
  • A row with no quantity is named in the report instead of being pooled as if it were nil.
  • The personal allowance is right for every year back to 2018/19. It was £12,570 for all of them. It was £11,850 in 2018/19 and £12,500 in 2019/20 and 2020/21, so an earlier year's basic-rate band started in the wrong place and CGT could be charged at the higher rate when it was not due.
  • The higher-rate threshold is right for every year. It was £125,140 throughout, which is the figure from 2023/24 onward (FA 2023 s6). It was £150,000 in 2022/23 and earlier. On £100,000 of salary and £40,000 of dividends in 2022/23 the tax came out £2,128 too high.
  • Dividends falling in the additional-rate band are taxed at the additional-rate dividend rate. Everything above the higher-rate threshold was charged at the upper rate, so on £100,000 of salary and £40,000 of dividends in 2025/26 the tax was £14,163.41 and was being reported as £15,543.25.
  • A pension contribution paid under relief at source now extends the higher-rate limit as well as the basic-rate one (FA 2004 s192(4)). Only the basic-rate band was being extended, which left £10,000 of contributions on a £110,000 salary £2,000 short.
  • Trading 212: a trade settled in dollars was being counted as if the Total were pounds. The currency now comes from the file's own Currency (Total) cell, and a row that names no currency anywhere is refused rather than assumed sterling. On a worked example a $2,976.24 purchase is £2,380.99 at the HMRC rate, and the gain moves from £960.00 to £899.21.
  • Trading 212: a London share quoted in pence was coming out a hundred times too small. The row carried the quote's currency (GBX) while its money was the Total in pounds, so the pence normaliser divided the pounds too. A £757.15 gain was reported as £7.57.
  • Trading 212: interest paid on your cash balance is taxable and was never reaching the return. It was in the skip list, and the skip ran before the income check, so the code that would have captured it could not be reached.
  • Trading 212: foreign tax withheld from a dividend now carries the currency it was withheld in. It was taking the Total's currency, so $0.02 of US withholding was claimed as £0.02 and the foreign tax credit was overstated by the exchange rate.
  • Trading 212: a dividend paid on 6 April was landing in the previous tax year, because the pay date was built from a UTC timestamp rather than the calendar date.
  • Trading 212: an order type we had not seen before, a stop limit buy for instance, was being dropped without a word, and the sale that followed showed the whole proceeds as gain. The direction is now read from the words buy and sell, and anything still unreadable is named.
  • Trading 212: a dividend row with an empty Ticker cell used to stop the entire file importing.
  • tastytrade: shares delivered when a written option was assigned were recorded as a purchase instead of a sale. 100 shares delivered for $15,000 became an acquisition at minus $15,000, and the disposal did not exist at all. It is now proceeds £12,500.00 against £9,600.00 of cost.
  • tastytrade: dividends, interest and withholding tax were all being thrown away. The whole Money Movement section was skipped, so none of it reached SA100 or SA106.
  • tastytrade: a trade whose Instrument Type cell is blank is now read. Share or option is decided from the expiry, strike and multiplier, with the reading stated. Such rows used to vanish, leaving the later sale with no cost: £10,832.40 of proceeds as pure gain where £1,231.50 was the gain.
  • Binance: an order filled in two parts was losing one of the fills. The legs are now summed per coin within the second, so a 10 + 7 ADA order acquires 17 ADA for $22.95 rather than 10 for $13.50. 41% of the cost base had been dropped. Two unrelated trades in the same second are refused and named, because nothing in the ledger says which leg paid for which.
  • Binance: an amount written with a thousands separator was being read as the digits before the comma, so 30,000.00 came through as 30. A 0.5 BTC purchase for 30,000 USDT had a cost of £23.08 instead of £23,076.92, and the gain on selling it came out £24,976.92 against a true £1,923.08.
  • Morgan Stanley: a US-style date such as 03/25/2026 was being read as January 2028. That is the wrong tax year, silently. A date that cannot exist is now refused and named, with the US reading offered rather than taken.
  • Freetrade: every Freetrade file was being read by the Revolut parser and importing nothing at all. Revolut was matching on a column name Freetrade also uses, and was asked first.
  • Freetrade: interest paid on your cash balance was being left out of the return.
  • Morgan Stanley: a Trading 212 file that happened to hold Morgan Stanley shares was claimed by the Morgan Stanley parser and imported nothing. Fidelity accounts holding Vanguard funds had the same problem. Both are now decided by the file's own columns rather than by a name appearing anywhere in it.
  • Morgan Stanley: a dividend reinvestment was being valued as an RSU vest at the gross quantity, because the word "invest" appears inside "reinvestment".
  • Every broker: a row we cannot read is now named in the report with the reason. Schwab, Hargreaves Lansdown, Coinbase, Robinhood and Interactive Brokers each had rows that simply vanished.
  • Interactive Brokers: currency conversions in a statement are now named, with what s252 means for them, instead of passing unmentioned.
  • Creating an account no longer reveals whether an address already has one. The wording was always identical. The reply came back in half a millisecond for an address we knew and forty-three for one we did not, and the clock answered the question the words refuse to.
  • A second sign-up for an address can no longer take over the first. Each sign-up now carries its own password on its own link, so whoever reads the mailbox decides.
  • Verification and password-reset links are no longer written to the server log, in any mode, and the server refuses to start in the mode that used to print them.
  • Signing in, registering and resetting a password can no longer be switched off for everyone at once by filling the rate limiter's table.
  • A missing file is a 404 again whatever it is called. That is the same failure that once rendered a blank app in production.
  • The upload area can be reached from the keyboard, column headers sort with Enter, every remove button says what it removes, and every box on the transactions and rates screens has a name a screen reader can read out.
  • The monthly gains chart's pop-up is legible. Its figures were left over from a dark colour scheme and the net gain sat on white at a contrast of 1.74 to 1.

2026.09.16

  • A holding priced in euros, yen or any currency other than the dollar is now converted at that currency's HMRC rate. It was being divided by the dollar rate, because the rate lookup had no currency in it at all and the store held one column, the dollar. On a worked example, €5,000 bought in May 2025 and €6,000 sold in August, the gain came out as £663.37 where the published euro rates give £915.33, and nothing in the report said so. The further a currency sits from the dollar the larger the error: for a yen holding it was a factor of about 167. Any report covering a non-dollar holding should be re-run.
  • HMRC publish about 140 currencies in the same monthly file, and all of them are now kept and used. Only the dollar was being stored; the rest were parsed and thrown away.
  • A currency with no published rate for the month is refused by name instead of borrowing another currency's. "MISSING RATE" now says which currency as well as which month. It used to say "USD" whatever the holding was, which sent you looking for a month that was in fact present.
  • A row already denominated in sterling is no longer divided by the dollar rate, which had been shrinking it by about a third.

2026.09.15

  • A corporate action no longer wipes out the whole year's tax. A spin-off, a transfer out and a nil-cost transfer in are all recorded as rows worth £0 in sterling, which is correct, because their cost arrives from the parent pool or leaves with the shares. The engine tested that figure for truthiness rather than presence, read the £0 as no sterling figure given, and fell back to converting a foreign amount that those rows do not carry. The result was not a number, and not-a-number spreads. On one worked example a spin-off made an unrelated £39,200 gain in the same year report no tax at all, where £8,671.80 was due. Any report that included a spin-off, a transfer in or a transfer out should be re-run.
  • Nothing that is not a number can now leave the engine. A row whose sterling value cannot be established by any route is named in the report and treated as nil, instead of being passed through into the totals. A missing figure is a question for the filer, never a hole in the arithmetic.

2026.09.14

  • Cryptoasset rows we could not value can now be priced. HMRC publish monthly rates for currencies and a token is not one. A row carrying no sterling consideration, which is typical of a token-for-token swap, had nothing to convert and nothing to look up, so the whole holding was withheld from the figures. The engine had accepted a price for this since 2026.09.2 and the browser had no box to type it into, so the advice was unfollowable. "Price £/unit" on the transaction editor supplies it: the sterling price of one unit, which is what CRYPTO22600 asks the taxpayer to work out and keep a record of. Every priced row is named in the report with its arithmetic, qty @ price = consideration, so a per-unit figure mistaken for a deal total is visible rather than plausible.
  • Every explanation of a withheld cryptoasset now reaches the report: which row could not be valued, why, and that the whole holding was quarantined rather than valued at nil. The engine produced them all and the server dropped them before the response was built. A holder of an unpriceable token saw the holding simply absent, with nothing said. No figure changes. What changes is that the silence is gone.
  • Cryptoasset pools are in the closing position. A token is pooled exactly as a share is, but only share pools were returned, so someone still holding coins was told "nothing is left in a Section 104 pool". That pooled cost is the figure that carries into next year's return. Where one name appears as both a share and a token in the same import, the two are not merged. They are different assets and a pool holds one kind (TCGA 1992 s104(3)), and the clash is named.
  • A tax year split by a change of residence can now be answered. Residence is a whole-year status (FA 2013 Sch 45), so disposals made after you left are out of charge only if one of the eight Cases in RDR3 Part 3 is met. That turns on homes, full-time work abroad and day counts that no broker export carries. The Residency panel now asks, and the answer moves money: say that none of the Cases applies and every disposal in that year becomes chargeable, including those made while abroad. Left unanswered the date still decides, which is right whenever a Case is met, and the year is flagged so the figure is not mistaken for a settled one.

2026.09.13

  • The annual exempt amount is right for every year back to 2018/19. The table started at 2023/24 and every earlier year silently fell back to £3,000. The allowance was £12,300 in 2020/21, 2021/22 and 2022/23, £12,000 in 2019/20 and £11,700 in 2018/19. A 2019/20 gain of £19,000 was therefore taxed on £16,000 instead of £7,000. All figures verified against gov.uk.
  • A tax year the engine does not hold an allowance for no longer gets £3,000 by default. It gets none, and the report says the allowance is not held and that the taxable figure shown is too high. A wrong exemption applied quietly is the worst kind of error. Nil overstates the tax, which is at least the safe direction, and it is now said out loud.

2026.09.12

  • Interactive Investor statements are read at last. The real export is a cash ledger: Date, Settlement Date, Symbol, Sedol, Quantity, Price, Description, Reference, Debit, Credit, Running Balance, with no Type column and no Amount column. The parser looked for both, so every row came back a non-trade and the file imported with nothing in it and nothing said. Direction now comes from Debit against Credit and from the Reference (B... a purchase, S... a sale), and a row where those disagree is refused with a reason rather than guessed at.
  • Interactive Investor: Debit and Credit are all-in cash movements. 1,000 Vodafone at 0.6954 is £695.40 of shares and a £703.35 debit, with the dealing charge and stamp duty already inside it, so the figure is taken as given and no fee is added on top.
  • Interactive Investor: buying a fund with DIVIDEND in its name is a purchase. "VANGUARD FTSE ALLWLD HIGH DIVIDEND YIELD" was read as a £462.95 dividend because the word appears in the fund's name. A row with a quantity is a trade, and only a row with nothing bought or sold is considered for income.

2026.09.11

  • Interactive Brokers: an Activity Statement is recognised however long its preamble is. Detection read only the first 4,000 characters, and a real statement opens with Account Information, Net Asset Value and Change in NAV before it reaches the trades. In two published statements the Trades section starts at byte 9,771 and byte 19,523, so neither was detected and both had to be selected by hand.
  • Interactive Brokers: a statement generated without per-trade detail now says so. Where the Trades section holds only subtotals there is nothing to compute a gain from, but the warning only fired when the file had no income either, so a statement with dividends imported quietly with every disposal missing.
  • Interactive Brokers: a trade whose Quantity and Proceeds carry the same sign is flagged. A purchase is a positive quantity with negative proceeds and a sale is the reverse, so a row where they agree is malformed, and reading a disposal as an acquisition is wrong twice over. It is still counted, on the quantity, and named.

2026.09.10

  • Coinbase: a CONVERT is no longer counted twice. Swapping one coin for another is a disposal of the first and an acquisition of the second (CRYPTO22110), and Coinbase writes that as two rows: the coin leaving with a negative quantity, the coin arriving with a positive one, both carrying the same "Converted X A to Y B" note. The parser read that note and produced both legs from every row, so one swap became four transactions, with the disposal counted twice and the acquisition counted twice. On a real four-year export that turned 68 transactions into 104 and doubled both the crypto gains and the pool. Where an export gives only one row for a swap, the missing leg is reconstructed from the note and said to be reconstructed.
  • Coinbase: a current export is recognised again. Detection demanded a "Spot Price" column and Coinbase has renamed it "Price at Transaction", so recent files were not detected at all and had to be selected by hand.
  • Coinbase: withdrawing your own pounds is no longer flagged as a possible disposal. It is a fiat movement and is named as one. A crypto Send still is flagged, since it may be a spend or a gift (CRYPTO22100), and a Receive is now named too, with what it means: those coins are not in the pool, so a later disposal of them shows as unmatched and its gain would be overstated. Receives used to be dropped in silence.

2026.09.9

  • A written option bought back after the end of the tax year it was granted in is now called out. The figures were already right. What you pay to close is an allowable cost of the grant (CG55545), so it reduces the gain of the year the option was written. The report said nothing about what that means if that year has already been filed. It now names the amount, the year it moves to, and both deadlines: amend the return yourself within twelve months of the filing date (TMA 1970 s9ZA), then claim overpayment relief for up to four years after the end of the tax year (TMA 1970 Sch 1AB). On one real file that is £515.64 of closing costs landing back in 2025/26.

2026.09.8

  • tastytrade: the Action column is read whichever way it is written. It has been seen both as "Buy to Open" and as BUY_TO_OPEN, and only the first was matched, so an export using the other spelling imported with no trades at all. Underscores, spacing and case are now normalised away before matching, and the same normalisation is applied to Expiration, Assignment and Exercise.
  • Fidelity: a US brokerage export (the one with a Run Date column) is now named as unsupported, with what to do instead. This parser reads Fidelity's UK platform export. The US file previously just failed to find a header.

2026.09.7

  • Hargreaves Lansdown: trades from the Transaction Summary export are read at last. That export puts the security name in Description and signs the deal in the Reference column (B... is a buy, S... a sale). The parser only understood "Bought" and "Sold", so every real trade was discarded as a non-trade and the file imported with no disposals at all. The holding name no longer swallows the quantity and price either. "... 4563 @ 3287.199" made a purchase and a sale of the same fund into two different holdings, and the sale got a nil cost base.
  • Revolut: BUY and SELL rows are read. Revolut writes the currency inside the money cell ("USD 1000"), so the amount could not be parsed and every trade was rejected while the dividends came through. The file imported cleanly and produced nothing to tax.
  • Morgan Stanley: vest dates in dd-Mon-yyyy form ("25-Mar-2026") are read, and a net-settled vest now brings in only the shares actually delivered. Counting the gross quantity left the shares withheld to pay the income tax sitting in the pool, where no disposal could ever clear them.
  • Freetrade: a FREESHARE_ORDER is an acquisition at the value it was given at (TCGA 1992 s17(1), s37), not a row to skip. Skipped, the share had no cost, so selling it charged the whole proceeds as gain. A free share worth £11.04 sold for £10.63 showed a £10.63 gain instead of a 41p loss.
  • An Interactive Brokers Transaction History statement and a Vanguard cash report are now named as the wrong export, with what to download instead, rather than failing with a bare message.

2026.09.6

  • Same-day identification (s105) is now settled for every disposal before any 30-day matching. It was applied one disposal at a time, in date order, so an earlier disposal's bed-and-breakfast claim could take an acquisition that a later same-day disposal was entitled to, and that disposal then fell through to the Section 104 pool. On one real file: 700 shares sold on 19 Sep 2025, then 21 bought and 20 sold on 25 Sep. The 19 Sep disposal took the 25 Sep purchase, and the 25 Sep gain came out at £29.14 instead of £2.18.
  • No fee is added to a Robinhood share trade any more. Two were, and the export disproves both. The first was a 0.1% FX spread on every trade. Robinhood charges that when it converts currency, and those conversions are their own rows, so across 104 sells the model invented $194.13 that is not in the file. The second was TAF at $0.000166/share, which is real but already deducted in the Amount column: 700 shares at $25.50 is $17,850.00 gross and $17,849.88 net, and the 12 cents is the TAF. It cost £208 of gain on one 2025/26 file, spread invisibly across every disposal in the same direction.
  • An option premium now attaches to the share leg of its own assignment or exercise. Brokers book the share leg a day either side, so there is a fallback that allows 3 days either way, and it could beat a same-day match: a call written on 9 July 2025 and assigned on 11 July put its £29.33 on an ordinary 9 July sale instead of on the assigned one. Within a year the total was unaffected. Across 5 April it is the wrong return.

2026.09.5

  • The CGT rate now follows the income of the year being reported. One income figure used to be applied to every year in the file, which gets every year but one wrong: a £27,000 taxable gain costs £2,700 in a year you earned nothing and £6,480 in a year you earned £150,000. The figure is editable per year, and the income layer uses that year's figure for the savings and dividend bands too.
  • Foreign Tax Credit Relief is no longer computed for a distribution whose issuer country is unknown. The relief is the lower of the tax withheld, the treaty limit for the payer's country and the UK tax on that income (TIOPA 2010 s42). With no country there is no limit to apply, so the old behaviour quietly allowed the whole amount withheld, in your favour, against a country a real SA106 has no box for. The tax is not written off. It is reported as pending, and the report now asks for the country. Answering it produces the credit.
  • Foreign currency conversions are reported. Currency other than sterling is an asset (TCGA 1992 s21(1)(b)). A foreign currency bank account held by an individual has been outside capital gains since 6 April 2012 (s252, FA 2012 Sch 12), and a brokerage cash balance is not obviously one. Where it was held is a question rather than an assumption. The pool is at average cost: s104 and s106A apply to securities, and currency is not one, so there is no same-day or 30-day rule. Where the conversions in a file do not account for all the currency sold, which happens when the currency sold came from a share sale, no figure is produced and the shortfall is named. Every conversion is listed either way.

2026.09.4

  • A trade is now dated by its calendar date, not by the timestamp on the wire. The browser sends each date in UTC, so from the UK in summer time midnight on 6 April 2026 travels as 5 April 23:00 and the server read back 5 April. Two consequences, both of which looked right. A disposal on 6 April, the first day of a tax year, was filed on the previous year's return, and anything dated the 1st of a month between late March and late October was valued at the previous month's HMRC rate. On one real file that was 5 disposals in the wrong tax year and 65 rows at the wrong rate.
  • Robinhood: interest, stock-lending payments and withholding tax are reported as income. They were dropped in silence, not counted, not warned about, not listed as rejected. On one real file that was 28 interest payments, 6 lending payments and a withholding row, none of them mentioned anywhere. Two more codes, ISABR and IENT, were in no list at all and vanished the same way. Every code a file can carry is now either counted or named with a reason.
  • Robinhood: a stock reward paid in shares takes the base cost it was taxed on (TCGA 1992 s17(1), s37) instead of being acquired at nil cost, which overstated the gain on every later sale. Where there is nothing to value it with, the row is named rather than guessed at.
  • Income is totalled per tax year. A single summary used to be built from every income row in the file and labelled with the latest year, so a file spanning three years put three years of interest on one year's SA106. That is the right total for a period nobody files.

2026.09.3

  • Traded options now follow the share identification rules, not first-in-first-out. CG55535: options of the same series are pooled in a Section 104 holding, so a disposal is matched same-day (s105), then against anything bought in the next 30 days (s106A), then against the pool at its average cost (s104). That is the same order shares have always used here. FIFO got all three wrong. It preferred an older contract to one bought the same day, it never looked forward at all, and it handed over the oldest contract's cost where the pool average was due. On a day-traded book this moves most option figures; on one real 2025/26 file it moved the year's total gain by £703, and it also matched a contract FIFO had reported as unmatched.
  • A written option is charged in the tax year it was granted, not the year it was bought back or lapsed. Granting an option is itself the disposal (TCGA 1992 s144(1), CG12312), a later buy-back is an allowable cost of that grant (CG55545), and a lapse has no effect on the grantor at all (CG55536). Each leg still converts at its own date's HMRC rate. A position written in March and closed in April used to fall in the wrong tax year entirely.
  • Every option disposal now names the rule that matched it and carries the matched lot, so the report shows same-day / 30-day / pool the way it already does for shares.

2026.09.2

  • Split years (RDR3 Part 3): a residency change part-way through a tax year is now raised as a question rather than assumed. Residence is a whole-year status, so the overseas part is out of charge only if one of the eight Cases is met, which turns on homes, work abroad and day counts that are not in your transactions. Until it is answered the date still decides, as before. Declaring that no Case applies makes the whole year chargeable: on a £50,000 gain after a September departure that is £9,018 of tax where the report previously showed nil.
  • A user-supplied sterling price (priceOverrideGBP) is accepted where no crypto price could be established, instead of the row being refused. A price that is not usable is named and ignored, never guessed.

2026.09.1

  • Offshore funds: a loss on a non-reporting fund is an allowable capital loss (reg 42), no longer discarded.
  • ERI is reported as income as well as a pool uplift, dated the fund distribution date (period end + 6 months).
  • ERI: units bed-and-breakfasted across a period end are deemed held (reg 94(3A)); the uplift is dated, so no earlier disposal takes a share of it.
  • Residency: non-residents are not charged on shares or crypto; temporary non-residence defers to the year of return (s1M/s1N).
  • Bed & breakfast no longer matches a repurchase made while non-resident (s106A(5A), acquisitions from 22 Mar 2006).
  • Corporate actions: ticker renames, cash mergers, spin-offs, stock dividends, returns of capital and transfers in/out.
  • A per-transaction FX override is honoured and named in the report.

2026.08.1

  • First versioned engine: share matching, pooling, options, crypto, ERI pool uplift and the income layer.