Jay Butera

Senior software engineer. I write about a few projects I've built — a trading frontend, a reinforcement-learning environment, and a consensus algorithm rewritten for cache locality.

Open Hype

Keyboard-driven alt frontend for Hyperliquid with risk-first orders, ICT killzones, and a paper options trader.

github.com/jaybutera/open-hype · React, TypeScript, Vite, Zustand, Lightweight Charts

I built Open Hype because the official Hyperliquid interface is too simple for the way I actually trade. It's fine if you're clicking buy and sell, but the moment you want to do real chart work — fib retracements, mapping out structure, watching how price reacts inside the London or NY killzone — you're eyeballing and tabbing between tools. I wanted one screen.

The first thing I added was automatic ICT killzone visualization. Asia, London, NY — they highlight on the chart on their own, DST-aware, so I'm not redrawing sessions every day. Then fib retracements. Hyperliquid not having them out of the box is one of those small frictions you don't notice until it's gone.

The order panel is risk-first. On the official UI, if I want a setup with a defined dollar risk, I'm reversing out the position size by hand — stop distance, leverage, fees. Open Hype flips that. I type a risk amount, shift+click to draw the long or short box on the chart, and size, leverage, TP, and SL fall out of the geometry. Reward is whatever ratio the box gives. It changed how I trade — fewer impulsive entries, because the stop has to exist before the order does.

Open Hype main interface
The main interface — chart, killzones, risk-first order panel.

Paper trading was the original reason I started. Other DEXes offer real-time data, but none with the asset coverage or liquidity of Hyperliquid, and I wanted somewhere to test setups without putting money on the line. The paper engine simulates HL's fee schedule accurately enough that PnL matches live results, which matters more than people realize — most paper traders feel free in a way real trading doesn't, and you end up learning the wrong lessons.

Later I added an options paper trader, which I haven't seen anywhere else. It pulls chain data from Yahoo Finance since HL doesn't do options, and it's built specifically for practicing swing trades — holding through expiry, scaling in over days, watching theta eat a position you held too long. Pricing, margin, and PnL live in their own engine module with tests, because options PnL is unforgiving and a sign error doesn't announce itself for a week. The trades I take on it are the trades I'd take with real money — same size, same conviction — which is the only way paper trading produces useful feedback.

I've been using it daily for months. It's stable. I haven't deployed it publicly — nobody should trust an unofficial frontend with their keys, and I don't want to be in the support business for other people's losses — but the source is up and it's a few commands to run locally.

TetrisRL

A Tetris RL environment built to test Wissner-Gross's entropy-maximization theory of intelligence.

github.com/jaybutera/tetrisRL · 75★ · Python, PyTorch, NumPy

I started TetrisRL in 2017 after reading Alex Wissner-Gross's Causal Entropic Forces, a paper that proposes a strikingly compact theory of intelligence: that intelligent behavior emerges from a single principle — maximize the diversity of futures available to you. The formal expression is

F=TSτF = T \nabla S_{\tau}

where SτS_{\tau} is the entropy over future paths up to a time horizon τ\tau, and FF is a "causal entropic force" that pushes the agent toward states with more reachable futures. Wissner-Gross shows simple physical systems exhibiting tool use, cooperation, and balance — all from this one objective, no goal specified.

The framing was hard to shake. If intelligence is just future-entropy maximization, the reward function should be agnostic to the task. You shouldn't have to tell the agent what to do — only that it should keep its options open. So I built TetrisRL as a place to test that.

Tetris is a near-perfect environment for it. The losing condition — board fills up — is exactly the state where the agent has the fewest available actions. Future entropy collapses to zero. So the entire game can be played by an agent that knows nothing about lines, scores, or rules, only that it should maximize free space on the board. Clearing lines is the only sustainable way to do that, so an entropy-maximizer learns to play Tetris without ever being told the goal.

