synpath 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- synpath/__init__.py +183 -0
- synpath/__main__.py +66 -0
- synpath/base.py +723 -0
- synpath/bucket.py +154 -0
- synpath/client.py +356 -0
- synpath/engine/__init__.py +37 -0
- synpath/engine/__main__.py +354 -0
- synpath/engine/alerts.py +170 -0
- synpath/engine/engine.py +888 -0
- synpath/engine/eod.py +154 -0
- synpath/engine/events.py +140 -0
- synpath/engine/fair_values.py +117 -0
- synpath/engine/feeds.py +220 -0
- synpath/engine/journal.py +907 -0
- synpath/engine/ledger.py +353 -0
- synpath/engine/orders/__init__.py +42 -0
- synpath/engine/orders/base.py +441 -0
- synpath/engine/orders/day.py +72 -0
- synpath/engine/orders/iceberg.py +121 -0
- synpath/engine/orders/manager.py +223 -0
- synpath/engine/orders/oco.py +255 -0
- synpath/engine/orders/peg.py +168 -0
- synpath/engine/orders/routed.py +496 -0
- synpath/engine/orders/stop.py +240 -0
- synpath/engine/orders/taker.py +187 -0
- synpath/engine/orders/twap.py +190 -0
- synpath/engine/paper.py +532 -0
- synpath/engine/reconcile.py +279 -0
- synpath/engine/risk.py +403 -0
- synpath/engine/router.py +261 -0
- synpath/errors.py +98 -0
- synpath/history.py +71 -0
- synpath/hosted.py +86 -0
- synpath/hosted_auth.py +201 -0
- synpath/ids.py +61 -0
- synpath/kalshi.py +1378 -0
- synpath/matching.py +86 -0
- synpath/polymarket.py +1004 -0
- synpath/polymarket_us.py +989 -0
- synpath/remote.py +195 -0
- synpath/server/__init__.py +98 -0
- synpath/server/__main__.py +118 -0
- synpath/server/api.py +439 -0
- synpath/server/errors.py +87 -0
- synpath/server/local.py +96 -0
- synpath/server/models.py +75 -0
- synpath/server/serve.py +236 -0
- synpath/server/store.py +363 -0
- synpath/server/trading.py +764 -0
- synpath/trading/__init__.py +79 -0
- synpath/trading/__main__.py +69 -0
- synpath/trading/base.py +126 -0
- synpath/trading/credentials.py +400 -0
- synpath/trading/errors.py +94 -0
- synpath/trading/init.py +233 -0
- synpath/trading/instruments.py +162 -0
- synpath/trading/kalshi.py +957 -0
- synpath/trading/limiter.py +177 -0
- synpath/trading/money.py +172 -0
- synpath/trading/polymarket.py +1362 -0
- synpath/trading/polymarket_signing.py +478 -0
- synpath/trading/polymarket_us.py +705 -0
- synpath/trading/polymarket_us_exchange.py +825 -0
- synpath/trading/types.py +414 -0
- synpath/types.py +608 -0
- synpath/ws/__init__.py +55 -0
- synpath/ws/base.py +544 -0
- synpath/ws/grpc.py +578 -0
- synpath/ws/kalshi.py +418 -0
- synpath/ws/polymarket.py +430 -0
- synpath/ws/polymarket_us.py +299 -0
- synpath/ws/polymarket_us_exchange.py +754 -0
- synpath-0.1.0.dist-info/METADATA +224 -0
- synpath-0.1.0.dist-info/RECORD +77 -0
- synpath-0.1.0.dist-info/WHEEL +4 -0
- synpath-0.1.0.dist-info/entry_points.txt +2 -0
- synpath-0.1.0.dist-info/licenses/LICENSE +21 -0
synpath/matching.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""Cross-venue matching: "this market/event on venue A -- what is it on venue B?"
|
|
2
|
+
|
|
3
|
+
Every other call in this package asks one venue about itself. Matching takes both catalogs and a
|
|
4
|
+
judgement about whether two differently worded listings settle on the same fact, which no single
|
|
5
|
+
venue adapter can make -- so it is answered by a hosted matching service over HTTP, not computed
|
|
6
|
+
here. This module is the HTTP half; the actual matching (event identity, then market alignment)
|
|
7
|
+
lives in the service it calls.
|
|
8
|
+
|
|
9
|
+
The query is anchored, never a text search: give the market or event you already hold as a
|
|
10
|
+
Synpath id (`kalshi:KXHIGHTATL-26SEP23-B80`, `polymarket:2252244`), get back what the other
|
|
11
|
+
venue(s) call the same thing. Nothing here computes a similarity score or a confidence -- a
|
|
12
|
+
match is a deterministic parse both listings landed on, not a judgement call, and a caller that
|
|
13
|
+
wants to browse for candidates does that with each venue's own `fetch_markets(query=...)`.
|
|
14
|
+
|
|
15
|
+
Three answers, always:
|
|
16
|
+
|
|
17
|
+
* the anchor is not a listing this service knows -- `MarketNotFound` / `BadSymbol`
|
|
18
|
+
* it is, and the other venue has the same question -- a `MarketLink` / a list of ids
|
|
19
|
+
* it is, and the other venue does not -- `None`
|
|
20
|
+
|
|
21
|
+
That third case is a real, common answer (most brackets on a weather card never line up across
|
|
22
|
+
venues; most native events are single-venue), and it is never confused with the first: a caller
|
|
23
|
+
that gets `None` knows the anchor is good and there is simply nothing to pair it with.
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from typing import Any
|
|
28
|
+
|
|
29
|
+
from . import ids
|
|
30
|
+
from .base import HttpClient
|
|
31
|
+
from .errors import BadRequest
|
|
32
|
+
from .hosted import call, hosted_client
|
|
33
|
+
from .types import EventMatch, MarketLink, MarketMatch
|
|
34
|
+
|
|
35
|
+
BASE_URL_ENV = "SYNPATH_MATCHING_URL"
|
|
36
|
+
DEFAULT_URL = "https://api.synpath.dev"
|
|
37
|
+
"""Where the hosted matching service lives: Synpath's own, unless `base_url=` or
|
|
38
|
+
`SYNPATH_MATCHING_URL` points somewhere else (a staging deployment, a local one)."""
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _client(base_url: str | None, http_client: Any = None) -> HttpClient:
|
|
42
|
+
return hosted_client(base_url=base_url, env=BASE_URL_ENV, default=DEFAULT_URL, http_client=http_client)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _validate(anchor: str) -> None:
|
|
46
|
+
"""Same shape check the service itself makes, run here first so a caller gets `BadRequest`
|
|
47
|
+
without a round trip for something that could never have answered."""
|
|
48
|
+
venue, sep, native = anchor.partition(":")
|
|
49
|
+
if not sep or not native or venue not in ids.VENUES:
|
|
50
|
+
raise BadRequest(
|
|
51
|
+
f"{anchor!r} is not a Synpath id: expected 'venue:native_id' with venue one of {', '.join(ids.VENUES)}"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def match_market(anchor: str, *, base_url: str | None = None, client: Any = None,
|
|
56
|
+
api_key: str | None = None) -> MarketMatch:
|
|
57
|
+
"""The other venue's listing of the same proposition as `anchor`.
|
|
58
|
+
|
|
59
|
+
`anchor` is a Synpath id for a market you already hold, never a query -- browse each venue's
|
|
60
|
+
own catalog with `fetch_markets(query=...)` first if you do not have one yet. `client` is an
|
|
61
|
+
injectable `httpx.Client`, for tests and for a caller pooling connections itself.
|
|
62
|
+
|
|
63
|
+
Raises `MarketNotFound` when `anchor` is not a listing this service knows. Otherwise returns
|
|
64
|
+
a `MarketMatch` whose `matched` is a `MarketLink` when the other venue has the same
|
|
65
|
+
proposition, or `None` when the anchor is a real listing with nothing to pair it with -- a
|
|
66
|
+
different, and much more common, answer than "no such market".
|
|
67
|
+
"""
|
|
68
|
+
_validate(anchor)
|
|
69
|
+
# Only the client this call built for itself is closed after, never one the caller owns.
|
|
70
|
+
body = call(_client(base_url, client), "GET", "/match/market", params={"id": anchor},
|
|
71
|
+
api_key=api_key, owned=client is None, use_stored=True)
|
|
72
|
+
return MarketMatch.model_validate(body)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def match_event(anchor: str, *, base_url: str | None = None, client: Any = None,
|
|
76
|
+
api_key: str | None = None) -> EventMatch:
|
|
77
|
+
"""The other venues' native events that are the same event as `anchor`.
|
|
78
|
+
|
|
79
|
+
One native event on one venue is often several on another (a game split by market type, a
|
|
80
|
+
recurring series split by window), so each entry in `events` is a list, not a single id, and
|
|
81
|
+
is `None` rather than `[]` when that venue lists nothing on the same event.
|
|
82
|
+
"""
|
|
83
|
+
_validate(anchor)
|
|
84
|
+
body = call(_client(base_url, client), "GET", "/match/event", params={"id": anchor},
|
|
85
|
+
api_key=api_key, owned=client is None, use_stored=True)
|
|
86
|
+
return EventMatch.model_validate(body)
|