Skip to main content

ato-benchmark-compare

tests licence: MIT python

Compare a set of profit and loss figures against the ATO small business benchmarks, on your own machine, with the working shown.

The ATO publishes benchmark ranges for 100 industries and uses them to pick which small businesses to look at more closely. Checking a client against them is a sensible thing to do before lodgment, and it is usually done by hand: find the industry page, work out which turnover range applies, add up the right accounts, and divide. This does that, and it records which accounts went into which figure so the answer can be checked by someone else later.

Australian tax rules only. Every figure comes from the ATO's own published dataset, and the comparison is a comparison, not advice.

What it gets right

The arithmetic is not "expenses over income". The ATO defines these ratios narrowly, and the differences change the answer:

  • Turnover is the sales of goods and services label, not total income. It falls back to total business income only when sales are blank, zero, or less than 50% of total business income.
  • Total expenses for the ratio is total expenses less payments to associated persons. Wages to a spouse or an associated entity come out before the division.
  • Cost of sales for the ratio excludes salary and wages, so the wages sitting in a bakery's cost of sales are moved out of the numerator and stay in total expenses.
  • The key range is cost of sales to turnover where the ATO publishes one for that industry, otherwise total expenses to turnover.
  • Turnover bands are treated as adjoining. The ATO prints $65,000 - $400,000 then $400,001 - $750,000, which read literally leaves $400,000.50 in no band at all.

Source: Australian Taxation Office, How we calculate benchmark ratios (QC 37143).

Install

git clone https://github.com/ryanduguid/ato-benchmark-compare.git
cd ato-benchmark-compare
pip install .

Python 3.10 or later. The runtime has no dependencies at all: the benchmark data ships inside the package and nothing is fetched at run time.

Use it

The flow is two commands, because the middle step is a person reading the ledger.

1. Draft a mapping from the profit and loss.

ato-benchmark-compare map --profit-and-loss examples/bakery-pnl.csv --out mapping.csv

That writes one row per account with a suggested bucket, the reason it was suggested, and the amount it read. Suggestions come from account names alone.

2. Review it. Open mapping.csv, fix the buckets, and change the source column to reviewed. ato-benchmark-compare buckets explains each bucket. This is the step that decides whether the answer is worth anything: no account name tells you whether wages went to an associate.

3. Compare.

ato-benchmark-compare compare \
  --profit-and-loss examples/bakery-pnl.csv \
  --mapping examples/bakery-mapping.csv \
  --industry "Bakeries and hot bread shops"
ATO small business benchmark comparison
=======================================
Business type:  Bakeries and hot bread shops
Benchmark year: 2023-24
Turnover:       $850,000.00 (sales of goods and services)
Turnover band:  More than $750,000

Ratio                                   This business  ATO range         Result
---------------------------------------------------------------------------------
Cost of sales to turnover (key)         31.76%         29% to 36%        within
Total expenses to turnover              83.17%         82% to 90%        within
Labour to turnover                      27.39%         -                 no benchmark in this dataset
Rent to turnover                        7.29%          -                 no benchmark in this dataset
Motor vehicle expenses to turnover      1.12%          -                 no benchmark in this dataset

Figures used
  Sales of goods and services   $850,000.00
  Other business income         $1,200.00
  Total business income         $851,200.00
  Total expenses                $751,950.00
  Less payments to associates   $45,000.00
  Total expenses for the ratio  $706,950.00
  Cost of sales excluding wages $270,000.00
  Labour                        $232,800.00

Add --json result.json for the same result as structured data, including every bucket total and the source metadata.

Other commands:

ato-benchmark-compare industries --search cleaning   # find the ATO business type
ato-benchmark-compare show "Bakeries and hot bread shops"
ato-benchmark-compare buckets

Input formats

The format this tool guarantees is two columns, with an optional section column of income, cost_of_sales or expense:

account,amount
Sales,850000
Purchases,290000

A report style export, with a title block, section headings and subtotal rows, is also read. Subtotal rows are detected and written into the mapping marked excluded rather than dropped, so a total can never be quietly added to the figures it totals, and nothing vanishes without appearing in a file you can read. Amounts are taken from the first column that parses as amounts; --amount-column takes a column number or a column heading when a comparative export has more than one.

The report style layout is inferred. It was written against the shape these exports normally take, not verified against a real export from any particular accounting package. Check the mapping file against your own export the first time, and use --amount-column if it picked the wrong period.

Buckets

Bucket What the ATO does with it
turnover Sales of goods and services. The turnover denominator.
other_income Business income that is not sales. Only reaches turnover through the fallback rule.
cost_of_sales Cost of sales, excluding wages inside it.
cost_of_sales_labour Wages inside cost of sales. Kept out of the cost of sales ratio, kept in total expenses and labour.
salary_wages Salary and wages outside cost of sales.
contractor_commission Contractor, subcontractor and commission expenses.
associated_persons Payments to associated persons. Deducted from total expenses and from labour.
rent Rent expenses.
motor_vehicle Motor vehicle expenses.
other_expense Every other expense, including superannuation and depreciation.
excluded Outside the ATO calculation: income tax expense, subtotal rows.

