Skip to content

Releases

openport 0.5.1

Choose a tag to compare

@armanruzgar armanruzgar released this 29 Oct 01:24

openport 0.5.1

Built from 87522a2.

Install

  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/armanruzgar/openport:0.5.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.

Changes since v0.5.0

  • Release: v0.5.1
  • Changelog: 0.5.0's update check cannot follow the move, and the old tap's redirect lasts only while the name is unclaimed
  • Web: React 19.3.1, TanStack Query 5.105.0, Vite 8.3.5, Vitest 5.0.5 and jsdom 30.1.3
  • Web: undici 8.12.3, which fixes the denial of service from excessive content-encodings
  • Namespace: the project moved from 38st to armanruzgar
  • Homebrew: the service's web root uses opt_pkgshare, which Homebrew's service block provides
  • Python: openport-client 0.2.0
  • Changelog: open the Unreleased section
  • Homebrew: openport 0.5.0

openport 0.5.0

Choose a tag to compare

@armanruzgar armanruzgar released this 27 Oct 03:37

Install

  • Homebrew (macOS): brew tap armanruzgar/openport https://github.com/armanruzgar/openport, then brew install openport. Apple silicon uses the release archive; Intel Macs build this tag from source.
  • Docker (amd64 and arm64): docker run --rm -p 127.0.0.1:8080:8080 -v openport:/var/lib/openport ghcr.io/armanruzgar/openport:0.5.0, then open the link it prints, which carries its write token.
  • Linux packages (amd64 and arm64): .deb and .rpm with a private systemd service, not started automatically. Archives 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.

SHA256SUMS covers every archive and package. Before upgrading, back up your data root: see upgrade and backup.

New market-data providers and feed failover, working share orders, splits, queue fills and real-fill calibration, prop-firm rule types, an Analyze tab with a strategy optimizer and hedge suggestions, historical stress and VaR, an option tape, outside portfolio analysis, Linux packages and a backup and upgrade guide. Providers marked "not yet run live" were tested against documentation-shaped samples or recorded responses only; reports from live use are welcome.

Upgrading

Back up the data root first (upgrade and backup). An older openportd cannot be assumed to read journals written by this release, and these formats and defaults changed:

  • Recordings. Providers that deliver a trade's venue (Databento, and ThetaData or Databento imports) now write recording format version 5, which 0.4.0 refuses at the header. Every other provider writes the same files as before. Daily --record-dir files and a feed behind --fallback-provider carry the venue header as well.
  • Fills CSV. Every earlier column stays in place; the export ends with three new columns, feed, stress_ticks and queued. Fills in the API report the same fields, and share fills name their order as stock_order.
  • Named token files. Each secret must be at least eight printable characters; a shorter secret makes the file invalid, as a malformed line does. A # starts a comment only at the start of a field, so a # inside a secret is part of it. Token files reload live on change, SIGHUP or POST /api/tokens/reload.
  • Journal maintenance. --compact-journals and --repair-journals are separate runs: --compact-journals refuses --dry-run and --file, which belong to repair (a dry run used to compact for real). An empty write-token file no longer blocks startup; it is replaced.
  • Program rules. Financing rates, pin risk, queue fills, stop stress and every new prop-firm rule type are program rules: setting one drops a preset's plan_id, and financing overrides on evaluation, verification and funded plans are refused with PLAN_LOCKED. All of them are off by default and in no built-in preset, so existing plans keep their journal bytes. Built-in presets are marked illustrative in GET /api/plans.
  • API responses. The default exposure convention is named long_calls_short_puts (open_interest is still accepted as a deprecated input); without a finite positive spot, exposure totals and cells are null with exposure.available=false and a reason instead of 0. Series and surface-history errors use the standard error body. Account WebSocket events are versioned with bounded delivery. Outbound notification channels keep their previous default events; order_state is opt-in.
  • Docker and systemd. The image starts through an entrypoint script that adds the server settings only to a server start; --backtest, --import-day and --verify-run run in the image without them. docker-compose.yml reads OPENPORT_IMAGE and OPENPORT_VOLUME. The new Linux packages' systemd unit starts with --no-token-link, so the token stays out of journald; open the terminal with openportd --print-url --open.
  • Python. The client publishes to PyPI as openport-client (import name openport; the PyPI name openport is an unrelated project), from python-v* tags on main only.
  • Build. The Interactive Brokers adapter is behind OPENPORT_WITH_IBKR (on by default). The build embeds the stress shocks and built-in scenarios and objectives from data/.

