Cookbook
Numerics
Quantitative finance and scientific computing: options pricing, AAD, portfolio optimisation, SABR, fact tables, and statistics.
Run any example with:
etai cookbook/numerics/<file>.eta
Computationally intensive programs can be compiled first:
etac -O cookbook/numerics/<file>.eta
etai <file>.etac
European Option Greeks (AAD)
cookbook/numerics/european.eta · source
Black-Scholes option Greeks (Delta, Vega, Theta, Rho) and second-order Greeks
(Gamma, Vanna, Volga) using Eta’s built-in tape-based reverse-mode AD.
The VM records arithmetic onto a flat tape when a TapeRef operand is present;
a single backward pass sweeps the tape to accumulate all first-order adjoints.
(module european
(import std.core std.io std.aad)
(begin
;; Primal extraction helper for branch decisions
(defun branch-primal (x)
(if (tape-ref? x) (tape-ref-value x) x))
;; Normal PDF: phi(x) = (1/sqrt(2*pi)) * exp(-x^2/2)
(define inv-sqrt-2pi 0.3989422804014327)
(defun norm-pdf (x)
(* inv-sqrt-2pi (exp (* -0.5 (* x x)))))
;; Normal CDF (rational approximation)
(defun norm-cdf (x)
(let* ((px (branch-primal x))
(neg? (< px 0.0))
(ax (if neg? (- 0.0 x) x))
(t (/ 1.0 (+ 1.0 (* 0.2316419 ax))))
(poly (+ (* t (+ 0.319381530
(* t (+ -0.356563782
(* t (+ 1.781477937
(* t (+ -1.821255978
(* t 1.330274429))))))))))
(cdf (* (- 1.0 (* (norm-pdf ax) poly)))))
(if neg? (- 1.0 cdf) cdf)))
;; Black-Scholes call price
(defun bs-call (s k r q t vol)
(let* ((sqrt-t (sqrt t))
(d1 (/ (+ (log (/ s k))
(* t (+ (- r q) (* 0.5 vol vol))))
(* vol sqrt-t)))
(d2 (- d1 (* vol sqrt-t)))
(nd1 (norm-cdf d1))
(nd2 (norm-cdf d2)))
(- (* s (exp (* (- q) t)) nd1)
(* k (exp (* (- r) t)) nd2))))
;; Compute first-order Greeks via reverse-mode AD
;; Inputs: S=100 K=100 r=0.05 q=0.02 T=1.0 vol=0.20
(let* ((tape (aad:new-tape))
(s (aad:var tape 100.0))
(k (aad:var tape 100.0))
(r (aad:var tape 0.05))
(q (aad:var tape 0.02))
(T (aad:var tape 1.0))
(vol (aad:var tape 0.20))
(pv (bs-call s k r q T vol)))
(aad:backward tape pv)
(println (string-append "Price = " (number->string (tape-ref-value pv))))
(println (string-append "Delta = " (number->string (aad:grad s))))
(println (string-append "Vega = " (number->string (aad:grad vol))))
(println (string-append "Theta = " (number->string (aad:grad T))))
(println (string-append "Rho = " (number->string (aad:grad r)))))
))
AAD — Tape-Based Reverse-Mode AD
cookbook/numerics/aad.eta · source
Low-level demonstration of Eta’s automatic adjoint differentiation (AAD) tape. Shows tape construction, forward evaluation, backward sweep, and gradient extraction for elementary and composed functions.
(module aad-demo
(import std.core std.io std.aad)
(begin
;; f(x, y) = x^2 + 3*y
;; df/dx = 2x, df/dy = 3
(let* ((tape (aad:new-tape))
(x (aad:var tape 4.0))
(y (aad:var tape 2.0))
(f (+ (* x x) (* 3.0 y))))
(aad:backward tape f)
(println (aad:grad x)) ; => 8.0 (2*4)
(println (aad:grad y))) ; => 3.0
;; g(x) = sin(x) * exp(x)
;; dg/dx = cos(x)*exp(x) + sin(x)*exp(x)
(let* ((tape (aad:new-tape))
(x (aad:var tape 1.0))
(g (* (sin x) (exp x))))
(aad:backward tape g)
(display "dg/dx at x=1: ")
(println (aad:grad x)))
;; => cos(1)*exp(1) + sin(1)*exp(1) ~= 3.756
))
SABR Model
cookbook/numerics/sabr.eta · source
SABR stochastic volatility model: Hagan approximation for implied volatility, calibration via gradient descent using AAD, and volatility smile generation.
(module sabr
(import std.core std.io std.math std.aad)
(begin
;; Hagan et al. SABR implied-vol approximation
;; Parameters: F (forward), K (strike), T (expiry),
;; alpha (vol-of-forward), beta, rho, nu (vol-of-vol)
(defun sabr-vol (F K T alpha beta rho nu)
(let* ((FK (sqrt (* F K)))
(logFK (log (/ F K)))
(z (* (/ nu alpha) (expt FK (- 1.0 beta)) logFK))
(chi (log (/ (+ (sqrt (- 1.0 (* 2.0 rho z) (* z z))) z (- rho))
(- 1.0 rho))))
(A (/ alpha (expt FK (- 1.0 beta))))
(B1 (+ 1.0 (/ (* (- 1.0 beta) (- 1.0 beta) logFK logFK) 24.0)
(/ (* (- 1.0 beta) (- 1.0 beta) logFK logFK logFK logFK) 1920.0)))
(B2 (+ 1.0
(* T (+ (/ (* (- 1.0 beta) (- 1.0 beta) alpha alpha)
(* 24.0 (expt FK (* 2.0 (- 1.0 beta)))))
(/ (* rho beta nu alpha)
(* 4.0 (expt FK (- 1.0 beta))))
(/ (* nu nu (- 2.0 (* 3.0 rho rho)))
24.0))))))
(* A (/ z chi) (/ 1.0 B1) B2)))
;; Print a volatility smile
(define F 100.0) (define T 1.0)
(define alpha 0.20) (define beta 0.5)
(define rho -0.3) (define nu 0.4)
(for-each
(lambda (K)
(display "K=") (display K) (display " vol=")
(println (sabr-vol F K T alpha beta rho nu)))
'(80.0 90.0 95.0 100.0 105.0 110.0 120.0))
))
Portfolio LP
cookbook/numerics/portfolio-lp.eta · source
Mean-variance portfolio optimisation solved as a linear programme using
std.clpr (CLP over reals). Maximise expected return subject to a
volatility budget and long-only constraints.
(module portfolio-lp
(import std.core std.io std.collections std.clpr)
(begin
;; Assets: expected returns and pairwise covariance matrix
(define expected-returns '(0.12 0.08 0.15 0.06))
(define cov-matrix
'((0.04 0.01 0.02 0.00)
(0.01 0.02 0.01 0.00)
(0.02 0.01 0.06 0.01)
(0.00 0.00 0.01 0.01)))
;; Variables: weights w1..w4
(define ws (map (lambda (_) (clpr:var)) expected-returns))
;; Constraint: weights sum to 1
(clpr:= (apply + ws) 1.0)
;; Long-only: each weight >= 0
(for-each (lambda (w) (clpr:>= w 0.0)) ws)
;; Volatility budget: portfolio variance <= 0.025
(clpr:<= (apply +
(map (lambda (wi row)
(apply + (map (lambda (wj cij) (* wi wj cij))
ws row)))
ws cov-matrix))
0.025)
;; Maximise expected return
(define obj (apply + (map * ws expected-returns)))
(clpr:maximize obj)
;; Print solution
(for-each
(lambda (w i)
(display (string-append "w" (number->string i) " = "))
(println (clpr:value w)))
ws '(1 2 3 4))
))
Causal Portfolio Engine
cookbook/numerics/portfolio.eta · source
An end-to-end institutional portfolio construction system that combines symbolic specification, causal inference (do-calculus), CLP(Z/R) constraints, neural return estimation (libtorch), and AAD — all in a single Eta program.
;; Abbreviated overview — see the full source for details.
(module portfolio
(import std.io std.core std.math std.collections
std.fact_table std.causal std.causal.identify
std.logic std.clp std.clpr
(except std.torch grad) std.stats)
(begin
;; 1. Define the causal DAG
;; sentiment -> macro -> return
;; sentiment -> return
;; beta, sector, rate -> return
(define dag
(causal:dag
'((sentiment macro) (sentiment return)
(macro return) (beta return)
(sector return) (rate return))))
;; 2. Identify back-door adjustment formula for P(return|do(beta))
(define adjustment-sets
(causal:backdoor-sets dag 'beta 'return))
;; 3. Generate synthetic data, train a neural net to estimate
;; E[return | beta, macro, sector], then compute ATE via
;; the adjustment formula.
;; 4. Solve portfolio optimisation with CLP(R) constraints
;; (volatility budget, sector limits, long-only).
...
))
See
docs/featured/portfoliofor the full walkthrough with outputs.
Fact Tables
cookbook/numerics/fact-table.eta · source
In-memory columnar fact tables for aggregation and analytics, similar to a stripped-down OLAP engine. Supports group-by, filter, sum, mean, and join.
(module fact-table-demo
(import std.io std.fact_table)
(begin
;; Build a fact table from a list of records
(define ft
(fact-table:from-records
'(sector beta return)
'((tech 1.2 0.15)
(tech 0.9 0.08)
(fin 1.4 0.12)
(fin 1.1 0.09)
(util 0.6 0.04)
(util 0.7 0.05))))
;; Mean return by sector
(define by-sector
(fact-table:group-by ft 'sector
(list (cons 'mean-return (fact-table:mean 'return)))))
(fact-table:print by-sector)
;; sector | mean-return
;; tech | 0.115
;; fin | 0.105
;; util | 0.045
))
Statistics
cookbook/numerics/stats.eta · source
Descriptive statistics, sampling distributions, and hypothesis testing
via std.stats.
(module stats-demo
(import std.io std.stats)
(begin
(define xs '(2.1 3.4 2.8 4.1 3.7 2.2 3.9 4.5 2.6 3.1))
(println (stats:mean xs)) ; => 3.24
(println (stats:stddev xs)) ; sample std dev
(println (stats:median xs))
(println (stats:iqr xs)) ; interquartile range
;; Normal distribution helpers
(println (stats:norm-pdf 0.0)) ; => 0.3989...
(println (stats:norm-cdf 1.96)) ; => 0.9750...
;; One-sample t-test (H0: mu = 3.0)
(define result (stats:t-test xs 3.0))
(println (cons 't-stat (cdr (assoc 't-stat result))))
(println (cons 'p-value (cdr (assoc 'p-value result))))
))