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.
Files changed (77) hide show
  1. synpath/__init__.py +183 -0
  2. synpath/__main__.py +66 -0
  3. synpath/base.py +723 -0
  4. synpath/bucket.py +154 -0
  5. synpath/client.py +356 -0
  6. synpath/engine/__init__.py +37 -0
  7. synpath/engine/__main__.py +354 -0
  8. synpath/engine/alerts.py +170 -0
  9. synpath/engine/engine.py +888 -0
  10. synpath/engine/eod.py +154 -0
  11. synpath/engine/events.py +140 -0
  12. synpath/engine/fair_values.py +117 -0
  13. synpath/engine/feeds.py +220 -0
  14. synpath/engine/journal.py +907 -0
  15. synpath/engine/ledger.py +353 -0
  16. synpath/engine/orders/__init__.py +42 -0
  17. synpath/engine/orders/base.py +441 -0
  18. synpath/engine/orders/day.py +72 -0
  19. synpath/engine/orders/iceberg.py +121 -0
  20. synpath/engine/orders/manager.py +223 -0
  21. synpath/engine/orders/oco.py +255 -0
  22. synpath/engine/orders/peg.py +168 -0
  23. synpath/engine/orders/routed.py +496 -0
  24. synpath/engine/orders/stop.py +240 -0
  25. synpath/engine/orders/taker.py +187 -0
  26. synpath/engine/orders/twap.py +190 -0
  27. synpath/engine/paper.py +532 -0
  28. synpath/engine/reconcile.py +279 -0
  29. synpath/engine/risk.py +403 -0
  30. synpath/engine/router.py +261 -0
  31. synpath/errors.py +98 -0
  32. synpath/history.py +71 -0
  33. synpath/hosted.py +86 -0
  34. synpath/hosted_auth.py +201 -0
  35. synpath/ids.py +61 -0
  36. synpath/kalshi.py +1378 -0
  37. synpath/matching.py +86 -0
  38. synpath/polymarket.py +1004 -0
  39. synpath/polymarket_us.py +989 -0
  40. synpath/remote.py +195 -0
  41. synpath/server/__init__.py +98 -0
  42. synpath/server/__main__.py +118 -0
  43. synpath/server/api.py +439 -0
  44. synpath/server/errors.py +87 -0
  45. synpath/server/local.py +96 -0
  46. synpath/server/models.py +75 -0
  47. synpath/server/serve.py +236 -0
  48. synpath/server/store.py +363 -0
  49. synpath/server/trading.py +764 -0
  50. synpath/trading/__init__.py +79 -0
  51. synpath/trading/__main__.py +69 -0
  52. synpath/trading/base.py +126 -0
  53. synpath/trading/credentials.py +400 -0
  54. synpath/trading/errors.py +94 -0
  55. synpath/trading/init.py +233 -0
  56. synpath/trading/instruments.py +162 -0
  57. synpath/trading/kalshi.py +957 -0
  58. synpath/trading/limiter.py +177 -0
  59. synpath/trading/money.py +172 -0
  60. synpath/trading/polymarket.py +1362 -0
  61. synpath/trading/polymarket_signing.py +478 -0
  62. synpath/trading/polymarket_us.py +705 -0
  63. synpath/trading/polymarket_us_exchange.py +825 -0
  64. synpath/trading/types.py +414 -0
  65. synpath/types.py +608 -0
  66. synpath/ws/__init__.py +55 -0
  67. synpath/ws/base.py +544 -0
  68. synpath/ws/grpc.py +578 -0
  69. synpath/ws/kalshi.py +418 -0
  70. synpath/ws/polymarket.py +430 -0
  71. synpath/ws/polymarket_us.py +299 -0
  72. synpath/ws/polymarket_us_exchange.py +754 -0
  73. synpath-0.1.0.dist-info/METADATA +224 -0
  74. synpath-0.1.0.dist-info/RECORD +77 -0
  75. synpath-0.1.0.dist-info/WHEEL +4 -0
  76. synpath-0.1.0.dist-info/entry_points.txt +2 -0
  77. 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)