Claude
Skills
Sign in
Back

tax-loss-harvesting

Included with Lifetime
$97 forever

Tax-loss harvesting opportunity identification, scoring, and planning with wash sale compliance and annual carryforward tracking

Data & Analyticsscripts

What this skill does


# Tax-Loss Harvesting

Identify, score, and plan tax-loss harvesting (TLH) opportunities across a crypto portfolio. This skill covers unrealized-loss ranking, net-benefit calculation, wash sale compliance, annual loss carryforward tracking, and year-end "use it or lose it" strategies.

> **Disclaimer:** This skill provides informational analysis only. It is NOT tax advice. Tax rules vary by jurisdiction and change frequently. Consult a qualified tax professional before making any tax-related trading decisions.

## How Tax-Loss Harvesting Works

Tax-loss harvesting is the practice of intentionally realizing investment losses to offset realized capital gains, thereby reducing your current-year tax liability.

### Core Mechanism

1. **Identify** positions with unrealized losses in your portfolio.
2. **Sell** those positions to realize the loss.
3. **Offset** realized gains with the harvested loss, reducing taxable income.
4. **Optionally re-enter** a similar (but not "substantially identical") position to maintain market exposure.

### Short-Term vs Long-Term

| Holding Period | Classification | Typical Tax Rate |
|---------------|---------------|-----------------|
| < 1 year | Short-term capital gain/loss | Ordinary income rate |
| >= 1 year | Long-term capital gain/loss | Preferential rate (0-20%) |

Short-term losses first offset short-term gains; long-term losses first offset long-term gains. Remaining net losses cross over to offset the other category.

### Annual Loss Deduction Limit

If total net losses exceed total gains, the excess is deductible against ordinary income up to **$3,000 per year** ($1,500 if married filing separately). Any remaining loss carries forward indefinitely to future tax years.

## Ranking Unrealized Losses

Not all unrealized losses are equally valuable to harvest. This skill scores each opportunity on four dimensions:

### 1. Loss Magnitude

Larger dollar losses provide more tax savings. The raw loss is the difference between current market value and cost basis.

```
unrealized_loss = current_value - cost_basis  # negative when loss
tax_savings = abs(unrealized_loss) * marginal_tax_rate
```

### 2. Days Until Long-Term Threshold

A position approaching the 1-year holding mark deserves special consideration:
- If close to crossing into long-term territory, harvesting now locks in a **short-term loss** (offsets higher-taxed short-term gains).
- If already long-term, the loss offsets long-term gains (lower tax rate benefit).

```
days_held = (today - acquisition_date).days
days_to_long_term = max(0, 365 - days_held)
```

Positions with fewer days remaining until long-term are **more urgent** to evaluate because once they cross 365 days, a short-term loss becomes a less-valuable long-term loss.

### 3. Wash Sale Risk (Correlation Score)

The IRS wash sale rule prohibits claiming a loss if you buy a "substantially identical" security within 30 days before or after the sale. In crypto, the exact application is evolving, but prudent planning avoids re-entering the same token within the 61-day wash sale window (30 days before + sale day + 30 days after).

**Correlation scoring**: If you hold (or plan to re-enter) a position that is highly correlated with the harvested asset, wash sale risk increases. Score this as:

```
wash_sale_risk = 1.0  # if same token re-entry planned within 30 days
wash_sale_risk = correlation_coefficient  # if correlated substitute held
wash_sale_risk = 0.0  # if no re-entry or uncorrelated substitute
```

Higher wash sale risk reduces the effective score of the opportunity.

### 4. Available Gains to Offset

A harvested loss is only immediately useful if there are realized gains to offset. Score opportunities higher when:
- There are matching-type gains (short-term loss vs short-term gain).
- The loss amount does not greatly exceed available gains (diminishing marginal benefit beyond the $3K deduction cap).

```
offset_efficiency = min(1.0, available_matching_gains / abs(unrealized_loss))
```

### Composite Score

