Skip to content
OpenSmartRoute
Skillv1.0.0

tqx

TQX (tqx.trade) HK/US stock quant: factor analysis, strategy backtests, and agent-driven trading (paper or live) via the TQX CLIs. Use when the user wants to run factor IC/IR analysis, backtest a Pyth

by starchild-ai-agent(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from starchild-ai-agent/official-skills (tqx/SKILL.md). Install upstream with npx skills add starchild-ai-agent/official-skills --skill tqx. Copyright stays with the author.

TQX Quant — Factor Analysis & Strategy Backtest

TQX (https://www.tqx.trade) is a HK/US stock quant platform. This skill drives it through the official tqx-cli pip package.

Official TQX skills (source of truth — read these first)

TQX publishes two official skills. Fetch the raw URLs directly (the repo UI is a JS SPA; only /-/git/raw/ URLs return content):

1. tqx-research — factor analysis, strategy backtest, workflow management (Python tqx-cli, email/password login):

  • Main: https://cnb.cool/liangyunzhijing/clis/-/git/raw/main/skills/tqx-research/SKILL.md
  • References (read before generating code — do NOT guess APIs):
    • commands: .../skills/tqx-research/references/commands.md
    • strategy templates: .../skills/tqx-research/references/strategy_templates.md
    • US API: .../skills/tqx-research/references/stock_us_api.md
    • HK API: .../skills/tqx-research/references/stock_hk_api.md
    • tqx_data: .../skills/tqx-research/references/tqx_data_usage.md (replace ... with https://cnb.cool/liangyunzhijing/clis/-/git/raw/main)

2. tqx-trading — account/positions/orders/trades queries + authorized order placement (TypeScript @tqx-ai/cli@0.1.3, API-key auth, pin the version):

  • Main: https://cnb.cool/liangyunzhijing/clis/-/git/raw/main/skills/tqx-trading/SKILL.md
  • OpenAPI: https://www.tqx.trade/openapi/v1/openapi.json (interactive: /openapi/v1/scalar)

Routing rule: research/backtest/factor work → tqx-research (tqx-cli, Python). Live account state & order execution → tqx-trading (tqx, TS CLI). They use DIFFERENT CLIs and DIFFERENT auth (email login vs TQX_API_KEY) — don't mix them. This skill below adds what the official docs don't cover: verified onboarding, failure-mode table, and agent-automation patterns.

User onboarding (first-time setup, ~3 minutes)

  1. Register at https://www.tqx.trade (email signup). A PAPER (simulation) account is provisioned automatically — all workflows below are safe to run on it. Paper and live are the SAME API: tqx trading account reports "mode": "PAPER" or "mode": "LIVE", and every command (positions, orders place|modify|cancel, trades) is identical on both. Switching to real money is an account-level change on TQX, not a different code path — which is exactly why order-size caps and the human-approval rule below matter.

    Trading competition: TQX runs an agent trading competition — entry and rules at https://luma.com/dawwrdxk?tk=adzfZA. Competition accounts are created from the same dashboard (https://www.tqx.trade/hk/competition-manage?catalog=2), which is also where the TQX_API_KEY for the trading CLI is issued.

  2. Collect credentials securely: agents must use request_env_input for TQX_EMAIL and TQX_PASSWORD — never ask for credentials in chat.

  3. Install + login + verify:

pip install tqx-cli
tqx-cli login --email "$TQX_EMAIL" --password "$TQX_PASSWORD"
tqx-cli --json balance        # non-error response = onboarding complete

Token is cached in ~/.tqx/config.yaml.

  1. First quick win (recommended demo): run the "5d momentum" factor analysis from §1 below — completes in ~1–2 min and produces IC/IR/Sharpe numbers you can show immediately.

⚠️ Token expiry gotcha: both accessToken AND refresh_token can expire together. Do NOT only match one specific error string — re-login on ANY response containing LOGIN_REQUIRED, 均已失效, or Please log in to continue. A strict matcher silently fails and every later call returns auth errors.

CLI command map

factor_create / factor_run / factor_result / factor_list / factor_delete
strategy_create / strategy_run / strategy_result / strategy_list / strategy_delete
backtest_result   # per-backtest detail: summary/account/position/profit/trade/log sections
workflow_list / workflow_stop / balance

Add --json for machine-readable output.

1. Factor analysis (cross-sectional IC/IR)

tqx-cli --json factor_create --market us --name "5d momentum" \
  --formula "close/ref(close,5)-1" \
  --start-date 20250101 --end-date 20250701 --group-number 2
tqx-cli --json factor_run <factor_id>          # waits and returns results

Result parsing gotcha: the result JSON has TWO formats depending on backend version — legacy nodes[].result_json and current root-level factor_analysis. Handle both. Key metrics: IC mean, IR, t-stat, annualized group returns, Sharpe.

2. Strategy backtest (panda_backtest engine)

tqx-cli --json strategy_create --market us --name "AAPL SMA cross" \
  --code "$(cat strategy.py)" \
  --start-date 20250101 --end-date 20250701 \
  --start-capital 1000000 --commission-rate 0.0003 --slippage 0.001 --frequency 1d
tqx-cli --json strategy_run <strategy_id>

Strategy code contract

from panda_backtest.api.api import *            # common trading API — MANDATORY
from panda_backtest.api.stock_us_api import *   # US market data API — MANDATORY
# HK market: from panda_backtest.api.stock_hk_api import *
import tqx_data

def initialize(context):
    # Account ID is per-user — discover it once, do NOT hardcode.
    # The '8888' from CN-market docs does NOT exist for HK/US backtests.
    context.account = list(context.stock_account_dict.keys())[0]
    context.symbol = 'AAPL.NB'   # symbol format: US = TICKER.NB (NOT .US!), HK = 00700.HK
    context.closes = []

def handle_data(context, data):
    account = context.stock_account_dict.get(context.account)
    if account is None:
        return
    bar = data.get(context.symbol)
    # bar CAN be None — with a WRONG suffix it is None EVERY day (silent 0-trade run)
    if bar is None or getattr(bar, 'close', None) is None or float(bar.close) <= 0:
        return
    price = float(bar.close)
    context.closes.append(price)
    if len(context.closes) < 20:
        return
    fast = sum(context.closes[-5:]) / 5
    slow = sum(context.closes[-20:]) / 20
    position = account.positions.get(context.symbol)
    quantity = 0 if position is None else position.quantity
    sellable = 0 if position is None else position.sellable
    if fast > slow and quantity == 0:
        buy_qty = int(account.cash * 0.9 // price)
        if buy_qty > 0:
            order_shares(context.account, context.symbol, buy_qty, style=MarketOrderStyle)
            print(f"BUY {buy_qty} @ {price:.2f}")   # print() = strategy log; SRLog is FORBIDDEN
    elif fast < slow and quantity > 0 and sellable > 0:
        order_shares(context.account, context.symbol, -sellable, style=MarketOrderStyle)
        print(f"SELL {sellable} @ {price:.2f}")

Reference run: this exact code on AAPL.NB, 20250101–20251231, produces 18 real fills (check with backtest_result <backtest_id> --section trade --all-pages).

Hard rules learned from real failures:

Symptom Root cause Fix
禁止使用危险函数 dir() Security filter blocks introspection Never use dir()/eval()/exec; to inspect context, raise Exception(str(...)) and read the error_detail in run logs
访问了不存在的键 on order Wrong account ID (e.g. '8888') Use list(context.stock_account_dict.keys())[0]
order_shares() missing 1 required positional argument Called with 2 args Signature is order_shares(account, symbol, quantity)
股票X不属于当前股票回测市场 Wrong symbol suffix US = TICKER.NB (NOT .US!), HK = XXXXX.HK; .O/.N/bare tickers are rejected
Backtest SUCCESS but 0 trades, 0 log lines, profit = 0.0 Symbol suffix .US (or any wrong suffix) → every bar returns None → defensive guard skips all days silently Use TICKER.NB for US stocks. ALWAYS verify via backtest_result <id> --section trade — SUCCESS ≠ trades executed
Run FAILED immediately (~0.3s, node failed) SRLog is not a valid API in strategy code Use plain print() for strategy logging (visible in --section log)
Run status FAILED but NO failed node (all nodes success/pending) Transient TQX queue/scheduler error, not your code Resubmit the same workflow once — typically succeeds in ~30s. Only debug strategy code if a node actually failed
Backtest SUCCESS but 0 trades, 标的不在当前回测数据集内 Date range beyond ingested market data (recent months may not be loaded even though the benchmark series exists) Shift the window earlier (e.g. use last year's range); verify trades>0 in the trade section before trusting metrics
frequency rejected Only 1d and 1M are valid

Reading results

strategy_run/strategy_result returns run status + node outputs. For full detail, extract the backtest id from run logs (BacktestNodeIdentifier: line) or node output, then:

tqx-cli --json backtest_result <backtest_id> --section summary   # profit, alpha, beta, sharpe, IR
tqx-cli --json backtest_result <backtest_id> --section trade     # ⚠️ always check trades executed
tqx-cli --json backtest_result <backtest_id> --section log       # per-order rejection reasons

A run can report SUCCESS with zero trades (orders silently rejected day by day). Always confirm the trade section is non-empty before reporting performance numbers.

Daily equity curve (--section profit)

The profit section is the day-by-day NAV series — one row per trading day with gmt_create (YYYYMMDD), strategy_profit (cumulative strategy return, decimal) and csi_stock (cumulative benchmark return, decimal).

# ⚠️ --all-pages does NOT work for the profit section: it silently returns only page 1 (100 rows).
tqx-cli --json backtest_result <backtest_id> --section profit --page-size 1000
# -> pagination {total: 252, page: 1, page_size: 1000, total_pages: 1}   ✅ full year in one call

Two more behaviours to handle (reference: AAPL.NB, full-year 2025 = 252 rows):

  • Rows come back unsorted — always sort by gmt_create ascending before plotting; do not assume the API order.
  • Values are decimals, not percent (-0.1174 = −11.74%) and are already cumulative, so plot them directly; don't compound them again.
  • The last row must match the summary section's total return — use that as your correctness check.

Cache the series locally (one file per run) instead of re-fetching: the call costs ~2–4 s and the data is immutable once the run is done.

Debugging failed runs

Error details are NOT in the top-level status — fetch run logs and read error_detail, which includes the exact strategy line number and exception message:

from tqx_cli.config import load_config
from tqx_cli.auth import require_login
from tqx_cli.workflow import get_run_logs
cfg = load_config(); token, uid, _ = require_login(cfg, cfg.get("_config_path"))
for l in get_run_logs(cfg, token, uid, run_id).get("logs") or []:
    if l.get("error_detail"): print(l["error_detail"])

Cost & pacing

Backtests are billed in TQX compute credits (tqx-cli balance). A 6-month daily-frequency single-stock backtest takes ~2 minutes wall time. Poll strategy_result every 3s; don't fire concurrent runs of the same workflow.

3. Templates (copy-paste starting points)

T1 — Momentum factor (cross-sectional, whole market)

tqx-cli --json factor_create --market us --name "5d momentum" \
  --formula "close/ref(close,5)-1" \
  --start-date 20250101 --end-date 20250701 --group-number 5

Other verified formulas: mean reversion -(close/ref(close,5)-1), volume surge volume/mean(volume,20). Factor mode is whole-market cross-sectional only (--market hk|us) — it CANNOT target one stock; for single-stock questions use a strategy backtest (T2).

T2 — Single-stock backtest (SMA cross on AAPL)

Use the strategy code contract in §2 verbatim — it IS the template. Change context.symbol and the signal logic only. Keep the None-bar guard and dynamic account discovery.

T3 — Agent-driven automated trading loop

Pattern verified over a 10-round live run (~21 min, end-to-end):

loop every N minutes:
  1. fetch live positions + account state
  2. compute signal (factor value or strategy rule)
  3. decide: buy / sell / hold  ← agent reasoning step
  4. place order (paper account, small fixed qty during development)
  5. journal the decision: {ts, reasoning, tool_calls, params, result, position_delta}

Hard rules for automation:

  • PAPER account by default. Live trading uses the identical command surface, so nothing in the code stops a live order — only your gating does. Require an explicit user approval before pointing the loop at a live account, keep a hard order-size cap, and always pass --idempotencyKey so a retry can never double-fill.
  • Journal every decision (JSONL is enough) — users must be able to audit why each trade happened.
  • Re-login on ANY auth-ish error string (see token gotcha above); a mid-loop token expiry must self-heal, not kill the loop.
  • Check compute balance before each backtest-class call to avoid silent overdraft.

T4 — Studio: ready-to-run companion UI (templates/studio/)

A complete, tested web workbench ships with this skill — do NOT build a dashboard from scratch. Copy templates/studio/ into the user's workspace, start it, and adapt.

Files:

File Role
server.py Stdlib HTTP backend (port 8090, no pip deps). Proxies tqx-cli, auto re-login on token expiry, serves all /api/* routes
index.html Single-file frontend: factor analysis, backtest submit/history, positions, agent decision timeline
agent.py Agent trading loop (LLM via proxied_post + tool calls), JSONL decision journal
backtests.py / strategies.py / journal.py Disk persistence modules (see data spec below)

UI language: the template ships English-only. Any Chinese you see at runtime comes from the TQX API itself (metric key names, error strings) — do not translate those, they are matched against.

Run: python3 server.py from the studio dir (background), then preview(action="serve") on it. Credentials come from TQX_EMAIL / TQX_PASSWORD env vars (collect via secure input — never hardcode).

Design spec (keep when restyling):

  • Minimalist quant-tech aesthetic: dark-first, monospace numerals, dense tables, no decorative graphics. Avoid bright or cyberpunk themes.
  • History rows must be loadable: clicking Load on any history record re-displays its full result in the top result area (factor runs → factor metrics/charts via loadBt; strategy runs → dedicated strategy-result card via loadStgBt: return vs benchmark, annualized, Sharpe, max drawdown, trade count, params + code link). A history table that only lists rows without load-back is incomplete.
  • UI exposes only high-frequency params (formula, market, date range, groups, rebalance, direction) + account switcher + NAV curve + decision timeline. Everything complex (custom strategy code, stock pools, commission/slippage) stays in the conversation layer — the agent has the full CLI surface, the UI must not duplicate it.
  • Amounts: format gold/cash values with a single dedicated formatter two competing formatters produce inconsistent output. Check dark-mode contrast on every card.

Persistence & paths (why the two directories):

tqx-cli writes its login config to /root/.tqx/config.yaml, which lives on the container's ephemeral layer and is wiped on every machine restart — the agent would silently lose its session. Only /data/workspace survives restarts, so the studio mirrors the config into /data/workspace/.tqx/ and syncs both ways on startup (sync_tqx_config() in server.py, _sync_tqx_config() in agent.py).

These paths are intentionally fixed, not a portability oversight: every agent has the identical layout — /data/workspace = persistent volume, /root = ephemeral. Keep the rule when extending the studio: anything that must survive a restart is written under the workspace, never under /root or /tmp. In-studio state (data/backtests, data/journal, data/strategies) is already __file__-relative, so it inherits persistence as long as the studio itself is copied into the workspace. If you ever run this outside a Starchild machine, override the persistent root — nothing else in the code assumes an absolute path.

Data storage spec:

  • data/backtests/index.json + one JSON per run — MUST persist the full strategy code string (not a truncated preview) so any run can be reloaded and re-edited.
  • data/journal/*.jsonl — one line per agent decision, tagged source: manual | agent, append-only, never rewritten.
  • data/strategies/ — named saved strategies. All state is plain JSON on disk; no DB.

Testing spec (before declaring the studio 'working'):

  1. curl localhost:8090/api/health (or any GET route) returns JSON — backend alive.
  2. Submit one REAL backtest through the UI and confirm it appears in the history panel with full code + metrics. A rendered page alone is NOT verification.
  3. Verify fills exist via backtest_result <id> --section trade — SUCCESS status with 0 trades means a symbol-suffix bug (see failure table).
  4. Kill/restart server.py and confirm history persists (disk, not memory).

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/starchild-ai-agent-official-skills-tqx/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

starchild-ai-agent-official-skills-tqx.ocm.jsonjson
{
  "ocm": "1",
  "id": "starchild-ai-agent-official-skills-tqx",
  "kind": "skill",
  "name": "tqx",
  "description": "TQX (tqx.trade) HK/US stock quant: factor analysis, strategy backtests, and agent-driven trading (paper or live) via the TQX CLIs. Use when the user wants to run factor IC/IR analysis, backtest a Python trading strategy on Hong Kong or US stocks, or set up agent-automated trading on a paper or live account (e.g. \"backtest a moving-average strategy on AAPL\", \"analyze a momentum factor on HK stocks\", \"let the agent trade my TQX account\", \"join the TQX trading competition\").",
  "publisher": "starchild-ai-agent",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding",
      "finance"
    ],
    "tags": [
      "skill-md",
      "quant",
      "backtest",
      "factor-analysis",
      "stocks",
      "tqx",
      "trading",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "TQX (tqx.trade) HK/US stock quant: factor analysis, strategy backtests, and agent-driven trading (paper or live) via the TQX CLIs. Use when the user wants to run factor IC/IR analysis, backtest a Python trading strategy on Hong Kong or US stocks, or set up agent-automated trading on a paper or live account (e.g. \"backtest a moving-average strategy on AAPL\", \"analyze a momentum factor on HK stocks\", \"let the agent trade my TQX account\", \"join the TQX trading competition\")."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/starchild-ai-agent/official-skills",
      "path": "tqx/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/starchild-ai-agent/official-skills/blob/HEAD/tqx/SKILL.md",
      "key": "starchild-ai-agent/official-skills/tqx/SKILL.md"
    }
  },
  "instructions": "# TQX Quant — Factor Analysis & Strategy Backtest\n\nTQX (https://www.tqx.trade) is a HK/US stock quant platform. This skill drives it through the official `tqx-cli` pip package.\n\n## Official TQX skills (source of truth — read these first)\n\nTQX publishes two official skills. Fetch the raw URLs directly (the repo UI is a JS SPA; only `/-/git/raw/` URLs return content):\n\n**1. tqx-research** — factor analysis, strategy backtest, workflow management (Python `tqx-cli`, email/password login):\n- Main: `https://cnb.cool/liangyunzhijing/clis/-/git/raw/main/skills/tqx-research/SKILL.md`\n- References (read",
  "cost": {
    "context_tokens": 4276
  }
}

Fetch it by URL: GET /api/v1/registry/starchild-ai-agent-official-skills-tqx/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.