Skip to content

Latest commit

 

History

78 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

bbq

BQN Based Quant.

CI License: MIT Ask DeepWiki

v2.0


Overview

bbq is a quantitative finance toolkit in BQN. 11 modules: indicators, signal composition, backtesting, walk-forward validation, options pricing, Monte Carlo simulation, rolling analytics, risk management, execution realism, anti-overfitting diagnostics, and multi-asset universe management.

BQN 101

Micro syntax primer so you can read bbq code:

x ← 5                    # define
x ↩ 6                    # reassign
3‿1‿4                    # array (flat)
⟨3, 1‿4⟩                 # nested array
F ← {𝕩+1}               # function (𝕩 = right arg, 𝕨 = left arg)
+´ 1‿2‿3                 # fold: 6
F¨ 1‿2‿3                 # each: apply F to every element
F˘ mat                   # row-wise: apply F to each row
(F G H) x               # train: (F x) G (H x)

Evaluation is right-to-left: 2×3+1 = 2×(3+1) = 8.

Full tutorial: mlochbaum.github.io/BQN/tutorial

Requirements

Quick Start

Drop a CSV with Date,Open,High,Low,Close,Volume columns into data/, then:

make run name=ma_cross

Output:

═══ MA Cross (10/50) ═══
Total:          +42.2%      (B&H: +74.2%)
CAGR:           +7.6%       (B&H: +12.3%)
Sharpe:         0.66        (B&H: 0.76)
...
───
Verdict: Has potential, needs work

Data Sources

bbq works with any CSV containing Date,Open,High,Low,Close,Volume columns.

Stooq — free CSV, no API key:

curl -o data/SPY.csv "https://stooq.com/q/d/l/?s=spy.us&i=d"

Yahoo Finance — requires Python 3 + pip install yfinance:

import yfinance as yf
yf.download("SPY", period="5y").to_csv("data/SPY.csv")

Alpha Vantage — free API key:

curl -o data/SPY.csv "https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=SPY&outputsize=full&apikey=YOUR_KEY&datatype=csv"

Or export from your broker.

Makefile

make new name=X        Create strategy from template
make run name=X        Run a strategy
make test              Run test suite (134 tests)
make clean             Remove data files

Usage

Writing a Strategy

Every strategy is a BQN script that imports the engine, loads data, computes indicators, generates positions, and prints a report. Positions are arrays of 1 (long), 0 (flat), and ¯1 (short). The engine multiplies positions by returns.

bt•Import "../engine/bt.bqn"
databt.Validate bt.Load "../data/spy.csv"
cdata.close
fast10 bt.MA c
slow50 bt.MA c
pos ← (slow)fast > slow

Stateful pattern with _Sim (bar-by-bar state threading):

Step ← {
  pospeak𝕨
  pricelower𝕩
  npos ← {pos=0 ? price<lower ; pos}
  ⟨npos, npospeak, peakprice⟩⟩
}
posStep bt._Sim0,0⟩‿obs

Walk-Forward Validation

wf•Import "../engine/wf.bqn"
datawf.Validate wf.Load "../data/spy.csv"
pricesdata.close

MACross ← {
  fastslow𝕨
  fswf.Align (fast wf.MA 𝕩)‿(slow wf.MA 𝕩)
  f > s
}

gridwf.Grid81012, 405060resultsprices MACross wf._WF500, 100, grid, 0.001, wf.Sharpe"MA Cross"500100‿(grid) wf.WFReport results

Composed Strategies

Normalize features, compute weighted score, threshold into positions:

bt•Import "../engine/bt.bqn"
cmp•Import "../engine/cmp.bqn"
databt.Validate bt.Load "../data/spy.csv"
cdata.close

f1 ← ((-≠sma)c) - sma50 bt.MA c   # SMA distance
f214 bt.RSI c                       # RSI
uppermidlower202 bt.BB c
f3 ← (cb-lower)÷(upper-lower)+1e¯10    # BB position (cb←(-≠upper)↑c)

# ENorm: expanding-window z-score (no lookahead)
pos0.5 cmp.Thresh 0.40.30.3 cmp.Score cmp.ENorm¨ f1f2f3

Portfolio Backtesting

weights0.50.30.2
port_retweights bt.PortRun ⟨⟨pos_spy, ret_spy⟩, ⟨pos_qqq, ret_qqq⟩, ⟨pos_gld, ret_gld⟩⟩
port_eqbt.PortEquity port_ret

Options Pricing

opt•Import "../engine/opt.bqn"
# Black-Scholes: S=42, K=40, T=0.5, r=0.1, σ=0.2, call
opt.BS 42400.50.10.21     # ≈ 4.76
opt.Delta 42400.50.10.21  # ≈ 0.81
opt.IV 4.7642400.50.11    # ≈ 0.20 (round-trip)

Monte Carlo Simulation

