Docs
Full API reference for the Alphio open platform.
Getting started
- 1.Create an API key in API Key. Copy it once — we hash it before storage.
- 2.Onboard your end users:
UpsertVirtualUser→CreateChatSession→/openchat-steam/completions - 3.Wire your SSE reader to handle
submitted→delta* →doneevents.
curl https://api.alphio.ai/v1/openapi/users \
-H "Authorization: Bearer pk_live_••••••••••••••••••••••••••••" \
-H "Content-Type: application/json" \
-d '{"partner_user_ref": "u_998877"}'- Base URL
- https://api.alphio.ai
- Response envelope
- { ret, msg, data }
- HTTP status
- Always 200 (for non-SSE). Inspect ret for the business result.
- SSE
- Chat completions stream as text/event-stream.
Authentication
Every request carries a Bearer API key. End-user-scoped endpoints additionally need an X-Partner-User header.
| Header | Value | When |
|---|---|---|
| Authorization | Bearer pk_live_… | Every request |
| Content-Type | application/json | Every request |
| X-Partner-User | your_user_id | Only for end-user-scoped endpoints: /openchat-steam/completions + whales/following/ranking |
| Accept | text/event-stream | SSE chat only |
The value of X-Partner-User is your own user ID. The platform maps it to a stable internal_user_id like op_{partner_code}_{nanoid}. The user must first be registered via UpsertVirtualUser or chat returns ret=10404.
Errors & limits
| ret | Meaning | Typical cause |
|---|---|---|
| 0 | OK | Success |
| 10400 | Bad request | Missing required field / type mismatch / empty message |
| 10401 | Unauthenticated | Missing / wrong / expired / revoked Bearer |
| 10403 | Forbidden | User disabled / cross-user access |
| 10404 | Not found | User not registered (call UpsertVirtualUser) / bad session_id |
| 10429 | Rate limited | RPM quota exceeded |
| 10500 | Server error | Contact support with occurred_at / chat_id |
| 10501 | Insufficient balance | Top up to resume chat |
Default ceilings: 600 partner RPM · 60 per-user RPM · 8 concurrent chat streams. Negotiated on a per-plan basis.
Billing: one chat round (submit → done) deducts one billable unit. Interrupted / disconnected sessions still bill (anti-spam). failed events do not bill. Analysis, Whales, and Data endpoints are free of charge.
Virtual users
Manage end-user identities under your partner account. Virtual users are created lazily; the same partner_user_ref always maps to the same internal_user_id.
Register or fetch a virtual user. Idempotent — calling repeatedly with the same partner_user_ref is safe.
| Field | Type | Required | Description |
|---|---|---|---|
| partner_user_ref | string | yes | Your own user ID for this end user. |
| display_name | string | no | Optional, for audit/debugging. |
| metadata | string | no | Opaque JSON string, not parsed by the platform. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | VirtualUser | Response payload. |
| └internal_user_id | string | Platform-assigned ID. Format: "op_{partner_code}_{nanoid12}". |
| └partner_user_ref | string | Echoed back. |
| └display_name | string | Echoed back. |
| └metadata | string | Echoed back (JSON string). |
| └status | string | "active" / "disabled". |
| └is_new | bool | true only on first creation. |
| └created_at | string | ISO8601 UTC. |
| └last_active_at | string | ISO8601 UTC. Empty if never used. |
curl -X POST https://api.alphio.ai/v1/openapi/users \
-H "Authorization: Bearer pk_live_••••••••••••••••••••••••••••" \
-H "Content-Type: application/json" \
-d '{
"partner_user_ref": "u_998877",
"display_name": "Alice"
}'{
"ret": 0,
"msg": "ok",
"data": {
"internal_user_id": "op_intellectia_qUk8CyDetjsK",
"partner_user_ref": "u_998877",
"display_name": "Alice",
"metadata": "",
"status": "active",
"is_new": true,
"created_at": "2026-06-09T08:02:14Z",
"last_active_at": ""
}
}Look up a virtual user by partner_user_ref. Response shape matches UpsertVirtualUser except is_new is always false.
| Field | Type | Required | Description |
|---|---|---|---|
| partner_user_ref | string | yes | — |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | VirtualUser | Response payload. |
| └internal_user_id | string | Platform-assigned ID. Format: "op_{partner_code}_{nanoid12}". |
| └partner_user_ref | string | Echoed back. |
| └display_name | string | Echoed back. |
| └metadata | string | Echoed back (JSON string). |
| └status | string | "active" / "disabled". |
| └is_new | bool | true only on first creation. |
| └created_at | string | ISO8601 UTC. |
| └last_active_at | string | ISO8601 UTC. Empty if never used. |
Disable a virtual user. Their chat requests will return ret=10403 until re-enabled via UpsertVirtualUser.
| Field | Type | Required | Description |
|---|---|---|---|
| partner_user_ref | string | yes | — |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DisableVirtualUserData | Response payload. |
| └status | string | Always "disabled". |
Paginated list of your virtual users.
| Field | Type | Required | Description |
|---|---|---|---|
| filter | VirtualUserListFilter | no | Optional filters. |
| └status | string | no | "active" / "disabled" / "" (all). |
| └created_after | string | no | ISO8601 UTC. |
| └created_before | string | no | ISO8601 UTC. |
| page | int32 | no | 1-indexed. Default 1. |
| size | int32 | no | Default 20, max 200. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ListVirtualUsersData | Response payload. |
| └items | VirtualUser[] | — |
| └internal_user_id | string | Platform-assigned ID. Format: "op_{partner_code}_{nanoid12}". |
| └partner_user_ref | string | Echoed back. |
| └display_name | string | Echoed back. |
| └metadata | string | Echoed back (JSON string). |
| └status | string | "active" / "disabled". |
| └is_new | bool | true only on first creation. |
| └created_at | string | ISO8601 UTC. |
| └last_active_at | string | ISO8601 UTC. Empty if never used. |
| └pagination | Pagination | — |
| └page | int32 | 1-indexed. |
| └size | int32 | Items per page. |
| └total | int64 | Total rows matching the filter. |
| └has_more | bool | Whether more pages exist. |
Chat (SSE streaming)
Multi-turn AI chat with built-in skills (technical analysis, market data, news). Response is text/event-stream — every event is emitted as `event: NAME\ndata: JSON\n\n`. Unlike all other endpoints, the SSE stream is NOT wrapped in `{ret, msg, data}`.
Start a chat turn. Returns an SSE stream until done or failed.
| Field | Type | Required | Description |
|---|---|---|---|
| chat_id | string | yes | Your generated unique ID for this turn, e.g. chat-{uuid}. Used for idempotency and tracing. |
| message | string | yes | The user's question. |
| metadata | ChatMetadata | yes | — |
| └session_id | string | yes | From CreateChatSession. Wrong/missing → ret=10404. |
| └timezone | string | no | IANA timezone, e.g. "Asia/Shanghai". Affects "today/yesterday" interpretation. |
| └language | string | no | "zh" / "en" / etc. Default: adaptive to user language. |
| Field | Type | Description |
|---|---|---|
| event: submitted | SSE | Acknowledgement that the request was accepted. |
| └chat_id | string | Echoed back. |
| └status | string | "RUNNING". |
| └user_id | string | internal_user_id resolved from X-Partner-User. |
| └session_id | string | Echoed back. |
| └occurred_at | string | ISO8601 UTC. |
| event: status | SSE | Intermediate progress. |
| └stage | string | agent_round_start / tool_call_start / model_call_start / etc. |
| └message | string | Human-readable status. |
| └progress | float | 0.0 – 1.0. |
| event: delta | SSE | Streaming answer chunk. |
| └content | string | Incremental fragment — append to a client buffer. |
| └status | string | "RUNNING". |
| event: done | SSE | Stream complete. |
| └content | string | Full final answer (sanity check against the joined deltas). |
| └status | string | "SUCCESS". |
| └progress | float | 1.0. |
| └token_usage | object | Token counters for billing visibility. |
| event: failed | SSE | Terminal failure (insufficient balance, backend error, etc). |
| └message | string | Error description. |
| └status | string | "FAILED". |
curl -N -X POST https://api.alphio.ai/openchat-steam/completions \
-H "Authorization: Bearer pk_live_••••••••••••••••••••••••••••" \
-H "X-Partner-User: u_998877" \
-H "Accept: text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"chat_id": "chat-998877-1719283400",
"message": "What is AAPL'\''s current RSI?",
"metadata": {
"session_id": "sess_ifm92XaV7gqx",
"timezone": "America/New_York",
"language": "en"
}
}'event: submitted
data: {"chat_id":"chat-998877-1719283400","status":"RUNNING",
"user_id":"op_intellectia_qUk8CyDetjsK","session_id":"sess_ifm92XaV7gqx",
"occurred_at":"2026-06-09T08:18:24.77Z"}
event: status
data: {"chat_id":"...","stage":"agent_round_start",
"status":"PROCESSING","progress":0.15,"message":"Understanding question"}
event: status
data: {"chat_id":"...","stage":"tool_call_start",
"status":"PROCESSING","progress":0.50,"message":"Fetching technical indicators"}
event: delta
data: {"chat_id":"...","status":"RUNNING","content":"AAPL's current RSI(14) is 68,"}
event: delta
data: {"chat_id":"...","status":"RUNNING","content":" approaching the overbought zone (70)..."}
event: done
data: {"chat_id":"...","status":"SUCCESS","progress":1.0,
"stage":"task_completed","content":"AAPL's current RSI(14) is 68, approaching..."}Chat sessions & messages
A session groups related chat turns. History within a session is automatically injected as context.
| Field | Type | Required | Description |
|---|---|---|---|
| internal_user_id | string | yes | From UpsertVirtualUser. |
| title | string | no | Display title for your UI. |
| metadata | string | no | Opaque JSON string. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ChatSession | Response payload. |
| └session_id | string | Format: "sess_{nanoid}". |
| └internal_user_id | string | Owner. |
| └title | string | — |
| └metadata | string | JSON string. |
| └status | string | "active" / "deleted". |
| └last_message_at | string | ISO8601 UTC. Empty for a freshly created session. |
| └created_at | string | ISO8601 UTC. |
| └updated_at | string | ISO8601 UTC. |
| Field | Type | Required | Description |
|---|---|---|---|
| internal_user_id | string | no | Empty = list across all your virtual users. |
| status | string | no | "active" / "deleted" / "" (all). Default "active". |
| page | int32 | no | Default 1. |
| size | int32 | no | Default 20, max 200. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ListChatSessionsData | Response payload. |
| └items | ChatSession[] | — |
| └session_id | string | Format: "sess_{nanoid}". |
| └internal_user_id | string | Owner. |
| └title | string | — |
| └metadata | string | JSON string. |
| └status | string | "active" / "deleted". |
| └last_message_at | string | ISO8601 UTC. Empty for a freshly created session. |
| └created_at | string | ISO8601 UTC. |
| └updated_at | string | ISO8601 UTC. |
| └page | int32 | 1-indexed. |
| └size | int32 | Items per page. |
| └total | int64 | Total rows matching the filter. |
| └has_more | bool | Whether more pages exist. |
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | yes | — |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ChatSession | Response payload. |
| └session_id | string | Format: "sess_{nanoid}". |
| └internal_user_id | string | Owner. |
| └title | string | — |
| └metadata | string | JSON string. |
| └status | string | "active" / "deleted". |
| └last_message_at | string | ISO8601 UTC. Empty for a freshly created session. |
| └created_at | string | ISO8601 UTC. |
| └updated_at | string | ISO8601 UTC. |
Edit the title or metadata of an existing session.
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | yes | — |
| title | string | no | Empty = unchanged. |
| metadata | string | no | Empty = unchanged. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ChatSession | Response payload. |
| └session_id | string | Format: "sess_{nanoid}". |
| └internal_user_id | string | Owner. |
| └title | string | — |
| └metadata | string | JSON string. |
| └status | string | "active" / "deleted". |
| └last_message_at | string | ISO8601 UTC. Empty for a freshly created session. |
| └created_at | string | ISO8601 UTC. |
| └updated_at | string | ISO8601 UTC. |
Soft-delete by default. Message history remains queryable.
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | yes | — |
| soft_delete | bool | no | Default true. Set false for permanent deletion. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DeleteChatSessionData | Response payload. |
| └status | string | "deleted" / "hard_deleted". |
Cursor-paginated history. Order is by created_at DESC.
| Field | Type | Required | Description |
|---|---|---|---|
| session_id | string | yes | — |
| before_message_id | string | no | Cursor — pass the message_id of your current oldest message to fetch older ones. |
| size | int32 | no | Default 50, max 200. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ListSessionMessagesData | Response payload. |
| └items | ChatMessage[] | — |
| └message_id | string | Format: "msg_{nanoid}". |
| └chat_id | string | Matches the SSE chat_id. One chat_id usually produces 2 messages (user + assistant). |
| └session_id | string | May be empty for session-less chat. |
| └internal_user_id | string | — |
| └role | string | "user" / "assistant". |
| └content | string | Raw Markdown stream. May contain ```json card fences. |
| └attachments | ChatAttachment[] | — |
| └url | string | Pre-signed URL. May expire. |
| └mime | string | — |
| └name | string | — |
| └tool_calls | ChatToolCall[] | — |
| └step_id | string | — |
| └kind | string | "round" / "tool_call". |
| └round | int32 | — |
| └tool_name | string | — |
| └args_json | string | Stringified tool arguments. |
| └result_summary | string | — |
| └status | string | "ok" / "error" / "running". |
| └started_at_ms | int64 | Unix milliseconds. |
| └ended_at_ms | int64 | Unix milliseconds. |
| └sources | ChatSource[] | — |
| └title | string | — |
| └url | string | — |
| └snippet | string | — |
| └error_code | string | Non-empty on terminal failure. |
| └error_message | string | — |
| └doc_id | string | Chatbot's assistant doc_id. |
| └created_at | string | ISO8601 UTC. |
| └has_more | bool | — |
| Field | Type | Required | Description |
|---|---|---|---|
| message_id | string | yes | — |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ChatMessage | Response payload. |
| └message_id | string | Format: "msg_{nanoid}". |
| └chat_id | string | Matches the SSE chat_id. One chat_id usually produces 2 messages (user + assistant). |
| └session_id | string | May be empty for session-less chat. |
| └internal_user_id | string | — |
| └role | string | "user" / "assistant". |
| └content | string | Raw Markdown stream. May contain ```json card fences. |
| └attachments | ChatAttachment[] | — |
| └url | string | Pre-signed URL. May expire. |
| └mime | string | — |
| └name | string | — |
| └tool_calls | ChatToolCall[] | — |
| └step_id | string | — |
| └kind | string | "round" / "tool_call". |
| └round | int32 | — |
| └tool_name | string | — |
| └args_json | string | Stringified tool arguments. |
| └result_summary | string | — |
| └status | string | "ok" / "error" / "running". |
| └started_at_ms | int64 | Unix milliseconds. |
| └ended_at_ms | int64 | Unix milliseconds. |
| └sources | ChatSource[] | — |
| └title | string | — |
| └url | string | — |
| └snippet | string | — |
| └error_code | string | Non-empty on terminal failure. |
| └error_message | string | — |
| └doc_id | string | Chatbot's assistant doc_id. |
| └created_at | string | ISO8601 UTC. |
Up/down vote an assistant reply. Only valid for role=assistant messages.
| Field | Type | Required | Description |
|---|---|---|---|
| message_id | string | yes | — |
| rating | string | yes | "up" or "down". |
| note | string | no | Optional user note. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | RateChatMessageData | Response payload. |
| └message_id | string | Echoed back. |
| └rating | string | Echoed back. |
| └created_at | string | ISO8601 UTC. |
Suggested starter questions for your chat entry screen, regenerated daily from a digest of recent market news. Served from cache — this endpoint never invokes an LLM and is not billed. Each call returns a fresh random subset, so repeated calls give your UI variety.
| Field | Type | Required | Description |
|---|---|---|---|
| lang | string | no | Language tag: "en" / "en-us", "zh" / "zh-cn" / "zh-hans", "zh-tw" / "zh-hant" / "zh-hk". Case-insensitive. Empty or unrecognized falls back to "en". |
| count | int32 | no | Max questions to return. Default 10, max 50. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | ChatRecommendQuestionsData | Response payload. |
| └questions | string[] | Randomly ordered subset of the day's batch. |
| └lang | string | Language actually served after normalization/fallback: "en" / "zh-cn" / "zh-tw". |
| └generated_at | int64 | Unix seconds when the batch was generated. |
curl -X POST https://api.alphio.ai/v1/openapi/chat/recommend-questions \
-H "Authorization: Bearer pk_live_••••••••••••••••••••••••••••" \
-H "Content-Type: application/json" \
-d '{
"lang": "en",
"count": 3
}'{
"ret": 0,
"msg": "ok",
"data": {
"questions": [
"How could the latest Fed commentary affect rate-cut expectations this summer?",
"Is NVDA's pullback after earnings a buying opportunity?",
"What is driving the rally in gold prices this week?"
],
"lang": "en",
"generated_at": 1781136000
}
}Pivot point
Pivot point / support-resistance signals.
Returns every 神奇九转 + RSI(6) pivot signal (DIP / ALERT) the algorithm fired within the look-back window. The K-line period is selectable with multiplier / timespan (1–720 minute, hour, day, week, month, quarter, year); both omitted = daily bars over the trailing 1 year, the behaviour that predates the fields. Computed server-side from datafabric kline (US / HK / crypto all supported); cached 5 minutes, 1 minute for intraday periods. Empty `data.list` with `ret=0` means no signal in the window — distinct from a real error. A window longer than the period's max span comes back one page at a time — pass `data.next_cursor` back as `cursor` to walk further back.
| Field | Type | Required | Description |
|---|---|---|---|
| code | string | yes | Ticker, e.g. "AAPL", "00700", "BTC". Case-insensitive; uppercased server-side. |
| asset_type | int32 | yes | 0=stock, 1=etf, 2=crypto. |
| locale | string | no | Market the ticker belongs to: "US", "HK", "FOREX", "METAL". Case-insensitive; uppercased server-side. Empty defaults to "US". Crypto (asset_type=2) keeps the field for shape consistency but it's inert. |
| multiplier | int32 | no | Period count, paired with timespan. Allowed values depend on timespan: minute 1–720, hour 1–12, month 1 / 3 (= quarter) / 12 (= year); day, week, quarter and year accept 1 only. Any other combination is a parameter error rather than a silently mis-aggregated series. Default 1. |
| timespan | int32 | no | K-line period unit: 2=minute, 3=hour, 4=day, 5=week, 6=month, 7=quarter, 8=year (1=second is not supported). Omitted together with multiplier = daily. Bar stamping — day and above carry the period's FIRST TRADING DAY (NVDA's August 2026 monthly bar is 2026-08-03, its Q1 and 2026 yearly bars are both 2026-01-02); minute and hour bars are right-edge stamped and anchored to each trading session's open, truncated at the close (HK 60m → 10:30 / 11:30 / 12:00 / 14:00 / 15:00 / 16:00, HK 90m → 11:00 / 12:00 / 14:30 / 16:00, and a 3m series stamps the 09:30 bar 09:33). This anchoring is done by THIS endpoint, which folds hourly widths from 5-minute bars for the purpose; /v1/openapi/data/kline passes timespan straight through to the vendor and returns its CLOCK-aligned hourly stamps (10:00, 11:00) instead — so a 60m bar read from the two endpoints carries different timestamps by design. Crypto and perp serve only the exchange's native widths: 1 / 3 / 5 / 15 / 30 / 60 / 120 / 240 / 360 / 480 / 720 minutes, plus day / week / month. Note the upstream vendor stamps week and above on the CALENDAR period start (August 2026 arrives as 08-01); this endpoint moves them onto the first day the market actually traded, so those stamps can differ from the same bar read through /v1/openapi/data/kline. |
| from | string | no | Window start, YYYY-MM-DD (UTC, inclusive). Must be set together with to. The algorithm runs on exactly the [from, to] bars with no warmup preload — the signal math is window-sensitive (RSI warmup, TD-9 counts, FILTER suppression), so to reproduce the App chart's markers pass exactly the bar range the chart has loaded. Both empty = a default look-back sized for the period: 1 year for daily bars, days for a 1-minute series, decades for yearly. |
| to | string | no | Window end, YYYY-MM-DD (UTC, inclusive). Must be set together with from. Max span 5 years for minute / hour / day / week, 50 years for month / quarter / year. A LONGER window is not rejected — it is clamped to the ceiling, keeping `to` and moving `from` forward, and `msg` says which window actually ran (e.g. "ok (requested from 2020-12-07 exceeds the max span for this period; window clamped to 2021-08-27..2026-08-31)"). Windows shorter than 30 bars return "insufficient kline history" — which also means yearly signals only exist for tickers with 30+ years of history. Ignored when `cursor` is set — the cursor decides where the page ends. |
| cursor | int64 | no | Backward paging cursor, unix seconds. One request only computes the bars inside the max span for the period, so a longer history comes back one page at a time: take `data.next_cursor` from the response and pass it here to get the page immediately BEFORE it — the bars with ts strictly less than cursor, one max-span window wide, never earlier than `from`. `to` is ignored when cursor is set; `from` still bounds how far back paging can go. Pages are computed independently yet agree bar-for-bar with one big window: the server preloads ~100 extra bars before each page start to warm RSI / TD-9 / COUNT up and returns only the signals inside the page, so concatenating pages neither drops nor duplicates a signal at a boundary. Omit or 0 = first page. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisPivotPointInfoData | Response payload. |
| └list | AnalysisPivotAlertInfo[] | Filtered signals in CHRONOLOGICAL ASCENDING order. Empty when no signal fired in the look-back window. For the latest signal, take list[list.length-1]. |
| └date | string | Bar label in the market's own timezone (UTC for crypto / perp): "YYYY-MM-DD HH:MM" for minute and hour periods, "YYYY-MM-DD" for day and above. |
| └code | string | Echoed ticker, uppercased. |
| └sign | string | "DIP" (bullish reversal) or "ALERT" (bearish reversal). |
| └mark | string | "Buy Signal" / "Sell Signal" — human-readable label. |
| └price | string | Display price with 4-decimal precision. DIP = low × 0.98 (paint below the bar); ALERT = high × 1.03 (paint above). |
| └ts | int64 | Bar timestamp, unix seconds — the same instant date renders. |
| └next_cursor | int64 | Pass it back as `cursor` to get the page before this one. Unix seconds — the ts of the OLDEST bar on this page. 0 means there is no earlier page: paging has reached `from`, fewer than 30 bars remain before it, or this first page already covered the whole requested window. |
# Daily (period omitted — the pre-existing behaviour)
POST https://api.alphio.ai/v1/openapi/analysis/pivot-point/info
{ "code": "AAPL", "asset_type": 0, "locale": "US", "from": "2026-01-01", "to": "2026-07-28" }
# 60-minute bars
POST https://api.alphio.ai/v1/openapi/analysis/pivot-point/info
{ "code": "AAPL", "asset_type": 0, "locale": "US", "multiplier": 60, "timespan": 2 }
# Older signals — feed the previous response's next_cursor back as cursor
POST https://api.alphio.ai/v1/openapi/analysis/pivot-point/info
{ "code": "AAPL", "asset_type": 0, "locale": "US", "multiplier": 1, "timespan": 2, "cursor": 1789394400 }// Daily
{
"ret": 0, "msg": "ok",
"data": {
"list": [
{
"date": "2026-02-09", "code": "AAPL",
"sign": "ALERT", "mark": "Sell Signal",
"price": "286.5460", "ts": 1770613200
},
{
"date": "2026-06-09", "code": "AAPL",
"sign": "DIP", "mark": "Buy Signal",
"price": "291.7340", "ts": 1781007137
}
]
}
}
// 60-minute — note date carries the time of day
{
"ret": 0, "msg": "ok",
"data": {
"list": [
{
"date": "2026-08-24 11:30", "code": "AAPL",
"sign": "ALERT", "mark": "Sell Signal",
"price": "286.5460", "ts": 1787585400
},
{
"date": "2026-08-27 14:30", "code": "AAPL",
"sign": "DIP", "mark": "Buy Signal",
"price": "291.7340", "ts": 1787855400
}
]
}
}
// 1-minute with cursor — next_cursor is the oldest bar on this page; 0 = no more pages
{
"ret": 0, "msg": "ok",
"data": {
"list": [
{
"date": "2026-09-11 10:31", "code": "AAPL",
"sign": "DIP", "mark": "Buy Signal",
"price": "289.4100", "ts": 1789137060
}
],
"next_cursor": 1789051500
}
}Bulk scan / signal screener.
| Field | Type | Required | Description |
|---|---|---|---|
| signal_type | int32 | yes | 0=all, 1=bottom (dip / bottom-reversal), 2=alert (top warning). |
| page | int32 | no | 1-indexed. |
| page_size | int32 | no | Items per page. |
| asset_type | string | no | Numeric string: "0"=stock, "1"=etf, "2"=crypto. Empty = all. |
| period | int32 | no | 0=all, 1=15min, 2=30min, 3=1h, 4=2h, 5=4h. This is the screener's own enum — NOT the timespan / multiplier pair PivotPointInfo takes, and it has no daily or above option. |
| sort_field | int32 | no | 0=timestamp, 2=volume (1=market_cap is deprecated). |
| order | string | no | "asc" (default) / "desc". |
| first_id | string | no | Forward cursor. |
| last_id | string | no | Backward cursor. |
| refresh | bool | no | Force-bust cache. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisPivotPointSignalsData | Response payload. |
| └signals | AnalysisDayTradingSignal[] | — |
| └symbol | string | — |
| └code | string | — |
| └name | string | Company name. |
| └logo | string | — |
| └price | string | — |
| └change_ratio | string | — |
| └timestamp | int64 | Unix seconds. |
| └signal_types | int32[] | Active signal labels. |
| └period | int32 | — |
| └klines | AnalysisKlinePoint[] | OHLCV + technicals. |
| └open | double | — |
| └high | double | — |
| └low | double | — |
| └close | double | — |
| └volume | double | — |
| └timestamp | int64 | Unix seconds. |
| └ma5 | double | — |
| └ma20 | double | — |
| └rsi6 | double | — |
| └macd | double | — |
| └macd_signal | double | — |
| └macd_hist | double | — |
| └asset_type | int32 | — |
| └volume | string | — |
| └id | string | Stable row ID for cursor pagination. |
| └prev_close | string | — |
| └total | int64 | Total rows matching the filter. |
| └new_add | int64 | Rows newly added since last query. |
Swingmax (US)
Swing-trade signals for US equities.
Query open swingmax signals for the given tickers. Returns the SAME rich item shape as /swingmax/stocks (AnalysisSwingmaxStock — with kline, company name/logo, the r1/r2/r3 target ladder, stop loss). Ladder field names match the App swing-max/list payload one-to-one.
| Field | Type | Required | Description |
|---|---|---|---|
| tickers | AnalysisAsset[] | no | Tickers to query. Send either tickers or ids — one of them is required; both together is InvalidArgument. |
| └asset_type | int32 | no | 0=stock, 1=etf, 2=crypto. |
| └symbol | string | no | Legacy field. |
| └ticker | string | no | Preferred field. |
| └locale | string | no | "US" / "HK". |
| ids | int64[] | no | Signal ids to look up — the id field of a returned item. At most 20; more is InvalidArgument, NOT truncated, so a silently missing 21st id cannot happen. Mutually exclusive with tickers. Unlike tickers, which only sees the open pool, ids also returns positions that have closed since (exit_time_ts > 0), so an id taken from an earlier response can be followed until the trade ends. Unknown ids are skipped, not errored. Added 2026-09-15. |
| lang | string | no | Localizes the status text. When set it takes PRIORITY over the "lang" request header: "zh" / "zh-cn" = Simplified Chinese, "zh-tw" = Traditional Chinese. Omit/empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxSignalsData | Response payload. |
| └signals | AnalysisSwingmaxStock[] | Same item shape as /swingmax/stocks — one entry per matched open ticker. |
| └id | int64 | Signal id. Assigned when the position opens and unchanged for its whole life, including after it closes. Store it and pass it back as ids on /swingmax/signals to follow one trade. Added 2026-09-15. Filled on /swingmax/signals and on /swingmax/stocks for every stype: since 2026-09-16 the closed list (stype≠1) reads the same v2 store as the open pool, so an id taken from any /swingmax/stocks row round-trips through ids on /swingmax/signals. Before that date closed rows carried 0. |
| └symbol | string | — |
| └code | string | — |
| └company_name | string | — |
| └logo | string | — |
| └return | double | Realized return since entry, percent. Weighted over the ladder: 40% sold at Target 2 + 30% sold at Target 3 + the remaining 30% at final exit (unsold parts marked to the latest close). |
| └entry_price | double | — |
| └exit_price | double | Final-exit fill price for the remaining position. 0 while the position is open. |
| └entry_time | string | Entry date string from upstream, e.g. "2026-06-02". |
| └exit_time | string | Exit date string; empty while the position is open. |
| └change_ratio | double | Not populated since 2026-09-16 (the closed list moved to the v2 store, which has no such column); always 0. Use return instead. |
| └kline | AnalysisKlinePointV2[] | Snapshot bars with full OHLC + volume — enough to draw candlesticks. |
| └close | double | — |
| └timestamp | int64 | Unix seconds. |
| └open | double | — |
| └high | double | — |
| └low | double | — |
| └volume | double | — |
| └entry_time_ts | int64 | Unix seconds. |
| └exit_time_ts | int64 | Unix seconds; 0 while open. |
| └target_price | string | Legacy alias of r2_price (Target 2), kept for backward compatibility — prefer the r1/r2/r3_price ladder. |
| └stop_loss | string | Stop-loss price. The whole remaining position exits if it is hit. |
| └interval | int32 | Signal timeframe: 0=1d, 1=15min, 2=30min, 3=1h, 4=2h, 5=4h. |
| └side | int32 | 0=long, 1=short. |
| └market_cap | string | — |
| └current_price | string | — |
| └r1_price | string | Target 1 price — the first (lowest) pivot level above entry. A price milestone only: no partial sell is executed at R1. |
| └r1_signal_ts | int64 | Reserved for shape parity with the App swing-max/list; always 0 on this stock feed (only the crypto pipeline fills R1 triggers). |
| └r2_price | string | Target 2 price. When first reached, the strategy sells 40% of the position. Same value as the legacy target_price. |
| └r2_signal_ts | int64 | Unix seconds when the price first reached Target 2 (40% partial exit executed); 0 if not reached yet. |
| └r2_sell_price | string | Fill price of the 40% partial exit at Target 2; empty if not reached yet. |
| └r3_price | string | Target 3 price — the highest ladder level. When first reached, the strategy sells another 30% of the position. |
| └r3_signal_ts | int64 | Unix seconds when the price first reached Target 3 (30% partial exit executed); 0 if not reached yet. |
| └r3_sell_price | string | Fill price of the 30% partial exit at Target 3; empty if not reached yet. |
| └status | string | Server-rendered progress narrative (entry → 40% partial exit at Target 2 → 30% at Target 3 → final close) — same text the App shows on swing-max/list. Localized by the "lang" body param (priority) or "lang" request header: omit both for English, "zh" / "zh-cn" = Simplified Chinese, "zh-tw" = Traditional Chinese. Empty on the closed list (stype≠1). |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax/signals
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{
"tickers":[
{"asset_type":0,"ticker":"AAPL","locale":"US"},
{"asset_type":0,"ticker":"NVDA","locale":"US"}
],
"lang":"zh-tw"
}{
"ret": 0,
"msg": "ok",
"data": {
"signals":[
{"symbol":"AAPL","code":"AAPL.O","company_name":"Apple Inc","logo":"https://...",
"return":3.21,"entry_price":187.2,"exit_price":0,"entry_time":"2026-06-02","exit_time":"",
"change_ratio":3.21,
"kline":[{"close":190.5,"timestamp":1717286400,"open":188.9,"high":191.2,"low":188.1,"volume":51234567}],
"entry_time_ts":1717286400,"exit_time_ts":0,"target_price":"210.5","stop_loss":"177.84",
"interval":0,"side":0,"market_cap":"2.9T","current_price":"193.1",
"r1_price":"198.6","r1_signal_ts":0,
"r2_price":"210.5","r2_signal_ts":1719878400,"r2_sell_price":"211.02",
"r3_price":"224.9","r3_signal_ts":0,"r3_sell_price":"",
"status":"Booked partial profits @211.02 on 2026-07-01 09:35 ET and riding runners"}
]
}
}Browse the supported universe. NOTE: only stype=1 returns the OPEN positions pool; any other value returns the closed list. Since 2026-09-16 both come from the same v2 store: closed rows carry id, the r1/r2/r3 ladder fields and status like open rows, and return is the realized ladder return. Two fields differ from the pre-2026-09-16 closed list: change_ratio is no longer populated (0), and side=1 (short) returns an empty list because the v2 store is long-only. Before 2026-09-16 the closed list came from an older store that had stopped updating in 2025-08 and carried no id.
| Field | Type | Required | Description |
|---|---|---|---|
| stype | int32 | yes | GetSwingMaxStocksType. 1=open pool, 2=removed(closed), 3=today, 4=today-open, 5=today-update. Only stype=1 = open pool; 2-5 all return the same closed list (v2 store, rows carry id). |
| sort_type | int32 | no | 1-4 match the platform-wide meaning shared with every other list endpoint: 1=latest, 2=oldest, 3=highest return, 4=lowest return. 5-11 are extra orderings only this endpoint supports: 5=latest exit, 6=oldest exit, 7=latest entry, 8=oldest entry, 9=highest market cap, 10=lowest market cap, 11=highest potential. |
| page | int64 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, max 20 — larger values are clamped, not rejected. The same ceiling as every other paged list on this API; only the two swingmax /open endpoints are uncapped. Before 2026-09-15 the default was 100 with no clamp, so omitting size failed with a parameter error from upstream. |
| keyword | string | no | Case-insensitive substring match on ticker, code and company name. Omit to disable filtering. Max 64 characters. |
| side | int32 | no | 0=long, 1=short. |
| trade_status | int32 | no | 0=not traded, 1=traded, 2=all. |
| lang | string | no | Localizes the status text. When set it takes PRIORITY over the "lang" request header: "zh" / "zh-cn" = Simplified Chinese, "zh-tw" = Traditional Chinese. Omit/empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxStocksData | Response payload. |
| └stocks | AnalysisSwingmaxStock[] | — |
| └id | int64 | Signal id. Assigned when the position opens and unchanged for its whole life, including after it closes. Store it and pass it back as ids on /swingmax/signals to follow one trade. Added 2026-09-15. Filled on /swingmax/signals and on /swingmax/stocks for every stype: since 2026-09-16 the closed list (stype≠1) reads the same v2 store as the open pool, so an id taken from any /swingmax/stocks row round-trips through ids on /swingmax/signals. Before that date closed rows carried 0. |
| └symbol | string | — |
| └code | string | — |
| └company_name | string | — |
| └logo | string | — |
| └return | double | Realized return since entry, percent. Weighted over the ladder: 40% sold at Target 2 + 30% sold at Target 3 + the remaining 30% at final exit (unsold parts marked to the latest close). |
| └entry_price | double | — |
| └exit_price | double | Final-exit fill price for the remaining position. 0 while the position is open. |
| └entry_time | string | Entry date string from upstream, e.g. "2026-06-02". |
| └exit_time | string | Exit date string; empty while the position is open. |
| └change_ratio | double | Not populated since 2026-09-16 (the closed list moved to the v2 store, which has no such column); always 0. Use return instead. |
| └kline | AnalysisKlinePointV2[] | Snapshot bars with full OHLC + volume — enough to draw candlesticks. |
| └close | double | — |
| └timestamp | int64 | Unix seconds. |
| └open | double | — |
| └high | double | — |
| └low | double | — |
| └volume | double | — |
| └entry_time_ts | int64 | Unix seconds. |
| └exit_time_ts | int64 | Unix seconds; 0 while open. |
| └target_price | string | Legacy alias of r2_price (Target 2), kept for backward compatibility — prefer the r1/r2/r3_price ladder. |
| └stop_loss | string | Stop-loss price. The whole remaining position exits if it is hit. |
| └interval | int32 | Signal timeframe: 0=1d, 1=15min, 2=30min, 3=1h, 4=2h, 5=4h. |
| └side | int32 | 0=long, 1=short. |
| └market_cap | string | — |
| └current_price | string | — |
| └r1_price | string | Target 1 price — the first (lowest) pivot level above entry. A price milestone only: no partial sell is executed at R1. |
| └r1_signal_ts | int64 | Reserved for shape parity with the App swing-max/list; always 0 on this stock feed (only the crypto pipeline fills R1 triggers). |
| └r2_price | string | Target 2 price. When first reached, the strategy sells 40% of the position. Same value as the legacy target_price. |
| └r2_signal_ts | int64 | Unix seconds when the price first reached Target 2 (40% partial exit executed); 0 if not reached yet. |
| └r2_sell_price | string | Fill price of the 40% partial exit at Target 2; empty if not reached yet. |
| └r3_price | string | Target 3 price — the highest ladder level. When first reached, the strategy sells another 30% of the position. |
| └r3_signal_ts | int64 | Unix seconds when the price first reached Target 3 (30% partial exit executed); 0 if not reached yet. |
| └r3_sell_price | string | Fill price of the 30% partial exit at Target 3; empty if not reached yet. |
| └status | string | Server-rendered progress narrative (entry → 40% partial exit at Target 2 → 30% at Target 3 → final close) — same text the App shows on swing-max/list. Localized by the "lang" body param (priority) or "lang" request header: omit both for English, "zh" / "zh-cn" = Simplified Chinese, "zh-tw" = Traditional Chinese. Empty on the closed list (stype≠1). |
| └total | int32 | — |
Returns every currently-open position in a single call by default. Static signals only — no kline, no realtime return, no company name/logo. Cheap, cached ~1 minute.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Omit to return every open position in one call — that is the historical behaviour of this endpoint and it is unchanged. Set it only if you want pages. |
| sort_type | int32 | no | 0 = endpoint default, 1 = latest first, 2 = oldest first, 3/4 = by potential_gain (target-based upside, NOT realised return), high/low first. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Case-insensitive substring match on ticker and code — this endpoint carries no company name. Omit to disable filtering. Max 64 characters. |
| lang | string | no | Localizes server-rendered status text. Takes priority over the lang header. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxOpenData | Response payload. |
| └positions | AnalysisSwingmaxOpenPosition[] | Every currently-open position. |
| └id | int64 | Signal id — the same number as id on /swingmax/signals and /swingmax/stocks. Take it from this list and pass it back as ids on /swingmax/signals to follow one position until it closes. Added 2026-09-15. |
| └symbol | string | — |
| └code | string | — |
| └buy_price | string | Entry / Buy Target. |
| └stop_loss | string | — |
| └target1 | string | Sell Target 1 (r2). |
| └target2 | string | Sell Target 2 (r3). |
| └potential_gain | double | Static: (r3/buy - 1) * 100, percent. |
| └signal_time | int64 | Entry time, unix seconds. |
| └last_exit_ts | int64 | Exit time, unix seconds; 0 when open. |
| └total | int32 | — |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax/open
{}{
"ret": 0,
"msg": "ok",
"data": {
"positions":[
{"symbol":"GME","code":"GME.N","buy_price":"21.715","stop_loss":"20.629",
"target1":"24.252","target2":"28.152","potential_gain":29.6,
"signal_time":1647388800,"last_exit_ts":0}
],
"total": 1
}
}Swingmax (HK)
Swing-trade signals for Hong Kong equities. Same engine and same r2/r3 target ladder as the US endpoints, but a separate item shape: HK carries board_lot and trade_currency, which are meaningless for US equities. Amounts are in trade_currency, not always HKD.
Current open swingmax positions for the given HK tickers. Mirrors /swingmax/signals on the US side, including the fact that it returns OPEN positions only. Until 2026-09-08 this endpoint also returned closed positions — the status filter was missing, so querying two tickers could return a decade of history alongside the live ones. If you were relying on that to read past trades, switch to /swingmax/hk/stocks with stype=2 (closed); that is the endpoint built for it.
| Field | Type | Required | Description |
|---|---|---|---|
| tickers | AnalysisAsset[] | no | HK codes to query, 5 digits each — an array of OBJECTS, the same shape as US /swingmax/signals: [{"ticker":"00700"}]. asset_type and locale are accepted but inert here: the path already fixes the market. Send either tickers or ids — one of them is required; both together is InvalidArgument. |
| └asset_type | int32 | no | 0=stock, 1=etf, 2=crypto. |
| └symbol | string | no | Legacy field. |
| └ticker | string | no | Preferred field. |
| └locale | string | no | "US" / "HK". |
| ids | int64[] | no | Signal ids to look up — the id field of a returned item. At most 20; more is InvalidArgument, NOT truncated, so a silently missing 21st id cannot happen. Mutually exclusive with tickers. Unlike tickers, which only sees the open pool, ids also returns positions that have closed since (exit_time_ts > 0), so an id taken from an earlier response can be followed until the trade ends. Unknown ids are skipped, not errored. Added 2026-09-15. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxHKSignalsData | Response payload. |
| └signals | AnalysisSwingmaxHKItem[] | One entry per matched ticker. |
| └id | int64 | Signal id — same meaning as US swingmax id: assigned at entry, stable through close. Pass it back as ids on /swingmax/hk/signals to follow one trade. Added 2026-09-15. Also present on /swingmax/hk/open. |
| └symbol | string | HK code — always 5 digits, e.g. 00700. |
| └code | string | Symbol with the .HK suffix. |
| └company_name | string | Company name, in the language of the listing. |
| └trade_currency | string | HKD / CNY / USD. HK has three trading counters; the same company can list under more than one symbol, so amounts are NOT comparable across symbols without checking this. HK-only field. |
| └board_lot | int32 | Shares per lot. HK trades in lots, not shares — 00700 is 100 shares/lot (~HKD 40k). 0 means the lot size could not be resolved. HK-only field. |
| └entry_time | string | Signal date, a Hong Kong trading day (YYYY-MM-DD). |
| └entry_time_ts | int64 | Entry time, unix seconds — midnight HKT on entry_time. Always > 0. Use this to place the entry marker; it saves parsing the date string. |
| └entry_price | double | Buy target (breakout level), in trade_currency. The entry marker goes here. A number, not a string — matching US swingmax. |
| └stop_loss | string | Support level. Entry minus 15%; moves up to the entry price once r2 triggers. |
| └r2_price | string | Sell Target 1 (first resistance). |
| └r2_sell_price | string | Actual r2 fill; empty when not triggered. This is the price to mark, not r2_price. |
| └r2_signal_ts | int64 | r2 trigger time, unix seconds. 0 means not triggered — draw the first target marker only when this is > 0. Same rule as US swingmax. |
| └r3_price | string | Sell Target 2 (second resistance). |
| └r3_sell_price | string | Actual r3 fill; empty when not triggered. |
| └r3_signal_ts | int64 | r3 trigger time, unix seconds. 0 means not triggered — draw the second target marker only when this is > 0. |
| └exit_time | string | Exit date; empty while the position is still open. |
| └exit_time_ts | int64 | Exit time, unix seconds. 0 while the position is open — this one field carries both when it exited and whether it has exited, exactly as in US swingmax. There is no exit_signal_ts field in either market. |
| └exit_price | double | Final exit price. The exit marker goes here. 0 while the position is open — check exit_time_ts, not this, to tell open from closed. |
| └return | double | Net return of the WHOLE position, decimal fraction. Same field, same meaning and same type as US swingmax return. It was called profit_rate until 2026-09-09. |
| └realized | string | Return already banked by the scale-out, decimal fraction. This — not return — is the win indicator: realized > 0 means the trade counted as a win, matching how US swingmax reports its win rate. The two numbers differ materially, so do not mix them. HK-only field. |
| └exit_reason | string | ALERT = stopped at the original -15% stop (the only losing bucket). BREAKEVEN = r2 was hit, the stop moved up to the entry price, and it later stopped out at cost. R3 = took profit and gave back via the trailing stop. MAX_HOLD = held the full 60 trading days. HK-only field. |
| └hold_days | int32 | Trading days held. HK-only field. |
| └status | string | open / closed. |
| └kline | AnalysisKlinePointV2[] | Daily bars with full OHLC + volume — enough to draw candlesticks. Roughly the last 90 calendar days, ending today. Same source and format as the US endpoints. NOT returned by /swingmax/hk/open, which is built for pulling the whole list at once and would inflate several times over with bars. |
| └close | double | — |
| └timestamp | int64 | Unix seconds. |
| └open | double | — |
| └high | double | — |
| └low | double | — |
| └volume | double | — |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax/hk/signals
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{
"tickers":[
{"asset_type":0,"ticker":"00700","locale":"HK"},
{"asset_type":0,"ticker":"09988","locale":"HK"}
],
"lang":"zh-tw"
}{
"ret": 0,
"msg": "ok",
"data": {
"signals":[
{"symbol":"00700","code":"00700.HK","company_name":"腾讯控股","trade_currency":"HKD","board_lot":100,
"entry_time":"2026-03-12","entry_time_ts":1773244800,"entry_price":402.4,"stop_loss":"402.4000000",
"r2_price":"441.8000000","r2_sell_price":"441.8000000","r2_signal_ts":1775750400,
"r3_price":"482.8800000","r3_sell_price":"","r3_signal_ts":0,
"exit_time":"","exit_time_ts":0,"exit_price":0,"return":0,"realized":"0.0391000",
"exit_reason":"","hold_days":31,"status":"open"}
]
}
}Browse HK swingmax signals over a date range. Mirrors /swingmax/stocks on the US side.
| Field | Type | Required | Description |
|---|---|---|---|
| stype | int32 | no | GetSwingMaxStocksType. 1=open pool, 2=closed, 3=today's new signals, 4=today's still-open. 5 (today-updated) returns InvalidArgument on HK: the HK signal table records only entry_time, with no last-updated column to distinguish it. |
| side | int32 | no | 0=long. HK swingmax is long-only, so side=1 (short) returns InvalidArgument rather than an empty list — an empty list reads as "no signals today" and would leave you waiting for data that never comes. |
| trade_status | int32 | no | 0 or 2 (all). HK has no paper-trade execution tracking, so trade_status=1 (traded) returns InvalidArgument. |
| page | int64 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, capped at 20 — the same ceiling as every other paged list on this API; only the two swingmax /open endpoints are uncapped. Was default 100 / cap 500 before 2026-09-15. |
| sort_type | int32 | no | 0 = endpoint default, 1 = latest first, 2 = oldest first, 3/4 = by return (whole-trade net P&L), high/low first. Note this is NOT realized, which is the banked scale-out portion used for win-rate — the two differ materially. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Case-insensitive substring match on ticker, code and company name. Omit to disable filtering. Max 64 characters. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxHKStocksData | Response payload. |
| └stocks | AnalysisSwingmaxHKItem[] | One entry per signal. This array was called items until 2026-09-09; it is stocks now, matching US /swingmax/stocks. Reading the old key gets you nothing and no error — it looks like HK returned no data. |
| └id | int64 | Signal id — same meaning as US swingmax id: assigned at entry, stable through close. Pass it back as ids on /swingmax/hk/signals to follow one trade. Added 2026-09-15. Also present on /swingmax/hk/open. |
| └symbol | string | HK code — always 5 digits, e.g. 00700. |
| └code | string | Symbol with the .HK suffix. |
| └company_name | string | Company name, in the language of the listing. |
| └trade_currency | string | HKD / CNY / USD. HK has three trading counters; the same company can list under more than one symbol, so amounts are NOT comparable across symbols without checking this. HK-only field. |
| └board_lot | int32 | Shares per lot. HK trades in lots, not shares — 00700 is 100 shares/lot (~HKD 40k). 0 means the lot size could not be resolved. HK-only field. |
| └entry_time | string | Signal date, a Hong Kong trading day (YYYY-MM-DD). |
| └entry_time_ts | int64 | Entry time, unix seconds — midnight HKT on entry_time. Always > 0. Use this to place the entry marker; it saves parsing the date string. |
| └entry_price | double | Buy target (breakout level), in trade_currency. The entry marker goes here. A number, not a string — matching US swingmax. |
| └stop_loss | string | Support level. Entry minus 15%; moves up to the entry price once r2 triggers. |
| └r2_price | string | Sell Target 1 (first resistance). |
| └r2_sell_price | string | Actual r2 fill; empty when not triggered. This is the price to mark, not r2_price. |
| └r2_signal_ts | int64 | r2 trigger time, unix seconds. 0 means not triggered — draw the first target marker only when this is > 0. Same rule as US swingmax. |
| └r3_price | string | Sell Target 2 (second resistance). |
| └r3_sell_price | string | Actual r3 fill; empty when not triggered. |
| └r3_signal_ts | int64 | r3 trigger time, unix seconds. 0 means not triggered — draw the second target marker only when this is > 0. |
| └exit_time | string | Exit date; empty while the position is still open. |
| └exit_time_ts | int64 | Exit time, unix seconds. 0 while the position is open — this one field carries both when it exited and whether it has exited, exactly as in US swingmax. There is no exit_signal_ts field in either market. |
| └exit_price | double | Final exit price. The exit marker goes here. 0 while the position is open — check exit_time_ts, not this, to tell open from closed. |
| └return | double | Net return of the WHOLE position, decimal fraction. Same field, same meaning and same type as US swingmax return. It was called profit_rate until 2026-09-09. |
| └realized | string | Return already banked by the scale-out, decimal fraction. This — not return — is the win indicator: realized > 0 means the trade counted as a win, matching how US swingmax reports its win rate. The two numbers differ materially, so do not mix them. HK-only field. |
| └exit_reason | string | ALERT = stopped at the original -15% stop (the only losing bucket). BREAKEVEN = r2 was hit, the stop moved up to the entry price, and it later stopped out at cost. R3 = took profit and gave back via the trailing stop. MAX_HOLD = held the full 60 trading days. HK-only field. |
| └hold_days | int32 | Trading days held. HK-only field. |
| └status | string | open / closed. |
| └kline | AnalysisKlinePointV2[] | Daily bars with full OHLC + volume — enough to draw candlesticks. Roughly the last 90 calendar days, ending today. Same source and format as the US endpoints. NOT returned by /swingmax/hk/open, which is built for pulling the whole list at once and would inflate several times over with bars. |
| └close | double | — |
| └timestamp | int64 | Unix seconds. |
| └open | double | — |
| └high | double | — |
| └low | double | — |
| └volume | double | — |
| └total | int32 | — |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax/hk/stocks
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{"stype":2,"page":1,"size":50,"sort_type":1}{
"ret": 0,
"msg": "ok",
"data": {
"stocks":[
{"symbol":"00700","code":"00700.HK","company_name":"腾讯控股","trade_currency":"HKD","board_lot":100,
"entry_time":"2026-03-12","entry_time_ts":1773244800,"entry_price":402.4,"stop_loss":"402.4000000",
"r2_price":"441.8000000","r2_sell_price":"441.8000000","r2_signal_ts":1775750400,
"r3_price":"482.8800000","r3_sell_price":"","r3_signal_ts":0,
"exit_time":"2026-04-28","exit_time_ts":1777305600,"exit_price":402.4,
"return":0.0391,"realized":"0.0391000",
"exit_reason":"BREAKEVEN","hold_days":31,"status":"closed"}
],
"total": 1
}
}Returns every currently-open HK position in a single call by default. Mirrors /swingmax/open on the US side, including the shared paging parameters.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Omit to return every open position in one call — that is the historical behaviour of this endpoint and it is unchanged. Set it only if you want pages. |
| sort_type | int32 | no | 0 = endpoint default, 1 = latest first, 2 = oldest first, 3/4 = by return (whole-trade net P&L, not the banked realized portion), high/low first. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Case-insensitive substring match on ticker, code and company name. Omit to disable filtering. Max 64 characters. |
| lang | string | no | Localizes server-rendered status text. Takes priority over the lang header. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxHKOpenData | Response payload. |
| └positions | AnalysisSwingmaxHKOpenPosition[] | Every currently-open HK position. Field for field the same shape as US /swingmax/open, including HK-only trade_currency and board_lot at the end. |
| └id | int64 | Signal id — the same number as id on /swingmax/hk/signals and /swingmax/hk/stocks. Take it from this list and pass it back as ids on /swingmax/hk/signals to follow one position until it closes. Added 2026-09-15. |
| └symbol | string | HK code — always 5 digits, e.g. 00700. |
| └code | string | Symbol with the .HK suffix. |
| └buy_price | string | Entry / Buy Target, in trade_currency. Same number that /swingmax/hk/signals calls entry_price — a string here, a double there, because this endpoint mirrors US /swingmax/open. |
| └stop_loss | string | Support level. Entry minus 15%; moves up to the entry price once target1 triggers. |
| └target1 | string | Sell Target 1 (r2). Same number /swingmax/hk/signals calls r2_price. |
| └target2 | string | Sell Target 2 (r3). Same number /swingmax/hk/signals calls r3_price. |
| └potential_gain | double | Static: (target2/buy_price - 1) * 100, percent, rounded to 2 decimals. Identical computation to US swingmax, so the two markets' values are directly comparable. Note it measures the distance to target2, the FURTHER target — a position that already ran past target1 still reports the full distance to target2. This is what sort_type 3/4 sorts by on this endpoint. |
| └signal_time | int64 | Entry time, unix seconds. Same number /swingmax/hk/signals calls entry_time_ts. |
| └last_exit_ts | int64 | Exit time, unix seconds; always 0 here since this endpoint returns open positions only. |
| └trade_currency | string | HKD / CNY / USD. buy_price and both targets are in this currency, so they are NOT comparable across symbols without checking it. HK-only field. |
| └board_lot | int32 | Shares per lot. HK trades in lots, not shares — 00700 is 100 shares/lot. 0 means the lot size could not be resolved. HK-only field. |
| └total | int32 | Rows after filtering, before paging. |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax/hk/open
{}{
"ret": 0,
"msg": "ok",
"data": {
"positions":[
{"symbol":"00700","code":"00700.HK","buy_price":"402.4","stop_loss":"342.04",
"target1":"441.8","target2":"482.88","potential_gain":20,
"signal_time":1787155200,"last_exit_ts":0,
"trade_currency":"HKD","board_lot":100}
],
"total": 1
}
}DayTrading (US)
Intraday signals for US equities. A different animal from Swingmax: signals fire on 15m/30m bars, a dozen or so a day, and most resolve within hours — Swingmax is a daily-bar swing strategy whose positions live for weeks. Poll accordingly.
Positions from one US trading session, open and closed. Which session: on a trading day before the US open (09:30 ET), and on any non-trading day, it is the previous trading session; from the open onward it is the current one, including after the close. Closed positions carry sell_price, sell_ts and a realized return_rate; open ones carry current_price and a live return_rate. NOTE: between the open and the first signal of the day (intraday signals only start at 10:00 ET), and on days when no signal fires at all, the current session is empty — that is expected, not an outage.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, capped at 20 — the same ceiling as every other paged list on this API. Unlike the two swingmax /open endpoints this one is NOT uncapped: every row carries minute bars, so a full-book response would be several times larger. Was 10 before 2026-09-15. |
| sort_type | int32 | no | 0 = endpoint default (by return_rate, high to low — realized for closed positions, live unrealized for open ones), 1 = latest first, 2 = oldest first, 3 = highest return first, 4 = lowest return first. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Case-insensitive substring match on ticker, code and company name. Omit to disable filtering. Max 64 characters. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisDaytradingOpenData | Response payload. |
| └list | AnalysisDaytradingPosition[] | Every position of the session this endpoint is showing — open and closed. Field for field the same shape as /daytrading/signals and /daytrading/history. |
| └id | int64 | Signal id — the same number on /open, /signals and /history for the same trade. Store it from any of the three and pass it back as ids on /signals to follow this position. |
| └symbol | string | Bare code. US: NVDA. HK: five digits, e.g. 00700. |
| └code | string | Suffixed form. US: NVDA.O. HK: 00700.HK. |
| └name | string | Company name. |
| └logo | string | Logo URL; empty when unavailable. |
| └interval | string | Bar interval behind the entry, 15m or 30m. |
| └signal_date | string | Signal day on that market's trading calendar, YYYY-MM-DD. Derived from buy_ts in the market's own timezone — an HK 09:30 signal is still the previous day in New York. |
| └signal_time | string | Human-readable trigger time, YYYY-MM-DD HH:MM:SS in the market's own timezone. Same format as on /daytrading/signals and /daytrading/history. |
| └buy_ts | int64 | Entry time, unix seconds. On 30m signals it is the right-edge timestamp of the bar that triggered the entry, so it matches one klines entry exactly. |
| └buy_price | string | Entry price. |
| └sell_ts | int64 | Exit time, unix seconds; 0 while the position is still open. This endpoint returns every position of the session it shows, closed ones included, so closed rows carry their exit time. On 30m signals a kline-triggered exit (take-profit or stop) carries that bar's right-edge timestamp; the 15:50 force-close carries wall-clock time. |
| └sell_price | string | Exit price; empty while the position is still open. |
| └stop_loss_price | string | Strategy stop, entry × 0.97 — both markets stop at -3%. Without it you cannot reproduce the strategy. |
| └current_price | string | Latest price. |
| └return_rate | string | Current return, percent. |
| └status | string | Human-readable progress text. Same field as on /daytrading/signals and /daytrading/history. |
| └klines | AnalysisKlinePointV2[] | Minute bars, same point shape as everywhere else in this API. Sorted by timestamp ascending (oldest first) — the same order in both markets, on all three daytrading endpoints, and as swingmax. Bar stamping since 2026-09-17: on 30m signals the bars are right-edge stamped and anchored to the session open, the same convention as /pivot-point/info — the first US bar of the day is 10:00, the first HK afternoon bar 13:30, and buy_ts is one of these timestamps. 15m signals keep the upstream left-edge stamps with the 09:30 bar removed, so that series starts at 09:45. |
| └total | int32 | Rows after filtering, before paging. |
POST https://api.alphio.ai/v1/openapi/analysis/daytrading/open
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{"page":1,"size":10,"sort_type":1}{
"ret": 0,
"msg": "ok",
"data": {
"list":[
{"id":90211,"symbol":"NVDA","code":"NVDA.O","name":"NVIDIA Corp","logo":"https://.../nvda.png",
"interval":"15m","signal_date":"2025-08-19","signal_time":"2025-08-19 10:00:00",
"buy_ts":1755612000,"buy_price":"118.42","sell_ts":0,"sell_price":"",
"stop_loss_price":"114.87","current_price":"119.80",
"return_rate":"1.17","status":"Entered @118.42 and staying patient",
"klines":[]}
],
"total": 1
}
}Signal records for the given tickers — what fired and how it resolved, as opposed to /daytrading/open which describes the current book. Same request shape as /swingmax/signals: pass tickers, get every signal for those codes in one response.
| Field | Type | Required | Description |
|---|---|---|---|
| tickers | AnalysisAsset[] | no | An array of OBJECTS, not of strings: [{"ticker":"NVDA"}]. Either tickers or ids is required; both together is InvalidArgument. Matches both the bare code and the suffixed one, case-insensitively. Every signal for those codes comes back in one response, newest buy_ts first. |
| └asset_type | int32 | no | 0=stock, 1=etf, 2=crypto. |
| └symbol | string | no | Legacy field. |
| └ticker | string | no | Preferred field. |
| └locale | string | no | "US" / "HK". |
| ids | int64[] | no | Signal ids to look up — the id field of an item returned by /open, /signals or /history (all three carry the same signal id). At most 20; more is InvalidArgument, NOT truncated. Mutually exclusive with tickers. Selects the same rows the tickers path would (in-flight and resolved signals alike), just by id. Negative ids — HK backtest rows from /history — are resolved too, returning that round-trip in the same item shape (status starts with "Backtest:"). 0 is InvalidArgument; unknown ids are skipped, not errored. Added 2026-09-15. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisDaytradingSignalsData | Response payload. |
| └list | AnalysisDaytradingSignalItem[] | One entry per signal. |
| └id | int64 | Signal id — the value to pass back as ids on this endpoint; the same number as id on /open and /history for the same trade. |
| └symbol | string | Bare code. US: NVDA. HK: five digits, e.g. 00700. |
| └code | string | Suffixed form. Empty on US — that pipeline has no ticker lookup on this path. |
| └name | string | Company name. Populated on HK (real name from the HK code table). Empty on US. |
| └logo | string | Logo URL. Empty on both: HK has no logo source, and the US pipeline is left untouched here. |
| └interval | string | Bar interval that produced the entry, 15m or 30m. |
| └signal_date | string | Signal day on that market's trading calendar, YYYY-MM-DD. |
| └signal_time | string | Human-readable trigger time. HK only. |
| └buy_ts | int64 | Entry time, unix seconds. On 30m signals it is the right-edge timestamp of the bar that triggered the entry, so it matches one klines entry exactly. |
| └buy_price | string | Entry signal price. |
| └sell_ts | int64 | Exit time, unix seconds. 0 while still open. On 30m signals a kline-triggered exit (take-profit or stop) carries that bar's right-edge timestamp; the 15:50 force-close carries wall-clock time. |
| └sell_price | string | Exit signal price; empty while still open. |
| └stop_loss_price | string | Strategy stop (entry × 0.97 — both markets stop at -3%). |
| └current_price | string | Latest price; empty for settled signals. |
| └return_rate | string | Percent, not a fraction. Same name and meaning as on /open and /history. |
| └status | string | Human-readable progress/exit text — the same field as status on /open and /history. |
| └klines | AnalysisKlinePointV2[] | Minute bars centred on the entry. Sorted by timestamp ascending (oldest first) — the same order in both markets, on all three daytrading endpoints, and as swingmax. Bar stamping since 2026-09-17: on 30m signals the bars are right-edge stamped and anchored to the session open, the same convention as /pivot-point/info — the first US bar of the day is 10:00, the first HK afternoon bar 13:30, and buy_ts is one of these timestamps. 15m signals keep the upstream left-edge stamps with the 09:30 bar removed, so that series starts at 09:45. |
| └total | int32 | Always equal to the length of list — this endpoint is not paged. |
POST https://api.alphio.ai/v1/openapi/analysis/daytrading/signals
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{"tickers":[{"asset_type":0,"ticker":"NVDA","locale":"US"}]}{
"ret": 0,
"msg": "ok",
"data": {
"list":[
{"id":90211,"symbol":"NVDA","code":"","name":"","logo":"","interval":"15m","signal_date":"2026-08-19","signal_time":"",
"buy_ts":1755612000,"buy_price":"118.42","sell_ts":1755620100,"sell_price":"121.97","stop_loss_price":"114.87","current_price":"",
"return_rate":"3.00","status":"Booked partial profits @121.97",
"klines":[{"close":118.9,"timestamp":1755612000,"open":118.4,"high":119.1,"low":118.2,"volume":1234567}]}
],
"total": 1
}
}Closed round-trips — one row per completed entry-and-exit, with both prices, both timestamps and the realised return. Deliberately carries no K-line data. Call /v1/openapi/data/kline if you need bars — inlining them here would grow the payload by an order of magnitude for callers who only want the numbers.
| Field | Type | Required | Description |
|---|---|---|---|
| symbol | string | no | Optional ticker, e.g. NVDA. Omit for all symbols. Passing one enables the synthetic open-position row described in the notes. |
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, capped at 20 — the same ceiling as every other paged list on this API; only the two swingmax /open endpoints are uncapped. Was 10 before 2026-09-15. |
| sort_type | int32 | no | 0 = endpoint default, 1 = latest first, 2 = oldest first. 3 and 4 (by return) return InvalidArgument here: this endpoint pages upstream, so sorting would only reorder the current page — sort client-side after fetching all pages instead. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Exact ticker match, applied upstream before paging (the trades table has no name column). If symbol is also set, symbol wins — an exact filter should not be overridden by a fuzzy one. Omit to disable filtering. Max 64 characters. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisDaytradingHistoryData | Response payload. |
| └list | AnalysisDaytradingHistoryItem[] | One entry per round-trip, newest entry first. |
| └id | int64 | Signal id — the same number as id on /open and /signals for this trade, so an id stored from any of the three endpoints can be passed back as ids on /signals. Before 2026-09-15 this field was the round-trip table's own key, a different keyspace. Negative means a backtest row (HK only — exit_reason starts with "Backtest:"): every backtest row carries its own distinct negative id, so it works as a bookmark key, and passing it back as ids on /daytrading/hk/signals returns that round-trip in the same item shape as a live signal. 0 means a legacy row with no linked signal; 0 is the one value ids rejects. |
| └symbol | string | Bare code. US: NVDA. HK: five digits, e.g. 00700. |
| └code | string | Suffixed form. US: NVDA.O. HK: 00700.HK. |
| └name | string | Company name. |
| └logo | string | Logo URL; empty when unavailable. |
| └interval | string | Bar interval behind the entry, 15m or 30m. |
| └signal_date | string | Signal day on that market's trading calendar, YYYY-MM-DD. |
| └signal_time | string | Human-readable trigger time. |
| └buy_ts | int64 | Entry time, unix seconds. On 30m signals it is the right-edge timestamp of the bar that triggered the entry, so it matches one klines entry exactly. |
| └buy_price | string | Entry price. |
| └sell_ts | int64 | Exit time, unix seconds. 0 = not settled yet. On 30m signals a kline-triggered exit (take-profit or stop) carries that bar's right-edge timestamp; the 15:50 force-close carries wall-clock time. |
| └sell_price | string | Exit price; empty when not settled. |
| └stop_loss_price | string | Strategy stop price (HK daytrading stops at -3%). This was missing before — without it you cannot reproduce or check the strategy. |
| └current_price | string | Latest price. |
| └return_rate | string | Percent, not a fraction: "2.35" means +2.35%. Same name and meaning as on /daytrading/open. |
| └status | string | Human-readable exit text. Same field as on /daytrading/open. |
| └klines | AnalysisKlinePointV2[] | Minute bars around the trade — the same series the product cards draw candlesticks from. Previously suppressed by this layer even though upstream always returned them. Sorted by timestamp ascending (oldest first) — the same order in both markets, on all three daytrading endpoints, and as swingmax. Bar stamping since 2026-09-17: on 30m signals the bars are right-edge stamped and anchored to the session open, the same convention as /pivot-point/info — the first US bar of the day is 10:00, the first HK afternoon bar 13:30, and buy_ts is one of these timestamps. 15m signals keep the upstream left-edge stamps with the 09:30 bar removed, so that series starts at 09:45. |
| └total | int32 | Total rows matching the range, for paging. Excludes the synthetic open-position row. |
POST https://api.alphio.ai/v1/openapi/analysis/daytrading/history
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
Content-Type: application/json
{ "symbol": "NVDA", "page": 1, "size": 20 }{
"ret": 0,
"msg": "ok",
"data": {
"list": [
{
"id": 3521,
"symbol": "NVDA",
"code": "NVDA",
"trade_date": "2026-08-19",
"entry_time": 1755612000,
"exit_time": 1755620100,
"entry_price": "118.4200",
"exit_price": "121.9700",
"return_rate": "3.00",
"interval": "15m",
"exit_reason": "Booked 3.00% profits @121.97 at 11:35 AM"
}
],
"total": 1
}
}DayTrading (HK)
Intraday signals for HK equities. Same shape as the US feed but a SEPARATE pipeline end to end — its own process, its own signal table, its own switch. One market going down does not affect the other, which is also why the paths differ instead of taking a locale parameter. The strategy parameters are NOT the US ones: take profit at 0.5%, book on a 0.2% pull-back from the high, stop at -3%, and entries only fire while the market (equal-weighted intraday move across the pool) is below -0.4% (it was -0.8% until 2026-09-29; relaxed so more sessions produce entries). Those numbers were calibrated on HK data — the US set (3% / 1%) scored a 46.5% win rate with negative expectancy when replayed on HK bars. Sessions are 09:30-12:00 and 13:00-16:00 HKT; signal windows are 10:00-11:00 and 13:00-14:00, and anything still open is force-closed at 15:50.
Positions from one Hong Kong trading session, open and closed. Which session: on a trading day before the HK open (09:30 HKT), and on any non-trading day, it is the previous trading session; from the open onward it is the current one, including after the close. `code` carries the .HK suffix (00700.HK); `symbol` is the bare five-digit number. Closed positions carry sell_price, sell_ts and a realized return_rate; open ones carry current_price and a live return_rate. NOTE: between the open and the first signal of the day (intraday signals only start at 10:00 HKT), and on days when the market-breadth gate never opens, the current session is empty — that is expected, not an outage.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, capped at 20 — the same ceiling as every other paged list on this API. Unlike the two swingmax /open endpoints this one is NOT uncapped: every row carries minute bars, so a full-book response would be several times larger. Was 10 before 2026-09-15. |
| sort_type | int32 | no | 0 = endpoint default (by return_rate, high to low — realized for closed positions, live unrealized for open ones), 1 = latest first, 2 = oldest first, 3 = highest return first, 4 = lowest return first. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Case-insensitive substring match on ticker, code and company name. Omit to disable filtering. Max 64 characters. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisDaytradingOpenData | Response payload. |
| └list | AnalysisDaytradingPosition[] | Every position of the session this endpoint is showing — open and closed. Field for field the same shape as /daytrading/signals and /daytrading/history. |
| └id | int64 | Signal id — the same number on /open, /signals and /history for the same trade. Store it from any of the three and pass it back as ids on /signals to follow this position. |
| └symbol | string | Bare code. US: NVDA. HK: five digits, e.g. 00700. |
| └code | string | Suffixed form. US: NVDA.O. HK: 00700.HK. |
| └name | string | Company name. |
| └logo | string | Logo URL; empty when unavailable. |
| └interval | string | Bar interval behind the entry, 15m or 30m. |
| └signal_date | string | Signal day on that market's trading calendar, YYYY-MM-DD. Derived from buy_ts in the market's own timezone — an HK 09:30 signal is still the previous day in New York. |
| └signal_time | string | Human-readable trigger time, YYYY-MM-DD HH:MM:SS in the market's own timezone. Same format as on /daytrading/signals and /daytrading/history. |
| └buy_ts | int64 | Entry time, unix seconds. On 30m signals it is the right-edge timestamp of the bar that triggered the entry, so it matches one klines entry exactly. |
| └buy_price | string | Entry price. |
| └sell_ts | int64 | Exit time, unix seconds; 0 while the position is still open. This endpoint returns every position of the session it shows, closed ones included, so closed rows carry their exit time. On 30m signals a kline-triggered exit (take-profit or stop) carries that bar's right-edge timestamp; the 15:50 force-close carries wall-clock time. |
| └sell_price | string | Exit price; empty while the position is still open. |
| └stop_loss_price | string | Strategy stop, entry × 0.97 — both markets stop at -3%. Without it you cannot reproduce the strategy. |
| └current_price | string | Latest price. |
| └return_rate | string | Current return, percent. |
| └status | string | Human-readable progress text. Same field as on /daytrading/signals and /daytrading/history. |
| └klines | AnalysisKlinePointV2[] | Minute bars, same point shape as everywhere else in this API. Sorted by timestamp ascending (oldest first) — the same order in both markets, on all three daytrading endpoints, and as swingmax. Bar stamping since 2026-09-17: on 30m signals the bars are right-edge stamped and anchored to the session open, the same convention as /pivot-point/info — the first US bar of the day is 10:00, the first HK afternoon bar 13:30, and buy_ts is one of these timestamps. 15m signals keep the upstream left-edge stamps with the 09:30 bar removed, so that series starts at 09:45. |
| └total | int32 | Rows after filtering, before paging. |
POST https://api.alphio.ai/v1/openapi/analysis/daytrading/hk/open
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{"page":1,"size":10,"sort_type":1}{
"ret": 0,
"msg": "ok",
"data": {
"list":[
{"id":13,"symbol":"00522","code":"00522.HK","name":"ASMPT Ltd","logo":"https://.../00522.png",
"interval":"30m","signal_date":"2026-09-10","signal_time":"2026-09-10 13:41:49",
"buy_ts":1789018909,"buy_price":"164.40","sell_ts":0,"sell_price":"",
"stop_loss_price":"159.47","current_price":"165.60",
"return_rate":"0.73","status":"Entered @164.40 and staying patient",
"klines":[]}
],
"total": 1
}
}Signal records for the given tickers — what fired and how it resolved, as opposed to /daytrading/hk/open which describes the current book. Same request shape as /swingmax/hk/signals: pass tickers, get every signal for those codes in one response.
| Field | Type | Required | Description |
|---|---|---|---|
| tickers | AnalysisAsset[] | no | An array of OBJECTS, not of strings: [{"ticker":"00700"}]. Either tickers or ids is required; both together is InvalidArgument. Matches both the bare code and the suffixed one, case-insensitively. Every signal for those codes comes back in one response, newest buy_ts first. |
| └asset_type | int32 | no | 0=stock, 1=etf, 2=crypto. |
| └symbol | string | no | Legacy field. |
| └ticker | string | no | Preferred field. |
| └locale | string | no | "US" / "HK". |
| ids | int64[] | no | Signal ids to look up — the id field of an item returned by /open, /signals or /history (all three carry the same signal id). At most 20; more is InvalidArgument, NOT truncated. Mutually exclusive with tickers. Selects the same rows the tickers path would (in-flight and resolved signals alike), just by id. Negative ids — HK backtest rows from /history — are resolved too, returning that round-trip in the same item shape (status starts with "Backtest:"). 0 is InvalidArgument; unknown ids are skipped, not errored. Added 2026-09-15. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisDaytradingSignalsData | Response payload. |
| └list | AnalysisDaytradingSignalItem[] | One entry per signal. |
| └id | int64 | Signal id — the value to pass back as ids on this endpoint; the same number as id on /open and /history for the same trade. |
| └symbol | string | Bare code. US: NVDA. HK: five digits, e.g. 00700. |
| └code | string | Suffixed form. Empty on US — that pipeline has no ticker lookup on this path. |
| └name | string | Company name. Populated on HK (real name from the HK code table). Empty on US. |
| └logo | string | Logo URL. Empty on both: HK has no logo source, and the US pipeline is left untouched here. |
| └interval | string | Bar interval that produced the entry, 15m or 30m. |
| └signal_date | string | Signal day on that market's trading calendar, YYYY-MM-DD. |
| └signal_time | string | Human-readable trigger time. HK only. |
| └buy_ts | int64 | Entry time, unix seconds. On 30m signals it is the right-edge timestamp of the bar that triggered the entry, so it matches one klines entry exactly. |
| └buy_price | string | Entry signal price. |
| └sell_ts | int64 | Exit time, unix seconds. 0 while still open. On 30m signals a kline-triggered exit (take-profit or stop) carries that bar's right-edge timestamp; the 15:50 force-close carries wall-clock time. |
| └sell_price | string | Exit signal price; empty while still open. |
| └stop_loss_price | string | Strategy stop (entry × 0.97 — both markets stop at -3%). |
| └current_price | string | Latest price; empty for settled signals. |
| └return_rate | string | Percent, not a fraction. Same name and meaning as on /open and /history. |
| └status | string | Human-readable progress/exit text — the same field as status on /open and /history. |
| └klines | AnalysisKlinePointV2[] | Minute bars centred on the entry. Sorted by timestamp ascending (oldest first) — the same order in both markets, on all three daytrading endpoints, and as swingmax. Bar stamping since 2026-09-17: on 30m signals the bars are right-edge stamped and anchored to the session open, the same convention as /pivot-point/info — the first US bar of the day is 10:00, the first HK afternoon bar 13:30, and buy_ts is one of these timestamps. 15m signals keep the upstream left-edge stamps with the 09:30 bar removed, so that series starts at 09:45. |
| └total | int32 | Always equal to the length of list — this endpoint is not paged. |
POST https://api.alphio.ai/v1/openapi/analysis/daytrading/hk/signals
Authorization: Bearer pk_live_••••••••••••••••••••••••••••
{"tickers":[{"asset_type":0,"ticker":"09988","locale":"HK"}],"lang":"zh-tw"}{
"ret": 0,
"msg": "ok",
"data": {
"list":[
{"id":41207,"symbol":"09988","code":"09988.HK","name":"阿里巴巴-W","logo":"","interval":"15m","signal_date":"2026-08-19","signal_time":"2026-08-19 10:15:00",
"buy_ts":1755569700,"buy_price":"118.40","sell_ts":1755571500,"sell_price":"119.00","stop_loss_price":"114.85","current_price":"",
"return_rate":"0.51","status":"Booked partial profits @119.00",
"klines":[{"close":118.6,"timestamp":1755569700,"open":118.4,"high":118.9,"low":118.3,"volume":2310000}]}
],
"total": 1
}
}Closed round-trips — one row per completed entry-and-exit, with both prices, both timestamps and the realised return. Deliberately carries no K-line data. Call /v1/openapi/data/kline if you need bars — inlining them here would grow the payload by an order of magnitude for callers who only want the numbers.
| Field | Type | Required | Description |
|---|---|---|---|
| symbol | string | no | Optional. Bare five-digit HK code (00700). Omit for all symbols. |
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, capped at 20 — the same ceiling as every other paged list on this API; only the two swingmax /open endpoints are uncapped. Was 10 before 2026-09-15. |
| sort_type | int32 | no | 0 = endpoint default, 1 = latest first, 2 = oldest first. 3 and 4 (by return) return InvalidArgument here: this endpoint pages upstream, so sorting would only reorder the current page — sort client-side after fetching all pages instead. The same number means the same thing on the US and HK endpoints. |
| keyword | string | no | Exact ticker match, applied upstream before paging (the trades table has no name column). If symbol is also set, symbol wins — an exact filter should not be overridden by a fuzzy one. Omit to disable filtering. Max 64 characters. |
| lang | string | no | Localizes the status text. When set it takes priority over the "lang" request header: "zh" / "zh-cn" for Simplified Chinese, "zh-tw" for Traditional Chinese. Omit or leave empty to fall back to the header (English by default). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisDaytradingHistoryData | Response payload. |
| └list | AnalysisDaytradingHistoryItem[] | One entry per completed round-trip, newest entry first. |
| └id | int64 | Signal id — the same number as id on /open and /signals for this trade, so an id stored from any of the three endpoints can be passed back as ids on /signals. Before 2026-09-15 this field was the round-trip table's own key, a different keyspace. Negative means a backtest row (HK only — exit_reason starts with "Backtest:"): every backtest row carries its own distinct negative id, so it works as a bookmark key, and passing it back as ids on /daytrading/hk/signals returns that round-trip in the same item shape as a live signal. 0 means a legacy row with no linked signal; 0 is the one value ids rejects. |
| └symbol | string | Bare code. US: NVDA. HK: five digits, e.g. 00700. |
| └code | string | Suffixed form. US: NVDA.O. HK: 00700.HK. |
| └name | string | Company name. |
| └logo | string | Logo URL; empty when unavailable. |
| └interval | string | Bar interval behind the entry, 15m or 30m. |
| └signal_date | string | Signal day on that market's trading calendar, YYYY-MM-DD. |
| └signal_time | string | Human-readable trigger time. |
| └buy_ts | int64 | Entry time, unix seconds. On 30m signals it is the right-edge timestamp of the bar that triggered the entry, so it matches one klines entry exactly. |
| └buy_price | string | Entry price. |
| └sell_ts | int64 | Exit time, unix seconds. 0 = not settled yet. On 30m signals a kline-triggered exit (take-profit or stop) carries that bar's right-edge timestamp; the 15:50 force-close carries wall-clock time. |
| └sell_price | string | Exit price; empty when not settled. |
| └stop_loss_price | string | Strategy stop price (HK daytrading stops at -3%). This was missing before — without it you cannot reproduce or check the strategy. |
| └current_price | string | Latest price. |
| └return_rate | string | Percent, not a fraction: "2.35" means +2.35%. Same name and meaning as on /daytrading/open. |
| └status | string | Human-readable exit text. Same field as on /daytrading/open. |
| └klines | AnalysisKlinePointV2[] | Minute bars around the trade — the same series the product cards draw candlesticks from. Previously suppressed by this layer even though upstream always returned them. Sorted by timestamp ascending (oldest first) — the same order in both markets, on all three daytrading endpoints, and as swingmax. Bar stamping since 2026-09-17: on 30m signals the bars are right-edge stamped and anchored to the session open, the same convention as /pivot-point/info — the first US bar of the day is 10:00, the first HK afternoon bar 13:30, and buy_ts is one of these timestamps. 15m signals keep the upstream left-edge stamps with the 09:30 bar removed, so that series starts at 09:45. |
| └total | int32 | Total rows matching the range, for paging. |
POST https://api.alphio.ai/v1/openapi/analysis/daytrading/hk/history
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{ "symbol": "00700", "page": 1, "size": 20 }{
"ret": 0,
"msg": "ok",
"data": {
"list": [
{
"id": 12,
"symbol": "00700",
"code": "00700.HK",
"trade_date": "2026-09-08",
"entry_time": 1788838200,
"exit_time": 1788845400,
"entry_price": "445.4000",
"exit_price": "448.2000",
"return_rate": "0.63",
"interval": "15m",
"exit_reason": "Booked 0.63% profits @448.20 at 12:30 PM"
}
],
"total": 1
}
}AI Stock Picker
A model portfolio, not a signal feed. AI Stock Picker holds a basket of roughly ten US stocks by weight, rebalances weekly and stops names out intraday. Unlike /swingmax and /daytrading, where every row is an independent trade, these rows add up to one book and performance is measured on the book. Three endpoints mirror the product page: current holdings, closed positions, performance. Scope: analysis:stock-picker.
Current holdings of the AI Stock Picker book, with entry, stop, latest price, unrealized return, weight and daily bars for each name. Returns every holding in one call by default; the paging, sorting and keyword parameters are there for callers that want them.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Omit to return every holding in one call — the book holds about ten names. Set it only if you want pages. |
| sort_type | int32 | no | 0 = endpoint default (upstream order: weight, high to low), 1 = newest join_date first, 2 = oldest join_date first, 3 = highest return first, 4 = lowest return first. |
| keyword | string | no | Case-insensitive substring match on symbol and code. Omit to disable filtering. Max 64 characters. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisStockPickerCurrentData | Response payload. |
| └positions | AnalysisStockPickerPosition[] | One row per holding. |
| └symbol | string | Bare ticker, e.g. NVDA. |
| └code | string | Same as symbol for this product today — the upstream feed carries no exchange suffix here (e.g. MSFT, not MSFT.O). |
| └locale | string | Always US. |
| └asset_type | int32 | 0 = stock. |
| └narrative | string | Theme the name was picked under, e.g. "AI infrastructure". The portfolio is diversified across themes, so this is the grouping key. English only. |
| └rationale | string | Why this name was picked, as written by the model at entry. English only. |
| └join_date | string | Entry date, YYYY-MM-DD (US Eastern trading day). Compare with as_of to tell a fresh pick from a name that has been held for weeks. |
| └entry_price | double | Cost basis. |
| └stop_loss | double | Stop price. When it triggers the row moves to status=stopped and drops out of this list at the next snapshot; the exit then shows up on /stock-picker/history with exit_reason=stop_loss. |
| └current_price | double | Latest price. 0 means the quote could not be fetched — in that case return is also 0, which is NOT "flat". |
| └return | double | (current_price / entry_price - 1) * 100, in percent, 2 decimals. Unrealized. |
| └weight | double | Portfolio weight in percent (10 = 10% of the book). |
| └status | string | active, or stopped for a name whose stop triggered intraday and is waiting for the next snapshot to leave the book. |
| └kline | AnalysisKlinePointV2[] | Daily bars from join_date to today, oldest first. OHLC only — volume is always 0 on this endpoint. |
| └total | int32 | Rows after keyword filtering, before paging. |
| └as_of | string | Snapshot date of the book, YYYY-MM-DD US Eastern. The snapshot is refreshed every trading day around 08:00 ET, but rebalancing only happens weekly — a new as_of does not mean the holdings changed; look at join_date for that. |
POST https://api.alphio.ai/v1/openapi/analysis/stock-picker/current
{}{
"ret": 0,
"msg": "ok",
"data": {
"positions": [
{"symbol":"ULTA","code":"ULTA","locale":"US","asset_type":0,
"narrative":"Beauty retail resilience","rationale":"...",
"join_date":"2026-10-06","entry_price":412.5,"stop_loss":371.25,
"current_price":430.1,"return":4.27,"weight":10,"status":"active",
"kline":[{"close":415.2,"timestamp":1759723200,"open":411.9,"high":417.3,"low":410.8,"volume":0}]}
],
"total": 1,
"as_of": "2026-10-15"
}
}Closed positions of the AI Stock Picker book, newest exit first, paged upstream. Each row is one complete holding: entry and exit dates and prices, realized return, weight while held, and why it left the book.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, maximum 20; larger values are clamped, not rejected. |
| start_date | string | no | Earliest exit_date to include, YYYY-MM-DD, inclusive. Omit for no lower bound. |
| end_date | string | no | Latest exit_date to include, YYYY-MM-DD, inclusive. Omit for no upper bound. Must not be before start_date — a reversed range is InvalidArgument, not an empty list. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisStockPickerHistoryData | Response payload. |
| └list | AnalysisStockPickerClosedPosition[] | Closed positions, newest exit_date first. |
| └symbol | string | Bare ticker, e.g. NVDA. |
| └code | string | Same as symbol for this product today — the upstream feed carries no exchange suffix here (e.g. MSFT, not MSFT.O). |
| └locale | string | Always US. |
| └asset_type | int32 | 0 = stock. |
| └narrative | string | Theme the name was picked under, e.g. "AI infrastructure". The portfolio is diversified across themes, so this is the grouping key. English only. |
| └rationale | string | Why this name was picked, as written by the model at entry. English only. |
| └join_date | string | Entry date, YYYY-MM-DD. |
| └exit_date | string | Exit date, YYYY-MM-DD. This is what start_date / end_date filter on. |
| └entry_price | double | Cost basis. |
| └exit_price | double | Fill price at exit. 0 on the rare early rows where the pipeline did not record it. |
| └return | double | Realized return of the position, (exit_price / entry_price - 1) * 100, in percent. |
| └weight | double | Portfolio weight while held, in percent. |
| └exit_reason | string | rebalance = swapped out at the weekly rebalance; stop_loss = the stop triggered intraday. |
| └total | int32 | Rows matching the date filter, before paging. |
POST https://api.alphio.ai/v1/openapi/analysis/stock-picker/history
{"page": 1, "size": 20, "start_date": "2026-09-01", "end_date": "2026-09-30"}{
"ret": 0,
"msg": "ok",
"data": {
"list": [
{"symbol":"NVDA","code":"NVDA","locale":"US","asset_type":0,
"narrative":"AI infrastructure","rationale":"...",
"join_date":"2026-09-01","exit_date":"2026-09-29",
"entry_price":100,"exit_price":112.35,"return":12.35,"weight":8,
"exit_reason":"rebalance"}
],
"total": 1
}
}Track record of the AI Stock Picker book since inception: headline statistics plus the cumulative-return curve against the S&P 500 on the same time axis. Recomputed upstream once a day after the US close; there is no period parameter.
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisStockPickerPerformanceData | Response payload. |
| └strategy_name | string | Product name, "AI Stock Picker". |
| └description | string | One-paragraph strategy description. English only. |
| └total_return | double | Cumulative return since inception, percent. |
| └annualized_return | double | Annualized return, percent. |
| └win_rate | double | Share of closed positions that were profitable, percent. |
| └max_drawdown | double | Largest peak-to-trough decline of the book, percent, negative. |
| └sharpe_ratio | double | Sharpe ratio. Not a percent. |
| └day1_change | double | Change of the book over the latest trading day, percent. |
| └biggest_lose_return | double | Worst single closed position, percent, negative. |
| └strategy_curve | AnalysisPerformancePoint[] | Cumulative return of the book, one point per trading day, oldest first. |
| └date | string | Trading day, YYYY-MM-DD in US Eastern time. |
| └ts | int64 | Unix seconds at 00:00 US Eastern on that trading day. Both curves carry date and ts so one charting routine works for every portfolio product. |
| └cumulative_return | double | Cumulative return since the first point of the curve, in percent (2.35 = +2.35%). |
| └sp500_curve | AnalysisPerformancePoint[] | S&P 500 over the same days, same time axis, so the two can be drawn on one chart. |
| └date | string | Trading day, YYYY-MM-DD in US Eastern time. |
| └ts | int64 | Unix seconds at 00:00 US Eastern on that trading day. Both curves carry date and ts so one charting routine works for every portfolio product. |
| └cumulative_return | double | Cumulative return since the first point of the curve, in percent (2.35 = +2.35%). |
POST https://api.alphio.ai/v1/openapi/analysis/stock-picker/performance
{}{
"ret": 0,
"msg": "ok",
"data": {
"strategy_name": "AI Stock Picker",
"description": "...",
"total_return": 23.45, "annualized_return": 30.1, "win_rate": 61.23,
"max_drawdown": -10.2, "sharpe_ratio": 1.23, "day1_change": 0.42,
"biggest_lose_return": -14.8,
"strategy_curve": [{"date":"2026-01-02","ts":1767330000,"cumulative_return":0}, {"date":"2026-01-05","ts":1767589200,"cumulative_return":0.8}],
"sp500_curve": [{"date":"2026-01-02","ts":1767330000,"cumulative_return":0}, {"date":"2026-01-05","ts":1767589200,"cumulative_return":0.3}]
}
}SwingMax Portfolio
SwingMax Portfolio is the book built from SwingMax signals: up to ten US names held by weight, with the same R2/R3 ladder exits as the single-name signals, plus a cash sleeve. It is a separate product from /swingmax/* — those endpoints give you every signal, this one gives you the managed portfolio — and a separate scope: analysis:swingmax-portfolio. Three endpoints: current book, closed trades, performance.
The book as it stands: current positions with weight and unrealized return, the industry breakdown, and the fills of the most recent trading session. One call, no paging — the book holds at most ten names.
| Field | Type | Required | Description |
|---|---|---|---|
| lang | string | no | Localizes description. "zh" / "zh-cn" = Simplified Chinese, "zh-tw" = Traditional Chinese; anything else, or empty, is English. Takes priority over the lang request header. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxPortfolioCurrentData | Response payload. |
| └description | string | One-paragraph product description, localized by lang. |
| └positions | AnalysisSwingmaxPortfolioPosition[] | Current holdings, weight high to low, at most ten. |
| └symbol | string | Bare ticker, e.g. NVDA. |
| └name | string | Company name. |
| └locale | string | Always US. |
| └asset_type | int32 | 0 = stock. |
| └price | double | Latest daily close — not a live quote. |
| └cost | double | Entry price. |
| └return | double | (price / cost - 1) * 100, percent, 2 decimals. Unrealized. |
| └weight | double | Portfolio weight in percent (10 = 10% of the book). |
| └entry_ts | int64 | Entry time, unix seconds. |
| └industries | AnalysisSwingmaxPortfolioIndustry[] | Industry breakdown of the book, Cash first then by weight. |
| └industry | string | TRBC industry group name. The first row is always "Cash" — the part of the book not invested. |
| └weight | double | Percent of the book. All rows add up to 100. |
| └latest_trades | AnalysisSwingmaxPortfolioTrade[] | Fills of the most recent trading session, newest first. Empty on a session with no trades. |
| └symbol | string | Bare ticker, e.g. NVDA. |
| └name | string | Company name. |
| └locale | string | Always US. |
| └asset_type | int32 | 0 = stock. |
| └signal_ts | int64 | Fill time, unix seconds. |
| └filled_price | double | Fill price. |
| └weight_before | double | Weight of this name in the book before the fill, percent. |
| └weight_after | double | Weight after the fill, percent. 0 on a full exit. |
| └event | string | BUY, R2, R3 or SELL — the same ladder names as the /swingmax signals: R2 and R3 are partial profit-taking at the first and second targets, SELL is the final exit (stop or max hold). |
| └side | int32 | 1 = buy, 2 = sell. R2, R3 and SELL are all sells. |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax-portfolio/current
{"lang": ""}{
"ret": 0,
"msg": "ok",
"data": {
"description": "SwingMax Portfolio is a curated AI portfolio built from the best SwingMax signals. ...",
"positions": [
{"symbol":"AAPL","name":"Apple Inc","locale":"US","asset_type":0,
"price":230.5,"cost":220,"return":4.77,"weight":9.5,"entry_ts":1759723200}
],
"industries": [
{"industry":"Cash","weight":12.5},
{"industry":"Software & IT Services","weight":87.5}
],
"latest_trades": [
{"symbol":"NVDA","name":"NVIDIA Corp","locale":"US","asset_type":0,
"signal_ts":1760000000,"filled_price":180.25,
"weight_before":9.8,"weight_after":4.9,"event":"R2","side":2}
]
}
}Closed trades of the SwingMax Portfolio book, one row per completed round trip: entry and exit time and price, weight while held, realized return. Paged and sorted upstream, so all four sort orders are available.
| Field | Type | Required | Description |
|---|---|---|---|
| page | int32 | no | 1-based. 0 or negative is treated as unset and means page 1. |
| size | int32 | no | Rows per page. Default 20, maximum 20; larger values are clamped, not rejected. |
| sort_type | int32 | no | 0 or 1 = newest entry first, 2 = oldest entry first, 3 = highest realized_return first, 4 = lowest first. The default is newest first, not the upstream table's natural order. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxPortfolioHistoryData | Response payload. |
| └list | AnalysisSwingmaxPortfolioClosedTrade[] | Closed trades in the requested order. |
| └symbol | string | Bare ticker, e.g. NVDA. |
| └name | string | Company name. |
| └locale | string | Always US. |
| └asset_type | int32 | 0 = stock. |
| └entry_ts | int64 | Entry time, unix seconds. |
| └entry_price | double | Entry price. |
| └exit_ts | int64 | Exit time, unix seconds. |
| └exit_price | double | Exit price. |
| └weight | double | Portfolio weight while held, in percent. |
| └realized_return | double | Realized return of the trade, percent, 2 decimals. |
| └total | int32 | All closed trades, before paging. |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax-portfolio/history
{"page": 1, "size": 20, "sort_type": 3}{
"ret": 0,
"msg": "ok",
"data": {
"list": [
{"symbol":"TSLA","name":"Tesla Inc","locale":"US","asset_type":0,
"entry_ts":1757376000,"entry_price":100,"exit_ts":1759104000,"exit_price":110,
"weight":9.9,"realized_return":10}
],
"total": 1
}
}Performance of the SwingMax Portfolio book over a chosen window: the book's return and the S&P 500's over the same window, both cumulative-return curves on one time axis, and the since-inception statistics.
| Field | Type | Required | Description |
|---|---|---|---|
| period | int32 | no | Window for the curves and the two window returns: 0 or 5 = everything since 2024-01-01, 1 = last 1 month, 2 = last 3 months, 3 = last 6 months, 4 = last 1 year. Any other value is InvalidArgument. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | AnalysisSwingmaxPortfolioPerformanceData | Response payload. |
| └period | int32 | The window actually applied — 0 is echoed back as 5. |
| └portfolio_return | double | Return of the book over the window, percent: last capital in the window against the first. |
| └sp500_return | double | S&P 500 (SPY close) over the same window, percent. |
| └stats | AnalysisSwingmaxPortfolioStats | Since-inception statistics. Independent of period. |
| └total_return | double | Cumulative return since the book's inception, percent. |
| └annualized_return | double | Annualized return, percent. |
| └day1_change | double | Change of the book over the latest trading day, percent. |
| └sharpe_ratio | double | Sharpe ratio. Not a percent. |
| └portfolio_curve | AnalysisPerformancePoint[] | Cumulative return of the book inside the window, rebased to 0 at the first point. Aligned to SPY's trading days; days the book has no record for carry the previous value forward. |
| └date | string | Trading day, YYYY-MM-DD in US Eastern time. |
| └ts | int64 | Unix seconds at 00:00 US Eastern on that trading day. Both curves carry date and ts so one charting routine works for every portfolio product. |
| └cumulative_return | double | Cumulative return since the first point of the curve, in percent (2.35 = +2.35%). |
| └sp500_curve | AnalysisPerformancePoint[] | S&P 500 cumulative return over the same days, same time axis. |
| └date | string | Trading day, YYYY-MM-DD in US Eastern time. |
| └ts | int64 | Unix seconds at 00:00 US Eastern on that trading day. Both curves carry date and ts so one charting routine works for every portfolio product. |
| └cumulative_return | double | Cumulative return since the first point of the curve, in percent (2.35 = +2.35%). |
POST https://api.alphio.ai/v1/openapi/analysis/swingmax-portfolio/performance
{"period": 2}{
"ret": 0,
"msg": "ok",
"data": {
"period": 2,
"portfolio_return": 6.4,
"sp500_return": 3.1,
"stats": {"total_return": 40.1, "annualized_return": 20.2, "day1_change": -0.3, "sharpe_ratio": 1.4},
"portfolio_curve": [{"date":"2026-07-15","ts":1784088000,"cumulative_return":0}, {"date":"2026-07-16","ts":1784174400,"cumulative_return":0.5}],
"sp500_curve": [{"date":"2026-07-15","ts":1784088000,"cumulative_return":0}, {"date":"2026-07-16","ts":1784174400,"cumulative_return":0.2}]
}
}Whales tracker
Endpoints tracking institutional (13F) and Congressional holdings. entity_type: 1=institution, 2=congress member. seo_name is the stable partner-facing identifier. All return/chart values are decimal fractions (0.012 = +1.2%). Rankings are cached ~10s server-side.
Institutions ranked by the chosen period's return, descending. Institutions only — for congress members use Ranking with entity_type=2.
| Field | Type | Required | Description |
|---|---|---|---|
| period | string | yes | "1d" / "1w" / "1m" / "3m" / "1y". |
| limit | int32 | yes | 1 – 50. |
| include | string | no | Comma-separated: "chart" (equity curve) / "holdings" (top_holdings ≤2 tickers + holding_count) / "performance" (sharpe_ratio + mdd) / "returns" (return_1d / return_1w / return_1m / return_1y). Empty = base fields only. |
| keyword | string | no | Fuzzy entity-name filter (matches names containing the keyword). Empty = no filtering. |
| sort | string | no | "<field>:<asc|desc>", one field at a time. Fields: total_return (the requested period's return), sharpe_ratio, return_1d, return_1w, return_1m, return_1y, mdd. Empty = period return, descending. Sorting works regardless of include — include only controls which fields are returned. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesTopReturnsData | Response payload. |
| └entities | WhalesEntity[] | Ranked by return_value descending by default; sort overrides the order. |
| └name | string | Entity display name. |
| └action | string | Currently always "Holding" on ranking endpoints; empty on FollowingRanking. |
| └return_value | double | Return for the requested period, decimal fraction (0.618 = +61.8%). TopReturnsByAsset always uses the 3m return. |
| └top_holdings | WhalesHolding[] | Largest positions, tickers only. Only populated when include contains holdings (capped at 2-3 tickers). |
| └ticker | string | Ticker symbol. |
| └holding_count | int32 | Number of positions in the latest filing. 0 unless include contains holdings. |
| └chart | WhalesChartPoint[] | Equity-curve points. Only populated when include contains chart. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └avatar | string | CDN avatar URL. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Stable slug — the partner-facing identifier, feed it to DetailsBySeoName. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. Only populated when include contains performance. |
| └mdd | double | Maximum drawdown, computed from the equity curve. Positive decimal fraction (0.2 = 20% drawdown). Only populated when include contains performance. |
| └return_1d | double | 1-day return, decimal fraction (0.012 = +1.2%). Only populated when include contains returns. |
| └return_1w | double | 1-week return, decimal fraction. Only populated when include contains returns. |
| └return_1m | double | 1-month return, decimal fraction. Only populated when include contains returns. |
| └return_1y | double | 1-year return, decimal fraction. Only populated when include contains returns. |
Ranking filtered by entity_type. Query one period (period → data.entities) or up to 4 at once (periods → data.period_groups).
| Field | Type | Required | Description |
|---|---|---|---|
| period | string | no | Single-period query: "1d" / "1w" / "1m" / "3m" / "1y". Exactly one of period / periods must be set. |
| periods | string[] | no | Multi-period query: up to 4 unique values from the same set. Response returns one period_groups entry per requested period, in request order. |
| limit | int32 | yes | 1 – 50 (applies to each period's list). |
| include | string | no | Comma-separated: "chart" (mini equity curve per entity) / "performance" (sharpe_ratio + mdd) / "returns" (return_1d / return_1w / return_1m / return_1y). |
| entity_type | WhalesEntityType | yes | INSTITUTION (1) / CONGRESS (2). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesRankingData | Response payload. |
| └entities | WhalesEntity[] | Populated for single-period requests. |
| └name | string | Entity display name. |
| └action | string | Currently always "Holding" on ranking endpoints; empty on FollowingRanking. |
| └return_value | double | Return for the requested period, decimal fraction (0.618 = +61.8%). TopReturnsByAsset always uses the 3m return. |
| └top_holdings | WhalesHolding[] | Largest positions, tickers only. Only populated when include contains holdings (capped at 2-3 tickers). |
| └ticker | string | Ticker symbol. |
| └holding_count | int32 | Number of positions in the latest filing. 0 unless include contains holdings. |
| └chart | WhalesChartPoint[] | Equity-curve points. Only populated when include contains chart. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └avatar | string | CDN avatar URL. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Stable slug — the partner-facing identifier, feed it to DetailsBySeoName. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. Only populated when include contains performance. |
| └mdd | double | Maximum drawdown, computed from the equity curve. Positive decimal fraction (0.2 = 20% drawdown). Only populated when include contains performance. |
| └return_1d | double | 1-day return, decimal fraction (0.012 = +1.2%). Only populated when include contains returns. |
| └return_1w | double | 1-week return, decimal fraction. Only populated when include contains returns. |
| └return_1m | double | 1-month return, decimal fraction. Only populated when include contains returns. |
| └return_1y | double | 1-year return, decimal fraction. Only populated when include contains returns. |
| └period_groups | WhalesRankingPeriodGroup[] | Populated for multi-period requests, in the same order as req.periods. |
| └period | string | The requested period this group belongs to. |
| └entities | WhalesEntity[] | Ranking list for this period. |
| └name | string | Entity display name. |
| └action | string | Currently always "Holding" on ranking endpoints; empty on FollowingRanking. |
| └return_value | double | Return for the requested period, decimal fraction (0.618 = +61.8%). TopReturnsByAsset always uses the 3m return. |
| └top_holdings | WhalesHolding[] | Largest positions, tickers only. Only populated when include contains holdings (capped at 2-3 tickers). |
| └ticker | string | Ticker symbol. |
| └holding_count | int32 | Number of positions in the latest filing. 0 unless include contains holdings. |
| └chart | WhalesChartPoint[] | Equity-curve points. Only populated when include contains chart. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └avatar | string | CDN avatar URL. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Stable slug — the partner-facing identifier, feed it to DetailsBySeoName. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. Only populated when include contains performance. |
| └mdd | double | Maximum drawdown, computed from the equity curve. Positive decimal fraction (0.2 = 20% drawdown). Only populated when include contains performance. |
| └return_1d | double | 1-day return, decimal fraction (0.012 = +1.2%). Only populated when include contains returns. |
| └return_1w | double | 1-week return, decimal fraction. Only populated when include contains returns. |
| └return_1m | double | 1-month return, decimal fraction. Only populated when include contains returns. |
| └return_1y | double | 1-year return, decimal fraction. Only populated when include contains returns. |
Reverse-lookup: institutions currently holding a specific ticker, ranked by their 3-month return (descending). return_value is always the 3m return.
| Field | Type | Required | Description |
|---|---|---|---|
| asset | WhalesAsset | yes | The ticker to look up. |
| └asset_type | int32 | no | 0=stock, 1=etf. |
| └ticker | string | yes | Ticker symbol, e.g. "AAPL". |
| └locale | string | no | "US" (default) / "HK". |
| include | string | no | Comma-separated: "chart" / "holdings" / "performance" / "returns". With holdings, the queried ticker is guaranteed to appear in top_holdings. |
| limit | int32 | no | Defaults to 6 when omitted. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesTopReturnsData | Response payload. |
| └entities | WhalesEntity[] | Ranked by 3m return, descending. |
| └name | string | Entity display name. |
| └action | string | Currently always "Holding" on ranking endpoints; empty on FollowingRanking. |
| └return_value | double | Return for the requested period, decimal fraction (0.618 = +61.8%). TopReturnsByAsset always uses the 3m return. |
| └top_holdings | WhalesHolding[] | Largest positions, tickers only. Only populated when include contains holdings (capped at 2-3 tickers). |
| └ticker | string | Ticker symbol. |
| └holding_count | int32 | Number of positions in the latest filing. 0 unless include contains holdings. |
| └chart | WhalesChartPoint[] | Equity-curve points. Only populated when include contains chart. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └avatar | string | CDN avatar URL. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Stable slug — the partner-facing identifier, feed it to DetailsBySeoName. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. Only populated when include contains performance. |
| └mdd | double | Maximum drawdown, computed from the equity curve. Positive decimal fraction (0.2 = 20% drawdown). Only populated when include contains performance. |
| └return_1d | double | 1-day return, decimal fraction (0.012 = +1.2%). Only populated when include contains returns. |
| └return_1w | double | 1-week return, decimal fraction. Only populated when include contains returns. |
| └return_1m | double | 1-month return, decimal fraction. Only populated when include contains returns. |
| └return_1y | double | 1-year return, decimal fraction. Only populated when include contains returns. |
Ranks the entities the calling user follows (their watchlist) by the chosen period's return, descending. Requires X-Partner-User, like the watchlist endpoints.
| Field | Type | Required | Description |
|---|---|---|---|
| period | string | yes | "1d" / "1w" / "1m" / "3m" / "1y". |
| limit | int32 | yes | 1 – 50. Truncates the sorted list. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesFollowingRankingData | Response payload. |
| └entities | WhalesEntity[] | Only name, return_value, avatar, entity_type and seo_name are populated here — no action / top_holdings / holding_count / chart / performance metrics. |
| └name | string | Entity display name. |
| └action | string | Currently always "Holding" on ranking endpoints; empty on FollowingRanking. |
| └return_value | double | Return for the requested period, decimal fraction (0.618 = +61.8%). TopReturnsByAsset always uses the 3m return. |
| └top_holdings | WhalesHolding[] | Largest positions, tickers only. Only populated when include contains holdings (capped at 2-3 tickers). |
| └ticker | string | Ticker symbol. |
| └holding_count | int32 | Number of positions in the latest filing. 0 unless include contains holdings. |
| └chart | WhalesChartPoint[] | Equity-curve points. Only populated when include contains chart. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └avatar | string | CDN avatar URL. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Stable slug — the partner-facing identifier, feed it to DetailsBySeoName. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. Only populated when include contains performance. |
| └mdd | double | Maximum drawdown, computed from the equity curve. Positive decimal fraction (0.2 = 20% drawdown). Only populated when include contains performance. |
| └return_1d | double | 1-day return, decimal fraction (0.012 = +1.2%). Only populated when include contains returns. |
| └return_1w | double | 1-week return, decimal fraction. Only populated when include contains returns. |
| └return_1m | double | 1-month return, decimal fraction. Only populated when include contains returns. |
| └return_1y | double | 1-year return, decimal fraction. Only populated when include contains returns. |
Most net-bought / net-sold tickers, aggregated across all tracked institutions' latest quarterly (13F) filings and ranked by aggregate share change.
| Field | Type | Required | Description |
|---|---|---|---|
| locale | string | yes | "us" = US stocks + ETFs / "hk" = HK stocks. |
| tab | string | yes | "increase" = largest aggregate share increases (net buying) / "decrease" = largest aggregate decreases (net selling). |
| limit | int32 | yes | 1 – 50. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesInstitutionsPopularTradesData | Response payload. |
| └trades | WhalesPopularTrade[] | One row per ticker, ordered by |share_change| (largest net buys first on increase, largest net sells first on decrease). |
| └ticker | string | Ticker symbol, e.g. "NVDA". |
| └code | string | Exchange-qualified code, e.g. "NVDA.O". |
| └name | string | Security display name. |
| └asset_type | int32 | 0=stock, 1=etf. |
| └locale | string | "US" / "HK". |
| └share_change | double | Net change in shares held vs the previous quarter, summed across all tracked institutions. Positive = net buying, negative = net selling. This is the ranking key. |
| └holding_mv | double | Total market value (USD) of the position summed across all tracked institutions, per the latest filings. |
Full entity detail by id (from any ranking response).
| Field | Type | Required | Description |
|---|---|---|---|
| id | int32 | yes | ≥ 1. |
| include | string | no | Comma-separated: "chart" (equity curves), "trade_update" (recent trades + last_updated), "current_holdings" (sector distribution). Base fields and positions are always returned. |
| entity_type | WhalesEntityType | yes | INSTITUTION (1) / CONGRESS (2). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesEntityDetails | Response payload. |
| └name | string | Entity display name. |
| └is_watched | bool | Whether the requesting user watches this entity. Always false on partner API calls — no user context is forwarded on this endpoint. |
| └top20_holding_mv | int64 | Aggregate market value (USD) of the entity's 20 largest positions, per the latest filing. |
| └last_updated | string | Date (YYYY-MM-DD) of the most recent reported portfolio change. Only populated when include contains trade_update. |
| └holding_count | int32 | Number of positions currently held. |
| └description | string | Short text description of the entity. |
| └performance | WhalesPerformance | Tracked-portfolio performance stats. Returns are decimal fractions (0.012 = +1.2%). |
| └return_1d | double | Latest 1-day return, decimal fraction. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. |
| └total_return | double | Cumulative return since tracking began, decimal fraction. |
| └annualized_return | double | Annualized return, decimal fraction. |
| └charts | WhalesCharts | Equity curves. Only populated when include contains chart. |
| └strategy | WhalesChartPoint[] | Entity portfolio equity curve. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └sp500 | WhalesChartPoint[] | S&P 500 benchmark over the same window. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └trade_updates | WhalesTradeUpdate[] | Portfolio changes from the most recent rebalance/filing. Only populated when include contains trade_update. |
| └date | string | Rebalance date, YYYY-MM-DD. |
| └action | string | "buy" / "sell" / "hold" — derived from the weight change (rounded to 2 decimals). |
| └ticker | string | Ticker symbol, e.g. "NVDA". |
| └code | string | Exchange-qualified code, e.g. "NVDA.O". |
| └name | string | Security display name. |
| └asset_type | int32 | 0=stock, 1=etf. |
| └locale | string | "US" / "HK". |
| └old_percent | double | Portfolio weight (%) before the change. |
| └new_percent | double | Portfolio weight (%) after the change. |
| └fill_price | double | Price at the rebalance date. |
| └current_holdings | WhalesCurrentHoldings | Current portfolio. positions is always returned; sector_distribution requires include=current_holdings. |
| └sector_distribution | WhalesSectorWeight[] | Sector weights of the current portfolio. Only populated when include contains current_holdings. |
| └sector | string | Sector name; "other" when unclassified. |
| └weight | double | Weight of the sector, in %. |
| └positions | WhalesPosition[] | All current positions. |
| └ticker | string | Ticker symbol, e.g. "NVDA". |
| └code | string | Exchange-qualified code, e.g. "NVDA.O". |
| └name | string | Security display name. |
| └asset_type | int32 | 0=stock, 1=etf. |
| └locale | string | "US" / "HK". |
| └cost_price | double | Average cost per share. |
| └current_percent | double | Current portfolio weight (%). |
| └total_return | double | Cumulative return of the position since entry. |
| └sector_distribution_desc | string | Server-generated text summary of the sector mix. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └institution_profile | WhalesInstitutionProfile | Only set for institutions (entity_type=1). |
| └person_name | string | Fund manager / key person name. |
| └avatar | string | CDN avatar URL. |
| └profile | string | Manager / institution bio. |
| └investing_philosophy | string | Investing-philosophy blurb. |
| └congress_member_info | WhalesCongressMemberInfo | Only set for congress members (entity_type=2). |
| └avatar | string | Avatar URL. |
| └party | string | Political party, e.g. "Republican" / "Democrat". |
| └organization | string | Chamber, e.g. "Senate" / "House". |
| └faq | WhalesFAQInfo[] | Server-generated FAQ entries derived from the stats above (holding count, returns, AUM). |
| └question | string | — |
| └answer | string | — |
Same as Details but keyed by stable seo_name (from any ranking / search / home response). Preferred when you cached an entity earlier.
| Field | Type | Required | Description |
|---|---|---|---|
| seo_name | string | yes | Stable entity slug, min_len 1. |
| include | string | no | Comma-separated: "chart" (equity curves), "trade_update" (recent trades + last_updated), "current_holdings" (sector distribution). Base fields and positions are always returned. |
| entity_type | WhalesEntityType | yes | INSTITUTION (1) / CONGRESS (2). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesEntityDetails | Response payload. |
| └name | string | Entity display name. |
| └is_watched | bool | Whether the requesting user watches this entity. Always false on partner API calls — no user context is forwarded on this endpoint. |
| └top20_holding_mv | int64 | Aggregate market value (USD) of the entity's 20 largest positions, per the latest filing. |
| └last_updated | string | Date (YYYY-MM-DD) of the most recent reported portfolio change. Only populated when include contains trade_update. |
| └holding_count | int32 | Number of positions currently held. |
| └description | string | Short text description of the entity. |
| └performance | WhalesPerformance | Tracked-portfolio performance stats. Returns are decimal fractions (0.012 = +1.2%). |
| └return_1d | double | Latest 1-day return, decimal fraction. |
| └sharpe_ratio | double | Sharpe ratio of the tracked portfolio. |
| └total_return | double | Cumulative return since tracking began, decimal fraction. |
| └annualized_return | double | Annualized return, decimal fraction. |
| └charts | WhalesCharts | Equity curves. Only populated when include contains chart. |
| └strategy | WhalesChartPoint[] | Entity portfolio equity curve. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └sp500 | WhalesChartPoint[] | S&P 500 benchmark over the same window. |
| └date | string | YYYY-MM-DD. |
| └value | double | Cumulative return since tracking began, decimal fraction (0.618 = +61.8%). |
| └trade_updates | WhalesTradeUpdate[] | Portfolio changes from the most recent rebalance/filing. Only populated when include contains trade_update. |
| └date | string | Rebalance date, YYYY-MM-DD. |
| └action | string | "buy" / "sell" / "hold" — derived from the weight change (rounded to 2 decimals). |
| └ticker | string | Ticker symbol, e.g. "NVDA". |
| └code | string | Exchange-qualified code, e.g. "NVDA.O". |
| └name | string | Security display name. |
| └asset_type | int32 | 0=stock, 1=etf. |
| └locale | string | "US" / "HK". |
| └old_percent | double | Portfolio weight (%) before the change. |
| └new_percent | double | Portfolio weight (%) after the change. |
| └fill_price | double | Price at the rebalance date. |
| └current_holdings | WhalesCurrentHoldings | Current portfolio. positions is always returned; sector_distribution requires include=current_holdings. |
| └sector_distribution | WhalesSectorWeight[] | Sector weights of the current portfolio. Only populated when include contains current_holdings. |
| └sector | string | Sector name; "other" when unclassified. |
| └weight | double | Weight of the sector, in %. |
| └positions | WhalesPosition[] | All current positions. |
| └ticker | string | Ticker symbol, e.g. "NVDA". |
| └code | string | Exchange-qualified code, e.g. "NVDA.O". |
| └name | string | Security display name. |
| └asset_type | int32 | 0=stock, 1=etf. |
| └locale | string | "US" / "HK". |
| └cost_price | double | Average cost per share. |
| └current_percent | double | Current portfolio weight (%). |
| └total_return | double | Cumulative return of the position since entry. |
| └sector_distribution_desc | string | Server-generated text summary of the sector mix. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └institution_profile | WhalesInstitutionProfile | Only set for institutions (entity_type=1). |
| └person_name | string | Fund manager / key person name. |
| └avatar | string | CDN avatar URL. |
| └profile | string | Manager / institution bio. |
| └investing_philosophy | string | Investing-philosophy blurb. |
| └congress_member_info | WhalesCongressMemberInfo | Only set for congress members (entity_type=2). |
| └avatar | string | Avatar URL. |
| └party | string | Political party, e.g. "Republican" / "Democrat". |
| └organization | string | Chamber, e.g. "Senate" / "House". |
| └faq | WhalesFAQInfo[] | Server-generated FAQ entries derived from the stats above (holding count, returns, AUM). |
| └question | string | — |
| └answer | string | — |
Static editorial list of featured entities (ARK, Nancy Pelosi, Berkshire Hathaway, Soros, Renaissance, Pershing Square). Empty body.
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesHomeData | Response payload. |
| └items | WhalesHomeInfo[] | Curated, fixed order — not a ranking. |
| └name | string | Entity display name. |
| └cover | string | CDN cover-image URL for the home card. |
| └label | string | Editorial tag; currently always "Featured". |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Feed to DetailsBySeoName. |
Case-insensitive substring match over all institution and congress-member names.
| Field | Type | Required | Description |
|---|---|---|---|
| keyword | string | yes | min_len 1. Must contain a non-whitespace character. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesSearchData | Response payload. |
| └items | WhalesSearchInfo[] | Capped at 50 results (institutions prioritized up to 25, remainder congress members). |
| └name | string | Entity display name. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └seo_name | string | Feed to DetailsBySeoName. |
Static product-level FAQ about the Whales tracker, localized via Accept-Language (English default, Chinese supported). Not entity-specific — per-entity FAQ comes in Details.faq. Empty body.
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesFAQData | Response payload. |
| └items | WhalesFAQInfo[] | Fixed question/answer list. |
| └question | string | — |
| └answer | string | — |
List entities the user follows, with their returns across all periods. Requires X-Partner-User.
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | WhalesWatchlistListData | Response payload. |
| └items | WhalesWatchlistItem[] | One row per followed entity. |
| └name | string | Entity display name. |
| └entity_type | int32 | 1=institution, 2=congress. |
| └return_1d | double | 1-day return, decimal fraction (0.012 = +1.2%). |
| └return_7d | double | 7-day return, decimal fraction. |
| └return_1m | double | 1-month return, decimal fraction. |
| └return_3m | double | 3-month return, decimal fraction. |
| └return_1y | double | 1-year return, decimal fraction. |
| └avatar | string | CDN avatar URL. |
| └seo_name | string | Stable slug for DetailsBySeoName. |
Add an entity to the calling user's watchlist. Requires X-Partner-User.
| Field | Type | Required | Description |
|---|---|---|---|
| id | int32 | yes | Internal numeric entity id, ≥ 1. |
| entity_type | WhalesEntityType | yes | INSTITUTION (1) / CONGRESS (2). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success. |
| msg | string | Status / error message. |
Remove an entity from the calling user's watchlist. Requires X-Partner-User.
| Field | Type | Required | Description |
|---|---|---|---|
| id | int32 | yes | Internal numeric entity id, ≥ 1. |
| entity_type | WhalesEntityType | yes | INSTITUTION (1) / CONGRESS (2). |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success. |
| msg | string | Status / error message. |
Market data
Raw market data endpoints powering Chat card details. Keyed by symbol; partner UIs typically fetch these on-demand when expanding a card.
Historical valuation time-series.
| Field | Type | Required | Description |
|---|---|---|---|
| ticker | string | yes | e.g. "AAPL". |
| valuation_type | int32 | yes | EValuationType. 0=PE / 1=PB / 2=PS / 3=Price-to-FCF / 4=EV-EBITDA / 5=Price-to-OCF / 6=FCF-Yield / 7=EV-EBIT. |
| is_forward | bool | no | true=forward, false=trailing (default). |
| from | string | no | YYYY-MM-DD. Default last 1Y. |
| to | string | no | YYYY-MM-DD. Default today. |
| locale | string | no | "US" / "HK". |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DataValuationData | Response payload. |
| └valuation | DataValuationItem[] | Time series. |
| └t | string | Date (YYYY-MM-DD). |
| └v | string | Valuation value. |
| └variance_info | DataVarianceInfo | Five reference bands. |
| └mean | string | — |
| └variance | string | — |
| └overvalued | string | mean + 1σ. |
| └undervalued | string | mean − 1σ. |
| └strongly_overvalued | string | mean + 2σ. |
| └strongly_undervalued | string | mean − 2σ. |
POST https://api.alphio.ai/v1/openapi/data/valuation
{ "ticker":"AAPL", "valuation_type":0, "from":"2025-06-01", "to":"2026-06-01", "locale":"US" }{
"ret": 0, "msg": "ok",
"data": {
"valuation":[{"t":"2025-06-01","v":"28.5"},{"t":"2025-06-02","v":"28.7"}, ...],
"variance_info":{
"mean":"30.2","variance":"3.1",
"overvalued":"33.3","undervalued":"27.1",
"strongly_overvalued":"36.4","strongly_undervalued":"24.0"
}
}
}Analyst ratings.
| Field | Type | Required | Description |
|---|---|---|---|
| ticker | string | yes | e.g. "AAPL". |
| from | string | no | YYYY-MM-DD. |
| to | string | no | YYYY-MM-DD. |
| page | int32 | no | 1-indexed. |
| size | int32 | no | 1 – 100, default 20. |
| locale | string | no | "US" / "HK". |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DataRatingData | Response payload. |
| └results | DataStockAnalysis | — |
| └ticker | string | — |
| └code | string | — |
| └analyses | DataAnalysisItem[] | — |
| └rating_analyst | string | — |
| └rating_date | string | — |
| └rating_action | string | "upgrade" / "downgrade" / "maintain" / "initiate". |
| └rating_analyst_stars | double | — |
| └rating_analyst_firm | string | — |
| └rating_price_target | string | — |
| └rating | string | e.g. "buy" / "hold". |
| └rating_upside | double | — |
| └analysis_summary | DataAnalysisSummary | Aggregate snapshot. |
| └code | string | — |
| └symbol | string | — |
| └average_price_target | string | — |
| └buy | int32 | Count of buy ratings. |
| └content | string[] | Highlight bullets. |
| └highest_price_target | string | — |
| └hold | int32 | Count of hold ratings. |
| └lowest_price_target | string | — |
| └pagination | DataPagination | — |
| └current_page | int32 | — |
| └total_pages | int32 | — |
| └total_items | int32 | — |
Financial-metric snapshot (per-quarter or annual).
| Field | Type | Required | Description |
|---|---|---|---|
| code | string | yes | — |
| type | int32 | yes | EFinancialIndicatorsType. 1=EPS / 2=Revenue / 3=ROE / 4=Gross Margin / 5=Net Margin / 6=Current Ratio / 7=Debt to Equity / 8=Operating Margin. |
| report_type | int32 | yes | FinanceReportType. 1=annual / 2=quarterly. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DataSnapshotData | Response payload. |
| └columns | DataSnapshotColumn[] | Each column = one metric series. |
| └name | string | — |
| └values | DataSnapshotValue[] | One cell per period. |
| └title | string | e.g. "Q1 2026". |
| └value | double | — |
| └cur_type | string | Currency / unit. |
| └valid | bool | false → missing data; render as "—". |
OHLCV bars.
| Field | Type | Required | Description |
|---|---|---|---|
| tickers | WhalesAsset[] | yes | Max 20 per request. |
| └asset_type | int32 | no | SymbolType: 0=stock, 1=etf, 2=crypto, 3=commodity, 4=forex, 5=perp. |
| └ticker | string | no | e.g. "TSLA". |
| └locale | string | no | "US" / "HK". |
| from | string | no | YYYY-MM-DD (US-Eastern) or unix seconds. |
| to | string | no | YYYY-MM-DD (US-Eastern) or unix seconds. |
| multiplier | int32 | no | e.g. 1, 5, 15. |
| timespan | int32 | no | TimespanOpt. 2=minute, 3=hour, 4=day, 5=week, 6=month, 7=quarter, 8=year. Values outside 2–8 are rejected. |
| limit | int32 | no | Max 1000. Default 500. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DataKlineData | Response payload. |
| └series | DataKlineSeries[] | One series per requested ticker. |
| └ticker | string | — |
| └asset_type | int32 | — |
| └points | DataKlinePoint[] | OHLCV bars. Numbers are strings to avoid precision loss. |
| └open | string | — |
| └high | string | — |
| └low | string | — |
| └close | string | — |
| └volume | string | Traded value (turnover) for the bar — per proto this is 成交额, not share count. |
| └timestamp | int64 | Unix seconds. |
POST https://api.alphio.ai/v1/openapi/data/kline
{
"tickers":[ { "asset_type":0, "ticker":"TSLA", "locale":"US" } ],
"from":"2026-06-09", "to":"2026-07-09",
"multiplier":1, "timespan":4, "limit":30
}{
"ret": 0,
"msg": "ok",
"data": {
"series": [
{
"ticker": "TSLA",
"asset_type": 0,
"points": [
{"open":"391.09","high":"396.14","low":"388.42","close":"394.26",
"volume":"58231290","timestamp":"1783486800"}
]
}
]
}
}Historical OHLC bars backing the price-prediction card — no forecast fields in the payload itself. Request is a discriminated union by ticker_type; response has matching stock_data / crypto_data.
| Field | Type | Required | Description |
|---|---|---|---|
| ticker_type | string | yes | "stock" / "etf" / "" → stock branch; "crypto" → crypto branch. |
| stock | DataPricePredictionStockReq | no | Required when ticker_type is stock / etf / empty. |
| └code | string | no | Ticker, e.g. "AAPL". |
| └multiplier | int32 | no | Time multiplier. |
| └timespan | int32 | no | TimespanOpt. 2=minute, 3=hour, 4=day, 5=week, 6=month, 7=quarter, 8=year. |
| └timestamp | int64 | no | Anchor end-time (unix seconds). Empty = now. |
| └count | int32 | no | Bars to return. Max 5000, recommended 800. |
| └locale | string | no | "US" / "HK". |
| crypto | DataPricePredictionCryptoReq | no | Required when ticker_type = "crypto". |
| └type | int32 | no | QueryType. 1=crypto spot, 2=etf, 3=crypto derivative (HL perps). |
| └symbol | string | no | — |
| └multiplier | int32 | no | — |
| └timespan | int32 | no | TimespanOpt. 2=minute, 3=hour, 4=day, 5=week, 6=month, 7=quarter, 8=year. |
| └limit | int32 | no | — |
| └start_time | int64 | no | Unix seconds. |
| └end_time | int64 | no | Unix seconds. |
| └symbol_list | string[] | no | Batch query — per-symbol series come back in crypto_data.infos. |
| └locale | string | no | Source platform for multi-source assets, e.g. "HYPERLIQUID". Empty = default source. |
| Field | Type | Description |
|---|---|---|
| ret | int32 | Business return code. 0 = success, non-zero = error code (see Errors). |
| msg | string | Human-readable status / error message. "ok" on success. |
| data | DataPricePredictionData | Response payload. |
| └ticker_type | string | Echoed back. |
| └stock_data | DataPricePredictionStockData | Present on the stock branch. |
| └points | DataPricePredictionStockPoint[] | Historical bars, oldest first. |
| └code | string | — |
| └close | double | — |
| └high | double | — |
| └low | double | — |
| └transactions | int64 | Share volume (per proto: 交易量). |
| └open | double | — |
| └timestamp | int64 | Unix seconds. |
| └volume | double | Traded value / turnover (per proto: 成交额), not share count. |
| └vwap | double | Volume-weighted average price. |
| └otc | bool | — |
| └pre_close | double | Previous-period values (pre_* mirror the base fields). |
| └pre_high | double | — |
| └pre_low | double | — |
| └pre_transactions | int64 | — |
| └pre_open | double | — |
| └pre_timestamp | int64 | — |
| └pre_volume | double | — |
| └pre_vwap | double | — |
| └symbol | string | — |
| └last_time | int64 | Unix seconds. |
| └crypto_data | DataPricePredictionCryptoData | Present on the crypto branch. |
| └points | DataPricePredictionCryptoPoint[] | Bars for the primary symbol. |
| └high | double | — |
| └open | double | — |
| └low | double | — |
| └close | double | — |
| └timestamp | int64 | Unix seconds. |
| └volume | int64 | Legacy integer volume — kept for old clients only. |
| └volume_decimal | double | Preferred: float volume (needed for fractional assets like HL perps). |
| └infos | map<string, DataPricePredictionCryptoSeries> | Per-symbol series when symbol_list was provided. |
POST https://api.alphio.ai/v1/openapi/data/price-prediction
{
"ticker_type":"stock",
"stock":{ "code":"AAPL", "multiplier":1, "timespan":4, "count":800, "locale":"US" }
}{
"ret": 0,
"msg": "ok",
"data": {
"ticker_type": "stock",
"stock_data": {
"points": [
{"code":"AAPL","close":195.5,"open":194.2,"high":196.1,"low":193.8,
"timestamp":1717286400,"volume":48230000.0,"vwap":195.1,"otc":false}
],
"last_time": 1717286400
}
}
}Stock screener. Request / response follow the upstream datafabric schema (chatfinbot.datafabric.v1.SelectStocksReq / SelectStocksRsp). Contact us for the full schema, or reuse a screenId returned by a Chat card.
ETF screener. Uses chatfinbot.datafabric.v1.SelectEtfsReq / SelectEtfsRsp upstream.
Crypto screener. Uses chatfinbot.datafabric.v1.SelectCryptosReq / SelectCryptosRsp upstream.