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.
Files changed (28) hide show
  1. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/PKG-INFO +1 -1
  2. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/pyproject.toml +1 -1
  3. simudyne_pulse-0.7.0.dev6/src/simudyne/resources/api_keys.py +83 -0
  4. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/data.py +21 -12
  5. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/fix.py +7 -5
  6. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/fm.py +71 -43
  7. simudyne_pulse-0.7.0.dev6/src/simudyne/resources/profile.py +103 -0
  8. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/simulation.py +403 -316
  9. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/simulator_gym.py +33 -20
  10. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/validation.py +303 -130
  11. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/PKG-INFO +1 -1
  12. simudyne_pulse-0.7.0.dev4/src/simudyne/resources/api_keys.py +0 -12
  13. simudyne_pulse-0.7.0.dev4/src/simudyne/resources/profile.py +0 -30
  14. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/LICENSE +0 -0
  15. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/README.md +0 -0
  16. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/setup.cfg +0 -0
  17. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/__init__.py +0 -0
  18. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/client.py +0 -0
  19. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/exceptions.py +0 -0
  20. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/__init__.py +0 -0
  21. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne/resources/historical.py +0 -0
  22. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/SOURCES.txt +0 -0
  23. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/dependency_links.txt +0 -0
  24. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/requires.txt +0 -0
  25. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/src/simudyne_pulse.egg-info/top_level.txt +0 -0
  26. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/tests/test_new_resources.py +0 -0
  27. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/tests/test_simulator_gym.py +0 -0
  28. {simudyne_pulse-0.7.0.dev4 → simudyne_pulse-0.7.0.dev6}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simudyne-pulse
3
- Version: 0.7.0.dev4
3
+ Version: 0.7.0.dev6
4
4
  Summary: Python SDK for the Simudyne Pulse synthetic market data API
5
5
  Author-email: Simudyne <support@simudyne.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simudyne-pulse"
7
- version = "0.7.0-dev.4"
7
+ version = "0.7.0-dev.6"
8
8
  description = "Python SDK for the Simudyne Pulse synthetic market data API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -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
- Args:
24
- symbol: Exact symbol, e.g. "700.HK".
25
- exchange: Exchange protocol, e.g. "hkex_securities".
26
- provider: Data provider, e.g. "omd" or "bmll".
27
- date: Calibration date "YYYY-MM-DD". Keeps only instruments
28
- calibrated on that date, and narrows each instrument's
29
- available_dates to it.
30
- q: Case-insensitive substring match over ticker and company name.
31
- limit: Max instruments to return.
32
- offset: Instruments to skip (for paging alongside limit).
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
- list of instrument dicts, each with available_dates.
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
- dict with ``total_runs``, ``simulated_seconds``, and ``runs`` — one
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
- Example:
27
- >>> usage = client.fix.usage()
28
- >>> print(f"{usage['total_runs']} FIX runs")
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
- dict with a ``models`` list.
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
- Args:
75
- model_id: Registered model (see models()). Unknown id -> 404.
76
- symbol: Exact symbol, e.g. "TSCO" or "700".
77
- q: Case-insensitive substring match over the symbol.
78
- provider: Data provider, e.g. "bmll".
79
- exchange: Protocol, e.g. "lse" or "hkex_securities".
80
- date: Trading date YYYY-MM-DD; keeps only symbols with data on it,
81
- and only that date.
82
- limit: Max symbols to return (default 50, max 200).
83
- offset: Symbols to skip, for paging.
84
-
85
- Returns:
86
- dict with ``symbols`` (each with its provider, exchange and dates)
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
- Args:
116
- model_id: A model from models().
117
- symbol: Symbol whose real data becomes the prompt context.
118
- cal_date: Trading date of the prompt, YYYY-MM-DD.
119
- provider: Data provider, e.g. "bmll".
120
- exchange: Exchange protocol, e.g. "hkex_securities".
121
- duration_minutes: Sim horizon as wall-clock minutes measured from
122
- the first row of the context. The resulting frame count is
123
- reported in the run's output rather than requested up front.
124
- horizon: Raw frame count — the older form; applies only when
125
- duration_minutes is unset.
126
- n_runs: Monte Carlo runs, 1-8 (per-run seeds derived from ``seed``
127
- exactly as the ABM derives them).
128
- seed: Random seed (default 42).
129
- model_args: Overrides for the model's declared knobs (see
130
- models()); unknown or out-of-range keys are rejected with 400.
131
- device: "cpu" or "gpu"; None uses the model's default.
132
- exec_algos: Execution algorithms, the ABM's config shape. At most
133
- one per job; market runs only.
134
-
135
- Returns:
136
- dict with job_id, the model version, and the queued sim_ids.
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
- dict with ``token`` (used to connect to the live chart),
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
- dict with job_id, ``status``, ``message``, ``detail``,
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
- dict with ``logs`` — the thing to read when a job failed.
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")