Skip to main content

On This Page

Deposit-Only Portfolio Rebalancing: Algorithm for Tax-Free Convergence

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Rebalancing a portfolio with only your next deposit (no selling)

Diego, solo developer of Balance, formalizes a rebalancing algorithm using only new deposits. The algorithm avoids selling by distributing a $1,000 contribution proportionally to category gaps, converging portfolios without taxable events.

Why This Matters

Standard portfolio rebalancing requires selling overweight assets, incurring capital gains taxes, brokerage fees, and emotional friction. In practice, this discourages regular rebalancing—investors either let allocations drift dangerously or pay unnecessary costs. Formalizing a deposit-driven algorithm that distributes new funds to underweight categories eliminates those costs entirely, making disciplined rebalancing accessible to anyone making recurring contributions.

Key Insights

  • Gap-based distribution: Only positions below their post-deposit target compete for new money, using max(0, target - current) to isolate deficits (Balance, 2026).
  • Edge case handling: If total_gap == 0 (all categories at or above target), algorithm splits deposit by target percentages to avoid division by zero (Balance app).
  • Market-specific quantization: Stocks buy whole units via int(), crypto buys fractions to 8 decimal places via quantize(), enabling a single engine for stock and Bitcoin portfolios.
  • Leftover deployment: A greedy second pass buys additional shares or crypto fractions for the most-underweight category until the deposit is fully used (Balance, 2026).
  • Tax-aware sales: For Brazilian investors, avoid_ir_sells flag excludes always-taxed ETFs/REITs (suffix 11) from sale suggestions, selling only tax-exempt stocks under R$20k/month.

Working Examples

Core algorithm: calculates budget per category by distributing deposit proportionally to gaps (target minus current value), ensuring overweight categories get zero budget.

from collections import defaultdict
from decimal import Decimal

def calculate(self, deposit_amount: Decimal) -> dict:
    deposit = Decimal(deposit_amount).quantize(Decimal('0.01'))
    investments = self._category_investments()
    current_total = self.portfolio.total_value
    new_total = current_total + deposit

    cat_value = defaultdict(lambda: Decimal('0'))
    for cat_id, rows in investments.items():
        for kind, item in rows:
            cat_value[cat_id] += item.current_value

    gaps = {}
    for cat_id, rows in investments.items():
        category = rows[0][1].category
        target_value = new_total * category.target_percentage / Decimal('100')
        gaps[cat_id] = max(Decimal('0'), target_value - cat_value[cat_id])

    total_gap = sum(gaps.values())

    cat_budget = {
        cat_id: (deposit * gaps[cat_id] / total_gap).quantize(Decimal('0.01'))
        for cat_id in investments
    }
    ...

Converts budget to orders: whole shares for stocks, fractions down to 8 decimal places for crypto.

def _buy_suggestion(self, kind, item, budget: Decimal):
    if budget <= 0:
        return None
    if self.portfolio.market == 'CRYPTO':
        quantity = (budget / item.current_price).quantize(Decimal('0.00000001'))
    else:
        quantity = int(budget / item.current_price)
    if quantity <= 0:
        return None
    cost = (quantity * item.current_price).quantize(Decimal('0.01'))
    return self._asset_suggestion_row(item, quantity, cost)

Practical Applications

  • (Balance / recurring contributors): Use deposit-only rebalancing for monthly infusions to avoid brokerage fees and capital gains taxes; pitfall is ignoring rounding-locks that leave idle cash if not handled with greedy repurposing.
  • (Brazilian investors with Balance): Leverage avoid_ir_sells flag to rebalance by selling only tax-exempt assets (stocks under R$20k/month), keeping ETFs/REITs untouched; pitfall is triggering taxable events by selling always-taxed assets without flag.
  • (Event: monthly deposit day for any portfolio): Formalize the ‘spreadsheet and guess’ approach into an algorithm that calculates gaps automatically; pitfall is overweight categories drifting so far that deposits alone can’t correct, requiring optional sale enforcement.

References:

Continue reading

Next article

Stack Overflow Opens Its Largest-Ever Developer Survey Amid Doubling Agent Usage

Related Content