Providers and historical import

  • Charles Schwab market data. --provider schwab polls Trader API option chains with the underlying quote, open interest, volume, delta and gamma, using an OAuth refresh token from the environment. Health follows each response's isDelayed; isMini/isNonStandard and mini/nonStandard both mark a nonstandard contract. Tested against documentation-shaped samples; not yet run live.
  • Alpaca market data. --provider alpaca polls option snapshots for equity and ETF underlyings from the free indicative feed (reported as delayed, derived quotes) or OPRA with a subscription. Alpaca has no index options, so SPX and other indexes are refused. Not yet run live.
  • Interactive Brokers market data. --provider ibkr reads Client Portal Web API snapshots through your logged-in local gateway: it keeps the session alive, maps contract ids to OSI symbols, paces requests and counts market-data lines. Requires --expiries and --window. Not yet run live.
  • Feed failover. --fallback-provider NAME switches an underlying to a second provider once the main one has been in error or silent for --fallback-seconds (default 30), and back once it has been fresh for as long. A primary labelled stale whose snapshots advance keeps its underlyings, and none move onto a backup that could not start or reports an error. Contracts map by OSI symbol; the backup reports delayed with a fallback label in status and the terminal. Paper trading keeps its freshness checks, and every fill names the feed that priced it (feed in the fills API and journal).
  • Published AM settlement values. --am-settlement cboe fetches the special opening quotations Cboe publishes for SPX, RUT, DJX and VIX (indices SET, RLS, DJS and VRO, from Cboe's public daily history) and settles live AM positions only on the history row for their exact expiry date, with source published_soq. Waiting positions show settle_by: "soq" while the expiry date is within the fetcher's 14-day lookback, instead of turning manual at 17:00 ET on the expiry date; manual import remains the fallback. The index's delayed quote is not used, because its trade time cannot tell reliably when it shows the day's value. Options trading and rollover wait while a position awaits settlement; Cboe's posting lag is unmeasured. Tested with responses recorded on 2026-10-21.
  • Import historical options from Massive (Polygon). Historical contract discovery, paginated quotes and trades preserve vendor timestamps. Quote and trade pages grow up to Massive's 50,000-row maximum within the buffer cap. Tested with generated saved-response fixtures; paid historical access has not been validated live.
  • Import date ranges and resume. All importers accept inclusive --import-days ranges and repeated dates, skip calendar closures, report progress and skip only matching complete recordings.
  • Provider certification. openport-probe --certify writes redacted JSON/Markdown reports for timed observations or a snapshot cycle, including event/contract coverage, clock checks, Greek scale hints and errors, for the new provider report issue template. Demo/replay reports are labelled as such and do not claim live validation.
  • Greek and volume mappings. Documented ORATS/DXLink Greeks and ThetaData vega/rho scales are mapped; ThetaData theta remains unknown. Tradier chain and DXLink session volume are mapped without inventing trades or timestamps, and Tradier volume from an earlier trading date is withheld. Sample/mock tested, not yet validated live.
  • Option prints carry the printing venue where the provider gives one. Unknown ThetaData snapshot times are preserved; unused DXLink Profile subscriptions are gone, supplied Summary event times are kept for open interest, and tastytrade subscribes only to the events it reads, raising the contracts its cap allows. A ThetaData Retry-After outside 1-60 s, or a date, backs off instead of failing the import. /api/status reports provider.extended_hours_prints, false for Cboe and the demo market.
  • --provider replay without --symbols plays the recording's symbols.

Recording and replay

  • Record across trading dates. --record-dir rolls at calendar boundaries and publishes only complete files, with optional oldest-first age/size retention that protects active files. Replay lists trading dates, symbols and sources across providers. Retention runs off the feed thread at rollover, reports files it cannot remove instead of stopping recording, and counts stale staging folders toward the size cap.
  • Replay pacing survives several pauses and resumes before the pacing loop observes them. A replay stall no longer moves orders to another account, and a new replay run drops the last run's market data in the terminal.
  • Backtests and replays: a damaged run or sidecar no longer blocks the rest, failed resumes and cancelled checks lose nothing, listings resume, and rule codes and archived modes stay straight. Replay CSV exports name the run as the account.

Trading, financing and halts

  • Working share orders. Stock and ETF shares take resting market, limit, stop and stop-limit orders (POST /api/stocks/orders, /preview, GET, DELETE /api/stocks/orders/{id}), DAY or GTC, with e...
Read more

openport 0.4.0

Choose a tag to compare

@armanruzgar armanruzgar released this 06 Oct 08:45

openport 0.4.0

Built from a4f66ab.

Install

  • Homebrew (Apple silicon): brew tap armanruzgar/openport https://github.com/armanruzgar/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/armanruzgar/openport:0.4.0, 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.1

Evaluation plans

  • Practise more kinds of evaluations. Static floors, floors that stop trailing, daily loss rules, minimum days and best-day consistency join the custom plan editor. Dashboard shows what remains to pass.
  • Set trade-level objectives. Require closed whole option trades, limit the biggest trade's share of profit, set minimum holding time or cap profit from very short trades. Protective and system exits still work during a minimum hold.
  • Control when and what you trade. Set evaluation and inactivity deadlines, allowed symbols, entry hours, mandatory flat time and no-overnight rules. Saved event calendars add news blackouts and weekend, earnings and dividend restrictions.
  • Limit opening exposure. Cap contracts held, require stops, limit risk per trade, forbid opposing positions or cap holdings against traded option volume. Volume caps refuse entries when volume is unknown or stale; stops can still slip.
  • Follow a two-step programme. A passed challenge unlocks verification, then simulated funded trading. Add payout consistency, retained buffers, contract scaling and funded size reviews. Fees and reset limits track programme costs without deducting trading cash. Funded screens stay hidden unless enabled or already funded; OpenPort funds no one and pays no real withdrawals.

Orders, exits and fills

  • Keep protection through partial fills. Brackets grow with entries and shrink with exits. Attach stop/target pairs to held options or spreads, use stop-limits or trailing stops, or link orders so one cancels or triggers another.
  • Trade across sessions. All-session orders and timestamp expiry join DAY/GTC. Conditions can watch another symbol, volatility or a New York time. Overnight and curb execution needs limits; new orders, including GTC, are refused between product sessions. Missing trigger data does not trigger an order.
  • Choose inside fills and walking limits. Limits can fill at midpoint or a chosen share of the spread, or move in steps toward a cap. These are optional; As displayed remains the default. Neither model simulates queue position.
  • Preview costs, fills and order changes. Choose flat or itemized fees and see why an order waits. Fills retain the quote, displayed size and quote age.
  • Close and adjust the whole position. Roll strikes or an entire condor; Flatten keeps spread closes working across quotes and preserves remaining protection. Preview what it leaves behind, or use limit flatten outside regular hours. Worthless longs can be abandoned, or marked do-not-exercise for expiry.

Shares, margin and risk

  • Trade stock and ETF shares during stock regular hours, with buying-power and delta previews. Covered-call and collar templates buy shares first: shares remain if the option order fails or partly fills. Automatic playbooks still trade options.
  • Choose cash, IRA or margin accounts. Add house requirements or portfolio volatility shocks. Strategy margin recognises share covers, straddles and combinations across expiries, showing the allocation and any conservative fallback.
  • Compare adjustments before trading. What-if compares buying power, Greeks, scenario losses and floor room. Held-book warnings and per-symbol limits help track exposure; risk profiles add later dates, IV changes, beta weighting and probability cones. These are model estimates, not predictions.

Journal and account review

  • Keep rolls and adjustments in one whole trade. Group entries for review, retain planned risk, and compare return on buying power and P&L by Greek. Exports identify the attempt, replay, scenario and seed, and label forced exits.
  • Inspect settlement sources. Journal shows references and provenance. New demo and replay runs use the expiry opening print for AM settlement, an approximation of the official quotation; live feeds still need manual imports.
  • Manage accounts. Rename, archive or delete accounts, or copy risk settings. Deleted files remain; damaged journals are readable through verified history.

Replays and practice days

  • Carry one account through several sessions with overnight gaps, GTC orders, assignment and dividends. Scenarios add XSP, NDX, RUT and VIX, American ETF pricing and simulated quarterly SPY/QQQ dividends. Stress days can include bad quotes, feed stalls, halts and early closes; these are not historical reconstructions.
  • Step, watch or retry a drill. Advance by time or the next snapshot, play at a chosen speed to a target, or interrupt a long step. Restart at a chosen time with the original commands through that point in a new run, keeping the source.
  • Resume unfinished runs after shutdown and verify finished runs in the terminal, with a downloadable receipt. Verification detects changed inputs and damaged history; identical results are not promised across different platforms.

Playbooks and backtests

  • Add technical entry and exit rules. Use moving averages, RSI, Bollinger bands, VIX levels and opening gaps; manage trailing profit, days to expiry and trading-day deadlines. Missing history blocks entries rather than inventing data.
  • Forward-test automatically on live paper accounts. Auto resumes after restart and compares each version with saved backtests. Normal trading checks still apply.
  • Test two to eight playbooks together on one account with shared buying power and plan limits, plus results for each playbook and daily evaluation progress. Comparing and summing separate runs remains an independent-results comparison. Open positions at the end stay reported, without invented closing prices.

Alerts and upgrade notes

  • Keep account alerts running with the terminal closed. Watch options, spreads, IV, equity, floor room and exposure, with optional external delivery. Demo and replay forwarding needs explicit opt-in; backtests and sandboxes never forward.
  • Older journals still load. Saved scenario runs retain their original price generation for verification. Resume/restart requires supported runs and unchanged inputs; for an older live demo journal, keep its original revision and day settings.
  • Resets preserve daily discipline. Profit locks, trade limits, opening counts and active cooldowns survive an account reset. New 100% soft-floor settings are refused, though stored ones still load. Passed or failed attempts can still close.
  • Pin backtests you want to keep. The server now defaults to retaining 20 finished unpinned runs, pruning older excess runs before starting another. Set retention to zero for unlimited storage; CLI reports are outside this policy.
  • Practice is not a prediction. Delayed quotes give hindsight, and generated days cannot establish future performance. Historical importers and providers other than Cboe, Demo and Replay still have not been run live with a key/account.

Fixed

  • Closing and buying power now handle partial protection, worthless wings, shared covers and margin released by fills more consistently. Reductions can proceed over exposure limits, but removing a hedge can still increase risk and fail.
  • Replay timing keeps same-time quotes together, preserves gaps after stepping and refuses out-of-range steps before moving. Storage failures are clearer.
  • P&L and history preserve prior-day marks, dividends and whole-trade labels. Resets restore original scaled plan limits. Profit-taking exits no longer start a stop cooldown unless the separate loss threshold is met.

openport 0.3.1

Choose a tag to compare

@armanruzgar armanruzgar 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

@armanruzgar armanruzgar 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/armanruzgar/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

@armanruzgar armanruzgar 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

@armanruzgar armanruzgar 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/armanruzgar/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/armanruzgar/openport

openport 0.1.0

Choose a tag to compare

@armanruzgar armanruzgar 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/armanruzgar/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.