fintech-algorithms
Using a coding agent? Give it the skill: npx skills add IslamBaraka90/Fintech-Algorithms-Library What it does →

Tax-Aware Portfolio Optimization

Install and import#

bash
npm install fintech-algorithms
ts
import { optimizeTaxAwareTrade } from "fintech-algorithms/portfolio-construction/practical-constraints/tax-aware-portfolio-optimization";

Signature#

optimizeTaxAwareTrade(holdingsInit, benchmark, expectedReturn, riskMatrix, prices, lots, tradeDate, options)

Scores which lots a fixed-size sale draws on, and separately solves the exact trade balancing return, tracking risk, cost and a declared illustrative lot score.

Parameters#

NameTypeNotes
holdingsInitunknown
benchmarkunknown
expectedReturnunknown
riskMatrixunknown
pricesunknown
lotsunknown
tradeDateunknown
options{ gammaRisk?: unknown; gammaTax?: unknown; gammaTc?: unknown; costRates?: unknown; cashInit?: unknown; taxCash?: unknown; settlement?: SettlementMode; settlementDate?: unknown; policy?: unknown; }optional

Worked example#

executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.

Input#

holdingsInit
[500, 500]
benchmark
[600, 400]
expectedReturn
[0.04, 0]
riskMatrix
[
  [0.0001, 0],
  [0, 0.0001]
]
prices
[1, 1]
lots
[
  [
    {
      "lotId": "A",
      "shares": 500,
      "saleScoreRate": 0.05,
      "acquiredOn": "2025-01-02"
    }
  ],
  [
    {
      "lotId": "B",
      "shares": 500,
      "saleScoreRate": 0.01,
      "acquiredOn": "2025-01-02"
    }
  ]
]
tradeDate
"2026-01-02"
options
{
  "gammaRisk": 1,
  "gammaTax": 1,
  "gammaTc": 0
}

Call#

optimizeTaxAwareTrade(holdingsInit, benchmark, expectedReturn, riskMatrix, prices, lots, tradeDate, options)

Returns#

object with 16 fields: status, tradeDate, trade, tradeTotal, holdings, direction, utility, terms, …

{
  "status": "optimal",
  "tradeDate": "2026-01-02",
  "trade": [175, -175],
  "tradeTotal": 0,
  "holdings": [675, 325],
  "direction": "buy-first-sell-second",
  "utility": 4.125,
  "terms": {
    "expectedReturn": 7,
    "riskPenalty": 1.125,
    "executionCostPenalty": 0,
    "taxScorePenalty": 1.75
  },
  "executionCost": 0,
  "taxScore": 1.75,
  "saleCapacities": [500, 500],
  "lotSales": {
    "asset": 1,
    "price": 1,
    "saleDollars": 175,
    "totalCapacity": 500,
    "fillSequence": ["B"],
    "totalScore": 1.75,
    "lots": [
      {
        "lotId": "B",
        "acquiredOn": "2025-01-02",
        "sharesAvailable": 500,
        "basisPerShare": null,
        "illustrativeRate": null,
        "perDollarScore": 0.01,
        "capacity": 500,
        "saleDollars": 175,
        "sharesSold": 175,
        "remainingCapacity": 325,
        "lotScore": 1.75
      }
    ]
  },
  "branches": [
    {
      "branch": "buy-first-sell-second",
      "interval": [0, 500],
      "quadraticCoefficient": -0.0002,
      "linearCoefficient": 0.07,
      "constant": -2,
      "stationaryX": 175,
      "stationaryInInterval": true,
      "x": 175,
      "binding": "stationary",
      "utility": 4.125000000000001
    },
    {
      "branch": "sell-first-buy-second",
      "interval": [-500, 0],
      "quadraticCoefficient": -0.0002,
      "linearCoefficient": 0.13,
      "constant": -2,
      "stationaryX": 325,
      "stationaryInInterval": false,
      "x": 0,
      "binding": "upper-bound",
      "utility": -2
    }
  ],
  "cash": {
    "settlement": "objective-only-forecast",
    "settlementDate": null,
    "cashInit": 0,
    "tradeTotal": 0,
    "executionCost": 0,
    "taxCash": 0,
    "cashPost": 0,
    "holdingsTotalPost": 1000,
    "portfolioValuePost": 1000,
    "taxChargedTo": "objective-score-only",
    "note": "taxCash is subtracted once, inside cashPost; portfolioValuePost adds that net balance and never subtracts the same amoun…"
  }
}

Showing 14 of 16 fields.

Other exports#

This module also exports reviewPolicyState, applySplitToLot, scoreFixedSale, settleTradeCash, canonicalExample. Every module additionally exports run as an alias of its primary function, and a meta object carrying its catalog id, domain, family, shape and article URL.

Diagrams#

Tax-Aware Portfolio Optimization — article hero

How it works#

This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.

Read the article →

References#

  • Tax-Aware Portfolio Construction via Convex Optimization
  • Investment Income and Expenses
  • Shares and Capital Gains Tax
  • Capital losses

The rest of the Practical Constraints family#