Small demo app and library to simulate ETF prices built from synthetic bond data.
This repository contains a compact Streamlit application and supporting modules to:
- generate synthetic bond data,
- build a simple ETF from a subset of bonds with randomized weights,
- compute ETF price (weighted sum of bond prices), and
- visualize and compare ETF compositions between two dates.
The app is intended as a concise coding interview project illustrating basic data modeling, small domain objects, and a Streamlit UI for interactive exploration.
- Generate 2·N random
Bondobjects with configurable price ranges. - Build an
ETFfrom a selected subset of bonds with random weights. - Compute ETF price and pool value.
- Streamlit dashboard to run simulations and visualize:
- ETF weights at two dates
- Weight differences for common bonds
- Bonds entering or exiting the ETF
- Pool value comparison
app.py— Streamlit app (UI). Entry point for interactive simulations and visualizations.main.py— Core helper functions:generate_bonds,generate_weights,build_etf, and a simplemain()runner for quick testing.assets.py— Domain dataclasses:BondandETFwithpriceproperty andextract_data()helper.images/— UI assets (logo) referenced byapp.pyand the UML diagram generated with PlantUML.tests/— Unit tests forassets.pyandmain.pyto ensure correct behaviour. All tests can be run withpytest -qwhen the virtual environment is activated.requirements.txt— Python dependencies for running the app.
- Recommended: create and activate a virtual environment.
python -m venv .venv
source .venv/bin/activate- Install dependencies:
pip install -r requirements.txt- Run the Streamlit app (from the project root):
streamlit run app.pyOpen the URL printed by Streamlit (usually http://localhost:8501).
- In the app UI you can choose the number of bonds (
N) and a price range for generated bonds. - The app will generate
2·Nbonds but build each ETF fromNrandomly sampled bonds — this permits comparing two ETF snapshots built from different random samples.
Key functions:
main.generate_bonds(n, price_range)— returnsList[Bond].main.build_etf(name, as_of_date, bonds)— returns anETFinstance.ETF.price— computed as the weighted sum of underlying bond prices.
Below is a rendered class diagram for the main domain model.
This project is a personal demo by Karl ODJO.
