Documentation

Command reference, language syntax, and practical recipes for econometric work.

Language basics

Hayashi uses a Stata-like command grammar with modern expression support. Statements are separated by newlines or semicolons. Results are printed unless suppressed with a trailing semicolon.

basics.hay
// Load data
load "wage1.csv" as df

// Variables and assignment
let x = 10
let y = x + 5

// Conditional
if y > 10 {
  print("large")
}

// Loop
for i in 1..5 {
  print(i)
}

Data I/O

Hayashi reads and writes several tabular formats. ODBC is available as an optional feature.

CommandDescription
load "file.csv" as dfLoad CSV/TSV
load "file.json" as dfLoad JSON array
load "file.dta" as dfLoad Stata .dta
load "file.xlsx" as dfLoad Excel sheet
load "file.parquet" as dfLoad Parquet
load "sqlite://path.db" as dfSQL query to DataFrame
save df, "csv", "out.csv"Save DataFrame

Block expressions & output control

A block can be used as an expression: it runs statements and returns the last expression. Variables declared inside are local to the block.

blocks.hay
let df = {
  let raw = load("data.csv")
  generate raw y = log(x)
  keep(raw, ["date", "y"])
  raw
}

quietly on
let m = merge(df2, df3, key=id, type=inner)
quietly off

print("done")

quietly on suppresses automatic output from statements and estimators. print(...) and display ... still appear. The flag is scope-aware: toggling inside a block reverts when the block ends.

Data & I/O utilities

Common helpers for missing values, file-system checks, and simple caching.

CommandDescription
dropna(df, col1, col2)Remove rows with NaN
ffill(df)Forward-fill NaN in float columns
file_exists("path")Check if path exists
ensure_dir("cache")Create directory if missing
write("text", "file.txt")Write string to file
export(df, "csv", "out.csv")Save DataFrame

Estimators

All estimators share a common formula syntax and return a model object with post-estimation methods.

CommandFamily
ols(y ~ x1 + x2, df)Ordinary least squares
iv(y ~ x1 + x2, ~ z1 + z2, df)Instrumental variables / 2SLS
logit(y ~ x1 + x2, df)Binary logistic regression
probit(y ~ x1 + x2, df)Binary probit regression
poisson(y ~ x1 + x2, df)Poisson regression
nbreg(y ~ x1 + x2, df)Negative binomial
tobit(y ~ x1 + x2, df)Censored regression
qreg(y ~ x1 + x2, df, tau=0.5)Quantile regression
fe(y ~ x1 + x2 | id, df)Panel fixed effects
re(y ~ x1 + x2 | id, df)Panel random effects
ab(y ~ x1 + x2 | id + year, df)Arellano-Bond dynamic panel
heckman(y ~ x1 + x2, s ~ z1 + z2, df)Heckman two-step
garch(y ~ 1, df, p=1, q=1)GARCH volatility
var(df, lags=2)Vector autoregression
vecm(df, lags=2, rank=1)Vector error correction
did(y ~ treat + post, df)Difference-in-differences
gmm(y ~ x1, df, instruments=z1)Generalized method of moments
rolling(y ~ x1 + x2, df, window=30)Rolling OLS with optional date=date_col

Post-estimation

After fitting a model, use these verbs for inference, prediction, and diagnostics.

CommandDescription
test(model, "x1 = 0")Wald test
predict(model, df)Generate predictions
margins(model, dydx(x1))Marginal effects
bootstrap(model, reps=1000)Bootstrap inference
estat(model, "vif")Diagnostic statistics
nlcom(model, "x1/x2")Nonlinear combination
esttab(model)Regression table output
tidy(model)Convert model to a tidy DataFrame of coefficients
glance(model)Convert model to a one-row summary DataFrame

Modern syntax

Hayashi adds modern conveniences to the Stata-like grammar without breaking the REPL workflow.

modern.hay
// Pipes
let df2 = df |> filter(educ > 12) |> mutate(lwage = log(wage))

// F-strings
print("R² = {model.r2}")

// Match expression
let sign = match coef > 0 { true => "+", false => "-" }

// Functions
fn my_mean(x) {
  return sum(x) / len(x)
}

Recipe: rolling CAPM

A complete daily CAPM pipeline with rolling betas.

capm.hay
import("sheep-farm/hayahoo", as=yahoo)

let asset = yahoo::history("AAPL", {"range": "50y", "interval": "1d"})
generate asset asset_ret = log(close / L.close)
asset |> keep(["date", "asset_ret"])

let market = yahoo::history("SPY", {"range": "50y", "interval": "1d"})
generate market market_ret = log(close / L.close)
market |> keep(["date", "market_ret"])

let merged = merge(asset, market, key=date, type=inner)

let with_rf = merged
generate with_rf excess_asset = asset_ret
generate with_rf excess_market = market_ret
let df = dropna(with_rf, excess_asset, excess_market)

let model = df |> ols(excess_asset ~ excess_market, _)
print(model)

let roll = rolling(excess_asset ~ excess_market, df, window=252, date=date)
let betas = tidy(roll)
let coefs = betas["excess_market"]

print("mean =", mean(coefs))
print("sd   =", sd(coefs))
print("min  =", min(coefs))
print("max  =", max(coefs))

CLI commands

CommandDescription
hay script.hayRun a script
hayStart REPL
hay install user/repoInstall plugin
hay update [user/repo]Update plugin(s)
hay remove user/repoRemove plugin
hay listList installed plugins
hay validateRun empirical validation suite
hay dist-updateUpdate Hayashi binary to latest release