simudyne-pulse 0.7.0.dev4__tar.gz → 0.7.0.dev6__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.
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/PKG-INFO +1 -1
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/pyproject.toml +1 -1
- simudyne_pulse-0.7.0.dev6/src/simudyne/resources/api_keys.py +83 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/data.py +21 -12
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/fix.py +7 -5
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/fm.py +71 -43
- simudyne_pulse-0.7.0.dev6/src/simudyne/resources/profile.py +103 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/simulation.py +403 -316
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/simulator_gym.py +33 -20
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/validation.py +303 -130
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/PKG-INFO +1 -1
- simudyne_pulse-0.7.0.dev4/src/simudyne/resources/api_keys.py +0 -12
- simudyne_pulse-0.7.0.dev4/src/simudyne/resources/profile.py +0 -30
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/LICENSE +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/README.md +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/setup.cfg +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/__init__.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/client.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/exceptions.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/__init__.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/historical.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/SOURCES.txt +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/dependency_links.txt +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/requires.txt +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/top_level.txt +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/tests/test_new_resources.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/tests/test_simulator_gym.py +0 -0
- {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/tests/test_validation.py +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
class ApiKeysResource:
|
|
2
|
+
def __init__(self, client):
|
|
3
|
+
self._client = client
|
|
4
|
+
|
|
5
|
+
def create(self, name: str):
|
|
6
|
+
"""Mint a new API key.
|
|
7
|
+
|
|
8
|
+
The only call that ever returns the key material. It is shown once —
|
|
9
|
+
store it before the call returns, or mint another.
|
|
10
|
+
|
|
11
|
+
Parameters
|
|
12
|
+
----------
|
|
13
|
+
name : str
|
|
14
|
+
A label for the key. Name it by purpose ("notebook",
|
|
15
|
+
"production", "CI pipeline") so you know which to revoke if one
|
|
16
|
+
is compromised.
|
|
17
|
+
|
|
18
|
+
Returns
|
|
19
|
+
-------
|
|
20
|
+
dict
|
|
21
|
+
api_key : str
|
|
22
|
+
The key material, shown exactly once.
|
|
23
|
+
api_key_id : str
|
|
24
|
+
The handle to pass to :meth:`revoke`.
|
|
25
|
+
warning : str
|
|
26
|
+
A reminder that the key will not be shown again.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> new_key = client.api_keys.create(name="Training script")
|
|
31
|
+
>>> print(new_key["api_key"]) # save this, it won't be shown again
|
|
32
|
+
"""
|
|
33
|
+
return self._client._request("POST", "/api-keys", json={"name": name})
|
|
34
|
+
|
|
35
|
+
def list(self):
|
|
36
|
+
"""List your active API keys and their labels.
|
|
37
|
+
|
|
38
|
+
The full key is never returned after creation; only ``key_prefix``,
|
|
39
|
+
the first 12 characters, is stored. That is enough to tell keys apart
|
|
40
|
+
and not enough to reconstruct one.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
list of dict
|
|
45
|
+
One entry per key, each with:
|
|
46
|
+
|
|
47
|
+
- api_key_id (str): the handle to pass to :meth:`revoke`
|
|
48
|
+
- key_prefix (str): first 12 characters, e.g. "pk_live_ab12"
|
|
49
|
+
- name (str): the label you gave it
|
|
50
|
+
- is_active (bool): False once revoked
|
|
51
|
+
- created_at (str): when it was created
|
|
52
|
+
- last_used_at (str or None): None until the key is first used
|
|
53
|
+
- expires_at (str or None): None for keys that do not expire
|
|
54
|
+
|
|
55
|
+
Examples
|
|
56
|
+
--------
|
|
57
|
+
>>> for key in client.api_keys.list():
|
|
58
|
+
... print(key["name"], key["key_prefix"], key["created_at"])
|
|
59
|
+
"""
|
|
60
|
+
return self._client._request("GET", "/api-keys")
|
|
61
|
+
|
|
62
|
+
def revoke(self, key_id: str):
|
|
63
|
+
"""Invalidate a key immediately.
|
|
64
|
+
|
|
65
|
+
Any request still using the key returns HTTP 401 from this point on.
|
|
66
|
+
|
|
67
|
+
Parameters
|
|
68
|
+
----------
|
|
69
|
+
key_id : str
|
|
70
|
+
The ``api_key_id`` from :meth:`list` or :meth:`create` — not the
|
|
71
|
+
key material itself.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
dict
|
|
76
|
+
The revocation result.
|
|
77
|
+
|
|
78
|
+
Examples
|
|
79
|
+
--------
|
|
80
|
+
>>> new_key = client.api_keys.create(name="Training script")
|
|
81
|
+
>>> client.api_keys.revoke(key_id=new_key["api_key_id"])
|
|
82
|
+
"""
|
|
83
|
+
return self._client._request("DELETE", f"/api-keys/{key_id}")
|
|
@@ -20,19 +20,28 @@ class DataResource:
|
|
|
20
20
|
All arguments are optional filters; with none passed the whole catalog
|
|
21
21
|
comes back, as before.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
symbol : str, optional
|
|
26
|
+
Exact symbol, e.g. "700.HK".
|
|
27
|
+
exchange : str, optional
|
|
28
|
+
Exchange protocol, e.g. "hkex_securities".
|
|
29
|
+
provider : str, optional
|
|
30
|
+
Data provider, e.g. "omd" or "bmll".
|
|
31
|
+
date : str, optional
|
|
32
|
+
Calibration date "YYYY-MM-DD". Keeps only instruments
|
|
33
|
+
calibrated on that date, and narrows each instrument's
|
|
34
|
+
available_dates to it.
|
|
35
|
+
q : str, optional
|
|
36
|
+
Case-insensitive substring match over ticker and company name.
|
|
37
|
+
limit : int, optional
|
|
38
|
+
Max instruments to return.
|
|
39
|
+
offset : int, optional
|
|
40
|
+
Instruments to skip (for paging alongside limit).
|
|
33
41
|
|
|
34
|
-
Returns
|
|
35
|
-
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
list of instrument dicts, each with available_dates.
|
|
36
45
|
"""
|
|
37
46
|
params = {
|
|
38
47
|
k: v for k, v in {
|
|
@@ -18,13 +18,15 @@ class FixResource:
|
|
|
18
18
|
def usage(self) -> dict:
|
|
19
19
|
"""FIX simulation statistics: what was run over FIX, and how often.
|
|
20
20
|
|
|
21
|
-
Returns
|
|
22
|
-
|
|
21
|
+
Returns
|
|
22
|
+
-------
|
|
23
|
+
dict with ``total_runs``, ``simulated_seconds``, and ``runs`` — one
|
|
23
24
|
entry per distinct configuration, each with its ``symbol``,
|
|
24
25
|
``cal_date``, ``scenario`` and ``runs`` count.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
Examples
|
|
28
|
+
--------
|
|
29
|
+
>>> usage = client.fix.usage()
|
|
30
|
+
>>> print(f"{usage['total_runs']} FIX runs")
|
|
29
31
|
"""
|
|
30
32
|
return self._client._request("GET", USAGE_PATH)
|
|
@@ -47,8 +47,9 @@ class FmResource:
|
|
|
47
47
|
``min_prompt_rows``, and the ``model_args`` descriptors for the knobs
|
|
48
48
|
run() will accept. Pro tier.
|
|
49
49
|
|
|
50
|
-
Returns
|
|
51
|
-
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
dict with a ``models`` list.
|
|
52
53
|
"""
|
|
53
54
|
return self._client._request("GET", MODELS_PATH)
|
|
54
55
|
|
|
@@ -71,19 +72,29 @@ class FmResource:
|
|
|
71
72
|
restricts the result to the (provider, exchange) markets that model's
|
|
72
73
|
``supported_data`` declares — exactly what run() will accept.
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
model_id : str, optional
|
|
78
|
+
Registered model (see models()). Unknown id -> 404.
|
|
79
|
+
symbol : str, optional
|
|
80
|
+
Exact symbol, e.g. "TSCO" or "700".
|
|
81
|
+
q : str, optional
|
|
82
|
+
Case-insensitive substring match over the symbol.
|
|
83
|
+
provider : str, optional
|
|
84
|
+
Data provider, e.g. "bmll".
|
|
85
|
+
exchange : str, optional
|
|
86
|
+
Protocol, e.g. "lse" or "hkex_securities".
|
|
87
|
+
date : str, optional
|
|
88
|
+
Trading date YYYY-MM-DD; keeps only symbols with data on it,
|
|
89
|
+
and only that date.
|
|
90
|
+
limit : int, default 50
|
|
91
|
+
Max symbols to return (default 50, max 200).
|
|
92
|
+
offset : int, default 0
|
|
93
|
+
Symbols to skip, for paging.
|
|
94
|
+
|
|
95
|
+
Returns
|
|
96
|
+
-------
|
|
97
|
+
dict with ``symbols`` (each with its provider, exchange and dates)
|
|
87
98
|
and ``total``, paged by symbol identity.
|
|
88
99
|
"""
|
|
89
100
|
params = {"limit": limit, "offset": offset}
|
|
@@ -112,28 +123,42 @@ class FmResource:
|
|
|
112
123
|
) -> dict:
|
|
113
124
|
"""Submit a foundation-model inference job. Pro tier.
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
model_id : str
|
|
129
|
+
A model from models().
|
|
130
|
+
symbol : str
|
|
131
|
+
Symbol whose real data becomes the prompt context.
|
|
132
|
+
cal_date : str
|
|
133
|
+
Trading date of the prompt, YYYY-MM-DD.
|
|
134
|
+
provider : str
|
|
135
|
+
Data provider, e.g. "bmll".
|
|
136
|
+
exchange : str
|
|
137
|
+
Exchange protocol, e.g. "hkex_securities".
|
|
138
|
+
duration_minutes : float, optional
|
|
139
|
+
Sim horizon as wall-clock minutes measured from
|
|
140
|
+
the first row of the context. The resulting frame count is
|
|
141
|
+
reported in the run's output rather than requested up front.
|
|
142
|
+
horizon : int, optional
|
|
143
|
+
Raw frame count — the older form; applies only when
|
|
144
|
+
duration_minutes is unset.
|
|
145
|
+
n_runs : int, default 1
|
|
146
|
+
Monte Carlo runs, 1-8 (per-run seeds derived from ``seed``
|
|
147
|
+
exactly as the ABM derives them).
|
|
148
|
+
seed : int, default 42
|
|
149
|
+
Random seed (default 42).
|
|
150
|
+
model_args : dict, optional
|
|
151
|
+
Overrides for the model's declared knobs (see
|
|
152
|
+
models()); unknown or out-of-range keys are rejected with 400.
|
|
153
|
+
device : str, optional
|
|
154
|
+
"cpu" or "gpu"; None uses the model's default.
|
|
155
|
+
exec_algos : list, optional
|
|
156
|
+
Execution algorithms, the ABM's config shape. At most
|
|
157
|
+
one per job; market runs only.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
dict with job_id, the model version, and the queued sim_ids.
|
|
137
162
|
"""
|
|
138
163
|
payload = {
|
|
139
164
|
"model_id": model_id,
|
|
@@ -165,8 +190,9 @@ class FmResource:
|
|
|
165
190
|
) -> dict:
|
|
166
191
|
"""Start a live streaming session instead of a batch job. Pro tier.
|
|
167
192
|
|
|
168
|
-
Returns
|
|
169
|
-
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
dict with ``token`` (used to connect to the live chart),
|
|
170
196
|
``job_id`` and ``model_id``.
|
|
171
197
|
"""
|
|
172
198
|
payload = {"model_id": model_id, "seed": seed}
|
|
@@ -179,8 +205,9 @@ class FmResource:
|
|
|
179
205
|
def job_status(self, job_id: str) -> dict:
|
|
180
206
|
"""Foundation-model job status.
|
|
181
207
|
|
|
182
|
-
Returns
|
|
183
|
-
|
|
208
|
+
Returns
|
|
209
|
+
-------
|
|
210
|
+
dict with job_id, ``status``, ``message``, ``detail``,
|
|
184
211
|
``started_at`` and ``completed_at``. ``status`` is one of queued,
|
|
185
212
|
provisioning, starting, running, complete or failed — only the
|
|
186
213
|
last two are terminal (see TERMINAL_STATUSES), so poll until one
|
|
@@ -193,7 +220,8 @@ class FmResource:
|
|
|
193
220
|
def job_logs(self, job_id: str) -> dict:
|
|
194
221
|
"""Foundation-model job pod logs.
|
|
195
222
|
|
|
196
|
-
Returns
|
|
197
|
-
|
|
223
|
+
Returns
|
|
224
|
+
-------
|
|
225
|
+
dict with ``logs`` — the thing to read when a job failed.
|
|
198
226
|
"""
|
|
199
227
|
return self._client._request("GET", f"{JOBS_PATH}/{job_id}/logs")
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
class ProfileResource:
|
|
2
|
+
def __init__(self, client):
|
|
3
|
+
self._client = client
|
|
4
|
+
|
|
5
|
+
def get(self):
|
|
6
|
+
"""Return your account record.
|
|
7
|
+
|
|
8
|
+
The cheapest way to confirm a key works and to find out which tier it
|
|
9
|
+
is on — worth calling first when a 403 surprises you.
|
|
10
|
+
|
|
11
|
+
Returns
|
|
12
|
+
-------
|
|
13
|
+
dict
|
|
14
|
+
user_id : str
|
|
15
|
+
Your account id. Also your FIX CompID, where FIX is enabled.
|
|
16
|
+
email : str
|
|
17
|
+
The address the account was created with.
|
|
18
|
+
name : str
|
|
19
|
+
Display name.
|
|
20
|
+
organization : str
|
|
21
|
+
Organisation, empty string if never set.
|
|
22
|
+
is_admin : bool
|
|
23
|
+
Administrative flag governing user administration, not
|
|
24
|
+
simulator access. It is not a tier bypass: an admin flag on a
|
|
25
|
+
free-tier key still cannot run a simulation. When a call
|
|
26
|
+
returns 403, read ``tier``, not this.
|
|
27
|
+
tier : {"free", "pro", "demo"}
|
|
28
|
+
What gates every endpoint.
|
|
29
|
+
download_limit : int
|
|
30
|
+
New simulation groups per rolling 24 hours. Only enforced on
|
|
31
|
+
the free tier.
|
|
32
|
+
|
|
33
|
+
Examples
|
|
34
|
+
--------
|
|
35
|
+
>>> me = client.profile.get()
|
|
36
|
+
>>> print(f"{me['email']} — tier {me['tier']}")
|
|
37
|
+
"""
|
|
38
|
+
return self._client._request("GET", "/profile")
|
|
39
|
+
|
|
40
|
+
def usage(self):
|
|
41
|
+
"""Return your request count for the current calendar month.
|
|
42
|
+
|
|
43
|
+
Resets on the 1st, and counts *requests* rather than simulations —
|
|
44
|
+
one ``run()`` of 100 Monte Carlo runs is a single request here.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
dict
|
|
49
|
+
user_id : str
|
|
50
|
+
Your account id.
|
|
51
|
+
month : str
|
|
52
|
+
The calendar month being reported, "YYYY-MM".
|
|
53
|
+
total_requests : int
|
|
54
|
+
Requests so far this month.
|
|
55
|
+
by_endpoint : dict
|
|
56
|
+
Request count keyed by endpoint path. The keys are the
|
|
57
|
+
concrete paths that were called, so a job-scoped endpoint
|
|
58
|
+
appears once per job id rather than as a template — aggregate
|
|
59
|
+
by prefix if you want per-endpoint totals.
|
|
60
|
+
|
|
61
|
+
Examples
|
|
62
|
+
--------
|
|
63
|
+
>>> usage = client.profile.usage()
|
|
64
|
+
>>> print(f"{usage['month']}: {usage['total_requests']} requests")
|
|
65
|
+
"""
|
|
66
|
+
return self._client._request("GET", "/profile/usage")
|
|
67
|
+
|
|
68
|
+
def downloads(self):
|
|
69
|
+
"""Return the free-tier download allowance for the current window.
|
|
70
|
+
|
|
71
|
+
The unit is a simulation group — every Monte Carlo run of one
|
|
72
|
+
symbol/date/scenario — not a call, a run, or a file. Membership is
|
|
73
|
+
permanent: a group you have downloaded before is free to re-fetch
|
|
74
|
+
forever, in any run or file format.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
dict
|
|
79
|
+
limit : int or None
|
|
80
|
+
Groups per window. None on the pro and demo tiers, meaning
|
|
81
|
+
unlimited.
|
|
82
|
+
used : int
|
|
83
|
+
New groups added in the current window.
|
|
84
|
+
remaining : int or None
|
|
85
|
+
``limit`` minus ``used``, floored at 0. None when unlimited.
|
|
86
|
+
window_hours : int
|
|
87
|
+
Length of the rolling window, 24.
|
|
88
|
+
downloaded_groups : list of str or None
|
|
89
|
+
Every group you have ever downloaded. None when unlimited.
|
|
90
|
+
downloaded_group_details : list of dict or None
|
|
91
|
+
The same groups, each with a ``downloaded_at`` timestamp.
|
|
92
|
+
|
|
93
|
+
Notes
|
|
94
|
+
-----
|
|
95
|
+
A request that would exceed the allowance returns HTTP 429 without
|
|
96
|
+
charging anything, so a partial download never silently eats quota.
|
|
97
|
+
|
|
98
|
+
Examples
|
|
99
|
+
--------
|
|
100
|
+
>>> quota = client.profile.downloads()
|
|
101
|
+
>>> print(f"{quota['used']}/{quota['limit']} used, {quota['remaining']} left")
|
|
102
|
+
"""
|
|
103
|
+
return self._client._request("GET", "/profile/downloads")
|