openbb-tensorust 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.
@@ -0,0 +1,52 @@
1
+ """OpenBB provider and router extension for Tensorust data.
2
+
3
+ Private credit loan marks from SEC BDC filings, federal contractor credit,
4
+ banned-vendor exposure in federal research awards, and No Surprises Act IDR
5
+ offer bands. Free previews without a key; set ``tensorust_api_key`` (or the
6
+ ``TENSORUST_API_KEY`` environment variable) for full records.
7
+ """
8
+
9
+ from openbb_core.provider.abstract.provider import Provider
10
+
11
+ from openbb_tensorust.models.contractor import (
12
+ TensorustContractorCreditFetcher,
13
+ TensorustContractorWatchFetcher,
14
+ )
15
+ from openbb_tensorust.models.credit import (
16
+ TensorustBdcLoanMarksFetcher,
17
+ TensorustCreditDisagreementsFetcher,
18
+ TensorustCreditQ3CutsFetcher,
19
+ )
20
+ from openbb_tensorust.models.exposure import TensorustExposureInstitutionFetcher
21
+ from openbb_tensorust.models.idr import TensorustIdrOfferFetcher
22
+
23
+ __version__ = "0.1.0"
24
+
25
+ tensorust_provider = Provider(
26
+ name="tensorust",
27
+ website="https://tensorust.com",
28
+ description=(
29
+ "Tensorust builds entity-level datasets from US public records: what BDC (private credit) "
30
+ "lenders mark each first-lien loan at, which federal contractors sit on marked-down loans, "
31
+ "which federal research awards pay for work by vendors on banned-vendor lists, and the "
32
+ "No Surprises Act IDR offer band by code, payer and state. Every command answers a free "
33
+ "preview without a key."
34
+ ),
35
+ credentials=["api_key"],
36
+ fetcher_dict={
37
+ "TensorustBdcLoanMarks": TensorustBdcLoanMarksFetcher,
38
+ "TensorustCreditDisagreements": TensorustCreditDisagreementsFetcher,
39
+ "TensorustCreditQ3Cuts": TensorustCreditQ3CutsFetcher,
40
+ "TensorustContractorCredit": TensorustContractorCreditFetcher,
41
+ "TensorustContractorWatch": TensorustContractorWatchFetcher,
42
+ "TensorustExposureInstitution": TensorustExposureInstitutionFetcher,
43
+ "TensorustIdrOffer": TensorustIdrOfferFetcher,
44
+ },
45
+ repr_name="Tensorust",
46
+ instructions=(
47
+ "No key is needed for previews. For full records set the credential tensorust_api_key "
48
+ "to a Tensorust enterprise key (tdk_...): https://shop.tensorust.com/offers/enterprise-api"
49
+ ),
50
+ )
51
+
52
+ __all__ = ["__version__", "tensorust_provider"]
@@ -0,0 +1,110 @@
1
+ """Tensorust MCP client: one JSON-RPC ``tools/call`` per OpenBB command.
2
+
3
+ Every fetcher in this package calls the public Tensorust MCP server
4
+ (https://shop.tensorust.com/api/mcp). Without a key it answers free previews.
5
+ With a Tensorust key (``tensorust_api_key`` in OpenBB credentials, or the
6
+ ``TENSORUST_API_KEY`` environment variable) the call asks for ``full=true``
7
+ and the server returns full records.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import os
14
+ from typing import Any
15
+
16
+ import requests
17
+ from openbb_core.app.model.abstract.error import OpenBBError
18
+ from openbb_core.provider.utils.errors import EmptyDataError
19
+
20
+ MCP_URL = "https://shop.tensorust.com/api/mcp"
21
+ KEY_URL = "https://shop.tensorust.com/offers/enterprise-api"
22
+ USER_AGENT = "openbb-tensorust"
23
+
24
+
25
+ def mcp_url() -> str:
26
+ """Endpoint, overridable with TENSORUST_MCP_URL (tests, staging)."""
27
+ return os.environ.get("TENSORUST_MCP_URL", MCP_URL)
28
+
29
+
30
+ def api_key(credentials: dict[str, str] | None) -> str | None:
31
+ """The Tensorust key from OpenBB credentials, else from the environment."""
32
+ key = (credentials or {}).get("tensorust_api_key") or os.environ.get("TENSORUST_API_KEY")
33
+ return key.strip() if key and key.strip() else None
34
+
35
+
36
+ def call_tool(
37
+ name: str,
38
+ arguments: dict[str, Any],
39
+ credentials: dict[str, str] | None = None,
40
+ timeout: float = 60.0,
41
+ ) -> dict[str, Any]:
42
+ """Call one Tensorust MCP tool and return its JSON answer as a dict.
43
+
44
+ Adds ``full=true`` and the bearer key when a key is configured.
45
+ Raises OpenBBError on transport or tool errors.
46
+ """
47
+ key = api_key(credentials)
48
+ args = {k: v for k, v in arguments.items() if v is not None and v != ""}
49
+ headers = {
50
+ "content-type": "application/json",
51
+ "accept": "application/json",
52
+ "user-agent": USER_AGENT,
53
+ }
54
+ if key:
55
+ headers["authorization"] = f"Bearer {key}"
56
+ args["full"] = True
57
+ payload = {
58
+ "jsonrpc": "2.0",
59
+ "id": 1,
60
+ "method": "tools/call",
61
+ "params": {"name": name, "arguments": args},
62
+ }
63
+ try:
64
+ resp = requests.post(mcp_url(), json=payload, headers=headers, timeout=timeout)
65
+ except requests.RequestException as exc: # pragma: no cover - network
66
+ raise OpenBBError(f"Tensorust request failed: {exc}") from exc
67
+ if resp.status_code != 200:
68
+ raise OpenBBError(f"Tensorust answered HTTP {resp.status_code}: {resp.text[:300]}")
69
+ body = resp.json()
70
+ if "error" in body:
71
+ raise OpenBBError(f"Tensorust error: {body['error'].get('message', body['error'])}")
72
+ result = body.get("result") or {}
73
+ text = "".join(c.get("text", "") for c in result.get("content", []) if c.get("type") == "text")
74
+ if result.get("isError"):
75
+ raise EmptyDataError(text or f"Tensorust tool {name} returned an error.")
76
+ try:
77
+ data = json.loads(text)
78
+ except json.JSONDecodeError as exc:
79
+ raise OpenBBError(f"Tensorust tool {name} returned non-JSON text: {text[:200]}") from exc
80
+ if not isinstance(data, dict):
81
+ raise OpenBBError(f"Tensorust tool {name} returned {type(data).__name__}, not an object.")
82
+ return data
83
+
84
+
85
+ def not_found(data: dict[str, Any], what: str) -> EmptyDataError:
86
+ """EmptyDataError naming the closest matches the server suggested."""
87
+ similar = data.get("similar") or []
88
+ names = [s.get("name") if isinstance(s, dict) else str(s) for s in similar if s]
89
+ hint = f" Closest names: {', '.join(n for n in names if n)}." if names else ""
90
+ note = f" {data['note']}" if data.get("note") else ""
91
+ return EmptyDataError(f"No {what} matches '{data.get('query', '')}'.{note}{hint}")
92
+
93
+
94
+ def access_note(data: dict[str, Any]) -> str | None:
95
+ """How to get the full answer, when this one is a preview (None when it is already full)."""
96
+ if data.get("access") in ("full", "key", "free"):
97
+ return None
98
+ scope = ""
99
+ for k in ("access", "full_data", "full"):
100
+ v = data.get(k)
101
+ if isinstance(v, str) and v.lower().startswith(("top ", "first ")):
102
+ scope = f" ({v.split(';')[0].strip()})"
103
+ break
104
+ is_preview = data.get("access") is not None or data.get("preview") is True or "full_data" in data
105
+ if not is_preview:
106
+ return None
107
+ return (
108
+ f"Free preview{scope}. For full records set obb.user.credentials.tensorust_api_key "
109
+ f"(or TENSORUST_API_KEY) to a Tensorust key: {KEY_URL}"
110
+ )
@@ -0,0 +1 @@
1
+ """Tensorust provider models."""
@@ -0,0 +1,213 @@
1
+ """Contractor Credit: federal contractors financed by BDC lenders, and how those lenders mark them.
2
+
3
+ Sources: SEC BDC schedules of investments (Q3 2026 from 10-Qs as filed),
4
+ USAspending.gov, SAM parent UEI, DOL Form 5500, FCC, FAA and county records.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any, Literal
10
+
11
+ from openbb_core.provider.abstract.annotated_result import AnnotatedResult
12
+ from openbb_core.provider.abstract.data import Data
13
+ from openbb_core.provider.abstract.fetcher import Fetcher
14
+ from openbb_core.provider.abstract.query_params import QueryParams
15
+ from pydantic import Field
16
+
17
+ from openbb_tensorust.client import access_note, call_tool, not_found
18
+
19
+ MARK = "Fraction of par (0.95 = 95% of par)."
20
+
21
+
22
+ # ---- contractor_credit ----------------------------------------------------------------------
23
+
24
+
25
+ class TensorustContractorCreditQueryParams(QueryParams):
26
+ """Contractor credit query."""
27
+
28
+ contractor: str = Field(description="Federal contractor name, 12-character UEI or 9-digit EIN.")
29
+
30
+
31
+ class TensorustContractorCreditData(Data):
32
+ """One federal contractor's credit picture."""
33
+
34
+ operating_company: str = Field(description="Federal award recipient.")
35
+ uei: str | None = Field(default=None, description="SAM UEI of the recipient.")
36
+ state: str | None = Field(default=None, description="Recipient state.")
37
+ borrower: str | None = Field(default=None, description="Borrower name in BDC filings.")
38
+ sam_parent: str | None = Field(default=None, description="Parent reported to SAM.")
39
+ federal_obligations_fy2025_to_date: float | None = Field(default=None, description="USD.")
40
+ dod_fy2024_2026: float | None = Field(default=None, description="DoD obligations FY2024-26, USD.")
41
+ top_agency: str | None = Field(default=None, description="Agency with the most obligations.")
42
+ marks_as_of: str | None = Field(default=None, description="Quarter end of the BDC marks.")
43
+ lowest_mark: float | None = Field(default=None, description="Lowest Jun 30 BDC mark. " + MARK)
44
+ highest_mark: float | None = Field(default=None, description="Highest Jun 30 BDC mark. " + MARK)
45
+ sep30_lowest_mark: float | None = Field(default=None, description="Lowest Sep 30 2026 mark filed so far. " + MARK)
46
+ all_debt_mark: float | None = Field(
47
+ default=None, description="Par-weighted mark of every BDC debt line, latest quarter."
48
+ )
49
+ bdc_par: float | None = Field(default=None, description="BDC first-lien par, USD.")
50
+ headcount_change_pct: float | None = Field(default=None, description="Form 5500 participants, 2024 to 2025, %.")
51
+ signals: list[str] = Field(default_factory=list, description="Stress signals.")
52
+ market_priced: str | None = Field(default=None, description="Set when the credit is already market priced.")
53
+ read: str | None = Field(default=None, description="One-paragraph summary.")
54
+
55
+
56
+ class TensorustContractorCreditFetcher(
57
+ Fetcher[TensorustContractorCreditQueryParams, list[TensorustContractorCreditData]]
58
+ ):
59
+ """contractor_credit: obligations, lender marks, headcount and signals for one contractor."""
60
+
61
+ require_credentials = False
62
+
63
+ @staticmethod
64
+ def transform_query(params: dict[str, Any]) -> TensorustContractorCreditQueryParams:
65
+ return TensorustContractorCreditQueryParams(**params)
66
+
67
+ @staticmethod
68
+ def extract_data(
69
+ query: TensorustContractorCreditQueryParams,
70
+ credentials: dict[str, str] | None,
71
+ **kwargs: Any,
72
+ ) -> dict[str, Any]:
73
+ return call_tool("contractor_credit", {"name": query.contractor}, credentials)
74
+
75
+ @staticmethod
76
+ def transform_data(
77
+ query: TensorustContractorCreditQueryParams, data: dict[str, Any], **kwargs: Any
78
+ ) -> AnnotatedResult[list[TensorustContractorCreditData]]:
79
+ if not data.get("found"):
80
+ raise not_found(data, "BDC-financed federal contractor")
81
+ op = data.get("operating_company") or {}
82
+ fed = data.get("federal") or {}
83
+ m = data.get("marks") or {}
84
+ hc = data.get("headcount") or {}
85
+ mp = data.get("market_priced") or {}
86
+ all_debt = m.get("all_debt_lines_latest") or {}
87
+ row = TensorustContractorCreditData(
88
+ operating_company=op.get("name") or query.contractor,
89
+ uei=op.get("uei"),
90
+ state=op.get("state"),
91
+ borrower=data.get("borrower"),
92
+ sam_parent=op.get("sam_parent_reported"),
93
+ federal_obligations_fy2025_to_date=fed.get("obligations_fy2025_to_date"),
94
+ dod_fy2024_2026=fed.get("dod_fy2024_2026"),
95
+ top_agency=fed.get("top_agency"),
96
+ marks_as_of=m.get("as_of"),
97
+ lowest_mark=m.get("lowest"),
98
+ highest_mark=m.get("highest"),
99
+ sep30_lowest_mark=m.get("q3_lowest"),
100
+ all_debt_mark=all_debt.get("mark"),
101
+ bdc_par=m.get("bdc_par"),
102
+ headcount_change_pct=hc.get("change_pct"),
103
+ signals=data.get("signals") or [],
104
+ market_priced=mp.get("kind"),
105
+ read=data.get("read"),
106
+ )
107
+ meta: dict[str, Any] = {
108
+ k: data[k]
109
+ for k in (
110
+ "federal",
111
+ "marks",
112
+ "headcount",
113
+ "footprint",
114
+ "subcontracts_fy2025_to_date",
115
+ "market_priced",
116
+ "agencies",
117
+ "sample_agencies",
118
+ "lenders",
119
+ "q3_pending_holders",
120
+ "recipients",
121
+ "mark_history",
122
+ "source",
123
+ )
124
+ if data.get(k) is not None
125
+ }
126
+ note = access_note(data)
127
+ if note:
128
+ meta["access"] = note
129
+ return AnnotatedResult(result=[row], metadata=meta)
130
+
131
+
132
+ # ---- contractor_watch -----------------------------------------------------------------------
133
+
134
+
135
+ class TensorustContractorWatchQueryParams(QueryParams):
136
+ """Stressed federal contractors query."""
137
+
138
+ sort: Literal["federal", "mark", "q3"] = Field(
139
+ default="federal",
140
+ description="federal: largest federal exposure first; mark: lowest mark first; q3: biggest Sep 30 cut first.",
141
+ )
142
+ private_only: bool = Field(default=False, description="Drop names with listed equity or a rated syndicated loan.")
143
+ agency: str | None = Field(default=None, description="Only contractors paid by this agency (substring).")
144
+ state: str | None = Field(default=None, description="Two-letter recipient state.")
145
+ signal: str | None = Field(
146
+ default=None,
147
+ description="One signal instead of the stress default, e.g. marked_below_80, lenders_10pt_apart, cut_5pt_q3.",
148
+ )
149
+
150
+
151
+ class TensorustContractorWatchData(Data):
152
+ """A federal contractor whose BDC lenders are marking its loan down."""
153
+
154
+ operating_company: str = Field(description="Federal award recipient.")
155
+ borrower: str | None = Field(default=None, description="Borrower name in BDC filings.")
156
+ uei: str | None = Field(default=None, description="SAM UEI.")
157
+ state: str | None = Field(default=None, description="Recipient state.")
158
+ federal_exposure: float | None = Field(
159
+ default=None, description="Larger of FY2025-to-date and DoD FY2024-26 obligations, USD."
160
+ )
161
+ top_agency: str | None = Field(default=None, description="Agency with the most obligations.")
162
+ latest_mark: float | None = Field(default=None, description="Latest BDC mark. " + MARK)
163
+ q3_change_points: float | None = Field(default=None, description="Worst Jun 30 to Sep 30 move, points.")
164
+ managers: int | None = Field(default=None, description="BDC managers on the loan.")
165
+ bdc_par: float | None = Field(default=None, description="BDC first-lien par, USD.")
166
+ headcount_change_pct: float | None = Field(default=None, description="Form 5500 participants, 2024 to 2025, %.")
167
+ signals: list[str] = Field(default_factory=list, description="Stress signals.")
168
+ market_priced: str | None = Field(default=None, description="public or bsl when already market priced.")
169
+
170
+
171
+ class TensorustContractorWatchFetcher(Fetcher[TensorustContractorWatchQueryParams, list[TensorustContractorWatchData]]):
172
+ """contractor_credit_watch. Free: top 10; with a key: every name."""
173
+
174
+ require_credentials = False
175
+
176
+ @staticmethod
177
+ def transform_query(params: dict[str, Any]) -> TensorustContractorWatchQueryParams:
178
+ return TensorustContractorWatchQueryParams(**params)
179
+
180
+ @staticmethod
181
+ def extract_data(
182
+ query: TensorustContractorWatchQueryParams,
183
+ credentials: dict[str, str] | None,
184
+ **kwargs: Any,
185
+ ) -> dict[str, Any]:
186
+ args: dict[str, Any] = {
187
+ "sort": query.sort,
188
+ "agency": query.agency,
189
+ "state": query.state,
190
+ "signal": query.signal,
191
+ }
192
+ if query.private_only:
193
+ args["private_only"] = True
194
+ return call_tool("contractor_credit_watch", args, credentials)
195
+
196
+ @staticmethod
197
+ def transform_data(
198
+ query: TensorustContractorWatchQueryParams, data: dict[str, Any], **kwargs: Any
199
+ ) -> AnnotatedResult[list[TensorustContractorWatchData]]:
200
+ fields = set(TensorustContractorWatchData.model_fields)
201
+ rows = []
202
+ for x in data.get("items") or []:
203
+ known = {k: v for k, v in x.items() if k in fields}
204
+ known["signals"] = x.get("signals") or []
205
+ extra = {k: v for k, v in x.items() if k not in fields and k != "key"}
206
+ rows.append(TensorustContractorWatchData(**known, **extra))
207
+ meta: dict[str, Any] = {
208
+ k: data[k] for k in ("marks_as_of", "q3_filers", "q3_last_filed", "count", "federal_exposure") if k in data
209
+ }
210
+ note = access_note(data)
211
+ if note:
212
+ meta["access"] = note
213
+ return AnnotatedResult(result=rows, metadata=meta)
@@ -0,0 +1,261 @@
1
+ """Private credit: what BDC lenders mark a company's first-lien loan at.
2
+
3
+ Source: SEC Business Development Company data sets (XBRL schedules of
4
+ investments), first-lien term loans, fully funded, cost 85-110% of par.
5
+ Marks are fractions of par (0.95 = 95% of par).
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+
12
+ from openbb_core.provider.abstract.annotated_result import AnnotatedResult
13
+ from openbb_core.provider.abstract.data import Data
14
+ from openbb_core.provider.abstract.fetcher import Fetcher
15
+ from openbb_core.provider.abstract.query_params import QueryParams
16
+ from pydantic import Field
17
+
18
+ from openbb_tensorust.client import access_note, call_tool, not_found
19
+
20
+ MARK = "Fair value as a fraction of par (0.95 = 95% of par)."
21
+
22
+
23
+ def _meta(data: dict[str, Any], *keys: str) -> dict[str, Any]:
24
+ out = {k: data[k] for k in keys if data.get(k) is not None}
25
+ note = access_note(data)
26
+ if note:
27
+ out["access"] = note
28
+ return out
29
+
30
+
31
+ # ---- bdc_loan_marks -------------------------------------------------------------------------
32
+
33
+
34
+ class TensorustBdcLoanMarksQueryParams(QueryParams):
35
+ """BDC loan marks query."""
36
+
37
+ company: str = Field(
38
+ description="Borrower name as BDC schedules of investments spell it. A prefix works ('Pluralsight')."
39
+ )
40
+
41
+
42
+ class TensorustBdcLoanMarksData(Data):
43
+ """One BDC fund's mark on a company's first-lien term loan."""
44
+
45
+ company: str = Field(description="Borrower name.")
46
+ as_of: str | None = Field(default=None, description="Quarter end of the marks.")
47
+ fund: str = Field(description="BDC fund holding the loan.")
48
+ manager: str | None = Field(default=None, description="Fund manager.")
49
+ mark: float | None = Field(default=None, description=MARK)
50
+ prior_mark: float | None = Field(default=None, description="Prior-quarter mark (key only). " + MARK)
51
+ sep30_mark: float | None = Field(default=None, description="Sep 30 2026 mark if this fund has filed it (key only).")
52
+ sep30_filed: str | None = Field(default=None, description="Date the Sep 30 mark was filed (key only).")
53
+ par: float | None = Field(default=None, description="Par held by this fund, USD (key only).")
54
+ filing: str | None = Field(default=None, description="SEC filing link (key only).")
55
+
56
+
57
+ class TensorustBdcLoanMarksFetcher(Fetcher[TensorustBdcLoanMarksQueryParams, list[TensorustBdcLoanMarksData]]):
58
+ """lender_marks: every BDC fund's mark on one borrower's first-lien loan."""
59
+
60
+ require_credentials = False
61
+
62
+ @staticmethod
63
+ def transform_query(params: dict[str, Any]) -> TensorustBdcLoanMarksQueryParams:
64
+ return TensorustBdcLoanMarksQueryParams(**params)
65
+
66
+ @staticmethod
67
+ def extract_data(
68
+ query: TensorustBdcLoanMarksQueryParams,
69
+ credentials: dict[str, str] | None,
70
+ **kwargs: Any,
71
+ ) -> dict[str, Any]:
72
+ return call_tool("lender_marks", {"name": query.company}, credentials)
73
+
74
+ @staticmethod
75
+ def transform_data(
76
+ query: TensorustBdcLoanMarksQueryParams, data: dict[str, Any], **kwargs: Any
77
+ ) -> AnnotatedResult[list[TensorustBdcLoanMarksData]]:
78
+ if not data.get("found"):
79
+ raise not_found(data, "BDC first-lien term loan")
80
+ company = data.get("company") or data.get("name") or query.company
81
+ as_of = data.get("as_of")
82
+ lenders = data.get("lenders")
83
+ if isinstance(lenders, list): # full record
84
+ rows = [
85
+ TensorustBdcLoanMarksData(
86
+ company=company,
87
+ as_of=as_of,
88
+ fund=x.get("fund"),
89
+ manager=x.get("manager"),
90
+ mark=x.get("mark"),
91
+ prior_mark=x.get("prev_mark"),
92
+ sep30_mark=x.get("q3_mark"),
93
+ sep30_filed=x.get("q3_filed"),
94
+ par=x.get("par"),
95
+ filing=x.get("filing"),
96
+ )
97
+ for x in lenders
98
+ ]
99
+ else:
100
+ rows = [
101
+ TensorustBdcLoanMarksData(
102
+ company=company, as_of=as_of, fund=x.get("fund"), manager=x.get("manager"), mark=x.get("mark")
103
+ )
104
+ for x in data.get("sample") or []
105
+ ]
106
+ meta = _meta(
107
+ data,
108
+ "funds",
109
+ "managers",
110
+ "loan_par_usd",
111
+ "maturity",
112
+ "lowest_mark",
113
+ "lowest_manager",
114
+ "highest_mark",
115
+ "highest_manager",
116
+ "gap_points",
117
+ "read",
118
+ "q3_so_far",
119
+ "signal",
120
+ "source",
121
+ )
122
+ if "gap_points" not in meta and isinstance(data.get("gap"), (int, float)):
123
+ meta["gap_points"] = round(data["gap"] * 100, 1)
124
+ return AnnotatedResult(result=rows, metadata=meta)
125
+
126
+
127
+ # ---- credit_disagreements -------------------------------------------------------------------
128
+
129
+
130
+ class TensorustCreditDisagreementsQueryParams(QueryParams):
131
+ """Loans BDC lenders disagree on. No parameters."""
132
+
133
+
134
+ class TensorustCreditDisagreementsData(Data):
135
+ """A company whose first-lien loan two or more BDC managers mark 10+ points apart."""
136
+
137
+ company: str = Field(description="Borrower name.")
138
+ gap_points: float | None = Field(default=None, description="Highest minus lowest manager mark, in points of par.")
139
+ lowest_mark: float | None = Field(default=None, description="Lowest manager mark. " + MARK)
140
+ lowest_manager: str | None = Field(default=None, description="Manager with the lowest mark.")
141
+ highest_mark: float | None = Field(default=None, description="Highest manager mark. " + MARK)
142
+ highest_manager: str | None = Field(default=None, description="Manager with the highest mark.")
143
+ loan_par: float | None = Field(default=None, description="BDC par on the loan, USD.")
144
+ funds: int | None = Field(default=None, description="BDC funds holding the loan.")
145
+ managers: int | None = Field(default=None, description="Distinct managers (key only).")
146
+ maturity: str | None = Field(default=None, description="Loan maturity (key only).")
147
+
148
+
149
+ class TensorustCreditDisagreementsFetcher(
150
+ Fetcher[TensorustCreditDisagreementsQueryParams, list[TensorustCreditDisagreementsData]]
151
+ ):
152
+ """credit_disagreements: widest gaps first. Free: top 10; with a key: all of them."""
153
+
154
+ require_credentials = False
155
+
156
+ @staticmethod
157
+ def transform_query(params: dict[str, Any]) -> TensorustCreditDisagreementsQueryParams:
158
+ return TensorustCreditDisagreementsQueryParams(**params)
159
+
160
+ @staticmethod
161
+ def extract_data(
162
+ query: TensorustCreditDisagreementsQueryParams,
163
+ credentials: dict[str, str] | None,
164
+ **kwargs: Any,
165
+ ) -> dict[str, Any]:
166
+ return call_tool("credit_disagreements", {}, credentials)
167
+
168
+ @staticmethod
169
+ def transform_data(
170
+ query: TensorustCreditDisagreementsQueryParams, data: dict[str, Any], **kwargs: Any
171
+ ) -> AnnotatedResult[list[TensorustCreditDisagreementsData]]:
172
+ rows = []
173
+ for x in data.get("items") or []:
174
+ gap = x.get("gap_points")
175
+ if gap is None and isinstance(x.get("gap"), (int, float)):
176
+ gap = round(x["gap"] * 100, 1)
177
+ rows.append(
178
+ TensorustCreditDisagreementsData(
179
+ company=x.get("company") or x.get("name"),
180
+ gap_points=gap,
181
+ lowest_mark=x.get("lowest_mark", x.get("low")),
182
+ lowest_manager=x.get("lowest_manager", x.get("low_manager")),
183
+ highest_mark=x.get("highest_mark", x.get("high")),
184
+ highest_manager=x.get("highest_manager", x.get("high_manager")),
185
+ loan_par=x.get("loan_par_usd", x.get("par")),
186
+ funds=x.get("funds"),
187
+ managers=x.get("managers"),
188
+ maturity=x.get("maturity"),
189
+ )
190
+ )
191
+ return AnnotatedResult(
192
+ result=rows,
193
+ metadata=_meta(data, "as_of", "companies_with_2plus_managers", "disagreements_10pt", "source"),
194
+ )
195
+
196
+
197
+ # ---- credit_q3_cuts -------------------------------------------------------------------------
198
+
199
+
200
+ class TensorustCreditQ3CutsQueryParams(QueryParams):
201
+ """Q3 2026 BDC markdowns. No parameters."""
202
+
203
+
204
+ class TensorustCreditQ3CutsData(Data):
205
+ """A fund that cut its mark on a loan by 5+ points from Jun 30 to Sep 30 2026."""
206
+
207
+ company: str = Field(description="Borrower name.")
208
+ fund: str = Field(description="BDC fund that cut its mark.")
209
+ manager: str | None = Field(default=None, description="Fund manager (key only).")
210
+ jun30_mark: float | None = Field(default=None, description="Jun 30 2026 mark. " + MARK)
211
+ sep30_mark: float | None = Field(default=None, description="Sep 30 2026 mark. " + MARK)
212
+ change_points: float | None = Field(default=None, description="Sep 30 minus Jun 30, points of par.")
213
+ par: float | None = Field(default=None, description="Par held by this fund, USD.")
214
+ filed: str | None = Field(default=None, description="Date the Sep 30 mark was filed (key only).")
215
+ holders_not_filed_yet_above: int | None = Field(
216
+ default=None,
217
+ description="Other holders that have not filed Sep 30 yet and still carry the loan 5+ points higher.",
218
+ )
219
+
220
+
221
+ class TensorustCreditQ3CutsFetcher(Fetcher[TensorustCreditQ3CutsQueryParams, list[TensorustCreditQ3CutsData]]):
222
+ """credit_q3_cuts: biggest cuts first. Free: top 10; with a key: all, with each pending holder."""
223
+
224
+ require_credentials = False
225
+
226
+ @staticmethod
227
+ def transform_query(params: dict[str, Any]) -> TensorustCreditQ3CutsQueryParams:
228
+ return TensorustCreditQ3CutsQueryParams(**params)
229
+
230
+ @staticmethod
231
+ def extract_data(
232
+ query: TensorustCreditQ3CutsQueryParams,
233
+ credentials: dict[str, str] | None,
234
+ **kwargs: Any,
235
+ ) -> dict[str, Any]:
236
+ return call_tool("credit_q3_cuts", {}, credentials)
237
+
238
+ @staticmethod
239
+ def transform_data(
240
+ query: TensorustCreditQ3CutsQueryParams, data: dict[str, Any], **kwargs: Any
241
+ ) -> AnnotatedResult[list[TensorustCreditQ3CutsData]]:
242
+ rows = []
243
+ for x in data.get("items") or []:
244
+ pending = x.get("not_filed_yet_above")
245
+ count = len(pending) if isinstance(pending, list) else x.get("holders_not_filed_yet_above")
246
+ extra: dict[str, Any] = {"pending_holders": pending} if isinstance(pending, list) else {}
247
+ rows.append(
248
+ TensorustCreditQ3CutsData(
249
+ company=x.get("company"),
250
+ fund=x.get("fund"),
251
+ manager=x.get("manager"),
252
+ jun30_mark=x.get("jun30"),
253
+ sep30_mark=x.get("sep30"),
254
+ change_points=x.get("change_points"),
255
+ par=x.get("par"),
256
+ filed=x.get("filed"),
257
+ holders_not_filed_yet_above=count,
258
+ **extra,
259
+ )
260
+ )
261
+ return AnnotatedResult(result=rows, metadata=_meta(data, "as_of", "funds_filed", "last_filing", "cuts_5pt"))
@@ -0,0 +1,107 @@
1
+ """Research Exposure Ledger: federal awards whose papers name vendors on banned-vendor lists.
2
+
3
+ Lists: DoD 1260H, Section 889 (FAR 52.204-25), FCC Covered List, DHS UFLPA
4
+ Entity List, BIOSECURE. Evidence: Europe PMC, OpenAlex, Crossref, open-access
5
+ PDFs, ENA and dbGaP; dollars from USAspending and NIH RePORTER.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import Any
11
+
12
+ from openbb_core.provider.abstract.annotated_result import AnnotatedResult
13
+ from openbb_core.provider.abstract.data import Data
14
+ from openbb_core.provider.abstract.fetcher import Fetcher
15
+ from openbb_core.provider.abstract.query_params import QueryParams
16
+ from pydantic import Field
17
+
18
+ from openbb_tensorust.client import access_note, call_tool, not_found
19
+
20
+
21
+ class TensorustExposureInstitutionQueryParams(QueryParams):
22
+ """Exposure query for one institution."""
23
+
24
+ institution: str = Field(description="Federal award recipient name or UEI.")
25
+
26
+
27
+ class TensorustExposureInstitutionData(Data):
28
+ """One federal award whose 2025-26 papers name a listed vendor."""
29
+
30
+ award: str = Field(description="Award id (FAIN).")
31
+ recipient: str | None = Field(default=None, description="Recipient name.")
32
+ agency: str | None = Field(default=None, description="Awarding agency.")
33
+ title: str | None = Field(default=None, description="Award title.")
34
+ fy25_obligations: float | None = Field(default=None, description="Whole-award FY2025 obligations, USD.")
35
+ fy26_amount: float | None = Field(default=None, description="FY2026 amount, USD.")
36
+ project_end: str | None = Field(default=None, description="Project end date.")
37
+ vendors: list[str] = Field(default_factory=list, description="Listed vendors named in the evidence.")
38
+ lists: list[str] = Field(default_factory=list, description="Lists the vendors are on.")
39
+ rules: dict[str, str] = Field(default_factory=dict, description="Rule id to status for this award.")
40
+ attribution: str | None = Field(default=None, description="broad, narrow or likely_paid.")
41
+ in_force_or_no_grace: bool | None = Field(
42
+ default=None, description="A consequence binds now or has no grace period."
43
+ )
44
+ papers: int | None = Field(default=None, description="Citing 2025-26 papers.")
45
+ latest_paper: str | None = Field(default=None, description="Date of the latest citing paper.")
46
+ evidence: str | None = Field(default=None, description="Sentence naming the vendor (key only).")
47
+ evidence_paper: str | None = Field(default=None, description="Link to the paper (key only).")
48
+
49
+
50
+ class TensorustExposureInstitutionFetcher(
51
+ Fetcher[TensorustExposureInstitutionQueryParams, list[TensorustExposureInstitutionData]]
52
+ ):
53
+ """exposure_institution. Free: totals and the 5 largest awards; with a key: every award with evidence."""
54
+
55
+ require_credentials = False
56
+
57
+ @staticmethod
58
+ def transform_query(params: dict[str, Any]) -> TensorustExposureInstitutionQueryParams:
59
+ return TensorustExposureInstitutionQueryParams(**params)
60
+
61
+ @staticmethod
62
+ def extract_data(
63
+ query: TensorustExposureInstitutionQueryParams,
64
+ credentials: dict[str, str] | None,
65
+ **kwargs: Any,
66
+ ) -> dict[str, Any]:
67
+ return call_tool("exposure_institution", {"name": query.institution}, credentials)
68
+
69
+ @staticmethod
70
+ def transform_data(
71
+ query: TensorustExposureInstitutionQueryParams, data: dict[str, Any], **kwargs: Any
72
+ ) -> AnnotatedResult[list[TensorustExposureInstitutionData]]:
73
+ if not data.get("found"):
74
+ raise not_found(data, "award recipient with a listed-vendor paper")
75
+ rows = []
76
+ for a in data.get("items") or []:
77
+ row = {k: v for k, v in a.items() if v is not None}
78
+ row["vendors"] = a.get("vendors") or []
79
+ row["lists"] = a.get("lists") or []
80
+ row["rules"] = a.get("rules") or {}
81
+ rows.append(TensorustExposureInstitutionData(**row))
82
+ meta: dict[str, Any] = {
83
+ k: data[k]
84
+ for k in (
85
+ "institution",
86
+ "uei",
87
+ "state",
88
+ "as_of",
89
+ "awards",
90
+ "fy25",
91
+ "fy26",
92
+ "in_force_awards",
93
+ "in_force_fy25",
94
+ "narrow_awards",
95
+ "narrow_fy25",
96
+ "likely_paid_awards",
97
+ "likely_paid_fy25",
98
+ "by_list",
99
+ "rule_status_counts",
100
+ "ontology_id",
101
+ )
102
+ if k in data
103
+ }
104
+ note = access_note(data)
105
+ if note:
106
+ meta["access"] = note
107
+ return AnnotatedResult(result=rows, metadata=meta)
@@ -0,0 +1,128 @@
1
+ """No Surprises Act federal IDR: the offer band that wins for a code, payer and state.
2
+
3
+ Source: CMS Federal IDR Public Use File, 2025 Q4, computed by Tensorust LLC
4
+ (altered and aggregated; not CMS data as published).
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from openbb_core.provider.abstract.annotated_result import AnnotatedResult
12
+ from openbb_core.provider.abstract.data import Data
13
+ from openbb_core.provider.abstract.fetcher import Fetcher
14
+ from openbb_core.provider.abstract.query_params import QueryParams
15
+ from pydantic import Field
16
+
17
+ from openbb_tensorust.client import access_note, call_tool
18
+
19
+
20
+ class TensorustIdrOfferQueryParams(QueryParams):
21
+ """IDR offer query."""
22
+
23
+ code: str = Field(description="CPT or HCPCS code, e.g. 99284.")
24
+ payer: str | None = Field(
25
+ default=None, description="Payer email domain or common name (uhc.com, aetna.com, cigna.com)."
26
+ )
27
+ state: str | None = Field(default=None, description="Two-letter state.")
28
+ entity: str | None = Field(default=None, description="Certified IDR entity (arbitrator), optional.")
29
+ qpa: float | None = Field(
30
+ default=None, description="Your qualifying payment amount in USD, for expected value (key or small cells)."
31
+ )
32
+
33
+
34
+ class TensorustIdrOfferData(Data):
35
+ """The IDR cell that decides the dispute."""
36
+
37
+ code: str = Field(description="Service code.")
38
+ payer: str | None = Field(default=None, description="Payer domain matched.")
39
+ state: str | None = Field(default=None, description="State matched.")
40
+ level: str | None = Field(default=None, description="Which cell matched (code+payer+state, or a wider one).")
41
+ determinations: int | None = Field(default=None, description="Determinations in the cell.")
42
+ provider_win_rate_pct: float | None = Field(default=None, description="Share of line items providers won, %.")
43
+ offer_band_low_multiple: float | None = Field(
44
+ default=None, description="Median winning provider offer, multiple of QPA."
45
+ )
46
+ offer_band_high_multiple: float | None = Field(
47
+ default=None, description="75th percentile winning provider offer, multiple of QPA."
48
+ )
49
+ winning_p25_multiple: float | None = Field(
50
+ default=None, description="25th percentile winning offer, multiple of QPA (full)."
51
+ )
52
+ plan_median_offer_multiple: float | None = Field(
53
+ default=None, description="Median plan offer, multiple of QPA (full)."
54
+ )
55
+ losing_provider_median_offer_multiple: float | None = Field(
56
+ default=None, description="Median losing provider offer (full)."
57
+ )
58
+ median_days_to_determination: float | None = Field(
59
+ default=None, description="Median days to a determination (full)."
60
+ )
61
+ access: str | None = Field(default=None, description="preview, free (small cell) or key.")
62
+
63
+
64
+ class TensorustIdrOfferFetcher(Fetcher[TensorustIdrOfferQueryParams, list[TensorustIdrOfferData]]):
65
+ """idr_offer. Free: win rate and offer band; with a key (or a cell under 50): quartiles, arbitrators, EV."""
66
+
67
+ require_credentials = False
68
+
69
+ @staticmethod
70
+ def transform_query(params: dict[str, Any]) -> TensorustIdrOfferQueryParams:
71
+ return TensorustIdrOfferQueryParams(**params)
72
+
73
+ @staticmethod
74
+ def extract_data(
75
+ query: TensorustIdrOfferQueryParams,
76
+ credentials: dict[str, str] | None,
77
+ **kwargs: Any,
78
+ ) -> dict[str, Any]:
79
+ return call_tool(
80
+ "idr_offer",
81
+ {"code": query.code, "payer": query.payer, "state": query.state, "entity": query.entity, "qpa": query.qpa},
82
+ credentials,
83
+ )
84
+
85
+ @staticmethod
86
+ def transform_data(
87
+ query: TensorustIdrOfferQueryParams, data: dict[str, Any], **kwargs: Any
88
+ ) -> AnnotatedResult[list[TensorustIdrOfferData]]:
89
+ q = data.get("query") or {}
90
+ matched = data.get("matched") or {}
91
+ cell = data.get("cell") or {}
92
+ band = data.get("recommended_offer_band") or {}
93
+ win = (cell.get("winning_multiple_of_qpa") or {}) if cell else {}
94
+ preview = data.get("preview") is True
95
+ row = TensorustIdrOfferData(
96
+ code=q.get("code") or query.code.upper(),
97
+ payer=q.get("payer"),
98
+ state=q.get("state"),
99
+ level=matched.get("level"),
100
+ determinations=matched.get("determinations"),
101
+ provider_win_rate_pct=cell.get("provider_win_rate_pct", data.get("provider_win_rate_pct")),
102
+ offer_band_low_multiple=band.get("low_multiple"),
103
+ offer_band_high_multiple=band.get("high_multiple"),
104
+ winning_p25_multiple=win.get("p25"),
105
+ plan_median_offer_multiple=cell.get("plan_median_offer_multiple"),
106
+ losing_provider_median_offer_multiple=cell.get("losing_provider_median_offer_multiple"),
107
+ median_days_to_determination=cell.get("median_days_to_determination"),
108
+ access="preview" if preview else data.get("access"),
109
+ )
110
+ meta = {
111
+ k: data[k]
112
+ for k in (
113
+ "cell",
114
+ "at_your_qpa",
115
+ "code_dollars_q4_2025",
116
+ "arbitrators_in_cell",
117
+ "chosen_arbitrator",
118
+ "entity_pick",
119
+ "flags",
120
+ "pricing",
121
+ "source",
122
+ "vintage",
123
+ )
124
+ if data.get(k) is not None
125
+ }
126
+ if preview:
127
+ meta["access"] = access_note(data)
128
+ return AnnotatedResult(result=[row], metadata=meta)
@@ -0,0 +1,115 @@
1
+ """obb.tensorust: commands served by the Tensorust provider."""
2
+
3
+ from openbb_core.app.model.command_context import CommandContext
4
+ from openbb_core.app.model.example import APIEx
5
+ from openbb_core.app.model.obbject import OBBject
6
+ from openbb_core.app.provider_interface import (
7
+ ExtraParams,
8
+ ProviderChoices,
9
+ StandardParams,
10
+ )
11
+ from openbb_core.app.query import Query
12
+ from openbb_core.app.router import Router
13
+
14
+ router = Router(prefix="", description="Tensorust: private credit marks, contractor credit, exposure and IDR data.")
15
+
16
+
17
+ @router.command(
18
+ model="TensorustBdcLoanMarks",
19
+ examples=[APIEx(parameters={"company": "Pluralsight", "provider": "tensorust"})],
20
+ )
21
+ async def bdc_loan_marks(
22
+ cc: CommandContext,
23
+ provider_choices: ProviderChoices,
24
+ standard_params: StandardParams,
25
+ extra_params: ExtraParams,
26
+ ) -> OBBject:
27
+ """What each BDC (private credit) fund marks one company's first-lien term loan at, as a fraction of par.
28
+
29
+ The results metadata carries the lowest and highest manager mark, the gap and Q3 2026 marks filed so far.
30
+ """
31
+ return await OBBject.from_query(Query(**locals()))
32
+
33
+
34
+ @router.command(
35
+ model="TensorustCreditDisagreements",
36
+ examples=[APIEx(parameters={"provider": "tensorust"})],
37
+ )
38
+ async def credit_disagreements(
39
+ cc: CommandContext,
40
+ provider_choices: ProviderChoices,
41
+ standard_params: StandardParams,
42
+ extra_params: ExtraParams,
43
+ ) -> OBBject:
44
+ """Companies whose first-lien loan two or more BDC managers mark 10+ points apart, widest gap first."""
45
+ return await OBBject.from_query(Query(**locals()))
46
+
47
+
48
+ @router.command(
49
+ model="TensorustCreditQ3Cuts",
50
+ examples=[APIEx(parameters={"provider": "tensorust"})],
51
+ )
52
+ async def credit_q3_cuts(
53
+ cc: CommandContext,
54
+ provider_choices: ProviderChoices,
55
+ standard_params: StandardParams,
56
+ extra_params: ExtraParams,
57
+ ) -> OBBject:
58
+ """Q3 2026 BDC markdowns of 5+ points as funds file their 10-Qs, with holders that have not filed yet."""
59
+ return await OBBject.from_query(Query(**locals()))
60
+
61
+
62
+ @router.command(
63
+ model="TensorustContractorCredit",
64
+ examples=[APIEx(parameters={"contractor": "Peraton", "provider": "tensorust"})],
65
+ )
66
+ async def contractor_credit(
67
+ cc: CommandContext,
68
+ provider_choices: ProviderChoices,
69
+ standard_params: StandardParams,
70
+ extra_params: ExtraParams,
71
+ ) -> OBBject:
72
+ """One federal contractor: obligations, what its BDC lenders mark its loan at, headcount trend and signals."""
73
+ return await OBBject.from_query(Query(**locals()))
74
+
75
+
76
+ @router.command(
77
+ model="TensorustContractorWatch",
78
+ examples=[APIEx(parameters={"sort": "q3", "provider": "tensorust"})],
79
+ )
80
+ async def contractor_watch(
81
+ cc: CommandContext,
82
+ provider_choices: ProviderChoices,
83
+ standard_params: StandardParams,
84
+ extra_params: ExtraParams,
85
+ ) -> OBBject:
86
+ """Federal contractors whose BDC lenders are marking their loans down."""
87
+ return await OBBject.from_query(Query(**locals()))
88
+
89
+
90
+ @router.command(
91
+ model="TensorustExposureInstitution",
92
+ examples=[APIEx(parameters={"institution": "Harvard", "provider": "tensorust"})],
93
+ )
94
+ async def exposure_institution(
95
+ cc: CommandContext,
96
+ provider_choices: ProviderChoices,
97
+ standard_params: StandardParams,
98
+ extra_params: ExtraParams,
99
+ ) -> OBBject:
100
+ """Federal awards of one institution whose 2025-26 papers name a vendor on a banned-vendor list."""
101
+ return await OBBject.from_query(Query(**locals()))
102
+
103
+
104
+ @router.command(
105
+ model="TensorustIdrOffer",
106
+ examples=[APIEx(parameters={"code": "99284", "payer": "uhc.com", "state": "TX", "provider": "tensorust"})],
107
+ )
108
+ async def idr_offer(
109
+ cc: CommandContext,
110
+ provider_choices: ProviderChoices,
111
+ standard_params: StandardParams,
112
+ extra_params: ExtraParams,
113
+ ) -> OBBject:
114
+ """No Surprises Act federal IDR: provider win rate and the winning offer band for a code, payer and state."""
115
+ return await OBBject.from_query(Query(**locals()))
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.5
2
+ Name: openbb-tensorust
3
+ Version: 0.1.0
4
+ Summary: OpenBB extension for Tensorust data: BDC private credit loan marks, federal contractor credit, banned-vendor exposure in federal awards and No Surprises Act IDR offer bands.
5
+ Project-URL: Homepage, https://tensorust.com
6
+ Project-URL: Source, https://github.com/Mattbusel/openbb-tensorust
7
+ Project-URL: Documentation, https://github.com/Mattbusel/openbb-tensorust/blob/main/docs/index.md
8
+ Project-URL: Changelog, https://github.com/Mattbusel/openbb-tensorust/blob/main/CHANGELOG.md
9
+ Project-URL: Workspace backend, https://shop.tensorust.com/api/openbb
10
+ Author: Matthew Busel
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: bdc,federal-contracts,finance,loan-marks,no-surprises-act,openbb,private-credit,sanctions
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Financial and Insurance Industry
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Office/Business :: Financial :: Investment
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: openbb-core<3,>=1.6
25
+ Requires-Dist: requests>=2.31
26
+ Description-Content-Type: text/markdown
27
+
28
+ # openbb-tensorust
29
+
30
+ An [OpenBB Platform](https://github.com/OpenBB-finance/OpenBB) extension for
31
+ [Tensorust](https://tensorust.com) data, built from US public records.
32
+
33
+ ```bash
34
+ pip install openbb openbb-tensorust
35
+ openbb-build # once, so obb picks up the new commands
36
+ ```
37
+
38
+ ```python
39
+ from openbb import obb
40
+
41
+ obb.tensorust.credit_disagreements().to_df() # loans BDC lenders mark 10+ points apart
42
+ obb.tensorust.bdc_loan_marks(company="Pluralsight").to_df()
43
+ obb.tensorust.credit_q3_cuts().to_df() # Q3 2026 markdowns as BDCs file
44
+ obb.tensorust.contractor_credit(contractor="Peraton")
45
+ obb.tensorust.contractor_watch(sort="q3").to_df()
46
+ obb.tensorust.exposure_institution(institution="Harvard").to_df()
47
+ obb.tensorust.idr_offer(code="99284", payer="uhc.com", state="TX")
48
+ ```
49
+
50
+ | Command | Answers |
51
+ |---|---|
52
+ | `bdc_loan_marks` | What each BDC fund marks one company's first-lien loan at (SEC schedules of investments) |
53
+ | `credit_disagreements` | Loans two or more BDC managers mark 10+ points apart |
54
+ | `credit_q3_cuts` | Fund-level cuts of 5+ points from Jun 30 to Sep 30 2026, and who has not filed yet |
55
+ | `contractor_credit` | A federal contractor's obligations, lender marks, headcount trend and stress signals |
56
+ | `contractor_watch` | Federal contractors whose lenders are marking them down |
57
+ | `exposure_institution` | Federal awards whose papers name vendors on the 1260H, Section 889, FCC Covered, UFLPA or BIOSECURE lists |
58
+ | `idr_offer` | No Surprises Act federal IDR: provider win rate and the winning offer band by code, payer and state |
59
+
60
+ No key is needed: every command answers a free preview (top 10 rows, or a summary).
61
+ Set `obb.user.credentials.tensorust_api_key = "tdk_..."` (or `TENSORUST_API_KEY`) for full
62
+ records. The same data loads in OpenBB Workspace as a custom backend:
63
+ `https://shop.tensorust.com/api/openbb`.
64
+
65
+ Docs: https://github.com/Mattbusel/openbb-tensorust/blob/main/docs/index.md
@@ -0,0 +1,13 @@
1
+ openbb_tensorust/__init__.py,sha256=OlgfZYk3nSHy6plIWR1sIr0NPcHswxuWddY-pd3Duhk,2242
2
+ openbb_tensorust/client.py,sha256=VDEk61OgFEN62NuUqwEX3kguX585RSNxZFuo_EOIT9Q,4427
3
+ openbb_tensorust/router.py,sha256=UOoAZO7g_B3YunyudExfPLvIOOqeRWaVt3UluhyZSeE,3961
4
+ openbb_tensorust/models/__init__.py,sha256=hCiRAV6sAyhJXHnLoUVl3LJNHXyDbSZRhdLNf3bxMJM,33
5
+ openbb_tensorust/models/contractor.py,sha256=qpDyPrVXC_OoLcL4zAf4kd2ImkV9DamXbrq-5cSxiyU,9800
6
+ openbb_tensorust/models/credit.py,sha256=rT0Hu2nIV7-JhUqDN_8CfDi_FmatvKXKAWCN6Rth_pQ,11113
7
+ openbb_tensorust/models/exposure.py,sha256=2IXylKGibxnL3jVbVoBdSjma4IVfAvmURfEODMGG7E0,4658
8
+ openbb_tensorust/models/idr.py,sha256=0lYLfswK9HQ51bxquRoviyHYo7JtqNesnSWGdAr7Atc,5506
9
+ openbb_tensorust-0.1.0.dist-info/METADATA,sha256=8TeHWBOD6Vm6Lj4DmKJoMRtIlVZ-r-L5d7bocyUXRZQ,3321
10
+ openbb_tensorust-0.1.0.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
11
+ openbb_tensorust-0.1.0.dist-info/entry_points.txt,sha256=XqO7mOh_vDsRGmJheNHYiM6QmE0vwkgXCB9feUsydZ8,144
12
+ openbb_tensorust-0.1.0.dist-info/licenses/LICENSE,sha256=TpCqwl9Iq4EFUnYGbR2dGUSmF5tDy-hCISSPJasaP10,1070
13
+ openbb_tensorust-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.33.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,5 @@
1
+ [openbb_core_extension]
2
+ tensorust = openbb_tensorust.router:router
3
+
4
+ [openbb_provider_extension]
5
+ tensorust = openbb_tensorust:tensorust_provider
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matthew Busel
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.