Causal Agricultural Intelligence

Testing Policy Thresholds
On Mandi Margins

MandiIQ is an open-source analytical warehouse and dashboard that applies Causal Regression Discontinuity Designs (RDD) to test whether IMD rainfall-deficit thresholds drive structural margins in national commodity markets.

Regression Discontinuity Causal Inference DuckDB Analytical Store FastAPI inference Streamlit Front MLflow Models
01 / REAL-TIME LEDGER

Warehouse Scale & Coverage

Live Price Records
Prices in DuckDB warehouse
Commodity Scope
Unique agricultural commodities
District Coverage
Markets across India
RDD Estimates
Causal estimates computed
Deployment Surface Health checking…
LATESTSTALEDOWNAUTH/STATIC
02 / EMPIRICAL FRAMEWORK

Regression Discontinuity Design

Does the IMD declaring a region as "rain-deficient" drive agricultural market behavior, or is price movement merely a continuous function of physical precipitation?

We test this by placing rain departure on the horizontal axis and modeling the discontinuity at the official -20% deficit cutoff.

Causal RDD Specification

We estimate local linear regressions on both sides of the -20% threshold:

Yit = α + β Dit + γ1 (Xit - c) + γ2 Dit(Xit - c) + εit

Where Yit is log market price, Xit is rainfall departure %, c = -20% is the threshold, and Dit is indicator for deficit territory.

Our findings suggest that while physical rainfall levels strongly affect yields, the administrative -20% declaration produces statistically insignificant jumps in most crops, with the notable exception of Onions which show active hoarding signals.

Empirical Results
CropDiscontinuityP-Value
Onion+0.142p < 0.05
Tomato-0.024p = 0.74
Wheat+0.009p = 0.89
Potato+0.053p = 0.31
McCrary Density Check

We run a McCrary Density Test to examine manipulation of the running variable around the -20% cutoff boundary, ensuring the validity of our causal estimates.

03 / SYSTEM ARCHITECTURE

Decoupled Processing & Serving

MandiIQ decouples the analytical warehouse from the customer-facing dashboard. The system runs an automated ELT pipeline using DuckDB, fits locally weighted regressions, tracks models in MLflow, and exposes predictions through FastAPI.

%%{init: {"theme": "dark", "themeVariables": { "primaryColor": "#1a1a2e", "primaryTextColor": "#fff", "lineColor": "#d7ff00"}}}%%
flowchart TB
    subgraph Sources["Data Sources"]
        A1["Agmarknet API
Daily Mandi Prices"] A2["IMD Weather Grids
Rainfall Departure"] A6["Ashoka CEDA
Historical Price CSV"] end subgraph Ingestion["Ingestion Pipeline"] B1["fetch_prices.py
Pagination + Retry"] B2["fetch_rainfall.py
Sub-division Parser"] B3["fetch_ndvi.py
Sentinel Hub"] B4["scheduler.py
Orchestration"] end subgraph Storage["Analytical Store"] C1["DuckDB
mandi_iq.duckdb
{{n_prices}} rows"] C2["data_lineage
Provenance Tracking"] end subgraph Analysis["Analysis Engine"] D1["Causal RDD
Local-linear + FE"] D2["Forecast
Seasonal Naive"] D3["Classifier
XGBoost + SHAP"] end subgraph Serving["Serving Layer"] F1["FastAPI Gateway
/health /prices /forecast"] F2["Streamlit Dashboard
test-mandi-keae7eruks2n4cqvumjfu8.streamlit.app"] end A1 --> B1; A6 --> B3; A2 --> B2; B4 --> B1; B4 --> B2; B4 --> B3; B1 --> C1; B2 --> C1; B3 --> C1; C1 --> D1; C1 --> D2; C1 --> D3; D1 --> F1; D2 --> F1; D3 --> F1; F1 --> F2;

Failure Modes

If the MLflow registry is unreachable, FastAPI falls back to a local serialized model pickle. Climate variables exceeding 3σ trigger automated retraining on a 90-day window. All forecasting endpoints gracefully fallback to moving-average baselines.

Active Fail-Safe

All endpoints fallback gracefully. If an API call fails, the dashboard swaps to a historical moving-average baseline.

02 / PROJECT STRUCTURE

Repository Map 87 Python · 10 Modules · 14 Dashboard Pages · 5 SQL

Click any file to open it on GitHub.

ai/ 3 files
Multi-model AI orchestrator with circuit breaker, Gemini/OpenRouter routing, and model config.
  • orchestrator.py
  • router.py
  • models.yaml
analysis/ 8 modules
RDD causal engine, fixed-effects cross-check, forecast (seasonal naive + LSTM), classifier, prescriptive advice.
  • rdd_engine.py Causal RDD
  • fixed_effects.py FE cross-check
  • forecast.py
  • classifier.py
  • prescriptive.py
ingestion/ 6-stage ETL
Price fetch (page + variety), rainfall parser, NDVI satellite, historical CSV backfill, scheduler.
  • fetch_prices.py 200ms
  • fetch_rainfall.py 1m 24s
  • fetch_ndvi.py 3m 0s
  • scheduler.py
dashboard/pages/ 14 core
Streamlit multi-page app: executive overview, causal explorer, forecast, risk map, satellite NDVI.
  • executive_overview
  • discontinuity
  • forecast
  • risk_map
  • satellite
  • causal_explorer
api / storage / styles / tests infra
FastAPI gateway, DuckDB analytical store, design tokens CSS, and data integrity test suite.
  • api/main.py
  • storage/duckdb_store.py
  • styles/design.css
  • tests/test_verification.py
dashboard/frontend/ Vite + React
TypeScript React app with FlipBoard KPI count-up, Three.js WebGL hero, and code-split Vite build.
  • FlipBoard.tsx
  • WebGLHero.tsx
  • vite.config.ts
<1s (fast) <20s (medium) ≥20s (slow)
🐍 run_hourly.py 📋 render.yaml 🐳 Dockerfile.northflank 📄 requirements.txt 🗄 mandi_iq.duckdb
03 / PIPELINE REPORT

Live Pipeline Status loading...

Failed to load data.
Price Rows
loading...
Commodities
loading...
States / Districts
loading...
RDD Results
loading...
Forecast Models
loading...
Avg MAPE
loading...
Last Run
loading...
NDVI Districts
loading...
Pipeline DAG auto-refresh 60s
60s
Rendering pipeline diagram...
Commodity Freshness
CommodityLatest DateEarliest DateRowsDistrictsStates
Loading...
Last updated: just now ⟳ Refresh · GitHub
04 / PIPELINE DIAGRAM

Interactive Pipeline Flow loading metrics...

01 Ingestion 02 Warehouse 03 Analysis 04 Orchestrator 05 Serving
primary flow secondary flow bidirectional click any node to open source file