{"id":50341365,"url":"https://github.com/lubasinkal/v-star","last_synced_at":"2026-05-29T17:02:10.054Z","repository":{"id":345132166,"uuid":"1184635271","full_name":"lubasinkal/v-star","owner":"lubasinkal","description":"High-performance actuarial engine in Go — zero dependencies, CSV streaming at millions/sec, Monte Carlo, VaR/CTE, annuities, and mortality tables. Doesn't suck and Its NOT slow.","archived":false,"fork":false,"pushed_at":"2026-05-27T21:24:11.000Z","size":14424,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T22:13:53.436Z","etag":null,"topics":["actuarial","actuarial-science","annuity","financial-modeling","go","golang","high-performance","monte-carlo","mortality-rates","quantitative-finance","risk-management","zero-dependencies"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lubasinkal.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"lubasinkal","open_collective":"lubasinkal"}},"created_at":"2026-03-17T19:27:27.000Z","updated_at":"2026-05-27T21:23:34.000Z","dependencies_parsed_at":"2026-05-13T16:01:51.254Z","dependency_job_id":null,"html_url":"https://github.com/lubasinkal/v-star","commit_stats":null,"previous_names":["lubasinkal/v-star"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/lubasinkal/v-star","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubasinkal%2Fv-star","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubasinkal%2Fv-star/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubasinkal%2Fv-star/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubasinkal%2Fv-star/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lubasinkal","download_url":"https://codeload.github.com/lubasinkal/v-star/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubasinkal%2Fv-star/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33662205,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actuarial","actuarial-science","annuity","financial-modeling","go","golang","high-performance","monte-carlo","mortality-rates","quantitative-finance","risk-management","zero-dependencies"],"created_at":"2026-05-29T17:02:09.265Z","updated_at":"2026-05-29T17:02:10.030Z","avatar_url":"https://github.com/lubasinkal.png","language":"Go","funding_links":["https://github.com/sponsors/lubasinkal","https://opencollective.com/lubasinkal"],"categories":[],"sub_categories":[],"readme":"# v-star: The Actuarial Engine That Doesn't Suck\n\n**Your calculations just got millions of times faster.**\n\nEver tried to run a valuation on a million-policy census? Watched Excel freeze, crash, or take hours? v-star is the answer. Built in Go — an actually fast language compared to R, Python, or VBA — it handles massive datasets and calculations in milliseconds while your coffee is still hot.\n\n![CI](https://github.com/lubasinkal/v-star/actions/workflows/ci.yml/badge.svg)\n![License](https://img.shields.io/badge/License-MIT-green)\n\n---\n\n## The Story\n\nActuarial science grad. Tired of:\n\n- Excel crashing on big files\n- VBA scripts that nobody understands\n- Python code that felt slow (still better than VBA)\n- Proprietary tools where you can't see the math\n- Waiting to get accepted for a job\n\nSo I built v-star. Zero dependencies. All the actuarial stuff a gradute would think you'd need. Fast enough to make your laptop feel like a supercomputer.\n\nWhy the name? Comes from a joke in class: if premiums compound at rate **j** but you're discounting at **i**, the new discount factor is **v\\*** = (1+j) × v. The star marks the difference.\n\n---\n\n## What Can It Do?\n\n| Feature | What it means for you |\n|---------|----------------------|\n| **Present Value** | Standard \u0026 v\\* discount factors — the core of everything |\n| **Annuities** | Whole life, term, deferred — with real mortality tables |\n| **Reserves** | Net premium, gross premium, prospective, retrospective |\n| **Monte Carlo** | GBM + Vasicek mean-reverting models. 100k paths in ~27ms |\n| **Risk Measures** | VaR, CTE, Expected Shortfall, confidence intervals |\n| **Multiple Decrements** | Combine death, lapse, disability into a single table |\n| **Big CSV Streaming** | Stream millions of rows without blowing up your RAM |\n| **HTTP API** | Call from Python, R, Excel via REST endpoints |\n| **Zero Dependencies** | Standard library only. No pip, no npm, no version hell |\n\n**New:** Core interfaces added — `PathGenerator` (stochastic), `ContingencyCalculator` (annuities), `RecordWriter` (writer). Stream from any `io.Reader` via `StreamCensusFromReader`. `JSONRecord`/`CSVRecord` unified into `Record` type. `MortalityTable` now includes `Ex()` and `Lx()`. Parallel Monte Carlo (2.2× faster at 1M paths × 180 steps).\n\n---\n\n## Speed\n\nBenchmarked on an Intel i5-8250U laptop (1.6-3.4 GHz, 8 cores, NVMe SSD). Plugged in.\n\n| Benchmark | Time | Throughput |\n|-----------|------|------------|\n| **CSV Parsing** (10M rows, 288 MB) | 0.80s | **12.6M rows/s** |\n| **Present Value** (single call, direct) | 2.6 ns | **380M / second** |\n| **Present Value** (single call, constructor) | 22.8 ns | **44M / second** |\n| **Annuity** (whole life, 90 terms) | 512 ns | **2M / second** |\n| **Monte Carlo** (100k paths, 10 steps) | 27 ms | **3.7M paths/sec** |\n| **Risk Report** (VaR + CTE, 100k losses) | 0.42 ms | **237M losses/sec** |\n| **Valuation** (10M policies, parallel) | 37 ms | **272M policies/sec** |\n\n### CSV Comparison (10M Rows)\n\n| Tool | Time | Memory |\n|------|------|--------|\n| **v-star** (mmap) | **0.80s** | **1.3 GB (OS page cache)** |\n| **v-star** (streaming) | 1.12s | ~0.2 MB |\n| Polars | ~535ms | ~500 MB |\n| Pandas | ~30s | \u003e2 GB |\n\n*v-star uses memory-mapped I/O for zero-copy parsing. The mmap path uses OS page cache (lazily paged, released to OS under memory pressure). The streaming path keeps memory constant regardless of file size.*\n\n### Monte Carlo (100k Paths)\n\n| Tool | Time | VaR/CTE |\n|------|------|---------|\n| **v-star** | **27ms** | ✓ (with confidence intervals) |\n| Python/Numpy | ~2s | ✓ |\n| R | ~5s | ✓ |\n\n---\n\n## Quick Start\n\n```bash\n# Install\ngo get github.com/lubasinkal/v-star\n\n# Run examples\ngo run ./examples/quickstart              # PV and duration\ngo run ./examples/monte_carlo_risk       # Monte Carlo + VaR\ngo run ./examples/csv_valuation           # Big CSV processing\n\n# Build CLI\ngo build -o v-star ./cmd/v-star\n\n# Process a policy CSV\n./v-star read policies.csv --benchmark\n\n# Run Monte Carlo\n./v-star montecarlo --paths=100000 --steps=10\n\n# Start HTTP server\n./v-star serve\n```\n\n---\n\n## Code Examples\n\n### For Actuarial Students \u0026 Professionals\n\nYou already know the math:\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n\n    \"github.com/lubasinkal/v-star/pkg/annuities\"\n    \"github.com/lubasinkal/v-star/pkg/mortality\"\n    \"github.com/lubasinkal/v-star/pkg/rates\"\n    \"github.com/lubasinkal/v-star/pkg/reserves\"\n)\n\nfunc main() {\n    // Present value — like Excel's =PV(0.05, 20, 0, -100000)\n    converter := rates.NewRateConverter(0.05)\n    pv := converter.PresentValue(100000, 20)\n    fmt.Printf(\"PV: %.2f\\n\", pv) // 37,688.95\n\n    // Build a mortality table inline\n    qx := []float64{0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.10}\n    mort := mortality.NewTable(\"example\", qx)\n\n    // Annuity with mortality table\n    ann := annuities.NewAnnuityCalculator(converter, mort)\n    pv = ann.WholeLifeImmediate(65, 1000)\n    fmt.Printf(\"Annuity PV: %.2f\\n\", pv)\n\n    // Reserve calculation\n    policy := reserves.PolicySpec{Age: 50, Term: 20, SumAssured: 100000}\n    reserve := reserves.NetPremiumReserve(policy, converter, mort)\n    fmt.Printf(\"Reserve: %.2f\\n\", reserve)\n\n    // Multiple decrements (death + lapse combined)\n    death := mortality.NewTable(\"death\", []float64{0, 0.01, 0.02})\n    lapse := mortality.NewTable(\"lapse\", []float64{0, 0.05, 0.10})\n    dt := mortality.NewDecrementTable([]*mortality.Table{death, lapse}, nil)\n    fmt.Printf(\"Total qx at age 1: %.4f\\n\", dt.Qx(1))\n    fmt.Printf(\"Death cause qx at age 1: %.4f\\n\", dt.QxByCause(1, 0))\n}\n```\n\n### For Developers\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n    \"os\"\n\n    \"github.com/lubasinkal/v-star/pkg/concurrency\"\n    \"github.com/lubasinkal/v-star/pkg/rates\"\n    \"github.com/lubasinkal/v-star/pkg/reader\"\n    \"github.com/lubasinkal/v-star/pkg/risk\"\n    \"github.com/lubasinkal/v-star/pkg/stochastic\"\n    \"github.com/lubasinkal/v-star/pkg/writer\"\n)\n\nfunc main() {\n    converter := rates.NewRateConverter(0.05)\n\n    // Vasicek mean-reverting rates (instead of GBM)\n    vg := stochastic.NewVasicekGenerator(0.05, 0.04, 0.5, 0.02)\n    path := vg.GeneratePath(10, 1.0)\n    fmt.Println(\"Vasicek final rate:\", path[10])\n\n    // Monte Carlo + VaR with confidence intervals\n    rg := stochastic.NewRateGeneratorWithSeed(0.05, 0.02, 0.15, 42)\n    paths := rg.GeneratePaths(100000, 10, 1.0)\n    losses := make([]float64, len(paths))\n    for i, p := range paths {\n        losses[i] = 1000000 * (0.05/p[10] - 1)\n        if losses[i] \u003c 0 {\n            losses[i] = 0\n        }\n    }\n    report := risk.ComputeReport(losses)\n    fmt.Printf(\"VaR 95%%: %.2f, CTE 95%%: %.2f\\n\", report.VaR95, report.CTE95)\n\n    // Stream census records (simulating from memory)\n    records := []reader.CensusRecord{\n        {Age: 30, Sex: \"M\", PolicyType: \"term\", SumAssured: 100000, Term: 20},\n        {Age: 45, Sex: \"F\", PolicyType: \"whole\", SumAssured: 200000, Term: 15},\n    }\n\n    // Generic parallel worker pool with context cancellation\n    wp := concurrency.NewWorkerPool(4, func(r reader.CensusRecord) float64 {\n        return converter.PresentValue(r.SumAssured, r.Term)\n    })\n    totalPV := wp.ProcessBatch(records)\n    fmt.Printf(\"Total PV: %.2f\\n\", totalPV)\n\n    ctx := context.Background()\n    result, err := wp.ProcessBatchContext(ctx, records)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Printf(\"Context result: %.2f\\n\", result)\n\n    // Monte Carlo parallel — concrete types satisfy PathGenerator implicitly\n    gen := stochastic.NewRateGenerator(0.05, 0.02, 0.15)\n    paths = gen.GeneratePathsParallel(100000, 10, 0, 1.0)\n    fmt.Printf(\"Generated %d paths in parallel\\n\", len(paths))\n\n    // Pick output format at runtime\n    w := writer.NewRecordWriter(os.Stdout, \"json\")\n    defer w.Close()\n    w.WriteRecord(writer.Record{\n        Age: 30, Sex: \"M\", SumAssured: 100000, Term: 20, PresentValue: 37688.95,\n    })\n}\n```\n\n### CSV Reader — Which one to use\n\n| Function | When to use |\n|----------|-------------|\n| `StreamCensus` | Process an actuarial census CSV row by row (auto-detects columns); accumulate your own metrics |\n| `StreamCensusChunked` | Batch processing (database inserts, API calls) |\n| `StreamCensusFromReader` | Stream census data from any `io.Reader` (stdin, HTTP body, in-memory) |\n| `StreamCSV` | Generic CSV with string fields (non-standard column layout) |\n| `StreamCSVRaw` | Generic CSV with zero-allocation byte slices |\n| `GetHeaders` | Inspect column headers before deciding parsing strategy |\n\n**All standard library. Zero external dependencies.**\n\n---\n\n## CLI\n\n```bash\n# Calculate discount factors\n./v-star -i 0.05 -j 0.02\n\n# Process a policy CSV\n./v-star read policies.csv --benchmark\n./v-star read policies.csv --table=mortality.csv --output=json\n./v-star read policies.csv --output=csv --limit=10000\n./v-star read policies.csv --output=report\n./v-star read policies.csv --interest=0.04 --header=true\n\n# Run Monte Carlo\n./v-star montecarlo --paths=100000 --steps=10 --seed=42\n./v-star montecarlo --paths=1000000 --steps=180 --workers=8 --drift=0.03 --volatility=0.20\n\n# Run benchmark suite\n./v-star bench\n\n# Start HTTP server\n./v-star serve --port=8080\n```\n\n---\n\n## HTTP API\n\nStart the server:\n\n```bash\n./v-star serve --port=8080\n```\n\nAll endpoints return JSON. The server includes CORS (cross-origin), request logging, and graceful shutdown on Ctrl+C.\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/health` | GET | Health check |\n| `/value` | POST | Present value calculation (batch records) |\n| `/simulate` | POST | Stochastic simulation — GBM or Vasicek + risk metrics (VaR, CTE) |\n| `/annuity` | POST | Life-contingent annuity and net single premium calculations |\n| `/reserve` | POST | Policy reserve calculations (net/gross/premium/prospective/retrospective) |\n\n### Examples\n\n```bash\n# Present value\ncurl -s -X POST http://localhost:8080/value \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"interest_rate\":0.05,\"records\":[{\"sum_assured\":100000,\"term\":20}]}'\n\n# Monte Carlo\ncurl -s -X POST http://localhost:8080/simulate \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"num_paths\":10000,\"steps\":10,\"initial_rate\":0.05,\"drift\":0.02,\"volatility\":0.15}'\n\n# Annuity\ncurl -s -X POST http://localhost:8080/annuity \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"interest_rate\":0.05,\"qxs\":[0.001],\"age\":30,\"amount\":1000,\"computation\":\"whole_life_immediate\"}'\n\n# Reserve\ncurl -s -X POST http://localhost:8080/reserve \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"interest_rate\":0.05,\"qxs\":[0.001],\"age\":30,\"term\":20,\"sum_assured\":100000,\"method\":\"net_premium\"}'\n```\n\n### Python\n\n```python\nimport requests\n\n# Present value\nresp = requests.post(\"http://localhost:8080/value\", json={\n    \"interest_rate\": 0.05,\n    \"records\": [{\"sum_assured\": 100000, \"term\": 20}]\n})\nprint(resp.json())\n\n# Monte Carlo\nresp = requests.post(\"http://localhost:8080/simulate\", json={\n    \"num_paths\": 100000, \"steps\": 10,\n    \"initial_rate\": 0.05, \"drift\": 0.02, \"volatility\": 0.15\n})\nprint(resp.json())  # {\"var_95\": ..., \"cte_95\": ...}\n\n```\n\n**v-star's HTTP API works from any language** — Python, R, JavaScript,\nTypeScript, Excel VBA, Julia, Rust, etc. See\n[examples/api-clients/](./examples/api-clients/) for full examples in\nPython, R, JavaScript, TypeScript, and cURL.\n\n---\n\n## Why Go?\n\n- **Speed** — Compiles to native code, no interpreter overhead. 380M PV calculations/sec\n- **Zero deps** — Standard library only. No pip, no npm, no version conflicts\n- **Readable** — Every formula is right there in the source. Audit-friendly\n- **Concurrent** — Goroutines make parallelism trivial\n- **Portable** — One binary, runs anywhere\n\n---\n\n## Who's It For?\n\n| Person | Why v-star |\n|--------|------------|\n| **Actuarial student** | Learn by reading the code. Fast calculations for assignments. |\n| **Actuary** | Replace slow Excel/VBA. Process big censuses in seconds. |\n| **Analyst** | Stream big CSVs without crashing. Get results, not errors. |\n| **Developer** | Build insurance/risk tools via HTTP API from any language. |\n| **Risk manager** | Run Monte Carlo + VaR in production. Fast. |\n\n---\n\n## What's Coming Next?\n\n- **v0.8.0** — Reserve methods, CensusSource interface, profit testing, Dockerfile, API freeze\n- **v1.0.0** — Stable API, 90%+ test coverage, \n\nFull roadmap: [ROADMAP.md](./ROADMAP.md)\n\n---\n\n## Contributing\n\nPRs welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md). Found a bug? [Open an issue](https://github.com/lubasinkal/v-star/issues).\n\n---\n\n## License\n\nMIT — do whatever you want with it. See [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flubasinkal%2Fv-star","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flubasinkal%2Fv-star","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flubasinkal%2Fv-star/lists"}