Financial Intelligence
Platform
Enterprise financial data governance platform built on Snowflake and dbt. Real OHLCV market data, 500k simulated banking transactions, and 200k consumer loan records are loaded into Snowflake and transformed through versioned dbt models into analytics-ready tables. A LangChain NL-to-SQL agent powered by Llama converts plain-English business questions into validated SQL, with schema-aware prompts, sqlglot safety checks, and a 3-attempt retry loop. Automated data quality checks and append-only lineage tracking run after every pipeline execution.
Ask the NL-SQL Agent
Ask any business question in plain English. A local Llama model generates the SQL, runs it against a DuckDB & Snowflake warehouse of 700k+ financial records, and returns real results in seconds. This runs live on my machine via a Cloudflare Tunnel.
What Was Built
An enterprise-grade financial data governance platform. Raw financial data flows from source systems through a dbt transformation layer into a Snowflake cloud warehouse, with a natural language query interface powered by a local LLM agent.
Cloud Warehouse Architecture
The platform follows an ELT pattern: raw financial data lands in Snowflake staging tables, then dbt models apply business logic, grain definitions, and data quality assertions to produce analytics-ready output. All transformation logic is version-controlled and replayable.
NL-to-SQL Agent
A LangChain agent converts plain-English questions into validated SQL using a schema-aware system prompt, few-shot examples, and a 3-attempt retry loop. sqlglot blocks any non-SELECT statement before it touches the database.
Automated Data Quality
After every ingestion run, inline DQ validators check row counts, null rates, value distributions, and date ranges across all 4 data tables. Results are written to data_quality_log and exposed via /query/dq.
End-to-End Architecture
Three layers: a Python ingestion pipeline that loads raw financial data into Snowflake staging tables, a dbt transformation layer that builds analytics models with built-in DQ tests, and an NL-SQL agent that bridges plain-English questions to Snowflake SQL.
ref() dependencies define the transformation DAG: staging models clean and type-cast raw data, mart models apply business logic, aggregations, and fraud classification. Every model is documented, testable, and independently replayable.
Five Warehouse Tables
Transaction and loan-level records aren't available outside a production banking environment, so three of the tables are built from simulated data, calibrated against real-world statistical distributions and produced deterministically with NumPy (seed=42). Market data is fetched live from the yfinance API on each ingestion run. All four are loaded into Snowflake staging and transformed through dbt staging and mart models into the final analytics schema.
yf.download()
with a 5-year lookback. Flattened from MultiIndex to per-row format:
(symbol, trade_date, open, high, low, close, adj_close, volume).
A UNIQUE(symbol, trade_date) constraint prevents duplicate rows on re-fetch.
Approximately 26,000 rows total.
GET /query/dq or through the NL-SQL agent.
data/lineage.json
records a lineage entry for every table after ingestion: source system,
row count, ingest timestamp, and DQ pass rate. Never overwritten, creating
an audit trail of every pipeline run. Exposed via GET /query/lineage/{'{'}table{'}'}.
Natural Language to SQL Agent
The agent converts plain-English questions into Snowflake SQL using a schema-aware system prompt with all 5 table definitions, few-shot examples for common patterns, and a retry loop that feeds SQL execution errors back to the model.
Agent Flow
Sample Questions
| Question | Tables |
|---|---|
| Which merchant categories have the highest confirmed fraud rate this year? | transactions + fraud_events |
| Fraud type breakdown by channel with confirmation rate and avg confidence score | transactions + fraud_events |
| Top 10 accounts by total confirmed fraud value in the last 90 days | transactions + fraud_events |
| High-confidence fraud events above 0.85 with merchant category and channel | transactions + fraud_events |
| Loan grade default rate, avg FICO, and avg interest rate ranked by risk | loans |
| Which loan purpose has the highest default rate and average DTI? | loans |
| Goldman Sachs monthly closing price and volume trend last 12 months | market_data |
| Avg daily high-low spread for JPM, GS, BAC, and C over the last 6 months | market_data |
| Fraud model version precision rate broken down by fraud type | fraud_events |
| Monthly flagged transaction trend this year with avg amount and total value | transactions |
Select expression. Any INSERT, UPDATE, DELETE, DROP, or CREATE returns an error immediately without executing, making the API safe to expose without authentication.
FastAPI Endpoints
Five endpoints exposed via FastAPI. The query endpoint runs the NL-SQL agent against the Snowflake warehouse. The others expose schema metadata, data quality results, and lineage records.
Key Design Decisions
Choices made during development and the reasoning behind them.
ELT over ETL with dbt
Raw financial data is loaded first, transformed second. Python ingestion writes to Snowflake staging tables without applying business logic. dbt then applies transformations, grain definitions, and aggregations as versioned SQL models. Transformation logic is auditable, testable with dbt test, and replayable independently of ingestion.
sqlglot as the SQL Safety Layer
Before any generated SQL reaches the Snowflake warehouse, sqlglot parses the statement and asserts every node is a Select expression. INSERT, UPDATE, DELETE, DROP, or CREATE are rejected before execution. This makes the /query endpoint safe to expose without authentication, even against a production-grade warehouse.
Ollama OpenAI-compat Endpoint
LangChain's ChatOpenAI is pointed at the local Ollama OpenAI-compatible endpoint with temperature=0.0. No custom Ollama integration needed. Any model registered with Ollama works without code changes: the model name is a single configurable setting.
Seed-Based Data Simulation
All data simulators use np.random.default_rng(seed=42). Every pipeline run produces identical data given the same parameters. BLS Consumer Expenditure Survey weights for transactions and LendingClub grade parameters for loans are hardcoded distributions, ensuring statistical reproducibility across analytics testing cycles.