mc•Import "../engine/mc.bqn"
pathsmc.Paths 100001000.050.21252   # 10k GBM paths
price100mc.EuroCall mc._Price paths0.051
# Antithetic variance reduction
apathsmc.Paths mc._Antithetic 50001000.050.21252
# Fat tails: Student's t innovations (ν=5)
tpathsmc.TPaths 100001000.050.212525

Risk Management

risk•Import "../engine/risk.bqn"
scaled0.15 risk.VolTarget sigret            # target 15% annualized vol
kelly200.5 risk.KellySeries sigret         # half-Kelly, 20-bar lookback
safe3‿(¯0.10) risk.CircuitBreaker posret    # pause after 3-bar loss > 10%

Anti-Overfitting

ovf•Import "../engine/ovf.bqn"
ovf.DSR 100 srskewkurtT     # Deflated Sharpe (100 trials)
ovf.PBO wf_result               # Probability of Backtest Overfitting
ovf.HHI ret                     # Return concentration

Execution Realism

exec•Import "../engine/exec.bqn"
slip0.10.1 exec.Slippage posvol            # Almgren-Chriss impact
capped0.01 exec.FillLimit posvol             # volume-based fill cap
r0.02 exec.StopLoss posdata                  # 2% stop-loss
r0.050.10 exec.StopTake posdata             # 5% stop, 10% take-profit

Universe Management

uni•Import "../engine/uni.bqn"
datasetsbt.LoadMany "../data/spy.csv""../data/qqq.csv""../data/gld.csv"
uuni.Universe datasets
scoresuni.XScore signal_mat     # cross-sectional z-score
weights2 uni.TopN scores        # long top-2, short bottom-2

API Reference

Data Contract

Load returns a namespace: {dates⇐, close⇐, high⇐, low⇐, open⇐, vol⇐}. All numeric arrays are flat floats, same length. Any data source that returns this shape works with bbq.

Name Signature Description
Load Load path Parse a CSV into the data namespace
Validate Validate data Enforce finiteness & OHLC relations (0 Validate = futures mode)
LoadMany LoadMany paths Load several CSVs, tail-aligned to the shortest
Align Align arrays Tail-align a list of arrays to the shortest
AlignDates AlignDates datasets Tail-align a list of data namespaces

Also exported for reuse: the constants eps (1e¯10) and tdy (252), and the helpers Split (CSV tokenizer), Wilder (smoothing), and Pstd (population std).

Indicators

All dyadic: n Indicator prices unless noted. Output is shorter than input by the warmup period. EMA returns same length.

Name Signature Description
MA n MA prices Simple moving average (O(n) prefix-sum)
EMA n EMA prices Exponential moving average
WMA n WMA prices Weighted moving average
Std n Std prices Rolling population std
RSI n RSI prices Relative Strength Index (0-100)
MACD fast‿slow‿sig MACD prices Returns macd‿signal‿histogram
ATR n ATR data Average True Range (takes namespace)
Mom n Mom prices Momentum
ROC n ROC prices Rate of Change (%)
Stoch n Stoch data Stochastic %K/%D (takes namespace)
BB n‿k BB prices Bollinger Bands: upper‿mid‿lower
OBV OBV close‿vol On-Balance Volume (monadic)
VWAP VWAP data Volume-Weighted Avg Price (monadic)
AD AD data Accumulation/Distribution (monadic)
RMax n RMax prices Rolling maximum
RMin n RMin prices Rolling minimum

Signal Utilities

Name Signature Description
Cross fast Cross slow 1 where fast crosses above slow
CrossDown fast CrossDown slow 1 where fast crosses below slow
Mask n Mask arr Zero first n elements
Fill Fill signals Forward-fill: hold last non-zero
Thresh level Thresh values 1 where value crosses above level
ThreshDown level ThreshDown values 1 where value crosses below level
Hold n Hold positions Min n-bar holding period

Composition

Signal-fusion layer (cmp.bqn). Normalize features, blend into a score, map to positions. Note cmp.Thresh differs from the Thresh above: it maps scores to 1/0/¯1 rather than emitting crossing signals.

Name Signature Description
Norm Norm arr Z-score, full-array (per-fold use)
ENorm ENorm arr Expanding-window z-score (no lookahead)
Score weights Score features Weighted sum with auto-alignment
Thresh level Thresh scores Map score to position 1/0/¯1
Compose weights‿level Compose features Norm → Score → Thresh (full-array; lookahead)

Backtest

The core fold: lag positions one bar, multiply by returns, subtract costs.

Name Signature Description
Ret Ret prices Simple returns (1 shorter than input)
LogRet LogRet prices Log returns (1 shorter than input)
Run pos Run ret Strategy returns (pos × ret)
RunOHLC pos RunOHLC data Open-to-open execution returns
Cost rate Cost pos Per-bar transaction-cost array
Equity Equity ret Equity curve from returns (starts at 1)
_Sim Step _Sim init‿obs Thread bar-by-bar state into a position array
Report name‿pos Report strat‿bh Print a strategy-vs-benchmark summary

