A market research platform, 14.5 months with one client
A market research company publishes ETF and stock research for its readers. I’ve worked on its platform since August 2025, from the price loaders and the database to the dashboards, the nightly research charts and the email that lands each morning.




The client
A research company that publishes ETF and stock analysis. Readers get dashboards, holdings tables and a daily email card, and the company’s analysts write their own research in Python on the same platform.
I started in August 2025 on hourly work. Since March 2026 the work runs in numbered sprints, each with a written scope and one report at the end, under a direct contract since late April. Sprint 19 closed on 2 November and the next one is planned.
What I own
The whole path. Nightly loaders pull prices and fund holdings from 29 sources into PostgreSQL. A Django REST API serves them to a React app with Chart.js and Plotly. 342 research scripts run every night, render charts with Matplotlib and go out as email reports through AWS SES.
It runs on AWS ECS Fargate and RDS, with all infrastructure in Terraform Cloud and 18 GitHub Actions workflows for tests and deploys.
Three fixes, measured
Scheduled reports had been stuck for 72 days when I found the cause. They run on time again.
The reports page froze because one page load made more than 3,800 API requests. It now makes 3.
On 26 October, 30 of 75 nightly charts came out blank. Several threads shared one Matplotlib state. After the fix, 0 of 94 and then 0 of 88 were blank.
Data a reader can trust
I rebuilt 24 ETF cards from raw prices in a clean room and compared every figure. None was made up, and the 10 year annualized returns matched to 0.035 percentage points on average.
Holdings tables went from 600 to 1,800 rows with server-side paging, sorting and search, and one page now weighs about 6 KB compressed.
How the sprints run
Every sprint starts with a written scope and ends with one written report and an invoice by hours. Tests grow with the code, backend from 933 to 948 and front end from 152 to 185.
Security work rides along. API keys moved out of the task environment into AWS Secrets Manager, and the database password and app secret were rotated through Terraform.
The client’s name is withheld under an NDA. The screens are anonymized, and every number on them is public market data.