跳转到内容

替换 FA 分配

replaceFA() 用来替换 TWS 中的 FA 分配配置。它不是“追加一个字段”的接口,而是把传入的完整 XML 写回 TWS。因此它属于高风险修改接口,必须先备份原 XML。

普通账户不应调用 replaceFA()。如果 requestFA() 已经返回 321 non FA customers,说明账户没有 FA 配置可替换。

app.replaceFA(reqId, faData, cxml)
参数类型中文含义说明
reqIdint请求编号用于匹配 replaceFAEnd()
faDataintFA 数据类型新项目主要替换 1 账户组;旧 Profile 受 TWS 设置影响。
cxmlstr完整 XML 配置会替换对应类型的原配置。

replaceFA() 的语义是“整份替换”,不是“局部更新”。如果只想改一个组,也要先读取原 XML、修改目标节点,再把完整 XML 交回 TWS。不要拿文档示例 XML 直接提交。

def replaceFAEnd(self, reqId, text):
print("FA 配置替换完成:", reqId, text)

收到 replaceFAEnd() 只代表 TWS 处理了替换请求。稳妥做法是替换完成后再次调用 requestFA(),把返回 XML 和预期配置对比。

requestFA() 读取原 XML
-> 保存原 XML 备份
-> 用 XML 解析器生成新 XML
-> 校验组名、账户数量、方法名
-> replaceFA() 提交完整 XML
-> 等待 replaceFAEnd()
-> 再次 requestFA() 读取并比对

不要手写字符串拼 XML。应该先解析原 XML,再基于节点修改,最后序列化。

import xml.etree.ElementTree as ET
def validate_fa_xml(cxml):
root = ET.fromstring(cxml)
groups = root.findall(".//Group")
if not groups:
raise ValueError("XML 中没有找到 Group 节点")
for group in groups:
name = group.findtext("name")
method = group.findtext("defaultMethod")
accounts = group.findall(".//String")
if not name:
raise ValueError("Group 缺少 name")
if not method:
raise ValueError(f"Group {name} 缺少 defaultMethod")
if not accounts:
raise ValueError(f"Group {name} 没有账户")

普通模拟账户请求 requestFA() 可能返回:

ERROR=reqId=-1;code=321;msg=FA data operations ignored for non FA customers.

中文界面可能显示为:

ERROR=reqId=-1;code=321;msg=确认请求时出错。:-'X':导致- FA data operations ignored for non FA customers.

这种情况下不要尝试 replaceFA()。正确处理是提示用户切换 FA 账户,或把 FA 替换功能隐藏为不可用。