I wrote the environment with an OpenAI Gym-style interface so it was easy to swap agents. The repo ships two: a DQN that learns from the entropy reward, and a supervised baseline trained on a dataset of my own playthroughs (same convolutional architecture as the DQN's policy network, just a classification loss instead of TD). The supervised agent plateaus at roughly how well I play. The DQN starts from nothing and, after the recent round of improvements, dramatically outperforms it within about ten minutes of training.

Coming back to it last year, the original entropy result felt incomplete. I'd shown that an agent could learn from a pure free-space reward, but not that it could learn well. The rewrite was substantial: frame stacking so the network can see motion across timesteps, a target network for DQN stability, prioritized replay so it learns from rare events instead of the average step, Boltzmann exploration alongside epsilon-greedy. The CNN replaced an older feedforward model, and LayerNorm came back out — it was hurting more than it helped. The reward stayed entropy-based, but I added a per-row signal that grows quadratically as a row fills, smoothing the gradient between full clears. You can recover the original "free space only" reward by zeroing that term, and the agent still learns; it's just slower.

Trained DQN agent running in the terminal — low stack, board mostly empty
Trained DQN agent running in the terminal. Stack low, board mostly empty, an active piece falling.

The image above is the trained agent partway through an evaluation game. It's the kind of board state Wissner-Gross's principle would predict: most of the playfield is empty, the stack is low and broad, and the agent is keeping vertical channels open for I-pieces it hasn't seen yet. It's not playing for points. It's playing to not lose, which in Tetris is the same thing.

The repo has been online since 2017. It picked up 75 stars and a handful of contributors over the years — bug fixes, a PyTorch version bump, a CUDA loading patch — and it's published on PyPI. It's a small project, but the framing has held up: an agent told only to keep its options open ends up playing Tetris.

fast-hashgraph

A performance-focused rewrite of Hashgraph consensus, using struct-of-arrays layout and Floyd-Warshall reachability.

This is a Rust implementation of SWIRLDS Hashgraph, the consensus algorithm Leemon Baird published in 2016 and that powers Hedera. At the time, hashgraph was making bold claims about being one of the fastest BFT consensus algorithms in existence — in the same conversation as Tendermint, HotStuff, and the early DAG-based protocols. Today that picture is more contested. The state of the art has moved fast: HotStuff variants (Diem, Aptos), Narwhal/Bullshark, Sui's Mysticeti, Solana's Tower BFT — most of them DAG-based now, some pipelining hashgraph's own ideas at higher throughput. But hashgraph's core insight — that you can derive total order from a virtual voting protocol layered over a gossip DAG, without sending any vote messages — still holds up as one of the more elegant designs in the space.

I built this as the second iteration. The first one, rust-hashgraph, compiled to WebAssembly and ran in the browser with a D3.js force-directed visualizer for the event DAG. It worked, and it was good for explaining the algorithm, but it leaned hard on Rust iterators and string-keyed lookups for the WASM boundary, and it didn't scale. Reachability checks — the operation hashgraph uses to compute "X sees Y" and "X strongly sees Y" — were essentially traversing the DAG from scratch every time, putting the hot path somewhere around O(n³) for a graph of n events with the constants of repeated allocation and pointer chasing.

Force-directed hashgraph visualizer from the original Rust/WASM implementation
Force-directed visualizer from the original Rust/WASM implementation. Each color is a different validator; labels track the round each event belongs to.

The rewrite started from a different premise: stop pretending the graph is a graph. Hashgraph events have at most two parents (self-parent and other-parent), and the algorithm only ever asks about reachability and creator membership. So I represented the entire graph as a struct of parallel arrays — one Vec<EventId> for self-parents, another for other-parents, one Vec<u32> for round, one Vec<bool> for witness status, one Vec<Vec<bool>> for the reachability matrix. Adding an event is O(1) array writes plus an OR of two parent reachability rows. Cache-friendly, allocation-light, and the kind of layout you reach for once you've stared at enough flame graphs.

The reachability matrix itself is computed via Floyd-Warshall — the classic O(n³) all-pairs algorithm that's the same triple loop you'd write for boolean matrix multiplication. It's not asymptotically better than the original, but the constant factor is roughly nothing: dense bit operations on contiguous memory instead of HashMap lookups and iterator chains. There's a planned incremental update that uses the structure of hashgraph's parent relationships to avoid recomputing the full matrix on each event — only the new row needs filling, since older events can't reach newer ones — which would cut the dominant term to O(n²). I sketched it in the source comments but didn't ship it; I had what I came for.

I presented this work at Capital Factory in Austin. The talk was less about the rewrite and more about why the data layout matters for consensus protocols specifically: every BFT algorithm has a "majority of majorities" check at its core, and how you store the graph determines whether that check is a tight inner loop or a series of cache misses. Hashgraph happens to make this especially visible because the algorithm is almost pure graph reachability with no message passing, but the lesson generalizes.

The repo isn't actively maintained — it served its purpose. Consensus is a moving target and the algorithms I'd reach for now are different. But the project still stands as a study in performance engineering: the same algorithm, the same correctness properties, made meaningfully faster by changing nothing but where the bytes live.