Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a14e271
feat(engine): establish SQLite order storage checkpoint
Richard-LZ-Zhang Oct 14, 2026
4076f70
feat(engine): make stop dispatch and recovery durable
Richard-LZ-Zhang Oct 14, 2026
244ccc8
feat(engine): verify bounded Kalshi stop-limit lifecycle
Richard-LZ-Zhang Oct 14, 2026
7f5e0a7
test(engine): add bounded crypto stop-fill verification
Richard-LZ-Zhang Oct 14, 2026
1726d1f
fix(engine): preserve uncertain stops and verify US execution
Richard-LZ-Zhang Oct 14, 2026
d44a681
Add PostgreSQL journal storage and recovery contracts
Richard-LZ-Zhang Oct 14, 2026
e53153a
Verify PostgreSQL live stops and normalize Kalshi execution averages
Richard-LZ-Zhang Oct 14, 2026
a92d4ba
Use SQLAlchemy and Alembic for single-owner order storage
Richard-LZ-Zhang Oct 14, 2026
8807523
Merge remote-tracking branch 'origin/main' into codex/order-lifecycle…
Richard-LZ-Zhang Oct 14, 2026
4f29619
Preserve transaction ownership through canceled commits and rollback …
Richard-LZ-Zhang Oct 15, 2026
a407712
serve: library parity for data and buckets (auth, live streams, batch…
Oct 15, 2026
423d4ce
tests: wait for the hub to open a venue stream before using it
Oct 15, 2026
98b7bf6
engine: order gaps for the terminal (list, in-doubt, cancel-after-fil…
Oct 15, 2026
e52370f
Merge remote-tracking branch 'origin/sp/serve-parity' into sp/order-gaps
Oct 15, 2026
fd57881
tests: wider lease margins in the stop-fill lease tests
Oct 15, 2026
d33bffb
engine: outcome and action on orders, order log, book-marked positions
Oct 21, 2026
a500c18
Merge main into the experimental line (#32, #33)
Oct 21, 2026
b627074
Merge main into serve parity (#32, #33 via #35)
Oct 21, 2026
46b310e
Merge serve parity with main (#30 + #32, #33) into order gaps
Oct 21, 2026
7f73b77
Merge pull request #35 from Synpath-ai/sp/sync-main-into-experimental
YukiC0804 Oct 21, 2026
53983d9
Merge main into the experimental line (#34)
Oct 21, 2026
19418d2
Merge the experimental base (#34 sync) into sp/serve-parity
Oct 21, 2026
f1e0ed2
Merge the experimental base (#34 sync) into sp/order-gaps
Oct 21, 2026
03c487c
Merge pull request #36 from Synpath-ai/sp/sync-main-2
YukiC0804 Oct 21, 2026
7d5c593
Merge pull request #30 from Synpath-ai/sp/serve-parity
YukiC0804 Oct 21, 2026
5ae2269
Merge pull request #31 from Synpath-ai/sp/order-gaps
YukiC0804 Oct 21, 2026
e82445b
rfq: RFQ and combos on Polymarket US, Kalshi, Polymarket and SX Bet
Oct 21, 2026
c4a9b82
Merge pull request #37 from Synpath-ai/sp/rfq-combo
YukiC0804 Oct 21, 2026
42531a8
Clarify managed-order execution names and routing stages
Richard-LZ-Zhang Oct 22, 2026
471fb50
rfq: cross-venue RFQ groups, combo board and preview, combo routes
Oct 22, 2026
2cbf7e5
Merge pull request #38 from Synpath-ai/sp/combo-api
YukiC0804 Oct 22, 2026
4983475
fix: complete routed cancellation after delayed child updates
Richard-LZ-Zhang Oct 22, 2026
205d307
merge: integrate current terminal SDK branch and update RFQ callers
Richard-LZ-Zhang Oct 22, 2026
e2df3ba
test: verify pending routed cancellation across SQLite restart
Richard-LZ-Zhang Oct 22, 2026
1d86b9f
docs: clarify experimental journal downgrade limits
Richard-LZ-Zhang Oct 22, 2026
27b4ea4
Merge pull request #39 from Synpath-ai/codex/routed-cancellation-life…
Richard-LZ-Zhang Oct 22, 2026
6b21210
Warm combo boards in serve and name the legs a venue lacks
Oct 22, 2026
8501387
Merge pull request #40 from Synpath-ai/sp/combo-warm
YukiC0804 Oct 22, 2026
e721d91
fix: remove nominal execution venue from routed parents
Richard-LZ-Zhang Oct 25, 2026
7bfb56f
test: verify scoped event delivery and transactional recovery
Richard-LZ-Zhang Oct 25, 2026
396f88b
test: assert bounded membership page queries
Richard-LZ-Zhang Oct 25, 2026
148ea2e
test: compare pagination in database collation order
Richard-LZ-Zhang Oct 25, 2026
7084154
Merge pull request #44 from Synpath-ai/codex/pre-6-cross-venue-parent
Richard-LZ-Zhang Oct 26, 2026
8e0c517
refactor: clarify submission and routed order planning flow (#46)
Richard-LZ-Zhang Oct 27, 2026
1dc1999
docs: explain capability inheritance and defaults (#47)
Richard-LZ-Zhang Oct 27, 2026
7b91777
refactor(stream): clarify lifecycle and raw frame ownership (#48)
Richard-LZ-Zhang Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: tests

on:
push:
branches: [main]
branches: [main, codex/order-lifecycle-storage]
pull_request:

jobs:
Expand Down Expand Up @@ -49,3 +49,32 @@ jobs:
out=$(env -i HOME=/tmp/norust-home PATH=/usr/bin:/bin /tmp/norust/bin/python -m pip install --no-deps dist/*.tar.gz 2>&1 || true)
echo "$out" | tail -20
echo "$out" | grep -q "sh.rustup.rs" || { echo "the install-Rust message did not appear"; exit 1; }


postgres:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:18
env:
POSTGRES_DB: synpath_test
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d synpath_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- run: pip install -e ".[dev,postgres]"
- name: PostgreSQL journal, recovery and mocked venue contracts
run: pytest -q tests/test_postgres_storage.py tests/test_owner_migrations.py tests/test_routed_execution_scope.py tests/test_routed_scope_transactions.py tests/test_routed_audit_pagination.py
env:
SYNPATH_TEST_POSTGRES_DSN: postgresql://postgres:postgres@localhost:5432/synpath_test
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,12 @@ async with KalshiTrading(require("kalshi", creds)) as kalshi, \
**REST server**

```bash
python -m synpath.server # http://127.0.0.1:8000/docs
python -m synpath.server # http://127.0.0.1:8000/docs, no auth: keep it on localhost
curl "localhost:8000/venues/kalshi/markets?limit=1"
```

`synpath serve` runs the same routes (batch reads and search included), plus live books at `/ws/market` (a bucket's merged book too, with a router preview at `/trading/buckets/{id}/plan`) and Synpath's hosted matching and tick history at `/matching` and `/history` (with serve's own Synpath API key), behind its access token; see [docs/server.md](docs/server.md).

Trading has its own app, with per-account keys and an append-only audit log:

```bash
Expand Down Expand Up @@ -252,3 +254,10 @@ secret.
## License

MIT


Experimental execution storage on `codex/order-lifecycle-storage` supports SQLite
(default) and explicitly configured PostgreSQL, with one active execution worker.
See [engine README](synpath/engine/README.md) for configuration, recovery and test
coverage. Terminal integration and remaining live venue guarantees are tracked
separately; this experimental branch stays unmerged.
11 changes: 11 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@ Because results are ranked by relevance, paging deep into a large result set
is best effort. To enumerate every market, walk `fetch_markets()` without a
query.

Over HTTP, `synpath serve` answers one venue's search at
`GET /venues/{venue}/markets?query=`, and several venues' at once at
`GET /search/markets` and `GET /search/events`, each venue's page reported
separately; `GET /markets?ids=` and `GET /books?ids=` are the batch reads
([server](server.md#batch-reads-and-search)).

### Sort

`volume`, `liquidity` or `newest`, on every venue -- but not the same way on
Expand Down Expand Up @@ -241,6 +247,11 @@ synpath.match_event("kalshi:KXHIGHTATL-26SEP23")
# events={"polymarket": ["polymarket:1003798"]})
```

`synpath serve` makes these calls for its clients, with its own key, at
`GET /matching/market`, `GET /matching/event` and (the hosted cross-venue
scan) `GET /matching/arbitrage`; tick history is at `GET /history/...`
([server](server.md#hosted-services-matching-and-tick-history)).

### Status

One vocabulary, one meaning per word, on every venue.
Expand Down
10 changes: 8 additions & 2 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ onboarded firms.
| `fetch_settlements` | yes | yes, from the redemption activity | yes | no | no | no | no | no | no |
| `fetch_queue_position` | yes | no | no | no | no | no | no | no | no |
| `fetch_fee_estimate` | yes | yes | yes | yes | yes, from the fee contract, 0.25 USDT minimum | yes, the closing charge; opening fills pay nothing | yes, `rate * min(p, 1 - p)` a share | yes, the venue's buy-fee curve on the token bought | yes, 1% of a winning taker bet's profit |
| `rfq` | yes | no | no | no | no | no | no | no | no |
| `rfq` | yes; the older key, kept one release: the typed methods below | no | no | no | no | no | no | no | no |
| `rfq_taker` | yes; two-sided RFQs by contracts (`contracts_fp`) or USD (`target_cost_dollars`), accept with `worst_price` (buy YES sends `accepted_side=no`) | yes; combo RFQs, one side of the combo's YES: buy by pUSD, sell by shares; accept signs an Exchange v3 order, refused on `worst_price` before signing; Deposit Wallet, proxy or Safe only (EOAs refused) | yes; two-sided RFQs by contracts or USD (`cashOrderQty`), accept with `worst_price` | no | no | no | no | no | no; no API requests a parlay (a bettor asks on sx.bet) |
| `rfq_quoter` | yes; quote (`yes_bid`/`no_bid`), cancel, confirm (30 s, 3 s on combos); replace is cancel then send | yes; requests over the quoter WebSocket (400 ms window), quotes as signed Exchange v3 orders over REST, cancel, confirm (1 s last look, venue opt-in); replace is cancel then send | yes; quote, replace, cancel, confirm (3 s last look) | no | no | no | no | no | yes; parlay requests from `parlay_markets:global`, a quote is signed orders on the parlay market expiring with it (60 s); cancel, replace (cancel then send); no last look, so no confirm |
| `combos` | yes; multivariate collections, create (5,000 a week) and fetch by `KXMVE…` ticker, no read-only lookup by legs | yes; RFQ-only: no create or lookup at the venue; `create_combo` is offline (a provisional id until an RFQ names `combo-<condition_id>`), legs from the public catalogue | yes; create (idempotent) and fetch by symbol, no read-only lookup by legs | no | no | no | no | no | yes; a parlay market and its legs, fetched and looked up among the requests heard; none created through the API |
| `split_merge` | no; contracts are not tokens | partial: Deposit Wallets and EOAs | no | no | no | no | no | no | no |

Order types are a separate question. A venue holds `limit` and `market`;
Expand Down Expand Up @@ -256,12 +259,15 @@ Every stream answers the `watch_*` keys the same way
| `LimitlessUserStream` | no | no | no | no | yes | yes | no | no |
| `SxBetMarketStream` | yes | partial | yes | yes | no | no | no | no |
| `SxBetUserStream` | no | no | no | no | yes | yes | no | no |
| `SxBetParlayStream` | no | no | no | no | no | no | no | no |
| `BetfairMarketStream` | yes, best offers to 10 levels | partial: top of book | no: no public trades | yes, per runner | no | no | no | no |
| `SmarketsMarketStream` | partial: polled from REST quotes, every 5 s by default | partial: polled | no: read the recent tape with `fetch_trades` | partial: polled every few rounds | no | no | no | no |

The exchange API's other gRPC streams carry one thing each and say so:
drop copy and trade capture carry fills, position and position-change carry
positions, instrument state carries market status, and the balance ledger
carries account movements as venue events.
carries account movements as venue events. `SxBetParlayStream` carries
parlay requests (`parlay_markets:global`) as `parlay_request` venue events,
each with the request as an incoming `Rfq`.

---
Loading
Loading