Skip to content

Releases: 38st/openport

openport 0.3.1

Choose a tag to compare

@38st 38st released this 28 Sep 06:40

openport 0.3.1

Built from 516518c.

Install

  • Homebrew (Apple silicon): brew tap 38st/openport https://github.com/38st/openport, then brew install openport. brew services start openport runs it on 127.0.0.1 with its data under Homebrew's var/openport; brew info openport says where to find the token link.
  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/38st/openport:0.3.1, then open the link it prints, which carries its write token. docker-compose.yml in the repository does the same with a restart policy and a health check.
  • Linux archives (amd64 and arm64): need OpenSSL 3, zlib and zstd (apt install libssl3t64 zlib1g libzstd1 on Ubuntu 24.04). Unpack one and run bin/openportd.
  • macOS archive (Apple silicon): needs nothing installed. Unpack it with tar -xzf and run bin/openportd. Unpacked in Finder, macOS may refuse to run it as from an unidentified developer; xattr -dr com.apple.quarantine on the folder allows it.

Then open http://127.0.0.1:8080. openportd --help lists every option. SHA256SUMS covers every archive.

What's new since 0.3.0

Backtests

  • Run a playbook over many days and see whether it passes the evaluation plan. Each day runs a fresh account on recorded days, imported days or seeded scenario days. Reports give pass rate, expectancy, win rate, the distributions of daily P&L and drawdown, the worst days, and each day's kept journal, which openportd --verify-run checks.
  • The same inputs and seed give byte-identical reports. Run it from the Backtest page, openportd --backtest, /api/backtests or the Python client. Results are simulated trading, not predictions.

Past days from your data provider

  • openportd --import-day databento|thetadata --date YYYY-MM-DD fetches one trading day's option chain from the provider's historical API, with your own key, and writes a recording that Replay plays. The data stays on your machine. Neither importer has been run live with a key yet; both follow the providers' documented APIs and are tested against saved responses.

Harder fills, if you want them

  • Optional latency and size impact. Latency fills an order against the first quote at or after its market time plus the delay. Size impact charges extra ticks beyond the displayed size. A Conservative preset uses 1,000 ms, one slippage tick and one impact tick per block. Both are off by default, and accounts with them off are exactly as before.

Notifications

  • Alerts to Discord, Telegram, ntfy or any webhook for live accounts: fills and rejections, equity near the floor, rule trips, assignments and exercises, staged playbook orders and a stalled feed. Delivery never blocks the engine, and secrets never reach flags, logs or the API. Replays, backtests and the demo never notify.

The demo market as a feed

  • openportd --provider demo plays the built-in simulated days back to back as the server's own feed, with no data provider and no network access. Each day plays on the next trading date, and a restart resumes after the accounts' last market day. Its default journal is separate from your live one. The README explains how to run a public, watch-only instance; one runs at https://openport-production.up.railway.app.
  • The terminal shows one "Watch only" notice when the server needs a write token and the browser has none.
  • Sandboxes for visitors. With --sandboxes N on a demo server, a visitor can take their own practice account and trade it, and can't see or touch anyone else's account or the server's settings. Each sandbox has a random token stored only as a hash; creation and orders are rate-limited per client (--client-ip-header names the real-address header behind a proxy); an unused sandbox is removed with its files after 24 hours. The option is refused with any provider but demo.

Install

  • A Homebrew tap in this repository, a docker-compose.yml, and opt-in update notices: when turned on under Status > Updates, the browser checks GitHub's latest release at most once a day and shows a notice when it's newer.

Fixed

  • Closing prints and settlements could read freed memory while recording closes for several positions. The demo feed's two-day settlement test found it under AddressSanitizer.
  • Tests that waited on the clock now wait on the events themselves, so a heavily loaded machine no longer fails them.

openport 0.3.0

Choose a tag to compare

@38st 38st released this 28 Sep 00:31

openport 0.3.0

Built from ba2fa77.

Install

  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/38st/openport:0.3.0, then open the link it prints, which carries its write token; or docker build -t openport . from this tag.
  • Linux archives (amd64 and arm64): need OpenSSL 3, zlib and zstd (apt install libssl3t64 zlib1g libzstd1 on Ubuntu 24.04). Unpack one and run bin/openportd.
  • macOS archive (Apple silicon): needs nothing installed. Unpack it with tar -xzf and run bin/openportd. Unpacked in Finder, macOS may refuse to run it as from an unidentified developer; xattr -dr com.apple.quarantine on the folder allows it.

Then open http://127.0.0.1:8080. openportd --help lists every option. SHA256SUMS covers every archive.

What's new since 0.2.1