Reporting helpers (also exported): Pct (signed percent), Rd (2-dp round), Pad (right-pad to width).

Metrics

All take returns, return a number. Trades/TimeIn/Exposure take positions.

Name What it tells you
Sharpe Risk-adjusted return (annualized, Rf=0)
Sortino Like Sharpe, penalizes downside only
Calmar CAGR relative to worst drawdown
MaxDD Worst peak-to-trough loss (negative)
MaxDDDur Longest drawdown in bars
TotalRet Cumulative return as decimal
CAGR Compound annual growth rate
AnnVol Annualized volatility
WinRate Fraction of positive-return days
ProfitFactor Gross profit / gross loss
AvgWin / AvgLoss Mean winning / losing return
Expectancy Expected value per trade
Trades Position change count
TimeIn / Exposure Fraction of time in market
Skew / Kurt Distribution shape

Portfolio

Name Signature Description
PortRun weights PortRun assets Weighted multi-asset returns
PortCost rates PortCost positions Combined transaction costs
PortEquity PortEquity ret Equity curve (alias)
PortReport name‿cpos PortReport assets‿cret Per-asset + combined report

Walk-Forward

Name Signature Description
Windows train‿test Windows prices Rolling train/test splits
Grid Grid ranges Cartesian product of param ranges
_WF prices Strategy _WF config Walk-forward orchestrator
WFReport name‿tr‿te‿gs WFReport results Print WF summary

Options Pricing

Name Signature Description
BS BS S‿K‿T‿r‿σ‿type Black-Scholes price (1=call, ¯1=put)
Delta / Gamma / Theta / Vega / Rho Same args Greeks
IV IV target‿S‿K‿T‿r‿type Implied volatility (Newton-Raphson)
Parity Parity S‿K‿T‿r Put-call parity forward
Npdf / Phi / PhiInv Monadic Normal distribution functions
Tpdf / Tcdf ν Tpdf x Student's t PDF / CDF
TcdfInv ν TcdfInv p Inverse Student's t CDF (Newton-Raphson)

Monte Carlo