```python
def tlh_score(
    unrealized_loss: float,
    days_to_long_term: int,
    wash_sale_risk: float,
    offset_efficiency: float,
    weights: dict | None = None,
) -> float:
    w = weights or {
        "magnitude": 0.35,
        "urgency": 0.25,
        "wash_safety": 0.20,
        "offset_match": 0.20,
    }
    magnitude_score = min(abs(unrealized_loss) / 10_000, 1.0)
    urgency_score = max(0, 1.0 - days_to_long_term / 365)
    wash_safety_score = 1.0 - wash_sale_risk
    return (
        w["magnitude"] * magnitude_score
        + w["urgency"] * urgency_score
        + w["wash_safety"] * wash_safety_score
        + w["offset_match"] * offset_efficiency
    )
```

## Net Benefit Calculation

Harvesting a loss is not free. Transaction costs (swap fees, slippage, gas) reduce the benefit.

```python
def net_benefit(
    unrealized_loss: float,
    marginal_tax_rate: float,
    transaction_cost: float,
    re_entry_cost: float = 0.0,
) -> float:
    """Compute net dollar benefit of harvesting a loss.

    Args:
        unrealized_loss: Negative number representing the loss.
        marginal_tax_rate: Applicable tax rate (0.0 to 1.0).
        transaction_cost: Cost to execute the sell (fees + slippage).
        re_entry_cost: Cost to re-enter a substitute position.

    Returns:
        Net benefit in dollars. Positive means harvesting is worthwhile.
    """
    tax_savings = abs(unrealized_loss) * marginal_tax_rate
    total_costs = transaction_cost + re_entry_cost
    return tax_savings - total_costs
```

**Rule of thumb**: Only harvest when `net_benefit > 0` by a meaningful margin. Very small losses are not worth the transaction costs and operational complexity.

## Year-End "Use It or Lose It"

Near December 31, evaluate whether to accelerate harvesting:

1. **Tally year-to-date realized gains** (both short-term and long-term).
2. **Identify unrealized losses** that can offset those gains.
3. **Prioritize** losses that offset same-type gains (short-term loss vs short-term gain yields the highest tax rate differential).
4. **Check the $3K excess limit**: If net losses already exceed gains by $3K, additional harvesting this year has no immediate tax benefit (though the carryforward still has value).
5. **Consider settlement timing**: Ensure trades settle before year-end.

## Wash Sale Compliance

### The 61-Day Window

The wash sale rule applies to purchases of substantially identical securities within:
- **30 days before** the sale (retroactive wash sale)
- **The day of** the sale
- **30 days after** the sale

If triggered, the disallowed loss is added to the cost basis of the replacement shares, deferring (not eliminating) the tax benefit.

### Compliance Strategies

| Strategy | Description | Trade-off |
|----------|------------|-----------|
| **Wait 31 days** | Sell, wait 31 days, re-buy | Market exposure gap |
| **Substitute asset** | Sell, immediately buy a non-identical but correlated asset | Tracking error |
| **No re-entry** | Sell and stay out | Lost upside |
| **Double-up** | Buy additional shares, wait 31 days, sell original lot | Capital intensive |

### Crypto-Specific Considerations

- The IRS has not explicitly ruled that the wash sale rule applies to cryptocurrency (as of 2025). However, proposed legislation may extend it.
- Prudent practitioners treat crypto as subject to wash sale rules for conservative planning.
- Different tokens (e.g., SOL vs ETH) are generally considered non-identical.
- Wrapped versions of the same token (e.g., SOL vs wSOL) may be considered substantially identical.

## Annual Loss Carryforward Tracking

```python
def compute_carryforward(
    realized_gains_st: float,
    realized_gains_lt: float,
    realized_losses_st: float,
    realized_losses_lt: float,
    prior_carryforward: float = 0.0,
    annual_deduction_limit: float = 3_000.0,
) -> dict:
    """Compute net tax position and carryforward.

    Returns dict with keys:
        net_

Related in Data & Analytics