Python 56.2%
TeX 43.7%
1"""LaTeX table generators for the Polymarket Arrow-Debreu paper."""23from __future__ import annotations45from pathlib import Path67import numpy as np8import pandas as pd910from src.config import TABLES111213def _save_table(content: str, name: str) -> str:14 TABLES.mkdir(parents=True, exist_ok=True)15 path = TABLES / f"{name}.tex"16 path.write_text(content)17 return content181920def _esc(s: str) -> str:21 """Escape LaTeX special characters in text."""22 return str(s).replace("$", r"\$").replace("_", r"\_").replace("&", r"\&").replace("%", r"\%").replace("#", r"\#")232425def _fmt(x: float, decimals: int = 3) -> str:26 if pd.isna(x):27 return ""28 return f"{x:.{decimals}f}"293031def _stars(p: float) -> str:32 if pd.isna(p):33 return ""34 if p < 0.01:35 return "^{***}"36 if p < 0.05:37 return "^{**}"38 if p < 0.10:39 return "^{*}"40 return ""414243def table_descriptive_stats(metadata: pd.DataFrame) -> str:44 """Table 1: Descriptive statistics of Polymarket contracts."""45 rows = []46 for _, row in metadata.iterrows():47 name = _esc(str(row.get("name", row.get("question", "")))[:40])48 vol = row.get("volume", 0)49 liq = row.get("liquidity", 0)50 n_obs = int(row.get("n_obs", 0))51 mean_p = row.get("mean_price", np.nan)52 std_p = row.get("std_price", np.nan)53 rows.append(54 f" {name} & {vol:,.0f} & {liq:,.0f} & {n_obs} & {_fmt(mean_p)} & {_fmt(std_p)} \\\\"55 )5657 body = "\n".join(rows)58 tex = rf"""\begin{{table}}[htbp]59\centering60\begin{{threeparttable}}61\caption{{Descriptive Statistics of Polymarket Contracts}}62\label{{tab:descriptive_stats}}63\begin{{tabular}}{{l S S c S S}}64\toprule65Market & {{Volume (\$)}} & {{Liquidity (\$)}} & Obs & {{Mean Price}} & {{Std Dev}} \\66\midrule67{body}68\bottomrule69\end{{tabular}}70\begin{{tablenotes}}71\small72\item \textit{{Notes:}} This table reports summary statistics for the Polymarket contracts analyzed.73Volume and liquidity are reported in US dollars. Mean price represents the average implied probability.74\end{{tablenotes}}75\end{{threeparttable}}76\end{{table}}"""77 return _save_table(tex, "table1_descriptive_stats")787980def table_summary_stats(prices: pd.DataFrame) -> str:81 """Table 2: Summary statistics of price series."""82 stats = []83 for col in prices.columns:84 s = prices[col].dropna()85 from scipy.stats import jarque_bera86 try:87 jb_stat, jb_p = jarque_bera(s)88 except Exception:89 jb_stat, jb_p = np.nan, np.nan90 stats.append({91 "Market": _esc(col[:30]),92 "Mean": s.mean(),93 "Std": s.std(),94 "Min": s.min(),95 "Max": s.max(),96 "Skew": s.skew(),97 "Kurt": s.kurtosis(),98 "JB": jb_stat,99 })100101 rows = []102 for st in stats:103 rows.append(104 f" {st['Market']} & {_fmt(st['Mean'])} & {_fmt(st['Std'])} & "105 f"{_fmt(st['Min'])} & {_fmt(st['Max'])} & {_fmt(st['Skew'],2)} & "106 f"{_fmt(st['Kurt'],2)} & {_fmt(st['JB'],1)} \\\\"107 )108109 body = "\n".join(rows)110 tex = rf"""\begin{{table}}[htbp]111\centering112\begin{{threeparttable}}113\caption{{Summary Statistics of Prediction Market Prices}}114\label{{tab:summary_stats}}115\begin{{tabular}}{{l S S S S S S S}}116\toprule117Market & {{Mean}} & {{Std}} & {{Min}} & {{Max}} & {{Skew}} & {{Kurt}} & {{JB}} \\118\midrule119{body}120\bottomrule121\end{{tabular}}122\begin{{tablenotes}}123\small124\item \textit{{Notes:}} JB is the Jarque--Bera test statistic for normality.125$^{{***}}$, $^{{**}}$, and $^{{*}}$ denote significance at the 1\%, 5\%, and 10\% levels.126\end{{tablenotes}}127\end{{threeparttable}}128\end{{table}}"""129 return _save_table(tex, "table2_summary_stats")130131132def table_completeness_test(test_result) -> str:133 """Table 3: Arrow-Debreu completeness test results."""134 tex = rf"""\begin{{table}}[htbp]135\centering136\begin{{threeparttable}}137\caption{{Arrow--Debreu Market Completeness Tests}}138\label{{tab:completeness}}139\begin{{tabular}}{{l S}}140\toprule141Statistic & {{Value}} \\142\midrule143 Mean state price sum & {_fmt(test_result.mean_sum, 4)} \\144 Std of state price sum & {_fmt(test_result.std_sum, 4)} \\145 Mean deviation from unity & {_fmt(test_result.mean_deviation, 4)} \\146 Max absolute deviation & {_fmt(test_result.max_deviation, 4)} \\147 All state prices positive & {{{'Yes' if test_result.all_positive else 'No'}}} \\148 Implied discount factor & {_fmt(test_result.discount_factor, 4)} \\149 Number of observations & {len(test_result.daily_sums)} \\150\bottomrule151\end{{tabular}}152\begin{{tablenotes}}153\small154\item \textit{{Notes:}} This table reports results from testing Arrow--Debreu market completeness155conditions using the Fed rate decision markets on Polymarket. Under complete markets,156the sum of state prices equals $1/(1+r_f)$. Mean deviation measures the average157departure from this theoretical prediction.158\end{{tablenotes}}159\end{{threeparttable}}160\end{{table}}"""161 return _save_table(tex, "table3_completeness")162163164def table_event_study(results: dict[str, object]) -> str:165 """Table 4: Event study cumulative abnormal returns."""166 rows = []167 for event_type, result in results.items():168 if hasattr(result, "test_stats") and not result.test_stats.empty:169 for _, row in result.test_stats.iterrows():170 window = row.get("window", "")171 market = _esc(str(row.get("market", "")))172 car = row.get("mean_CAR", np.nan)173 t = row.get("t_stat", np.nan)174 p = row.get("p_value", np.nan)175 stars = _stars(p)176 rows.append(177 f" {_esc(event_type)}: {market} & {window} & ${_fmt(car)}{stars}$ & "178 f"{_fmt(t, 2)} & {_fmt(p)} & {result.n_events} \\\\"179 )180181 body = "\n".join(rows) if rows else " \\multicolumn{6}{c}{No significant results} \\\\"182 tex = rf"""\begin{{table}}[htbp]183\centering184\begin{{threeparttable}}185\caption{{Event Study: Cumulative Abnormal Returns Around Macroeconomic Events}}186\label{{tab:event_study}}187\begin{{tabular}}{{l l c c c c}}188\toprule189Event Type & Window & {{CAR}} & {{$t$-stat}} & {{$p$-value}} & $N$ \\190\midrule191{body}192\bottomrule193\end{{tabular}}194\begin{{tablenotes}}195\small196\item \textit{{Notes:}} This table reports cumulative abnormal returns (CARs) for prediction market197prices around macroeconomic events. Abnormal returns are computed relative to a constant mean198model estimated over a 60-day estimation window. $t$-statistics are computed using the199cross-sectional standard deviation of CARs. $^{{***}}$, $^{{**}}$, $^{{*}}$ denote200significance at 1\%, 5\%, 10\%.201\end{{tablenotes}}202\end{{threeparttable}}203\end{{table}}"""204 return _save_table(tex, "table4_event_study")205206207def table_granger_causality(f_stats: pd.DataFrame, p_values: pd.DataFrame) -> str:208 """Table 5: Granger causality test results."""209 rows = []210 for caused in f_stats.index:211 for causing in f_stats.columns:212 if caused != causing:213 f_val = f_stats.loc[caused, causing]214 p_val = p_values.loc[caused, causing]215 stars = _stars(p_val)216 rows.append(217 f" {_esc(causing)} $\\to$ {_esc(caused)} & ${_fmt(f_val, 2)}{stars}$ & {_fmt(p_val)} \\\\"218 )219220 body = "\n".join(rows)221 tex = rf"""\begin{{table}}[htbp]222\centering223\begin{{threeparttable}}224\caption{{Granger Causality Tests}}225\label{{tab:granger}}226\begin{{tabular}}{{l c c}}227\toprule228Direction & {{$F$-stat}} & {{$p$-value}} \\229\midrule230{body}231\bottomrule232\end{{tabular}}233\begin{{tablenotes}}234\small235\item \textit{{Notes:}} This table reports $F$-statistics and $p$-values for pairwise Granger236causality tests. The null hypothesis is that the causing variable does not Granger-cause237the caused variable. Lag length selected by AIC. $^{{***}}$, $^{{**}}$, $^{{*}}$ denote238significance at 1\%, 5\%, 10\%.239\end{{tablenotes}}240\end{{threeparttable}}241\end{{table}}"""242 return _save_table(tex, "table5_granger")243244245def table_var_results(var_results: dict) -> str:246 """Table 6: VAR estimation results."""247 tex = rf"""\begin{{table}}[htbp]248\centering249\begin{{threeparttable}}250\caption{{Vector Autoregression Estimates}}251\label{{tab:var}}252\begin{{tabular}}{{l {'S ' * min(len(var_results.get('coefficients', {}).keys()), 4)}}}253\toprule254"""255 coefs = var_results.get("coefficients", {})256 if coefs:257 cols = list(coefs.keys())[:4]258 tex += " & ".join(["Variable"] + [f"{{{_esc(c)}}}" for c in cols]) + " \\\\\n\\midrule\n"259 first_col = coefs[cols[0]]260 if isinstance(first_col, pd.Series):261 for var_name in first_col.index[:15]:262 row_vals = [f"{_fmt(coefs[c].get(var_name, np.nan), 3)}" for c in cols]263 tex += f" {_esc(str(var_name))} & " + " & ".join(row_vals) + " \\\\\n"264 tex += rf"""\bottomrule265\end{{tabular}}266\begin{{tablenotes}}267\small268\item \textit{{Notes:}} VAR model estimates. Optimal lag length selected by AIC.269Standard errors in parentheses. $^{{***}}$, $^{{**}}$, $^{{*}}$ denote significance270at 1\%, 5\%, 10\%.271\end{{tablenotes}}272\end{{threeparttable}}273\end{{table}}"""274 return _save_table(tex, "table6_var")275276277def table_garch(garch_results: dict[str, object]) -> str:278 """Table 7: GARCH estimation results."""279 rows = []280 for name, result in garch_results.items():281 if hasattr(result, "params"):282 for param_name, value in result.params.items():283 se = result.std_errors.get(param_name, np.nan) if hasattr(result, "std_errors") else np.nan284 rows.append(f" {_esc(name)}: {_esc(str(param_name))} & {_fmt(value, 4)} & ({_fmt(se, 4)}) \\\\")285286 body = "\n".join(rows) if rows else " \\multicolumn{3}{c}{No results} \\\\"287 tex = rf"""\begin{{table}}[htbp]288\centering289\begin{{threeparttable}}290\caption{{GARCH Model Estimates}}291\label{{tab:garch}}292\begin{{tabular}}{{l S l}}293\toprule294Parameter & {{Estimate}} & (Std Err) \\295\midrule296{body}297\bottomrule298\end{{tabular}}299\begin{{tablenotes}}300\small301\item \textit{{Notes:}} GARCH(1,1) model estimates for prediction market return volatility.302$^{{***}}$, $^{{**}}$, $^{{*}}$ denote significance at 1\%, 5\%, 10\%.303\end{{tablenotes}}304\end{{threeparttable}}305\end{{table}}"""306 return _save_table(tex, "table7_garch")307308309def table_har_rv(har_result) -> str:310 """Table 8: HAR-RV estimation results."""311 rows = []312 if hasattr(har_result, "coefficients"):313 for name, val in har_result.coefficients.items():314 se = har_result.std_errors.get(name, np.nan) if hasattr(har_result, "std_errors") else np.nan315 t = har_result.t_stats.get(name, np.nan) if hasattr(har_result, "t_stats") else np.nan316 rows.append(f" {_esc(str(name))} & {_fmt(val, 4)} & ({_fmt(se, 4)}) & {_fmt(t, 2)} \\\\")317318 body = "\n".join(rows) if rows else " \\multicolumn{4}{c}{No results} \\\\"319 r2 = _fmt(har_result.r_squared, 3) if hasattr(har_result, "r_squared") else ""320 adj_r2 = _fmt(har_result.adj_r_squared, 3) if hasattr(har_result, "adj_r_squared") else ""321322 tex = rf"""\begin{{table}}[htbp]323\centering324\begin{{threeparttable}}325\caption{{HAR-RV Model Estimates}}326\label{{tab:har_rv}}327\begin{{tabular}}{{l S l S}}328\toprule329Variable & {{Coefficient}} & (Std Err) & {{$t$-stat}} \\330\midrule331{body}332\midrule333 $R^2$ & \multicolumn{{3}}{{c}}{{{r2}}} \\334 Adj.~$R^2$ & \multicolumn{{3}}{{c}}{{{adj_r2}}} \\335\bottomrule336\end{{tabular}}337\begin{{tablenotes}}338\small339\item \textit{{Notes:}} HAR-RV model following \citet{{corsi2009simple}}.340RV$_{{t+1}}^{{(d)}} = c + \beta_d RV_t^{{(d)}} + \beta_w RV_t^{{(w)}} + \beta_m RV_t^{{(m)}} + \varepsilon_{{t+1}}$.341Newey--West standard errors with 5 lags.342\end{{tablenotes}}343\end{{threeparttable}}344\end{{table}}"""345 return _save_table(tex, "table8_har_rv")346347348def table_liquidity(liquidity_stats: pd.DataFrame) -> str:349 """Table 9: Liquidity regression results."""350 rows = []351 for _, row in liquidity_stats.iterrows():352 var_name = _esc(str(row.get("variable", "")))353 coef = row.get("coefficient", np.nan)354 se = row.get("std_error", np.nan)355 t = row.get("t_stat", np.nan)356 p = row.get("p_value", np.nan)357 stars = _stars(p)358 rows.append(359 f" {var_name} & ${_fmt(coef, 4)}{stars}$ & ({_fmt(se, 4)}) & {_fmt(t, 2)} \\\\"360 )361362 body = "\n".join(rows) if rows else " \\multicolumn{4}{c}{No results} \\\\"363 tex = rf"""\begin{{table}}[htbp]364\centering365\begin{{threeparttable}}366\caption{{Liquidity Determinants}}367\label{{tab:liquidity}}368\begin{{tabular}}{{l S l S}}369\toprule370Variable & {{Coefficient}} & (Std Err) & {{$t$-stat}} \\371\midrule372{body}373\bottomrule374\end{{tabular}}375\begin{{tablenotes}}376\small377\item \textit{{Notes:}} OLS regression of bid--ask spread on volume, volatility, and event dummies.378Newey--West standard errors. $^{{***}}$, $^{{**}}$, $^{{*}}$ denote significance at 1\%, 5\%, 10\%.379\end{{tablenotes}}380\end{{threeparttable}}381\end{{table}}"""382 return _save_table(tex, "table9_liquidity")383