Name Signature Description
Paths Paths n‿S₀‿μ‿σ‿T‿steps GBM price paths [n, steps]
TPaths TPaths n‿S₀‿μ‿σ‿T‿steps‿ν Fat-tailed GBM paths (Student's t)
RandT ν RandT n n Student's t samples
_Price Payoff _Price paths‿r‿T Discounted expected payoff
_Antithetic Paths _Antithetic config Antithetic variance reduction
EuroCall / EuroPut k F path European payoffs
AsianCall k AsianCall path Arithmetic average call
BarrierUpOut k‿barrier BarrierUpOut path Up-and-out barrier call

Rolling Analytics

Name Signature Description
RSharpe n RSharpe ret Rolling annualized Sharpe
RVol n RVol ret Rolling annualized vol
RMaxDD n RMaxDD ret Rolling max drawdown
RBeta n‿bench RBeta ret Rolling beta vs benchmark
Alpha bench‿rf Alpha ret Jensen's alpha
IR bench IR ret Information ratio
Drawdowns Drawdowns ret Episode namespace {start,end,depth,dur}
UpsideCapture / DownsideCapture bench F ret Capture ratios

Risk Management

Name Signature Description
VolTarget target VolTarget sig‿ret Vol-scaled position sizing
KellyFrac frac KellyFrac ret Fractional Kelly (clipped ±1)
KellySeries n‿frac KellySeries sig‿ret Rolling Kelly positions
MaxPos cap MaxPos pos Clip magnitude, preserve sign
CircuitBreaker n‿thresh CircuitBreaker pos‿ret Pause on cumulative loss
DDControl thresh DDControl pos‿ret Pause on drawdown
Scale arr Scale pos Element-wise position scaling

Anti-Overfitting

Name Signature Description
DSR n DSR SR‿sk‿ku‿T Deflated Sharpe Ratio
PSR bench PSR SR‿T‿n‿sk‿ku Probabilistic Sharpe Ratio
MinTRL n‿SR MinTRL sk‿ku Minimum track record length
PBO PBO wf_result Probability of backtest overfitting
HHI HHI ret Return concentration (Herfindahl)
TrialCorrect n‿alpha TrialCorrect pvals BH multiple-test correction

Execution Realism

Name Signature Description
Slippage impact‿decay Slippage pos‿vol Almgren-Chriss market impact
FillLimit pct FillLimit pos‿vol Volume-based fill cap
StopLoss pct StopLoss pos‿data Intrabar stop-loss
TakeProfit pct TakeProfit pos‿data Intrabar take-profit
StopTake stop‿tp StopTake pos‿data Combined (stop wins on tie)

Universe Management

Name Signature Description
Universe Universe namespaces Stack aligned OHLCV into matrices
XRank XRank mat Cross-sectional rank per row
XScore XScore mat Cross-sectional z-score per row
XWeight XWeight mat L1-normalize row weights
LongOnly LongOnly mat Zero negatives, renormalize
TopN n TopN scores Long top-N, short bottom-N
_UniRun Strategy _UniRun universe Apply strategy per asset
UniReport name UniReport weights‿uni Per-asset + combined report

Why BQN

  • Dense, array-oriented — natural fit for time series and matrix operations
  • Concise — entire indicator suite in ~25 lines vs 160+ in Python (benchmarks)
  • Stable spec — no breaking changes
  • Fast — CBQN compiles to native, competitive with numpy at scale
  • Readable once learned — trains and combinators compose cleanly

More at mlochbaum.github.io/BQN.

Benchmarks

CBQN vs Python (pandas/numpy) vs Julia on synthetic GBM data. Median of 10 runs, 3 warmup.

Indicators (MA, EMA, RSI, ATR, BB, Stoch, OBV, VWAP)

Rows BQN pandas numpy Julia
1,000 5ms 211ms 211ms 1,087ms
10,000 15ms 213ms 219ms 1,088ms
100,000 124ms 275ms 345ms 1,180ms
1,000,000 1,453ms 855ms 1,556ms 1,774ms

Signals (Cross, Fill, Hold, Thresh)

Rows BQN pandas numpy Julia
1,000 5ms 214ms 211ms 760ms
10,000 16ms 239ms 248ms 803ms
100,000 128ms 321ms 332ms 876ms
1,000,000 1,451ms 1,362ms 1,383ms 1,410ms

Full Pipeline (indicators → signals → backtest → metrics)

Rows BQN pandas numpy Julia
1,000 5ms 213ms 213ms 676ms
10,000 15ms 233ms 226ms 708ms
100,000 117ms 289ms 295ms 802ms
1,000,000 1,385ms 954ms 952ms 1,162ms

Walk-Forward Grid Search (20 param combos, 504/126 train/test)

Rows BQN Python Julia
10,000 26ms 254ms 997ms
100,000 225ms 639ms 1,110ms

Code Size

Benchmark BQN Python Julia
indicators 25 162 (6.5x) 161 (6.4x)
signals 26 132 (5.1x) 118 (4.5x)
pipeline 26 129 (5.0x) 90 (3.5x)
loading 6 49 (8.2x) 48 (8.0x)

Benchmark source on the bench branch.

Architecture

engine/
├── core.bqn    # Shared: data loading, indicators, signal utilities
├── bt.bqn      # Backtesting: simulation, PnL, metrics, portfolio, reporting
├── wf.bqn      # Walk-forward: windowing, grid search, OOS aggregation
├── cmp.bqn     # Composition: normalization, scoring, thresholding
├── opt.bqn     # Options pricing: Black-Scholes, Greeks, IV
├── mc.bqn      # Monte Carlo: GBM paths, pricing, payoffs, antithetic variates
├── roll.bqn    # Rolling analytics: RSharpe, RVol, drawdowns, capture ratios
├── risk.bqn    # Position sizing & risk controls: Kelly, vol target, circuit breaker
├── ovf.bqn     # Anti-overfitting: DSR, PSR, PBO, HHI, trial correction
├── exec.bqn    # Execution realism: slippage, fill limits, stop/take-profit
└── uni.bqn     # Universe management: cross-sectional ops, ranking, multi-asset

Dependency chain: core.bqn ← bt.bqn ← wf.bqn. Each layer re-exports the one below it. Strategies import bt.bqn, walk-forward scripts import wf.bqn.

Leaf modules (opt.bqn, mc.bqn, roll.bqn, risk.bqn, ovf.bqn, exec.bqn, uni.bqn) import bt.bqn or core.bqn directly.

Design

A backtest is a fold. Indicators are array operations. Positions are arrays of 1, 0, and ¯1. The engine multiplies positions by returns.

The architecture has two phases: indicators (pure array ops, SIMD-friendly) and execution (compound-state scan, inherently sequential). Five primitive patterns implement all indicators: windowed reduction, scan accumulation, shifted arrays, element-wise arithmetic, and compound scan.

_Sim exists for strategies that need bar-by-bar state (trailing stops, regime filters, Kalman filters). It generates position arrays that feed into the same Run pipeline.

Walk-forward validation splits history into rolling train/test windows, optimizes parameters on train, evaluates on test, and stitches out-of-sample segments. The OOS equity curve is the real result.

Acknowledgements

License

MIT.

About

BQN Based Quant. An "APL for your flying saucer" quantitative finance toolkit.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages