webull-openapi
Trade stocks, options, futures, crypto, and event contracts on Webull. Query real-time and historical market data. Manage accounts and positions. Supports US and HK regions with configurable risk controls.
Best use case
webull-openapi is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Trade stocks, options, futures, crypto, and event contracts on Webull. Query real-time and historical market data. Manage accounts and positions. Supports US and HK regions with configurable risk controls.
Teams using webull-openapi should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/webull_openapi_skills/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How webull-openapi Compares
| Feature / Agent | webull-openapi | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Trade stocks, options, futures, crypto, and event contracts on Webull. Query real-time and historical market data. Manage accounts and positions. Supports US and HK regions with configurable risk controls.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Webull OpenAPI Skill
This skill lets you interact with Webull's trading platform through natural language. You can place orders, check market data, query account info, and manage positions — all via the official Webull Python SDK.
## What You Can Do
- **Trade**: Place, preview, modify, and cancel orders for stocks, options, futures, crypto, and event contracts
- **Market Data**: Get real-time snapshots, historical bars, tick data, quotes, and order flow for all asset classes
- **Accounts**: List accounts, check balances, view positions
- **Instruments**: Look up stock, crypto, futures, and event contract instruments
## Safety Rules
**All order-mutating operations require user confirmation before execution.**
Mutating actions: `place`, `replace`, `cancel`, `batch-place`, `algo-place`, `option-place`, `option-replace`, `option-strategy-place`, `futures-place`, `futures-replace`, `crypto-place`, `event-place`, `event-replace`.
Before executing any of these operations, the AI must:
1. Display a clear summary of the operation to the user, including:
- Action type (place / replace / cancel)
- Symbol, side, order type, quantity, price
- Account being used
2. Explicitly ask the user to confirm (e.g., "Confirm this order? [Yes/No]")
3. Only proceed after receiving explicit user approval
Read-only operations (`account-list`, `balance`, `position`, `open`, `history`, `detail`, `instrument-*`, all `market-data` actions) do not require confirmation and can be executed immediately.
---
## Quick Examples
> **Python command:** Use `python3` on macOS/Linux, `python` on Windows. Examples below use `python3`.
> **Passing order JSON:** Prefer `--order-file <path>` (write JSON to a temp file first) over `--order-json '<inline>'`. Inline JSON with `--order-json` is fragile across shells — Windows bash, PowerShell, and some macOS terminals mangle quotes and escapes. Using `--order-file` avoids all shell quoting issues.
```bash
# Check your accounts
python3 scripts/cli.py trading --action account-list
# Get AAPL stock price
python3 scripts/cli.py market-data --action stock-snapshot --symbols AAPL
# Get account balance
python3 scripts/cli.py trading --action balance --account-id <id>
# Place a limit buy order (recommended: use --order-file)
# First write JSON to a file, then pass it:
# echo '{"symbol":"AAPL","side":"BUY","order_type":"LIMIT","limit_price":180,"quantity":10,"instrument_type":"EQUITY","market":"US","time_in_force":"DAY","entrust_type":"QTY","support_trading_session":"CORE","combo_type":"NORMAL"}' > /tmp/order.json
# python3 scripts/cli.py trading --action place --account-id <id> --order-file /tmp/order.json
#
# Alternative (inline, may fail on some shells):
python3 scripts/cli.py trading --action place --account-id <id> \
--order-json '{"symbol":"AAPL","side":"BUY","order_type":"LIMIT","limit_price":180,"quantity":10,"instrument_type":"EQUITY","market":"US","time_in_force":"DAY","entrust_type":"QTY","support_trading_session":"CORE","combo_type":"NORMAL"}'
# Cancel an order
python3 scripts/cli.py trading --action cancel --account-id <id> --client-order-id <oid>
```
## CLI Entry Point
```
python3 scripts/cli.py [--env-file PATH] [--verbose-sdk-log] <module> --action <ACTION> [options]
```
Three modules: `trading`, `market-data`, `auth`.
---
## Module: trading
Instrument queries, account/asset operations, and all order operations.
### Instrument Queries
| Action | Description | Key Options |
|--------|-------------|-------------|
| `instrument-stock` | Stock/ETF instrument info | `--symbols AAPL,TSLA` |
| `instrument-crypto` | Crypto instrument info | `--symbols BTCUSD` |
| `instrument-futures-products` | Futures product codes | `--category US_FUTURES` |
| `instrument-futures-list` | Futures instruments by symbol | `--symbols ESM6` |
| `instrument-futures-by-code` | Futures by product code | `--code ES` |
| `instrument-event-series` | Event contract series | `--page-size 50` |
| `instrument-event-list` | Event instruments by series | `--series-symbol <sym>` |
| `instrument-event-categories` | Event contract categories | |
| `instrument-event-events` | Events within a series | `--series-symbol <sym>` |
### Account & Asset
| Action | Description | Key Options |
|--------|-------------|-------------|
| `account-list` | List all linked accounts | |
| `balance` | Account balance | `--account-id <id>` |
| `position` | Account positions | `--account-id <id>` |
### Stock Orders
| Action | Description |
|--------|-------------|
| `place` | Place stock order (single, non-combo) |
| `preview` | Preview order without submitting |
| `replace` | Modify existing stock order |
| `batch-place` | Combo orders (OTO/OCO/OTOCO) — US only |
| `algo-place` | Algorithmic order (TWAP/VWAP/POV) — US only |
### Option Orders
| Action | Description |
|--------|-------------|
| `option-place` | Place single-leg option order |
| `option-preview` | Preview option order |
| `option-replace` | Modify option order |
| `option-strategy-place` | Multi-leg strategy (VERTICAL, STRADDLE, etc.) — US only |
### Futures / Crypto / Event Orders (US only)
| Action | Description |
|--------|-------------|
| `futures-place` | Place futures order |
| `futures-replace` | Modify futures order |
| `crypto-place` | Place crypto order (no replace supported) |
| `event-place` | Place event contract order |
| `event-replace` | Modify event contract order |
### Order Management
| Action | Description | Key Options |
|--------|-------------|-------------|
| `cancel` | Cancel an order | `--account-id`, `--client-order-id` |
| `open` | List open/pending orders | `--account-id` |
| `history` | Order history | `--account-id` |
| `detail` | Single order detail | `--account-id`, `--client-order-id` |
| `local-check` | Risk check only (no API call) | `--order-json` |
---
### Order JSON Format
Orders are passed via `--order-json` (inline string) or `--order-file` (path to a JSON file). **`--order-file` is strongly recommended** to avoid shell quoting issues.
> **Important:** The `place` and `replace` actions accept **different** JSON fields. Do NOT use `place` fields for `replace` — the CLI spreads JSON keys directly into the function, so unexpected fields cause errors.
> **`client_order_id` / `client_combo_order_id` rules:** Max 32 characters, must be alphanumeric only (letters and digits, no hyphens/underscores/special chars), and must be unique per account. If not provided, the system auto-generates one.
---
#### Place Order JSON (for `place`, `preview`)
> **Type note:** Stock place CLI does `float()` conversion internally, so strings technically work — but for consistency and to avoid issues, always use **number** types for numeric fields.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `combo_type` | Yes | string | `NORMAL` (single order). For combo: `MASTER`, `STOP_PROFIT`, `STOP_LOSS`, `OTO`, `OCO`, `OTOCO` |
| `symbol` | Yes | string | Ticker symbol, e.g. `AAPL`, `00700`, `BTCUSD`, `ESZ5` |
| `instrument_type` | Yes | string | `EQUITY`, `OPTION`, `FUTURES`, `CRYPTO`, `EVENT` |
| `market` | Yes | string | `US`, `HK`, `CN` |
| `side` | Yes | string | `BUY`, `SELL`, `SHORT` |
| `order_type` | Yes | string | See [Order Types by Market](#order-types-by-market) below |
| `time_in_force` | Yes | string | See [Time in Force](#time-in-force) below |
| `quantity` | Conditional | number (float) | Number of shares/contracts. Required when `entrust_type=QTY`. e.g. `10` — NOT `"10"` |
| `entrust_type` | Yes | string | `QTY` (by quantity) or `AMOUNT` (fractional shares / crypto by dollar amount) |
| `limit_price` | Conditional | number (float) | Required for `LIMIT`, `STOP_LOSS_LIMIT` orders, e.g. `180` — NOT `"180"` |
| `stop_price` | Conditional | number (float) | Required for `STOP_LOSS`, `STOP_LOSS_LIMIT` orders |
| `support_trading_session` | US stocks | string | `CORE` (regular hours), `ALL` (extended hours), `NIGHT` (night session) |
| `total_cash_amount` | Conditional | number (float) | Required when `entrust_type=AMOUNT` (US fractional shares / crypto) |
| `trailing_type` | Conditional | string | Required for `TRAILING_STOP_LOSS`: `AMOUNT` or `PERCENTAGE` |
| `trailing_stop_step` | Conditional | number (float) | Required for `TRAILING_STOP_LOSS`: trail amount or percentage (0.01 = 1%) |
| `sender_sub_id` | No (HK broker) | string | Broker user UUID for third-party transactions (HK region, institutional only) |
| `no_party_ids` | No (HK broker) | array | BCAN party identifiers for HK stock orders (institutional only). See below |
> **`quantity` vs `total_cash_amount`:** These two fields are mutually exclusive.
> - When `entrust_type=QTY`: provide `quantity` (number of shares/contracts)
> - When `entrust_type=AMOUNT`: provide `total_cash_amount` (dollar amount for fractional shares / crypto)
> - Do NOT provide both at the same time.
Stock limit buy example:
```json
{
"symbol": "AAPL",
"side": "BUY",
"order_type": "LIMIT",
"limit_price": 180,
"quantity": 10,
"instrument_type": "EQUITY",
"market": "US",
"time_in_force": "DAY",
"entrust_type": "QTY",
"support_trading_session": "CORE",
"combo_type": "NORMAL"
}
```
HK stock order example (with BCAN, institutional/broker only):
```json
{
"symbol": "00700",
"side": "BUY",
"order_type": "ENHANCED_LIMIT",
"limit_price": 350,
"quantity": 100,
"instrument_type": "EQUITY",
"market": "HK",
"time_in_force": "DAY",
"entrust_type": "QTY",
"combo_type": "NORMAL",
"sender_sub_id": "<broker_user_uuid>",
"no_party_ids": [
{
"party_id": "ABC123.2568",
"party_id_source": "D",
"party_role": "3"
}
]
}
```
`no_party_ids` array item fields:
| Field | Required | Description |
|-------|----------|-------------|
| `party_id` | Yes | BCAN ID, format: `CE_NUMBER.BCAN` e.g. `ABC123.2568` |
| `party_id_source` | Yes | Always `"D"` (Proprietary/Custom Code) |
| `party_role` | Yes | Always `"3"` (Client ID / BCAN Field) |
---
#### Option Place JSON (for `option-place`, `option-preview`)
> **⚠️ Type-sensitive:** Option place uses `**o` spread — JSON types must match function signatures exactly. `quantity` must be **integer**, `strike_price`/`limit_price`/`stop_price` must be **number** (float), not strings.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `symbol` | Yes | string | Underlying symbol, e.g. `AAPL` |
| `instrument_type` | Yes | string | `OPTION` |
| `option_type` | Yes | string | `CALL` or `PUT` |
| `strike_price` | Yes | number (float) | Strike price, e.g. `220.00` — NOT `"220.00"` |
| `expiration_date` | Yes | string | Expiration date, format `yyyy-MM-dd`, e.g. `"2026-06-19"` |
| `side` | Yes | string | `BUY`, `SELL`, `SHORT` |
| `order_type` | Yes | string | `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT` |
| `time_in_force` | Yes | string | `DAY`, `GTC`. Sell-side only supports `DAY` |
| `quantity` | Yes | number (int) | Number of contracts, e.g. `1` — NOT `"1"` |
| `limit_price` | Conditional | number (float) | Required for `LIMIT` orders, e.g. `11.25` — NOT `"11.25"` |
| `stop_price` | Conditional | number (float) | Required for `STOP_LOSS` orders |
| `position_intent` | No | string | Position strategy (US only). `BUY_TO_OPEN`, `BUY_TO_CLOSE`, `SELL_TO_OPEN`, `SELL_TO_CLOSE`. Must match `side` |
| `sender_sub_id` | No (HK broker) | string | Broker user UUID (HK region, institutional only). No BCAN needed for options |
Option single-leg example:
```json
{
"symbol": "AAPL",
"instrument_type": "OPTION",
"option_type": "CALL",
"strike_price": 220.00,
"expiration_date": "2026-06-19",
"side": "BUY",
"order_type": "LIMIT",
"limit_price": 11.25,
"quantity": 1,
"time_in_force": "DAY",
"position_intent": "BUY_TO_OPEN"
}
```
---
#### Option Strategy Place JSON (for `option-strategy-place`)
> **⚠️ Type-sensitive:** Same as option-place — numeric fields must be numbers, not strings.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `strategy` | Yes | string | `VERTICAL`, `STRADDLE`, `STRANGLE`, `BUTTERFLY`, `CONDOR`, `CALENDAR`, `DIAGONAL`, `IRON_BUTTERFLY`, `IRON_CONDOR`, `COLLAR_WITH_STOCK`, `COVERED_STOCK` |
| `symbol` | Yes | string | Underlying symbol |
| `order_type` | Yes | string | `LIMIT`, `MARKET` |
| `time_in_force` | Yes | string | `DAY`, `GTC` |
| `quantity` | No | number (int) | Number of contracts per leg |
| `limit_price` | Conditional | number (float) | Net debit/credit price for the strategy |
| `legs` | Yes | array | Array of leg objects (see below) |
Each leg object:
| Field | Required | JSON Type | Values |
|-------|----------|-----------|--------|
| `side` | Yes | string | `BUY`, `SELL` |
| `quantity` | Yes | string | Contracts for this leg |
| `symbol` | Yes | string | Underlying symbol |
| `strike_price` | Yes | string | Strike price |
| `option_expire_date` | Yes | string | `yyyy-MM-dd` |
| `instrument_type` | Yes | string | `OPTION` |
| `option_type` | Yes | string | `CALL` or `PUT` |
| `market` | Yes | string | `US` |
---
#### Futures Place JSON (for `futures-place`)
> **⚠️ Type-sensitive:** Futures place uses `**o` spread — `quantity`/`limit_price`/`stop_price` must be **number** (float), not strings.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `symbol` | Yes | string | Futures symbol, e.g. `ESZ5`, `NQM6` |
| `side` | Yes | string | `BUY`, `SELL` |
| `order_type` | Yes | string | `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TRAILING_STOP_LOSS` |
| `time_in_force` | Yes | string | `DAY`, `GTC` |
| `quantity` | Yes | number (float) | Number of contracts, e.g. `1` — NOT `"1"` |
| `limit_price` | Conditional | number (float) | Required for `LIMIT`, `STOP_LOSS_LIMIT` |
| `stop_price` | Conditional | number (float) | Required for `STOP_LOSS`, `STOP_LOSS_LIMIT` |
Futures example:
```json
{
"symbol": "ESZ5",
"side": "BUY",
"order_type": "LIMIT",
"limit_price": 4500,
"quantity": 1,
"time_in_force": "DAY"
}
```
---
#### Crypto Place JSON (for `crypto-place`)
> **⚠️ Type-sensitive:** Crypto place uses `**o` spread — `quantity`/`limit_price`/`stop_price`/`total_cash_amount` must be **number** (float), not strings.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `symbol` | Yes | string | e.g. `BTCUSD`, `ETHUSD` |
| `side` | Yes | string | `BUY`, `SELL` |
| `order_type` | Yes | string | `MARKET` (tif **must** be `IOC`), `LIMIT` (tif `DAY`/`GTC`), `STOP_LOSS_LIMIT` (tif `DAY`/`GTC`) |
| `time_in_force` | Yes | string | `IOC` (only for `MARKET`), `DAY` or `GTC` (for `LIMIT`/`STOP_LOSS_LIMIT`) |
| `entrust_type` | Yes | string | `QTY` or `AMOUNT` |
| `quantity` | Conditional | number (float) | Required when `entrust_type=QTY`. Supports up to 8 decimal places |
| `total_cash_amount` | Conditional | number (float) | Required when `entrust_type=AMOUNT` |
| `limit_price` | Conditional | number (float) | Required for `LIMIT`, `STOP_LOSS_LIMIT` |
| `stop_price` | Conditional | number (float) | Required for `STOP_LOSS_LIMIT` |
> Note: Crypto does NOT support replace (modify) orders. When selling, position must not fall below $2.
Crypto example:
```json
{
"symbol": "BTCUSD",
"side": "BUY",
"order_type": "LIMIT",
"limit_price": 80000,
"quantity": 0.003,
"time_in_force": "DAY",
"entrust_type": "QTY"
}
```
---
#### Event Contract Place JSON (for `event-place`)
> **⚠️ Type-sensitive:** Event place uses `**o` spread — `quantity` and `limit_price` must be **number** (float), not strings.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `symbol` | Yes | string | Event contract symbol |
| `side` | Yes | string | `BUY`, `SELL` |
| `quantity` | Yes | number (float) | Number of contracts. Accepts 0-2 decimal places |
| `limit_price` | Yes | number (float) | Limit price (LIMIT orders only) |
| `event_outcome` | Yes | string | `yes` or `no` |
| `order_type` | No | string | Default `LIMIT` (only LIMIT supported) |
| `time_in_force` | No | string | Default `DAY` (only DAY supported) |
Event contract example:
```json
{
"symbol": "KXRATECUTCOUNT-26DEC31-T3",
"side": "BUY",
"quantity": 5,
"limit_price": 0.10,
"event_outcome": "yes"
}
```
---
#### Algo Place JSON (for `algo-place`) — US only
> **⚠️ Type-sensitive:** Algo place uses `**o` spread — `quantity`/`limit_price` must be **number**, `target_vol_percent`/`max_target_percent` must be **integer**.
| Field | Required | JSON Type | Values / Description |
|-------|----------|-----------|----------------------|
| `symbol` | Yes | string | Stock symbol |
| `side` | Yes | string | `BUY`, `SELL` |
| `quantity` | Yes | number (float) | Number of shares |
| `algo_type` | Yes | string | `TWAP`, `VWAP`, `POV` |
| `order_type` | No | string | `MARKET` or `LIMIT` (default `LIMIT`) |
| `limit_price` | Conditional | number (float) | Required for `LIMIT` order type |
| `max_target_percent` | Conditional | number (int) | Required for `TWAP`/`VWAP`. Integer 1-20 |
| `target_vol_percent` | Conditional | number (int) | Required for `POV`. Integer 1-20 |
| `algo_start_time` | No | string | US Eastern Time, `HH:mm:ss` format, e.g. `"09:30:00"` |
| `algo_end_time` | No | string | US Eastern Time, `HH:mm:ss` format, e.g. `"16:00:00"` |
Algo TWAP example:
```json
{
"symbol": "AAPL",
"side": "BUY",
"quantity": 100,
"algo_type": "TWAP",
"order_type": "LIMIT",
"limit_price": 180,
"max_target_percent": 10,
"algo_start_time": "09:30:00",
"algo_end_time": "16:00:00"
}
```
---
### Replace (Modify) Order JSON
Replace actions use a **different, smaller** set of fields. Only include `client_order_id` plus the fields you want to change.
> **CRITICAL:** Do NOT include `symbol`, `side`, `instrument_type`, `market`, `entrust_type`, or `combo_type` in replace JSON — these cause `unexpected keyword argument` errors.
> **Note:** `client_order_id` MUST be in the JSON body. The `--client-order-id` CLI flag is NOT passed to replace functions.
#### Stock Replace (`replace`)
| Field | Required | JSON Type | Description |
|-------|----------|-----------|-------------|
| `client_order_id` | Yes | string | The order to modify |
| `quantity` | No | number (float) | New quantity |
| `limit_price` | No | number (float) | New limit price |
| `stop_price` | No | number (float) | New stop price |
| `time_in_force` | No | string | `DAY`, `GTC` |
| `order_type` | No | string | New order type |
| `trailing_type` | No | string | `AMOUNT` or `PERCENTAGE` |
| `trailing_stop_step` | No | number (float) | New trailing stop spread |
| `target_vol_percent` | No | number (int) | For algo orders (1-20) |
| `max_target_percent` | No | number (int) | For algo orders (1-20) |
| `algo_start_time` | No | string | For algo orders, `HH:mm:ss` |
| `algo_end_time` | No | string | For algo orders, `HH:mm:ss` |
Stock replace example — change quantity from 1 to 2:
```json
{
"client_order_id": "7af9c5c03a6f4e6ca46a194609f158e1",
"quantity": 2,
"limit_price": 258
}
```
Replace example using `--order-file` (recommended):
```bash
echo '{"client_order_id":"<oid>","quantity":2}' > /tmp/replace.json
python3 scripts/cli.py trading --action replace --account-id <id> --order-file /tmp/replace.json
```
#### Option Replace (`option-replace`)
> **⚠️ Type-sensitive:** Option replace requires `quantity` as **integer** (not string) and `limit_price`/`stop_price` as **number** (not string). Passing `"2"` instead of `2` will cause errors.
| Field | Required | JSON Type | Description |
|-------|----------|-----------|-------------|
| `client_order_id` | Yes | string | The order to modify |
| `quantity` | No | number (int) | New quantity — must be integer, NOT string |
| `limit_price` | No | number (float) | New limit price — must be number, NOT string |
| `stop_price` | No | number (float) | New stop price — must be number, NOT string |
| `time_in_force` | No | string | `DAY`, `GTC` |
Option replace example:
```json
{
"client_order_id": "abc123def456",
"quantity": 2,
"limit_price": 3.5
}
```
> Note: Option leg IDs are auto-fetched from order detail. No need to provide `legs` manually.
#### Futures Replace (`futures-replace`)
Futures modification rules (from official API docs):
- Market orders: only `quantity` can be modified
- Limit orders: `order_type` (can only change to `MARKET`), `time_in_force`, `quantity`, `limit_price`
- Stop orders: `order_type` (can only change to `MARKET`), `time_in_force`, `quantity`, `stop_price`
- Stop limit orders: `order_type` (can only change to `LIMIT`), `time_in_force`, `quantity`, `limit_price`, `stop_price`
- Trailing stop orders: only `trailing_stop_step` can be modified
| Field | Required | JSON Type | Description |
|-------|----------|-----------|-------------|
| `client_order_id` | Yes | string | The order to modify |
| `quantity` | No | number (float) | New quantity |
| `limit_price` | No | number (float) | New limit price |
| `order_type` | No | string | New order type (restricted, see rules above) |
Futures replace example:
```json
{
"client_order_id": "abc123def456",
"quantity": 2,
"limit_price": 4550
}
```
#### Event Replace (`event-replace`)
| Field | Required | JSON Type | Description |
|-------|----------|-----------|-------------|
| `client_order_id` | Yes | string | The order to modify |
| `quantity` | No | number (float) | New quantity |
| `limit_price` | No | number (float) | New limit price |
Event replace example:
```json
{
"client_order_id": "abc123def456",
"quantity": 10,
"limit_price": 0.15
}
```
#### Crypto Replace
**Not supported.** Cancel and re-place instead.
---
### Order Types by Market
| Market | Supported Order Types |
|--------|----------------------|
| US stocks/ETFs | `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TRAILING_STOP_LOSS` |
| US stocks (institutional) | Also: `MARKET_ON_OPEN`, `MARKET_ON_CLOSE`, `LIMIT_ON_OPEN` |
| US options | `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT` |
| US futures | `MARKET`, `LIMIT`, `STOP_LOSS`, `STOP_LOSS_LIMIT`, `TRAILING_STOP_LOSS` |
| US crypto | `MARKET`, `LIMIT`, `STOP_LOSS_LIMIT` |
| US event contracts | `LIMIT` only |
| HK stocks | `ENHANCED_LIMIT`, `AT_AUCTION`, `AT_AUCTION_LIMIT` |
| CN A-shares (via HK) | `LIMIT` only |
### Time in Force
| Value | Description | Supported By |
|-------|-------------|--------------|
| `DAY` | Valid for current trading day only | All instruments |
| `GTC` | Good-Till-Canceled (up to 60 days) | US stocks, options, futures, crypto |
| `IOC` | Immediate-Or-Cancel (unfilled portion canceled) | Crypto `MARKET` orders only |
### Trading Sessions (US stocks only)
| Value | Description |
|-------|-------------|
| `CORE` | Regular hours (9:30 AM - 4:00 PM ET) |
| `ALL` | Extended hours (pre-market + after-hours) |
| `NIGHT` | Night session only |
### Combo Types (US stocks only)
| Value | Description |
|-------|-------------|
| `NORMAL` | Standard single order |
| `MASTER` | Simple order + take profit or stop loss |
| `STOP_PROFIT` | Take profit order (child of MASTER) |
| `STOP_LOSS` | Stop loss order (child of MASTER) |
| `OTO` | One Triggers Other |
| `OCO` | One Cancels Other |
| `OTOCO` | One Triggers a One Cancels Other |
### Option Strategies (US only)
`SINGLE`, `COVERED_STOCK`, `VERTICAL`, `STRADDLE`, `STRANGLE`, `CALENDAR`, `DIAGONAL`, `BUTTERFLY`, `CONDOR`, `COLLAR_WITH_STOCK`, `IRON_BUTTERFLY`, `IRON_CONDOR`
### Algo Types (US only)
| Type | Description | Required Param |
|------|-------------|----------------|
| `TWAP` | Time Weighted Average Price | `max_target_percent` (1-20) |
| `VWAP` | Volume Weighted Average Price | `max_target_percent` (1-20) |
| `POV` | Percentage of Volume | `target_vol_percent` (1-20) |
---
## Module: market-data
Real-time and historical market data for all asset classes.
### Stock
| Action | Description | Key Options |
|--------|-------------|-------------|
| `stock-snapshot` | Real-time snapshot | `--symbols AAPL,TSLA` |
| `stock-bars` | OHLCV bars (single symbol) | `--symbol AAPL --timespan D --count 200` |
| `stock-batch-bars` | OHLCV bars (multiple symbols) | `--symbols AAPL,TSLA --timespan D` |
| `stock-tick` | Tick-by-tick trades | `--symbol AAPL --count 30` |
| `stock-quotes` | Bid/ask depth | `--symbol AAPL --depth 5` |
| `stock-footprint` | Large order flow | `--symbols AAPL --timespan M1` |
### Futures (US only)
| Action | Description | Key Options |
|--------|-------------|-------------|
| `futures-snapshot` | Futures snapshot | `--symbols ESM6` |
| `futures-bars` | Futures OHLCV | `--symbols ESM6 --timespan D` |
| `futures-tick` | Futures ticks | `--symbol ESM6 --count 30` |
| `futures-depth` | Order book depth | `--symbol ESM6 --depth 5` |
| `futures-footprint` | Futures order flow | `--symbols ESM6 --timespan M1` |
### Crypto (US only)
| Action | Description | Key Options |
|--------|-------------|-------------|
| `crypto-snapshot` | Crypto snapshot | `--symbols BTCUSD` |
| `crypto-bars` | Crypto OHLCV | `--symbols BTCUSD --timespan D` |
### Event Contracts (US only)
| Action | Description | Key Options |
|--------|-------------|-------------|
| `event-snapshot` | Event snapshot | `--symbols <sym>` |
| `event-depth` | Event depth | `--symbol <sym> --depth 5` |
| `event-bars` | Event OHLCV | `--symbols <sym> --timespan D` |
| `event-tick` | Event ticks | `--symbol <sym> --count 30` |
### Common Options
| Option | Default | Description |
|--------|---------|-------------|
| `--category` | auto | See [Category Values](#category-values) below |
| `--timespan` | `D` | `M1`, `M5`, `M15`, `M30`, `H1`, `H4`, `D`, `W` |
| `--count` | `200` | Number of bars/ticks |
| `--depth` | `1` | Order book depth levels |
| `--extend-hour-required` | false | Include extended hours |
| `--overnight-required` | false | Include overnight data |
### Category Values
Category determines which market's data you're querying. It varies by region:
**US Region (`WEBULL_REGION_ID=us`):**
| Category | Description |
|----------|-------------|
| `US_STOCK` | US stocks (default for stock actions) |
| `US_ETF` | US ETFs |
| `US_FUTURES` | US futures (default for futures actions) |
| `US_CRYPTO` | US crypto (default for crypto actions) |
| `US_EVENT` | US event contracts (default for event actions) |
**HK Region (`WEBULL_REGION_ID=hk`):**
| Category | Description |
|----------|-------------|
| `US_STOCK` | US stocks (traded via HK account) |
| `US_ETF` | US ETFs (traded via HK account) |
| `HK_STOCK` | Hong Kong stocks |
| `CN_STOCK` | China Connect A-shares |
Examples:
```bash
# US stock (default for US region)
python3 scripts/cli.py market-data --action stock-snapshot --symbols AAPL
# HK stock (must specify category for HK region)
python3 scripts/cli.py market-data --action stock-snapshot --symbols 00700 --category HK_STOCK
# China Connect A-share
python3 scripts/cli.py market-data --action stock-snapshot --symbols 600519 --category CN_STOCK
```
---
## Module: auth
```bash
python3 scripts/cli.py auth
```
Interactive 2FA authentication. Run once before first use. The SDK waits up to 5 minutes for you to approve in the Webull mobile app. Token is cached and auto-refreshes.
---
## Output Format
All operations output formatted text directly to stdout, with a region-aware disclaimer at the top:
```
⚠️ Disclaimer: The information provided by this tool is for reference only ...
=== Stock Snapshot: AAPL ===
Symbol: AAPL
Price: 255.92
Pre Close: 255.63
Change: 0.29
...
```
- Success: disclaimer + formatted data to stdout, exit code 0
- Error: error message to stderr, exit code 1
- US region: English disclaimer only
- HK region: English + Simplified Chinese + Traditional Chinese disclaimer
---
## Configuration
Via `.env` file or environment variables. Required:
```
WEBULL_APP_KEY=<your_app_key>
WEBULL_APP_SECRET=<your_app_secret>
```
**`.env` lookup order** (when `--env-file` is not specified):
1. `$WEBULL_CONFIG_DIR/.env` — if `WEBULL_CONFIG_DIR` is set
2. `<project_root>/.env` — default (sibling of `webull_openapi_skills/`)
3. Current working directory `.env` — last resort
> To keep credentials outside the project directory, set `WEBULL_CONFIG_DIR` as a **system environment variable** (e.g. in `~/.zshrc`), then place your `.env` at `$WEBULL_CONFIG_DIR/.env`. Setting `WEBULL_CONFIG_DIR` inside a `.env` file has no effect — it must be set before the process starts.
Optional:
| Variable | Default | Description |
|----------|---------|-------------|
| `WEBULL_ENVIRONMENT` | `uat` | `uat` (sandbox) or `prod` (live) |
| `WEBULL_REGION_ID` | `us` | `us` or `hk` |
| `WEBULL_MAX_ORDER_NOTIONAL_USD` | `10000` | Max order value (USD) |
| `WEBULL_MAX_ORDER_QUANTITY` | `1000` | Max shares per order |
| `WEBULL_SYMBOL_WHITELIST` | (none) | Comma-separated allowed symbols |
| `WEBULL_CONFIG_DIR` | (none) | **System env var only** (not in `.env`). Moves `.env` lookup and token storage to this directory |
| `WEBULL_TOKEN_DIR` | `<project_root>/conf/` | Token storage directory |
| `WEBULL_AUDIT_LOG_FILE` | (stderr) | Audit log file path |
| `WEBULL_LOG_LEVEL` | `WARNING` | SDK log level |
---
## Region Support
| Feature | US | HK |
|---------|:--:|:--:|
| Stock trading | ✓ | ✓ (US/HK/CN) |
| Options | ✓ | ✓ (US only) |
| Futures | ✓ | ✗ |
| Crypto | ✓ | ✗ |
| Event contracts | ✓ | ✗ |
| Combo orders | ✓ | ✗ |
| Algo orders | ✓ | ✗ |
| Trailing stop loss | ✓ | ✗ |
| Fractional shares | ✓ (US market) | ✗ |
### HK-Specific Notes
- HK stocks use order types: `ENHANCED_LIMIT`, `AT_AUCTION`, `AT_AUCTION_LIMIT`
- CN A-shares (Stock Connect): `LIMIT` only, disabled by default — contact Webull to enable
- Board lot sizes vary by HK stock
- No combo orders, algo orders, futures, crypto, or event contracts in HK region
- HK stock orders (institutional/broker): require `sender_sub_id` and `no_party_ids` (BCAN)
- HK US options (institutional/broker): support `sender_sub_id` only, no BCAN needed
---
## Rate Limits
### US Region
- Market data: 600 req/min
- Order place/replace/cancel: 600 req/min
- Order query: 2 req/2s
- Auth: 10 req/30s
### HK Region
- Market data: 60 req/60s
- Order place: 15 req/s (US stocks), 1 req/s (HK/A-share)
- Order preview: 40 req/10s
- Order query: 40 req/2s
---
## Official API Documentation
- US: https://developer.webull.com/apis/docs/webull-open-api-reference
- HK: https://developer.webull.hk/apis/docs
---
## Disclaimer
The information provided by this tool is for reference only and does not constitute investment advice. Trading involves risk; please make decisions carefully.