Faster, however long the account's history

  • Quote handling no longer grows with the history. After 10,000 fills, a quote batch took 10.1 ms of CPU in 0.2.1; it now takes about 8 µs, and one holding a position under 25 µs instead of 26.6 ms. A submit went from 33 ms to about 45 µs. A transaction's copy of the account and each published snapshot now share the history in persistent trees. The risk checks read positions and working orders instead of building whole snapshots, trade reviews update as fills arrive, and a journal record's change is found field by field. The journal format is unchanged, and journals from older builds recover to the same state.
  • Submits stay flat past 100,000 fills. A write copies a tree path instead of a list of every chunk: after 100,000 fills a submit took about 95 µs against 250 µs with flat lists.
  • Calendar lookups are cached per thread under the published holiday schedule. A session lookup takes about 135 ns instead of 10 µs, and every answer is the same.
  • Replay journals sync to disk in batches, every 250 ms and at pause, stop and finish. A replay writing 906 records took 2.6 s instead of 11.8 s. Live accounts still sync every record before a transaction is published. A power cut during a replay can lose its last quarter second.

Fixed

  • An announced closure without a name now closes the market. It used to count as a business day with a regular session.

Checks

  • OPENPORT_VERIFY_REVIEWS=1 and OPENPORT_VERIFY_JOURNAL=1 make the simulator check its reviews and journal changes against full rebuilds on every transaction. CI runs the whole suite with both.

Measured on an Apple M2 Max, as described in docs/architecture.md.

openport 0.2.1

Choose a tag to compare

@38st 38st released this 27 Sep 07:59

openport 0.2.1

Built from a03ece0.

Install

  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/38st/openport:0.2.1, then open the link it prints, which carries its write token; or docker build -t openport . from this tag.
  • Linux archives (amd64 and arm64): need OpenSSL 3, zlib and zstd (apt install libssl3t64 zlib1g libzstd1 on Ubuntu 24.04). Unpack one and run bin/openportd.
  • macOS archive (Apple silicon): needs nothing installed. Unpack it with tar -xzf and run bin/openportd. Unpacked in Finder, macOS may refuse to run it as from an unidentified developer; xattr -dr com.apple.quarantine on the folder allows it.

Then open http://127.0.0.1:8080. openportd --help lists every option. SHA256SUMS covers every archive.

What's new since 0.2.0

The account keeps trading

  • No more stale-quote lockouts. Cboe resends only quotes that changed, so a held option whose quote sat still for a minute went stale and blocked every order, closes included. Each snapshot poll now ends with a mark that keeps unchanged quotes current. An underlying whose source runs a minute or two behind the others stays tradable within the stall tolerance. A far wing with no bid (0.00 / 0.05) is marked halfway to its ask and valued at its ask IV instead of blocking the account. After an overnight gap the account waits for the day's first complete snapshot. Holding an iron condor through a demo day, 0.2.0 refused 81 of 125 probe orders as stale; this release refused none of 265, and its marks stayed current throughout.
  • A reduce-only kill switch. A daily-loss or manual trip leaves the account able to close: closing orders, Flatten, bracket exits and the system's closes keep working, while orders that open or add exposure reject.
  • 0DTE stays selected in the chain until its auto-close, with a countdown.

Trading and risk

  • Plan-locked limits and personal guardrails. During an evaluation a limit can be tightened at once, and loosened only from the next day. Optional guardrails: a soft floor, a daily trade cap, a cooldown after a stop-out, and a daily profit lock.
  • Order preview. POST /api/orders/preview, and the tickets, show buying power, the change in Greeks and the maximum loss against the floor, with "Size to floor".
  • Strategy templates: verticals, iron condors and butterflies, strangles, straddles, calendars and diagonals, chosen by delta, points or expected move. Probability of profit now includes the skew term.
  • Good-till-cancelled orders, tags and notes on orders, and brackets on spreads.
  • Chain liquidity: session volume, spreads as a share of the mid, and liquidity warnings on tickets.

Review and practice

  • Trade review: the market and account at every fill, MAE and MFE, R-multiples, day notes, and CSV exports of trades and fills.
  • Replay: 14 scenario days with fresh seeds, drills that start at a chosen time, replay accounts kept in their own journals, and openportd --verify-run to check that a run reproduces exactly.
  • Playbooks: versioned setups that stage orders through the preview, run automatically in replays, and track adherence and pass odds.
  • Brief: one page to read before the bell.

Data and analytics

  • Volatility: model-free implied volatility by the VIX method, skew, realized volatility, implied moves, IV rank and percentile, and the variance risk premium, with a local history (--series-dir, --backfill-series).
  • Tradier and tastytrade market data. These are market-data-only adapters, not yet run live with an account; reports are welcome.
  • An OpenAPI contract, a Python client and an MCP server, with named tokens scoped to read, trade, replay or admin, and the actor recorded on every journal transaction.

