Skip to main content

Modeleon

PyPI Python License Open in Colab

Write Python. Ship real Excel formulas.

Variable — a value.
MultiVariable — a concept, modeled as a set of Variables and sub-concepts.
Excel — one cell-traceable snapshot of a MultiVariable.

Modeleon demo — Python on the left, live Excel formulas on the right

import modeleon as mo

forecast = mo.MultiVariable("Forecast")
forecast.pnl = mo.MultiVariable("P&L")
with forecast.pnl as pnl:
    pnl.revenue  = mo.Variable(1_000_000, unit="$")
    pnl.cogs_pct = mo.Variable(0.6, display_name="COGS %")
    pnl.cogs     = pnl.revenue * pnl.cogs_pct
    pnl.profit   = pnl.revenue - pnl.cogs

forecast.to_excel("forecast.xlsx")

The resulting forecast.xlsx:

A B
1 Revenue ($) 1000000
2 COGS % 0.6
3 Cogs =B1*B2
4 Profit =B1-B3

B3 is =B1*B2 — a real Excel formula, not the baked value 600000.


How is this different from openpyxl / xlsxwriter / pandas?

Modeleon openpyxl / xlsxwriter pandas → Excel
Output is a live model ✅ formulas ⚠️ you author them as strings ❌ values only
Cross-cell dependency graph ✅ tracked automatically ❌ ❌
Cross-sheet refs (=Sheet!Cell) ✅ resolved by the engine ⚠️ manual string concat ❌
Audit-trail per cell ✅ every value traces back ❌ ❌

The lower stack writes spreadsheets. Modeleon writes the model that produces a spreadsheet — every cell, every formula, every dependency.


Install

pip install modeleon

Python 3.12+.


Variable

A value or formula. Arithmetic tracks dependencies automatically.

revenue = mo.Variable(1_000_000)
cogs    = revenue * mo.Variable(0.6)
cogs.value         # 600_000.0
cogs.formula       # 'revenue * 0.6'
cogs.dependencies  # {'revenue'}

Scalar, list, or unit-bearing — all the same Variable.


MultiVariable

A concept. Variables are its attributes; sub-MultiVariables are its inner concepts.

forecast = mo.MultiVariable("Forecast")
forecast.assumptions = mo.MultiVariable("Assumptions", tax_rate=mo.Variable(0.25))
forecast.pnl = mo.MultiVariable("P&L")
forecast.pnl.revenue = mo.Variable(1_000_000)
forecast.pnl.taxes   = forecast.pnl.revenue * forecast.assumptions.tax_rate

Cross-sheet refs resolve automatically.
forecast.pnl.taxes = forecast.pnl.revenue * forecast.assumptions.tax_rate — the engine emits =B1 * Assumptions!B2 in Excel. Change the tax rate on Assumptions, P&L recalculates.

Reusable concepts subclass MultiVariableClass:

class Cohort(mo.MultiVariableClass):
    def compute(self, start, churn, price):
        self.users   = mo.recurrence(start, "{prev} * (1 - {c})", c=churn)
        self.revenue = self.users * price

Recurrence — period-over-period series

recurrence builds a list-valued Variable where every period references the previous period via a formula. The Excel output is a chain of cells, not a static list of values.

forecast.assumptions = mo.MultiVariable("Assumptions",
    start_rev=mo.Variable(1_000_000, unit="$"),
    growth=mo.Variable([0.05] * 12),
)

forecast.pnl = mo.MultiVariable("P&L")
forecast.pnl.revenue = mo.recurrence(
    start=forecast.assumptions.start_rev,
    formula="{prev} * (1 + {growth})",
    growth=forecast.assumptions.growth,
)

The 12 emitted Excel cells:

B1: =Assumptions!B1                          (period 0 = start)
C1: =B1 * (1 + Assumptions!C2)               (compounded period 1)
D1: =C1 * (1 + Assumptions!D2)               ...
... through M1

Change a growth value on Assumptions — every later cell recalculates.


Excel as a snapshot

.to_excel() walks the MultiVariable tree and writes a workbook where every Variable is a cell, every formula is =A1*B2, every cross-sheet reference is =Sheet!Cell.

Standard library functions emit live formulas, not values:

mo.IRR(cf)       # =IRR(B2:F2, 0.1)
mo.NPV(0.1, cf)  # =NPV(0.1, B2:F2)
mo.IF(rev > 0, rev * 0.25, 0)   # =IF(B1>0, B1*0.25, 0)
mo.EOMONTH(start, 1)            # =EOMONTH(B1, 1)

Also: IRR, NPV, XIRR, PMT, FV, PV · SUM, MAX, MIN, AVERAGE · IF, AND, OR, NOT · ABS, ROUND, INT, MOD · YEAR, MONTH, DAY, EDATE, EOMONTH, DATE, TODAY · CONCAT, UPPER, LOWER, LEN. All emit live formulas.


In a notebook

Every Variable, MultiVariable, and Model has a built-in _repr_html_. In Jupyter you see a live grid of values + formulas with click-to-trace-precedents — Excel's "Trace Precedents" button, in the browser. Toggle "Formulas" to flip every cell to its underlying expression.

Modeleon notebook trace-precedents — clicking a formula cell highlights its inputs in gold

Try it without installing anything: Open the first-model notebook in Colab.


If Modeleon resonates — a GitHub ⭐ helps more people find it.


License

Apache 2.0. See LICENSE and NOTICE.

Why this exists → The case for Financial Model Engineering

Releases: CHANGELOG · GitHub releases

modeleon.ai · PyPI


Built with ❤️ from Kazakhstan

Release files for modeleon 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for modeleon 0.2.0
File Size Uploaded
modeleon-0.2.0.tar.gz 391.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for modeleon 0.2.0
File Interpreter ABI Platform
modeleon-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 663.6 kB

Release files / modeleon-0.2.0.tar.gz

Download URL modeleon-0.2.0.tar.gz
Size 391.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d95320fb727fb648c3cd8476ee5e3ace52d7a9cc24c365fcd017f8b24a09c0d6
BLAKE2b-256 checksum
How to use checksums
3c0a3e77dbd8ad44f99a10d3fe15e89aa8bb369cc596b1a0510f6b2996f619e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release files / modeleon-0.2.0-py3-none-any.whl

Download URL modeleon-0.2.0-py3-none-any.whl
Size 271.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea4b7af3a1f52890e9e97cc02ae5a3dadd62bf8146605f63c22bae9b993c0cf6
BLAKE2b-256 checksum
How to use checksums
68b7983d0b74b58e071857fc968dce42b59a19c2878862d2cc53015e86c9ef13
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page