# SFGrid 网格交易策略流程图 ## 1. 总览:策略生命周期 ```mermaid flowchart TD A["SFGridStrategy.__init__()"] --> B["订阅事件总线
onOrderCreateAsync / onOrderTrade / onOrderError"] B --> C["获取涨跌停价
todayUpStopPrice / todayDownStopPrice"] C --> D["loadExistOrders()
从券商侧恢复未成交订单到 orderGrid"] D --> E["enabledTrading(enabled)"] E --> F{"enabled ?"} F -->|True| G["启用交易流程 → 见 §3"] F -->|False| H["停用交易流程 → 见 §3"] G --> I["saveProxy() 持久化"] H --> I I --> J["构造完成,进入事件循环
等待 QMT 回调 / UI 操作"] ``` --- ## 2. 核心:refreshGridOrder() 网格下单 ```mermaid flowchart TD START["refreshGridOrder()"] --> CHECK1{"qmtv.isMarketActive
AND
tradeTarget.enabled ?"} CHECK1 -->|No| SKIP["跳过不下单"] CHECK1 -->|Yes| QUERY["查询未成交订单
queryPendingOrder()"] QUERY --> STATUS{"tradeTarget.status ?"} STATUS -->|"= 0 未建仓"| CHECK_INIT{"已存在建仓单?
remark = 'INIT,1,{code}'"} CHECK_INIT -->|"No 没有"| PLACE_INIT["下建仓单 (STOCK_BUY)
价格 = getPriceGrid()[0]
remark = 'INIT,1,{code}'"] CHECK_INIT -->|"Yes 已有"| DONE_INIT["建仓单已在途,跳过"] STATUS -->|"= 1 已建仓"| GET_IDX["currentIdx = grid_index"] GET_IDX --> SELL_CHECK{"currentIdx > 0 ?
(grid_index 不是最低点)"} SELL_CHECK -->|"Yes 可挂卖单"| SELL_EXIST{"已存在同 remark 卖单?
remark='SELL,{idx-1},{code}'"} SELL_EXIST -->|"No 没有"| SELL_PLACE["下卖出单 (STOCK_SELL)
价格 = grid[sellIdx]
sellIdx = currentIdx - 1"] SELL_EXIST -->|"Yes 已有"| SELL_SKIP["跳过,避免重复"] SELL_CHECK -->|"No 价格已最低"| SELL_SKIP2["无卖出空间"] SELL_PLACE --> BUY_CHECK SELL_SKIP --> BUY_CHECK SELL_SKIP2 --> BUY_CHECK BUY_CHECK{"currentIdx < len(grid)-1 ?
(grid_index 不是最高点)"} BUY_CHECK -->|"Yes 可挂买单"| BUY_EXIST{"已存在同价同类型买单?
order_type=BUY AND price=buyPrice"} BUY_EXIST -->|"No 没有"| BUY_PLACE["下买入单 (STOCK_BUY)
价格 = grid[buyIdx]
buyIdx = currentIdx + 1"] BUY_EXIST -->|"Yes 已有"| BUY_SKIP["跳过,避免重复"] BUY_CHECK -->|"No 价格已最高"| BUY_SKIP2["无买入空间"] ``` --- ## 3. 交易启停:enabledTrading() ```mermaid flowchart TD START["enabledTrading(enabled)"] --> SET["self.tradeTarget.enabled = enabled"] SET --> BRANCH{"enabled ?"} BRANCH -->|"True 启用"| STATUS{"tradeTarget.status ?"} STATUS -->|"= 0 未建仓"| INIT_IDX{"grid_index == 0 ?"} INIT_IDX -->|"Yes"| SET1["grid_index = 1
(默认建仓位置)"] INIT_IDX -->|"No"| KEEP["保留现有 grid_index"] SET1 --> REFRESH1["refreshGridOrder()"] KEEP --> REFRESH1 STATUS -->|"= 1 已建仓"| CALC["计算最小需求仓位
min = grid_volume × grid_index"] CALC --> CHECK{"current_position >= min ?"} CHECK -->|"Yes 充足"| REFRESH2["refreshGridOrder()"] CHECK -->|"No 不足"| DENY["拒绝启用
enabled = False
(风控保护)"] BRANCH -->|"False 停用"| CANCEL["取消所有未成交订单
cancel_order_stock_async()"] CANCEL --> LOG["记录取消数量"] REFRESH1 --> SAVE["saveProxy() 持久化"] REFRESH2 --> SAVE DENY --> SAVE LOG --> SAVE ``` --- ## 4. 事件回调链 ```mermaid flowchart TD subgraph QMT["QMT / xtquant 层"] OA["orderAsync()
返回 seq"] PUSH_ERR["C扩展推送
XtOrderError"] PUSH_RESP["C扩展推送
XtOrderResponse"] PUSH_TRADE["C扩展推送
XtTrade"] end subgraph BUS["事件总线 event_bus"] EVT_ERR["MarketOrderError"] EVT_RESP["MarketOrderCreated"] EVT_TRADE["MarketOrderTraded"] end subgraph STG["SFGridStrategy 回调"] OE["onOrderError()"] OC["onOrderCreateAsync()"] OT["onOrderTrade()"] end OA --> PUSH_RESP OA --> PUSH_ERR PUSH_ERR --> EVT_ERR --> OE PUSH_RESP --> EVT_RESP --> OC PUSH_TRADE --> EVT_TRADE --> OT ``` --- ## 5. onOrderError() 委托失败处理 ```mermaid flowchart TD START["onOrderError(order_error)"] --> CHK1{"order_remark 非空 ?"} CHK1 -->|"No 空"| EXIT1["无法解析,忽略"] CHK1 -->|"Yes"| PARSE["解析 remark
'{type},{gridIdx},{stockCode}'"] PARSE --> CHK2{"len(parts) >= 3 ?"} CHK2 -->|"No"| EXIT1 CHK2 -->|"Yes"| CHK3{"strategy_name == 'SFGRID'
AND
stockCode 匹配本标的 ?"} CHK3 -->|"No 不匹配"| EXIT1 CHK3 -->|"Yes"| LOCK["获取 dataUpdateLock"] LOCK --> DEL{"gridIdx in orderGrid ?"} DEL -->|"Yes"| REMOVE["del orderGrid[gridIdx]
清理孤立条目"] DEL -->|"No"| LOG_ERR["记录错误日志
error_id / error_msg"] REMOVE --> LOG_ERR LOG_ERR --> UNLOCK["释放 dataUpdateLock"] ``` --- ## 6. onOrderCreateAsync() 订单确认 ```mermaid flowchart TD START["onOrderCreateAsync(response)"] --> PARSE["解析 remark
'{type},{gridIdx},{stockCode}'"] PARSE --> FILTER{"strategy_name == 'SFGRID'
AND len(parts) >= 3
AND stockCode 匹配 ?"} FILTER -->|"No"| EXIT["忽略"] FILTER -->|"Yes"| LOCK["获取 dataUpdateLock"] LOCK --> UPDATE["orderGrid[gridIdx] = response.order_id
seq → order_id 替换"] UPDATE --> UNLOCK["释放 dataUpdateLock"] ``` --- ## 7. onOrderTrade() 成交处理 ```mermaid flowchart TD START["onOrderTrade(trade)"] --> PARSE["解析 remark
'{type},{gridIdx},{stockCode}'"] PARSE --> FILTER{"strategy_name == 'SFGRID'
AND len(parts) >= 3
AND stockCode 匹配 ?"} FILTER -->|"No"| EXIT["忽略"] FILTER -->|"Yes"| LOCK["获取 dataUpdateLock"] LOCK --> TYPE{"orderType ?"} TYPE -->|"INIT 建仓单"| INIT["status = 1
init_price = traded_price
grid_index = 1"] TYPE -->|"BUY / SELL 网格单"| CMP{"gridIdx vs grid_index ?"} CMP -->|"gridIdx > grid_index
(买入成交)"| DOWN["grid_index += 1
下移一格"] CMP -->|"gridIdx < grid_index
(卖出成交)"| UP["grid_index -= 1
上移一格
match_count += 1
total_profit += grid_size × volume"] CMP -->|"gridIdx == grid_index
(异常)"| SAME["日志: 理论上不应该输出"] INIT --> POST DOWN --> POST UP --> POST SAME --> POST POST["成交后处理"] --> SAVE["saveProxy() 持久化状态"] SAVE --> DEL["del orderGrid[gridIdx]
移除已成交订单"] DEL --> REPORT["打印成交报告
成交价/量/手续费"] REPORT --> REFRESH["refreshGridOrder()
在新位置挂新的网格单"] REFRESH --> UNLOCK["释放 dataUpdateLock"] ``` --- ## 8. 网格交易完整状态机 ```mermaid stateDiagram-v2 [*] --> 未建仓: 创建 SFGridStrategy 未建仓 --> 建仓中: enabledTrading(True)
下建仓单 INIT 建仓中 --> 已建仓: onOrderTrade(INIT)
建仓单成交 建仓中 --> 建仓失败: onOrderError(INIT)
委托被拒 建仓失败 --> 建仓中: refreshGridOrder()
重新下建仓单 已建仓 --> 网格运行: refreshGridOrder()
上下各挂一单 网格运行 --> 网格运行: onOrderTrade(SELL)
卖出成交 → 上移
重新挂单 网格运行 --> 网格运行: onOrderTrade(BUY)
买入成交 → 下移
重新挂单 网格运行 --> 单边挂单: onOrderError
某方向委托失败 单边挂单 --> 网格运行: refreshGridOrder()
重新补挂失败方向的单 已建仓 --> 已停用: enabledTrading(False)
取消所有挂单 网格运行 --> 已停用: enabledTrading(False) 单边挂单 --> 已停用: enabledTrading(False) 已停用 --> 已建仓: enabledTrading(True)
仓位检查通过 已停用 --> 已停用: enabledTrading(True)
仓位不足,回退 ``` --- ## 9. 网格价格示意 ``` 价格 ↑ │ grid[5] = 12.00 ← 最贵(顶部) │ grid[4] = 11.50 │ grid[3] = 11.00 ← 当前位置 grid_index=3 │ grid[2] = 10.50 上方挂卖单 @10.50 (sellIdx=2, grid_index-1) │ grid[1] = 10.00 下方挂买单 @10.00 (buyIdx=1, 已成交位置) │ grid[0] = 9.50 ← 最便宜(底部/建仓价) │ └──────────────────────→ grid_index=3 时: 卖单挂在 grid[2] @10.50 → 价格跌到 10.50 卖出(上移一格,赚差价) 买单挂在 grid[4] @11.50 → 价格涨到 11.50 买入(下移一格,补仓) grid_size = grid[i] - grid[i-1] = 0.50(每格利润空间) ```