xoomar 0.1.0__tar.gz

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.
xoomar-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 XOOMAR
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
xoomar-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: xoomar
3
+ Version: 0.1.0
4
+ Summary: Client for the XOOMAR free market data API: short interest, insider trades, COT, funding rates, Fed liquidity, SEC filings and more.
5
+ Author-email: XOOMAR <info@xoomar.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://xoomar.com/markets/api
8
+ Project-URL: Documentation, https://xoomar.com/markets/api
9
+ Project-URL: Source, https://github.com/xoomar-llc/xoomar-python
10
+ Project-URL: Data, https://xoomar.com/markets
11
+ Keywords: market data,sec,finra,cot,short interest,insider trading,crypto,api
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Office/Business :: Financial
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Dynamic: license-file
23
+
24
+ # xoomar
25
+
26
+ Python client for the [XOOMAR](https://xoomar.com/markets) free market data API: 29 datasets from primary sources (SEC EDGAR and XBRL, FINRA, CFTC, the Federal Reserve, USAspending, exchange APIs) as clean JSON, no key needed to start.
27
+
28
+ ```bash
29
+ pip install xoomar
30
+ ```
31
+
32
+ ```python
33
+ from xoomar import Xoomar
34
+
35
+ x = Xoomar() # 30 requests a minute; Xoomar(api_key="...") for 120 with a free key
36
+
37
+ x.short_interest("GME")[-1] # FINRA short interest, latest settlement
38
+ x.short_volume("GME", days=30) # FINRA daily short sale volume
39
+ x.fails_to_deliver("GME") # SEC fails to deliver
40
+ x.insiders("NVDA") # SEC Form 4 trades
41
+ x.large_holders("HIMS") # Schedule 13D and 13G holders
42
+ x.financials("AAPL")["quarterly"] # XBRL income statement by quarter
43
+ x.fund_holders("AMZN") # which tracked 13F managers hold it
44
+ x.cot("gold") # CFTC positioning history
45
+ x.fed_liquidity()[-1] # net liquidity, this week
46
+ x.funding_rates() # perpetual funding on three exchanges
47
+ x.bitcoin_treasuries() # bitcoin on public balance sheets
48
+ x.form_d(days=7) # private placements filed this week
49
+ x.federal_contracts(ticker="LMT") # federal contract actions
50
+ ```
51
+
52
+ Every method returns the `data` part of the response; `x.last_meta` holds `updatedAt`, `source`, `license` and `attribution` from the last call. `x.get("short-interest", symbol="TSLA")` calls any endpoint directly and `x.csv("short-interest/csv")` fetches a CSV download.
53
+
54
+ Full endpoint reference, fields and limits: https://xoomar.com/markets/api
55
+
56
+ ## Datasets
57
+
58
+ Short interest, daily short volume, fails to deliver, insider trades (Form 4), planned sales (Form 144), large holders (13D/13G), 13F fund holdings, company financials and buybacks (XBRL), 8-K events, structured products, federal contracts, Form D private placements, the IPO pipeline, bitcoin treasuries, CFTC COT, funding rates, open interest, liquidations, options, whale positions, sentiment, signals, ETF flows, prediction markets, Fed liquidity, macro, policy rates, economic calendar.
59
+
60
+ ## Rate limits and keys
61
+
62
+ 30 requests a minute per IP without a key. A free account at https://xoomar.com/signup gives a key for 120 a minute; pass it as `Xoomar(api_key=...)`. A 429 raises `XoomarRateLimited` with `retry_after`.
63
+
64
+ ## Attribution
65
+
66
+ The data is free to use, including commercially. When you republish it, on a site, in an app, in an article, in a dataset or a chart, credit XOOMAR with a visible link to the dataset page on xoomar.com. Terms: https://xoomar.com/terms
67
+
68
+ ## License
69
+
70
+ MIT, XOOMAR.
xoomar-0.1.0/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # xoomar
2
+
3
+ Python client for the [XOOMAR](https://xoomar.com/markets) free market data API: 29 datasets from primary sources (SEC EDGAR and XBRL, FINRA, CFTC, the Federal Reserve, USAspending, exchange APIs) as clean JSON, no key needed to start.
4
+
5
+ ```bash
6
+ pip install xoomar
7
+ ```
8
+
9
+ ```python
10
+ from xoomar import Xoomar
11
+
12
+ x = Xoomar() # 30 requests a minute; Xoomar(api_key="...") for 120 with a free key
13
+
14
+ x.short_interest("GME")[-1] # FINRA short interest, latest settlement
15
+ x.short_volume("GME", days=30) # FINRA daily short sale volume
16
+ x.fails_to_deliver("GME") # SEC fails to deliver
17
+ x.insiders("NVDA") # SEC Form 4 trades
18
+ x.large_holders("HIMS") # Schedule 13D and 13G holders
19
+ x.financials("AAPL")["quarterly"] # XBRL income statement by quarter
20
+ x.fund_holders("AMZN") # which tracked 13F managers hold it
21
+ x.cot("gold") # CFTC positioning history
22
+ x.fed_liquidity()[-1] # net liquidity, this week
23
+ x.funding_rates() # perpetual funding on three exchanges
24
+ x.bitcoin_treasuries() # bitcoin on public balance sheets
25
+ x.form_d(days=7) # private placements filed this week
26
+ x.federal_contracts(ticker="LMT") # federal contract actions
27
+ ```
28
+
29
+ Every method returns the `data` part of the response; `x.last_meta` holds `updatedAt`, `source`, `license` and `attribution` from the last call. `x.get("short-interest", symbol="TSLA")` calls any endpoint directly and `x.csv("short-interest/csv")` fetches a CSV download.
30
+
31
+ Full endpoint reference, fields and limits: https://xoomar.com/markets/api
32
+
33
+ ## Datasets
34
+
35
+ Short interest, daily short volume, fails to deliver, insider trades (Form 4), planned sales (Form 144), large holders (13D/13G), 13F fund holdings, company financials and buybacks (XBRL), 8-K events, structured products, federal contracts, Form D private placements, the IPO pipeline, bitcoin treasuries, CFTC COT, funding rates, open interest, liquidations, options, whale positions, sentiment, signals, ETF flows, prediction markets, Fed liquidity, macro, policy rates, economic calendar.
36
+
37
+ ## Rate limits and keys
38
+
39
+ 30 requests a minute per IP without a key. A free account at https://xoomar.com/signup gives a key for 120 a minute; pass it as `Xoomar(api_key=...)`. A 429 raises `XoomarRateLimited` with `retry_after`.
40
+
41
+ ## Attribution
42
+
43
+ The data is free to use, including commercially. When you republish it, on a site, in an app, in an article, in a dataset or a chart, credit XOOMAR with a visible link to the dataset page on xoomar.com. Terms: https://xoomar.com/terms
44
+
45
+ ## License
46
+
47
+ MIT, XOOMAR.
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "xoomar"
7
+ version = "0.1.0"
8
+ description = "Client for the XOOMAR free market data API: short interest, insider trades, COT, funding rates, Fed liquidity, SEC filings and more."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "XOOMAR", email = "info@xoomar.com" }]
13
+ keywords = ["market data", "sec", "finra", "cot", "short interest", "insider trading", "crypto", "api"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "Intended Audience :: Financial and Insurance Industry",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Topic :: Office/Business :: Financial",
22
+ ]
23
+ dependencies = []
24
+
25
+ [project.urls]
26
+ Homepage = "https://xoomar.com/markets/api"
27
+ Documentation = "https://xoomar.com/markets/api"
28
+ Source = "https://github.com/xoomar-llc/xoomar-python"
29
+ Data = "https://xoomar.com/markets"
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"]
xoomar-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,230 @@
1
+ """Client for the XOOMAR free market data API (https://xoomar.com/markets/api).
2
+
3
+ Every method returns the ``data`` part of the JSON response as plain Python
4
+ objects (lists or dicts). The full envelope of the last call, with
5
+ ``updatedAt``, ``source``, ``license`` and ``attribution``, is on
6
+ ``client.last_meta``.
7
+
8
+ The data is free with attribution: when you republish it, link to the
9
+ dataset page on xoomar.com. See https://xoomar.com/terms.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import urllib.error
16
+ import urllib.parse
17
+ import urllib.request
18
+ from typing import Any, Dict, Optional
19
+
20
+ __version__ = "0.1.0"
21
+ __all__ = ["Xoomar", "XoomarError", "XoomarRateLimited"]
22
+
23
+ DEFAULT_BASE_URL = "https://xoomar.com"
24
+
25
+
26
+ class XoomarError(Exception):
27
+ """An HTTP or API error. ``status`` is the HTTP status, ``body`` the response text."""
28
+
29
+ def __init__(self, status: int, body: str, url: str):
30
+ super().__init__(f"HTTP {status} from {url}: {body[:200]}")
31
+ self.status = status
32
+ self.body = body
33
+ self.url = url
34
+
35
+
36
+ class XoomarRateLimited(XoomarError):
37
+ """429: 30 requests a minute without a key, 120 with a free key from https://xoomar.com/signup."""
38
+
39
+ def __init__(self, status: int, body: str, url: str, retry_after: Optional[int]):
40
+ super().__init__(status, body, url)
41
+ self.retry_after = retry_after
42
+
43
+
44
+ class Xoomar:
45
+ """
46
+ >>> from xoomar import Xoomar
47
+ >>> x = Xoomar() # or Xoomar(api_key="...") for 120 requests a minute
48
+ >>> x.short_interest("GME")[-1]
49
+ {'settlementDate': '2026-08-14', 'symbol': 'GME', 'shortQty': 54036583, ...}
50
+ """
51
+
52
+ def __init__(self, api_key: Optional[str] = None, base_url: str = DEFAULT_BASE_URL, timeout: float = 30.0, user_agent: Optional[str] = None):
53
+ self.api_key = api_key
54
+ self.base_url = base_url.rstrip("/")
55
+ self.timeout = timeout
56
+ self.user_agent = user_agent or f"xoomar-python/{__version__}"
57
+ self.last_meta: Dict[str, Any] = {}
58
+
59
+ # ── transport ──
60
+
61
+ def get(self, path: str, **params: Any) -> Any:
62
+ """GET ``/api/markets/<path>`` with query parameters; returns the ``data`` field."""
63
+ query = {k: v for k, v in params.items() if v is not None}
64
+ url = f"{self.base_url}/api/markets/{path.lstrip('/')}"
65
+ if query:
66
+ url += "?" + urllib.parse.urlencode(query)
67
+ headers = {"Accept": "application/json", "User-Agent": self.user_agent}
68
+ if self.api_key:
69
+ headers["x-api-key"] = self.api_key
70
+ req = urllib.request.Request(url, headers=headers)
71
+ try:
72
+ with urllib.request.urlopen(req, timeout=self.timeout) as res:
73
+ payload = json.loads(res.read().decode("utf-8"))
74
+ except urllib.error.HTTPError as e:
75
+ body = e.read().decode("utf-8", "replace") if e.fp else ""
76
+ if e.code == 429:
77
+ ra = e.headers.get("Retry-After") if e.headers else None
78
+ raise XoomarRateLimited(e.code, body, url, int(ra) if ra and ra.isdigit() else None) from None
79
+ raise XoomarError(e.code, body, url) from None
80
+ if isinstance(payload, dict) and "data" in payload:
81
+ self.last_meta = {k: v for k, v in payload.items() if k != "data"}
82
+ return payload["data"]
83
+ self.last_meta = {}
84
+ return payload
85
+
86
+ def csv(self, path: str, **params: Any) -> str:
87
+ """The CSV download for a dataset, e.g. ``csv("short-interest/csv")``, as text."""
88
+ query = {k: v for k, v in params.items() if v is not None}
89
+ url = f"{self.base_url}/api/markets/{path.lstrip('/')}"
90
+ if query:
91
+ url += "?" + urllib.parse.urlencode(query)
92
+ headers = {"Accept": "text/csv", "User-Agent": self.user_agent}
93
+ if self.api_key:
94
+ headers["x-api-key"] = self.api_key
95
+ req = urllib.request.Request(url, headers=headers)
96
+ try:
97
+ with urllib.request.urlopen(req, timeout=self.timeout) as res:
98
+ return res.read().decode("utf-8")
99
+ except urllib.error.HTTPError as e:
100
+ raise XoomarError(e.code, e.read().decode("utf-8", "replace") if e.fp else "", url) from None
101
+
102
+ # ── companies (SEC and FINRA) ──
103
+
104
+ def short_interest(self, symbol: Optional[str] = None) -> Any:
105
+ """FINRA short interest: history for a symbol, or the latest settlement's highest days to cover."""
106
+ return self.get("short-interest", symbol=symbol)
107
+
108
+ def short_volume(self, symbol: Optional[str] = None, days: Optional[int] = None, sort: Optional[str] = None) -> Any:
109
+ """FINRA daily short sale volume: history for a symbol, or the latest day (sort="shares" for largest volumes)."""
110
+ return self.get("short-volume", symbol=symbol, days=days, sort=sort)
111
+
112
+ def fails_to_deliver(self, symbol: Optional[str] = None) -> Any:
113
+ """SEC fails to deliver: history for a symbol, or the latest settlement date's largest fails."""
114
+ return self.get("fails-to-deliver", symbol=symbol)
115
+
116
+ def insiders(self, ticker: Optional[str] = None, type: Optional[str] = None, window: Optional[str] = None) -> Any:
117
+ """SEC Form 4 trades: a ticker's history, or the latest across companies (type="buys", window="7d")."""
118
+ if ticker:
119
+ return self.get(f"insiders/{ticker.lower()}")
120
+ return self.get("insiders", type=type, window=window)
121
+
122
+ def planned_sales(self, symbol: Optional[str] = None, days: Optional[int] = None) -> Any:
123
+ """SEC Form 144 notices of proposed sale."""
124
+ return self.get("planned-sales", symbol=symbol, days=days)
125
+
126
+ def large_holders(self, symbol: Optional[str] = None, form: Optional[str] = None, days: Optional[int] = None, new: Optional[bool] = None, sort: Optional[str] = None) -> Any:
127
+ """Schedule 13D and 13G cover pages (form="13D" or "13G")."""
128
+ return self.get("large-holders", symbol=symbol, form=form, days=days, new=1 if new else None, sort=sort)
129
+
130
+ def financials(self, symbol: str) -> Any:
131
+ """XBRL quarterly income, annual statements and latest balance sheet for a ticker."""
132
+ return self.get("financials", symbol=symbol)
133
+
134
+ def buybacks(self) -> Any:
135
+ """Largest share repurchases per company in its latest fiscal year."""
136
+ return self.get("buybacks")
137
+
138
+ def fund_holders(self, ticker: str) -> Any:
139
+ """Tracked 13F managers holding a ticker at their latest filing."""
140
+ return self.get("funds", ticker=ticker)
141
+
142
+ def fund(self, slug: str) -> Any:
143
+ """One tracked manager's latest 13F portfolio (e.g. "berkshire-hathaway")."""
144
+ return self.get(f"funds/{slug}")
145
+
146
+ def events(self, ticker: Optional[str] = None, item: Optional[str] = None, days: Optional[int] = None) -> Any:
147
+ """SEC 8-K material events."""
148
+ return self.get("events", ticker=ticker, item=item, days=days)
149
+
150
+ def structured_products(self, **params: Any) -> Any:
151
+ """Bank structured notes from 424B2 and FWP filings (issuer=, underlying=, noteType=, days=, cursor=)."""
152
+ return self.get("structured-products", **params)
153
+
154
+ def federal_contracts(self, ticker: Optional[str] = None, days: Optional[int] = None, by: Optional[str] = None, listed: Optional[bool] = None) -> Any:
155
+ """Largest US federal contract actions (by="ticker" sums by listed parent)."""
156
+ return self.get("federal-contracts", ticker=ticker, days=days, by=by, listed=1 if listed else None)
157
+
158
+ # ── markets ──
159
+
160
+ def funding_rates(self, slug: Optional[str] = None) -> Any:
161
+ """Perpetual futures funding on Binance, Bybit and OKX; a symbol slug (e.g. "btc") gives its history."""
162
+ return self.get(f"funding-rates/{slug}") if slug else self.get("funding-rates")
163
+
164
+ def open_interest(self, slug: str) -> Any:
165
+ """Hourly open interest history for a symbol slug."""
166
+ return self.get(f"open-interest/{slug}")
167
+
168
+ def liquidations(self) -> Any:
169
+ """Recent crypto liquidations across exchanges."""
170
+ return self.get("liquidations")
171
+
172
+ def options(self, currency: str = "BTC") -> Any:
173
+ """Deribit options: put/call, max pain, DVOL for BTC or ETH."""
174
+ return self.get(f"options/{currency}")
175
+
176
+ def whales(self, coin: Optional[str] = None) -> Any:
177
+ """Hyperliquid whale positions, all or for one coin."""
178
+ return self.get(f"whales/{coin}") if coin else self.get("whales")
179
+
180
+ def cot(self, market: Optional[str] = None) -> Any:
181
+ """CFTC Commitments of Traders: the latest report across markets, or one market's history (e.g. "gold")."""
182
+ return self.get(f"cot/{market}") if market else self.get("cot")
183
+
184
+ def sentiment(self, asset: Optional[str] = None, kind: Optional[str] = None, window: Optional[str] = None) -> Any:
185
+ """Composite sentiment scores, all assets or one asset slug."""
186
+ return self.get(f"sentiment/{asset}") if asset else self.get("sentiment", kind=kind, window=window)
187
+
188
+ def signals(self, asset: Optional[str] = None) -> Any:
189
+ """Rules-based composite signals."""
190
+ return self.get(f"signals/{asset}") if asset else self.get("signals")
191
+
192
+ def etf_flows(self, asset: Optional[str] = None, days: Optional[int] = None) -> Any:
193
+ """Spot bitcoin and ether ETF flows."""
194
+ return self.get("etf-flows", asset=asset, days=days)
195
+
196
+ def bitcoin_treasuries(self) -> Any:
197
+ """Bitcoin held by public companies from their SEC filings."""
198
+ return self.get("bitcoin-treasuries")
199
+
200
+ def predictions(self, category: Optional[str] = None) -> Any:
201
+ """Polymarket odds."""
202
+ return self.get("predictions", category=category)
203
+
204
+ # ── macro ──
205
+
206
+ def macro(self, series: Optional[str] = None, from_: Optional[str] = None, to: Optional[str] = None) -> Any:
207
+ """US Treasury yield curve, spreads, stablecoin supply (series=, from=, to=)."""
208
+ return self.get("macro", series=series, **{"from": from_, "to": to})
209
+
210
+ def fed_liquidity(self, series: Optional[str] = None, limit: Optional[int] = None) -> Any:
211
+ """Weekly net liquidity with components, or one FRED series (WALCL, WRESBAL, RRPONTSYD, WTREGEN, SOFR, EFFR, IORB, WSHOSHO)."""
212
+ return self.get("fed-liquidity", series=series, limit=limit)
213
+
214
+ def rates(self, country: Optional[str] = None) -> Any:
215
+ """Central bank policy rates: all economies, or one country code's history (e.g. "us")."""
216
+ return self.get(f"rates/{country}") if country else self.get("rates")
217
+
218
+ def calendar(self, from_: Optional[str] = None, to: Optional[str] = None, importance: Optional[str] = None) -> Any:
219
+ """US economic calendar with consensus and actuals."""
220
+ return self.get("calendar", importance=importance, **{"from": from_, "to": to})
221
+
222
+ # ── filings and offerings ──
223
+
224
+ def form_d(self, days: Optional[int] = None, funds: Optional[bool] = None, cik: Optional[str] = None, sort: Optional[str] = None, amendments: Optional[bool] = None) -> Any:
225
+ """SEC Form D private placements: largest raises in a window, one issuer by CIK, or sort="recent"."""
226
+ return self.get("startup-funding", days=days, funds=1 if funds else None, cik=cik, sort=sort, amendments=1 if amendments else None)
227
+
228
+ def ipos(self, form: Optional[str] = None, days: Optional[int] = None, new: Optional[bool] = None) -> Any:
229
+ """IPO pipeline filings (form="S-1,F-1", "424B4", "RW", "EFFECT"; new=True for filers not yet listed)."""
230
+ return self.get("ipos", form=form, days=days, new=1 if new else None)
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: xoomar
3
+ Version: 0.1.0
4
+ Summary: Client for the XOOMAR free market data API: short interest, insider trades, COT, funding rates, Fed liquidity, SEC filings and more.
5
+ Author-email: XOOMAR <info@xoomar.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://xoomar.com/markets/api
8
+ Project-URL: Documentation, https://xoomar.com/markets/api
9
+ Project-URL: Source, https://github.com/xoomar-llc/xoomar-python
10
+ Project-URL: Data, https://xoomar.com/markets
11
+ Keywords: market data,sec,finra,cot,short interest,insider trading,crypto,api
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Office/Business :: Financial
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Dynamic: license-file
23
+
24
+ # xoomar
25
+
26
+ Python client for the [XOOMAR](https://xoomar.com/markets) free market data API: 29 datasets from primary sources (SEC EDGAR and XBRL, FINRA, CFTC, the Federal Reserve, USAspending, exchange APIs) as clean JSON, no key needed to start.
27
+
28
+ ```bash
29
+ pip install xoomar
30
+ ```
31
+
32
+ ```python
33
+ from xoomar import Xoomar
34
+
35
+ x = Xoomar() # 30 requests a minute; Xoomar(api_key="...") for 120 with a free key
36
+
37
+ x.short_interest("GME")[-1] # FINRA short interest, latest settlement
38
+ x.short_volume("GME", days=30) # FINRA daily short sale volume
39
+ x.fails_to_deliver("GME") # SEC fails to deliver
40
+ x.insiders("NVDA") # SEC Form 4 trades
41
+ x.large_holders("HIMS") # Schedule 13D and 13G holders
42
+ x.financials("AAPL")["quarterly"] # XBRL income statement by quarter
43
+ x.fund_holders("AMZN") # which tracked 13F managers hold it
44
+ x.cot("gold") # CFTC positioning history
45
+ x.fed_liquidity()[-1] # net liquidity, this week
46
+ x.funding_rates() # perpetual funding on three exchanges
47
+ x.bitcoin_treasuries() # bitcoin on public balance sheets
48
+ x.form_d(days=7) # private placements filed this week
49
+ x.federal_contracts(ticker="LMT") # federal contract actions
50
+ ```
51
+
52
+ Every method returns the `data` part of the response; `x.last_meta` holds `updatedAt`, `source`, `license` and `attribution` from the last call. `x.get("short-interest", symbol="TSLA")` calls any endpoint directly and `x.csv("short-interest/csv")` fetches a CSV download.
53
+
54
+ Full endpoint reference, fields and limits: https://xoomar.com/markets/api
55
+
56
+ ## Datasets
57
+
58
+ Short interest, daily short volume, fails to deliver, insider trades (Form 4), planned sales (Form 144), large holders (13D/13G), 13F fund holdings, company financials and buybacks (XBRL), 8-K events, structured products, federal contracts, Form D private placements, the IPO pipeline, bitcoin treasuries, CFTC COT, funding rates, open interest, liquidations, options, whale positions, sentiment, signals, ETF flows, prediction markets, Fed liquidity, macro, policy rates, economic calendar.
59
+
60
+ ## Rate limits and keys
61
+
62
+ 30 requests a minute per IP without a key. A free account at https://xoomar.com/signup gives a key for 120 a minute; pass it as `Xoomar(api_key=...)`. A 429 raises `XoomarRateLimited` with `retry_after`.
63
+
64
+ ## Attribution
65
+
66
+ The data is free to use, including commercially. When you republish it, on a site, in an app, in an article, in a dataset or a chart, credit XOOMAR with a visible link to the dataset page on xoomar.com. Terms: https://xoomar.com/terms
67
+
68
+ ## License
69
+
70
+ MIT, XOOMAR.
@@ -0,0 +1,9 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/xoomar/__init__.py
5
+ src/xoomar.egg-info/PKG-INFO
6
+ src/xoomar.egg-info/SOURCES.txt
7
+ src/xoomar.egg-info/dependency_links.txt
8
+ src/xoomar.egg-info/top_level.txt
9
+ tests/test_client.py
@@ -0,0 +1 @@
1
+ xoomar
@@ -0,0 +1,47 @@
1
+ import io
2
+ import json
3
+ import unittest
4
+ from unittest import mock
5
+
6
+ from xoomar import Xoomar, XoomarRateLimited
7
+
8
+
9
+ class FakeResponse(io.BytesIO):
10
+ def __enter__(self):
11
+ return self
12
+
13
+ def __exit__(self, *a):
14
+ return False
15
+
16
+
17
+ class ClientTests(unittest.TestCase):
18
+ def test_get_returns_data_and_keeps_meta(self):
19
+ payload = {"data": [{"symbol": "GME"}], "updatedAt": "2026-09-13T00:00:00Z", "source": "xoomar.com", "attribution": "Free with attribution"}
20
+ with mock.patch("urllib.request.urlopen", return_value=FakeResponse(json.dumps(payload).encode())) as u:
21
+ x = Xoomar(api_key="k")
22
+ rows = x.short_interest("GME")
23
+ self.assertEqual(rows, [{"symbol": "GME"}])
24
+ self.assertEqual(x.last_meta["source"], "xoomar.com")
25
+ req = u.call_args[0][0]
26
+ self.assertEqual(req.full_url, "https://xoomar.com/api/markets/short-interest?symbol=GME")
27
+ self.assertEqual(req.get_header("X-api-key"), "k")
28
+
29
+ def test_path_methods(self):
30
+ with mock.patch("urllib.request.urlopen", return_value=FakeResponse(b'{"data": []}')) as u:
31
+ Xoomar().insiders("nvda")
32
+ self.assertEqual(u.call_args[0][0].full_url, "https://xoomar.com/api/markets/insiders/nvda")
33
+ with mock.patch("urllib.request.urlopen", return_value=FakeResponse(b'{"data": []}')) as u:
34
+ Xoomar().large_holders("HIMS", form="13D", new=True)
35
+ self.assertEqual(u.call_args[0][0].full_url, "https://xoomar.com/api/markets/large-holders?symbol=HIMS&form=13D&new=1")
36
+
37
+ def test_rate_limit(self):
38
+ import urllib.error
39
+ err = urllib.error.HTTPError("https://xoomar.com/api/markets/cot", 429, "Too Many Requests", {"Retry-After": "12"}, io.BytesIO(b"slow down"))
40
+ with mock.patch("urllib.request.urlopen", side_effect=err):
41
+ with self.assertRaises(XoomarRateLimited) as ctx:
42
+ Xoomar().cot()
43
+ self.assertEqual(ctx.exception.retry_after, 12)
44
+
45
+
46
+ if __name__ == "__main__":
47
+ unittest.main()