{"id":"6f5f39dc-b90b-4fee-9dfc-9cb8381a98d0","entityType":"agent","slug":"clawhub-turkeydick-gmquant","name":"掘金量化skill","canonicalUrl":"https://www.xpersona.co/agent/clawhub-turkeydick-gmquant","canonicalPath":"/agent/clawhub-turkeydick-gmquant","generatedAt":"2026-10-11T10:48:58.885Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T07:26:45.809Z","emptyReason":null},"description":"掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym... Skill: 掘金量化skill Owner: turkeydick Summary: 掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym... Tags: automation:1.0.2, finance:1.0.2, gm:1.0.2, joinquant:1.0.2, latest:1.0.3, quant:1.0.2, stock:1.0.2, trading:1.0.2, workbuddy:1.0.2 Version history: v1.0.3 | 2026-05-26T09:22:10.719Z | user gmquant v1.0.3 - Add","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s1720w1mawags81sjr872kwe1185smvf:gmquant","sourceUrl":"https://clawhub.ai/turkeydick/gmquant","homepage":"https://clawhub.ai/turkeydick/skills/gmquant","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/turkeydick/gmquant","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/turkeydick/skills/gmquant","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:26:45.809Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:26:45.809Z","emptyReason":null},"stars":null,"forks":null,"downloads":1124,"packageName":null,"latestVersion":"1.0.3","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T07:26:45.740Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T07:26:45.809Z","lastCrawledAt":"2026-10-11T07:26:45.740Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T07:26:45.740Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.3","createdAt":"2026-05-26T09:22:10.719Z","changelog":"gmquant v1.0.3 - Added premium API references for stocks, funds, convertible bonds, and futures in the documentation. - Introduced new user guide/reference files for enhanced coverage. - Added scripts to test all premium and new APIs. - Updated SKILL.md description and function list; expanded API coverage in documentation. - Removed the old user guide reference (`references/18-user-guide.md`).","fileCount":40,"zipByteSize":148742},{"version":"1.0.2","createdAt":"2026-04-29T10:13:30.666Z","changelog":"gmquant v1.0.2 - No file changes detected in this version. - No new features, fixes, or updates introduced.","fileCount":33,"zipByteSize":91104},{"version":"1.0.1","createdAt":"2026-04-29T08:26:10.221Z","changelog":"gm-quant v2.0.0 is a major update focused on natural language quantitative strategy generation: - Introduces a full natural language to code workflow: users describe strategy ideas in Chinese to generate ready-to-run Python strategy files. - Enforces user-supplied strategy_id for tracking and performance analysis in the MyQuant terminal; the system will prompt if absent. - Expanded skill triggers to recognize a wide range of QuantTrade-relevant commands and intent. - Provides a comprehensive strategy template with best practices (token setup, symbol format, modes, error handling, etc.). - Guides users step-by-step: intent clarification, code generation, and one-click backtest/execution instructions. - Strengthens prompts to ensure precise user requirements before code output; vague descriptions will trigger follow-up questions.","fileCount":33,"zipByteSize":86102}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s1720w1mawags81sjr872kwe1185smvf:gmquant","setupComplexity":"low","setupSteps":["Setup complexity is LOW. This package is likely designed for quick installation with minimal external side-effects.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T10:48:58.883Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-turkeydick-gmquant/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T07:26:45.809Z","emptyReason":null},"readme":"Skill: 掘金量化skill\n\nOwner: turkeydick\n\nSummary: 掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym...\n\nTags: automation:1.0.2, finance:1.0.2, gm:1.0.2, joinquant:1.0.2, latest:1.0.3, quant:1.0.2, stock:1.0.2, trading:1.0.2, workbuddy:1.0.2\n\nVersion history:\n\nv1.0.3 | 2026-05-26T09:22:10.719Z | user\n\ngmquant v1.0.3\n\n- Added premium API references for stocks, funds, convertible bonds, and futures in the documentation.\n- Introduced new user guide/reference files for enhanced coverage.\n- Added scripts to test all premium and new APIs.\n- Updated SKILL.md description and function list; expanded API coverage in documentation.\n- Removed the old user guide reference (`references/18-user-guide.md`).\n\nv1.0.2 | 2026-04-29T10:13:30.666Z | user\n\ngmquant v1.0.2\n\n- No file changes detected in this version.\n- No new features, fixes, or updates introduced.\n\nv1.0.1 | 2026-04-29T08:26:10.221Z | user\n\ngm-quant v2.0.0 is a major update focused on natural language quantitative strategy generation:\n\n- Introduces a full natural language to code workflow: users describe strategy ideas in Chinese to generate ready-to-run Python strategy files.\n- Enforces user-supplied strategy_id for tracking and performance analysis in the MyQuant terminal; the system will prompt if absent.\n- Expanded skill triggers to recognize a wide range of QuantTrade-relevant commands and intent.\n- Provides a comprehensive strategy template with best practices (token setup, symbol format, modes, error handling, etc.).\n- Guides users step-by-step: intent clarification, code generation, and one-click backtest/execution instructions.\n- Strengthens prompts to ensure precise user requirements before code output; vague descriptions will trigger follow-up questions.\n\nArchive index:\n\nArchive v1.0.3: 40 files, 148742 bytes\n\nFiles: README.md (6963b), references/01-quick-start.md (3240b), references/02-core-functions.md (3448b), references/03-subscribe-events.md (8188b), references/04-market-data.md (7246b), references/05-l2-data.md (2886b), references/06-symbol-info.md (4317b), references/07-trading-dates.md (1904b), references/08-order-api.md (4221b), references/09-algo-order.md (3172b), references/10-account-query.md (510b), references/11-bond-convertible.md (1725b), references/12-data-objects.md (3137b), references/13-enums.md (2189b), references/14-context.md (2489b), references/15-user-guide.md (18464b), references/16-premium-data-apis.md (8139b), references/17-financial-data-fields.md (7528b), references/18-stock-premium-apis.md (154126b), references/19-fund-premium-apis.md (42397b), references/20-cb-premium-apis.md (22782b), references/21-futures-premium-apis.md (31933b), scripts/check_import.py (2479b), scripts/run_strategy.py (4672b), scripts/strategy_etf_momentum_rotation.py (12635b), scripts/strategy_etf_momentum.py (11113b), scripts/strategy_etf_rotation.py (11611b), scripts/strategy_event_callbacks_test.py (20973b), scripts/strategy_high_dividend.py (14302b), scripts/strategy_ma_cross.py (4124b), scripts/strategy_xinyisheng_ma.py (4126b), scripts/test_account_apis.py (4653b), scripts/test_all_apis.py (8710b), scripts/test_all_premium_apis.py (15122b), scripts/test_financial_apis.py (8782b), scripts/test_new_apis.py (3617b), skill-card.md (2922b), SKILL.md (38483b), TEST_REPORT.md (9856b), _meta.json (126b)\n\nFile v1.0.3:SKILL.md\n\n---\nname: gm-quant\nversion: 2.1.0\ndescription: >\n  掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、\n  量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、\n  order_volume、subscribe、history、set_token、get_symbols、get_symbol_infos、\n  get_history_symbol、history_n、current、last_tick、current_price、get_trading_dates、\n  order_percent、order_value、order_target_volume、algo_order、\n  get_orders、get_position、get_cash、bond_convertible、\n  L2行情、逐笔成交、逐笔委托、schedule定时任务、 财务数据、资产负债表、利润表、现金流量表、估值指标、PE/PB/PS/股息率、\n  市值、股本、流通股、成分股、行业分类、 可转债分析、转股溢价率、纯债价值、ETF成分股、基金净值、 期货合约信息、仓单数据、成交持仓排名、连续合约、\n  stk_get_fundamentals、stk_get_daily_valuation、stk_get_index_constituents、\n  stk_get_industry_category、stk_get_industry_constituents、stk_get_symbol_industry、\n  stk_get_sector_category、stk_get_sector_constituents、stk_get_symbol_sector、\n  stk_get_dividend、stk_get_ration、stk_get_adj_factor、stk_get_shareholder_num、\n  stk_get_top_shareholder、stk_get_share_change、stk_abnor_change_stocks、\n  stk_abnor_change_detail、stk_quota_shszhk_infos、stk_active_stock_top10_shszhk_info、\n  stk_get_money_flow、stk_get_finance_audit、stk_get_finance_forecast、\n  bnd_get_analysis、bnd_get_conversion_price、bnd_get_call_info、bnd_get_put_info、bnd_get_amount_change、\n  fnd_get_portfolio、fnd_get_etf_constituents、fnd_get_net_value、fnd_get_adj_factor、fnd_get_dividend、fnd_get_split、fnd_get_share、\n  fut_get_contract_info、fut_get_continuous_contracts、fut_get_transaction_rankings、fut_get_warehouse_receipt、\n  get_open_call_auction\n  时，自动加载此 skill。\n---\n\n# 掘金量化 SDK 技能 — v2.0 自然语言策略引擎\n\n## 定位\n\n你是**掘金量化平台的自然语言策略助手**。用户用中文描述交易想法，你负责：\n1. **理解需求** → 提炼策略逻辑（标的/信号/风控）\n2. **生成代码** → 输出可直接运行的完整策略 `.py` 文件\n3. **执行运行** → 调用 `scripts/run_strategy.py` 一键启动回测或实盘\n\n## 核心原则\n\n1. **必须先 set_token**：纯数据查询（非策略 run）场景下，代码开头必须调用 `set_token('your_token')`。\n2. **symbol 格式**：`交易所代码.证券代码`，如 `SHSE.600000`、`SZSE.000001`，**严格区分大小写**。\n3. **gm 包通过掘金终端连接**：终端必须保持打开，否则接口会超时或报错。\n4. **两种模式**：`MODE_LIVE=1`（实时/仿真）、`MODE_BACKTEST=2`（回测）；`run()` 函数启动策略。\n5. **数据查询不需要 run**：仅用 `set_token` 后直接调用数据函数即可。\n\n## 🚀 用户工作流（自然语言→运行）\n\n### 第 0 步：确认 Strategy ID（重要！）\n\n**每次生成策略前，必须向用户索要 `strategy_id`。**\n\n`strategy_id` 是策略在掘金终端中的唯一标识。填写后：\n- 回测结果**持久化**到掘金终端后台\n- 用户登录 [掘金终端网页](https://www.myquant.cn) → 策略列表 → 查看完整的**绩效分析图表**\n  （收益曲线、回撤分析、夏普比率、持仓明细等）\n\n> **交互方式**：如果用户没有主动提供 strategy_id，在生成代码前询问：\n> \"请给我一个 **strategy_id**（英文/数字/下划线），用于在掘金终端标识这个策略。\n> 填完后你可以在终端网页上看到绩效分析图表。例如：`ma_cross_600519`、`momentum_v1`\"\n\n| 场景 | 处理方式 |\n|------|---------|\n| 用户提供了 strategy_id | 直接使用 |\n| 用户没提供 | **必须追问**，不能自己编造一个默认值后静默使用 |\n| 用户说\"随便起一个\" | 根据策略特征起一个有意义的名字（如 `dual_ma_kweichow`） |\n\n### 第一步：理解用户意图\n\n当用户用自然语言描述策略时，按以下维度提取信息：\n\n| 维度 | 需确认的信息 | 默认值（如未明确说明） |\n|------|-------------|---------------------|\n| **strategy_id** | 策略在掘金终端的标识（**必须用户提供，见第0步**） | 无默认，必须询问 |\n| **标的池** | 哪些股票/指数？ | 沪深300成分股 |\n| **时间频率** | 日线/分钟线/tick？ | 日线 `1d` |\n| **买入信号** | 什么条件买入？（均线/指标/事件） | 必须明确，不能猜测 |\n| **卖出信号** | 什么条件卖出？ | 必须明确，不能猜测 |\n| **仓位管理** | 全仓/固定金额/比例/等权 | 等权分配 |\n| **止损止盈** | 有无？阈值多少？ | 无 |\n| **回测区间** | 开始~结束日期 | 最近1年 |\n| **初始资金** | 多少钱？ | 100万 |\n| **运行模式** | 回测还是实盘？ | 先回测 |\n\n> ⚠️ **如果用户描述模糊（如\"帮我做个赚钱的策略\"），必须追问具体条件后再生成代码。**\n\n### 第二步：生成策略文件\n\n使用下方**标准策略模板**生成完整 `.py` 文件，保存到用户的输出目录：\n\n```python\n\"\"\"\n策略名称：{name}\n策略描述：{description}\n生成时间：{date}\n\"\"\"\n\nimport sys, os, io\nsys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')\n\nfrom gm.api import *\n\n# ============================================================\n# 配置区 —— 用户可通过修改此处调整策略参数\n# ============================================================\nSYMBOLS = 'SHSE.600519,SZSE.000001'      # 标的（逗号分隔）\nFREQUENCY = '1d'                          # K线周期：1d/60s/300s/tick\nCOUNT = 20                                # 订阅K线数量（context.data滑窗大小）\n\n# 交易参数\nORDER_TYPE = OrderType_Market              # 下单方式：Market(市价) / Limit(限价)\nPOSITION_PCT = 0.2                        # 单只股票仓位占比（0~1）\n\n# 回测参数\nBACKTEST_START = '2024-01-02 09:30:00'\nBACKTEST_END   = '2025-12-31 15:30:00'\nINITIAL_CASH   = 1000000                  # 初始资金\nCOMMISSION     = 0.00025                  # 手续费率\nSLIPPAGE       = 0.001                    # 滑点\n\n\n# ============================================================\n# 策略逻辑\n# ============================================================\n\ndef init(context):\n    \"\"\"初始化：订阅行情\"\"\"\n    log.info(f'策略启动 | 标的:{SYMBOLS} | 周期:{FREQUENCY}')\n    subscribe(symbols=SYMBOLS, frequency=FREQUENCY, count=COUNT)\n\n    # 存储策略状态\n    context.last_signal = {}  # {symbol: last_signal_time}\n\n\ndef on_bar(context, bars):\n    \"\"\"每根K线触发\"\"\"\n    for bar in bars:\n        symbol = bar['symbol']\n        try:\n            _handle_bar(context, symbol)\n        except Exception as e:\n            log.error(f'处理{symbol}异常: {e}')\n\n\ndef on_tick(context, tick):\n    \"\"\"tick级别回调（如订阅了tick会走这里）\"\"\"\n    pass\n\n\ndef _handle_bar(context, symbol):\n    \"\"\"单只标的策略逻辑\"\"\"\n\n    # 1. 获取历史数据（滑窗内）—— 注意返回 DataFrame\n    data = context.data(symbol=symbol, frequency=FREQUENCY, count=COUNT)\n    if data is None or len(data) < COUNT:\n        return\n\n    # 2. 获取当前持仓 —— get_position() 不带参数，返回全部持仓列表\n    all_positions = get_position()\n    position = None\n    if all_positions:\n        for p in all_positions:\n            sym = p.get('symbol') if isinstance(p, dict) else (p.symbol if hasattr(p, 'symbol') else None)\n            if sym == symbol:\n                position = p\n                break\n\n    # ========================================\n    # 【策略核心】在此处实现买卖信号\n    # ========================================\n\n    # 示例：双均线策略\n    close = data['close'].tolist()\n    ma_short = sum(close[-5:]) / 5    # MA5\n    ma_long  = sum(close[-20:]) / 20  # MA20\n    prev_ma5 = sum(close[-6:-1]) / 5 if len(close) >= 6 else ma_short\n    prev_ma20 = sum(close[-26:-6]) / 20 if len(close) >= 27 else ma_long\n\n    buy_signal  = (prev_ma5 <= prev_ma20) and (ma_short > ma_long)\n    sell_signal = (prev_ma5 >= prev_ma20) and (ma_short < ma_long)\n\n    # ========================================\n    # 3. 执行交易\n    # ========================================\n\n    current_price = close[-1]\n    cash_info = get_cash()\n\n    if buy_signal and not position:\n        # 买入：按仓位比例计算金额\n        available = cash_info.available\n        order_value = available * POSITION_PCT\n        if order_value > 10000:  # 最少1万元\n            volume = int(order_value / current_price / 100) * 100  # A股必须100股整数倍\n            order_volume(symbol, volume,\n                         side=OrderSide_Buy,\n                         position_effect=PositionEffect_Open,\n                         order_type=ORDER_TYPE)\n            print(f'[买入] {symbol} 价格={current_price:.2f} 数量={volume}')\n\n    elif sell_signal and position:\n        # 卖出：清仓该标的（注意用 position_side 不是 position_effect）\n        order_target_volume(symbol, 0,\n                            position_side=PositionSide_Long,\n                            order_type=ORDER_TYPE)\n        print(f'[卖出] {symbol} 价格={current_price:.2f}')\n\n\ndef handle_error(context, error_code, error_msg, **kwargs):\n    \"\"\"错误处理\"\"\"\n    log.error(f'策略异常 [{error_code}]: {msg}')\n\n\n# ============================================================\n# 启动入口\n# ============================================================\nif __name__ == '__main__':\n    # 从环境变量读取参数（由 run_strategy.py 传入）\n    TOKEN = os.environ.get('GM_TOKEN', '') or ''\n    MODE = os.environ.get('GM_RUN_MODE', 'backtest')\n    STRATEGY_ID = os.environ.get('GM_STRATEGY_ID', '') or 'my_strategy'\n    START = os.environ.get('GM_BACKTEST_START', BACKTEST_START)\n    END = os.environ.get('GM_BACKTEST_END', BACKTEST_END)\n    CASH = float(os.environ.get('GM_INITIAL_CASH', str(INITIAL_CASH)))\n\n    mode = MODE_LIVE if MODE.lower() in ('live', 'realtime') else MODE_BACKTEST\n\n    run(\n        strategy_id=STRATEGY_ID,\n        filename=__file__[:__file__.rfind('.')] if '.' in __file__ else __file__,\n        mode=mode,\n        token=TOKEN,\n        backtest_start_time=START,\n        backtest_end_time=END,\n        backtest_initial_cash=CASH,\n        backtest_commission_ratio=COMMISSION,\n        backtest_slippage_ratio=SLIPPAGE,\n        backtest_adjust=ADJUST_PREV,\n    )\n```\n\n### 第三步：执行策略\n\n使用运行器脚本一键执行：\n\n```bash\npython scripts/run_strategy.py --strategy <策略文件路径> --strategy-id <你的策略ID> [--mode backtest|live] [--token YOUR_TOKEN]\n```\n\n> **`--strategy-id` 必填**：填写后回测结果会持久化到掘金终端，登录终端网页即可查看绩效分析图表（收益曲线、回撤、夏普比率等）。\n> 如果不填，回测结果仅在控制台输出，不会保存到终端。\n\n运行器脚本路径：`C:\\Users\\wjz\\.workbuddy\\skills\\gm-quant\\scripts\\run_strategy.py`\n\n## 参考文档索引\n\n详细 API 文档位于 `references/` 目录下：\n\n| 文件 | 内容 |\n|------|------|\n| `01-quick-start.md` | 快速开始、策略架构、运行模式 |\n| `02-core-functions.md` | `run`、`set_token`、`stop`、`schedule`、`timer` |\n| `03-subscribe-events.md` | `subscribe`、`unsubscribe`、`on_tick`、`on_bar`、`on_l2*` |\n| `04-market-data.md` | `current`、`last_tick`、`current_price`、`history`、`history_n`、`context.data` |\n| `05-l2-data.md` | L2 行情查询接口（付费） |\n| `06-symbol-info.md` | 标的信息查询 API |\n| `07-trading-dates.md` | 交易日历 API |\n| `08-order-api.md` | 下单 API 全集 |\n| `09-algo-order.md` | 算法单 API |\n| `10-account-query.md` | 账户查询 API |\n| `11-bond-convertible.md` | 可转债交易 API |\n| `12-dataobjects.md` | 数据对象字段定义 |\n| `13-enums.md` | 枚举常量速查 |\n| `14-context.md` | context 对象 |\n| `15-user-guide.md` | 用户指南（常见问题） |\n| `16-premium-data-apis.md` | 增值数据 API 速查合集（股票/基金/转债/期货） |\n| `17-financial-data-fields.md` | 财务数据字段定义 |\n| `18-stock-premium-apis.md` | 股票增值数据 API 完整文档（行业/板块/分红/龙虎榜/沪深港通/资金流向等） |\n| `19-fund-premium-apis.md` | 基金增值数据 API 完整文档（ETF成分股/净值/资产组合/规模等） |\n| `20-cb-premium-apis.md` | 可转债增值数据 API 完整文档（转股价/赎回/回售/分析指标等） |\n| `21-futures-premium-apis.md` | 期货增值数据 API 完整文档（品种信息/成交持仓排名/仓单/连续合约映射等） |\n\n## 交易 API 补充\n\n### 融资融券（信用交易）\n\n融资融券交易需在信用账户下操作，使用 `credit_` 前缀函数：\n\n```python\n# 融资买入（借入资金买证券）\ncredit_buying_on_margin(symbol, volume, price=0, order_type=OrderType_Market, position_effect=PositionEffect_Open)\n\n# 融券卖出（借入证券卖出）\ncredit_short_selling(symbol, volume, price=0, order_type=OrderType_Market, position_effect=PositionEffect_Open)\n\n# 买券还券（买入证券归还融券）\ncredit_buying_on_repayment(symbol, volume, price=0, order_type=OrderType_Market)\n\n# 卖券还款（卖出证券归还融资）\ncredit_selling_on_repayment(symbol, volume, price=0, order_type=OrderType_Market)\n\n# 直接还款（用现金直接归还融资）\ncredit_direct_repayment(amount)\n\n# 直接还券（用持仓直接归还融券）\ncredit_direct_return_securities(symbol, volume)\n\n# 信用账户查询\ncredit_get_collateral_instruments()    # 查询可担保证券\ncredit_get_borrowable_instruments()    # 查询可融券证券\ncredit_get_collateral_ratio(symbol)    # 查询担保折算率\ncredit_get_concentrate_limit(symbol)   # 查询集中度限制\ncredit_get_margin_ratio(symbol)        # 查询融资融券保证金比例\ncredit_get_max_volume(symbol, side)    # 查询最大可借数量\n```\n\n> ⚠️ 融资融券功能需要开通信用账户，且掘金终端需切换到信用交易模式。\n\n### 批量下单\n\n```python\n# 批量下单 — 一次提交多笔委托，减少网络往返\norders = [\n    {'symbol': 'SHSE.600519', 'volume': 100, 'side': OrderSide_Buy, 'position_effect': PositionEffect_Open, 'order_type': OrderType_Market},\n    {'symbol': 'SZSE.000001', 'volume': 200, 'side': OrderSide_Buy, 'position_effect': PositionEffect_Open, 'order_type': OrderType_Market},\n]\norder_batch(orders)\n```\n\n> `order_batch` 返回订单ID列表，与 `order_volume` 返回值一致。\n\n### 撤单\n\n```python\n# 撤销指定委托\norder_cancel(cl_ord_id)         # cl_ord_id 从 get_orders() 或 on_order_status 回调中获取\n\n# 撤销全部未成交委托\norder_cancel_all()\n\n# 查询未成交委托\nget_unfinished_orders()\n```\n\n> `order_cancel` 的参数是 `cl_ord_id`（客户端订单ID），**不是** `order_id`。可以从 `on_order_status` 回调的 `order.cl_ord_id` 字段或 `get_unfinished_orders()` 返回值中获取。\n\n### 特殊交易函数\n\n```python\n# 新股申购\nipo_buy(symbol, volume, price=0, order_type=OrderType_Limit)\n\n# ETF 申购/赎回（场内基金）\nfund_etf_buy(symbol, volume, price=0, order_type=OrderType_Market)       # ETF 申购\nfund_etf_redemption(symbol, volume, price=0, order_type=OrderType_Market) # ETF 赎回\n\n# 场外基金\nfund_subscribing(symbol, volume, price=0)   # 场外基金认购\nfund_buy(symbol, volume, price=0)           # 场外基金申购\nfund_redemption(symbol, volume, price=0)    # 场外基金赎回\n\n# 国债逆回购\nbond_reverse_repurchase_agreement(symbol, volume, price=0, order_type=OrderType_Limit)\n```\n\n> ⚠️ 国债逆回购的 `volume` 单位是**张**（1张=1000元面值），`price` 是年化利率（如 2.5 表示年化 2.5%）。\n\n### 动态参数（终端 UI 可调）\n\n在 `init()` 中用 `add_parameter` 注册参数后，用户可在掘金终端 UI 上实时调整策略参数，无需改代码重启：\n\n```python\ndef init(context):\n    add_parameter(key='ma_short', value=5, min=1, max=100, step=1, name='短期均线周期')\n    add_parameter(key='ma_long', value=20, min=1, max=200, step=1, name='长期均线周期')\n    add_parameter(key='stop_loss_pct', value=0.05, min=0.01, max=0.5, step=0.01, name='止损比例')\n\n# 用户在终端修改参数时触发回调\ndef on_parameter(context, parameter):\n    key = parameter['key']\n    value = parameter['value']\n    log.info(f'参数变更: {key} = {value}')\n    if key == 'ma_short':\n        context.ma_short_period = value\n\n# 策略中读取当前参数值\ndef on_bar(context, bars):\n    ma_short = get_parameter(key='ma_short')\n    ma_long = get_parameter(key='ma_long')\n```\n\n### 连接事件\n\n适用于实盘/仿真模式，可用于断线重连逻辑或告警通知（回测模式下不会触发）：\n\n```python\ndef on_market_data_connected(context):\n    log.info('行情服务已连接')\n\ndef on_market_data_disconnected(context):\n    log.info('行情服务已断开')\n\ndef on_trade_data_connected(context):\n    log.info('交易服务已连接')\n\ndef on_trade_data_disconnected(context):\n    log.info('交易服务已断开')\n```\n\n### 交易所代码表\n\n| 代码 | 交易所 | 示例 |\n|------|--------|------|\n| SHSE | 上海证券交易所 | SHSE.600000 |\n| SZSE | 深圳证券交易所 | SZSE.000001 |\n| CFFEX | 中国金融期货交易所 | CFFEX.IF2506 |\n| SHFE | 上海期货交易所 | SHFE.ag2506 |\n| DCE | 大连商品交易所 | DCE.m2509 |\n| CZCE | 郑州商品交易所 | CZCE.CF501 |\n| INE | 上海国际能源交易中心 | INE.sc2506 |\n| GFEX | 广州期货交易所 | GFEX.si2508 |\n\n### 枚举常量表（速查）\n\n```python\n# ---- 订单状态 OrderStatus ----\nOrderStatus_New = 1                # 新建\nOrderStatus_PartiallyFilled = 3    # 部分成交\nOrderStatus_Filled = 4             # 全部成交\nOrderStatus_Canceled = 5           # 已撤\nOrderStatus_Rejected = 7           # 拒绝\nOrderStatus_Cancelling = 8         # 待撤\n# 注意：回测中可能出现未记录状态码 10（内部中间态），需兼容处理\n\n# ---- 订单类型 OrderType ----\nOrderType_Market = 1               # 市价单\nOrderType_Limit = 2                # 限价单\n\n# ---- 买卖方向 OrderSide ----\nOrderSide_Buy = 1\nOrderSide_Sell = 2\n\n# ---- 开平仓 PositionEffect（order_volume 用）----\nPositionEffect_Open = 1            # 开仓\nPositionEffect_Close = 2           # 平仓\nPositionEffect_CloseToday = 3      # 平今\nPositionEffect_CloseYesterday = 4  # 平昨\n\n# ---- 持仓方向 PositionSide（order_target_* 用）----\nPositionSide_Long = 1\nPositionSide_Short = 2\n\n# ---- 复权方式 AdjustType ----\nADJUST_NONE = 0                    # 不复权\nADJUST_PREV = 1                    # 前复权（回测常用）\nADJUST_POST = 2                    # 后复权\n\n# ---- 运行模式 ----\nMODE_LIVE = 1                      # 实时/仿真\nMODE_BACKTEST = 2                  # 回测\n```\n\n### 数据频率与运行模式\n\n**K线频率（frequency）**：\n\n| 值 | 说明 |\n|----|------|\n| `tick` | 逐笔 |\n| `60s` | 1分钟 |\n| `300s` | 5分钟 |\n| `900s` | 15分钟 |\n| `1800s` | 30分钟 |\n| `3600s` | 1小时 |\n| `1d` | 日线 |\n\n**运行模式**：\n\n| 值 | 说明 |\n|----|------|\n| `MODE_LIVE = 1` | 实时/仿真模式，行情实时推送 |\n| `MODE_BACKTEST = 2` | 回测模式，数据按时间序列回放 |\n\n### ~~基本面数据（已下线）~~\n\n> ⚠️ `get_fundamentals()` / `get_fundamentals_n()` 已下线，请使用 `stk_get_fundamentals_*_pt` 系列替代。\n\n### 新股申购\n\n```python\n# 查询新股申购额度\nipo_get_quota(exchange='SHSE')        # 返回沪市/深市可用额度\n\n# 查询可申购新股列表\nipo_get_instruments(trade_date='2025-01-15')  # 指定交易日的可申购新股\n\n# 查询申购配号\nipo_get_match_number(symbol='SHSE.688001')\n\n# 查询中签信息\nipo_get_lot_info(symbol='SHSE.688001')\n```\n\n### 分红数据\n\n```python\n# 查询分红送配数据（时序）\nget_dividend(symbol='SHSE.600519', start_date='2020-01-01', end_date='2025-12-31', df=True)\n# 返回字段：ex_date(除权日), record_date(登记日), pay_date(发放日), cash_div(每股派息),\n#           bonus_share_r(送股比例), transfer_share_r(转增比例)\n```\n\n### L2 历史数据查询\n\n```python\n# L2 逐笔成交\nget_history_l2_transaction(symbol, start_time, end_time, fields=None, df=True)\n\n# L2 逐笔委托\nget_history_l2_order(symbol, start_time, end_time, fields=None, df=True)\n\n# L2 队列（买卖盘口）\nget_history_l2_queue(symbol, start_time, end_time, fields=None, df=True)\n```\n\n> ⚠️ L2 数据接口为付费功能，仅特定券商可用，需要开通相应权限。\n\n## 进阶策略示例\n\n### 配对交易（均值回归）\n\n```python\ndef init(context):\n    context.pair = ('SHSE.600036', 'SZSE.000001')  # 招行 vs 平安\n    subscribe(symbols=','.join(context.pair), frequency='1d', count=60)\n    context.half_life = 20\n    context.entry_z = 2.0\n    context.exit_z = 0.5\n\ndef on_bar(context, bars):\n    s1, s2 = context.pair\n    d1 = context.data(symbol=s1, frequency='1d', count=60)\n    d2 = context.data(symbol=s2, frequency='1d', count=60)\n    if d1 is None or d2 is None or len(d1) < 30:\n        return\n\n    spread = d1['close'].values / d2['close'].values\n    mean = spread[-context.half_life:].mean()\n    std = spread[-context.half_life:].std()\n    zscore = (spread[-1] - mean) / std if std > 0 else 0\n\n    if zscore > context.entry_z and _get_position_volume(context, s1) == 0:\n        order_target_percent(s1, -0.5, position_side=PositionSide_Short, order_type=OrderType_Market)\n        order_target_percent(s2, 0.5, position_side=PositionSide_Long, order_type=OrderType_Market)\n    elif zscore < -context.entry_z and _get_position_volume(context, s2) == 0:\n        order_target_percent(s1, 0.5, position_side=PositionSide_Long, order_type=OrderType_Market)\n        order_target_percent(s2, -0.5, position_side=PositionSide_Short, order_type=OrderType_Market)\n    elif abs(zscore) < context.exit_z:\n        for sym in context.pair:\n            order_target_volume(sym, 0, position_side=PositionSide_Long, order_type=OrderType_Market)\n            order_target_volume(sym, 0, position_side=PositionSide_Short, order_type=OrderType_Market)\n```\n\n### CTA 海龟交易法\n\n```python\ndef init(context):\n    subscribe(symbols='SHFE.ag2506', frequency='1d', count=55)\n    context.atr_period = 20\n    context.entry_period = 20\n    context.exit_period = 10\n    context.unit_risk = 0.01  # 每笔最大亏损占总资金1%\n\ndef on_bar(context, bars):\n    data = context.data(symbol='SHFE.ag2506', frequency='1d', count=55)\n    if data is None or len(data) < 55:\n        return\n\n    high, low, close = data['high'].values, data['low'].values, data['close'].values\n    tr = [max(high[i]-low[i], abs(high[i]-close[i-1]), abs(low[i]-close[i-1])) for i in range(1, len(close))]\n    atr = sum(tr[-context.atr_period:]) / context.atr_period\n\n    entry_high = max(high[-context.entry_period:-1])\n    exit_low = min(low[-context.exit_period:-1])\n    curr = close[-1]\n\n    cash = get_cash()\n    unit = int(cash.available * context.unit_risk / atr / 1000) * 1000\n    pos = _get_position_volume(context, 'SHFE.ag2506')\n\n    if curr > entry_high and pos == 0:\n        order_volume('SHFE.ag2506', unit, side=OrderSide_Buy,\n                     position_effect=PositionEffect_Open, order_type=OrderType_Market)\n    elif curr < exit_low and pos > 0:\n        order_volume('SHFE.ag2506', pos, side=OrderSide_Sell,\n                     position_effect=PositionEffect_Close, order_type=OrderType_Market)\n```\n\n### 风控模块（可嵌入任意策略）\n\n```python\nclass RiskManager:\n    \"\"\"通用风控：止损/止盈/最大持仓/回撤控制\"\"\"\n\n    def __init__(self, stop_loss_pct=0.05, take_profit_pct=0.10,\n                 max_position_pct=0.3, max_drawdown_pct=0.15):\n        self.stop_loss_pct = stop_loss_pct\n        self.take_profit_pct = take_profit_pct\n        self.max_position_pct = max_position_pct\n        self.max_drawdown_pct = max_drawdown_pct\n        self.peak_value = 0\n\n    def check_stop_loss(self, entry_price, current_price, side='long'):\n        if side == 'long':\n            return (current_price - entry_price) / entry_price < -self.stop_loss_pct\n        return (entry_price - current_price) / entry_price < -self.stop_loss_pct\n\n    def check_take_profit(self, entry_price, current_price, side='long'):\n        if side == 'long':\n            return (current_price - entry_price) / entry_price > self.take_profit_pct\n        return (entry_price - current_price) / entry_price > self.take_profit_pct\n\n    def check_drawdown(self):\n        cash = get_cash()\n        total = cash.nav if hasattr(cash, 'nav') else cash.available\n        self.peak_value = max(self.peak_value, total)\n        dd = (self.peak_value - total) / self.peak_value if self.peak_value > 0 else 0\n        return dd > self.max_drawdown_pct\n\n    def check_position_limit(self, symbol_value, total_value):\n        return (symbol_value / total_value) > self.max_position_pct\n```\n\n### 行业轮动（动量因子 + schedule 定时调仓）\n\n```python\ndef init(context):\n    context.sectors = {\n        'SHSE.512000': '券商', 'SHSE.512010': '医药', 'SHSE.512660': '军工',\n        'SHSE.512800': '银行', 'SHSE.512690': '白酒', 'SHSE.515030': '新能源',\n    }\n    context.top_n = 2\n    subscribe(symbols=','.join(context.sectors.keys()), frequency='1d', count=22)\n    schedule(rebalance, frequency='1d', time_rule='15:05')\n\ndef rebalance(context, bar_dict):\n    momentum = {}\n    for sym in context.sectors:\n        data = context.data(symbol=sym, frequency='1d', count=22)\n        if data is not None and len(data) >= 20:\n            momentum[sym] = data['close'].iloc[-1] / data['close'].iloc[-20] - 1\n\n    ranked = sorted(momentum.items(), key=lambda x: x[1], reverse=True)\n    targets = [s[0] for s in ranked[:context.top_n]]\n\n    for sym in context.sectors:\n        if sym in targets:\n            order_target_percent(sym, 1.0 / context.top_n,\n                                 position_side=PositionSide_Long, order_type=OrderType_Market)\n        else:\n            order_target_volume(sym, 0,\n                                position_side=PositionSide_Long, order_type=OrderType_Market)\n```\n\n## API 参数补充说明\n\n### current() 回测 vs 实盘字段差异\n\n```python\ndata = current(symbols='SHSE.600519,SZSE.000001')\n# 通用字段：symbol, open, high, low, close, volume, amount, frequency, timestamp\n# 实盘额外字段：bid_price/bid_volume(买价买量), ask_price/ask_volume(卖价卖量),\n#               last_price(最新价), num_trades(成交笔数)\n```\n\n> ⚠️ 回测模式下 `current()` 只能查询已订阅标的，实盘模式可查询任意标的。\n\n**⚠️ current() 实时模式调用频次限制（2026-05-19 起）**：\n- 5分钟内最多调用 **100 次**\n- 24小时内最多调用 **1000 次**\n- **2026-06-01 起**：单次查询标的数量上限调整为 **50 个**\n\n### last_tick — 查询已订阅的最新 Tick（推荐替代 current）\n\n不受 `current()` 调用频次限制，返回数据更精简高效。\n\n```python\nlast_tick(symbols, fields=\"\", include_call_auction=False)\n```\n\n| 参数 | 类型 | 说明 |\n|------|------|------|\n| symbols | str or list | 标的代码，多个用英文逗号隔开或列表格式 |\n| fields | str | 返回字段，默认所有 |\n| include_call_auction | bool | 是否支持集合竞价(09:15-09:25)取数，默认 False |\n\n**返回值**：`list[dict]`，每项包含 `symbol`、`price`、`created_at` 等字段\n\n```python\nfrom gm.api import *\nset_token('YOUR_TOKEN')\n\nsubscribe(symbols='SZSE.000001,SHSE.600000', frequency='tick')\nresult = last_tick(symbols='SZSE.000001,SHSE.600000', fields='symbol,price,open,created_at')\nfor item in result:\n    print(item['symbol'], item['price'])\n```\n\n> ⚠️ 输入的 `symbols` **必须先通过 `subscribe` 订阅 tick 行情**；若未订阅，返回空数据。\n\n### current_price — 查询当前最新价（更轻量替代 current）\n\n仅返回最新价，不受 `current()` 调用频次限制。\n\n```python\ncurrent_price(symbols)\n```\n\n| 参数 | 类型 | 说明 |\n|------|------|------|\n| symbols | str or list | 标的代码，多个用英文逗号隔开或列表格式 |\n\n**返回值**：`list[dict]`，每项包含 `symbol`、`price`、`created_at`\n\n```python\nfrom gm.api import *\nset_token('YOUR_TOKEN')\n\nresult = current_price(symbols='SZSE.000001,SHSE.600000')\nprint(result[0]['symbol'], result[0]['price'])\n```\n\n### fut_get_continuous_contracts — 查询连续合约对应的真实合约\n\n```python\nfut_get_continuous_contracts(csymbol, start_date=\"\", end_date=\"\")\n```\n\n| 参数 | 类型 | 必填 | 默认值 | 说明 |\n|------|------|:----:|:-----:|------|\n| csymbol | str | Y | 无 | 连续合约代码，只能输入一个。支持主力/次主力/前5个月份/加权指数 |\n| start_date | str | N | \"\" | 开始日期 %Y-%m-%d，默认最新交易日 |\n| end_date | str | N | \"\" | 结束日期 %Y-%m-%d，默认最新交易日 |\n\n**csymbol 连续合约后缀规则**：\n\n| 后缀 | 含义 | 示例 |\n|:----:|------|------|\n| 无 | 主力连续 | `CFFEX.IM` |\n| 22 | 次主力连续 | `CFFEX.IM22` |\n| 00 | 当月连续 | `CFFEX.IM00` |\n| 01 | 下月连续 | `CFFEX.IM01` |\n| 02 | 下季连续 | `CFFEX.IM02` |\n| 03 | 隔季连续 | `CFFEX.IM03` |\n| 99 | 加权指数 | `CFFEX.IM99` |\n\n```python\nfrom gm.api import *\nset_token('YOUR_TOKEN')\n\n# 查询中证1000主力连续合约2025年真实合约\ndf = fut_get_continuous_contracts('CFFEX.IM', start_date='2025-01-01', end_date='2025-12-31')\nprint(df)\n```\n\n### history() 补充参数\n\n```python\nhistory(symbol, frequency, start_time=None, end_time=None, count=None,\n        fields=None, skip_suspended=True, fill_missing=None, df=True)\n\n# skip_suspended=True（默认）：跳过停牌日\n# skip_suspended=False：保留停牌日，数据字段用 NaN 填充\n\n# fill_missing='pre'：用前值填充缺失\n# fill_missing='post'：用后值填充缺失\n# fill_missing=None（默认）：不填充\n```\n\n### subscribe() wait_group 参数\n\n```python\n# 多标的等待同步：所有标的bar都到达后才触发一次 on_bar\nsubscribe(symbols='SHSE.600519,SZSE.000001', frequency='60s', count=20,\n          wait_group=True)\n\n# 默认 wait_group=False：每个标的bar到达时单独触发\n```\n\n> 多标的同频率策略建议开启 `wait_group=True`，避免部分标的先触发导致数据不齐。\n\n### order_value / order_percent / order_target_percent\n\n```python\n# order_value — 按金额下单（自动取整到100股倍数）\norder_value(symbol='SHSE.600519', value=50000, side=OrderSide_Buy,\n            position_effect=PositionEffect_Open, order_type=OrderType_Market)\n\n# order_percent — 按总资产百分比下单\norder_percent(symbol='SHSE.600519', percent=0.1, side=OrderSide_Buy,\n              position_effect=PositionEffect_Open, order_type=OrderType_Market)\n# percent=0.1 表示用总资产的10%买入\n\n# order_target_percent — 调仓到目标占比（ETF 调仓推荐）\norder_target_percent(symbol='SHSE.512000', percent=0.15,\n                     position_side=PositionSide_Long, order_type=OrderType_Market)\n# 调整到占总资产15%，不足买入，超出卖出\n```\n\n### 成交回报查询\n\n```python\nget_execution_reports(cl_ord_id=None, symbol=None, start_time=None,\n                      end_time=None, position_side=None, limit=None, df=True)\n# cl_ord_id: 指定订单ID\n# symbol: 指定标的\n# limit: 返回条数限制\n```\n\n## 常见问题 & 注意事项\n\n- `history()` 的 `df` 参数默认 `True` 返回 DataFrame，`False` 返回 `list[dict]`\n- 单次查询最多返回 33000 条数据\n- L2 数据接口（`get_history_l2*`）仅特定付费券商可用\n- `subscribe` 中 `count` 决定 `context.data` 的滑窗大小\n- 回测模式下 `init` 不支持交易操作\n- 虚拟合约（主力连续合约）仅在回测模式下可用，如 `SHFE.RB`\n- `get_trading_dates` 查交易日历时，`exchange` 参数用交易所代码如 `'SHSE'`\n- `run()` 参数名是 `strategy_id` 和 `filename`（模块名，不是文件路径！）\n- A 股最小下单单位为 100 股（1手），`order_volume` 必须是 100 的整数倍\n- `order_value` 会自动取整到 100 股倍数\n\n## 踩坑经验（实测验证）\n\n**以下坑点已通过实际运行验证，生成代码时必须遵守：**\n\n1. **`run()` 参数名**：是 `strategy_id` + `filename`（模块名，不带 .py 后缀），不是 `strategy_name` / `file_path`\n2. **`log()` 用法**：`log(msg, source)` 是普通函数，**不是** logger 对象。不要用 `log.info()`。推荐直接用 `print()`\n3. **`context.data()` 返回值**：返回的是 **DataFrame**（不是 dict list），用 `data['close'].tolist()` 访问数据列\n4. **`get_position()` 不带参数**：调用 `get_position()` 获取全部持仓列表，然后遍历查找目标 symbol 的持仓。不支持 `get_position(symbol=xxx)`\n5. **`order_target_volume()` 参数**：不需要 `side` 参数；用 `position_side=PositionSide_Long`（不是 `position_effect=PositionEffect_Close`）\n6. **`order_volume()` 买入参数**：需要 `side=OrderSide_Buy` + `position_effect=PositionEffect_Open`\n7. **Windows 编码**：脚本开头必须加 `sys.stdout = io.TextIOWrapper(...)` 否则中文 emoji 报错\n8. **A 股 T+1**：当天买入不能当天卖出，策略逻辑需要考虑这个约束\n9. **`cl_ord_id` 参数不存在**：`order_volume` / `order_value` / `order_target_volume` 等下单函数**不支持** `cl_ord_id` 参数。传入会直接抛 `TypeError: got an unexpected keyword argument 'cl_ord_id'`。订单标识由系统自动生成\n10. **`on_order_status` 回测模式状态码**：回测中会出现文档未记录的状态码 `10`（未知/内部中间态），实际运行时需兼容处理。完整状态码：1=新建, 2=已报, 3=部分成交, 4=已成交, 5=已撤, 6=未成交(超时), 7=拒绝, 8=待撤, 9=未知, **10=回测内部态**\n11. **`on_execution_report` 的 exec_type**：回测模式下返回数字而非字符，实测值为 `15`（成交确认）。实盘/仿真可能返回 `'T'`(Trade) / `'C'(Cancel)\n12. **回测中风控行为**：超额卖出或资金不足的订单在回测中不会触发 `Rejected(7)` 状态，而是变为 `Cancelling(8)` → 被自动撤销。**拒单原因需要实盘/仿真环境才能观察到**\n13. **`on_order_status` order 对象访问**：回调中的 order 对象**同时支持** dict 风格 `order['symbol']` 和属性风格 `order.symbol`，但推荐用 try/getattr 兼容两种方式\n14. **`on_execution_report` execrpt 对象访问**：同上，同时支持 dict 和属性风格。关键字段：`symbol`, `side`(1买2卖), `volume`, `price`, `exec_type`, `commission`\n15. **市价单在回测中也可能不成交**：如果资金不足（如下单量×价格 > 可用资金），市价单会被标记为 Cancelling 而非报错抛异常\n16. **`stk_get_index_constituents` 没有 `df` 参数**：直接返回 DataFrame，不需要传 df=True\n17. **财务数据 API 的 `fields` 必填且不能为空**：所有 `stk_get_fundamentals_*_pt` / `stk_get_finance_*_pt` / `stk_get_daily_*_pt` 函数的 `fields` 参数是必填的，不能传空字符串 `\"\"`，否则报错\"填写的 fields 不正确\"。fields 不能超过 20 个\n18. **`stk_get_finance_prime_pt` ROE 字段名是 `roe_weight_avg`**，不是 `roe_waa`。常用字段: eps_basic/eps_dil/roe_weight_avg/roe_weight_avg_cut/net_prof_pcom_yoy/inc_oper_yoy\n19. **`stk_get_daily_basic_pt` 股本字段名**：流通股本是 `circ_shr`（不是 float_shr），无限售条件流通股本是 `ttl_shr_unl`（不是 free_shr），有限售条件股本是 `ttl_shr_ltd`\n20. **财务衍生指标 `eps_dil2` vs `eps_dil`**：`stk_get_finance_deriv_pt` 中稀释 EPS 字段名是 `eps_dil2`（不是 `eps_dil`），而 `stk_get_finance_prime_pt` 中是 `eps_dil`\n21. **`_pt` 后缀 = 截面数据(多标的)**，无后缀 = 时序数据(单标的)。截面用 date/trade_date 参数，时序用 start_date/end_date 参数\n22. **付费增值数据 API**：期货(fut_get_*)、基金(fnd_get_*)、可转债(bnd_get_*) 的增值数据需要开通相应权限。详见 `references/16-premium-data-apis.md`\n23. **`stk_get_fundamentals_*_pt` 的 `date` 参数是发布日期**，不是报告期日期。返回的是发布日期 ≤ date 的最新报告期数据\n24. **`stk_get_daily_valuation_pt/mktvalue_pt/basic_pt` 的 `trade_date` 参数**：是交易日期，默认 None 返回最新交易日数据\n25. **回测交易日限制**：每个交易日 18:30 前只能回测上一个交易日的数据，因为当日日线数据要到 18:30 才更新完成。如果 `end_date` 设为当天但还没过 18:30，回测结果会缺少当日数据或报错\n26. **实时模式（仿真/实盘）没有发生交易的排查清单**：\n    - ① **定时任务时间过了**：`schedule` 定时任务只在指定时间触发，如果启动策略时已过了今天的时间点，要等到明天才会触发。临时解决：把时间改成当前时间之后几分钟\n    - ② **期货策略必须订阅具体合约**：实时模式只能推送具体合约行情（如 `SHFE.ag2506`），主连合约（如 `SHFE.agmain`）**没有行情推送**。回测可以主连，实时不行\n    - ③ **实时模式日线不会推送**：交易时间内日线还没走完，`on_bar` 不会收到日线 bar。需要用 `schedule` 定时任务替代，在收盘后（如 15:01）主动调用 `history` 获取日线数据\n    - ④ **检查打印日志**：确认是否有数据推送 → 是否有交易信号发出 → 是否有下单指令 → 订单状态是否正常。按这个链路逐级排查\n27. **`order_volume()` vs `order_target_volume/percent` 参数名不同**：`order_volume()` 的开平仓参数叫 `position_effect`（用 `PositionEffect_Open/Close`），而 `order_target_volume/percent/value` 的持仓方向参数叫 `position_side`（用 `PositionSide_Long/Short`）。ETF调仓推荐用 `order_target_percent`，更简洁不用算股数\n28. **56开头的ETF是沪市**：如562500机器人ETF应为 `SHSE.562500`，不是深市。5开头=沪市(SHSE)，1开头=深市(SZSE)\n\nFile v1.0.3:README.md\n\n# 掘金量化 Skill — 自然语言策略引擎 v2.1.0\r\n\r\n> **用中文说话就能跑量化策略。** 告诉我你的交易想法，我帮你生成代码、执行回测、查看结果。\r\n\r\n## 快速开始（3 步）\r\n\r\n### 1️⃣ 准备环境\r\n\r\n确保你的电脑已安装：\r\n\r\n- [**掘金终端**](https://www.myquant.cn) — 打开并登录\r\n- **Python 3.8+** — 安装 `gm` SDK 包：\r\n  ```bash\r\n  pip install gm\r\n  ```\r\n\r\n### 2️⃣ 设置 Token\r\n\r\n获取方式：掘金终端 → 系统设置 → 密钥管理 → 复制 Token\r\n\r\n然后告诉我：\"我的 token 是 `xxxxx`\"，我会自动保存。\r\n\r\n### 3️⃣ 用自然语言描述策略 + 提供 Strategy ID\r\n\r\n直接说你想做什么，**同时告诉我你的策略 ID**：\r\n\r\n> \"帮我写个双均线策略：茅台和平安银行，5 日均线上穿 20 日均线买入，下穿卖出，回测最近一年。**策略 ID 叫 `ma_cross_v1`**\"\r\n\r\n> \"写个动量策略：沪深 300 里选过去 20 天涨幅最大的 10 只等权买入，每月初调仓。**strategy_id 用 `momentum_top10`**\"\r\n\r\n> \"查一下贵州茅台最近半年的日线收盘价\"（纯查询不需要 strategy_id）\r\n\r\n我会自动生成完整的可运行策略文件并帮你跑起来。\r\n\r\n---\r\n\r\n## 支持的策略类型\r\n\r\n| 类型 | 示例描述 | 关键字 |\r\n|------|---------|--------|\r\n| **趋势跟踪** | \"双均线金叉死叉\" / \"布林带突破\" / \"MACD 策略\" | 均线、MA、MACD、布林带 |\r\n| **动量/因子** | \"选涨幅最大的 N 只\" / \"RSI 超卖买入\" / \"量价配合\" | 动量、RSI、成交量、排名 |\r\n| **均值回归** | \"偏离均值太多就反向操作\" / \"网格交易\" | 均值回归、网格、偏离 |\r\n| **多因子选股** | \"按 PE+ROE 选股\" / \"小市值+高成长\" | 因子、筛选、排序 |\r\n| **事件驱动** | \"财报后买入\" / \"涨停板打板\" | 财报、涨停、事件 |\r\n| **纯数据查询** | \"查行情\" / \"拉数据\" / \"看 K 线\" | 查询、历史、行情 |\r\n\r\n---\r\n\r\n## 运行模式\r\n\r\n| 模式 | 说明 | 适用场景 |\r\n|------|------|---------|\r\n| **回测 (Backtest)** | 用历史数据模拟交易 | 验证策略效果（默认） |\r\n| **实盘/仿真 (Live)** | 连接实时行情和模拟账户 | 策略验证后上线运行 |\r\n\r\n---\r\n\r\n## 典型对话示例\r\n\r\n### 示例 1：从零开始写策略\r\n\r\n```\r\n你: 写个双均线交叉策略，标的用贵州茅台，5日和20日均线。策略ID用 ma_cross_kweichow\r\n我: [生成 strategy_ma.py，strategy_id='ma_cross_kweichow']\r\n    策略已生成！参数如下：\r\n    - 策略ID: ma_cross_kweichow ← 终端可查看绩效\r\n    - 标的: SHSE.600519（贵州茅台）\r\n    - 周期: 日线 1d\r\n    - 信号: MA5上穿MA20买入 / 下穿卖出\r\n    - 回测: 2024-01 ~ 2025-12, 初始资金100万\r\n\r\n    要跑回测吗？\r\n你: 跑吧\r\n我: [自动调用 run_strategy.py --strategy-id ma_cross_kweichow 执行]\r\n    回测完成！结果摘要：\r\n    - 总收益: +23.5%\r\n    - 年化收益: 18.2%\r\n    - 最大回撤: -12.3%\r\n    - 夏普比率: 1.45\r\n    \r\n    ✅ 已保存到掘金终端 → 打开 https://www.myquant.cn 查看完整绩效图表\r\n```\r\n\r\n### 示例 2：只查询数据\r\n\r\n```\r\n你: 查一下中芯国际最近30天的收盘价\r\n我: [直接调用 API 返回 DataFrame]\r\n    SZSE.002371 中芯国际 最近30日收盘价：\r\n    日期          | 收盘价   | 涨跌幅\r\n    2026-03-10    | 52.30    | +2.1%\r\n    2026-03-11    | 51.80    | -0.96%\r\n    ...\r\n```\r\n\r\n---\r\n\r\n## 文件结构\r\n\r\n```\r\n~/.workbuddy/skills/gm-quant/\r\n├── SKILL.md                  # 技能主文件（AI 读取此文件理解如何工作）\r\n├── README.md                 # 本文件 — 用户引导\r\n├── TEST_REPORT.md            # API 测试报告\r\n├── references/               # API 详细参考文档（21篇）\r\n│   ├── 01-quick-start.md\r\n│   ├── 04-market-data.md\r\n│   ├── 16-premium-data-apis.md     # 增值数据 API 速查合集\r\n│   ├── 18-stock-premium-apis.md    # 股票增值数据（完整版）\r\n│   ├── 19-fund-premium-apis.md     # 基金增值数据（完整版）\r\n│   ├── 20-cb-premium-apis.md       # 可转债增值数据（完整版）\r\n│   └── 21-futures-premium-apis.md  # 期货增值数据（完整版）\r\n└── scripts/\r\n    ├── run_strategy.py        # ⭐ 策略一键运行器\r\n    ├── test_all_apis.py       # API 全量测试脚本\r\n    ├── test_account_apis.py   # 账户 API 策略环境测试\r\n    └── check_import.py        # 导入检测\r\n```\r\n\r\n---\r\n\r\n## ⭐ Strategy ID — 在掘金终端查看绩效分析\r\n\r\n> **这是使用回测功能前必须填写的一步。**\r\n\r\n### 什么是 Strategy ID？\r\n\r\n`strategy_id` 是你的策略在**掘金终端**中的唯一标识名。每次运行策略时传入它，回测结果会**持久化保存**到终端后台。\r\n\r\n### 填写后你能看到什么？\r\n\r\n登录 [掘金量化终端](https://www.myquant.cn) → **策略列表** → 找到你的策略 → 点击查看：\r\n\r\n| 绩效分析内容 | 说明 |\r\n|-------------|------|\r\n| 📈 **收益曲线** | 策略净值 vs 基准对比 |\r\n| 📉 **回撤分析** | 最大回撤、回撤持续时间 |\r\n| 📊 **风险指标** | 夏普比率、年化收益、波动率 |\r\n| 💰 **交易明细** | 每笔买入/卖出记录 |\r\n| 🎯 **持仓快照** | 每日持仓变化 |\r\n\r\n### 如何提供？\r\n\r\n在描述策略时顺便告诉我，例如：\r\n\r\n```\r\n你: 写个双均线策略，标的茅台。策略ID用 ma_cross_kweichow\r\n我: [生成代码，自动填入 strategy_id='ma_cross_kweichow']\r\n    回测完成！打开掘金终端 → 策略列表 → ma_cross_kweichow → 查看绩效图表\r\n```\r\n\r\n如果你没提供，**我会主动问你**，不会偷偷跳过。\r\n\r\n---\r\n\r\n## 注意事项\r\n\r\n- **掘金终端必须保持打开** — 所有 API 调用都通过终端通信\r\n- **Token 不要泄露给他人** — 相当于你的账号密码\r\n- **回测不等于实盘** — 回测结果仅供参考，实盘需考虑滑点、流动性等因素\r\n- **A 股 T+1** — 当天买入的股票当天不能卖出\r\n\r\n---\r\n\r\n## 🆕 v2.1.0 更新说明\r\n\r\n| 变更 | 说明 |\r\n|------|------|\r\n| ✨ `fut_get_continuous_contracts` | 新增期货连续合约→真实合约查询函数，支持主力/次主力/前5个月份/加权指数 |\r\n| ✨ `last_tick` | 新增函数，查询已订阅的最新Tick（多标的），替代 `current()` |\r\n| ✨ `current_price` | 新增函数，仅查询最新价，更轻量高效 |\r\n| ⚠️ `current()` 频次限制提醒 | 实时模式 5分钟100次/24小时1000次，推荐切换上述新函数 |\r\n| 📚 增值数据 API 文档全量上线 | 新增4份参考文档覆盖股票/基金/可转债/期货全部付费增值数据API（共40+个函数） |\r\n| ✅ 48个API实测全通过 | 涵盖行情、股票增值、基金增值、可转债增值、期货增值、实战数据查询全部场景 |\n\nFile v1.0.3:_meta.json\n\n{\n  \"ownerId\": \"kn73qb7dqheg4nh3p4x4ka1mxx85szhw\",\n  \"slug\": \"gmquant\",\n  \"version\": \"1.0.3\",\n  \"publishedAt\": 1779787330719\n}\n\nFile v1.0.3:references/01-quick-start.md\n\n# 快速开始 & 策略架构\r\n\r\n## 策略三大结构\r\n\r\n掘金量化策略主要有 3 种结构：\r\n\r\n### 1. 定时任务型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    schedule(schedule_func=algo, date_rule='1d', time_rule='14:50:00')\r\n\r\ndef algo(context):\r\n    order_volume(symbol='SHSE.600000', volume=200, side=OrderSide_Buy,\r\n                 order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n\r\nif __name__ == '__main__':\r\n    run(strategy_id='YOUR_ID', filename='main.py', mode=MODE_BACKTEST,\r\n        token='YOUR_TOKEN', backtest_start_time='2024-01-01 09:00:00',\r\n        backtest_end_time='2024-06-30 15:30:00', backtest_adjust=ADJUST_PREV,\r\n        backtest_initial_cash=1000000, backtest_commission_ratio=0.0001,\r\n        backtest_slippage_ratio=0.0001)\r\n```\r\n\r\n### 2. 数据事件驱动型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s')\r\n\r\ndef on_bar(context, bars):\r\n    print(bars)\r\n```\r\n\r\n### 3. 时间序列滑窗型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s', count=50,\r\n              format='df', fields='symbol,close,eob')\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol=bars[0]['symbol'], frequency='60s', count=50)\r\n    data['ma5'] = data['close'].rolling(5).mean()\r\n    print(data.tail())\r\n```\r\n\r\n## 纯数据研究（无需 run）\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')  # 掘金终端需保持打开\r\n\r\ndata = history(symbol='SHSE.600000', frequency='1d',\r\n               start_time='2024-01-01 09:00:00', end_time='2024-12-31 16:00:00',\r\n               fields='open,high,low,close,eob', adjust=ADJUST_PREV, df=True)\r\nprint(data)\r\n```\r\n\r\n## 模式说明\r\n\r\n| 模式 | 常量 | 说明 |\r\n|------|------|------|\r\n| 实时模式 | `MODE_LIVE = 1` | 仿真/实盘交易，接收实时行情 |\r\n| 回测模式 | `MODE_BACKTEST = 2` | 历史数据回放，快速验证策略 |\r\n\r\n## 运行参数 `run()` 全解\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| strategy_id | str | 掘金终端生成的策略 ID |\r\n| filename | str | 策略文件名（如 `main.py`） |\r\n| mode | int | MODE_LIVE 或 MODE_BACKTEST |\r\n| token | str | 用户 token（终端系统设置-密钥管理） |\r\n| backtest_start_time | str | 回测开始时间 `%Y-%m-%d %H:%M:%S` |\r\n| backtest_end_time | str | 回测结束时间 `%Y-%m-%d %H:%M:%S` |\r\n| backtest_initial_cash | float | 初始资金，默认 1000000 |\r\n| backtest_transaction_ratio | float | 成交比例，默认 1.0 |\r\n| backtest_commission_ratio | float | 佣金比例，默认 0 |\r\n| backtest_slippage_ratio | float | 滑点比例，默认 0 |\r\n| backtest_adjust | int | 复权方式：ADJUST_NONE/ADJUST_PREV/ADJUST_POST |\r\n| backtest_match_mode | int | 0=延时撮合(下一bar开盘价)，1=实时撮合(当前收盘价) |\r\n| backtest_check_cache | int | 是否用缓存，默认 1 |\r\n| serv_addr | str | 终端地址，默认本地，可指定 `ip:port` |\r\n\r\n## 注意事项\r\n- filename 必须与实际文件名一致\r\n- 前复权/后复权回测不处理分红送转事件（已通过复权因子调整）\r\n- 不复权模式会自动处理分红送转\n\nFile v1.0.3:references/02-core-functions.md\n\n# 核心基础函数\r\n\r\n## set_token - 设置用户 Token\r\n\r\n```python\r\nset_token('YOUR_TOKEN_ID')\r\n```\r\n\r\n- 纯数据查询时第一步必须调用\r\n- Token 在掘金终端「系统设置 → 密钥管理」中获取\r\n- Token 不正确会抛出异常\r\n\r\n---\r\n\r\n## run - 启动策略\r\n\r\n```python\r\nrun(strategy_id='', filename='', mode=MODE_UNKNOWN, token='',\r\n    backtest_start_time='', backtest_end_time='',\r\n    backtest_initial_cash=1000000, backtest_transaction_ratio=1,\r\n    backtest_commission_ratio=0, backtest_slippage_ratio=0,\r\n    backtest_adjust=ADJUST_NONE, backtest_check_cache=1,\r\n    serv_addr='', backtest_match_mode=0)\r\n```\r\n\r\n详细参数说明见 `01-quick-start.md`。\r\n\r\n---\r\n\r\n## stop - 停止策略\r\n\r\n```python\r\nstop()\r\n```\r\n\r\n- 停止策略，退出策略进程\r\n- 示例：当订阅代码集合为空时停止\r\n```python\r\nif not context.symbols:\r\n    stop()\r\n```\r\n\r\n---\r\n\r\n## schedule - 定时任务\r\n\r\n```python\r\nschedule(schedule_func, date_rule, time_rule)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| schedule_func | function | 定时执行的函数 |\r\n| date_rule | str | `n + d/w/m`，如 `'1d'`(每天)、`'1w'`(每周)、`'1m'`(每月) |\r\n| time_rule | str | 执行时间 `HH:MM:SS`，**时分秒不可省略前导零**，如 `'09:40:00'` |\r\n\r\n**注意**：`1w`、`1m` 仅回测可用；`time_rule` 不能写 `'9:40:0'` 这种格式。\r\n\r\n```python\r\ndef init(context):\r\n    schedule(schedule_func=algo_daily, date_rule='1d', time_rule='09:40:00')\r\n    schedule(schedule_func=algo_monthly, date_rule='1m', time_rule='09:30:00')\r\n\r\ndef algo_daily(context):\r\n    print('每天09:40执行', context.now)\r\n\r\ndef algo_monthly(context):\r\n    print('每月第一个交易日09:30执行', context.now)\r\n```\r\n\r\n---\r\n\r\n## timer / timer_stop - 毫秒级定时器\r\n\r\n**仅实时/仿真模式可用，回测不生效。**\r\n\r\n```python\r\n# 设置定时器\r\nresult = timer(timer_func=my_func, period=60000, start_delay=0)\r\n# result: {'timer_status': 0, 'timer_id': 1}\r\n\r\n# 停止定时器\r\nis_stopped = timer_stop(timer_id=result['timer_id'])\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| timer_func | function | 触发时执行的函数 |\r\n| period | int | 间隔毫秒数，范围 [1, 43200000] |\r\n| start_delay | int | 延迟启动毫秒数，范围 [0, 43200000] |\r\n\r\n```python\r\ndef init(context):\r\n    # 每60秒执行一次，立即启动\r\n    context.timer_id = timer(timer_func=on_timer, period=60000, start_delay=0)\r\n\r\ndef on_timer(context):\r\n    cash = context.account().cash\r\n    print('定时检查资金:', cash['available'])\r\n```\r\n\r\n---\r\n\r\n## log - 日志\r\n\r\n**仅实时模式可用。**\r\n\r\n```python\r\nlog(level='info', msg='信号触发', source='strategy')\r\n```\r\n\r\n| level | 说明 |\r\n|-------|------|\r\n| `'info'` | 信息级别 |\r\n| `'warning'` | 警告级别 |\r\n| `'error'` | 错误级别 |\r\n\r\n---\r\n\r\n## add_parameter - 动态参数\r\n\r\n**仅实时模式可用，重启后重置。**\r\n\r\n```python\r\nadd_parameter(key='k_value', value=23, min=0, max=100,\r\n              name='K值阈值', intro='KDJ策略K值阈值',\r\n              group='1', readonly=False)\r\n```\r\n\r\n- 在终端 UI 界面显示和实时修改参数\r\n- 修改时触发 `on_parameter(context, parameter)` 事件\r\n\r\n```python\r\ndef on_parameter(context, parameter):\r\n    if parameter['name'] == 'K值阈值':\r\n        context.k_value = parameter['value']\r\n        print('参数已更新:', context.k_value)\r\n```\n\nFile v1.0.3:references/03-subscribe-events.md\n\n# 数据订阅与事件\r\n\r\n## subscribe - 订阅行情\r\n\r\n```python\r\nsubscribe(symbols, frequency='1d', count=1,\r\n          wait_group=False, wait_group_timeout='10s',\r\n          unsubscribe_previous=False, fields=None, format='df')\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbols | str or list | 标的代码，多个用英文逗号分隔 |\r\n| frequency | str | 频率：`'tick'`、`'60s'`、`'300s'`、`'900s'`、`'1800s'`、`'3600s'`、`'1d'`，L2：`'l2transaction'`、`'l2order'` |\r\n| count | int | 数据滑窗大小，`context.data` 可用的最大条数 |\r\n| wait_group | bool | 是否等同频率所有标的 bar 到齐再触发，默认 False |\r\n| wait_group_timeout | str | wait_group 超时，默认 `'10s'` |\r\n| unsubscribe_previous | bool | 是否取消之前订阅，默认 False |\r\n| fields | str | 指定返回字段，越少越快 |\r\n| format | str | 数据格式：`'df'`(DataFrame)、`'row'`(list[dict])、`'col'`(dict) |\r\n\r\n**性能说明**：`row > col > df`，对性能敏感时用 `format='row'`。\r\n\r\n```python\r\ndef init(context):\r\n    # 订阅日线，滑窗20条\r\n    subscribe(symbols='SHSE.600000,SZSE.000001', frequency='1d', count=20)\r\n    # 同时订阅分钟线\r\n    subscribe(symbols='SHSE.600000', frequency='60s', count=60)\r\n```\r\n\r\n---\r\n\r\n## unsubscribe - 取消订阅\r\n\r\n```python\r\nunsubscribe(symbols='*', frequency='60s')\r\n```\r\n\r\n- 默认取消所有已订阅行情\r\n- 只取消指定标的的指定频率，其他频率不受影响\r\n\r\n---\r\n\r\n## on_tick - Tick 数据事件\r\n\r\n```python\r\ndef on_tick(context, tick):\r\n    print(tick['symbol'], tick['price'])\r\n```\r\n\r\ntick 对象包含：`symbol`、`open`、`high`、`low`、`price`、`cum_volume`、`cum_amount`、`last_volume`、`last_amount`、`quotes`（5档买卖盘）、`created_at`\r\n\r\n---\r\n\r\n## on_bar - Bar 数据事件\r\n\r\n```python\r\ndef on_bar(context, bars):\r\n    for bar in bars:\r\n        print(bar['symbol'], bar['close'])\r\n```\r\n\r\nbars 是 list，单标的时长度为 1（wait_group=False），多标的全到时长度 > 1。\r\n\r\nbar 对象包含：`symbol`、`frequency`、`open`、`close`、`high`、`low`、`volume`、`amount`、`bob`、`eob`\r\n\r\n---\r\n\r\n## on_l2transaction - 逐笔成交（L2）\r\n\r\n> 仅特定付费券商可用\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='l2transaction')\r\n\r\ndef on_l2transaction(context, transaction):\r\n    print(transaction)\r\n```\r\n\r\n---\r\n\r\n## on_l2order - 逐笔委托（L2）\r\n\r\n> 仅特定付费券商可用，仅深市标的\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SZSE.000001', frequency='l2order')\r\n\r\ndef on_l2order(context, l2order):\r\n    print(l2order)\r\n```\r\n\r\n---\r\n\r\n## 交易事件回调\r\n\r\n| 函数 | 触发时机 |\r\n|------|--------|\r\n| `on_execution_report(context, execrpt)` | 委托执行时触发 |\r\n| `on_order_status(context, order)` | 委托状态变更时触发 |\r\n| `on_account_status(context, account)` | 账户状态变更时触发 |\r\n| `on_error(context, code, info)` | 发生异常时触发 |\r\n| `on_parameter(context, parameter)` | 动态参数修改时触发 |\r\n| `on_backtest_finished(context, indicator)` | 回测结束时触发 |\r\n\r\n### 回测结束事件示例\r\n```python\r\ndef on_backtest_finished(context, indicator):\r\n    print('累计收益率:', indicator['pnl_ratio'])\r\n    print('年化收益率:', indicator['pnl_ratio_annual'])\r\n    print('夏普比率:', indicator['sharp_ratio'])\r\n    print('最大回撤:', indicator['max_drawdown'])\r\n    print('胜率:', indicator['win_ratio'])\r\n```\r\n\r\n---\r\n\r\n## on_execution_report - 成交回报事件（✅ 已实测通过）\r\n\r\n> **触发时机**：每当有成交发生时触发（包括部分成交）\r\n> **实测环境**：回测模式 (MODE_BACKTEST)，SDK v3.0.183\r\n\r\n```python\r\ndef on_execution_report(context, execrpt):\r\n    \"\"\"\r\n    execrpt 对象关键字段（已验证）:\r\n      symbol       — str,   标的代码（如 'SHSE.600519'）\r\n      side         — int,   1=买入, 2=卖出\r\n      volume       — int,   成交数量（股）\r\n      price        — float, 成交均价\r\n      exec_type    — int/str, 回测中为数字15(成交确认), 实盘可能为'T'/'C'\r\n      commission   — float, 本笔手续费\r\n      cl_ord_id    — str,   客户端订单ID（系统生成）\r\n      order_id     — str,   柜台订单ID\r\n      created_at   — datetime, 成交时间\r\n    \"\"\"\r\n    # 推荐的兼容写法（支持 dict 和属性两种风格）:\r\n    if isinstance(execrpt, dict):\r\n        symbol = execrpt.get('symbol', '')\r\n        volume = execrpt.get('volume', 0)\r\n        price = execrpt.get('price', 0)\r\n    else:\r\n        symbol = getattr(execrpt, 'symbol', '')\r\n        volume = getattr(execrpt, 'volume', 0)\r\n        price = getattr(execrpt, 'price', 0)\r\n\r\n    print(f'成交: {symbol} {volume}股 @ {price}')\r\n```\r\n\r\n**实测行为（2026-04-17 验证）**：\r\n- `order_target_volume` 买入 → 触发 **1次** on_execution_report（全部成交汇总）\r\n- `order_target_volume` 卖出 → 触发 **1次** on_execution_report\r\n- 每笔成交回报都带 `commission` 手续费值\r\n- `exec_type` 在回测中返回数字 `15`，不是字符 `'T'`\r\n\r\n---\r\n\r\n## on_order_status - 委托状态变更事件（✅ 已实测通过）\r\n\r\n> **触发时机**：订单生命周期中的每个状态变化都会触发\r\n> **特别重要**：status=7(拒绝) 时包含拒单原因\r\n> **实测环境**：回测模式 (MODE_BACKTEST)，SDK v3.0.183\r\n\r\n```python\r\ndef on_order_status(context, order):\r\n    \"\"\"\r\n    order 对象关键字段（已验证）:\r\n      cl_ord_id          — str,   客户端订单ID\r\n      order_id           — str,   柜台订单ID\r\n      symbol             — str,   标的代码\r\n      status             — int,   委托状态（见下方枚举）\r\n      side               — int,   1=买, 2=卖\r\n      volume             — int,   委托总量\r\n      price              — float, 委托价格\r\n      filled_volume      — int,   已成交数量\r\n      filled_vwap        — float, 已成交均价\r\n      created_at         — datetime, 创建时间\r\n      rejection_reason   — str,   仅 status=7 时有值（拒单原因）\r\n    \"\"\"\r\n\r\n    # 状态码映射（完整版，含回测特有码）\r\n    status_map = {\r\n        1: '新建(New)',\r\n        2: '已报(Sent)',\r\n        3: '部分成交(PartiallyFilled)',\r\n        4: '已成交(Filled)',\r\n        5: '已撤(Cancelled)',\r\n        6: '未成交(Expired)',          # 限价超时未成交\r\n        7: '拒绝(Rejected)',            # ⚠️ 含 rejection_reason\r\n        8: '待撤(Cancelling)',          # 正在撤销\r\n        9: '未知(Unknown)',\r\n        10: '内部态(Internal)',          # ⚠️ 回测模式特有！文档未记录\r\n    }\r\n\r\n    status = order.get('status') if isinstance(order, dict) else getattr(order, status, None)\r\n    status_text = status_map.get(status, f'未知({status})')\r\n\r\n    if status == 7:\r\n        reason = order.get('rejection_reason') if isinstance(order, dict) \\\r\n                 else getattr(order, 'rejection_reason', None)\r\n        print(f'❌ 订单被拒绝! 原因: {reason}')\r\n```\r\n\r\n**实测状态流转（2026-04-17 验证）**：\r\n\r\n| 下单方式 | 触发的状态序列 | 备注 |\r\n|----------|---------------|------|\r\n| `order_volume` 市价买 | **10 → 8** | 资金不足时：内部态→待撤 |\r\n| `order_target_volume` 买 | **10 → 1 → 3** | 内部态→新建→部分成交 |\r\n| `order_target_volume` 卖 | **10 → 1 → 3** | 内部态→新建→部分成交 |\r\n| `order_volume` 限价(低价) | **10 → 8** | 不会成交→自动撤单 |\r\n| 超额卖出 | **10 → 8** | 回测不报Rejected，变Cancelling |\r\n| 超额买入(资金不足) | **10 → 8** | 同上 |\r\n\r\n**⚠️ 关键发现**：\r\n- **回测模式没有 Rejected(7)**：所有风控违规（超额/资金不足）都变为 Cancelling(8)\r\n- **要测试 Rejected(7)**：必须用 **live（仿真/实盘）** 模式\r\n- 状态 **10** 是回测内部中间态，每个订单首先收到一个 status=10\r\n- `order_target_volume` 会产生比 `order_volume` 更多的状态事件（多了 New → PartiallyFilled 流转）\n\nFile v1.0.3:references/04-market-data.md\n\n# 行情数据查询\r\n\r\n## current - 查询当前行情快照\r\n\r\n```python\r\ncurrent(symbols, fields='', include_call_auction=False)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbols | str or list | 标的代码 |\r\n| fields | str | 返回字段，默认所有 |\r\n| include_call_auction | bool | 是否支持集合竞价(09:15-09:25)取数，默认 False |\r\n\r\n**返回值**：`list[dict]`，每项是一个 tick 字典\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\nresult = current(symbols='SZSE.000001,SHSE.600000')\r\nfor item in result:\r\n    print(item['symbol'], item['price'])\r\n```\r\n\r\n**注意**：\r\n- 实时模式返回最新 tick，回测模式只有 symbol/price/created_at 有效\r\n- 集合竞价阶段有效字段只有 quotes\r\n\r\n**⚠️ 实时模式调用频次限制（2026-05-19 起）**：\r\n- 5分钟内最多调用 **100 次**\r\n- 24小时内最多调用 **1000 次**\r\n- **2026-06-01 起**：单次查询标的数量上限调整为 **50 个**\r\n\r\n> **强烈建议切换到新函数**：`last_tick`（多标的Tick快照）或 `current_price`（仅查最新价）完全不受上述频次限制，且返回数据更精简高效。详见下方说明。\r\n\r\n---\r\n\r\n## last_tick - 查询已订阅的最新 Tick（多标的，推荐替代 current）\r\n\r\n> **推荐理由**：不受 `current()` 的调用频次限制（5分钟100次/24小时1000次），返回数据更精简高效。\r\n\r\n```python\r\nlast_tick(symbols, fields=\"\", include_call_auction=False)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbols | str or list | 标的代码，多个用英文逗号隔开或列表格式 |\r\n| fields | str | 返回字段，默认所有（详见 tick 对象字段） |\r\n| include_call_auction | bool | 是否支持集合竞价(09:15-09:25)取数，默认 False |\r\n\r\n**返回值**：`list[dict]`，每个字典包含 `symbol`、`price`、`created_at` 等字段\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\n# 必须先订阅 tick 行情\r\nsubscribe(symbols='SZSE.000001,SHSE.600000', frequency='tick')\r\n\r\n# 查询最新 tick\r\nresult = last_tick(symbols='SZSE.000001,SHSE.600000', fields='symbol,price,open,created_at')\r\nfor item in result:\r\n    print(item['symbol'], item['price'])\r\n```\r\n\r\n**注意**：\r\n- 输入的 `symbols` **必须先通过 `subscribe` 订阅 tick 行情**；若未订阅，返回字典中除 `symbol` 外均为空\r\n- 实时模式获取集合竞价数据需指定 `include_call_auction=True`，集合竞价阶段有效字段仅 `quotes`\r\n- 回测模式需先订阅 tick，返回回测当前时刻最新的 `tick.price`\r\n\r\n---\r\n\r\n## current_price - 查询当前最新价（更轻量替代 current）\r\n\r\n> **推荐理由**：仅返回最新价，不受 `current()` 调用频次限制，数据量更小。\r\n\r\n```python\r\ncurrent_price(symbols)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbols | str or list | 标的代码，多个用英文逗号隔开或列表格式 |\r\n\r\n**返回值**：`list[dict]`，每个字典包含：\r\n\r\n| 字段 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbol | str | 标的代码，如 `SHSE.600000` |\r\n| price | float | 最新价；实时模式为当前 tick.price；回测模式根据订阅频度返回对应 bar.close 或 tick.price |\r\n| created_at | datetime | 创建时间 |\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\n# 查询单标的最新价\r\nresult = current_price(symbols='SZSE.000001')\r\nprint(result[0]['symbol'], result[0]['price'])\r\n\r\n# 查询多标的最新价\r\nresult = current_price(symbols='SZSE.000001,SHSE.600000')\r\n```\r\n\r\n**注意**：\r\n- 若输入包含无效标的代码，返回列表仅包含有效代码对应的字典\r\n- 回测模式：订阅 tick 或分钟 bar 后调用，返回当前时刻最新价；订阅日线时根据 `backtest_intraday` 参数决定返回值\r\n\r\n---\r\n\r\n## history - 查询历史行情\r\n\r\n```python\r\nhistory(symbol, frequency, start_time, end_time,\r\n        fields=None, skip_suspended=True, fill_missing=None,\r\n        adjust=ADJUST_NONE, adjust_end_time='', df=True)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbol | str or list | 标的代码，支持多标的 |\r\n| frequency | str | 频率：`'tick'`、`'60s'`、`'300s'`、`'1d'` 等 |\r\n| start_time | str/datetime | 开始时间 `%Y-%m-%d %H:%M:%S` |\r\n| end_time | str/datetime | 结束时间 `%Y-%m-%d %H:%M:%S` |\r\n| fields | str | 指定字段，默认全部 |\r\n| adjust | int | 复权：`ADJUST_NONE=0`、`ADJUST_PREV=1`、`ADJUST_POST=2` |\r\n| adjust_end_time | str | 复权基点时间，默认当前 |\r\n| df | bool | True=返回 DataFrame，False=返回 list[dict] |\r\n\r\n```python\r\n# 查询日线（前复权），返回 DataFrame\r\ndf = history(symbol='SHSE.600000', frequency='1d',\r\n             start_time='2024-01-01', end_time='2024-12-31',\r\n             fields='open,high,low,close,volume,eob',\r\n             adjust=ADJUST_PREV, df=True)\r\n\r\n# 查询多标的\r\ndf = history(symbol='SHSE.600000,SZSE.000001', frequency='1d',\r\n             start_time='2024-01-01', end_time='2024-01-31',\r\n             df=True)\r\n\r\n# 返回 list[dict]\r\ndata = history(symbol='SHSE.000300', frequency='1d',\r\n               start_time='2024-01-01', end_time='2024-01-05',\r\n               adjust=ADJUST_PREV, df=False)\r\n```\r\n\r\n**注意**：\r\n- 数据区间采用**前开后闭**方式，按 eob 升序排序\r\n- 单次最多返回 33000 条\r\n- start_time/end_time 输入不存在的日期会报错\r\n- `skip_suspended` 和 `fill_missing` 目前暂不支持\r\n\r\n---\r\n\r\n## history_n - 查询最新 N 条历史行情\r\n\r\n```python\r\nhistory_n(symbol, frequency, count, end_time=None,\r\n          fields=None, skip_suspended=True, fill_missing=None,\r\n          adjust=ADJUST_NONE, adjust_end_time='', df=False)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 单标的代码（不支持多标的） |\r\n| count | 取最新 N 条 |\r\n| end_time | 结束时间，默认 None（取实际当前时间，非回测时间） |\r\n\r\n```python\r\n# 取最新100条日线（前复权）\r\ndf = history_n(symbol='SHSE.600519', frequency='1d', count=100,\r\n               end_time='2024-12-31 15:30:00',\r\n               fields='symbol,open,close,high,low,eob',\r\n               adjust=ADJUST_PREV, df=True)\r\nprint(df.tail())\r\n```\r\n\r\n---\r\n\r\n## context.data - 获取订阅数据滑窗\r\n\r\n> 必须先调用 `subscribe` 才能使用\r\n\r\n```python\r\ndata = context.data(symbol, frequency, count, fields)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 单标的（不支持多标的） |\r\n| frequency | 必须是已订阅的频率 |\r\n| count | 必须 ≤ subscribe 里的 count |\r\n| fields | 必须在 subscribe 的 fields 范围内 |\r\n\r\n返回格式与 subscribe 的 format 参数一致：\r\n- `format='df'`（默认）→ DataFrame\r\n- `format='row'` → list[dict]\r\n- `format='col'` → dict（col 模式下 tick 的 quotes 被拆分，只有买卖一档）\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600519', frequency='60s', count=50,\r\n              fields='symbol,close,eob', format='df')\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol=bars[0]['symbol'], frequency='60s', count=20)\r\n    ma5 = data['close'].rolling(5).mean()\r\n    print(ma5.tail())\r\n```\n\nFile v1.0.3:references/05-l2-data.md\n\n# L2 行情数据查询（付费专项）\r\n\r\n> 以下所有接口**仅特定付费券商托管版**可用\r\n\r\n## get_history_l2ticks - 查询历史 L2 Tick\r\n\r\n```python\r\nget_history_l2ticks(symbols, start_time, end_time, fields=None,\r\n                    skip_suspended=True, fill_missing=None,\r\n                    adjust=ADJUST_NONE, adjust_end_time='', df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据；时间跨度超过 31 天则返回空。\r\n\r\n```python\r\nticks = get_history_l2ticks('SHSE.600519', '2024-11-23 14:00:00',\r\n                             '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n---\r\n\r\n## get_history_l2bars - 查询历史 L2 Bar\r\n\r\n```python\r\nget_history_l2bars(symbols, frequency, start_time, end_time,\r\n                   fields=None, skip_suspended=True, fill_missing=None,\r\n                   adjust=ADJUST_NONE, adjust_end_time='', df=False)\r\n```\r\n\r\n**限制**：每次最多取 **31 天**（1 个自然月）。\r\n\r\n```python\r\nbars = get_history_l2bars('SHSE.600000', '60s',\r\n                          '2024-11-01 09:30:00', '2024-11-30 15:30:00',\r\n                          df=True)\r\n```\r\n\r\n---\r\n\r\n## get_history_l2transactions - 查询历史 L2 逐笔成交\r\n\r\n```python\r\nget_history_l2transactions(symbols, start_time, end_time, fields=None, df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据。\r\n\r\n```python\r\ntrans = get_history_l2transactions('SHSE.600000',\r\n                                   '2024-11-23 14:00:00',\r\n                                   '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n返回字段：`symbol`、`side`（沪市：B/S/N）、`price`、`volume`、`exec_type`（深市：4=撤单，F=成交）、`created_at`\r\n\r\n---\r\n\r\n## get_history_l2orders - 查询历史 L2 逐笔委托\r\n\r\n> 仅深市标的可用\r\n\r\n```python\r\nget_history_l2orders(symbols, start_time, end_time, fields=None, df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据。\r\n\r\n```python\r\norders = get_history_l2orders('SZSE.000001',\r\n                              '2024-11-23 14:00:00',\r\n                              '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n返回字段：`symbol`、`side`（深市：1=买，2=卖，F=借入，G=出借；沪市：B=买，S=卖）、`price`、`volume`、`order_type`、`order_index`、`created_at`\r\n\r\n---\r\n\r\n## get_history_l2orders_queue - 查询历史 L2 委托队列\r\n\r\n```python\r\nget_history_l2orders_queue(symbols, start_time, end_time, fields=None, df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据。\r\n\r\n```python\r\nqueue = get_history_l2orders_queue('SZSE.000001',\r\n                                   '2024-11-23 14:00:00',\r\n                                   '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n返回字段：`symbol`、`price`、`total_orders`（委托总数）、`queue_orders`（队列数）、`queue_volumes`（前50个委托量列表）、`side`、`volume`、`created_at`\n\nFile v1.0.3:references/06-symbol-info.md\n\n# 标的信息查询\r\n\r\n## get_symbol_infos - 查询标的基本信息（静态信息）\r\n\r\n> 与时间无关，返回标的基础属性\r\n\r\n```python\r\nget_symbol_infos(sec_type1, sec_type2=None, exchanges=None, symbols=None, df=False)\r\n```\r\n\r\n| 参数 | 类型 | 必填 | 说明 |\r\n|------|------|------|------|\r\n| sec_type1 | int | **是** | 证券大类：1010=股票，1020=基金，1030=债券，1040=期货，1050=期权，1060=指数，1070=板块 |\r\n| sec_type2 | int | 否 | 证券细类（见下表） |\r\n| exchanges | str/list | 否 | 交易所代码，如 `'SHSE,SZSE'` |\r\n| symbols | str/list | 否 | 标的代码 |\r\n| df | bool | 否 | True=DataFrame，False=list[dict] |\r\n\r\n**sec_type2 细类表**：\r\n- 股票：101001=A股，101002=B股，101003=存托凭证\r\n- 基金：102001=ETF，102002=LOF，102005=FOF\r\n- 债券：103001=可转债，103003=国债，103006=企业债，103008=回购\r\n- 期货：104001=股指期货，104003=商品期货，104006=国债期货\r\n- 期权：105001=股票期权，105002=指数期权，105003=商品期权\r\n- 指数：106001=股票指数，106002=基金指数，106003=债券指数\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\n# 查询指定股票\r\ninfos = get_symbol_infos(sec_type1=1010, symbols='SHSE.600000,SZSE.000001', df=True)\r\n\r\n# 查询全部 A 股\r\ninfos = get_symbol_infos(sec_type1=1010, sec_type2=101001, df=True)\r\n\r\n# 查询全部 ETF\r\ninfos = get_symbol_infos(sec_type1=1020, sec_type2=102001, df=True)\r\n\r\n# 查询全部可转债\r\ninfos = get_symbol_infos(sec_type1=1030, sec_type2=103001, df=True)\r\n\r\n# 查询上交所股票期权\r\ninfos = get_symbol_infos(sec_type1=1050, sec_type2=105001, exchanges='SHSE', df=True)\r\n```\r\n\r\n**返回字段**：`symbol`、`sec_type1`、`sec_type2`、`board`、`exchange`、`sec_id`、`sec_name`、`sec_abbr`、`price_tick`、`trade_n`、`listed_date`、`delisted_date`、`underlying_symbol`（期货/期权/可转债）、`option_type`（欧式E/美式A）、`call_or_put`（C/P）\r\n\r\n---\r\n\r\n## get_symbols - 查询指定交易日多标的交易信息\r\n\r\n> 返回基本信息 + 当日行情信息（涨跌停、换手率等）\r\n\r\n```python\r\nget_symbols(sec_type1, sec_type2=None, exchanges=None, symbols=None,\r\n            skip_suspended=True, skip_st=True, trade_date=None, df=False)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| skip_suspended | 是否跳过停牌，默认 True |\r\n| skip_st | 是否跳过 ST 类股票，默认 True |\r\n| trade_date | 交易日期 `%Y-%m-%d`，默认 None=最新截面 |\r\n\r\n```python\r\n# 获取全 A 股今日信息（含涨跌停价）\r\ndf = get_symbols(sec_type1=1010, sec_type2=101001, df=True)\r\nsymbols_list = df['symbol'].tolist()\r\n\r\n# 指定交易日\r\ndf = get_symbols(sec_type1=1010, symbols='SHSE.600000,SZSE.000001',\r\n                 trade_date='2024-01-15', df=True)\r\n```\r\n\r\n**额外返回字段（比 get_symbol_infos 多）**：\r\n`trade_date`、`pre_close`、`upper_limit`（涨停价）、`lower_limit`（跌停价）、`turn_rate`（换手率%）、`adj_factor`（复权因子）、`is_suspended`（是否停牌）、`is_st`（是否ST）、`margin_ratio`（期货保证金比例）、`multiplier`（合约乘数）\r\n\r\n---\r\n\r\n## get_history_symbol - 查询指定标的多日历史交易信息\r\n\r\n```python\r\nget_history_symbol(symbol=None, start_date=None, end_date=None, df=False)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 单个标的代码（必填） |\r\n| start_date | 开始日期 `%Y-%m-%d` |\r\n| end_date | 结束日期 `%Y-%m-%d` |\r\n\r\n```python\r\n# 查询某标的历史涨跌停价变化\r\ndf = get_history_symbol(symbol='SHSE.600000',\r\n                        start_date='2024-01-01',\r\n                        end_date='2024-12-31', df=True)\r\n```\r\n\r\n**注意**：`get_history_symbol` 可在 `init` 里批量预取，按 (symbol, date) 做索引，提高回测效率：\r\n```python\r\ndef init(context):\r\n    instruments = get_history_symbol(symbol='SZSE.000001',\r\n                                     start_date=context.backtest_start_time,\r\n                                     end_date=context.backtest_end_time)\r\n    context.ins_dict = {(i.symbol, i.trade_date.date()): i for i in instruments}\r\n\r\ndef on_bar(context, bars):\r\n    info = context.ins_dict[(bars[0].symbol, bars[0].eob.date())]\r\n    print(info.upper_limit)\r\n```\n\nFile v1.0.3:references/07-trading-dates.md\n\n# 交易日历查询\r\n\r\n## get_trading_dates - 查询交易日列表\r\n\r\n```python\r\nget_trading_dates(exchange, start_date, end_date, df=False)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| exchange | str | 交易所代码：`'SHSE'`、`'SZSE'`、`'CFFEX'`、`'SHFE'`、`'DCE'`、`'CZCE'` 等 |\r\n| start_date | str | 开始日期 `%Y-%m-%d` |\r\n| end_date | str | 结束日期 `%Y-%m-%d` |\r\n| df | bool | True=DataFrame，False=list[datetime] |\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\n# 获取上交所 2024 年全年交易日\r\ndates = get_trading_dates('SHSE', '2024-01-01', '2024-12-31')\r\nprint(f'2024年共 {len(dates)} 个交易日')\r\n\r\n# 返回 DataFrame\r\ndf = get_trading_dates('SHSE', '2024-01-01', '2024-01-31', df=True)\r\n```\r\n\r\n---\r\n\r\n## get_previous_trading_date - 查询上一交易日\r\n\r\n```python\r\nget_previous_trading_date(exchange, date)\r\n```\r\n\r\n```python\r\nprev = get_previous_trading_date('SHSE', '2024-01-15')\r\nprint('上一交易日:', prev)  # datetime 对象\r\n```\r\n\r\n---\r\n\r\n## get_next_trading_date - 查询下一交易日\r\n\r\n```python\r\nget_next_trading_date(exchange, date)\r\n```\r\n\r\n```python\r\nnext_day = get_next_trading_date('SHSE', '2024-01-15')\r\nprint('下一交易日:', next_day)\r\n```\r\n\r\n---\r\n\r\n## 实用场景\r\n\r\n### 判断今天是否交易日\r\n```python\r\nfrom gm.api import *\r\nfrom datetime import date\r\n\r\nset_token('YOUR_TOKEN')\r\ntoday = str(date.today())\r\ndates = get_trading_dates('SHSE', today, today)\r\nis_trading = len(dates) > 0\r\nprint('今天是否交易日:', is_trading)\r\n```\r\n\r\n### 获取本月所有交易日\r\n```python\r\nimport calendar\r\nfrom datetime import date\r\n\r\nyear, month = 2024, 12\r\n_, last_day = calendar.monthrange(year, month)\r\nstart = f'{year}-{month:02d}-01'\r\nend = f'{year}-{month:02d}-{last_day}'\r\ndates = get_trading_dates('SHSE', start, end)\r\nprint(f'{year}年{month}月共 {len(dates)} 个交易日')\r\n```\n\nFile v1.0.3:references/08-order-api.md\n\n# 交易下单 API\r\n\r\n> 所有下单函数只能在策略事件回调中使用（`on_bar`、`on_tick`、`algo` 定时任务等）\r\n> 回测模式下 `init` 中不支持交易操作\r\n\r\n## 常用枚举常量\r\n\r\n```python\r\n# 买卖方向\r\nOrderSide_Buy = 1   # 买入\r\nOrderSide_Sell = 2  # 卖出\r\n\r\n# 委托类型\r\nOrderType_Limit = 1    # 限价\r\nOrderType_Market = 2   # 市价\r\n\r\n# 开平标志\r\nPositionEffect_Open = 1   # 开仓\r\nPositionEffect_Close = 2  # 平仓（平昨）\r\nPositionEffect_Close_Today = 3  # 平今（期货）\r\n\r\n# 持仓方向\r\nPositionSide_Long = 1   # 多头\r\nPositionSide_Short = 2  # 空头\r\n```\r\n\r\n---\r\n\r\n## order_volume - 按数量下单\r\n\r\n```python\r\norder_volume(symbol, volume, side, order_type, position_effect,\r\n             price=0, account=None)\r\n```\r\n\r\n```python\r\n# 市价买入200股\r\norder_volume(symbol='SHSE.600000', volume=200, side=OrderSide_Buy,\r\n             order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n\r\n# 限价卖出100股\r\norder_volume(symbol='SZSE.000001', volume=100, side=OrderSide_Sell,\r\n             order_type=OrderType_Limit, position_effect=PositionEffect_Close, price=16.5)\r\n```\r\n\r\n---\r\n\r\n## order_value - 按金额下单\r\n\r\n```python\r\norder_value(symbol, value, side, order_type, position_effect,\r\n            price=0, account=None)\r\n```\r\n\r\n```python\r\n# 买入10000元的股票\r\norder_value(symbol='SHSE.600000', value=10000, side=OrderSide_Buy,\r\n            order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n```\r\n\r\n---\r\n\r\n## order_percent - 按账户总资产比例下单\r\n\r\n```python\r\norder_percent(symbol, percent, side, order_type, position_effect,\r\n              price=0, account=None)\r\n```\r\n\r\n```python\r\n# 买入账户总资产的1%\r\norder_percent(symbol='SHSE.600000', percent=0.01, side=OrderSide_Buy,\r\n              order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n```\r\n\r\n---\r\n\r\n## order_target_volume - 调仓到目标数量\r\n\r\n> 自动计算差值，决定买入或卖出\r\n\r\n```python\r\norder_target_volume(symbol, volume, position_side=PositionSide_Long,\r\n                    order_type=OrderType_Market, price=0, account=None)\r\n```\r\n\r\n```python\r\n# 调整到持有500股（多头）\r\norder_target_volume(symbol='SHSE.600000', volume=500,\r\n                    position_side=PositionSide_Long,\r\n                    order_type=OrderType_Market)\r\n```\r\n\r\n---\r\n\r\n## order_target_value - 调仓到目标金额\r\n\r\n```python\r\norder_target_value(symbol, value, position_side=PositionSide_Long,\r\n                   order_type=OrderType_Market, price=0, account=None)\r\n```\r\n\r\n---\r\n\r\n## order_target_percent - 调仓到目标比例\r\n\r\n```python\r\norder_target_percent(symbol, percent, position_side=PositionSide_Long,\r\n                     order_type=OrderType_Market, price=0, account=None)\r\n```\r\n\r\n```python\r\n# 调整到账户总资产的10%\r\norder_target_percent(symbol='SHSE.600000', percent=0.1,\r\n                     position_side=PositionSide_Long,\r\n                     order_type=OrderType_Market)\r\n```\r\n\r\n---\r\n\r\n## order_cancel - 撤销委托\r\n\r\n```python\r\norder_cancel(wait_cancel_orders, account=None)\r\n```\r\n\r\n```python\r\n# 撤销指定委托\r\norders = get_orders()  # 先获取委托列表\r\norder_cancel(wait_cancel_orders=orders)\r\n```\r\n\r\n---\r\n\r\n## order_close_all - 一键平仓\r\n\r\n```python\r\norder_close_all()\r\n```\r\n\r\n- 平掉当前账户所有持仓\r\n\r\n---\r\n\r\n## 实用组合示例\r\n\r\n```python\r\ndef on_bar(context, bars):\r\n    bar = bars[0]\r\n    symbol = bar['symbol']\r\n    \r\n    # 获取当前持仓\r\n    pos = context.account().position(symbol=symbol, side=PositionSide_Long)\r\n    \r\n    # 无持仓时买入\r\n    if not pos:\r\n        cash = context.account().cash\r\n        available = cash['available']\r\n        if available > 10000:\r\n            order_percent(symbol=symbol, percent=0.1, side=OrderSide_Buy,\r\n                          order_type=OrderType_Market,\r\n                          position_effect=PositionEffect_Open)\r\n    else:\r\n        # 已有持仓时全部卖出\r\n        order_target_volume(symbol=symbol, volume=0,\r\n                            position_side=PositionSide_Long,\r\n                            order_type=OrderType_Market)\r\n```\n\nFile v1.0.3:references/09-algo-order.md\n\n# 算法委托（TWAP/VWAP 等）\r\n\r\n## algo_order - 算法下单\r\n\r\n```python\r\nalgo_order(symbol, volume, side, position_effect, order_type,\r\n           price=0, algo_name='', algo_param={}, account=None)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 标的代码 |\r\n| volume | 委托量 |\r\n| side | 买卖方向（OrderSide_Buy/Sell） |\r\n| position_effect | 开平标志 |\r\n| order_type | 委托类型 |\r\n| algo_name | 算法名称，如 `'TWAP'`、`'VWAP'` |\r\n| algo_param | 算法参数 dict |\r\n\r\n```python\r\n# TWAP 算法买入\r\nalgo_order(symbol='SHSE.600000', volume=1000, side=OrderSide_Buy,\r\n           position_effect=PositionEffect_Open,\r\n           order_type=OrderType_Market,\r\n           algo_name='TWAP',\r\n           algo_param={'start_time': '09:30:00', 'end_time': '15:00:00'})\r\n```\r\n\r\n## algo_order_cancel - 取消算法委托\r\n\r\n```python\r\nalgo_order_cancel(wait_cancel_algo_orders, account=None)\r\n```\r\n\r\n---\r\n\r\n# 账户与资金查询\r\n\r\n## get_orders - 查询委托列表\r\n\r\n```python\r\nget_orders(account=None)\r\n```\r\n\r\n返回 `list[dict]`，每项为 Order 委托对象。\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\norders = get_orders()\r\nfor order in orders:\r\n    print(order['symbol'], order['status'], order['volume'])\r\n```\r\n\r\n**委托状态 OrderStatus**：\r\n- 1=待报，2=已报，3=已报待撤，4=部成待撤，5=部撤，6=已撤，7=已成，8=废单，10=已报待改\r\n\r\n---\r\n\r\n## get_execution_reports - 查询成交回报\r\n\r\n```python\r\nget_execution_reports(account=None)\r\n```\r\n\r\n返回 `list[dict]`，每项为 ExecRpt 回报对象。\r\n\r\n---\r\n\r\n## get_cash - 查询账户资金\r\n\r\n```python\r\nget_cash(account=None)\r\n```\r\n\r\n返回资金 dict：\r\n\r\n| 字段 | 说明 |\r\n|------|------|\r\n| nav | 总资产 |\r\n| available | 可用资金 |\r\n| fpnl | 浮动盈亏 |\r\n| market_value | 持仓市值 |\r\n| balance | 资金余额 |\r\n| order_frozen | 冻结资金 |\r\n\r\n```python\r\ncash = get_cash()\r\nprint(f\"总资产: {cash['nav']:.2f}\")\r\nprint(f\"可用资金: {cash['available']:.2f}\")\r\n```\r\n\r\n---\r\n\r\n## get_position - 查询持仓\r\n\r\n```python\r\nget_position(symbol=None, side=None, account=None)\r\n```\r\n\r\n```python\r\n# 查询全部持仓\r\npositions = get_position()\r\n\r\n# 查询指定标的多头持仓\r\npos = get_position(symbol='SHSE.600000', side=PositionSide_Long)\r\nif pos:\r\n    print(f\"持仓量: {pos[0]['volume']}\")\r\n    print(f\"持仓均价: {pos[0]['vwap']}\")\r\n    print(f\"浮动盈亏: {pos[0]['fpnl']}\")\r\n```\r\n\r\n**Position 对象关键字段**：\r\n\r\n| 字段 | 说明 |\r\n|------|------|\r\n| symbol | 标的代码 |\r\n| side | 持仓方向 |\r\n| volume | 总持仓量 |\r\n| volume_today | 今日买入量 |\r\n| available | 可用持仓（非冻结） |\r\n| vwap | 持仓均价 |\r\n| market_value | 持仓市值 |\r\n| fpnl | 浮动盈亏 |\r\n| amount | 持仓额 |\r\n\r\n---\r\n\r\n## context.account() - 在策略中查询账户\r\n\r\n```python\r\n# 获取所有持仓\r\nall_positions = context.account().positions()\r\n\r\n# 获取指定持仓\r\npos = context.account().position(symbol='SHSE.600519', side=PositionSide_Long)\r\n\r\n# 获取资金\r\ncash = context.account().cash\r\n\r\n# 账户状态\r\nstatus = context.account().status\r\n```\n\nArchive v1.0.2: 33 files, 91104 bytes\n\nFiles: README.md (5750b), references/01-quick-start.md (3240b), references/02-core-functions.md (3448b), references/03-subscribe-events.md (8188b), references/04-market-data.md (4163b), references/05-l2-data.md (2886b), references/06-symbol-info.md (4317b), references/07-trading-dates.md (1904b), references/08-order-api.md (4221b), references/09-algo-order.md (3172b), references/10-account-query.md (510b), references/11-bond-convertible.md (1725b), references/12-data-objects.md (3137b), references/13-enums.md (2189b), references/14-context.md (2489b), references/16-premium-data-apis.md (5855b), references/17-financial-data-fields.md (7528b), references/18-user-guide.md (18464b), scripts/check_import.py (2479b), scripts/run_strategy.py (4672b), scripts/strategy_etf_momentum_rotation.py (12635b), scripts/strategy_etf_momentum.py (11113b), scripts/strategy_etf_rotation.py (11611b), scripts/strategy_event_callbacks_test.py (20973b), scripts/strategy_high_dividend.py (14302b), scripts/strategy_ma_cross.py (4124b), scripts/strategy_xinyisheng_ma.py (4126b), scripts/test_account_apis.py (4653b), scripts/test_all_apis.py (8710b), scripts/test_financial_apis.py (8782b), SKILL.md (34763b), TEST_REPORT.md (4764b), _meta.json (126b)\n\nFile v1.0.2:SKILL.md\n\n---\r\nname: gm-quant\r\nversion: 2.0.0\r\ndescription: >\r\n  掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、\r\n  量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、\r\n  order_volume、subscribe、history、set_token、get_symbols、get_symbol_infos、\r\n  get_history_symbol、history_n、current、get_trading_dates、\r\n  order_percent、order_value、order_target_volume、algo_order、\r\n  get_orders、get_position、get_cash、bond_convertible、\r\n  L2行情、逐笔成交、逐笔委托、schedule定时任务、\r\n  财务数据、资产负债表、利润表、现金流量表、估值指标、PE/PB/PS/股息率、\r\n  市值、股本、流通股、成分股、行业分类、\r\n  可转债分析、转股溢价率、纯债价值、ETF成分股、基金净值、\r\n  期货合约信息、仓单数据、成交持仓排名、\r\n  stk_get_fundamentals、stk_get_daily_valuation、stk_get_index_constituents、\r\n  bnd_get_analysis、fnd_get_portfolio、fut_get_contract_info\r\n  时，自动加载此 skill。\r\n---\r\n\r\n# 掘金量化 SDK 技能 — v2.0 自然语言策略引擎\r\n\r\n## 定位\r\n\r\n你是**掘金量化平台的自然语言策略助手**。用户用中文描述交易想法，你负责：\r\n1. **理解需求** → 提炼策略逻辑（标的/信号/风控）\r\n2. **生成代码** → 输出可直接运行的完整策略 `.py` 文件\r\n3. **执行运行** → 调用 `scripts/run_strategy.py` 一键启动回测或实盘\r\n\r\n## 核心原则\r\n\r\n1. **必须先 set_token**：纯数据查询（非策略 run）场景下，代码开头必须调用 `set_token('your_token')`。\r\n2. **symbol 格式**：`交易所代码.证券代码`，如 `SHSE.600000`、`SZSE.000001`，**严格区分大小写**。\r\n3. **gm 包通过掘金终端连接**：终端必须保持打开，否则接口会超时或报错。\r\n4. **两种模式**：`MODE_LIVE=1`（实时/仿真）、`MODE_BACKTEST=2`（回测）；`run()` 函数启动策略。\r\n5. **数据查询不需要 run**：仅用 `set_token` 后直接调用数据函数即可。\r\n\r\n## 🚀 用户工作流（自然语言→运行）\r\n\r\n### 第 0 步：确认 Strategy ID（重要！）\r\n\r\n**每次生成策略前，必须向用户索要 `strategy_id`。**\r\n\r\n`strategy_id` 是策略在掘金终端中的唯一标识。填写后：\r\n- 回测结果**持久化**到掘金终端后台\r\n- 用户登录 [掘金终端网页](https://www.myquant.cn) → 策略列表 → 查看完整的**绩效分析图表**\r\n  （收益曲线、回撤分析、夏普比率、持仓明细等）\r\n\r\n> **交互方式**：如果用户没有主动提供 strategy_id，在生成代码前询问：\r\n> \"请给我一个 **strategy_id**（英文/数字/下划线），用于在掘金终端标识这个策略。\r\n> 填完后你可以在终端网页上看到绩效分析图表。例如：`ma_cross_600519`、`momentum_v1`\"\r\n\r\n| 场景 | 处理方式 |\r\n|------|---------|\r\n| 用户提供了 strategy_id | 直接使用 |\r\n| 用户没提供 | **必须追问**，不能自己编造一个默认值后静默使用 |\r\n| 用户说\"随便起一个\" | 根据策略特征起一个有意义的名字（如 `dual_ma_kweichow`） |\r\n\r\n### 第一步：理解用户意图\r\n\r\n当用户用自然语言描述策略时，按以下维度提取信息：\r\n\r\n| 维度 | 需确认的信息 | 默认值（如未明确说明） |\r\n|------|-------------|---------------------|\r\n| **strategy_id** | 策略在掘金终端的标识（**必须用户提供，见第0步**） | 无默认，必须询问 |\r\n| **标的池** | 哪些股票/指数？ | 沪深300成分股 |\r\n| **时间频率** | 日线/分钟线/tick？ | 日线 `1d` |\r\n| **买入信号** | 什么条件买入？（均线/指标/事件） | 必须明确，不能猜测 |\r\n| **卖出信号** | 什么条件卖出？ | 必须明确，不能猜测 |\r\n| **仓位管理** | 全仓/固定金额/比例/等权 | 等权分配 |\r\n| **止损止盈** | 有无？阈值多少？ | 无 |\r\n| **回测区间** | 开始~结束日期 | 最近1年 |\r\n| **初始资金** | 多少钱？ | 100万 |\r\n| **运行模式** | 回测还是实盘？ | 先回测 |\r\n\r\n> ⚠️ **如果用户描述模糊（如\"帮我做个赚钱的策略\"），必须追问具体条件后再生成代码。**\r\n\r\n### 第二步：生成策略文件\r\n\r\n使用下方**标准策略模板**生成完整 `.py` 文件，保存到用户的输出目录：\r\n\r\n```python\r\n\"\"\"\r\n策略名称：{name}\r\n策略描述：{description}\r\n生成时间：{date}\r\n\"\"\"\r\n\r\nimport sys, os, io\r\nsys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')\r\n\r\nfrom gm.api import *\r\n\r\n# ============================================================\r\n# 配置区 —— 用户可通过修改此处调整策略参数\r\n# ============================================================\r\nSYMBOLS = 'SHSE.600519,SZSE.000001'      # 标的（逗号分隔）\r\nFREQUENCY = '1d'                          # K线周期：1d/60s/300s/tick\r\nCOUNT = 20                                # 订阅K线数量（context.data滑窗大小）\r\n\r\n# 交易参数\r\nORDER_TYPE = OrderType_Market              # 下单方式：Market(市价) / Limit(限价)\r\nPOSITION_PCT = 0.2                        # 单只股票仓位占比（0~1）\r\n\r\n# 回测参数\r\nBACKTEST_START = '2024-01-02 09:30:00'\r\nBACKTEST_END   = '2025-12-31 15:30:00'\r\nINITIAL_CASH   = 1000000                  # 初始资金\r\nCOMMISSION     = 0.00025                  # 手续费率\r\nSLIPPAGE       = 0.001                    # 滑点\r\n\r\n\r\n# ============================================================\r\n# 策略逻辑\r\n# ============================================================\r\n\r\ndef init(context):\r\n    \"\"\"初始化：订阅行情\"\"\"\r\n    log.info(f'策略启动 | 标的:{SYMBOLS} | 周期:{FREQUENCY}')\r\n    subscribe(symbols=SYMBOLS, frequency=FREQUENCY, count=COUNT)\r\n\r\n    # 存储策略状态\r\n    context.last_signal = {}  # {symbol: last_signal_time}\r\n\r\n\r\ndef on_bar(context, bars):\r\n    \"\"\"每根K线触发\"\"\"\r\n    for bar in bars:\r\n        symbol = bar['symbol']\r\n        try:\r\n            _handle_bar(context, symbol)\r\n        except Exception as e:\r\n            log.error(f'处理{symbol}异常: {e}')\r\n\r\n\r\ndef on_tick(context, tick):\r\n    \"\"\"tick级别回调（如订阅了tick会走这里）\"\"\"\r\n    pass\r\n\r\n\r\ndef _handle_bar(context, symbol):\r\n    \"\"\"单只标的策略逻辑\"\"\"\r\n\r\n    # 1. 获取历史数据（滑窗内）—— 注意返回 DataFrame\r\n    data = context.data(symbol=symbol, frequency=FREQUENCY, count=COUNT)\r\n    if data is None or len(data) < COUNT:\r\n        return\r\n\r\n    # 2. 获取当前持仓 —— get_position() 不带参数，返回全部持仓列表\r\n    all_positions = get_position()\r\n    position = None\r\n    if all_positions:\r\n        for p in all_positions:\r\n            sym = p.get('symbol') if isinstance(p, dict) else (p.symbol if hasattr(p, 'symbol') else None)\r\n            if sym == symbol:\r\n                position = p\r\n                break\r\n\r\n    # ========================================\r\n    # 【策略核心】在此处实现买卖信号\r\n    # ========================================\r\n\r\n    # 示例：双均线策略\r\n    close = data['close'].tolist()\r\n    ma_short = sum(close[-5:]) / 5    # MA5\r\n    ma_long  = sum(close[-20:]) / 20  # MA20\r\n    prev_ma5 = sum(close[-6:-1]) / 5 if len(close) >= 6 else ma_short\r\n    prev_ma20 = sum(close[-26:-6]) / 20 if len(close) >= 27 else ma_long\r\n\r\n    buy_signal  = (prev_ma5 <= prev_ma20) and (ma_short > ma_long)\r\n    sell_signal = (prev_ma5 >= prev_ma20) and (ma_short < ma_long)\r\n\r\n    # ========================================\r\n    # 3. 执行交易\r\n    # ========================================\r\n\r\n    current_price = close[-1]\r\n    cash_info = get_cash()\r\n\r\n    if buy_signal and not position:\r\n        # 买入：按仓位比例计算金额\r\n        available = cash_info.available\r\n        order_value = available * POSITION_PCT\r\n        if order_value > 10000:  # 最少1万元\r\n            volume = int(order_value / current_price / 100) * 100  # A股必须100股整数倍\r\n            order_volume(symbol, volume,\r\n                         side=OrderSide_Buy,\r\n                         position_effect=PositionEffect_Open,\r\n                         order_type=ORDER_TYPE)\r\n            print(f'[买入] {symbol} 价格={current_price:.2f} 数量={volume}')\r\n\r\n    elif sell_signal and position:\r\n        # 卖出：清仓该标的（注意用 position_side 不是 position_effect）\r\n        order_target_volume(symbol, 0,\r\n                            position_side=PositionSide_Long,\r\n                            order_type=ORDER_TYPE)\r\n        print(f'[卖出] {symbol} 价格={current_price:.2f}')\r\n\r\n\r\ndef handle_error(context, error_code, error_msg, **kwargs):\r\n    \"\"\"错误处理\"\"\"\r\n    log.error(f'策略异常 [{error_code}]: {msg}')\r\n\r\n\r\n# ============================================================\r\n# 启动入口\r\n# ============================================================\r\nif __name__ == '__main__':\r\n    # 从环境变量读取参数（由 run_strategy.py 传入）\r\n    TOKEN = os.environ.get('GM_TOKEN', '') or ''\r\n    MODE = os.environ.get('GM_RUN_MODE', 'backtest')\r\n    STRATEGY_ID = os.environ.get('GM_STRATEGY_ID', '') or 'my_strategy'\r\n    START = os.environ.get('GM_BACKTEST_START', BACKTEST_START)\r\n    END = os.environ.get('GM_BACKTEST_END', BACKTEST_END)\r\n    CASH = float(os.environ.get('GM_INITIAL_CASH', str(INITIAL_CASH)))\r\n\r\n    mode = MODE_LIVE if MODE.lower() in ('live', 'realtime') else MODE_BACKTEST\r\n\r\n    run(\r\n        strategy_id=STRATEGY_ID,\r\n        filename=__file__[:__file__.rfind('.')] if '.' in __file__ else __file__,\r\n        mode=mode,\r\n        token=TOKEN,\r\n        backtest_start_time=START,\r\n        backtest_end_time=END,\r\n        backtest_initial_cash=CASH,\r\n        backtest_commission_ratio=COMMISSION,\r\n        backtest_slippage_ratio=SLIPPAGE,\r\n        backtest_adjust=ADJUST_PREV,\r\n    )\r\n```\r\n\r\n### 第三步：执行策略\r\n\r\n使用运行器脚本一键执行：\r\n\r\n```bash\r\npython scripts/run_strategy.py --strategy <策略文件路径> --strategy-id <你的策略ID> [--mode backtest|live] [--token YOUR_TOKEN]\r\n```\r\n\r\n> **`--strategy-id` 必填**：填写后回测结果会持久化到掘金终端，登录终端网页即可查看绩效分析图表（收益曲线、回撤、夏普比率等）。\r\n> 如果不填，回测结果仅在控制台输出，不会保存到终端。\r\n\r\n运行器脚本路径：`C:\\Users\\wjz\\.workbuddy\\skills\\gm-quant\\scripts\\run_strategy.py`\r\n\r\n## 参考文档索引\r\n\r\n详细 API 文档位于 `references/` 目录下：\r\n\r\n| 文件 | 内容 |\r\n|------|------|\r\n| `01-quick-start.md` | 快速开始、策略架构、运行模式 |\r\n| `02-core-functions.md` | `run`、`set_token`、`stop`、`schedule`、`timer` |\r\n| `03-subscribe-events.md` | `subscribe`、`unsubscribe`、`on_tick`、`on_bar`、`on_l2*` |\r\n| `04-market-data.md` | `current`、`history`、`history_n`、`context.data` |\r\n| `05-l2-data.md` | L2 行情查询接口（付费） |\r\n| `06-symbol-info.md` | 标的信息查询 API |\r\n| `07-trading-dates.md` | 交易日历 API |\r\n| `08-order-api.md` | 下单 API 全集 |\r\n| `09-algo-order.md` | 算法单 API |\r\n| `10-account-query.md` | 账户查询 API |\r\n| `11-bond-convertible.md` | 可转债交易 API |\r\n| `12-dataobjects.md` | 数据对象字段定义 |\r\n| `13-enums.md` | 枚举常量速查 |\r\n| `14-context.md` | context 对象 |\r\n\r\n## 交易 API 补充\r\n\r\n### 融资融券（信用交易）\r\n\r\n融资融券交易需在信用账户下操作，使用 `credit_` 前缀函数：\r\n\r\n```python\r\n# 融资买入（借入资金买证券）\r\ncredit_buying_on_margin(symbol, volume, price=0, order_type=OrderType_Market, position_effect=PositionEffect_Open)\r\n\r\n# 融券卖出（借入证券卖出）\r\ncredit_short_selling(symbol, volume, price=0, order_type=OrderType_Market, position_effect=PositionEffect_Open)\r\n\r\n# 买券还券（买入证券归还融券）\r\ncredit_buying_on_repayment(symbol, volume, price=0, order_type=OrderType_Market)\r\n\r\n# 卖券还款（卖出证券归还融资）\r\ncredit_selling_on_repayment(symbol, volume, price=0, order_type=OrderType_Market)\r\n\r\n# 直接还款（用现金直接归还融资）\r\ncredit_direct_repayment(amount)\r\n\r\n# 直接还券（用持仓直接归还融券）\r\ncredit_direct_return_securities(symbol, volume)\r\n\r\n# 信用账户查询\r\ncredit_get_collateral_instruments()    # 查询可担保证券\r\ncredit_get_borrowable_instruments()    # 查询可融券证券\r\ncredit_get_collateral_ratio(symbol)    # 查询担保折算率\r\ncredit_get_concentrate_limit(symbol)   # 查询集中度限制\r\ncredit_get_margin_ratio(symbol)        # 查询融资融券保证金比例\r\ncredit_get_max_volume(symbol, side)    # 查询最大可借数量\r\n```\r\n\r\n> ⚠️ 融资融券功能需要开通信用账户，且掘金终端需切换到信用交易模式。\r\n\r\n### 批量下单\r\n\r\n```python\r\n# 批量下单 — 一次提交多笔委托，减少网络往返\r\norders = [\r\n    {'symbol': 'SHSE.600519', 'volume': 100, 'side': OrderSide_Buy, 'position_effect': PositionEffect_Open, 'order_type': OrderType_Market},\r\n    {'symbol': 'SZSE.000001', 'volume': 200, 'side': OrderSide_Buy, 'position_effect': PositionEffect_Open, 'order_type': OrderType_Market},\r\n]\r\norder_batch(orders)\r\n```\r\n\r\n> `order_batch` 返回订单ID列表，与 `order_volume` 返回值一致。\r\n\r\n### 撤单\r\n\r\n```python\r\n# 撤销指定委托\r\norder_cancel(cl_ord_id)         # cl_ord_id 从 get_orders() 或 on_order_status 回调中获取\r\n\r\n# 撤销全部未成交委托\r\norder_cancel_all()\r\n\r\n# 查询未成交委托\r\nget_unfinished_orders()\r\n```\r\n\r\n> `order_cancel` 的参数是 `cl_ord_id`（客户端订单ID），**不是** `order_id`。可以从 `on_order_status` 回调的 `order.cl_ord_id` 字段或 `get_unfinished_orders()` 返回值中获取。\r\n\r\n### 特殊交易函数\r\n\r\n```python\r\n# 新股申购\r\nipo_buy(symbol, volume, price=0, order_type=OrderType_Limit)\r\n\r\n# ETF 申购/赎回（场内基金）\r\nfund_etf_buy(symbol, volume, price=0, order_type=OrderType_Market)       # ETF 申购\r\nfund_etf_redemption(symbol, volume, price=0, order_type=OrderType_Market) # ETF 赎回\r\n\r\n# 场外基金\r\nfund_subscribing(symbol, volume, price=0)   # 场外基金认购\r\nfund_buy(symbol, volume, price=0)           # 场外基金申购\r\nfund_redemption(symbol, volume, price=0)    # 场外基金赎回\r\n\r\n# 国债逆回购\r\nbond_reverse_repurchase_agreement(symbol, volume, price=0, order_type=OrderType_Limit)\r\n```\r\n\r\n> ⚠️ 国债逆回购的 `volume` 单位是**张**（1张=1000元面值），`price` 是年化利率（如 2.5 表示年化 2.5%）。\r\n\r\n### 动态参数（终端 UI 可调）\r\n\r\n在 `init()` 中用 `add_parameter` 注册参数后，用户可在掘金终端 UI 上实时调整策略参数，无需改代码重启：\r\n\r\n```python\r\ndef init(context):\r\n    add_parameter(key='ma_short', value=5, min=1, max=100, step=1, name='短期均线周期')\r\n    add_parameter(key='ma_long', value=20, min=1, max=200, step=1, name='长期均线周期')\r\n    add_parameter(key='stop_loss_pct', value=0.05, min=0.01, max=0.5, step=0.01, name='止损比例')\r\n\r\n# 用户在终端修改参数时触发回调\r\ndef on_parameter(context, parameter):\r\n    key = parameter['key']\r\n    value = parameter['value']\r\n    log.info(f'参数变更: {key} = {value}')\r\n    if key == 'ma_short':\r\n        context.ma_short_period = value\r\n\r\n# 策略中读取当前参数值\r\ndef on_bar(context, bars):\r\n    ma_short = get_parameter(key='ma_short')\r\n    ma_long = get_parameter(key='ma_long')\r\n```\r\n\r\n### 连接事件\r\n\r\n适用于实盘/仿真模式，可用于断线重连逻辑或告警通知（回测模式下不会触发）：\r\n\r\n```python\r\ndef on_market_data_connected(context):\r\n    log.info('行情服务已连接')\r\n\r\ndef on_market_data_disconnected(context):\r\n    log.info('行情服务已断开')\r\n\r\ndef on_trade_data_connected(context):\r\n    log.info('交易服务已连接')\r\n\r\ndef on_trade_data_disconnected(context):\r\n    log.info('交易服务已断开')\r\n```\r\n\r\n### 交易所代码表\r\n\r\n| 代码 | 交易所 | 示例 |\r\n|------|--------|------|\r\n| SHSE | 上海证券交易所 | SHSE.600000 |\r\n| SZSE | 深圳证券交易所 | SZSE.000001 |\r\n| CFFEX | 中国金融期货交易所 | CFFEX.IF2506 |\r\n| SHFE | 上海期货交易所 | SHFE.ag2506 |\r\n| DCE | 大连商品交易所 | DCE.m2509 |\r\n| CZCE | 郑州商品交易所 | CZCE.CF501 |\r\n| INE | 上海国际能源交易中心 | INE.sc2506 |\r\n| GFEX | 广州期货交易所 | GFEX.si2508 |\r\n\r\n### 枚举常量表（速查）\r\n\r\n```python\r\n# ---- 订单状态 OrderStatus ----\r\nOrderStatus_New = 1                # 新建\r\nOrderStatus_PartiallyFilled = 3    # 部分成交\r\nOrderStatus_Filled = 4             # 全部成交\r\nOrderStatus_Canceled = 5           # 已撤\r\nOrderStatus_Rejected = 7           # 拒绝\r\nOrderStatus_Cancelling = 8         # 待撤\r\n# 注意：回测中可能出现未记录状态码 10（内部中间态），需兼容处理\r\n\r\n# ---- 订单类型 OrderType ----\r\nOrderType_Market = 1               # 市价单\r\nOrderType_Limit = 2                # 限价单\r\n\r\n# ---- 买卖方向 OrderSide ----\r\nOrderSide_Buy = 1\r\nOrderSide_Sell = 2\r\n\r\n# ---- 开平仓 PositionEffect（order_volume 用）----\r\nPositionEffect_Open = 1            # 开仓\r\nPositionEffect_Close = 2           # 平仓\r\nPositionEffect_CloseToday = 3      # 平今\r\nPositionEffect_CloseYesterday = 4  # 平昨\r\n\r\n# ---- 持仓方向 PositionSide（order_target_* 用）----\r\nPositionSide_Long = 1\r\nPositionSide_Short = 2\r\n\r\n# ---- 复权方式 AdjustType ----\r\nADJUST_NONE = 0                    # 不复权\r\nADJUST_PREV = 1                    # 前复权（回测常用）\r\nADJUST_POST = 2                    # 后复权\r\n\r\n# ---- 运行模式 ----\r\nMODE_LIVE = 1                      # 实时/仿真\r\nMODE_BACKTEST = 2                  # 回测\r\n```\r\n\r\n### 数据频率与运行模式\r\n\r\n**K线频率（frequency）**：\r\n\r\n| 值 | 说明 |\r\n|----|------|\r\n| `tick` | 逐笔 |\r\n| `60s` | 1分钟 |\r\n| `300s` | 5分钟 |\r\n| `900s` | 15分钟 |\r\n| `1800s` | 30分钟 |\r\n| `3600s` | 1小时 |\r\n| `1d` | 日线 |\r\n\r\n**运行模式**：\r\n\r\n| 值 | 说明 |\r\n|----|------|\r\n| `MODE_LIVE = 1` | 实时/仿真模式，行情实时推送 |\r\n| `MODE_BACKTEST = 2` | 回测模式，数据按时间序列回放 |\r\n\r\n### ~~基本面数据（已下线）~~\r\n\r\n> ⚠️ `get_fundamentals()` / `get_fundamentals_n()` 已下线，请使用 `stk_get_fundamentals_*_pt` 系列替代。\r\n\r\n### 新股申购\r\n\r\n```python\r\n# 查询新股申购额度\r\nipo_get_quota(exchange='SHSE')        # 返回沪市/深市可用额度\r\n\r\n# 查询可申购新股列表\r\nipo_get_instruments(trade_date='2025-01-15')  # 指定交易日的可申购新股\r\n\r\n# 查询申购配号\r\nipo_get_match_number(symbol='SHSE.688001')\r\n\r\n# 查询中签信息\r\nipo_get_lot_info(symbol='SHSE.688001')\r\n```\r\n\r\n### 分红数据\r\n\r\n```python\r\n# 查询分红送配数据（时序）\r\nget_dividend(symbol='SHSE.600519', start_date='2020-01-01', end_date='2025-12-31', df=True)\r\n# 返回字段：ex_date(除权日), record_date(登记日), pay_date(发放日), cash_div(每股派息),\r\n#           bonus_share_r(送股比例), transfer_share_r(转增比例)\r\n```\r\n\r\n### L2 历史数据查询\r\n\r\n```python\r\n# L2 逐笔成交\r\nget_history_l2_transaction(symbol, start_time, end_time, fields=None, df=True)\r\n\r\n# L2 逐笔委托\r\nget_history_l2_order(symbol, start_time, end_time, fields=None, df=True)\r\n\r\n# L2 队列（买卖盘口）\r\nget_history_l2_queue(symbol, start_time, end_time, fields=None, df=True)\r\n```\r\n\r\n> ⚠️ L2 数据接口为付费功能，仅特定券商可用，需要开通相应权限。\r\n\r\n## 进阶策略示例\r\n\r\n### 配对交易（均值回归）\r\n\r\n```python\r\ndef init(context):\r\n    context.pair = ('SHSE.600036', 'SZSE.000001')  # 招行 vs 平安\r\n    subscribe(symbols=','.join(context.pair), frequency='1d', count=60)\r\n    context.half_life = 20\r\n    context.entry_z = 2.0\r\n    context.exit_z = 0.5\r\n\r\ndef on_bar(context, bars):\r\n    s1, s2 = context.pair\r\n    d1 = context.data(symbol=s1, frequency='1d', count=60)\r\n    d2 = context.data(symbol=s2, frequency='1d', count=60)\r\n    if d1 is None or d2 is None or len(d1) < 30:\r\n        return\r\n\r\n    spread = d1['close'].values / d2['close'].values\r\n    mean = spread[-context.half_life:].mean()\r\n    std = spread[-context.half_life:].std()\r\n    zscore = (spread[-1] - mean) / std if std > 0 else 0\r\n\r\n    if zscore > context.entry_z and _get_position_volume(context, s1) == 0:\r\n        order_target_percent(s1, -0.5, position_side=PositionSide_Short, order_type=OrderType_Market)\r\n        order_target_percent(s2, 0.5, position_side=PositionSide_Long, order_type=OrderType_Market)\r\n    elif zscore < -context.entry_z and _get_position_volume(context, s2) == 0:\r\n        order_target_percent(s1, 0.5, position_side=PositionSide_Long, order_type=OrderType_Market)\r\n        order_target_percent(s2, -0.5, position_side=PositionSide_Short, order_type=OrderType_Market)\r\n    elif abs(zscore) < context.exit_z:\r\n        for sym in context.pair:\r\n            order_target_volume(sym, 0, position_side=PositionSide_Long, order_type=OrderType_Market)\r\n            order_target_volume(sym, 0, position_side=PositionSide_Short, order_type=OrderType_Market)\r\n```\r\n\r\n### CTA 海龟交易法\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SHFE.ag2506', frequency='1d', count=55)\r\n    context.atr_period = 20\r\n    context.entry_period = 20\r\n    context.exit_period = 10\r\n    context.unit_risk = 0.01  # 每笔最大亏损占总资金1%\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol='SHFE.ag2506', frequency='1d', count=55)\r\n    if data is None or len(data) < 55:\r\n        return\r\n\r\n    high, low, close = data['high'].values, data['low'].values, data['close'].values\r\n    tr = [max(high[i]-low[i], abs(high[i]-close[i-1]), abs(low[i]-close[i-1])) for i in range(1, len(close))]\r\n    atr = sum(tr[-context.atr_period:]) / context.atr_period\r\n\r\n    entry_high = max(high[-context.entry_period:-1])\r\n    exit_low = min(low[-context.exit_period:-1])\r\n    curr = close[-1]\r\n\r\n    cash = get_cash()\r\n    unit = int(cash.available * context.unit_risk / atr / 1000) * 1000\r\n    pos = _get_position_volume(context, 'SHFE.ag2506')\r\n\r\n    if curr > entry_high and pos == 0:\r\n        order_volume('SHFE.ag2506', unit, side=OrderSide_Buy,\r\n                     position_effect=PositionEffect_Open, order_type=OrderType_Market)\r\n    elif curr < exit_low and pos > 0:\r\n        order_volume('SHFE.ag2506', pos, side=OrderSide_Sell,\r\n                     position_effect=PositionEffect_Close, order_type=OrderType_Market)\r\n```\r\n\r\n### 风控模块（可嵌入任意策略）\r\n\r\n```python\r\nclass RiskManager:\r\n    \"\"\"通用风控：止损/止盈/最大持仓/回撤控制\"\"\"\r\n\r\n    def __init__(self, stop_loss_pct=0.05, take_profit_pct=0.10,\r\n                 max_position_pct=0.3, max_drawdown_pct=0.15):\r\n        self.stop_loss_pct = stop_loss_pct\r\n        self.take_profit_pct = take_profit_pct\r\n        self.max_position_pct = max_position_pct\r\n        self.max_drawdown_pct = max_drawdown_pct\r\n        self.peak_value = 0\r\n\r\n    def check_stop_loss(self, entry_price, current_price, side='long'):\r\n        if side == 'long':\r\n            return (current_price - entry_price) / entry_price < -self.stop_loss_pct\r\n        return (entry_price - current_price) / entry_price < -self.stop_loss_pct\r\n\r\n    def check_take_profit(self, entry_price, current_price, side='long'):\r\n        if side == 'long':\r\n            return (current_price - entry_price) / entry_price > self.take_profit_pct\r\n        return (entry_price - current_price) / entry_price > self.take_profit_pct\r\n\r\n    def check_drawdown(self):\r\n        cash = get_cash()\r\n        total = cash.nav if hasattr(cash, 'nav') else cash.available\r\n        self.peak_value = max(self.peak_value, total)\r\n        dd = (self.peak_value - total) / self.peak_value if self.peak_value > 0 else 0\r\n        return dd > self.max_drawdown_pct\r\n\r\n    def check_position_limit(self, symbol_value, total_value):\r\n        return (symbol_value / total_value) > self.max_position_pct\r\n```\r\n\r\n### 行业轮动（动量因子 + schedule 定时调仓）\r\n\r\n```python\r\ndef init(context):\r\n    context.sectors = {\r\n        'SHSE.512000': '券商', 'SHSE.512010': '医药', 'SHSE.512660': '军工',\r\n        'SHSE.512800': '银行', 'SHSE.512690': '白酒', 'SHSE.515030': '新能源',\r\n    }\r\n    context.top_n = 2\r\n    subscribe(symbols=','.join(context.sectors.keys()), frequency='1d', count=22)\r\n    schedule(rebalance, frequency='1d', time_rule='15:05')\r\n\r\ndef rebalance(context, bar_dict):\r\n    momentum = {}\r\n    for sym in context.sectors:\r\n        data = context.data(symbol=sym, frequency='1d', count=22)\r\n        if data is not None and len(data) >= 20:\r\n            momentum[sym] = data['close'].iloc[-1] / data['close'].iloc[-20] - 1\r\n\r\n    ranked = sorted(momentum.items(), key=lambda x: x[1], reverse=True)\r\n    targets = [s[0] for s in ranked[:context.top_n]]\r\n\r\n    for sym in context.sectors:\r\n        if sym in targets:\r\n            order_target_percent(sym, 1.0 / context.top_n,\r\n                                 position_side=PositionSide_Long, order_type=OrderType_Market)\r\n        else:\r\n            order_target_volume(sym, 0,\r\n                                position_side=PositionSide_Long, order_type=OrderType_Market)\r\n```\r\n\r\n## API 参数补充说明\r\n\r\n### current() 回测 vs 实盘字段差异\r\n\r\n```python\r\ndata = current(symbols='SHSE.600519,SZSE.000001')\r\n# 通用字段：symbol, open, high, low, close, volume, amount, frequency, timestamp\r\n# 实盘额外字段：bid_price/bid_volume(买价买量), ask_price/ask_volume(卖价卖量),\r\n#               last_price(最新价), num_trades(成交笔数)\r\n```\r\n\r\n> ⚠️ 回测模式下 `current()` 只能查询已订阅标的，实盘模式可查询任意标的。\r\n\r\n### history() 补充参数\r\n\r\n```python\r\nhistory(symbol, frequency, start_time=None, end_time=None, count=None,\r\n        fields=None, skip_suspended=True, fill_missing=None, df=True)\r\n\r\n# skip_suspended=True（默认）：跳过停牌日\r\n# skip_suspended=False：保留停牌日，数据字段用 NaN 填充\r\n\r\n# fill_missing='pre'：用前值填充缺失\r\n# fill_missing='post'：用后值填充缺失\r\n# fill_missing=None（默认）：不填充\r\n```\r\n\r\n### subscribe() wait_group 参数\r\n\r\n```python\r\n# 多标的等待同步：所有标的bar都到达后才触发一次 on_bar\r\nsubscribe(symbols='SHSE.600519,SZSE.000001', frequency='60s', count=20,\r\n          wait_group=True)\r\n\r\n# 默认 wait_group=False：每个标的bar到达时单独触发\r\n```\r\n\r\n> 多标的同频率策略建议开启 `wait_group=True`，避免部分标的先触发导致数据不齐。\r\n\r\n### order_value / order_percent / order_target_percent\r\n\r\n```python\r\n# order_value — 按金额下单（自动取整到100股倍数）\r\norder_value(symbol='SHSE.600519', value=50000, side=OrderSide_Buy,\r\n            position_effect=PositionEffect_Open, order_type=OrderType_Market)\r\n\r\n# order_percent — 按总资产百分比下单\r\norder_percent(symbol='SHSE.600519', percent=0.1, side=OrderSide_Buy,\r\n              position_effect=PositionEffect_Open, order_type=OrderType_Market)\r\n# percent=0.1 表示用总资产的10%买入\r\n\r\n# order_target_percent — 调仓到目标占比（ETF 调仓推荐）\r\norder_target_percent(symbol='SHSE.512000', percent=0.15,\r\n                     position_side=PositionSide_Long, order_type=OrderType_Market)\r\n# 调整到占总资产15%，不足买入，超出卖出\r\n```\r\n\r\n### 成交回报查询\r\n\r\n```python\r\nget_execution_reports(cl_ord_id=None, symbol=None, start_time=None,\r\n                      end_time=None, position_side=None, limit=None, df=True)\r\n# cl_ord_id: 指定订单ID\r\n# symbol: 指定标的\r\n# limit: 返回条数限制\r\n```\r\n\r\n## 常见问题 & 注意事项\r\n\r\n- `history()` 的 `df` 参数默认 `True` 返回 DataFrame，`False` 返回 `list[dict]`\r\n- 单次查询最多返回 33000 条数据\r\n- L2 数据接口（`get_history_l2*`）仅特定付费券商可用\r\n- `subscribe` 中 `count` 决定 `context.data` 的滑窗大小\r\n- 回测模式下 `init` 不支持交易操作\r\n- 虚拟合约（主力连续合约）仅在回测模式下可用，如 `SHFE.RB`\r\n- `get_trading_dates` 查交易日历时，`exchange` 参数用交易所代码如 `'SHSE'`\r\n- `run()` 参数名是 `strategy_id` 和 `filename`（模块名，不是文件路径！）\r\n- A 股最小下单单位为 100 股（1手），`order_volume` 必须是 100 的整数倍\r\n- `order_value` 会自动取整到 100 股倍数\r\n\r\n## 踩坑经验（实测验证）\r\n\r\n**以下坑点已通过实际运行验证，生成代码时必须遵守：**\r\n\r\n1. **`run()` 参数名**：是 `strategy_id` + `filename`（模块名，不带 .py 后缀），不是 `strategy_name` / `file_path`\r\n2. **`log()` 用法**：`log(msg, source)` 是普通函数，**不是** logger 对象。不要用 `log.info()`。推荐直接用 `print()`\r\n3. **`context.data()` 返回值**：返回的是 **DataFrame**（不是 dict list），用 `data['close'].tolist()` 访问数据列\r\n4. **`get_position()` 不带参数**：调用 `get_position()` 获取全部持仓列表，然后遍历查找目标 symbol 的持仓。不支持 `get_position(symbol=xxx)`\r\n5. **`order_target_volume()` 参数**：不需要 `side` 参数；用 `position_side=PositionSide_Long`（不是 `position_effect=PositionEffect_Close`）\r\n6. **`order_volume()` 买入参数**：需要 `side=OrderSide_Buy` + `position_effect=PositionEffect_Open`\r\n7. **Windows 编码**：脚本开头必须加 `sys.stdout = io.TextIOWrapper(...)` 否则中文 emoji 报错\r\n8. **A 股 T+1**：当天买入不能当天卖出，策略逻辑需要考虑这个约束\r\n9. **`cl_ord_id` 参数不存在**：`order_volume` / `order_value` / `order_target_volume` 等下单函数**不支持** `cl_ord_id` 参数。传入会直接抛 `TypeError: got an unexpected keyword argument 'cl_ord_id'`。订单标识由系统自动生成\r\n10. **`on_order_status` 回测模式状态码**：回测中会出现文档未记录的状态码 `10`（未知/内部中间态），实际运行时需兼容处理。完整状态码：1=新建, 2=已报, 3=部分成交, 4=已成交, 5=已撤, 6=未成交(超时), 7=拒绝, 8=待撤, 9=未知, **10=回测内部态**\r\n11. **`on_execution_report` 的 exec_type**：回测模式下返回数字而非字符，实测值为 `15`（成交确认）。实盘/仿真可能返回 `'T'`(Trade) / `'C'(Cancel)\r\n12. **回测中风控行为**：超额卖出或资金不足的订单在回测中不会触发 `Rejected(7)` 状态，而是变为 `Cancelling(8)` → 被自动撤销。**拒单原因需要实盘/仿真环境才能观察到**\r\n13. **`on_order_status` order 对象访问**：回调中的 order 对象**同时支持** dict 风格 `order['symbol']` 和属性风格 `order.symbol`，但推荐用 try/getattr 兼容两种方式\r\n14. **`on_execution_report` execrpt 对象访问**：同上，同时支持 dict 和属性风格。关键字段：`symbol`, `side`(1买2卖), `volume`, `price`, `exec_type`, `commission`\r\n15. **市价单在回测中也可能不成交**：如果资金不足（如下单量×价格 > 可用资金），市价单会被标记为 Cancelling 而非报错抛异常\r\n16. **`stk_get_index_constituents` 没有 `df` 参数**：直接返回 DataFrame，不需要传 df=True\r\n17. **财务数据 API 的 `fields` 必填且不能为空**：所有 `stk_get_fundamentals_*_pt` / `stk_get_finance_*_pt` / `stk_get_daily_*_pt` 函数的 `fields` 参数是必填的，不能传空字符串 `\"\"`，否则报错\"填写的 fields 不正确\"。fields 不能超过 20 个\r\n18. **`stk_get_finance_prime_pt` ROE 字段名是 `roe_weight_avg`**，不是 `roe_waa`。常用字段: eps_basic/eps_dil/roe_weight_avg/roe_weight_avg_cut/net_prof_pcom_yoy/inc_oper_yoy\r\n19. **`stk_get_daily_basic_pt` 股本字段名**：流通股本是 `circ_shr`（不是 float_shr），无限售条件流通股本是 `ttl_shr_unl`（不是 free_shr），有限售条件股本是 `ttl_shr_ltd`\r\n20. **财务衍生指标 `eps_dil2` vs `eps_dil`**：`stk_get_finance_deriv_pt` 中稀释 EPS 字段名是 `eps_dil2`（不是 `eps_dil`），而 `stk_get_finance_prime_pt` 中是 `eps_dil`\r\n21. **`_pt` 后缀 = 截面数据(多标的)**，无后缀 = 时序数据(单标的)。截面用 date/trade_date 参数，时序用 start_date/end_date 参数\r\n22. **付费增值数据 API**：期货(fut_get_*)、基金(fnd_get_*)、可转债(bnd_get_*) 的增值数据需要开通相应权限。详见 `references/16-premium-data-apis.md`\r\n23. **`stk_get_fundamentals_*_pt` 的 `date` 参数是发布日期**，不是报告期日期。返回的是发布日期 ≤ date 的最新报告期数据\r\n24. **`stk_get_daily_valuation_pt/mktvalue_pt/basic_pt` 的 `trade_date` 参数**：是交易日期，默认 None 返回最新交易日数据\r\n25. **回测交易日限制**：每个交易日 18:30 前只能回测上一个交易日的数据，因为当日日线数据要到 18:30 才更新完成。如果 `end_date` 设为当天但还没过 18:30，回测结果会缺少当日数据或报错\r\n26. **实时模式（仿真/实盘）没有发生交易的排查清单**：\r\n    - ① **定时任务时间过了**：`schedule` 定时任务只在指定时间触发，如果启动策略时已过了今天的时间点，要等到明天才会触发。临时解决：把时间改成当前时间之后几分钟\r\n    - ② **期货策略必须订阅具体合约**：实时模式只能推送具体合约行情（如 `SHFE.ag2506`），主连合约（如 `SHFE.agmain`）**没有行情推送**。回测可以主连，实时不行\r\n    - ③ **实时模式日线不会推送**：交易时间内日线还没走完，`on_bar` 不会收到日线 bar。需要用 `schedule` 定时任务替代，在收盘后（如 15:01）主动调用 `history` 获取日线数据\r\n    - ④ **检查打印日志**：确认是否有数据推送 → 是否有交易信号发出 → 是否有下单指令 → 订单状态是否正常。按这个链路逐级排查\r\n27. **`order_volume()` vs `order_target_volume/percent` 参数名不同**：`order_volume()` 的开平仓参数叫 `position_effect`（用 `PositionEffect_Open/Close`），而 `order_target_volume/percent/value` 的持仓方向参数叫 `position_side`（用 `PositionSide_Long/Short`）。ETF调仓推荐用 `order_target_percent`，更简洁不用算股数\r\n28. **56开头的ETF是沪市**：如562500机器人ETF应为 `SHSE.562500`，不是深市。5开头=沪市(SHSE)，1开头=深市(SZSE)\n\nFile v1.0.2:README.md\n\n# 掘金量化 Skill — 自然语言策略引擎\r\n\r\n> **用中文说话就能跑量化策略。** 告诉我你的交易想法，我帮你生成代码、执行回测、查看结果。\r\n\r\n## 快速开始（3 步）\r\n\r\n### 1️⃣ 准备环境\r\n\r\n确保你的电脑已安装：\r\n\r\n- [**掘金终端**](https://www.myquant.cn) — 打开并登录\r\n- **Python 3.8+** — 安装 `gm` SDK 包：\r\n  ```bash\r\n  pip install gm\r\n  ```\r\n\r\n### 2️⃣ 设置 Token\r\n\r\n获取方式：掘金终端 → 系统设置 → 密钥管理 → 复制 Token\r\n\r\n然后告诉我：\"我的 token 是 `xxxxx`\"，我会自动保存。\r\n\r\n### 3️⃣ 用自然语言描述策略 + 提供 Strategy ID\r\n\r\n直接说你想做什么，**同时告诉我你的策略 ID**：\r\n\r\n> \"帮我写个双均线策略：茅台和平安银行，5 日均线上穿 20 日均线买入，下穿卖出，回测最近一年。**策略 ID 叫 `ma_cross_v1`**\"\r\n\r\n> \"写个动量策略：沪深 300 里选过去 20 天涨幅最大的 10 只等权买入，每月初调仓。**strategy_id 用 `momentum_top10`**\"\r\n\r\n> \"查一下贵州茅台最近半年的日线收盘价\"（纯查询不需要 strategy_id）\r\n\r\n我会自动生成完整的可运行策略文件并帮你跑起来。\r\n\r\n---\r\n\r\n## 支持的策略类型\r\n\r\n| 类型 | 示例描述 | 关键字 |\r\n|------|---------|--------|\r\n| **趋势跟踪** | \"双均线金叉死叉\" / \"布林带突破\" / \"MACD 策略\" | 均线、MA、MACD、布林带 |\r\n| **动量/因子** | \"选涨幅最大的 N 只\" / \"RSI 超卖买入\" / \"量价配合\" | 动量、RSI、成交量、排名 |\r\n| **均值回归** | \"偏离均值太多就反向操作\" / \"网格交易\" | 均值回归、网格、偏离 |\r\n| **多因子选股** | \"按 PE+ROE 选股\" / \"小市值+高成长\" | 因子、筛选、排序 |\r\n| **事件驱动** | \"财报后买入\" / \"涨停板打板\" | 财报、涨停、事件 |\r\n| **纯数据查询** | \"查行情\" / \"拉数据\" / \"看 K 线\" | 查询、历史、行情 |\r\n\r\n---\r\n\r\n## 运行模式\r\n\r\n| 模式 | 说明 | 适用场景 |\r\n|------|------|---------|\r\n| **回测 (Backtest)** | 用历史数据模拟交易 | 验证策略效果（默认） |\r\n| **实盘/仿真 (Live)** | 连接实时行情和模拟账户 | 策略验证后上线运行 |\r\n\r\n---\r\n\r\n## 典型对话示例\r\n\r\n### 示例 1：从零开始写策略\r\n\r\n```\r\n你: 写个双均线交叉策略，标的用贵州茅台，5日和20日均线。策略ID用 ma_cross_kweichow\r\n我: [生成 strategy_ma.py，strategy_id='ma_cross_kweichow']\r\n    策略已生成！参数如下：\r\n    - 策略ID: ma_cross_kweichow ← 终端可查看绩效\r\n    - 标的: SHSE.600519（贵州茅台）\r\n    - 周期: 日线 1d\r\n    - 信号: MA5上穿MA20买入 / 下穿卖出\r\n    - 回测: 2024-01 ~ 2025-12, 初始资金100万\r\n\r\n    要跑回测吗？\r\n你: 跑吧\r\n我: [自动调用 run_strategy.py --strategy-id ma_cross_kweichow 执行]\r\n    回测完成！结果摘要：\r\n    - 总收益: +23.5%\r\n    - 年化收益: 18.2%\r\n    - 最大回撤: -12.3%\r\n    - 夏普比率: 1.45\r\n    \r\n    ✅ 已保存到掘金终端 → 打开 https://www.myquant.cn 查看完整绩效图表\r\n```\r\n\r\n### 示例 2：只查询数据\r\n\r\n```\r\n你: 查一下中芯国际最近30天的收盘价\r\n我: [直接调用 API 返回 DataFrame]\r\n    SZSE.002371 中芯国际 最近30日收盘价：\r\n    日期          | 收盘价   | 涨跌幅\r\n    2026-03-10    | 52.30    | +2.1%\r\n    2026-03-11    | 51.80    | -0.96%\r\n    ...\r\n```\r\n\r\n---\r\n\r\n## 文件结构\r\n\r\n```\r\n~/.workbuddy/skills/gm-quant/\r\n├── SKILL.md                  # 技能主文件（AI 读取此文件理解如何工作）\r\n├── README.md                 # 本文件 — 用户引导\r\n├── TEST_REPORT.md            # API 测试报告\r\n├── references/               # API 详细参考文档（14篇）\r\n│   ├── 01-quick-start.md\r\n│   ├── 04-market-data.md\r\n│   └── ...\r\n└── scripts/\r\n    ├── run_strategy.py        # ⭐ 策略一键运行器\r\n    ├── test_all_apis.py       # API 全量测试脚本\r\n    ├── test_account_apis.py   # 账户 API 策略环境测试\r\n    └── check_import.py        # 导入检测\r\n```\r\n\r\n---\r\n\r\n## ⭐ Strategy ID — 在掘金终端查看绩效分析\r\n\r\n> **这是使用回测功能前必须填写的一步。**\r\n\r\n### 什么是 Strategy ID？\r\n\r\n`strategy_id` 是你的策略在**掘金终端**中的唯一标识名。每次运行策略时传入它，回测结果会**持久化保存**到终端后台。\r\n\r\n### 填写后你能看到什么？\r\n\r\n登录 [掘金量化终端](https://www.myquant.cn) → **策略列表** → 找到你的策略 → 点击查看：\r\n\r\n| 绩效分析内容 | 说明 |\r\n|-------------|------|\r\n| 📈 **收益曲线** | 策略净值 vs 基准对比 |\r\n| 📉 **回撤分析** | 最大回撤、回撤持续时间 |\r\n| 📊 **风险指标** | 夏普比率、年化收益、波动率 |\r\n| 💰 **交易明细** | 每笔买入/卖出记录 |\r\n| 🎯 **持仓快照** | 每日持仓变化 |\r\n\r\n### 如何提供？\r\n\r\n在描述策略时顺便告诉我，例如：\r\n\r\n```\r\n你: 写个双均线策略，标的茅台。策略ID用 ma_cross_kweichow\r\n我: [生成代码，自动填入 strategy_id='ma_cross_kweichow']\r\n    回测完成！打开掘金终端 → 策略列表 → ma_cross_kweichow → 查看绩效图表\r\n```\r\n\r\n如果你没提供，**我会主动问你**，不会偷偷跳过。\r\n\r\n---\r\n\r\n## 注意事项\r\n\r\n- **掘金终端必须保持打开** — 所有 API 调用都通过终端通信\r\n- **Token 不要泄露给他人** — 相当于你的账号密码\r\n- **回测不等于实盘** — 回测结果仅供参考，实盘需考虑滑点、流动性等因素\r\n- **A 股 T+1** — 当天买入的股票当天不能卖出\n\nFile v1.0.2:_meta.json\n\n{\n  \"ownerId\": \"kn73qb7dqheg4nh3p4x4ka1mxx85szhw\",\n  \"slug\": \"gmquant\",\n  \"version\": \"1.0.2\",\n  \"publishedAt\": 1777457610666\n}\n\nFile v1.0.2:references/01-quick-start.md\n\n# 快速开始 & 策略架构\r\n\r\n## 策略三大结构\r\n\r\n掘金量化策略主要有 3 种结构：\r\n\r\n### 1. 定时任务型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    schedule(schedule_func=algo, date_rule='1d', time_rule='14:50:00')\r\n\r\ndef algo(context):\r\n    order_volume(symbol='SHSE.600000', volume=200, side=OrderSide_Buy,\r\n                 order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n\r\nif __name__ == '__main__':\r\n    run(strategy_id='YOUR_ID', filename='main.py', mode=MODE_BACKTEST,\r\n        token='YOUR_TOKEN', backtest_start_time='2024-01-01 09:00:00',\r\n        backtest_end_time='2024-06-30 15:30:00', backtest_adjust=ADJUST_PREV,\r\n        backtest_initial_cash=1000000, backtest_commission_ratio=0.0001,\r\n        backtest_slippage_ratio=0.0001)\r\n```\r\n\r\n### 2. 数据事件驱动型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s')\r\n\r\ndef on_bar(context, bars):\r\n    print(bars)\r\n```\r\n\r\n### 3. 时间序列滑窗型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s', count=50,\r\n              format='df', fields='symbol,close,eob')\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol=bars[0]['symbol'], frequency='60s', count=50)\r\n    data['ma5'] = data['close'].rolling(5).mean()\r\n    print(data.tail())\r\n```\r\n\r\n## 纯数据研究（无需 run）\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')  # 掘金终端需保持打开\r\n\r\ndata = history(symbol='SHSE.600000', frequency='1d',\r\n               start_time='2024-01-01 09:00:00', end_time='2024-12-31 16:00:00',\r\n               fields='open,high,low,close,eob', adjust=ADJUST_PREV, df=True)\r\nprint(data)\r\n```\r\n\r\n## 模式说明\r\n\r\n| 模式 | 常量 | 说明 |\r\n|------|------|------|\r\n| 实时模式 | `MODE_LIVE = 1` | 仿真/实盘交易，接收实时行情 |\r\n| 回测模式 | `MODE_BACKTEST = 2` | 历史数据回放，快速验证策略 |\r\n\r\n## 运行参数 `run()` 全解\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| strategy_id | str | 掘金终端生成的策略 ID |\r\n| filename | str | 策略文件名（如 `main.py`） |\r\n| mode | int | MODE_LIVE 或 MODE_BACKTEST |\r\n| token | str | 用户 token（终端系统设置-密钥管理） |\r\n| backtest_start_time | str | 回测开始时间 `%Y-%m-%d %H:%M:%S` |\r\n| backtest_end_time | str | 回测结束时间 `%Y-%m-%d %H:%M:%S` |\r\n| backtest_initial_cash | float | 初始资金，默认 1000000 |\r\n| backtest_transaction_ratio | float | 成交比例，默认 1.0 |\r\n| backtest_commission_ratio | float | 佣金比例，默认 0 |\r\n| backtest_slippage_ratio | float | 滑点比例，默认 0 |\r\n| backtest_adjust | int | 复权方式：ADJUST_NONE/ADJUST_PREV/ADJUST_POST |\r\n| backtest_match_mode | int | 0=延时撮合(下一bar开盘价)，1=实时撮合(当前收盘价) |\r\n| backtest_check_cache | int | 是否用缓存，默认 1 |\r\n| serv_addr | str | 终端地址，默认本地，可指定 `ip:port` |\r\n\r\n## 注意事项\r\n- filename 必须与实际文件名一致\r\n- 前复权/后复权回测不处理分红送转事件（已通过复权因子调整）\r\n- 不复权模式会自动处理分红送转\n\nFile v1.0.2:references/02-core-functions.md\n\n# 核心基础函数\r\n\r\n## set_token - 设置用户 Token\r\n\r\n```python\r\nset_token('YOUR_TOKEN_ID')\r\n```\r\n\r\n- 纯数据查询时第一步必须调用\r\n- Token 在掘金终端「系统设置 → 密钥管理」中获取\r\n- Token 不正确会抛出异常\r\n\r\n---\r\n\r\n## run - 启动策略\r\n\r\n```python\r\nrun(strategy_id='', filename='', mode=MODE_UNKNOWN, token='',\r\n    backtest_start_time='', backtest_end_time='',\r\n    backtest_initial_cash=1000000, backtest_transaction_ratio=1,\r\n    backtest_commission_ratio=0, backtest_slippage_ratio=0,\r\n    backtest_adjust=ADJUST_NONE, backtest_check_cache=1,\r\n    serv_addr='', backtest_match_mode=0)\r\n```\r\n\r\n详细参数说明见 `01-quick-start.md`。\r\n\r\n---\r\n\r\n## stop - 停止策略\r\n\r\n```python\r\nstop()\r\n```\r\n\r\n- 停止策略，退出策略进程\r\n- 示例：当订阅代码集合为空时停止\r\n```python\r\nif not context.symbols:\r\n    stop()\r\n```\r\n\r\n---\r\n\r\n## schedule - 定时任务\r\n\r\n```python\r\nschedule(schedule_func, date_rule, time_rule)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| schedule_func | function | 定时执行的函数 |\r\n| date_rule | str | `n + d/w/m`，如 `'1d'`(每天)、`'1w'`(每周)、`'1m'`(每月) |\r\n| time_rule | str | 执行时间 `HH:MM:SS`，**时分秒不可省略前导零**，如 `'09:40:00'` |\r\n\r\n**注意**：`1w`、`1m` 仅回测可用；`time_rule` 不能写 `'9:40:0'` 这种格式。\r\n\r\n```python\r\ndef init(context):\r\n    schedule(schedule_func=algo_daily, date_rule='1d', time_rule='09:40:00')\r\n    schedule(schedule_func=algo_monthly, date_rule='1m', time_rule='09:30:00')\r\n\r\ndef algo_daily(context):\r\n    print('每天09:40执行', context.now)\r\n\r\ndef algo_monthly(context):\r\n    print('每月第一个交易日09:30执行', context.now)\r\n```\r\n\r\n---\r\n\r\n## timer / timer_stop - 毫秒级定时器\r\n\r\n**仅实时/仿真模式可用，回测不生效。**\r\n\r\n```python\r\n# 设置定时器\r\nresult = timer(timer_func=my_func, period=60000, start_delay=0)\r\n# result: {'timer_status': 0, 'timer_id': 1}\r\n\r\n# 停止定时器\r\nis_stopped = timer_stop(timer_id=result['timer_id'])\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| timer_func | function | 触发时执行的函数 |\r\n| period | int | 间隔毫秒数，范围 [1, 43200000] |\r\n| start_delay | int | 延迟启动毫秒数，范围 [0, 43200000] |\r\n\r\n```python\r\ndef init(context):\r\n    # 每60秒执行一次，立即启动\r\n    context.timer_id = timer(timer_func=on_timer, period=60000, start_delay=0)\r\n\r\ndef on_timer(context):\r\n    cash = context.account().cash\r\n    print('定时检查资金:', cash['available'])\r\n```\r\n\r\n---\r\n\r\n## log - 日志\r\n\r\n**仅实时模式可用。**\r\n\r\n```python\r\nlog(level='info', msg='信号触发', source='strategy')\r\n```\r\n\r\n| level | 说明 |\r\n|-------|------|\r\n| `'info'` | 信息级别 |\r\n| `'warning'` | 警告级别 |\r\n| `'error'` | 错误级别 |\r\n\r\n---\r\n\r\n## add_parameter - 动态参数\r\n\r\n**仅实时模式可用，重启后重置。**\r\n\r\n```python\r\nadd_parameter(key='k_value', value=23, min=0, max=100,\r\n              name='K值阈值', intro='KDJ策略K值阈值',\r\n              group='1', readonly=False)\r\n```\r\n\r\n- 在终端 UI 界面显示和实时修改参数\r\n- 修改时触发 `on_parameter(context, parameter)` 事件\r\n\r\n```python\r\ndef on_parameter(context, parameter):\r\n    if parameter['name'] == 'K值阈值':\r\n        context.k_value = parameter['value']\r\n        print('参数已更新:', context.k_value)\r\n```\n\nFile v1.0.2:references/03-subscribe-events.md\n\n# 数据订阅与事件\r\n\r\n## subscribe - 订阅行情\r\n\r\n```python\r\nsubscribe(symbols, frequency='1d', count=1,\r\n          wait_group=False, wait_group_timeout='10s',\r\n          unsubscribe_previous=False, fields=None, format='df')\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbols | str or list | 标的代码，多个用英文逗号分隔 |\r\n| frequency | str | 频率：`'tick'`、`'60s'`、`'300s'`、`'900s'`、`'1800s'`、`'3600s'`、`'1d'`，L2：`'l2transaction'`、`'l2order'` |\r\n| count | int | 数据滑窗大小，`context.data` 可用的最大条数 |\r\n| wait_group | bool | 是否等同频率所有标的 bar 到齐再触发，默认 False |\r\n| wait_group_timeout | str | wait_group 超时，默认 `'10s'` |\r\n| unsubscribe_previous | bool | 是否取消之前订阅，默认 False |\r\n| fields | str | 指定返回字段，越少越快 |\r\n| format | str | 数据格式：`'df'`(DataFrame)、`'row'`(list[dict])、`'col'`(dict) |\r\n\r\n**性能说明**：`row > col > df`，对性能敏感时用 `format='row'`。\r\n\r\n```python\r\ndef init(context):\r\n    # 订阅日线，滑窗20条\r\n    subscribe(symbols='SHSE.600000,SZSE.000001', frequency='1d', count=20)\r\n    # 同时订阅分钟线\r\n    subscribe(symbols='SHSE.600000', frequency='60s', count=60)\r\n```\r\n\r\n---\r\n\r\n## unsubscribe - 取消订阅\r\n\r\n```python\r\nunsubscribe(symbols='*', frequency='60s')\r\n```\r\n\r\n- 默认取消所有已订阅行情\r\n- 只取消指定标的的指定频率，其他频率不受影响\r\n\r\n---\r\n\r\n## on_tick - Tick 数据事件\r\n\r\n```python\r\ndef on_tick(context, tick):\r\n    print(tick['symbol'], tick['price'])\r\n```\r\n\r\ntick 对象包含：`symbol`、`open`、`high`、`low`、`price`、`cum_volume`、`cum_amount`、`last_volume`、`last_amount`、`quotes`（5档买卖盘）、`created_at`\r\n\r\n---\r\n\r\n## on_bar - Bar 数据事件\r\n\r\n```python\r\ndef on_bar(context, bars):\r\n    for bar in bars:\r\n        print(bar['symbol'], bar['close'])\r\n```\r\n\r\nbars 是 list，单标的时长度为 1（wait_group=False），多标的全到时长度 > 1。\r\n\r\nbar 对象包含：`symbol`、`frequency`、`open`、`close`、`high`、`low`、`volume`、`amount`、`bob`、`eob`\r\n\r\n---\r\n\r\n## on_l2transaction - 逐笔成交（L2）\r\n\r\n> 仅特定付费券商可用\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='l2transaction')\r\n\r\ndef on_l2transaction(context, transaction):\r\n    print(transaction)\r\n```\r\n\r\n---\r\n\r\n## on_l2order - 逐笔委托（L2）\r\n\r\n> 仅特定付费券商可用，仅深市标的\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SZSE.000001', frequency='l2order')\r\n\r\ndef on_l2order(context, l2order):\r\n    print(l2order)\r\n```\r\n\r\n---\r\n\r\n## 交易事件回调\r\n\r\n| 函数 | 触发时机 |\r\n|------|--------|\r\n| `on_execution_report(context, execrpt)` | 委托执行时触发 |\r\n| `on_order_status(context, order)` | 委托状态变更时触发 |\r\n| `on_account_status(context, account)` | 账户状态变更时触发 |\r\n| `on_error(context, code, info)` | 发生异常时触发 |\r\n| `on_parameter(context, parameter)` | 动态参数修改时触发 |\r\n| `on_backtest_finished(context, indicator)` | 回测结束时触发 |\r\n\r\n### 回测结束事件示例\r\n```python\r\ndef on_backtest_finished(context, indicator):\r\n    print('累计收益率:', indicator['pnl_ratio'])\r\n    print('年化收益率:', indicator['pnl_ratio_annual'])\r\n    print('夏普比率:', indicator['sharp_ratio'])\r\n    print('最大回撤:', indicator['max_drawdown'])\r\n    print('胜率:', indicator['win_ratio'])\r\n```\r\n\r\n---\r\n\r\n## on_execution_report - 成交回报事件（✅ 已实测通过）\r\n\r\n> **触发时机**：每当有成交发生时触发（包括部分成交）\r\n> **实测环境**：回测模式 (MODE_BACKTEST)，SDK v3.0.183\r\n\r\n```python\r\ndef on_execution_report(context, execrpt):\r\n    \"\"\"\r\n    execrpt 对象关键字段（已验证）:\r\n      symbol       — str,   标的代码（如 'SHSE.600519'）\r\n      side         — int,   1=买入, 2=卖出\r\n      volume       — int,   成交数量（股）\r\n      price        — float, 成交均价\r\n      exec_type    — int/str, 回测中为数字15(成交确认), 实盘可能为'T'/'C'\r\n      commission   — float, 本笔手续费\r\n      cl_ord_id    — str,   客户端订单ID（系统生成）\r\n      order_id     — str,   柜台订单ID\r\n      created_at   — datetime, 成交时间\r\n    \"\"\"\r\n    # 推荐的兼容写法（支持 dict 和属性两种风格）:\r\n    if isinstance(execrpt, dict):\r\n        symbol = execrpt.get('symbol', '')\r\n        volume = execrpt.get('volume', 0)\r\n        price = execrpt.get('price', 0)\r\n    else:\r\n        symbol = getattr(execrpt, 'symbol', '')\r\n        volume = getattr(execrpt, 'volume', 0)\r\n        price = getattr(execrpt, 'price', 0)\r\n\r\n    print(f'成交: {symbol} {volume}股 @ {price}')\r\n```\r\n\r\n**实测行为（2026-04-17 验证）**：\r\n- `order_target_volume` 买入 → 触发 **1次** on_execution_report（全部成交汇总）\r\n- `order_target_volume` 卖出 → 触发 **1次** on_execution_report\r\n- 每笔成交回报都带 `commission` 手续费值\r\n- `exec_type` 在回测中返回数字 `15`，不是字符 `'T'`\r\n\r\n---\r\n\r\n## on_order_status - 委托状态变更事件（✅ 已实测通过）\r\n\r\n> **触发时机**：订单生命周期中的每个状态变化都会触发\r\n> **特别重要**：status=7(拒绝) 时包含拒单原因\r\n> **实测环境**：回测模式 (MODE_BACKTEST)，SDK v3.0.183\r\n\r\n```python\r\ndef on_order_status(context, order):\r\n    \"\"\"\r\n    order 对象关键字段（已验证）:\r\n      cl_ord_id          — str,   客户端订单ID\r\n      order_id           — str,   柜台订单ID\r\n      symbol             — str,   标的代码\r\n      status             — int,   委托状态（见下方枚举）\r\n      side               — int,   1=买, 2=卖\r\n      volume             — int,   委托总量\r\n      price              — float, 委托价格\r\n      filled_volume      — int,   已成交数量\r\n      filled_vwap        — float, 已成交均价\r\n      created_at         — datetime, 创建时间\r\n      rejection_reason   — str,   仅 status=7 时有值（拒单原因）\r\n    \"\"\"\r\n\r\n    # 状态码映射（完整版，含回测特有码）\r\n    status_map = {\r\n        1: '新建(New)',\r\n        2: '已报(Sent)',\r\n        3: '部分成交(PartiallyFilled)',\r\n        4: '已成交(Filled)',\r\n        5: '已撤(Cancelled)',\r\n        6: '未成交(Expired)',          # 限价超时未成交\r\n        7: '拒绝(Rejected)',            # ⚠️ 含 rejection_reason\r\n        8: '待撤(Cancelling)',          # 正在撤销\r\n        9: '未知(Unknown)',\r\n        10: '内部态(Internal)',          # ⚠️ 回测模式特有！文档未记录\r\n    }\r\n\r\n    status = order.get('status') if isinstance(order, dict) else getattr(order, status, None)\r\n    status_text = status_map.get(status, f'未知({status})')\r\n\r\n    if status == 7:\r\n        reason = order.get('rejection_reason') if isinstance(order, dict) \\\r\n                 else getattr(order, 'rejection_reason', None)\r\n        print(f'❌ 订单被拒绝! 原因: {reason}')\r\n```\r\n\r\n**实测状态流转（2026-04-17 验证）**：\r\n\r\n| 下单方式 | 触发的状态序列 | 备注 |\r\n|----------|---------------|------|\r\n| `order_volume` 市价买 | **10 → 8** | 资金不足时：内部态→待撤 |\r\n| `order_target_volume` 买 | **10 → 1 → 3** | 内部态→新建→部分成交 |\r\n| `order_target_volume` 卖 | **10 → 1 → 3** | 内部态→新建→部分成交 |\r\n| `order_volume` 限价(低价) | **10 → 8** | 不会成交→自动撤单 |\r\n| 超额卖出 | **10 → 8** | 回测不报Rejected，变Cancelling |\r\n| 超额买入(资金不足) | **10 → 8** | 同上 |\r\n\r\n**⚠️ 关键发现**：\r\n- **回测模式没有 Rejected(7)**：所有风控违规（超额/资金不足）都变为 Cancelling(8)\r\n- **要测试 Rejected(7)**：必须用 **live（仿真/实盘）** 模式\r\n- 状态 **10** 是回测内部中间态，每个订单首先收到一个 status=10\r\n- `order_target_volume` 会产生比 `order_volume` 更多的状态事件（多了 New → PartiallyFilled 流转）\n\nFile v1.0.2:references/04-market-data.md\n\n# 行情数据查询\r\n\r\n## current - 查询当前行情快照\r\n\r\n```python\r\ncurrent(symbols, fields='', include_call_auction=False)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbols | str or list | 标的代码 |\r\n| fields | str | 返回字段，默认所有 |\r\n| include_call_auction | bool | 是否支持集合竞价(09:15-09:25)取数，默认 False |\r\n\r\n**返回值**：`list[dict]`，每项是一个 tick 字典\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\nresult = current(symbols='SZSE.000001,SHSE.600000')\r\nfor item in result:\r\n    print(item['symbol'], item['price'])\r\n```\r\n\r\n**注意**：\r\n- 实时模式返回最新 tick，回测模式只有 symbol/price/created_at 有效\r\n- 集合竞价阶段有效字段只有 quotes\r\n\r\n---\r\n\r\n## history - 查询历史行情\r\n\r\n```python\r\nhistory(symbol, frequency, start_time, end_time,\r\n        fields=None, skip_suspended=True, fill_missing=None,\r\n        adjust=ADJUST_NONE, adjust_end_time='', df=True)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| symbol | str or list | 标的代码，支持多标的 |\r\n| frequency | str | 频率：`'tick'`、`'60s'`、`'300s'`、`'1d'` 等 |\r\n| start_time | str/datetime | 开始时间 `%Y-%m-%d %H:%M:%S` |\r\n| end_time | str/datetime | 结束时间 `%Y-%m-%d %H:%M:%S` |\r\n| fields | str | 指定字段，默认全部 |\r\n| adjust | int | 复权：`ADJUST_NONE=0`、`ADJUST_PREV=1`、`ADJUST_POST=2` |\r\n| adjust_end_time | str | 复权基点时间，默认当前 |\r\n| df | bool | True=返回 DataFrame，False=返回 list[dict] |\r\n\r\n```python\r\n# 查询日线（前复权），返回 DataFrame\r\ndf = history(symbol='SHSE.600000', frequency='1d',\r\n             start_time='2024-01-01', end_time='2024-12-31',\r\n             fields='open,high,low,close,volume,eob',\r\n             adjust=ADJUST_PREV, df=True)\r\n\r\n# 查询多标的\r\ndf = history(symbol='SHSE.600000,SZSE.000001', frequency='1d',\r\n             start_time='2024-01-01', end_time='2024-01-31',\r\n             df=True)\r\n\r\n# 返回 list[dict]\r\ndata = history(symbol='SHSE.000300', frequency='1d',\r\n               start_time='2024-01-01', end_time='2024-01-05',\r\n               adjust=ADJUST_PREV, df=False)\r\n```\r\n\r\n**注意**：\r\n- 数据区间采用**前开后闭**方式，按 eob 升序排序\r\n- 单次最多返回 33000 条\r\n- start_time/end_time 输入不存在的日期会报错\r\n- `skip_suspended` 和 `fill_missing` 目前暂不支持\r\n\r\n---\r\n\r\n## history_n - 查询最新 N 条历史行情\r\n\r\n```python\r\nhistory_n(symbol, frequency, count, end_time=None,\r\n          fields=None, skip_suspended=True, fill_missing=None,\r\n          adjust=ADJUST_NONE, adjust_end_time='', df=False)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 单标的代码（不支持多标的） |\r\n| count | 取最新 N 条 |\r\n| end_time | 结束时间，默认 None（取实际当前时间，非回测时间） |\r\n\r\n```python\r\n# 取最新100条日线（前复权）\r\ndf = history_n(symbol='SHSE.600519', frequency='1d', count=100,\r\n               end_time='2024-12-31 15:30:00',\r\n               fields='symbol,open,close,high,low,eob',\r\n               adjust=ADJUST_PREV, df=True)\r\nprint(df.tail())\r\n```\r\n\r\n---\r\n\r\n## context.data - 获取订阅数据滑窗\r\n\r\n> 必须先调用 `subscribe` 才能使用\r\n\r\n```python\r\ndata = context.data(symbol, frequency, count, fields)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 单标的（不支持多标的） |\r\n| frequency | 必须是已订阅的频率 |\r\n| count | 必须 ≤ subscribe 里的 count |\r\n| fields | 必须在 subscribe 的 fields 范围内 |\r\n\r\n返回格式与 subscribe 的 format 参数一致：\r\n- `format='df'`（默认）→ DataFrame\r\n- `format='row'` → list[dict]\r\n- `format='col'` → dict（col 模式下 tick 的 quotes 被拆分，只有买卖一档）\r\n\r\n```python\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600519', frequency='60s', count=50,\r\n              fields='symbol,close,eob', format='df')\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol=bars[0]['symbol'], frequency='60s', count=20)\r\n    ma5 = data['close'].rolling(5).mean()\r\n    print(ma5.tail())\r\n```\n\nFile v1.0.2:references/05-l2-data.md\n\n# L2 行情数据查询（付费专项）\r\n\r\n> 以下所有接口**仅特定付费券商托管版**可用\r\n\r\n## get_history_l2ticks - 查询历史 L2 Tick\r\n\r\n```python\r\nget_history_l2ticks(symbols, start_time, end_time, fields=None,\r\n                    skip_suspended=True, fill_missing=None,\r\n                    adjust=ADJUST_NONE, adjust_end_time='', df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据；时间跨度超过 31 天则返回空。\r\n\r\n```python\r\nticks = get_history_l2ticks('SHSE.600519', '2024-11-23 14:00:00',\r\n                             '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n---\r\n\r\n## get_history_l2bars - 查询历史 L2 Bar\r\n\r\n```python\r\nget_history_l2bars(symbols, frequency, start_time, end_time,\r\n                   fields=None, skip_suspended=True, fill_missing=None,\r\n                   adjust=ADJUST_NONE, adjust_end_time='', df=False)\r\n```\r\n\r\n**限制**：每次最多取 **31 天**（1 个自然月）。\r\n\r\n```python\r\nbars = get_history_l2bars('SHSE.600000', '60s',\r\n                          '2024-11-01 09:30:00', '2024-11-30 15:30:00',\r\n                          df=True)\r\n```\r\n\r\n---\r\n\r\n## get_history_l2transactions - 查询历史 L2 逐笔成交\r\n\r\n```python\r\nget_history_l2transactions(symbols, start_time, end_time, fields=None, df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据。\r\n\r\n```python\r\ntrans = get_history_l2transactions('SHSE.600000',\r\n                                   '2024-11-23 14:00:00',\r\n                                   '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n返回字段：`symbol`、`side`（沪市：B/S/N）、`price`、`volume`、`exec_type`（深市：4=撤单，F=成交）、`created_at`\r\n\r\n---\r\n\r\n## get_history_l2orders - 查询历史 L2 逐笔委托\r\n\r\n> 仅深市标的可用\r\n\r\n```python\r\nget_history_l2orders(symbols, start_time, end_time, fields=None, df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据。\r\n\r\n```python\r\norders = get_history_l2orders('SZSE.000001',\r\n                              '2024-11-23 14:00:00',\r\n                              '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n返回字段：`symbol`、`side`（深市：1=买，2=卖，F=借入，G=出借；沪市：B=买，S=卖）、`price`、`volume`、`order_type`、`order_index`、`created_at`\r\n\r\n---\r\n\r\n## get_history_l2orders_queue - 查询历史 L2 委托队列\r\n\r\n```python\r\nget_history_l2orders_queue(symbols, start_time, end_time, fields=None, df=False)\r\n```\r\n\r\n**限制**：每次只能取**一天**数据。\r\n\r\n```python\r\nqueue = get_history_l2orders_queue('SZSE.000001',\r\n                                   '2024-11-23 14:00:00',\r\n                                   '2024-11-23 15:00:00', df=True)\r\n```\r\n\r\n返回字段：`symbol`、`price`、`total_orders`（委托总数）、`queue_orders`（队列数）、`queue_volumes`（前50个委托量列表）、`side`、`volume`、`created_at`\n\nFile v1.0.2:references/06-symbol-info.md\n\n# 标的信息查询\r\n\r\n## get_symbol_infos - 查询标的基本信息（静态信息）\r\n\r\n> 与时间无关，返回标的基础属性\r\n\r\n```python\r\nget_symbol_infos(sec_type1, sec_type2=None, exchanges=None, symbols=None, df=False)\r\n```\r\n\r\n| 参数 | 类型 | 必填 | 说明 |\r\n|------|------|------|------|\r\n| sec_type1 | int | **是** | 证券大类：1010=股票，1020=基金，1030=债券，1040=期货，1050=期权，1060=指数，1070=板块 |\r\n| sec_type2 | int | 否 | 证券细类（见下表） |\r\n| exchanges | str/list | 否 | 交易所代码，如 `'SHSE,SZSE'` |\r\n| symbols | str/list | 否 | 标的代码 |\r\n| df | bool | 否 | True=DataFrame，False=list[dict] |\r\n\r\n**sec_type2 细类表**：\r\n- 股票：101001=A股，101002=B股，101003=存托凭证\r\n- 基金：102001=ETF，102002=LOF，102005=FOF\r\n- 债券：103001=可转债，103003=国债，103006=企业债，103008=回购\r\n- 期货：104001=股指期货，104003=商品期货，104006=国债期货\r\n- 期权：105001=股票期权，105002=指数期权，105003=商品期权\r\n- 指数：106001=股票指数，106002=基金指数，106003=债券指数\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\n# 查询指定股票\r\ninfos = get_symbol_infos(sec_type1=1010, symbols='SHSE.600000,SZSE.000001', df=True)\r\n\r\n# 查询全部 A 股\r\ninfos = get_symbol_infos(sec_type1=1010, sec_type2=101001, df=True)\r\n\r\n# 查询全部 ETF\r\ninfos = get_symbol_infos(sec_type1=1020, sec_type2=102001, df=True)\r\n\r\n# 查询全部可转债\r\ninfos = get_symbol_infos(sec_type1=1030, sec_type2=103001, df=True)\r\n\r\n# 查询上交所股票期权\r\ninfos = get_symbol_infos(sec_type1=1050, sec_type2=105001, exchanges='SHSE', df=True)\r\n```\r\n\r\n**返回字段**：`symbol`、`sec_type1`、`sec_type2`、`board`、`exchange`、`sec_id`、`sec_name`、`sec_abbr`、`price_tick`、`trade_n`、`listed_date`、`delisted_date`、`underlying_symbol`（期货/期权/可转债）、`option_type`（欧式E/美式A）、`call_or_put`（C/P）\r\n\r\n---\r\n\r\n## get_symbols - 查询指定交易日多标的交易信息\r\n\r\n> 返回基本信息 + 当日行情信息（涨跌停、换手率等）\r\n\r\n```python\r\nget_symbols(sec_type1, sec_type2=None, exchanges=None, symbols=None,\r\n            skip_suspended=True, skip_st=True, trade_date=None, df=False)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| skip_suspended | 是否跳过停牌，默认 True |\r\n| skip_st | 是否跳过 ST 类股票，默认 True |\r\n| trade_date | 交易日期 `%Y-%m-%d`，默认 None=最新截面 |\r\n\r\n```python\r\n# 获取全 A 股今日信息（含涨跌停价）\r\ndf = get_symbols(sec_type1=1010, sec_type2=101001, df=True)\r\nsymbols_list = df['symbol'].tolist()\r\n\r\n# 指定交易日\r\ndf = get_symbols(sec_type1=1010, symbols='SHSE.600000,SZSE.000001',\r\n                 trade_date='2024-01-15', df=True)\r\n```\r\n\r\n**额外返回字段（比 get_symbol_infos 多）**：\r\n`trade_date`、`pre_close`、`upper_limit`（涨停价）、`lower_limit`（跌停价）、`turn_rate`（换手率%）、`adj_factor`（复权因子）、`is_suspended`（是否停牌）、`is_st`（是否ST）、`margin_ratio`（期货保证金比例）、`multiplier`（合约乘数）\r\n\r\n---\r\n\r\n## get_history_symbol - 查询指定标的多日历史交易信息\r\n\r\n```python\r\nget_history_symbol(symbol=None, start_date=None, end_date=None, df=False)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 单个标的代码（必填） |\r\n| start_date | 开始日期 `%Y-%m-%d` |\r\n| end_date | 结束日期 `%Y-%m-%d` |\r\n\r\n```python\r\n# 查询某标的历史涨跌停价变化\r\ndf = get_history_symbol(symbol='SHSE.600000',\r\n                        start_date='2024-01-01',\r\n                        end_date='2024-12-31', df=True)\r\n```\r\n\r\n**注意**：`get_history_symbol` 可在 `init` 里批量预取，按 (symbol, date) 做索引，提高回测效率：\r\n```python\r\ndef init(context):\r\n    instruments = get_history_symbol(symbol='SZSE.000001',\r\n                                     start_date=context.backtest_start_time,\r\n                                     end_date=context.backtest_end_time)\r\n    context.ins_dict = {(i.symbol, i.trade_date.date()): i for i in instruments}\r\n\r\ndef on_bar(context, bars):\r\n    info = context.ins_dict[(bars[0].symbol, bars[0].eob.date())]\r\n    print(info.upper_limit)\r\n```\n\nFile v1.0.2:references/07-trading-dates.md\n\n# 交易日历查询\r\n\r\n## get_trading_dates - 查询交易日列表\r\n\r\n```python\r\nget_trading_dates(exchange, start_date, end_date, df=False)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| exchange | str | 交易所代码：`'SHSE'`、`'SZSE'`、`'CFFEX'`、`'SHFE'`、`'DCE'`、`'CZCE'` 等 |\r\n| start_date | str | 开始日期 `%Y-%m-%d` |\r\n| end_date | str | 结束日期 `%Y-%m-%d` |\r\n| df | bool | True=DataFrame，False=list[datetime] |\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\n# 获取上交所 2024 年全年交易日\r\ndates = get_trading_dates('SHSE', '2024-01-01', '2024-12-31')\r\nprint(f'2024年共 {len(dates)} 个交易日')\r\n\r\n# 返回 DataFrame\r\ndf = get_trading_dates('SHSE', '2024-01-01', '2024-01-31', df=True)\r\n```\r\n\r\n---\r\n\r\n## get_previous_trading_date - 查询上一交易日\r\n\r\n```python\r\nget_previous_trading_date(exchange, date)\r\n```\r\n\r\n```python\r\nprev = get_previous_trading_date('SHSE', '2024-01-15')\r\nprint('上一交易日:', prev)  # datetime 对象\r\n```\r\n\r\n---\r\n\r\n## get_next_trading_date - 查询下一交易日\r\n\r\n```python\r\nget_next_trading_date(exchange, date)\r\n```\r\n\r\n```python\r\nnext_day = get_next_trading_date('SHSE', '2024-01-15')\r\nprint('下一交易日:', next_day)\r\n```\r\n\r\n---\r\n\r\n## 实用场景\r\n\r\n### 判断今天是否交易日\r\n```python\r\nfrom gm.api import *\r\nfrom datetime import date\r\n\r\nset_token('YOUR_TOKEN')\r\ntoday = str(date.today())\r\ndates = get_trading_dates('SHSE', today, today)\r\nis_trading = len(dates) > 0\r\nprint('今天是否交易日:', is_trading)\r\n```\r\n\r\n### 获取本月所有交易日\r\n```python\r\nimport calendar\r\nfrom datetime import date\r\n\r\nyear, month = 2024, 12\r\n_, last_day = calendar.monthrange(year, month)\r\nstart = f'{year}-{month:02d}-01'\r\nend = f'{year}-{month:02d}-{last_day}'\r\ndates = get_trading_dates('SHSE', start, end)\r\nprint(f'{year}年{month}月共 {len(dates)} 个交易日')\r\n```\n\nFile v1.0.2:references/08-order-api.md\n\n# 交易下单 API\r\n\r\n> 所有下单函数只能在策略事件回调中使用（`on_bar`、`on_tick`、`algo` 定时任务等）\r\n> 回测模式下 `init` 中不支持交易操作\r\n\r\n## 常用枚举常量\r\n\r\n```python\r\n# 买卖方向\r\nOrderSide_Buy = 1   # 买入\r\nOrderSide_Sell = 2  # 卖出\r\n\r\n# 委托类型\r\nOrderType_Limit = 1    # 限价\r\nOrderType_Market = 2   # 市价\r\n\r\n# 开平标志\r\nPositionEffect_Open = 1   # 开仓\r\nPositionEffect_Close = 2  # 平仓（平昨）\r\nPositionEffect_Close_Today = 3  # 平今（期货）\r\n\r\n# 持仓方向\r\nPositionSide_Long = 1   # 多头\r\nPositionSide_Short = 2  # 空头\r\n```\r\n\r\n---\r\n\r\n## order_volume - 按数量下单\r\n\r\n```python\r\norder_volume(symbol, volume, side, order_type, position_effect,\r\n             price=0, account=None)\r\n```\r\n\r\n```python\r\n# 市价买入200股\r\norder_volume(symbol='SHSE.600000', volume=200, side=OrderSide_Buy,\r\n             order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n\r\n# 限价卖出100股\r\norder_volume(symbol='SZSE.000001', volume=100, side=OrderSide_Sell,\r\n             order_type=OrderType_Limit, position_effect=PositionEffect_Close, price=16.5)\r\n```\r\n\r\n---\r\n\r\n## order_value - 按金额下单\r\n\r\n```python\r\norder_value(symbol, value, side, order_type, position_effect,\r\n            price=0, account=None)\r\n```\r\n\r\n```python\r\n# 买入10000元的股票\r\norder_value(symbol='SHSE.600000', value=10000, side=OrderSide_Buy,\r\n            order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n```\r\n\r\n---\r\n\r\n## order_percent - 按账户总资产比例下单\r\n\r\n```python\r\norder_percent(symbol, percent, side, order_type, position_effect,\r\n              price=0, account=None)\r\n```\r\n\r\n```python\r\n# 买入账户总资产的1%\r\norder_percent(symbol='SHSE.600000', percent=0.01, side=OrderSide_Buy,\r\n              order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n```\r\n\r\n---\r\n\r\n## order_target_volume - 调仓到目标数量\r\n\r\n> 自动计算差值，决定买入或卖出\r\n\r\n```python\r\norder_target_volume(symbol, volume, position_side=PositionSide_Long,\r\n                    order_type=OrderType_Market, price=0, account=None)\r\n```\r\n\r\n```python\r\n# 调整到持有500股（多头）\r\norder_target_volume(symbol='SHSE.600000', volume=500,\r\n                    position_side=PositionSide_Long,\r\n                    order_type=OrderType_Market)\r\n```\r\n\r\n---\r\n\r\n## order_target_value - 调仓到目标金额\r\n\r\n```python\r\norder_target_value(symbol, value, position_side=PositionSide_Long,\r\n                   order_type=OrderType_Market, price=0, account=None)\r\n```\r\n\r\n---\r\n\r\n## order_target_percent - 调仓到目标比例\r\n\r\n```python\r\norder_target_percent(symbol, percent, position_side=PositionSide_Long,\r\n                     order_type=OrderType_Market, price=0, account=None)\r\n```\r\n\r\n```python\r\n# 调整到账户总资产的10%\r\norder_target_percent(symbol='SHSE.600000', percent=0.1,\r\n                     position_side=PositionSide_Long,\r\n                     order_type=OrderType_Market)\r\n```\r\n\r\n---\r\n\r\n## order_cancel - 撤销委托\r\n\r\n```python\r\norder_cancel(wait_cancel_orders, account=None)\r\n```\r\n\r\n```python\r\n# 撤销指定委托\r\norders = get_orders()  # 先获取委托列表\r\norder_cancel(wait_cancel_orders=orders)\r\n```\r\n\r\n---\r\n\r\n## order_close_all - 一键平仓\r\n\r\n```python\r\norder_close_all()\r\n```\r\n\r\n- 平掉当前账户所有持仓\r\n\r\n---\r\n\r\n## 实用组合示例\r\n\r\n```python\r\ndef on_bar(context, bars):\r\n    bar = bars[0]\r\n    symbol = bar['symbol']\r\n    \r\n    # 获取当前持仓\r\n    pos = context.account().position(symbol=symbol, side=PositionSide_Long)\r\n    \r\n    # 无持仓时买入\r\n    if not pos:\r\n        cash = context.account().cash\r\n        available = cash['available']\r\n        if available > 10000:\r\n            order_percent(symbol=symbol, percent=0.1, side=OrderSide_Buy,\r\n                          order_type=OrderType_Market,\r\n                          position_effect=PositionEffect_Open)\r\n    else:\r\n        # 已有持仓时全部卖出\r\n        order_target_volume(symbol=symbol, volume=0,\r\n                            position_side=PositionSide_Long,\r\n                            order_type=OrderType_Market)\r\n```\n\nFile v1.0.2:references/09-algo-order.md\n\n# 算法委托（TWAP/VWAP 等）\r\n\r\n## algo_order - 算法下单\r\n\r\n```python\r\nalgo_order(symbol, volume, side, position_effect, order_type,\r\n           price=0, algo_name='', algo_param={}, account=None)\r\n```\r\n\r\n| 参数 | 说明 |\r\n|------|------|\r\n| symbol | 标的代码 |\r\n| volume | 委托量 |\r\n| side | 买卖方向（OrderSide_Buy/Sell） |\r\n| position_effect | 开平标志 |\r\n| order_type | 委托类型 |\r\n| algo_name | 算法名称，如 `'TWAP'`、`'VWAP'` |\r\n| algo_param | 算法参数 dict |\r\n\r\n```python\r\n# TWAP 算法买入\r\nalgo_order(symbol='SHSE.600000', volume=1000, side=OrderSide_Buy,\r\n           position_effect=PositionEffect_Open,\r\n           order_type=OrderType_Market,\r\n           algo_name='TWAP',\r\n           algo_param={'start_time': '09:30:00', 'end_time': '15:00:00'})\r\n```\r\n\r\n## algo_order_cancel - 取消算法委托\r\n\r\n```python\r\nalgo_order_cancel(wait_cancel_algo_orders, account=None)\r\n```\r\n\r\n---\r\n\r\n# 账户与资金查询\r\n\r\n## get_orders - 查询委托列表\r\n\r\n```python\r\nget_orders(account=None)\r\n```\r\n\r\n返回 `list[dict]`，每项为 Order 委托对象。\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')\r\n\r\norders = get_orders()\r\nfor order in orders:\r\n    print(order['symbol'], order['status'], order['volume'])\r\n```\r\n\r\n**委托状态 OrderStatus**：\r\n- 1=待报，2=已报，3=已报待撤，4=部成待撤，5=部撤，6=已撤，7=已成，8=废单，10=已报待改\r\n\r\n---\r\n\r\n## get_execution_reports - 查询成交回报\r\n\r\n```python\r\nget_execution_reports(account=None)\r\n```\r\n\r\n返回 `list[dict]`，每项为 ExecRpt 回报对象。\r\n\r\n---\r\n\r\n## get_cash - 查询账户资金\r\n\r\n```python\r\nget_cash(account=None)\r\n```\r\n\r\n返回资金 dict：\r\n\r\n| 字段 | 说明 |\r\n|------|------|\r\n| nav | 总资产 |\r\n| available | 可用资金 |\r\n| fpnl | 浮动盈亏 |\r\n| market_value | 持仓市值 |\r\n| balance | 资金余额 |\r\n| order_frozen | 冻结资金 |\r\n\r\n```python\r\ncash = get_cash()\r\nprint(f\"总资产: {cash['nav']:.2f}\")\r\nprint(f\"可用资金: {cash['available']:.2f}\")\r\n```\r\n\r\n---\r\n\r\n## get_position - 查询持仓\r\n\r\n```python\r\nget_position(symbol=None, side=None, account=None)\r\n```\r\n\r\n```python\r\n# 查询全部持仓\r\npositions = get_position()\r\n\r\n# 查询指定标的多头持仓\r\npos = get_position(symbol='SHSE.600000', side=PositionSide_Long)\r\nif pos:\r\n    print(f\"持仓量: {pos[0]['volume']}\")\r\n    print(f\"持仓均价: {pos[0]['vwap']}\")\r\n    print(f\"浮动盈亏: {pos[0]['fpnl']}\")\r\n```\r\n\r\n**Position 对象关键字段**：\r\n\r\n| 字段 | 说明 |\r\n|------|------|\r\n| symbol | 标的代码 |\r\n| side | 持仓方向 |\r\n| volume | 总持仓量 |\r\n| volume_today | 今日买入量 |\r\n| available | 可用持仓（非冻结） |\r\n| vwap | 持仓均价 |\r\n| market_value | 持仓市值 |\r\n| fpnl | 浮动盈亏 |\r\n| amount | 持仓额 |\r\n\r\n---\r\n\r\n## context.account() - 在策略中查询账户\r\n\r\n```python\r\n# 获取所有持仓\r\nall_positions = context.account().positions()\r\n\r\n# 获取指定持仓\r\npos = context.account().position(symbol='SHSE.600519', side=PositionSide_Long)\r\n\r\n# 获取资金\r\ncash = context.account().cash\r\n\r\n# 账户状态\r\nstatus = context.account().status\r\n```\n\nArchive v1.0.1: 33 files, 86102 bytes\n\nFiles: README.md (5750b), references/01-quick-start.md (3240b), references/02-core-functions.md (3448b), references/03-subscribe-events.md (8188b), references/04-market-data.md (4163b), references/05-l2-data.md (2886b), references/06-symbol-info.md (4317b), references/07-trading-dates.md (1904b), references/08-order-api.md (4221b), references/09-algo-order.md (3172b), references/10-account-query.md (510b), references/11-bond-convertible.md (1725b), references/12-data-objects.md (3137b), references/13-enums.md (2189b), references/14-context.md (2489b), references/16-premium-data-apis.md (5855b), references/17-financial-data-fields.md (7528b), references/18-user-guide.md (18464b), scripts/check_import.py (2479b), scripts/run_strategy.py (4672b), scripts/strategy_etf_momentum_rotation.py (12635b), scripts/strategy_etf_momentum.py (11113b), scripts/strategy_etf_rotation.py (11611b), scripts/strategy_event_callbacks_test.py (20973b), scripts/strategy_high_dividend.py (14302b), scripts/strategy_ma_cross.py (4124b), scripts/strategy_xinyisheng_ma.py (4126b), scripts/test_account_apis.py (4653b), scripts/test_all_apis.py (8710b), scripts/test_financial_apis.py (8782b), SKILL.md (18288b), TEST_REPORT.md (4764b), _meta.json (126b)\n\nFile v1.0.1:SKILL.md\n\n---\r\nname: gm-quant\r\nversion: 2.0.0\r\ndescription: >\r\n  掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、\r\n  量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、\r\n  order_volume、subscribe、history、set_token、get_symbols、get_symbol_infos、\r\n  get_history_symbol、history_n、current、get_trading_dates、\r\n  order_percent、order_value、order_target_volume、algo_order、\r\n  get_orders、get_position、get_cash、bond_convertible、\r\n  L2行情、逐笔成交、逐笔委托、schedule定时任务、\r\n  财务数据、资产负债表、利润表、现金流量表、估值指标、PE/PB/PS/股息率、\r\n  市值、股本、流通股、成分股、行业分类、\r\n  可转债分析、转股溢价率、纯债价值、ETF成分股、基金净值、\r\n  期货合约信息、仓单数据、成交持仓排名、\r\n  stk_get_fundamentals、stk_get_daily_valuation、stk_get_index_constituents、\r\n  bnd_get_analysis、fnd_get_portfolio、fut_get_contract_info\r\n  时，自动加载此 skill。\r\n---\r\n\r\n# 掘金量化 SDK 技能 — v2.0 自然语言策略引擎\r\n\r\n## 定位\r\n\r\n你是**掘金量化平台的自然语言策略助手**。用户用中文描述交易想法，你负责：\r\n1. **理解需求** → 提炼策略逻辑（标的/信号/风控）\r\n2. **生成代码** → 输出可直接运行的完整策略 `.py` 文件\r\n3. **执行运行** → 调用 `scripts/run_strategy.py` 一键启动回测或实盘\r\n\r\n## 核心原则\r\n\r\n1. **必须先 set_token**：纯数据查询（非策略 run）场景下，代码开头必须调用 `set_token('your_token')`。\r\n2. **symbol 格式**：`交易所代码.证券代码`，如 `SHSE.600000`、`SZSE.000001`，**严格区分大小写**。\r\n3. **gm 包通过掘金终端连接**：终端必须保持打开，否则接口会超时或报错。\r\n4. **两种模式**：`MODE_LIVE=1`（实时/仿真）、`MODE_BACKTEST=2`（回测）；`run()` 函数启动策略。\r\n5. **数据查询不需要 run**：仅用 `set_token` 后直接调用数据函数即可。\r\n\r\n## 🚀 用户工作流（自然语言→运行）\r\n\r\n### 第 0 步：确认 Strategy ID（重要！）\r\n\r\n**每次生成策略前，必须向用户索要 `strategy_id`。**\r\n\r\n`strategy_id` 是策略在掘金终端中的唯一标识。填写后：\r\n- 回测结果**持久化**到掘金终端后台\r\n- 用户登录 [掘金终端网页](https://www.myquant.cn) → 策略列表 → 查看完整的**绩效分析图表**\r\n  （收益曲线、回撤分析、夏普比率、持仓明细等）\r\n\r\n> **交互方式**：如果用户没有主动提供 strategy_id，在生成代码前询问：\r\n> \"请给我一个 **strategy_id**（英文/数字/下划线），用于在掘金终端标识这个策略。\r\n> 填完后你可以在终端网页上看到绩效分析图表。例如：`ma_cross_600519`、`momentum_v1`\"\r\n\r\n| 场景 | 处理方式 |\r\n|------|---------|\r\n| 用户提供了 strategy_id | 直接使用 |\r\n| 用户没提供 | **必须追问**，不能自己编造一个默认值后静默使用 |\r\n| 用户说\"随便起一个\" | 根据策略特征起一个有意义的名字（如 `dual_ma_kweichow`） |\r\n\r\n### 第一步：理解用户意图\r\n\r\n当用户用自然语言描述策略时，按以下维度提取信息：\r\n\r\n| 维度 | 需确认的信息 | 默认值（如未明确说明） |\r\n|------|-------------|---------------------|\r\n| **strategy_id** | 策略在掘金终端的标识（**必须用户提供，见第0步**） | 无默认，必须询问 |\r\n| **标的池** | 哪些股票/指数？ | 沪深300成分股 |\r\n| **时间频率** | 日线/分钟线/tick？ | 日线 `1d` |\r\n| **买入信号** | 什么条件买入？（均线/指标/事件） | 必须明确，不能猜测 |\r\n| **卖出信号** | 什么条件卖出？ | 必须明确，不能猜测 |\r\n| **仓位管理** | 全仓/固定金额/比例/等权 | 等权分配 |\r\n| **止损止盈** | 有无？阈值多少？ | 无 |\r\n| **回测区间** | 开始~结束日期 | 最近1年 |\r\n| **初始资金** | 多少钱？ | 100万 |\r\n| **运行模式** | 回测还是实盘？ | 先回测 |\r\n\r\n> ⚠️ **如果用户描述模糊（如\"帮我做个赚钱的策略\"），必须追问具体条件后再生成代码。**\r\n\r\n### 第二步：生成策略文件\r\n\r\n使用下方**标准策略模板**生成完整 `.py` 文件，保存到用户的输出目录：\r\n\r\n```python\r\n\"\"\"\r\n策略名称：{name}\r\n策略描述：{description}\r\n生成时间：{date}\r\n\"\"\"\r\n\r\nimport sys, os, io\r\nsys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')\r\n\r\nfrom gm.api import *\r\n\r\n# ============================================================\r\n# 配置区 —— 用户可通过修改此处调整策略参数\r\n# ============================================================\r\nSYMBOLS = 'SHSE.600519,SZSE.000001'      # 标的（逗号分隔）\r\nFREQUENCY = '1d'                          # K线周期：1d/60s/300s/tick\r\nCOUNT = 20                                # 订阅K线数量（context.data滑窗大小）\r\n\r\n# 交易参数\r\nORDER_TYPE = OrderType_Market              # 下单方式：Market(市价) / Limit(限价)\r\nPOSITION_PCT = 0.2                        # 单只股票仓位占比（0~1）\r\n\r\n# 回测参数\r\nBACKTEST_START = '2024-01-02 09:30:00'\r\nBACKTEST_END   = '2025-12-31 15:30:00'\r\nINITIAL_CASH   = 1000000                  # 初始资金\r\nCOMMISSION     = 0.00025                  # 手续费率\r\nSLIPPAGE       = 0.001                    # 滑点\r\n\r\n\r\n# ============================================================\r\n# 策略逻辑\r\n# ============================================================\r\n\r\ndef init(context):\r\n    \"\"\"初始化：订阅行情\"\"\"\r\n    log.info(f'策略启动 | 标的:{SYMBOLS} | 周期:{FREQUENCY}')\r\n    subscribe(symbols=SYMBOLS, frequency=FREQUENCY, count=COUNT)\r\n\r\n    # 存储策略状态\r\n    context.last_signal = {}  # {symbol: last_signal_time}\r\n\r\n\r\ndef on_bar(context, bars):\r\n    \"\"\"每根K线触发\"\"\"\r\n    for bar in bars:\r\n        symbol = bar['symbol']\r\n        try:\r\n            _handle_bar(context, symbol)\r\n        except Exception as e:\r\n            log.error(f'处理{symbol}异常: {e}')\r\n\r\n\r\ndef on_tick(context, tick):\r\n    \"\"\"tick级别回调（如订阅了tick会走这里）\"\"\"\r\n    pass\r\n\r\n\r\ndef _handle_bar(context, symbol):\r\n    \"\"\"单只标的策略逻辑\"\"\"\r\n\r\n    # 1. 获取历史数据（滑窗内）—— 注意返回 DataFrame\r\n    data = context.data(symbol=symbol, frequency=FREQUENCY, count=COUNT)\r\n    if data is None or len(data) < COUNT:\r\n        return\r\n\r\n    # 2. 获取当前持仓 —— get_position() 不带参数，返回全部持仓列表\r\n    all_positions = get_position()\r\n    position = None\r\n    if all_positions:\r\n        for p in all_positions:\r\n            sym = p.get('symbol') if isinstance(p, dict) else (p.symbol if hasattr(p, 'symbol') else None)\r\n            if sym == symbol:\r\n                position = p\r\n                break\r\n\r\n    # ========================================\r\n    # 【策略核心】在此处实现买卖信号\r\n    # ========================================\r\n\r\n    # 示例：双均线策略\r\n    close = data['close'].tolist()\r\n    ma_short = sum(close[-5:]) / 5    # MA5\r\n    ma_long  = sum(close[-20:]) / 20  # MA20\r\n    prev_ma5 = sum(close[-6:-1]) / 5 if len(close) >= 6 else ma_short\r\n    prev_ma20 = sum(close[-26:-6]) / 20 if len(close) >= 27 else ma_long\r\n\r\n    buy_signal  = (prev_ma5 <= prev_ma20) and (ma_short > ma_long)\r\n    sell_signal = (prev_ma5 >= prev_ma20) and (ma_short < ma_long)\r\n\r\n    # ========================================\r\n    # 3. 执行交易\r\n    # ========================================\r\n\r\n    current_price = close[-1]\r\n    cash_info = get_cash()\r\n\r\n    if buy_signal and not position:\r\n        # 买入：按仓位比例计算金额\r\n        available = cash_info.available\r\n        order_value = available * POSITION_PCT\r\n        if order_value > 10000:  # 最少1万元\r\n            volume = int(order_value / current_price / 100) * 100  # A股必须100股整数倍\r\n            order_volume(symbol, volume,\r\n                         side=OrderSide_Buy,\r\n                         position_effect=PositionEffect_Open,\r\n                         order_type=ORDER_TYPE)\r\n            print(f'[买入] {symbol} 价格={current_price:.2f} 数量={volume}')\r\n\r\n    elif sell_signal and position:\r\n        # 卖出：清仓该标的（注意用 position_side 不是 position_effect）\r\n        order_target_volume(symbol, 0,\r\n                            position_side=PositionSide_Long,\r\n                            order_type=ORDER_TYPE)\r\n        print(f'[卖出] {symbol} 价格={current_price:.2f}')\r\n\r\n\r\ndef handle_error(context, error_code, error_msg, **kwargs):\r\n    \"\"\"错误处理\"\"\"\r\n    log.error(f'策略异常 [{error_code}]: {msg}')\r\n\r\n\r\n# ============================================================\r\n# 启动入口\r\n# ============================================================\r\nif __name__ == '__main__':\r\n    # 从环境变量读取参数（由 run_strategy.py 传入）\r\n    TOKEN = os.environ.get('GM_TOKEN', '') or ''\r\n    MODE = os.environ.get('GM_RUN_MODE', 'backtest')\r\n    STRATEGY_ID = os.environ.get('GM_STRATEGY_ID', '') or 'my_strategy'\r\n    START = os.environ.get('GM_BACKTEST_START', BACKTEST_START)\r\n    END = os.environ.get('GM_BACKTEST_END', BACKTEST_END)\r\n    CASH = float(os.environ.get('GM_INITIAL_CASH', str(INITIAL_CASH)))\r\n\r\n    mode = MODE_LIVE if MODE.lower() in ('live', 'realtime') else MODE_BACKTEST\r\n\r\n    run(\r\n        strategy_id=STRATEGY_ID,\r\n        filename=__file__[:__file__.rfind('.')] if '.' in __file__ else __file__,\r\n        mode=mode,\r\n        token=TOKEN,\r\n        backtest_start_time=START,\r\n        backtest_end_time=END,\r\n        backtest_initial_cash=CASH,\r\n        backtest_commission_ratio=COMMISSION,\r\n        backtest_slippage_ratio=SLIPPAGE,\r\n        backtest_adjust=ADJUST_PREV,\r\n    )\r\n```\r\n\r\n### 第三步：执行策略\r\n\r\n使用运行器脚本一键执行：\r\n\r\n```bash\r\npython scripts/run_strategy.py --strategy <策略文件路径> --strategy-id <你的策略ID> [--mode backtest|live] [--token YOUR_TOKEN]\r\n```\r\n\r\n> **`--strategy-id` 必填**：填写后回测结果会持久化到掘金终端，登录终端网页即可查看绩效分析图表（收益曲线、回撤、夏普比率等）。\r\n> 如果不填，回测结果仅在控制台输出，不会保存到终端。\r\n\r\n运行器脚本路径：`C:\\Users\\wjz\\.workbuddy\\skills\\gm-quant\\scripts\\run_strategy.py`\r\n\r\n## 参考文档索引\r\n\r\n详细 API 文档位于 `references/` 目录下：\r\n\r\n| 文件 | 内容 |\r\n|------|------|\r\n| `01-quick-start.md` | 快速开始、策略架构、运行模式 |\r\n| `02-core-functions.md` | `run`、`set_token`、`stop`、`schedule`、`timer` |\r\n| `03-subscribe-events.md` | `subscribe`、`unsubscribe`、`on_tick`、`on_bar`、`on_l2*` |\r\n| `04-market-data.md` | `current`、`history`、`history_n`、`context.data` |\r\n| `05-l2-data.md` | L2 行情查询接口（付费） |\r\n| `06-symbol-info.md` | 标的信息查询 API |\r\n| `07-trading-dates.md` | 交易日历 API |\r\n| `08-order-api.md` | 下单 API 全集 |\r\n| `09-algo-order.md` | 算法单 API |\r\n| `10-account-query.md` | 账户查询 API |\r\n| `11-bond-convertible.md` | 可转债交易 API |\r\n| `12-dataobjects.md` | 数据对象字段定义 |\r\n| `13-enums.md` | 枚举常量速查 |\r\n| `14-context.md` | context 对象 |\r\n\r\n## 常见问题 & 注意事项\r\n\r\n- `history()` 的 `df` 参数默认 `True` 返回 DataFrame，`False` 返回 `list[dict]`\r\n- 单次查询最多返回 33000 条数据\r\n- L2 数据接口（`get_history_l2*`）仅特定付费券商可用\r\n- `subscribe` 中 `count` 决定 `context.data` 的滑窗大小\r\n- 回测模式下 `init` 不支持交易操作\r\n- 虚拟合约（主力连续合约）仅在回测模式下可用，如 `SHFE.RB`\r\n- `get_trading_dates` 查交易日历时，`exchange` 参数用交易所代码如 `'SHSE'`\r\n- `run()` 参数名是 `strategy_id` 和 `filename`（模块名，不是文件路径！）\r\n- A 股最小下单单位为 100 股（1手），`order_volume` 必须是 100 的整数倍\r\n- `order_value` 会自动取整到 100 股倍数\r\n\r\n## 踩坑经验（实测验证）\r\n\r\n**以下坑点已通过实际运行验证，生成代码时必须遵守：**\r\n\r\n1. **`run()` 参数名**：是 `strategy_id` + `filename`（模块名，不带 .py 后缀），不是 `strategy_name` / `file_path`\r\n2. **`log()` 用法**：`log(msg, source)` 是普通函数，**不是** logger 对象。不要用 `log.info()`。推荐直接用 `print()`\r\n3. **`context.data()` 返回值**：返回的是 **DataFrame**（不是 dict list），用 `data['close'].tolist()` 访问数据列\r\n4. **`get_position()` 不带参数**：调用 `get_position()` 获取全部持仓列表，然后遍历查找目标 symbol 的持仓。不支持 `get_position(symbol=xxx)`\r\n5. **`order_target_volume()` 参数**：不需要 `side` 参数；用 `position_side=PositionSide_Long`（不是 `position_effect=PositionEffect_Close`）\r\n6. **`order_volume()` 买入参数**：需要 `side=OrderSide_Buy` + `position_effect=PositionEffect_Open`\r\n7. **Windows 编码**：脚本开头必须加 `sys.stdout = io.TextIOWrapper(...)` 否则中文 emoji 报错\r\n8. **A 股 T+1**：当天买入不能当天卖出，策略逻辑需要考虑这个约束\r\n9. **`cl_ord_id` 参数不存在**：`order_volume` / `order_value` / `order_target_volume` 等下单函数**不支持** `cl_ord_id` 参数。传入会直接抛 `TypeError: got an unexpected keyword argument 'cl_ord_id'`。订单标识由系统自动生成\r\n10. **`on_order_status` 回测模式状态码**：回测中会出现文档未记录的状态码 `10`（未知/内部中间态），实际运行时需兼容处理。完整状态码：1=新建, 2=已报, 3=部分成交, 4=已成交, 5=已撤, 6=未成交(超时), 7=拒绝, 8=待撤, 9=未知, **10=回测内部态**\r\n11. **`on_execution_report` 的 exec_type**：回测模式下返回数字而非字符，实测值为 `15`（成交确认）。实盘/仿真可能返回 `'T'`(Trade) / `'C'(Cancel)\r\n12. **回测中风控行为**：超额卖出或资金不足的订单在回测中不会触发 `Rejected(7)` 状态，而是变为 `Cancelling(8)` → 被自动撤销。**拒单原因需要实盘/仿真环境才能观察到**\r\n13. **`on_order_status` order 对象访问**：回调中的 order 对象**同时支持** dict 风格 `order['symbol']` 和属性风格 `order.symbol`，但推荐用 try/getattr 兼容两种方式\r\n14. **`on_execution_report` execrpt 对象访问**：同上，同时支持 dict 和属性风格。关键字段：`symbol`, `side`(1买2卖), `volume`, `price`, `exec_type`, `commission`\r\n15. **市价单在回测中也可能不成交**：如果资金不足（如下单量×价格 > 可用资金），市价单会被标记为 Cancelling 而非报错抛异常\r\n16. **`stk_get_index_constituents` 没有 `df` 参数**：直接返回 DataFrame，不需要传 df=True\r\n17. **财务数据 API 的 `fields` 必填且不能为空**：所有 `stk_get_fundamentals_*_pt` / `stk_get_finance_*_pt` / `stk_get_daily_*_pt` 函数的 `fields` 参数是必填的，不能传空字符串 `\"\"`，否则报错\"填写的 fields 不正确\"。fields 不能超过 20 个\r\n18. **`stk_get_finance_prime_pt` ROE 字段名是 `roe_weight_avg`**，不是 `roe_waa`。常用字段: eps_basic/eps_dil/roe_weight_avg/roe_weight_avg_cut/net_prof_pcom_yoy/inc_oper_yoy\r\n19. **`stk_get_daily_basic_pt` 股本字段名**：流通股本是 `circ_shr`（不是 float_shr），无限售条件流通股本是 `ttl_shr_unl`（不是 free_shr），有限售条件股本是 `ttl_shr_ltd`\r\n20. **财务衍生指标 `eps_dil2` vs `eps_dil`**：`stk_get_finance_deriv_pt` 中稀释 EPS 字段名是 `eps_dil2`（不是 `eps_dil`），而 `stk_get_finance_prime_pt` 中是 `eps_dil`\r\n21. **`_pt` 后缀 = 截面数据(多标的)**，无后缀 = 时序数据(单标的)。截面用 date/trade_date 参数，时序用 start_date/end_date 参数\r\n22. **付费增值数据 API**：期货(fut_get_*)、基金(fnd_get_*)、可转债(bnd_get_*) 的增值数据需要开通相应权限。详见 `references/16-premium-data-apis.md`\r\n23. **`stk_get_fundamentals_*_pt` 的 `date` 参数是发布日期**，不是报告期日期。返回的是发布日期 ≤ date 的最新报告期数据\r\n24. **`stk_get_daily_valuation_pt/mktvalue_pt/basic_pt` 的 `trade_date` 参数**：是交易日期，默认 None 返回最新交易日数据\r\n25. **回测交易日限制**：每个交易日 18:30 前只能回测上一个交易日的数据，因为当日日线数据要到 18:30 才更新完成。如果 `end_date` 设为当天但还没过 18:30，回测结果会缺少当日数据或报错\r\n26. **实时模式（仿真/实盘）没有发生交易的排查清单**：\r\n    - ① **定时任务时间过了**：`schedule` 定时任务只在指定时间触发，如果启动策略时已过了今天的时间点，要等到明天才会触发。临时解决：把时间改成当前时间之后几分钟\r\n    - ② **期货策略必须订阅具体合约**：实时模式只能推送具体合约行情（如 `SHFE.ag2506`），主连合约（如 `SHFE.agmain`）**没有行情推送**。回测可以主连，实时不行\r\n    - ③ **实时模式日线不会推送**：交易时间内日线还没走完，`on_bar` 不会收到日线 bar。需要用 `schedule` 定时任务替代，在收盘后（如 15:01）主动调用 `history` 获取日线数据\r\n    - ④ **检查打印日志**：确认是否有数据推送 → 是否有交易信号发出 → 是否有下单指令 → 订单状态是否正常。按这个链路逐级排查\r\n27. **`order_volume()` vs `order_target_volume/percent` 参数名不同**：`order_volume()` 的开平仓参数叫 `position_effect`（用 `PositionEffect_Open/Close`），而 `order_target_volume/percent/value` 的持仓方向参数叫 `position_side`（用 `PositionSide_Long/Short`）。ETF调仓推荐用 `order_target_percent`，更简洁不用算股数\r\n28. **56开头的ETF是沪市**：如562500机器人ETF应为 `SHSE.562500`，不是深市。5开头=沪市(SHSE)，1开头=深市(SZSE)\n\nFile v1.0.1:README.md\n\n# 掘金量化 Skill — 自然语言策略引擎\r\n\r\n> **用中文说话就能跑量化策略。** 告诉我你的交易想法，我帮你生成代码、执行回测、查看结果。\r\n\r\n## 快速开始（3 步）\r\n\r\n### 1️⃣ 准备环境\r\n\r\n确保你的电脑已安装：\r\n\r\n- [**掘金终端**](https://www.myquant.cn) — 打开并登录\r\n- **Python 3.8+** — 安装 `gm` SDK 包：\r\n  ```bash\r\n  pip install gm\r\n  ```\r\n\r\n### 2️⃣ 设置 Token\r\n\r\n获取方式：掘金终端 → 系统设置 → 密钥管理 → 复制 Token\r\n\r\n然后告诉我：\"我的 token 是 `xxxxx`\"，我会自动保存。\r\n\r\n### 3️⃣ 用自然语言描述策略 + 提供 Strategy ID\r\n\r\n直接说你想做什么，**同时告诉我你的策略 ID**：\r\n\r\n> \"帮我写个双均线策略：茅台和平安银行，5 日均线上穿 20 日均线买入，下穿卖出，回测最近一年。**策略 ID 叫 `ma_cross_v1`**\"\r\n\r\n> \"写个动量策略：沪深 300 里选过去 20 天涨幅最大的 10 只等权买入，每月初调仓。**strategy_id 用 `momentum_top10`**\"\r\n\r\n> \"查一下贵州茅台最近半年的日线收盘价\"（纯查询不需要 strategy_id）\r\n\r\n我会自动生成完整的可运行策略文件并帮你跑起来。\r\n\r\n---\r\n\r\n## 支持的策略类型\r\n\r\n| 类型 | 示例描述 | 关键字 |\r\n|------|---------|--------|\r\n| **趋势跟踪** | \"双均线金叉死叉\" / \"布林带突破\" / \"MACD 策略\" | 均线、MA、MACD、布林带 |\r\n| **动量/因子** | \"选涨幅最大的 N 只\" / \"RSI 超卖买入\" / \"量价配合\" | 动量、RSI、成交量、排名 |\r\n| **均值回归** | \"偏离均值太多就反向操作\" / \"网格交易\" | 均值回归、网格、偏离 |\r\n| **多因子选股** | \"按 PE+ROE 选股\" / \"小市值+高成长\" | 因子、筛选、排序 |\r\n| **事件驱动** | \"财报后买入\" / \"涨停板打板\" | 财报、涨停、事件 |\r\n| **纯数据查询** | \"查行情\" / \"拉数据\" / \"看 K 线\" | 查询、历史、行情 |\r\n\r\n---\r\n\r\n## 运行模式\r\n\r\n| 模式 | 说明 | 适用场景 |\r\n|------|------|---------|\r\n| **回测 (Backtest)** | 用历史数据模拟交易 | 验证策略效果（默认） |\r\n| **实盘/仿真 (Live)** | 连接实时行情和模拟账户 | 策略验证后上线运行 |\r\n\r\n---\r\n\r\n## 典型对话示例\r\n\r\n### 示例 1：从零开始写策略\r\n\r\n```\r\n你: 写个双均线交叉策略，标的用贵州茅台，5日和20日均线。策略ID用 ma_cross_kweichow\r\n我: [生成 strategy_ma.py，strategy_id='ma_cross_kweichow']\r\n    策略已生成！参数如下：\r\n    - 策略ID: ma_cross_kweichow ← 终端可查看绩效\r\n    - 标的: SHSE.600519（贵州茅台）\r\n    - 周期: 日线 1d\r\n    - 信号: MA5上穿MA20买入 / 下穿卖出\r\n    - 回测: 2024-01 ~ 2025-12, 初始资金100万\r\n\r\n    要跑回测吗？\r\n你: 跑吧\r\n我: [自动调用 run_strategy.py --strategy-id ma_cross_kweichow 执行]\r\n    回测完成！结果摘要：\r\n    - 总收益: +23.5%\r\n    - 年化收益: 18.2%\r\n    - 最大回撤: -12.3%\r\n    - 夏普比率: 1.45\r\n    \r\n    ✅ 已保存到掘金终端 → 打开 https://www.myquant.cn 查看完整绩效图表\r\n```\r\n\r\n### 示例 2：只查询数据\r\n\r\n```\r\n你: 查一下中芯国际最近30天的收盘价\r\n我: [直接调用 API 返回 DataFrame]\r\n    SZSE.002371 中芯国际 最近30日收盘价：\r\n    日期          | 收盘价   | 涨跌幅\r\n    2026-03-10    | 52.30    | +2.1%\r\n    2026-03-11    | 51.80    | -0.96%\r\n    ...\r\n```\r\n\r\n---\r\n\r\n## 文件结构\r\n\r\n```\r\n~/.workbuddy/skills/gm-quant/\r\n├── SKILL.md                  # 技能主文件（AI 读取此文件理解如何工作）\r\n├── README.md                 # 本文件 — 用户引导\r\n├── TEST_REPORT.md            # API 测试报告\r\n├── references/               # API 详细参考文档（14篇）\r\n│   ├── 01-quick-start.md\r\n│   ├── 04-market-data.md\r\n│   └── ...\r\n└── scripts/\r\n    ├── run_strategy.py        # ⭐ 策略一键运行器\r\n    ├── test_all_apis.py       # API 全量测试脚本\r\n    ├── test_account_apis.py   # 账户 API 策略环境测试\r\n    └── check_import.py        # 导入检测\r\n```\r\n\r\n---\r\n\r\n## ⭐ Strategy ID — 在掘金终端查看绩效分析\r\n\r\n> **这是使用回测功能前必须填写的一步。**\r\n\r\n### 什么是 Strategy ID？\r\n\r\n`strategy_id` 是你的策略在**掘金终端**中的唯一标识名。每次运行策略时传入它，回测结果会**持久化保存**到终端后台。\r\n\r\n### 填写后你能看到什么？\r\n\r\n登录 [掘金量化终端](https://www.myquant.cn) → **策略列表** → 找到你的策略 → 点击查看：\r\n\r\n| 绩效分析内容 | 说明 |\r\n|-------------|------|\r\n| 📈 **收益曲线** | 策略净值 vs 基准对比 |\r\n| 📉 **回撤分析** | 最大回撤、回撤持续时间 |\r\n| 📊 **风险指标** | 夏普比率、年化收益、波动率 |\r\n| 💰 **交易明细** | 每笔买入/卖出记录 |\r\n| 🎯 **持仓快照** | 每日持仓变化 |\r\n\r\n### 如何提供？\r\n\r\n在描述策略时顺便告诉我，例如：\r\n\r\n```\r\n你: 写个双均线策略，标的茅台。策略ID用 ma_cross_kweichow\r\n我: [生成代码，自动填入 strategy_id='ma_cross_kweichow']\r\n    回测完成！打开掘金终端 → 策略列表 → ma_cross_kweichow → 查看绩效图表\r\n```\r\n\r\n如果你没提供，**我会主动问你**，不会偷偷跳过。\r\n\r\n---\r\n\r\n## 注意事项\r\n\r\n- **掘金终端必须保持打开** — 所有 API 调用都通过终端通信\r\n- **Token 不要泄露给他人** — 相当于你的账号密码\r\n- **回测不等于实盘** — 回测结果仅供参考，实盘需考虑滑点、流动性等因素\r\n- **A 股 T+1** — 当天买入的股票当天不能卖出\n\nFile v1.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn73qb7dqheg4nh3p4x4ka1mxx85szhw\",\n  \"slug\": \"gmquant\",\n  \"version\": \"1.0.1\",\n  \"publishedAt\": 1777451170221\n}\n\nFile v1.0.1:references/01-quick-start.md\n\n# 快速开始 & 策略架构\r\n\r\n## 策略三大结构\r\n\r\n掘金量化策略主要有 3 种结构：\r\n\r\n### 1. 定时任务型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    schedule(schedule_func=algo, date_rule='1d', time_rule='14:50:00')\r\n\r\ndef algo(context):\r\n    order_volume(symbol='SHSE.600000', volume=200, side=OrderSide_Buy,\r\n                 order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n\r\nif __name__ == '__main__':\r\n    run(strategy_id='YOUR_ID', filename='main.py', mode=MODE_BACKTEST,\r\n        token='YOUR_TOKEN', backtest_start_time='2024-01-01 09:00:00',\r\n        backtest_end_time='2024-06-30 15:30:00', backtest_adjust=ADJUST_PREV,\r\n        backtest_initial_cash=1000000, backtest_commission_ratio=0.0001,\r\n        backtest_slippage_ratio=0.0001)\r\n```\r\n\r\n### 2. 数据事件驱动型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s')\r\n\r\ndef on_bar(context, bars):\r\n    print(bars)\r\n```\r\n\r\n### 3. 时间序列滑窗型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s', count=50,\r\n              format='df', fields='symbol,close,eob')\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol=bar","readmeExcerpt":"Skill: 掘金量化skill Owner: turkeydick Summary: 掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym... Tags: automation:1.0.2, finance:1.0.2, gm:1.0.2, joinquant:1.0.2, latest:1.0.3, quant:1.0.2, stock:1.0.2, trading:1.0.2, workbuddy:1.0.2 Version history: v1.0.3 | 2026-05-26T09:22:10.719Z | user gmquant v1.0.3 - Add","codeSnippets":[],"executableExamples":[{"language":"python","snippet":"\"\"\"\n策略名称：{name}\n策略描述：{description}\n生成时间：{date}\n\"\"\"\n\nimport sys, os, io\nsys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')\n\nfrom gm.api import *\n\n# ============================================================\n# 配置区 —— 用户可通过修改此处调整策略参数\n# ============================================================\nSYMBOLS = 'SHSE.600519,SZSE.000001'      # 标的（逗号分隔）\nFREQUENCY = '1d'                          # K线周期：1d/60s/300s/tick\nCOUNT = 20                                # 订阅K线数量（context.data滑窗大小）\n\n# 交易参数\nORDER_TYPE = OrderType_Market              # 下单方式：Market(市价) / Limit(限价)\nPOSITION_PCT = 0.2                        # 单只股票仓位占比（0~1）\n\n# 回测参数\nBACKTEST_START = '2024-01-02 09:30:00'\nBACKTEST_END   = '2025-12-31 15:30:00'\nINITIAL_CASH   = 1000000                  # 初始资金\nCOMMISSION     = 0.00025                  # 手续费率\nSLIPPAGE       = 0.001                    # 滑点\n\n\n# ============================================================\n# 策略逻辑\n# ============================================================\n\ndef init(context):\n    \"\"\"初始化：订阅行情\"\"\"\n    log.info(f'策略启动 | 标的:{SYMBOLS} | 周期:{FREQUENCY}')\n    subscribe(symbols=SYMBOLS, frequency=FREQUENCY, count=COUNT)\n\n    # 存储策略状态\n    context.last_signal = {}  # {symbol: last_signal_time}\n\n\ndef on_bar(context, bars):\n    \"\"\"每根K线触发\"\"\"\n    for bar in bars:\n        symbol = bar['symbol']\n        try:\n            _handle_bar(context, symbol)\n        except Exception as e:\n            log.error(f'处理{symbol}异常: {e}')\n\n\ndef on_tick(context, tick):\n    \"\"\"tick级别回调（如订阅了tick会走这里）\"\"\"\n    pass\n\n\ndef _handle_bar(context, symbol):\n    \"\"\"单只标的策略逻辑\"\"\"\n\n    # 1. 获取历史数据（滑窗内）—— 注意返回 DataFrame\n    data = context.data(symbol=symbol, frequency=FREQUENCY, count=COUNT)\n    if data is None or len(data) < COUNT:\n        return\n\n    # 2. 获取当前持仓 —— get_position() 不带参数，返回全部持仓列表\n    all_positions = get_position()\n    position = None\n    if all_positions:\n        for p in all_positions:\n            sym = p.get('symbol') if isinstance(p, dict) else (p.s"},{"language":"bash","snippet":"python scripts/run_strategy.py --strategy <策略文件路径> --strategy-id <你的策略ID> [--mode backtest|live] [--token YOUR_TOKEN]"},{"language":"python","snippet":"# 融资买入（借入资金买证券）\ncredit_buying_on_margin(symbol, volume, price=0, order_type=OrderType_Market, position_effect=PositionEffect_Open)\n\n# 融券卖出（借入证券卖出）\ncredit_short_selling(symbol, volume, price=0, order_type=OrderType_Market, position_effect=PositionEffect_Open)\n\n# 买券还券（买入证券归还融券）\ncredit_buying_on_repayment(symbol, volume, price=0, order_type=OrderType_Market)\n\n# 卖券还款（卖出证券归还融资）\ncredit_selling_on_repayment(symbol, volume, price=0, order_type=OrderType_Market)\n\n# 直接还款（用现金直接归还融资）\ncredit_direct_repayment(amount)\n\n# 直接还券（用持仓直接归还融券）\ncredit_direct_return_securities(symbol, volume)\n\n# 信用账户查询\ncredit_get_collateral_instruments()    # 查询可担保证券\ncredit_get_borrowable_instruments()    # 查询可融券证券\ncredit_get_collateral_ratio(symbol)    # 查询担保折算率\ncredit_get_concentrate_limit(symbol)   # 查询集中度限制\ncredit_get_margin_ratio(symbol)        # 查询融资融券保证金比例\ncredit_get_max_volume(symbol, side)    # 查询最大可借数量"},{"language":"python","snippet":"# 批量下单 — 一次提交多笔委托，减少网络往返\norders = [\n    {'symbol': 'SHSE.600519', 'volume': 100, 'side': OrderSide_Buy, 'position_effect': PositionEffect_Open, 'order_type': OrderType_Market},\n    {'symbol': 'SZSE.000001', 'volume': 200, 'side': OrderSide_Buy, 'position_effect': PositionEffect_Open, 'order_type': OrderType_Market},\n]\norder_batch(orders)"},{"language":"python","snippet":"# 撤销指定委托\norder_cancel(cl_ord_id)         # cl_ord_id 从 get_orders() 或 on_order_status 回调中获取\n\n# 撤销全部未成交委托\norder_cancel_all()\n\n# 查询未成交委托\nget_unfinished_orders()"},{"language":"python","snippet":"# 新股申购\nipo_buy(symbol, volume, price=0, order_type=OrderType_Limit)\n\n# ETF 申购/赎回（场内基金）\nfund_etf_buy(symbol, volume, price=0, order_type=OrderType_Market)       # ETF 申购\nfund_etf_redemption(symbol, volume, price=0, order_type=OrderType_Market) # ETF 赎回\n\n# 场外基金\nfund_subscribing(symbol, volume, price=0)   # 场外基金认购\nfund_buy(symbol, volume, price=0)           # 场外基金申购\nfund_redemption(symbol, volume, price=0)    # 场外基金赎回\n\n# 国债逆回购\nbond_reverse_repurchase_agreement(symbol, volume, price=0, order_type=OrderType_Limit)"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: gm-quant\nversion: 2.1.0\ndescription: >\n  掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、\n  量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、\n  order_volume、subscribe、history、set_token、get_symbols、get_symbol_infos、\n  get_history_symbol、history_n、current、last_tick、current_price、get_trading_dates、\n  order_percent、order_value、order_target_volume、algo_order、\n  get_orders、get_position、get_cash、bond_convertible、\n  L2行情、逐笔成交、逐笔委托、schedule定时任务、 财务数据、资产负债表、利润表、现金流量表、估值指标、PE/PB/PS/股息率、\n  市值、股本、流通股、成分股、行业分类、 可转债分析、转股溢价率、纯债价值、ETF成分股、基金净值、 期货合约信息、仓单数据、成交持仓排名、连续合约、\n  stk_get_fundamentals、stk_get_daily_valuation、stk_get_index_constituents、\n  stk_get_industry_category、stk_get_industry_constituents、stk_get_symbol_industry、\n  stk_get_sector_category、stk_get_sector_constituents、stk_get_symbol_sector、\n  stk_get_dividend、stk_get_ration、stk_get_adj_factor、stk_get_shareholder_num、\n  stk_get_top_shareholder、stk_get_share_change、stk_abnor_change_stocks、\n  stk_abnor_change_detail、stk_quota_shszhk_infos、stk_active_stock_top10_shszhk_info、\n  stk_get_money_flow、stk_get_finance_audit、stk_get_finance_forecast、\n  bnd_get_analysis、bnd_get_conversion_price、bnd_get_call_info、bnd_get_put_info、bnd_get_amount_change、\n  fnd_get_portfolio、fnd_get_etf_constituents、fnd_get_net_value、fnd_get_adj_factor、fnd_get_dividend、fnd_get_split、fnd_get_share、\n  fut_get_contract_info、fut_get_continuous_contracts、fut_get_transaction_rankings、fut_get_warehouse_receipt、\n  get_open_call_auction\n  时，自动加载此 skill。\n---\n\n# 掘金量化 SDK 技能 — v2.0 自然语言策略引擎\n\n## 定位\n\n你是**掘金量化平台的自然语言策略助手**。用户用中文描述交易想法，你负责：\n1. **理解需求** → 提炼策略逻辑（标的/信号/风控）\n2. **生成代码** → 输出可直接运行的完整策略 `.py` 文件\n3. **执行运行** → 调用 `scripts/run_strategy.py` 一键启动回测或实盘\n\n## 核心原则\n\n1. **必须先 set_token**：纯数据查询（非策略 run）场景下，代码开头必须调用 `set_token('your_token')`。\n2. **symbol 格式**：`交易所代码.证券代码`，如 `SHSE.600000`、`SZSE.000001`，**严格区分大小写**。\n3. **gm 包通过掘金终端连接**：终端必须保持打开，否则接口会超时或报错。\n4. **两种模式**：`MODE_LIVE=1`（实时/仿真）、`MODE_BACKTEST=2`（回测）；`run()` 函数启动策略。\n5. **数据查询不需要 run**：仅用 `set_token` 后直接调用数据函数即可。\n\n## 🚀 用户工作流（自然语言→运行）\n\n### 第 0 步：确认 Strategy ID（重要！）\n\n**每次生成策略前，必须向用户索要 `strategy_id`。**\n\n`strategy_id` 是策略在掘金终端中的唯一标识。填写后：\n- 回测结果**持久化**到掘金终端后台\n- 用户登录 [掘金终端网页](https://www.myquant.cn) → 策略列表 → 查看完整的**绩效分析图表**\n  （收益曲线、回撤分析、夏普比率、持仓明细等）\n\n> **交互方式**：如果用户没有主动提供 strategy_id，在生成代码前询问：\n> \"请给我一个 **strategy_id**（英文/数字/下划线），用于在掘金终端标识这个策略。\n> 填完后你可以在终端网页上看到绩效分析图表。例如：`ma_cross_600519`、`momentum_v1`\"\n\n| 场景 | 处理方式 |\n|------|---------|\n| 用户提供了 strategy_id | 直接使用 |\n| 用户没提供 | **必须追问**，不能自己编造一个默认值后静默使用 |\n| 用户说\"随便起一个\" | 根据策略特征起一个有意义的名字（如 `dual_ma_kweichow`） |\n\n### 第一步：理解用户意图\n\n当用户用自然语言描述策略时，按以下维度提取信息：\n\n| 维度 | 需确认的信息 | 默认值（如未明确说明） |\n|------|-------------|---------------------|\n| **strategy_id** | 策略在掘金终端的标识（**必须用户提供，见第0步**） | 无默认，必须询问 |\n| **标的池** | 哪些股票/指数？ | 沪深300成分股 |\n| **时间频率** | 日线/分钟线/tick？ | 日线 `1d` |\n| **买入信号** | 什么条件买入？（均线/指标/事件） | 必须明确，不能猜测 |\n| **卖出信号** | 什么条件卖出？ | 必须明确，不能猜测 |\n| **仓位管理** | 全仓/固定金额/比例/等权 | 等权分配 |\n| **止损止盈** | 有无？阈值多少？ | 无 |\n| **回测区间** | 开始~结束日期 | 最近1年 |\n| **初始资金** | 多少钱？ | 100万 "},{"path":"README.md","content":"# 掘金量化 Skill — 自然语言策略引擎 v2.1.0\r\n\r\n> **用中文说话就能跑量化策略。** 告诉我你的交易想法，我帮你生成代码、执行回测、查看结果。\r\n\r\n## 快速开始（3 步）\r\n\r\n### 1️⃣ 准备环境\r\n\r\n确保你的电脑已安装：\r\n\r\n- [**掘金终端**](https://www.myquant.cn) — 打开并登录\r\n- **Python 3.8+** — 安装 `gm` SDK 包：\r\n  ```bash\r\n  pip install gm\r\n  ```\r\n\r\n### 2️⃣ 设置 Token\r\n\r\n获取方式：掘金终端 → 系统设置 → 密钥管理 → 复制 Token\r\n\r\n然后告诉我：\"我的 token 是 `xxxxx`\"，我会自动保存。\r\n\r\n### 3️⃣ 用自然语言描述策略 + 提供 Strategy ID\r\n\r\n直接说你想做什么，**同时告诉我你的策略 ID**：\r\n\r\n> \"帮我写个双均线策略：茅台和平安银行，5 日均线上穿 20 日均线买入，下穿卖出，回测最近一年。**策略 ID 叫 `ma_cross_v1`**\"\r\n\r\n> \"写个动量策略：沪深 300 里选过去 20 天涨幅最大的 10 只等权买入，每月初调仓。**strategy_id 用 `momentum_top10`**\"\r\n\r\n> \"查一下贵州茅台最近半年的日线收盘价\"（纯查询不需要 strategy_id）\r\n\r\n我会自动生成完整的可运行策略文件并帮你跑起来。\r\n\r\n---\r\n\r\n## 支持的策略类型\r\n\r\n| 类型 | 示例描述 | 关键字 |\r\n|------|---------|--------|\r\n| **趋势跟踪** | \"双均线金叉死叉\" / \"布林带突破\" / \"MACD 策略\" | 均线、MA、MACD、布林带 |\r\n| **动量/因子** | \"选涨幅最大的 N 只\" / \"RSI 超卖买入\" / \"量价配合\" | 动量、RSI、成交量、排名 |\r\n| **均值回归** | \"偏离均值太多就反向操作\" / \"网格交易\" | 均值回归、网格、偏离 |\r\n| **多因子选股** | \"按 PE+ROE 选股\" / \"小市值+高成长\" | 因子、筛选、排序 |\r\n| **事件驱动** | \"财报后买入\" / \"涨停板打板\" | 财报、涨停、事件 |\r\n| **纯数据查询** | \"查行情\" / \"拉数据\" / \"看 K 线\" | 查询、历史、行情 |\r\n\r\n---\r\n\r\n## 运行模式\r\n\r\n| 模式 | 说明 | 适用场景 |\r\n|------|------|---------|\r\n| **回测 (Backtest)** | 用历史数据模拟交易 | 验证策略效果（默认） |\r\n| **实盘/仿真 (Live)** | 连接实时行情和模拟账户 | 策略验证后上线运行 |\r\n\r\n---\r\n\r\n## 典型对话示例\r\n\r\n### 示例 1：从零开始写策略\r\n\r\n```\r\n你: 写个双均线交叉策略，标的用贵州茅台，5日和20日均线。策略ID用 ma_cross_kweichow\r\n我: [生成 strategy_ma.py，strategy_id='ma_cross_kweichow']\r\n    策略已生成！参数如下：\r\n    - 策略ID: ma_cross_kweichow ← 终端可查看绩效\r\n    - 标的: SHSE.600519（贵州茅台）\r\n    - 周期: 日线 1d\r\n    - 信号: MA5上穿MA20买入 / 下穿卖出\r\n    - 回测: 2024-01 ~ 2025-12, 初始资金100万\r\n\r\n    要跑回测吗？\r\n你: 跑吧\r\n我: [自动调用 run_strategy.py --strategy-id ma_cross_kweichow 执行]\r\n    回测完成！结果摘要：\r\n    - 总收益: +23.5%\r\n    - 年化收益: 18.2%\r\n    - 最大回撤: -12.3%\r\n    - 夏普比率: 1.45\r\n    \r\n    ✅ 已保存到掘金终端 → 打开 https://www.myquant.cn 查看完整绩效图表\r\n```\r\n\r\n### 示例 2：只查询数据\r\n\r\n```\r\n你: 查一下中芯国际最近30天的收盘价\r\n我: [直接调用 API 返回 DataFrame]\r\n    SZSE.002371 中芯国际 最近30日收盘价：\r\n    日期          | 收盘价   | 涨跌幅\r\n    2026-03-10    | 52.30    | +2.1%\r\n    2026-03-11    | 51.80    | -0.96%\r\n    ...\r\n```\r\n\r\n---\r\n\r\n## 文件结构\r\n\r\n```\r\n~/.workbuddy/skills/gm-quant/\r\n├── SKILL.md                  # 技能主文件（AI 读取此文件理解如何工作）\r\n├── README.md                 # 本文件 — 用户引导\r\n├── TEST_REPORT.md            # API 测试报告\r\n├── references/               # API 详细参考文档（21篇）\r\n│   ├── 01-quick-start.md\r\n│   ├── 04-market-data.md\r\n│   ├── 16-premium-data-apis.md     # 增值数据 API 速查合集\r\n│   ├── 18-stock-premium-apis.md    # 股票增值数据（完整版）\r\n│   ├── 19-fund-premium-apis.md     # 基金增值数据（完整版）\r\n│   ├── 20-cb-premium-apis.md       # 可转债增值数据（完整版）\r\n│   └── 21-futures-premium-apis.md  # 期货增值数据（完整版）\r\n└── scripts/\r\n    ├── run_strategy.py        # ⭐ 策略一键运行器\r\n    ├── test_all_apis.py       # API 全量测试脚本\r\n    ├── test_account_apis.py   # 账户 API 策略环境测试\r\n    └── check_import.py        # 导入检测\r\n```\r\n\r\n---\r\n\r\n## ⭐ Strategy ID — 在掘金终端查看绩效分析\r\n\r\n> **这是使用回测功能前必须填写的一步。**\r\n\r\n### 什么是 Strategy ID？\r\n\r\n`strategy_id` 是你的策略在**掘金终端**中的唯一标识名。每次运行策略时传入它，回测结果会**持久化保存**到终端后台。\r\n\r\n### 填写后你能看到什么？\r\n\r\n登录 [掘金量化终端](https://www.myquant.cn) → **策略"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn73qb7dqheg4nh3p4x4ka1mxx85szhw\",\n  \"slug\": \"gmquant\",\n  \"version\": \"1.0.3\",\n  \"publishedAt\": 1779787330719\n}"},{"path":"references/01-quick-start.md","content":"# 快速开始 & 策略架构\r\n\r\n## 策略三大结构\r\n\r\n掘金量化策略主要有 3 种结构：\r\n\r\n### 1. 定时任务型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    schedule(schedule_func=algo, date_rule='1d', time_rule='14:50:00')\r\n\r\ndef algo(context):\r\n    order_volume(symbol='SHSE.600000', volume=200, side=OrderSide_Buy,\r\n                 order_type=OrderType_Market, position_effect=PositionEffect_Open, price=0)\r\n\r\nif __name__ == '__main__':\r\n    run(strategy_id='YOUR_ID', filename='main.py', mode=MODE_BACKTEST,\r\n        token='YOUR_TOKEN', backtest_start_time='2024-01-01 09:00:00',\r\n        backtest_end_time='2024-06-30 15:30:00', backtest_adjust=ADJUST_PREV,\r\n        backtest_initial_cash=1000000, backtest_commission_ratio=0.0001,\r\n        backtest_slippage_ratio=0.0001)\r\n```\r\n\r\n### 2. 数据事件驱动型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s')\r\n\r\ndef on_bar(context, bars):\r\n    print(bars)\r\n```\r\n\r\n### 3. 时间序列滑窗型\r\n```python\r\nfrom gm.api import *\r\n\r\ndef init(context):\r\n    subscribe(symbols='SHSE.600000', frequency='60s', count=50,\r\n              format='df', fields='symbol,close,eob')\r\n\r\ndef on_bar(context, bars):\r\n    data = context.data(symbol=bars[0]['symbol'], frequency='60s', count=50)\r\n    data['ma5'] = data['close'].rolling(5).mean()\r\n    print(data.tail())\r\n```\r\n\r\n## 纯数据研究（无需 run）\r\n\r\n```python\r\nfrom gm.api import *\r\nset_token('YOUR_TOKEN')  # 掘金终端需保持打开\r\n\r\ndata = history(symbol='SHSE.600000', frequency='1d',\r\n               start_time='2024-01-01 09:00:00', end_time='2024-12-31 16:00:00',\r\n               fields='open,high,low,close,eob', adjust=ADJUST_PREV, df=True)\r\nprint(data)\r\n```\r\n\r\n## 模式说明\r\n\r\n| 模式 | 常量 | 说明 |\r\n|------|------|------|\r\n| 实时模式 | `MODE_LIVE = 1` | 仿真/实盘交易，接收实时行情 |\r\n| 回测模式 | `MODE_BACKTEST = 2` | 历史数据回放，快速验证策略 |\r\n\r\n## 运行参数 `run()` 全解\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| strategy_id | str | 掘金终端生成的策略 ID |\r\n| filename | str | 策略文件名（如 `main.py`） |\r\n| mode | int | MODE_LIVE 或 MODE_BACKTEST |\r\n| token | str | 用户 token（终端系统设置-密钥管理） |\r\n| backtest_start_time | str | 回测开始时间 `%Y-%m-%d %H:%M:%S` |\r\n| backtest_end_time | str | 回测结束时间 `%Y-%m-%d %H:%M:%S` |\r\n| backtest_initial_cash | float | 初始资金，默认 1000000 |\r\n| backtest_transaction_ratio | float | 成交比例，默认 1.0 |\r\n| backtest_commission_ratio | float | 佣金比例，默认 0 |\r\n| backtest_slippage_ratio | float | 滑点比例，默认 0 |\r\n| backtest_adjust | int | 复权方式：ADJUST_NONE/ADJUST_PREV/ADJUST_POST |\r\n| backtest_match_mode | int | 0=延时撮合(下一bar开盘价)，1=实时撮合(当前收盘价) |\r\n| backtest_check_cache | int | 是否用缓存，默认 1 |\r\n| serv_addr | str | 终端地址，默认本地，可指定 `ip:port` |\r\n\r\n## 注意事项\r\n- filename 必须与实际文件名一致\r\n- 前复权/后复权回测不处理分红送转事件（已通过复权因子调整）\r\n- 不复权模式会自动处理分红送转"},{"path":"references/02-core-functions.md","content":"# 核心基础函数\r\n\r\n## set_token - 设置用户 Token\r\n\r\n```python\r\nset_token('YOUR_TOKEN_ID')\r\n```\r\n\r\n- 纯数据查询时第一步必须调用\r\n- Token 在掘金终端「系统设置 → 密钥管理」中获取\r\n- Token 不正确会抛出异常\r\n\r\n---\r\n\r\n## run - 启动策略\r\n\r\n```python\r\nrun(strategy_id='', filename='', mode=MODE_UNKNOWN, token='',\r\n    backtest_start_time='', backtest_end_time='',\r\n    backtest_initial_cash=1000000, backtest_transaction_ratio=1,\r\n    backtest_commission_ratio=0, backtest_slippage_ratio=0,\r\n    backtest_adjust=ADJUST_NONE, backtest_check_cache=1,\r\n    serv_addr='', backtest_match_mode=0)\r\n```\r\n\r\n详细参数说明见 `01-quick-start.md`。\r\n\r\n---\r\n\r\n## stop - 停止策略\r\n\r\n```python\r\nstop()\r\n```\r\n\r\n- 停止策略，退出策略进程\r\n- 示例：当订阅代码集合为空时停止\r\n```python\r\nif not context.symbols:\r\n    stop()\r\n```\r\n\r\n---\r\n\r\n## schedule - 定时任务\r\n\r\n```python\r\nschedule(schedule_func, date_rule, time_rule)\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| schedule_func | function | 定时执行的函数 |\r\n| date_rule | str | `n + d/w/m`，如 `'1d'`(每天)、`'1w'`(每周)、`'1m'`(每月) |\r\n| time_rule | str | 执行时间 `HH:MM:SS`，**时分秒不可省略前导零**，如 `'09:40:00'` |\r\n\r\n**注意**：`1w`、`1m` 仅回测可用；`time_rule` 不能写 `'9:40:0'` 这种格式。\r\n\r\n```python\r\ndef init(context):\r\n    schedule(schedule_func=algo_daily, date_rule='1d', time_rule='09:40:00')\r\n    schedule(schedule_func=algo_monthly, date_rule='1m', time_rule='09:30:00')\r\n\r\ndef algo_daily(context):\r\n    print('每天09:40执行', context.now)\r\n\r\ndef algo_monthly(context):\r\n    print('每月第一个交易日09:30执行', context.now)\r\n```\r\n\r\n---\r\n\r\n## timer / timer_stop - 毫秒级定时器\r\n\r\n**仅实时/仿真模式可用，回测不生效。**\r\n\r\n```python\r\n# 设置定时器\r\nresult = timer(timer_func=my_func, period=60000, start_delay=0)\r\n# result: {'timer_status': 0, 'timer_id': 1}\r\n\r\n# 停止定时器\r\nis_stopped = timer_stop(timer_id=result['timer_id'])\r\n```\r\n\r\n| 参数 | 类型 | 说明 |\r\n|------|------|------|\r\n| timer_func | function | 触发时执行的函数 |\r\n| period | int | 间隔毫秒数，范围 [1, 43200000] |\r\n| start_delay | int | 延迟启动毫秒数，范围 [0, 43200000] |\r\n\r\n```python\r\ndef init(context):\r\n    # 每60秒执行一次，立即启动\r\n    context.timer_id = timer(timer_func=on_timer, period=60000, start_delay=0)\r\n\r\ndef on_timer(context):\r\n    cash = context.account().cash\r\n    print('定时检查资金:', cash['available'])\r\n```\r\n\r\n---\r\n\r\n## log - 日志\r\n\r\n**仅实时模式可用。**\r\n\r\n```python\r\nlog(level='info', msg='信号触发', source='strategy')\r\n```\r\n\r\n| level | 说明 |\r\n|-------|------|\r\n| `'info'` | 信息级别 |\r\n| `'warning'` | 警告级别 |\r\n| `'error'` | 错误级别 |\r\n\r\n---\r\n\r\n## add_parameter - 动态参数\r\n\r\n**仅实时模式可用，重启后重置。**\r\n\r\n```python\r\nadd_parameter(key='k_value', value=23, min=0, max=100,\r\n              name='K值阈值', intro='KDJ策略K值阈值',\r\n              group='1', readonly=False)\r\n```\r\n\r\n- 在终端 UI 界面显示和实时修改参数\r\n- 修改时触发 `on_parameter(context, parameter)` 事件\r\n\r\n```python\r\ndef on_parameter(context, parameter):\r\n    if parameter['name'] == 'K值阈值':\r\n        context.k_value = parameter['value']\r\n        print('参数已更新:', context.k_value)\r\n```"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym... Skill: 掘金量化skill Owner: turkeydick Summary: 掘金量化 Python SDK 专家技能。 当用户提到掘金、gm、gm.api、掘金量化、掘金策略、掘金SDK、掘金终端、 量化策略开发、回测、实时行情、订阅行情、历史行情、下单、委托、持仓、 order_volume、subscribe、history、set_token、get_symbols、get_sym... Tags: automation:1.0.2, finance:1.0.2, gm:1.0.2, joinquant:1.0.2, latest:1.0.3, quant:1.0.2, stock:1.0.2, trading:1.0.2, workbuddy:1.0.2 Version history: v1.0.3 | 2026-05-26T09:22:10.719Z | user gmquant v1.0.3 - Add","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":982,"uniquenessScore":54,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T07:26:45.809Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T07:26:45.809Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:48:58.885Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}