The files in raw/ are synthetic, produced by scripts/generate_data.py.
They are calibrated to published characteristics of Gujarat monsoon rainfall
but they are not observations. Nothing in this repository should be read as an
analysis of real Ahmedabad weather.
| File | Rows | Description |
|---|---|---|
rainfall_ahmedabad_daily.csv |
4,880 | Daily rainfall, kharif window, 1985 to 2024 |
yield_ahmedabad_annual.csv |
40 | Annual district yield, kg per hectare |
| Property | Value |
|---|---|
| Mean seasonal total | ~690 mm |
| Coefficient of variation | ~42% |
| Distribution shape | right-skewed, gamma-like |
| Trend | mild drying, roughly -1.9 mm per year |
| Dry-day probability | 72% |
Yield is generated as a saturating function of rainfall plus independent shocks. Those shocks represent pest outbreaks, heat stress, and harvest-time damage, none of which a rainfall index can observe. They are the reason the basis-risk analysis produces a non-trivial answer rather than a tautology.
The engine reads two CSVs with fixed schemas. Any source producing those schemas will work without code changes.
rainfall_ahmedabad_daily.csv
date,rainfall_mm
1985-06-01,0.0
1985-06-02,12.4
yield_ahmedabad_annual.csv
year,yield_kg_per_ha
1985,1642.0
The India Meteorological Department publishes 0.25 degree gridded daily
rainfall from 1901. The imdlib package wraps the download.
import imdlib as imd
data = imd.get_data("rain", 1985, 2024, fn_format="yearwise")
ds = data.get_xarray()
# Ahmedabad district centroid, approximately
lat, lon = 23.02, 72.57
series = ds.sel(lat=lat, lon=lon, method="nearest").to_dataframe().reset_index()
series = series.rename(columns={"time": "date", "rain": "rainfall_mm"})
series[["date", "rainfall_mm"]].to_csv("data/raw/rainfall_ahmedabad_daily.csv", index=False)For a real product the grid cell should be replaced by the actual reference weather station named in the policy wording, since the contract pays on that station and no other. Grid-to-station mismatch is itself a source of basis risk.
import pandas as pd, requests
url = (
"https://power.larc.nasa.gov/api/temporal/daily/point"
"?parameters=PRECTOTCORR&community=AG"
"&longitude=72.57&latitude=23.02"
"&start=19850101&end=20241231&format=JSON"
)
payload = requests.get(url).json()
series = payload["properties"]["parameter"]["PRECTOTCORR"]
df = pd.DataFrame({
"date": pd.to_datetime(list(series.keys())),
"rainfall_mm": list(series.values()),
})
df = df[df.rainfall_mm >= 0]
df.to_csv("data/raw/rainfall_ahmedabad_daily.csv", index=False)Ministry of Agriculture and Farmers Welfare district-level crop statistics are published through data.gov.in and the Directorate of Economics and Statistics. Select a single crop, since aggregating across crops with different water requirements blurs the signal the basis-risk analysis is trying to detect.
For Ahmedabad kharif, cotton or groundnut are the sensible choices.
Forty seasons is thin for tail estimation. The 99th percentile of the fitted distribution is being extrapolated well beyond the observed minimum, and any pricing conclusion about the extreme tail should be treated as indicative rather than firm. Longer records, or pooling across climatically similar districts, would tighten it materially.