Security and reliability

  • DNS rebinding blocked. Every request must address the server by an IP address, localhost, or a name you allow with --allowed-host.
  • Docker trades out of the box. The container keeps a write token in its volume and prints a link that saves it in your browser tab. CI now checks that the image fills an order.
  • Durable journal. On macOS it uses the full sync that survives a power loss. It stops before a full disk can tear it, openportd --repair-journals cuts off a torn last line and keeps the original, and transactions that change nothing are no longer written.
  • HTTP: API keys are not sent on redirects to other hosts, and a timed-out request is not retried. Cboe's timeout is 15 seconds, so one slow symbol no longer stalls the rest.
  • ThetaData snapshots are stamped with their data's time instead of the wall clock.
  • CI now runs the tests under AddressSanitizer and UndefinedBehaviorSanitizer with leak detection, and checks the Python client and the API contract.
  • The macOS archive runs without Homebrew.

Every commit since v0.2.0

  • Docker: give the web type check the shared template parity fixture
  • Build: include where pass odds throw, and brace a test loop's assertion
  • Tests: wait for the account's view of the seeded quotes before a preview purity check
  • Playbooks: versioned setups, staged and replay-automatic orders, adherence and pass odds
  • API: a checked OpenAPI contract, a Python client and MCP server, scoped tokens and actors
  • Brief: one page to read before the bell
  • Build: include for std::exchange, and read JSON values explicitly
  • Volatility: a local history, IV rank and percentile, and the ex-post variance risk premium
  • Replay: a thread-free desk, reproducible runs, --verify-run and stepping
  • Chain: session volume, spreads and liquidity warnings
  • Tests: brace an assertion GCC flags as a dangling else
  • Providers: Tradier and tastytrade market data
  • Build: unhide MetricsSource's account overload in two subclasses
  • Floor: plan-locked limits, personal guardrails, order preview, breach risk and intraday equity
  • Replay: a speed chosen while paused applies when play resumes
  • Journal: trade review with context at every fill, excursions, CSV and day notes
  • Replay: a scenario library, fresh seeds, drills from a start time, and kept journals
  • Orders: good-till-cancelled, tags on orders, and exits on spreads
  • Volatility: model-free IV, skew, realized volatility and implied moves
  • CI: silence GCC's false bounds warnings in sanitizer builds
  • Launch kit: a landing page, and a guide to writing a provider adapter
  • Tickets: probability of profit with skew, and strategy templates
  • Version 0.2.1
  • Trust fixes: a reduce-only kill switch, 0DTE until its auto-close, sanitizers in CI
  • Docs: count 532 C++ tests
  • Journal: survive power loss and a full disk, and repair a torn line
  • Docs: count 530 C++ and 295 web tests
  • ThetaData: stamp a snapshot with its data's time, not the wall clock
  • Journal: a transaction that changed nothing leaves no record
  • Docker: trade from the link the container prints
  • HTTP: keep keys on their origin, and give up on a slow response sooner
  • Web: refuse requests addressed by a DNS-rebinding name
  • Tests: rename a lambda's local that GCC flags as shadowing its parameter
  • Tools: a demo-day soak test for fills and freshness
  • Docs: count 524 C++ tests
  • Marks: a wing nobody bids for no longer blocks the account
  • Docs and Rules page: say what the simulator does
  • Freshness: a complete snapshot keeps unchanged quotes current
  • macOS: a release archive that runs without Homebrew
  • README: the roadmap lists 0.2.0's slippage, portfolio margin, cash dividends, IWM and DIA, and Cboe's new host
  • Analytics: an underlying waits for its first price instead of the wall clock

openport 0.2.0

Choose a tag to compare

@38st 38st released this 26 Sep 02:00

openport 0.2.0

Built from 3ff3f95.

Install

  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/38st/openport:0.2.0, or docker build -t openport . from this tag.
  • Linux archives (amd64 and arm64): need OpenSSL 3, zlib and zstd (apt install libssl3t64 zlib1g libzstd1 on Ubuntu 24.04). Unpack one and run bin/openportd.
  • macOS archive (Apple silicon): needs nothing installed. Unpack it with tar -xzf and run bin/openportd. Unpacked in Finder, macOS may refuse to run it as from an unidentified developer; xattr -dr com.apple.quarantine on the folder allows it. (Replaced on 2026-09-26 with this self-contained build of the same 0.2.0 code, which links OpenSSL and zstd statically; SHA256SUMS was updated with it.)

Then open http://127.0.0.1:8080. openportd --help lists every option. SHA256SUMS covers every archive.

What's new since 0.1.0

