iturri 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.
- iturri/__init__.py +87 -0
- iturri-0.1.0.dist-info/METADATA +28 -0
- iturri-0.1.0.dist-info/RECORD +5 -0
- iturri-0.1.0.dist-info/WHEEL +5 -0
- iturri-0.1.0.dist-info/top_level.txt +1 -0
iturri/__init__.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""iturri — client for the Iturri verified market-data API.
|
|
2
|
+
|
|
3
|
+
Every bar carries a quality flag; filter on it. Zero hard dependencies;
|
|
4
|
+
if pandas is installed, bars() and features() return DataFrames.
|
|
5
|
+
|
|
6
|
+
import iturri
|
|
7
|
+
df = iturri.bars("BTC", "1h", start="2024-01-01", end="2024-02-01")
|
|
8
|
+
df = df[df.quality == "verified"]
|
|
9
|
+
|
|
10
|
+
Iturri sells data and tooling only — nothing it returns is a trading
|
|
11
|
+
signal, a prediction, or financial advice.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import urllib.parse
|
|
18
|
+
import urllib.request
|
|
19
|
+
|
|
20
|
+
__version__ = "0.1.0"
|
|
21
|
+
BASE_URL = "https://iturri-data.odd-haze-3940.workers.dev"
|
|
22
|
+
|
|
23
|
+
QUALITY = {0: "verified", 1: "raw", 2: "reconciled", 3: "interpolated",
|
|
24
|
+
4: "disputed", 5: "outage"}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _get(path: str, params: dict | None = None) -> dict:
|
|
28
|
+
url = BASE_URL + path
|
|
29
|
+
if params:
|
|
30
|
+
url += "?" + urllib.parse.urlencode({k: v for k, v in params.items()
|
|
31
|
+
if v is not None})
|
|
32
|
+
req = urllib.request.Request(url, headers={"User-Agent": f"iturri-py/{__version__}"})
|
|
33
|
+
with urllib.request.urlopen(req, timeout=60) as r:
|
|
34
|
+
return json.loads(r.read())
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _maybe_frame(data: dict, quality_key: str | None = None):
|
|
38
|
+
"""Columnar dict → DataFrame when pandas is available, else plain dict."""
|
|
39
|
+
try:
|
|
40
|
+
import pandas as pd
|
|
41
|
+
except ImportError:
|
|
42
|
+
return data
|
|
43
|
+
d = dict(data)
|
|
44
|
+
t = pd.to_datetime(d.pop("t"), unit="s", utc=True).tz_convert(None)
|
|
45
|
+
if quality_key and quality_key in d:
|
|
46
|
+
d["quality"] = [QUALITY.get(q, "raw") for q in d.pop(quality_key)]
|
|
47
|
+
df = pd.DataFrame(d, index=t)
|
|
48
|
+
df.index.name = "timestamp"
|
|
49
|
+
return df
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def catalog() -> dict:
|
|
53
|
+
"""Full catalog: symbols, timeframes, ranges, pricing, quality legend. Free."""
|
|
54
|
+
return _get("/api/catalog")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def bars(symbol: str, tf: str, start: str | None = None, end: str | None = None):
|
|
58
|
+
"""Quality-flagged OHLCV. Returns a DataFrame (pandas) or columnar dict.
|
|
59
|
+
|
|
60
|
+
tf: crypto "1h"/"1d" · equities "1d_raw" (as-traded) / "1d_split".
|
|
61
|
+
"""
|
|
62
|
+
r = _get("/api/bars", {"symbol": symbol, "tf": tf, "start": start, "end": end})
|
|
63
|
+
out = _maybe_frame(r["data"], quality_key="q")
|
|
64
|
+
if not isinstance(out, dict):
|
|
65
|
+
out = out.rename(columns={"o": "open", "h": "high", "l": "low",
|
|
66
|
+
"c": "close", "v": "volume"})
|
|
67
|
+
out.attrs.update({k: r[k] for k in ("symbol", "tf", "datacard", "price_usd")
|
|
68
|
+
if k in r})
|
|
69
|
+
return out
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def features(symbol: str, tf: str, start: str | None = None, end: str | None = None):
|
|
73
|
+
"""Documented leakage-safe feature matrix rows (19 features + regime)."""
|
|
74
|
+
r = _get("/api/features", {"symbol": symbol, "tf": tf, "start": start, "end": end})
|
|
75
|
+
return _maybe_frame(r["data"])
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def bundle(pack: str) -> dict:
|
|
79
|
+
"""Signed download URLs for a training pack: 'crypto' or 'equities'."""
|
|
80
|
+
req = urllib.request.Request(
|
|
81
|
+
BASE_URL + "/api/bundle", data=json.dumps({"pack": pack}).encode(),
|
|
82
|
+
headers={"Content-Type": "application/json",
|
|
83
|
+
"User-Agent": f"iturri-py/{__version__}"})
|
|
84
|
+
with urllib.request.urlopen(req, timeout=60) as r:
|
|
85
|
+
out = json.loads(r.read())
|
|
86
|
+
out["signed_urls"] = [BASE_URL + u for u in out.get("signed_urls", [])]
|
|
87
|
+
return out
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iturri
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Client for the Iturri verified market-data API — every bar verified or flagged
|
|
5
|
+
Author: Iturri
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Provides-Extra: pandas
|
|
10
|
+
Requires-Dist: pandas>=2.0; extra == "pandas"
|
|
11
|
+
|
|
12
|
+
# iturri
|
|
13
|
+
|
|
14
|
+
Client for the [Iturri](https://iturri-data.odd-haze-3940.workers.dev) verified
|
|
15
|
+
market-data API. Every bar quality-flagged; filter on it.
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
import iturri
|
|
19
|
+
|
|
20
|
+
iturri.catalog() # free discovery
|
|
21
|
+
df = iturri.bars("BTC", "1h", start="2024-01-01", end="2024-02-01")
|
|
22
|
+
df = df[df.quality == "verified"] # the whole point
|
|
23
|
+
feats = iturri.features("SPY", "1d_split", start="2026-06-01")
|
|
24
|
+
iturri.bundle("crypto") # signed training-pack URLs
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Zero hard dependencies. With pandas installed you get DataFrames; without it,
|
|
28
|
+
columnar dicts. Data and tooling only — never signals or advice.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
iturri/__init__.py,sha256=FWnS396JeXZCIk4IIgRsSNTfUUZFVPdCvov9UuEVtko,3296
|
|
2
|
+
iturri-0.1.0.dist-info/METADATA,sha256=44CmDLTT2jjfqvdoERJKAUQW1fNM2q4CT6OXVmVCF6g,945
|
|
3
|
+
iturri-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
4
|
+
iturri-0.1.0.dist-info/top_level.txt,sha256=smA6D5_GyB6MqLCrvMfDLyjbOUK_J9IDe0S7bROOv44,7
|
|
5
|
+
iturri-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
iturri
|