v1.0.0 to v2.0.0
46 added, 21 removed. Audit A to A.
---
name: capital-gains-vs-business-income-classification
- description: Quantitative tax classification engine to automatically categorize trading
- activity as Capital Gains vs Business Income (Speculative / Non-Speculative) based
- on holding periods and asset class.
+ description: Jurisdiction-aware post-trade tax classification engine that sorts closed
+ trades into capital gains versus business income under Indian (s.43(5), s.2(42A)),
+ US (IRC s.1222, s.475(f), s.1256) and Canadian (ITA s.39(4), IT-479R, IT-346R) rules.
domain: Back-Office
subdomain: Taxation & Compliance
tags:
- tax
- capital-gains
- business-income
- speculative
- classification
brokers_frameworks:
- Generic Post-Trade
- version: "1.0.0"
+ version: "2.0.0"
author: algo-trading-skills-contributors
license: Apache-2.0
---
## When to Use
- Use this skill when processing end-of-year post-trade data for tax reporting or when building a backtesting engine that needs to accurately model net post-tax PnL. Tax authorities (like the CRA, IRS, or CBDT) differentiate heavily between casual investing (Capital Gains) and frequent algorithmic trading (Business Income). F&O trading is typically classified differently from Intraday Equity or Long-Term Equity.
+ Use this skill when sorting a year's closed trades into the tax buckets a *particular* tax authority recognises — for end-of-year reporting, or for modelling net post-tax PnL in a backtest. The classification is jurisdiction-specific down to the category names, so the engine takes `Jurisdiction` as a required argument:
+ | | India | United States | Canada |
+ |---|---|---|---|
+ | Business income split by speculation? | **Yes** — speculative vs non-speculative (s.43(5)) | No such concept | No such concept |
+ | Capital gains split by holding period? | Yes — 12 months listed, 24 months otherwise (s.2(42A)) | Yes — more than one year (IRC s.1222) | **No** — holding period is irrelevant |
+ | What makes trading income business income? | Shares held as stock-in-trade (CBDT Circular 6/2016); non-delivery settlement is always speculative business | An IRC s.475(f) mark-to-market election | Income account under the IT-479R factors, absent an ITA s.39(4) election |
+
+ ## When NOT to Use
+
+ - **For a jurisdiction not listed above.** There is no generic mode and no default. Porting India's speculative/non-speculative split to a US or Canadian return invents categories that do not exist on those forms.
+ - **To compute tax payable.** The engine classifies only. It applies no rates, no s.112A ₹1.25 lakh exemption, no s.111A rate, no Canadian inclusion rate, no US bracket.
+ - **To net losses across buckets.** Bucket-level set-off rules are separate and asymmetric — an Indian speculative business loss can only be set off against speculative business income (s.73), which the aggregate output does not enforce.
+ - **As the s.1256 engine.** US s.1256 contracts are flagged and routed out to `section-1256-contract-tax-treatment-us-futures`; the 60/40 split is not computed here.
+ - **To decide whether the taxpayer *is* a trader.** Trader-versus-investor status, the s.475(f) election, the s.39(4) election and the stock-in-trade position are all filing positions the taxpayer takes with an adviser. They are inputs (`TaxElections`), never inferences the engine draws from trade frequency.
+
## Prerequisites
- - Trade execution ledger with entry and exit timestamps.
- - Asset class tags (e.g., Equity, Derivative).
- - A clear definition of the local tax jurisdiction's rules regarding speculative vs. non-speculative holds.
+ - Closed round-trip trades with acquisition and disposal timestamps. Prefer timezone-aware timestamps: the session *date* decides intraday classification, and a US session closing at 16:00 ET falls on the next UTC date.
+ - Asset class tags, plus whether the instrument is listed on a recognised exchange (`is_listed`).
+ - For India, a delivery flag (`settled_without_delivery`) per trade. The statutory test in s.43(5) is settlement without actual delivery, not the calendar.
+ - The taxpayer's elections for the year, as a `TaxElections` object.
## Workflow
- 1. **Trade Ingestion**: Feed closed trades into the `TaxClassificationEngine`.
- 2. **Holding Period Extraction**: The engine calculates the duration between the open and close timestamps.
- 3. **Asset Class Filtering**:
- - Derivatives (Futures & Options) are categorically marked as *Non-Speculative Business Income*.
- - Intraday Equities (hold time < 1 day) are categorically marked as *Speculative Business Income*.
- - Equities held > 1 day are evaluated based on frequency and duration to determine if they qualify as *Capital Gains* (Short-Term or Long-Term).
- 4. **Aggregation**: Output a classified PnL ledger to map against the appropriate tax brackets.
+ 1. **Fix the Jurisdiction First**: Construct `TaxClassificationEngine(Jurisdiction.INDIA | UNITED_STATES | CANADA, elections)`. There is no neutral default, because the output categories differ per jurisdiction. `aggregate_pnl` returns only the buckets that exist in that jurisdiction, so a caller cannot read a zero out of a bucket its tax code does not have.
+ 2. **Supply Elections, Never Infer Them**: Populate `TaxElections`. A high trade count does not by itself make a US trader's gains ordinary — only a timely s.475(f) election does. Note that s.39(4) is unavailable to traders and dealers under s.39(5) and cannot be rescinded once made.
+ 3. **Normalise Timestamps**: The engine converts aware timestamps to the exchange-local session timezone before taking dates, and rejects a trade whose open and close differ in timezone awareness rather than comparing them and producing a `TypeError` deep in the call stack.
+ 4. **Classify**: `explain_trade()` returns the category *and* the rationale naming the provision applied — keep the rationale in the ledger, because it is what makes the classification auditable a year later.
+ 5. **Apply the Delivery Test (India)**: If `settled_without_delivery` is not supplied, the engine falls back to a same-session-date proxy and logs a warning. Treat that warning as a data-quality defect to fix, not as noise: the proxy misclassifies delivery-based same-day trades and BTST positions.
+ 6. **Route the Buckets**: Send each category to its own return line and its own set-off pool. Deduct infrastructure and data costs only against business-income buckets.
> Full procedure: see `references/workflows.md`.
> Standards reference: see `references/standards.md`.
> Printable pre-flight checklist: see `assets/checklist.md`.
## Common Pitfalls
- - **Mixing Classifications**: Randomly switching between treating a strategy as Business Income one year and Capital Gains the next; this triggers regulatory audits.
- - **Ignoring Wash Sales**: Failing to account for superficial loss rules or wash sale rules when treating activity as Capital Gains.
- - **Deducting Expenses Improperly**: Deducting server and data costs against Capital Gains instead of Business Income.
+ - **Assuming the Categories Travel**: "Speculative business income" is a creature of India's s.43(5). A US return has no such line; an intraday US equity round trip is an ordinary short-term capital gain absent a s.475(f) election. Canada has neither the speculative split *nor* a long-term/short-term split.
+ - **Counting 365 Days Instead of 12 Months**: Both India (s.2(42A): "not more than twelve months") and the US (IRS Topic 409: "more than one year") use calendar periods and a *strict* threshold. A position bought 1 Jan 2024 and sold 31 Dec 2024 is 365 days but is still short-term; and one sold on the 1 Jan 2025 anniversary is *also* still short-term. A `days >= 365` test gets both wrong.
+ - **Treating F&O as Business Income Everywhere**: India's s.43(5) proviso (d) carve-out only reaches *eligible* derivative transactions on a *recognised stock exchange* — an OTC derivative stays speculative. In the US the same contract is likely a s.1256 contract with a 60/40 split, and in Canada IT-346R lets a speculator report futures on capital account if done consistently.
+ - **Deriving Session Dates from UTC**: Taking `.date()` off a UTC timestamp turns a single US or Canadian session into a two-day hold, flipping an intraday trade into an overnight one.
+ - **Switching Basis Between Years**: Every election here carries a consistency obligation — CBDT Circular 6/2016, IT-346R, and the irrevocable s.39(4) election alike. Flipping treatment year to year is what invites the assessment.
+ - **Summing a Tax Ledger in Floats**: Binary float drift lands in a filed figure. The engine accumulates in `Decimal` and converts incoming floats via `str()`.
+ - **Deducting Expenses Against Capital Gains**: Server, data-feed and execution costs are deductible against business income, not against a capital gain.
+ - **Ignoring Wash Sale / Superficial Loss Rules**: Neither is applied here — see `wash-sale-rule-tracking-us`.
## Verification
- - Simulate an intraday equity trade, an options trade, and a 2-year equity hold. Verify the engine correctly outputs Speculative Business, Non-Speculative Business, and LTCG respectively.
- - Run `python scripts/test_capital_gains_vs_business_income_classification.py`.
+ - Classify one trade bought 1 Jan 2024 and sold 1 Jan 2025 under `Jurisdiction.UNITED_STATES`: it must be `SHORT_TERM_CAPITAL_GAINS`, not long-term. Move the disposal to 2 Jan 2025 and confirm it flips to `LONG_TERM_CAPITAL_GAINS`.
+ - Classify the same intraday equity trade under all three jurisdictions and confirm three different answers: `SPECULATIVE_BUSINESS` (India), `SHORT_TERM_CAPITAL_GAINS` (US), `BUSINESS_INCOME` (Canada, absent a s.39(4) election).
+ - Classify a seven-year Canadian equity hold and confirm no `LONG_TERM_CAPITAL_GAINS` is ever produced.
+ - Run `python -m unittest discover -s skills/capital-gains-vs-business-income-classification/scripts` and confirm all tests pass.
## Related Skills
- - `canada-iiroc-electronic-trading-rules`
+ - `section-1256-contract-tax-treatment-us-futures`
+ - `mark-to-market-election-for-active-traders-us`
+ - `wash-sale-rule-tracking-us`
+ - `fifo-vs-specific-lot-tax-accounting-methods`
+ - `multi-jurisdiction-tax-residency-implications`
- `best-execution-record-keeping-global`