Exit codes

Code Meaning
0 Comparison produced, key ratio inside the ATO range
1 Could not produce a comparison, for example an account with no mapping entry
2 Comparison produced, key ratio outside the ATO range
3 Comparison produced, but accounts still carry suggested buckets

What it does not do

  • It is not tax advice, and sitting outside a range is not a finding that anything is wrong. The ATO publishes ranges precisely because businesses differ.
  • The bulk dataset the ATO publishes carries the two key ratios only. Labour, rent and motor vehicle ratios are calculated and shown, but the ranges for them are on the ATO's individual industry pages and are not in this dataset yet.
  • Activity statement benchmarks are not covered. The ATO has not produced them since 1 July 2017.
  • It reads a profit and loss. It does not read a tax return, so it cannot see the W1 label, the salary and wages code, or anything else that only exists at lodgment. Pass --w1 if you want the ATO's W1 rule applied to the labour ratio.

Client data

Nothing leaves the machine. There is no network call anywhere in the runtime.

The .gitignore blocks the file names a real ledger arrives under, including pnl*.csv, mapping*.csv, spreadsheets, and client-data/. The example files are invented. Do not commit a real one.

Benchmark data

Year Business types Source
2023-24 100 ATO Small Business Benchmarks, data.gov.au
2022-23 100 same dataset

Each shipped file records the resource URL, the date it was retrieved, and the SHA-256 of the ATO workbook it was built from. The comparison prints all of that, so a report can be traced back to a specific published file.

To add a year when the ATO publishes one:

uv run --with openpyxl python tools/build_dataset.py \
  --xlsx small-business-benchmarks-2024-25-data.xlsx \
  --year 2024-25 \
  --resource-name "2024-25 Benchmarks" \
  --resource-url https://data.gov.au/... \
  --resource-last-modified 2027-03-15T00:00:00 \
  --retrieved 2027-03-20 \
  --out atobenchmark/data/benchmarks-2024-25.json

The builder refuses a workbook whose columns are not where it expects them, rather than quietly producing a dataset with the ratios in the wrong places.

Attribution

The benchmark figures are derived from Australian Taxation Office data, Small Business Benchmarks, used under CC BY 2.5 AU. The data has been converted from the ATO's spreadsheet into JSON, and turnover band bounds have been made adjoining as described above. No published ratio has been altered. The ATO has not endorsed this tool and has nothing to do with it.

The code in this repository is MIT licensed.

Author

Written by Ryan Duguid, a provisional member of Chartered Accountants ANZ, independently, in his own time and on his own equipment. Nothing here is the work of any employer, and no client data was used to build or test it.

Parts of this repository were written with AI assistance. Every ATO rule it implements was checked against the ATO's own published pages, and the shipped benchmark figures were cross checked against the ATO's industry page for the same industry.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ato_benchmark_compare-0.1.1.tar.gz (54.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ato_benchmark_compare-0.1.1-py3-none-any.whl (42.5 kB view details)

Uploaded Python 3

File details

Details for the file ato_benchmark_compare-0.1.1.tar.gz.

File metadata

  • Download URL: ato_benchmark_compare-0.1.1.tar.gz
  • Upload date:
  • Size: 54.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for ato_benchmark_compare-0.1.1.tar.gz
Algorithm Hash digest
SHA256 7f4108006491e3f64e8da6075ca366aaef72edb0d3e1e470e9cce6adf558c1ae
MD5 a9b555fd1dc61808480b7d49e5143c17
BLAKE2b-256 06ce1d3b2293d9bf1c00e0d224e3e1ee9b281b13d5edfc821d0575ac244cee8c

See more details on using hashes here.

Provenance

The following attestation bundles were made for ato_benchmark_compare-0.1.1.tar.gz:

Publisher: release.yml on ryanduguid/ato-benchmark-compare

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ato_benchmark_compare-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for ato_benchmark_compare-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a5283f6cd3acbaa192d5edd01203649a08b2427a635d623db7df710a7b5cbe83
MD5 2d8be8f8426250cddc91430e6d9e9dd1
BLAKE2b-256 94eaf7bc45e843c1f444f84613d1d38633566f1334ce491cfe97b2e2b4d24960

See more details on using hashes here.

Provenance

The following attestation bundles were made for ato_benchmark_compare-0.1.1-py3-none-any.whl:

Publisher: release.yml on ryanduguid/ato-benchmark-compare

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.4

2 files

0.1.3

2 files

This release

0.1.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page