npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cjroth/rebalance

v0.2.3

Published

> **Disclaimer:** This tool is for educational and informational purposes only and is not intended as financial or investment advice. I am not a financial advisor. This software is provided "as-is" with no warranties of accuracy or completeness. It may co

Downloads

211

Readme

Rebalance

Disclaimer: This tool is for educational and informational purposes only and is not intended as financial or investment advice. I am not a financial advisor. This software is provided "as-is" with no warranties of accuracy or completeness. It may contain bugs or calculation errors. Do not rely on it for actual investment decisions. Consult a qualified financial professional before making any trades. I accept no liability for any losses or damages arising from use of this tool.

A portfolio rebalancing tool that runs in both the terminal and the browser from a single codebase, powered by ink-web. Read the blog post.

screenshot

What it does

Import your Schwab brokerage holdings (CSV paste or drag-and-drop), set target allocation percentages, and generate the exact trades needed to rebalance — all without sending your data to a server.

The wizard walks you through four steps:

  1. Import — Paste a CSV, drag-and-drop a file, or pick a demo portfolio
  2. Review — Browse your holdings across multiple dimensions (symbol, account, country, asset class, tax status, provider, owner)
  3. Targets — Set target percentages for each symbol with real-time validation
  4. Trades — Generate trades using one of two strategies, then export as CSV

Rebalancing strategies

  • Minimize Trades — Makes the smallest changes needed to hit your targets. Best for taxable accounts or frequent rebalancing.
  • Consolidate — Moves each symbol into as few accounts as possible. Creates more trades but simplifies your portfolio structure.

Both strategies use a largest-remainder algorithm to convert dollar targets into whole shares while minimizing rounding error and respecting per-account budget constraints.

How it works

The UI is built with Ink (React for the terminal). ink-web bridges Ink to the browser by polyfilling Node.js APIs and connecting Ink's renderer to xterm.js. The same React components render natively in both environments — no code duplication.

In the browser, portfolio data is stored locally using the Origin Private File System (OPFS). In the terminal, it uses the local filesystem. A StorageAdapter interface abstracts the difference.

Install

npm install -g @cjroth/rebalance

Usage

Browser

npm run dev

Opens at http://localhost:1420. Drag and drop a CSV file or paste one in. Everything runs client-side.

Terminal

bun src/cli.ts              # full wizard
bun src/cli.ts import       # jump to a specific step
bun src/cli.ts review
bun src/cli.ts targets
bun src/cli.ts trades
bun src/cli.ts ./my-data    # custom data directory (default: ./portfolio-data)

CSV format

The universal CSV format uses #section headers:

#holdings
account,symbol,shares
401k,VTI,100
Roth IRA,VXUS,50

#symbols
name,price,countries,assets,beta
VTI,250.00,us:1.0,equity:1.0,1.0
VXUS,60.00,international:1.0,equity:1.0,1.1

#accounts
name,tax_status,provider,owner
401k,traditional,fidelity,sam
Roth IRA,roth,fidelity,sam

#targets
symbol,percent
VTI,60
VXUS,40

Only #holdings is required. Charles Schwab CSV exports are also auto-detected and parsed.

As a library

The rebalancing logic is published as @cjroth/rebalance and can be used programmatically:

import { calculateRebalanceMinTrades, calculateRebalance, convertToWholeShares } from '@cjroth/rebalance'

There's also a Next.js-compatible export for embedding the wizard in a web app:

import { Wizard } from '@cjroth/rebalance/next'

Tech stack

  • React 19 + Ink 6 — shared UI across terminal and browser
  • ink-web — the bridge that makes it work in both environments
  • Vite 7 — dev server and bundler
  • Bun — runtime for the CLI
  • Zod 4 — schema validation
  • xterm.js — terminal emulator in the browser
  • TypeScript — strict mode throughout