Market data

  • Cboe's new host. Cboe moved its delayed quotes from cdn.cboe.com to cdn-api.cboe.com in September 2026: the old host went stale on 2026-09-23, then answered with redirects. openport now reads the new host, and its HTTP client follows redirects (up to five, never from https down to http). Under 0.1.0 the chains fall back to Cboe's slower quote pages and the chart backfill fails, so this upgrade matters if you use the default data source.
  • IWM and DIA by default. openportd and the Docker image subscribe to SPX, SPY, QQQ, IWM and DIA.
  • Regular-session marks. Outside the session, stocks and ETFs are marked at their last regular close, not at after-hours prints.

Calendar, halts and settlement

  • Cboe's holiday schedule. openportd reads Cboe's published schedule at start and daily, so a special closure no longer needs a new build. --no-cboe-holidays turns it off.
  • Market-wide circuit breakers. The 7%, 13% and 20% levels of NYSE Rule 7.12 halt trading: orders reject with MARKET_HALTED, status and WebSocket ticks carry the state, the terminal shows a banner, and a halt survives a restart.
  • Official-close settlement. PM-settled options settle on Cboe's official close, revisions included, instead of the first print after 16:00.

Dividends and analytics

  • Dividends from Massive. --dividends massive reads cash dividends from Massive's API with MASSIVE_API_KEY.
  • Cash dividends in the American model. The binomial trees take known cash dividends (the escrowed model), which moves the early-exercise boundary of in-the-money calls before an ex-date.

Simulator rules

  • Slippage. slippage_ticks (0 to 10) fills every option that many ticks past the displayed far side.
  • Portfolio margin. margin: portfolio replaces strategy margin with a risk scan per underlying in the manner of Cboe Rule 12.4 and FINRA Rule 4210(g). The presets keep strategy margin and no slippage.

Fixes

  • Trading could stop after a restart. When an underlying's contract definitions reached the engine before any of its prices (Databento sends definitions first, as Massive and ThetaData do without an underlying price), its analytics were stamped with the wall clock, and an account with positions or orders rejected them as future-dated (INVALID_TIME), which disabled its trading until the next restart.
  • Resting orders wait out data gaps. An order whose quote arrived while the rest of the portfolio's marks or valuations were stale, as right after a stall, was cancelled with RISK_CHANGED. It now keeps working and fills once the data is complete.

Every commit since v0.1.0

  • Rules: a data gap holds a resting order's fill instead of cancelling it
  • Paper: analytics from before any price can no longer disable an account
  • Version 0.2.0
  • Cboe: read its delayed quotes from cdn-api.cboe.com, and follow redirects
  • Analytics: known cash dividends in the American exercise model
  • Rules: optional slippage, and portfolio margin
  • Halts: circuit-breaker state in status and ticks, kept across restarts, with a banner
  • Cboe: mark stocks and ETFs at their last regular close outside the session; trade IWM and DIA by default
  • Tests: brace the assertions GCC flags as a dangling else
  • Settlement: PM options settle on the official close, revisions included
  • Calendar: keep the first of two announced entries for a date, as documented
  • Dividends: read them from Massive's API with --dividends massive
  • Calendar and halts: Cboe's holiday schedule, and market-wide circuit breakers
  • README: start from the published image, ghcr.io/38st/openport

openport 0.1.0

Choose a tag to compare

@38st 38st released this 24 Sep 16:04

openport 0.1.0

Built from a770bac.

Install

  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/38st/openport:0.1.0, or docker build -t openport . from this tag.
  • Linux archives (amd64 and arm64): need OpenSSL 3, zlib and zstd (apt install libssl3t64 zlib1g libzstd1 on Ubuntu 24.04). Unpack one and run bin/openportd.
  • macOS archive (Apple Silicon): needs Homebrew's openssl@3, zstd and brotli. Unpack it and run bin/openportd.

Then open http://127.0.0.1:8080. openportd --help lists every option. SHA256SUMS covers every archive.

What's in it

The first release: self-hosted options analytics and a prop-firm-style paper-trading simulator in one C++20 process with a React terminal.

  • Market data from Cboe's free delayed quotes (the default), Databento, Massive or ThetaData, with recording and replay of any session, and a demo market of five simulated days for when nothing trades.
  • Implied volatility and Greeks computed by openport, forwards from put-call parity, de-Americanised IVs for equity and ETF options, SVI and SSVI smiles, and gamma and vanna exposure.
  • Paper accounts that fill against the displayed quotes under evaluation rules: single and multi-leg orders, brackets and triggers, buying power, exercise, assignment and settlement, a hash-chained journal, and a terminal with a chart, positions, a P&L journal and alerts.

See the README for the details and the numbers behind them.