Tax loss harvesting is one of the highest-return strategies available to crypto traders with unrealized losses in their portfolios. The concept is straightforward: sell a position at a loss to realize that loss on paper, use the realized loss to offset capital gains, then repurchase exposure to the same asset after the sale. The tax saving from the deducted loss is a direct improvement in after-tax returns that requires no price prediction—only careful timing and portfolio awareness.
AI agents are uniquely positioned to execute tax loss harvesting more effectively than human traders. Agents can monitor mark-to-market positions continuously, calculate the tax impact of every potential harvest in real time, and execute multi-leg strategies (sell-swap-repurchase) without delay or emotion. This guide covers the mechanics, current wash sale rules for crypto in 2026, optimization frameworks, and a complete Python tax harvesting agent using the Purple Flea Wallet API and Purple Flea Trading API.
Legal disclaimer: This guide is for educational purposes. Tax rules are jurisdiction-specific and change frequently. Always consult a qualified tax professional before implementing any tax strategy. Nothing in this article constitutes tax advice.
Tax Loss Harvesting Mechanics
The fundamental mechanism: when an asset is sold at a price below its cost basis (the price paid), the difference is a capital loss. Capital losses can be used to offset capital gains in the same tax year, reducing taxable income.
Example
Agent purchased 1 ETH at $4,000 (cost basis = $4,000).
Current ETH price: $3,200. Unrealized loss = -$800.
Agent also realized a $2,000 gain from a BTC trade earlier in the year.
Action: Sell the 1 ETH at $3,200. Realized loss = -$800.
Tax impact: $2,000 gain offset by $800 loss = $1,200 net gain taxed.
At 30% tax rate: saves $240 in taxes compared to not harvesting.
Agent immediately repurchases ETH exposure (via a correlated asset or after waiting) to maintain market position.
The key insight is that harvesting does not permanently eliminate the taxable gain—it defers it. When the agent later sells the repurchased ETH, the gain is computed from the new (lower) cost basis. But the time value of deferral is valuable, and in some cases (if the position is held long enough to qualify for long-term rates) the rate on the future gain may be lower.
Wash Sale Rules for Crypto
The wash sale rule, as it exists in US tax law for securities, prohibits claiming a capital loss if you repurchase a "substantially identical" security within 30 days before or after the sale. This 61-day window (30 days before, day of sale, 30 days after) is the "wash sale window."
Crypto Wash Sale Status in 2026
As of early 2026, the IRS has not formally extended wash sale rules to cryptocurrencies. The IRS classifies cryptocurrency as property, not a security, and the wash sale rule (IRC Section 1091) applies only to stocks and securities. This means crypto traders can:
- Sell ETH at a loss
- Immediately repurchase ETH
- Claim the full capital loss on the sale
This "buy-immediately-after-selling" strategy, which would disqualify a stock loss, is currently legal for crypto in the US.
Legislative risk: Multiple bills have been introduced in Congress since 2021 to extend wash sale rules to crypto. As of this writing none have passed, but the risk is real. Agents implementing aggressive tax loss harvesting strategies should monitor legislative developments and build configurable wash sale windows (e.g., 0, 30, or 60 days) that can be updated without code changes if rules change.
International Wash Sale Considerations
Non-US jurisdictions have varying rules:
| Jurisdiction | Wash Sale Rule for Crypto | Notes |
|---|---|---|
| United States | None (as of 2026) | Proposal risk exists; rule applies to securities, not property |
| United Kingdom | Yes ("Bed and Breakfasting") | 30-day window; same-day matching rules also apply |
| Germany | N/A (different system) | Crypto held >1 year is tax-free; no wash sale concept |
| Australia | None (similar to US) | CGT asset; no formal wash sale rule for crypto |
| Canada | Superficial loss rule | 30-day window, applies to "identical property"—application to crypto debated |
AI agents operating across multiple jurisdictions must implement jurisdiction-specific rules. The Python implementation below supports configurable wash sale window parameters.
Harvesting Frequency Optimization
How often should an agent harvest losses? The answer depends on several factors:
Transaction Costs vs. Tax Benefit
Every harvest involves trading costs: swap fees, gas costs, and potential slippage. A harvest is only worth executing if:
tax_benefit > transaction_cost + time_out_of_market_risk
Where tax_benefit = loss_amount * marginal_tax_rate and time_out_of_market_risk is the expected gain you might miss if the asset rebounds during any required waiting period.
For small unrealized losses (<1% of position), transaction costs often exceed tax benefit. The minimum loss threshold for harvesting is roughly:
def minimum_harvest_threshold(
position_value_usd: float,
marginal_tax_rate: float,
transaction_cost_usd: float,
wash_sale_wait_days: int = 0,
daily_volatility: float = 0.03,
) -> float:
"""
Compute minimum loss (in USD) worth harvesting.
Parameters:
- position_value_usd: current market value of the position
- marginal_tax_rate: e.g., 0.30 for 30%
- transaction_cost_usd: gas + swap fees for sell + repurchase
- wash_sale_wait_days: 0 for crypto (no current rule), 30+ for conservative
- daily_volatility: annualized 1-day return std dev, e.g., 0.03 = 3% daily
"""
import math
# Tax benefit needed to cover transaction costs
min_loss_for_costs = transaction_cost_usd / max(marginal_tax_rate, 0.01)
# Additional buffer for opportunity cost during waiting period
# Expected move = vol * sqrt(days) * 1 std dev
opportunity_cost_pct = daily_volatility * math.sqrt(wash_sale_wait_days) if wash_sale_wait_days > 0 else 0.0
opportunity_cost_usd = position_value_usd * opportunity_cost_pct
return min_loss_for_costs + opportunity_cost_usd
Year-End vs. Continuous Harvesting
Two common approaches:
- Continuous harvesting: Monitor positions daily and harvest whenever unrealized loss exceeds threshold. Maximizes total losses captured but requires active position management.
- Year-end harvesting: In Q4, systematically review all positions with unrealized losses and harvest before December 31. Simpler but may miss opportunities throughout the year and causes a rush in November-December.
AI agents are well-suited to continuous harvesting because they can monitor positions without human attention overhead. The Purple Flea Trading API exposes position mark-to-market data that makes continuous monitoring straightforward.
Cost Basis Accounting Methods
The cost basis method determines which lots are used when calculating the gain or loss on a sale. For tax optimization, specific identification (SpecID) is almost always the best choice:
| Method | How It Works | Tax Impact |
|---|---|---|
| FIFO (First In, First Out) | Oldest lots sold first | Often produces large gains if early lots have low basis |
| LIFO (Last In, First Out) | Newest lots sold first | Can maximize short-term losses; not IRS-preferred |
| HIFO (Highest In, First Out) | Lots with highest cost basis sold first | Minimizes gains (or maximizes losses) on each sale |
| Specific Identification (SpecID) | Choose exactly which lot to sell | Most flexible—optimal for active tax management |
| Average Cost Basis | Average price across all lots | Simple; may not be optimal for harvesting |
For a tax loss harvesting agent, HIFO is the default: always sell the lot with the highest cost basis first (producing the largest loss or smallest gain). SpecID with active lot selection can outperform HIFO in edge cases where short-term vs. long-term rate differences matter.
Python Tax Harvesting Agent
The following agent continuously monitors a portfolio via the Purple Flea Wallet and Trading APIs, identifies harvest opportunities, and executes them when the tax benefit exceeds costs.
"""
Crypto Tax Loss Harvesting Agent
Uses Purple Flea Wallet + Trading APIs to monitor positions
and execute harvests when tax benefit > transaction cost.
"""
import asyncio
import aiohttp
import json
import logging
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from typing import List, Dict, Optional
import math
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
PF_API = "https://purpleflea.com/api"
PF_API_KEY = "YOUR_API_KEY"
PF_AGENT_ID = "YOUR_AGENT_ID"
# Tax parameters - configure per jurisdiction
TAX_CONFIG = {
"short_term_rate": 0.37, # short-term capital gains rate
"long_term_rate": 0.20, # long-term capital gains rate (>1 year)
"wash_sale_days": 0, # 0 = crypto exemption (US 2026); set 30 for conservative
"jurisdiction": "US",
}
# Minimum tax benefit (USD) to trigger harvest
MIN_HARVEST_BENEFIT_USD = 25.0
# Daily price volatility estimate per asset
ASSET_VOLATILITY = {
"ETH": 0.035,
"BTC": 0.028,
"SOL": 0.055,
"BNB": 0.040,
}
@dataclass
class TaxLot:
asset: str
quantity: float
cost_basis_usd: float # price paid per unit
purchase_date: datetime
lot_id: str
@dataclass
class Position:
asset: str
lots: List[TaxLot]
current_price_usd: float
@property
def total_quantity(self) -> float:
return sum(lot.quantity for lot in self.lots)
@property
def total_cost_basis(self) -> float:
return sum(lot.quantity * lot.cost_basis_usd for lot in self.lots)
@property
def current_value(self) -> float:
return self.total_quantity * self.current_price_usd
@property
def total_unrealized_pnl(self) -> float:
return self.current_value - self.total_cost_basis
def get_harvestable_lots(self) -> List[TaxLot]:
"""Return lots with unrealized losses, sorted by loss (largest first)."""
result = []
for lot in self.lots:
lot_value = lot.quantity * self.current_price_usd
lot_basis = lot.quantity * lot.cost_basis_usd
if lot_value < lot_basis:
result.append(lot)
# Sort by largest loss first (HIFO approach)
result.sort(key=lambda l: l.cost_basis_usd - self.current_price_usd, reverse=True)
return result
@dataclass
class HarvestOpportunity:
position: Position
lot: TaxLot
unrealized_loss_usd: float
holding_days: int
is_long_term: bool # held > 1 year
applicable_rate: float
gross_tax_benefit: float
estimated_tx_cost: float
net_benefit: float
wash_sale_replacement: Optional[str] = None # correlated asset to use if waiting
async def fetch_positions(session: aiohttp.ClientSession) -> List[Position]:
"""Fetch current positions and prices from Purple Flea API."""
headers = {"Authorization": f"Bearer {PF_API_KEY}"}
try:
async with session.get(
f"{PF_API}/wallet/positions?agent_id={PF_AGENT_ID}",
headers=headers
) as resp:
data = await resp.json()
positions = []
for asset_data in data.get("positions", []):
lots = []
for lot_data in asset_data.get("lots", []):
lots.append(TaxLot(
asset=asset_data["asset"],
quantity=float(lot_data["quantity"]),
cost_basis_usd=float(lot_data["cost_basis_usd"]),
purchase_date=datetime.fromisoformat(lot_data["purchase_date"]),
lot_id=lot_data["lot_id"],
))
positions.append(Position(
asset=asset_data["asset"],
lots=lots,
current_price_usd=float(asset_data["current_price_usd"]),
))
return positions
except Exception as e:
logger.error(f"Failed to fetch positions: {e}")
return []
async def estimate_tx_cost(
session: aiohttp.ClientSession,
asset: str,
quantity: float
) -> float:
"""Estimate total transaction cost for sell + repurchase in USD."""
headers = {"Authorization": f"Bearer {PF_API_KEY}"}
try:
async with session.get(
f"{PF_API}/trading/fee-estimate?asset={asset}&quantity={quantity}",
headers=headers
) as resp:
data = await resp.json()
return float(data.get("estimated_total_usd", 5.0)) # default $5 if API fails
except Exception:
return 5.0 # conservative default
def compute_harvest_opportunity(
position: Position,
lot: TaxLot,
tx_cost: float,
tax_config: dict,
) -> Optional[HarvestOpportunity]:
"""Compute tax benefit for harvesting a specific lot."""
current_value = lot.quantity * position.current_price_usd
lot_basis = lot.quantity * lot.cost_basis_usd
unrealized_loss = current_value - lot_basis # negative = loss
if unrealized_loss >= 0:
return None # Not a loss
holding_days = (datetime.utcnow() - lot.purchase_date).days
is_long_term = holding_days > 365
# Use appropriate tax rate (loss offsets gains at the same rate)
rate = tax_config["long_term_rate"] if is_long_term else tax_config["short_term_rate"]
gross_benefit = abs(unrealized_loss) * rate
net_benefit = gross_benefit - tx_cost
if net_benefit < MIN_HARVEST_BENEFIT_USD:
return None
# Suggest wash sale replacement asset if waiting is needed
wash_sale_days = tax_config["wash_sale_days"]
replacement = None
if wash_sale_days > 0:
# Use correlated asset during waiting period to maintain exposure
CORRELATED = {
"BTC": "ETH", # high correlation; not "substantially identical"
"ETH": "BTC",
"SOL": "AVAX",
"BNB": "MATIC",
}
replacement = CORRELATED.get(position.asset)
return HarvestOpportunity(
position=position,
lot=lot,
unrealized_loss_usd=unrealized_loss,
holding_days=holding_days,
is_long_term=is_long_term,
applicable_rate=rate,
gross_tax_benefit=gross_benefit,
estimated_tx_cost=tx_cost,
net_benefit=net_benefit,
wash_sale_replacement=replacement,
)
async def execute_harvest(
session: aiohttp.ClientSession,
opportunity: HarvestOpportunity,
dry_run: bool = True,
) -> bool:
"""Execute a tax loss harvest by selling the lot and optionally repurchasing."""
lot = opportunity.lot
pos = opportunity.position
headers = {
"Authorization": f"Bearer {PF_API_KEY}",
"Content-Type": "application/json",
}
logger.info(
f"{'[DRY RUN] ' if dry_run else ''}Harvesting {lot.quantity:.6f} {pos.asset} "
f"(lot {lot.lot_id}, loss=${abs(opportunity.unrealized_loss_usd):.2f}, "
f"net benefit=${opportunity.net_benefit:.2f})"
)
if dry_run:
return True
# Step 1: Sell the loss lot
sell_payload = {
"agent_id": PF_AGENT_ID,
"action": "sell",
"asset": pos.asset,
"quantity": lot.quantity,
"lot_id": lot.lot_id, # specific lot identification
"reason": "tax_loss_harvest",
}
async with session.post(
f"{PF_API}/trading/execute",
json=sell_payload,
headers=headers,
) as resp:
sell_result = await resp.json()
if not sell_result.get("success"):
logger.error(f"Sell failed: {sell_result}")
return False
logger.info(f"Sold lot {lot.lot_id} at ${pos.current_price_usd:.2f}")
# Step 2: Handle wash sale window
wash_days = TAX_CONFIG["wash_sale_days"]
if wash_days > 0 and opportunity.wash_sale_replacement:
# Buy correlated asset during waiting period
repurchase_usd = lot.quantity * pos.current_price_usd
logger.info(
f"Buying ${repurchase_usd:.2f} of {opportunity.wash_sale_replacement} "
f"for {wash_days}-day wait period"
)
buy_replacement_payload = {
"agent_id": PF_AGENT_ID,
"action": "buy",
"asset": opportunity.wash_sale_replacement,
"amount_usd": repurchase_usd,
"reason": "wash_sale_replacement",
}
async with session.post(
f"{PF_API}/trading/execute",
json=buy_replacement_payload,
headers=headers,
) as resp:
await resp.json()
# Schedule repurchase after wash sale window
# In production, use a scheduler or persistent task queue
logger.info(f"Scheduled repurchase of {pos.asset} after {wash_days} days")
else:
# No wash sale rule — immediately repurchase
repurchase_usd = lot.quantity * pos.current_price_usd
buy_payload = {
"agent_id": PF_AGENT_ID,
"action": "buy",
"asset": pos.asset,
"amount_usd": repurchase_usd,
"reason": "harvest_repurchase",
}
async with session.post(
f"{PF_API}/trading/execute",
json=buy_payload,
headers=headers,
) as resp:
buy_result = await resp.json()
if buy_result.get("success"):
logger.info(f"Repurchased {pos.asset} immediately (no wash sale rule)")
return True
async def harvest_cycle(dry_run: bool = True):
"""Run one full harvest scan cycle."""
async with aiohttp.ClientSession() as session:
positions = await fetch_positions(session)
if not positions:
logger.info("No positions found.")
return
opportunities = []
for pos in positions:
harvestable_lots = pos.get_harvestable_lots()
for lot in harvestable_lots:
tx_cost = await estimate_tx_cost(session, pos.asset, lot.quantity)
opp = compute_harvest_opportunity(pos, lot, tx_cost, TAX_CONFIG)
if opp is not None:
opportunities.append(opp)
# Sort by net benefit, highest first
opportunities.sort(key=lambda o: o.net_benefit, reverse=True)
if not opportunities:
logger.info("No harvest opportunities meet the threshold.")
return
total_potential_benefit = sum(o.net_benefit for o in opportunities)
logger.info(
f"Found {len(opportunities)} harvest opportunities, "
f"total net benefit: ${total_potential_benefit:.2f}"
)
for opp in opportunities:
await execute_harvest(session, opp, dry_run=dry_run)
async def run_continuous(interval_hours: float = 6.0, dry_run: bool = True):
"""Run harvest cycles continuously."""
while True:
logger.info(f"--- Harvest cycle starting {'(DRY RUN) ' if dry_run else ''}---")
await harvest_cycle(dry_run=dry_run)
logger.info(f"Cycle complete. Sleeping {interval_hours}h.")
await asyncio.sleep(interval_hours * 3600)
if __name__ == "__main__":
# Run in dry-run mode first to verify positions and opportunities
asyncio.run(run_continuous(interval_hours=6.0, dry_run=True))
Tax Loss Harvesting with Perpetual Futures
For agents using Purple Flea's perpetual futures trading (275 markets via Hyperliquid integration), tax treatment of perp positions differs from spot holdings in most jurisdictions. In the US, futures contracts are typically treated under IRC Section 1256—60% long-term / 40% short-term regardless of holding period, with mark-to-market treatment at year end.
Key implications for harvesting agents:
- Section 1256 contracts are marked-to-market at December 31—all unrealized gains and losses are recognized at year end regardless of whether positions are closed
- This means perp traders automatically realize both gains and losses annually, eliminating the need to actively sell for tax purposes
- However, agents can still optimize by timing the closing of Section 1256 positions against spot portfolio losses/gains
- Non-US jurisdictions generally do not have the Section 1256 rule—perps are taxed only on close
Perps and the 1256 exemption: Whether exchange-traded crypto perpetuals qualify as Section 1256 contracts is an open IRS question in 2026. Many tax practitioners treat them as property (like spot crypto) rather than Section 1256. Until IRS guidance is clear, agents should consult a tax professional on this classification.
Wash Sale Avoidance Strategies
Even where wash sale rules do not currently apply to crypto, building avoidance strategies now is prudent defensive engineering. If rules change mid-year, an agent without wash sale logic will inadvertently disqualify harvested losses.
Correlated Asset Replacements
The wash sale rule applies to "substantially identical" assets. Using a different but correlated asset during the waiting period maintains market exposure without triggering wash sale disqualification:
- Sell ETH, buy BTC or WBTC during wait period (high correlation, not identical)
- Sell SOL, buy AVAX (layer-1 competitors, correlated but not identical)
- Sell a layer-2 token, buy a different layer-2 token
- Sell a DeFi governance token, hold ETH as a proxy
Different Entity Harvesting
The wash sale rule in traditional finance applies when the same taxpayer repurchases. Some agent architectures use separate legal entities (different agent wallet IDs) for different strategies. Whether purchases by a related entity trigger wash sale disqualification depends on the facts and entity relationships—consult a tax professional before relying on this approach.
Using Options or Synthetic Exposure
Rather than repurchasing the spot asset, an agent can maintain economic exposure via a call option or a synthetic long position (long call + short put). Options are not "substantially identical" to the underlying in most interpretations, making this a clean wash sale avoidance technique where the rule applies.
Record-Keeping for AI Agents
Agents executing frequent trades across multiple chains generate complex tax records. Automated record-keeping is essential:
import json
from datetime import datetime
from pathlib import Path
TAX_LOG_FILE = Path("/var/log/agent-tax/harvest-log.jsonl")
def log_harvest_event(
lot_id: str,
asset: str,
quantity: float,
cost_basis_usd: float,
sale_price_usd: float,
sale_date: datetime,
realized_loss_usd: float,
holding_days: int,
tx_hash: Optional[str],
repurchase_date: Optional[datetime],
repurchase_price_usd: Optional[float],
):
"""Log a harvest event to persistent JSONL file for tax reporting."""
TAX_LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
event = {
"timestamp": datetime.utcnow().isoformat(),
"event_type": "tax_loss_harvest",
"lot_id": lot_id,
"asset": asset,
"quantity": quantity,
"cost_basis_usd": cost_basis_usd,
"sale_price_usd": sale_price_usd,
"sale_date": sale_date.isoformat(),
"realized_loss_usd": realized_loss_usd,
"holding_days": holding_days,
"is_long_term": holding_days > 365,
"tx_hash": tx_hash,
"repurchase_date": repurchase_date.isoformat() if repurchase_date else None,
"repurchase_price_usd": repurchase_price_usd,
"new_cost_basis_usd": repurchase_price_usd, # new basis after harvest + repurchase
}
with open(TAX_LOG_FILE, "a") as f:
f.write(json.dumps(event) + "\n")
def generate_tax_summary(tax_year: int) -> dict:
"""Generate a summary of harvested losses for a tax year."""
if not TAX_LOG_FILE.exists():
return {}
total_short_term = 0.0
total_long_term = 0.0
events = []
with open(TAX_LOG_FILE) as f:
for line in f:
event = json.loads(line)
sale_date = datetime.fromisoformat(event["sale_date"])
if sale_date.year != tax_year:
continue
loss = abs(event["realized_loss_usd"])
if event["is_long_term"]:
total_long_term += loss
else:
total_short_term += loss
events.append(event)
return {
"tax_year": tax_year,
"total_short_term_losses": total_short_term,
"total_long_term_losses": total_long_term,
"total_losses": total_short_term + total_long_term,
"harvest_count": len(events),
}
Tax-Efficient Trading with Purple Flea
Access 275 perpetual markets, multi-chain wallets, and the full Purple Flea API suite to implement tax-optimized agent trading strategies.
Register Your AgentSummary
Tax loss harvesting is one of the clearest examples of where AI agent automation produces direct, measurable financial benefit. Key takeaways:
- Crypto is currently not subject to the US wash sale rule—agents can sell and immediately repurchase, capturing the loss while maintaining exposure
- This favorable treatment has legislative risk; build configurable wash sale windows into any implementation
- Use HIFO or SpecID lot selection to maximize the loss realized from each harvest sale
- Only harvest when net benefit (tax saving minus transaction costs) exceeds a meaningful threshold—small losses are not worth the trading overhead
- Continuous monitoring (every 6-12 hours) outperforms year-end-only harvesting by capturing losses throughout the year
- Purple Flea's Trading and Wallet APIs provide the position data and execution endpoints needed for a fully automated harvesting agent
- Keep meticulous JSONL logs of every harvest event; crypto tax reporting requires lot-level trade records
The Python implementation above is a functional starting point. For production, extend with integration to a tax software API (Koinly, TaxBit) for automated form generation, add per-exchange cost basis import, and implement jurisdiction-aware rule switching for agents operating across multiple legal entities.
Combining Spot Harvesting with Perpetual Positions
AI agents using Purple Flea's Trading API across 275 perpetual markets have a powerful additional tool: short perpetual positions as temporary hedges during harvest waiting periods. When an agent sells spot ETH to harvest a loss and wants to maintain market exposure during a wash sale window, opening a long ETH-PERP position creates a synthetic long without touching the spot asset.
This approach:
- Maintains full market delta (1:1 with spot ETH price movement)
- Avoids any wash sale concern since the perp is a derivative, not the underlying asset
- Incurs a funding rate cost (can be positive or negative depending on market conditions)
- Requires sufficient margin in the trading account
async def hedge_with_perp(
session: aiohttp.ClientSession,
asset: str,
quantity: float,
pf_api_key: str,
agent_id: str,
):
"""
Open a long perp position to hedge spot sale during wash sale window.
Uses Purple Flea Trading API (Hyperliquid integration).
"""
payload = {
"agent_id": agent_id,
"market": f"{asset}-PERP",
"side": "long",
"size": quantity,
"order_type": "market",
"reduce_only": False,
}
headers = {
"Authorization": f"Bearer {pf_api_key}",
"Content-Type": "application/json",
}
async with session.post(
"https://purpleflea.com/api/trading/open",
json=payload,
headers=headers,
) as resp:
data = await resp.json()
if data.get("success"):
print(f"Opened long {quantity} {asset}-PERP at ${data['fill_price']:.2f}")
else:
print(f"Failed to open hedge: {data.get('error')}")
return data
The funding cost of holding a perpetual hedge for 30 days is typically less than 0.5% in normal market conditions—far less than the tax benefit from harvesting a 5%+ unrealized loss. During periods of extreme positive funding (when longs pay shorts heavily), agents should weigh the funding cost against the tax benefit before using a perp hedge.
Year-Round Tax Calendar for Agent Operators
Beyond continuous harvesting, there are calendar-driven optimization windows:
| Month | Action | Rationale |
|---|---|---|
| January | Review prior year harvest log, confirm loss carry-forwards | Set baseline for new tax year |
| March-April | File prior year return or extension; confirm estimated payments | Avoid underpayment penalties |
| June | Mid-year portfolio review; harvest losses that have accumulated | Don't wait until year-end rush |
| September | Q3 review; check if short-term positions can become long-term before year-end | Rate planning (STCG vs. LTCG) |
| October-November | Aggressive harvest scan; identify all positions with >$500 unrealized loss | Leave time for wash sale windows if needed |
| December 31 | Final deadline for all harvests to count in current tax year | Settlement must occur on or before Dec 31 |
AI agents running continuously should treat the October-November period as a "harvest intensification" window—lowering the minimum harvest threshold (e.g., from $25 to $10 net benefit) to capture every available loss before the year closes.