pit-fundamentals 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.
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
env/
|
|
10
|
+
.env
|
|
11
|
+
.env.local
|
|
12
|
+
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
|
|
17
|
+
.DS_Store
|
|
18
|
+
Thumbs.db
|
|
19
|
+
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.swp
|
|
23
|
+
|
|
24
|
+
*.log
|
|
25
|
+
data-staging/
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pit-fundamentals
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Point-in-time company fundamentals from official regulator filings (US SEC EDGAR, Taiwan TWSE, Korea OpenDART) — as-first-reported, keyed by filing date, exportable. Zero dependencies.
|
|
5
|
+
Project-URL: Homepage, https://www.tradingagentapp.com/fundamentals
|
|
6
|
+
Project-URL: Documentation, https://www.tradingagentapp.com/developers
|
|
7
|
+
Project-URL: Licence terms, https://www.tradingagentapp.com/licences/personal
|
|
8
|
+
Author-email: WU Capital Limited <tradingagentapp@gmail.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: EDGAR,OpenDART,PIT,SEC,TWSE,backtesting,factor,financial-data,fundamentals,korea,look-ahead-bias,point-in-time,quant,stock-data,taiwan
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# pit-fundamentals
|
|
21
|
+
|
|
22
|
+
**Point-in-time company fundamentals from official regulator filings — as
|
|
23
|
+
first reported, keyed by filing date, exportable.** Zero dependencies
|
|
24
|
+
(pandas optional).
|
|
25
|
+
|
|
26
|
+
Backtests leak the future when they use restated numbers or use figures
|
|
27
|
+
before their filing date. This dataset stores every figure **as it was first
|
|
28
|
+
reported** and stamps it with its **filing date**, so `as_of` queries return
|
|
29
|
+
exactly what was public on that day.
|
|
30
|
+
|
|
31
|
+
| Market | Source | Coverage |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| US | SEC EDGAR (public domain) | ~6,900 filers · annual + quarterly · 2014→ |
|
|
34
|
+
| Taiwan | TWSE OpenAPI (Open Government Data License 1.0) | every listed company · accumulating quarterly |
|
|
35
|
+
| Korea | FSS OpenDART | full market · loading |
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install pit-fundamentals
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 60-second start (no signup — public demo key built in)
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import pit_fundamentals as pf
|
|
47
|
+
|
|
48
|
+
# TSMC's history, as first reported
|
|
49
|
+
rows = pf.fundamentals("2330.TW")
|
|
50
|
+
|
|
51
|
+
# What a backtest running on 2022-01-01 was allowed to know about Apple
|
|
52
|
+
snap = pf.latest("AAPL", as_of="2022-01-01")
|
|
53
|
+
print(snap["revenue"]) # FY2021, filed 2021-10-29 — nothing newer leaks
|
|
54
|
+
|
|
55
|
+
# The scored, resolved prediction panel (history incl. losses; delayed on free)
|
|
56
|
+
panel = pf.signals(market="TW", horizon="21d", limit=1000)
|
|
57
|
+
|
|
58
|
+
# pandas users
|
|
59
|
+
df = pf.to_df(rows)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The demo key covers **25 flagship tickers (US · TW · KR) at full fidelity** —
|
|
63
|
+
full fields, full history. Paid plans unlock every ticker; your code doesn't
|
|
64
|
+
change:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
export PIT_FUNDAMENTALS_KEY=ta_live_xxxxxxxx
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Pricing & licences
|
|
71
|
+
|
|
72
|
+
Free / Personal US$29/mo / Commercial US$149/mo / Redistribution US$499/mo —
|
|
73
|
+
plans and full licence texts: <https://www.tradingagentapp.com/fundamentals>
|
|
74
|
+
|
|
75
|
+
What makes the licence unusual: **no export bans, no display-only clause, and
|
|
76
|
+
your derived research is yours forever** (explicitly, in writing — including
|
|
77
|
+
after cancellation). We ingest from public filings directly, so no upstream
|
|
78
|
+
vendor licence forbids you taking the data with you.
|
|
79
|
+
|
|
80
|
+
## Notes worth knowing
|
|
81
|
+
|
|
82
|
+
- **Taiwan income statements are cumulative year-to-date** (Taiwan reporting
|
|
83
|
+
convention: Q2 = H1 total). Difference adjacent quarters for single-quarter
|
|
84
|
+
flows. Balance-sheet items are point-in-time as usual.
|
|
85
|
+
- Every API response embeds its statutory source attribution (e.g. 臺灣證券
|
|
86
|
+
交易所 under OGDL 1.0).
|
|
87
|
+
- Factual, historical data only — no forecasts, no advice, no price/OHLCV.
|
|
88
|
+
|
|
89
|
+
Docs: <https://www.tradingagentapp.com/developers> ·
|
|
90
|
+
Field dictionary and examples included.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# pit-fundamentals
|
|
2
|
+
|
|
3
|
+
**Point-in-time company fundamentals from official regulator filings — as
|
|
4
|
+
first reported, keyed by filing date, exportable.** Zero dependencies
|
|
5
|
+
(pandas optional).
|
|
6
|
+
|
|
7
|
+
Backtests leak the future when they use restated numbers or use figures
|
|
8
|
+
before their filing date. This dataset stores every figure **as it was first
|
|
9
|
+
reported** and stamps it with its **filing date**, so `as_of` queries return
|
|
10
|
+
exactly what was public on that day.
|
|
11
|
+
|
|
12
|
+
| Market | Source | Coverage |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| US | SEC EDGAR (public domain) | ~6,900 filers · annual + quarterly · 2014→ |
|
|
15
|
+
| Taiwan | TWSE OpenAPI (Open Government Data License 1.0) | every listed company · accumulating quarterly |
|
|
16
|
+
| Korea | FSS OpenDART | full market · loading |
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install pit-fundamentals
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 60-second start (no signup — public demo key built in)
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import pit_fundamentals as pf
|
|
28
|
+
|
|
29
|
+
# TSMC's history, as first reported
|
|
30
|
+
rows = pf.fundamentals("2330.TW")
|
|
31
|
+
|
|
32
|
+
# What a backtest running on 2022-01-01 was allowed to know about Apple
|
|
33
|
+
snap = pf.latest("AAPL", as_of="2022-01-01")
|
|
34
|
+
print(snap["revenue"]) # FY2021, filed 2021-10-29 — nothing newer leaks
|
|
35
|
+
|
|
36
|
+
# The scored, resolved prediction panel (history incl. losses; delayed on free)
|
|
37
|
+
panel = pf.signals(market="TW", horizon="21d", limit=1000)
|
|
38
|
+
|
|
39
|
+
# pandas users
|
|
40
|
+
df = pf.to_df(rows)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The demo key covers **25 flagship tickers (US · TW · KR) at full fidelity** —
|
|
44
|
+
full fields, full history. Paid plans unlock every ticker; your code doesn't
|
|
45
|
+
change:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
export PIT_FUNDAMENTALS_KEY=ta_live_xxxxxxxx
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Pricing & licences
|
|
52
|
+
|
|
53
|
+
Free / Personal US$29/mo / Commercial US$149/mo / Redistribution US$499/mo —
|
|
54
|
+
plans and full licence texts: <https://www.tradingagentapp.com/fundamentals>
|
|
55
|
+
|
|
56
|
+
What makes the licence unusual: **no export bans, no display-only clause, and
|
|
57
|
+
your derived research is yours forever** (explicitly, in writing — including
|
|
58
|
+
after cancellation). We ingest from public filings directly, so no upstream
|
|
59
|
+
vendor licence forbids you taking the data with you.
|
|
60
|
+
|
|
61
|
+
## Notes worth knowing
|
|
62
|
+
|
|
63
|
+
- **Taiwan income statements are cumulative year-to-date** (Taiwan reporting
|
|
64
|
+
convention: Q2 = H1 total). Difference adjacent quarters for single-quarter
|
|
65
|
+
flows. Balance-sheet items are point-in-time as usual.
|
|
66
|
+
- Every API response embeds its statutory source attribution (e.g. 臺灣證券
|
|
67
|
+
交易所 under OGDL 1.0).
|
|
68
|
+
- Factual, historical data only — no forecasts, no advice, no price/OHLCV.
|
|
69
|
+
|
|
70
|
+
Docs: <https://www.tradingagentapp.com/developers> ·
|
|
71
|
+
Field dictionary and examples included.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pit-fundamentals"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Point-in-time company fundamentals from official regulator filings (US SEC EDGAR, Taiwan TWSE, Korea OpenDART) — as-first-reported, keyed by filing date, exportable. Zero dependencies."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "WU Capital Limited", email = "tradingagentapp@gmail.com" }]
|
|
13
|
+
keywords = [
|
|
14
|
+
"point-in-time", "fundamentals", "PIT", "backtesting", "look-ahead-bias",
|
|
15
|
+
"SEC", "EDGAR", "taiwan", "TWSE", "korea", "OpenDART", "quant", "factor",
|
|
16
|
+
"financial-data", "stock-data",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Programming Language :: Python :: 3",
|
|
24
|
+
"Topic :: Office/Business :: Financial :: Investment",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://www.tradingagentapp.com/fundamentals"
|
|
29
|
+
Documentation = "https://www.tradingagentapp.com/developers"
|
|
30
|
+
"Licence terms" = "https://www.tradingagentapp.com/licences/personal"
|
|
31
|
+
|
|
32
|
+
[tool.hatch.build.targets.wheel]
|
|
33
|
+
packages = ["src/pit_fundamentals"]
|
|
34
|
+
|
|
35
|
+
[tool.hatch.build.targets.sdist]
|
|
36
|
+
include = ["src/pit_fundamentals", "README.md"]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""pit-fundamentals — point-in-time company fundamentals, zero dependencies.
|
|
2
|
+
|
|
3
|
+
As-first-reported figures from official regulator filings (US SEC EDGAR,
|
|
4
|
+
Taiwan TWSE, Korea FSS OpenDART), keyed by their FILING DATE so a backtest at
|
|
5
|
+
date T sees only what was public at T. Served by Trading Agent Data
|
|
6
|
+
(https://www.tradingagentapp.com/fundamentals).
|
|
7
|
+
|
|
8
|
+
Quickstart (works immediately — the public demo key covers 25 flagship
|
|
9
|
+
tickers at full fidelity, no signup):
|
|
10
|
+
|
|
11
|
+
import pit_fundamentals as pf
|
|
12
|
+
|
|
13
|
+
rows = pf.fundamentals("2330.TW") # full history
|
|
14
|
+
snap = pf.latest("AAPL", as_of="2022-01-01") # PIT snapshot
|
|
15
|
+
panel = pf.signals(market="TW", horizon="21d") # scored predictions
|
|
16
|
+
|
|
17
|
+
# with pandas installed:
|
|
18
|
+
df = pf.to_df(rows)
|
|
19
|
+
|
|
20
|
+
Paid keys unlock every ticker — set PIT_FUNDAMENTALS_KEY (or TRADING_AGENT_API_KEY)
|
|
21
|
+
in the environment, or pass api_key=... . Your code does not change otherwise.
|
|
22
|
+
|
|
23
|
+
Data licences: https://www.tradingagentapp.com/licences/personal
|
|
24
|
+
Taiwan data note: income-statement figures are cumulative year-to-date per
|
|
25
|
+
Taiwan reporting convention (Q2 = H1 total) — difference adjacent quarters for
|
|
26
|
+
single-quarter flows. Every response embeds its statutory source attribution.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import json
|
|
32
|
+
import os
|
|
33
|
+
import urllib.parse
|
|
34
|
+
import urllib.request
|
|
35
|
+
|
|
36
|
+
__all__ = ["fundamentals", "latest", "coverage", "signals", "to_df", "ApiError"]
|
|
37
|
+
__version__ = "0.1.0"
|
|
38
|
+
|
|
39
|
+
BASE_URL = os.environ.get("PIT_FUNDAMENTALS_BASE", "https://www.tradingagentapp.com/api/v1")
|
|
40
|
+
DEMO_KEY = "demo"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ApiError(RuntimeError):
|
|
44
|
+
"""Raised when the API returns a non-2xx response."""
|
|
45
|
+
|
|
46
|
+
def __init__(self, status: int, body: str):
|
|
47
|
+
super().__init__(f"HTTP {status}: {body[:300]}")
|
|
48
|
+
self.status = status
|
|
49
|
+
self.body = body
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _key(api_key: str | None) -> str:
|
|
53
|
+
return (
|
|
54
|
+
api_key
|
|
55
|
+
or os.environ.get("PIT_FUNDAMENTALS_KEY")
|
|
56
|
+
or os.environ.get("TRADING_AGENT_API_KEY")
|
|
57
|
+
or DEMO_KEY
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _get(path: str, params: dict, api_key: str | None):
|
|
62
|
+
qs = urllib.parse.urlencode({k: v for k, v in params.items() if v is not None})
|
|
63
|
+
req = urllib.request.Request(
|
|
64
|
+
f"{BASE_URL}{path}?{qs}",
|
|
65
|
+
headers={
|
|
66
|
+
"Authorization": f"Bearer {_key(api_key)}",
|
|
67
|
+
"User-Agent": f"pit-fundamentals/{__version__}",
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
try:
|
|
71
|
+
with urllib.request.urlopen(req, timeout=60) as r:
|
|
72
|
+
return json.loads(r.read().decode("utf-8"))
|
|
73
|
+
except urllib.error.HTTPError as e: # pragma: no cover - passthrough
|
|
74
|
+
raise ApiError(e.code, e.read().decode("utf-8", "replace")) from None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def fundamentals(
|
|
78
|
+
ticker: str,
|
|
79
|
+
*,
|
|
80
|
+
as_of: str | None = None,
|
|
81
|
+
metric: str | None = None,
|
|
82
|
+
from_: str | None = None,
|
|
83
|
+
market: str | None = None,
|
|
84
|
+
api_key: str | None = None,
|
|
85
|
+
) -> list[dict]:
|
|
86
|
+
"""As-first-reported history for one ticker (list of row dicts).
|
|
87
|
+
|
|
88
|
+
Row fields: m (metric), fy/fp (fiscal year/period), end (period end),
|
|
89
|
+
filed (filing date — the point-in-time key), v (value), u (unit).
|
|
90
|
+
`as_of` returns only rows with filed <= as_of (no look-ahead).
|
|
91
|
+
"""
|
|
92
|
+
out = _get(
|
|
93
|
+
"/fundamentals",
|
|
94
|
+
{"ticker": ticker, "as_of": as_of, "metric": metric, "from": from_, "market": market},
|
|
95
|
+
api_key,
|
|
96
|
+
)
|
|
97
|
+
return out.get("data", [])
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def latest(ticker: str, *, as_of: str | None = None, api_key: str | None = None) -> dict:
|
|
101
|
+
"""The as-of snapshot: latest value per metric with filed <= as_of."""
|
|
102
|
+
out = _get("/fundamentals", {"ticker": ticker, "as_of": as_of, "view": "latest"}, api_key)
|
|
103
|
+
return out.get("data", {})
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def coverage(api_key: str | None = None) -> dict:
|
|
107
|
+
"""Markets, tickers, per-market manifests, and (free tier) the ticker allowlist."""
|
|
108
|
+
return _get("/fundamentals", {}, api_key)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def signals(
|
|
112
|
+
*,
|
|
113
|
+
market: str | None = None,
|
|
114
|
+
horizon: str | None = None,
|
|
115
|
+
from_: str | None = None,
|
|
116
|
+
to: str | None = None,
|
|
117
|
+
limit: int | None = None,
|
|
118
|
+
api_key: str | None = None,
|
|
119
|
+
) -> list[dict]:
|
|
120
|
+
"""The resolved (historical, scored) prediction panel — wins and losses.
|
|
121
|
+
|
|
122
|
+
Free/demo keys get a ~90-day-delayed view; this is factual history, not
|
|
123
|
+
forward recommendations. predicted_pct / actual_pct are FRACTIONS.
|
|
124
|
+
"""
|
|
125
|
+
out = _get(
|
|
126
|
+
"/signals",
|
|
127
|
+
{"market": market, "horizon": horizon, "from": from_, "to": to, "limit": limit},
|
|
128
|
+
api_key,
|
|
129
|
+
)
|
|
130
|
+
return out.get("data", [])
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def to_df(rows: list[dict]):
|
|
134
|
+
"""Convert a row list to a pandas DataFrame (pandas required only here)."""
|
|
135
|
+
import pandas as pd # local import: the package itself stays zero-dep
|
|
136
|
+
|
|
137
|
+
return pd.DataFrame(rows)
|