tqsdk.TqScenario - 场景试算
- class tqsdk.TqScenario(api: TqApi, account: TqAccount | TqKq | TqSim | None = None, positions: Position | Entity | None = None, init_balance: float = 10000000.0)
天勤场景试算类
该类通过创建内部 SimTrade 实例, 将用户当前账户的持仓/资金信息导入到一个独立的试算截面中, 再通过同步接口对这个试算截面进行下单、调整保证金率、查询账户等操作, 用于评估不同交易动作对保证金占用和风险度的影响。
常用于以下场景:
评估当前持仓下还能开多少手
评估减仓后可释放多少保证金
评估多合约组合开仓/减仓后的保证金与风险度
假设某个期货品种保证金率调整后重新测算账户风险度
当前版本有如下约定:
仅支持期货合约
仅支持单账户试算
所有接口均为同步函数,不支持异步,建议在 wait_update 主循环外完成试算,不影响实盘业务数据更新
用户执行下单操作,以用户传入的价格立即撮合成交,不存在部分成交的情况
获取实盘保证金率时,如果失败,降级到使用 Quote 中的保证金信息
ctp 保证金率查询有流控,大概 1 秒一次一个合约的查询请求
导入实盘的持仓区分今昨仓,对于上期所或者上期能源,平仓时注意区分平今/平昨
- Args:
api (TqApi): [必填] TqApi 实例
- account (Optional[Union[TqSim, TqAccount, TqKq]]): [可选] 保证金率来源账户。
不传时默认创建
TqSim模拟账户, 使用 Quote 中的保证金信息; 传入实盘账户时, 会按该账户对应的保证金率进行试算- positions (Optional[Union[Position, Entity]]): [可选] 初始持仓截面。
可以传入
get_position()返回的全部持仓对象, 也可以传入某一个合约的持仓对象; 不传时表示从空仓开始试算- init_balance (float): [可选] 初始账户资金, 默认为一千万。
当传入 positions 时, 会以该资金和持仓共同构建试算账户截面; 不传 positions 时, 可用于模拟空仓起步后的资金规模
Example 1:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL = "SHFE.rb2611" account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) quote = api.get_quote(SYMBOL) with TqScenario(api, account=account, init_balance=1000000) as s: s.scenario_insert_order(SYMBOL, "BUY", "OPEN", 1, quote.last_price) margin = s.scenario_get_account().margin print(f"场景1: {SYMBOL} 按 {quote.last_price} 价格开 1 手, 实盘保证金约为 {margin:.2f} 元")
Example 2:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL = "SHFE.rb2611" NEW_MARGIN_RATE = 0.15 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) positions = api.get_position() with TqScenario(api, account=account, positions=positions) as s: base_acc = s.scenario_get_account() s.scenario_set_margin_rate(SYMBOL, NEW_MARGIN_RATE) acc = s.scenario_get_account() print(f"场景2: 将 {SYMBOL} 保证金率调整为 {NEW_MARGIN_RATE:.0%}") print(f" 保证金: {base_acc.margin:.2f} -> {acc.margin:.2f}") print(f" 风险度: {base_acc.risk_ratio:.4f} -> {acc.risk_ratio:.4f}")
Example 3:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL = "SHFE.rb2611" BUDGET = 200000 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) quote = api.get_quote(SYMBOL) positions = api.get_position() with TqScenario(api, account=account, positions=positions) as s: base_margin = s.scenario_get_account().margin volume = 0 while True: order = s.scenario_insert_order(SYMBOL, "BUY", "OPEN", 1, quote.last_price) if order.status == "FINISHED" and order.volume_left > 0: print(f"开仓失败: {order.last_msg}") break volume += 1 added = s.scenario_get_account().margin - base_margin if added > BUDGET: order = s.scenario_insert_order(SYMBOL, "SELL", "CLOSETODAY", 1, quote.last_price) if order.status == "FINISHED" and order.volume_left > 0: print(f"平仓失败: {order.last_msg}") break volume -= 1 break acc = s.scenario_get_account() print(f"场景3: {BUDGET/10000:.0f} 万预算下 {SYMBOL} 最多可开 {volume} 手") print(f" 保证金 {base_margin:.2f} -> {acc.margin:.2f} (增加 {acc.margin - base_margin:.2f})") print(f" 风险度={acc.risk_ratio:.4f}")
Example 4:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL = "SHFE.rb2611" TARGET_SAVING = 200000 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) quote = api.get_quote(SYMBOL) positions = api.get_position() with TqScenario(api, account=account, positions=positions) as s: base_margin = s.scenario_get_account().margin volume = 0 while True: order = s.scenario_insert_order(SYMBOL, "SELL", "CLOSE", 1, quote.last_price) if order.status == "FINISHED" and order.volume_left > 0: print(f"平仓失败: {order.last_msg}") break volume += 1 saved = base_margin - s.scenario_get_account().margin if saved >= TARGET_SAVING: break acc = s.scenario_get_account() saved = base_margin - acc.margin print(f"场景4: 平仓 {volume} 手 {SYMBOL} 可节约 {saved:.2f} 元保证金") print(f" 保证金 {base_margin:.2f} -> {acc.margin:.2f}") print(f" 风险度={acc.risk_ratio:.4f}")
Example 5:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL_A = "SHFE.rb2611" SYMBOL_B = "DCE.b2606" VOL_A, VOL_B = 10, 20 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) quote_a = api.get_quote(SYMBOL_A) quote_b = api.get_quote(SYMBOL_B) positions = api.get_position() with TqScenario(api, account=account, positions=positions) as s: base_acc = s.scenario_get_account() order_a = s.scenario_insert_order(SYMBOL_A, "BUY", "OPEN", VOL_A, quote_a.last_price) order_b = s.scenario_insert_order(SYMBOL_B, "BUY", "OPEN", VOL_B, quote_b.last_price) if order_a.status == "FINISHED" and order_a.volume_left > 0: print(f"A 开仓失败: {order_a.last_msg}") if order_b.status == "FINISHED" and order_b.volume_left > 0: print(f"B 开仓失败: {order_b.last_msg}") acc = s.scenario_get_account() print(f"场景5: 开仓 {VOL_A}手{SYMBOL_A} + {VOL_B}手{SYMBOL_B}") print(f" 保证金: {base_acc.margin:.2f} -> {acc.margin:.2f} (增加 {acc.margin - base_acc.margin:.2f})") print(f" 风险度: {base_acc.risk_ratio:.4f} -> {acc.risk_ratio:.4f}")
Example 6:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL_A = "SHFE.rb2611" SYMBOL_B = "DCE.b2606" VOL_A, VOL_B = 10, 20 INIT_BALANCE = 1000000 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) quote_a = api.get_quote(SYMBOL_A) quote_b = api.get_quote(SYMBOL_B) with TqScenario(api, account=account, init_balance=INIT_BALANCE) as s: s.scenario_insert_order(SYMBOL_A, "BUY", "OPEN", VOL_A, quote_a.last_price) s.scenario_insert_order(SYMBOL_B, "BUY", "OPEN", VOL_B, quote_b.last_price) acc = s.scenario_get_account() print(f"场景6: 空仓起步, 开仓 {VOL_A}手{SYMBOL_A} + {VOL_B}手{SYMBOL_B}") print(f" 初始资金: {INIT_BALANCE:.2f}") print(f" 保证金: {acc.margin:.2f}") print(f" 风险度: {acc.risk_ratio:.4f}")
Example 7:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario SYMBOL_A = "SHFE.rb2611" SYMBOL_B = "DCE.b2606" VOL_A, VOL_B = 10, 20 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) quote_a = api.get_quote(SYMBOL_A) quote_b = api.get_quote(SYMBOL_B) positions = api.get_position() with TqScenario(api, account=account, positions=positions) as s: base_acc = s.scenario_get_account() order_a = s.scenario_insert_order(SYMBOL_A, "SELL", "CLOSE", VOL_A, quote_a.last_price) order_b = s.scenario_insert_order(SYMBOL_B, "SELL", "CLOSE", VOL_B, quote_b.last_price) if order_a.status == "FINISHED" and order_a.volume_left > 0: print(f"A 平仓失败: {order_a.last_msg}") if order_b.status == "FINISHED" and order_b.volume_left > 0: print(f"B 平仓失败: {order_b.last_msg}") acc = s.scenario_get_account() print(f"场景7: 减仓 {VOL_A}手{SYMBOL_A} + {VOL_B}手{SYMBOL_B}") print(f" 保证金: {base_acc.margin:.2f} -> {acc.margin:.2f} (减少 {base_acc.margin - acc.margin:.2f})") print(f" 风险度: {base_acc.risk_ratio:.4f} -> {acc.risk_ratio:.4f}")
Example 8:
from tqsdk import TqApi, TqAccount, TqAuth from tqsdk.scenario import TqScenario EXTRA = 100000 account = TqAccount("期货公司", "账号", "密码") api = TqApi(account=account, auth=TqAuth("快期账户", "账户密码")) positions = api.get_position() balance = api.get_account().balance risk_ratio = api.get_account().risk_ratio with TqScenario(api, account=account, positions=positions, init_balance=balance + EXTRA) as s: acc = s.scenario_get_account() print(f"场景8: 当前持仓不变,权益增加 {EXTRA/10000:.0f} 万") print(f" 风险度: {risk_ratio:.4f} -> {acc.risk_ratio:.4f}")
- scenario_set_margin_rate(symbol: str, margin_rate: float = nan)
设置指定合约的保证金率。
调用后会立即更新试算截面中的该合约保证金, 并同步刷新账户保证金占用与风险度。 常用于模拟交易所或期货公司调整保证金率后的风险变化。
- Args:
symbol (str): 合约代码, 格式为 交易所代码.合约代码, 例如 "SHFE.rb2611"
margin_rate (float): 保证金率, 例如 0.12 表示 12%
- scenario_insert_order(symbol: str, direction: str, offset: str, volume: int, limit_price: float) Order
场景试算下单。
该接口会以传入的价格立即撮合成交, 并同步更新试算账户中的持仓、保证金占用和风险度。 可以在同一个 TqScenario 对象中连续调用, 线性模拟一组交易动作的累计影响。
- Args:
symbol (str): 合约代码, 格式为 交易所代码.合约代码, 例如 "SHFE.cu2501"
direction (str): "BUY" 或 "SELL"
offset (str): "OPEN", "CLOSE" 或 "CLOSETODAY" (上期所和上期能源分平今/平昨, 平今用 "CLOSETODAY", 平昨用 "CLOSE"; 其他交易所直接用 "CLOSE")
volume (int): 下单手数, 必须为正整数
limit_price (float): 下单价格, 以该价格立即撮合成交
- Returns:
Order: 委托单对象, 仅包含以下字段:status: "ALIVE" / "FINISHED"
volume_left: 剩余未成交手数, 0 表示全部成交
last_msg: 结果描述 (失败原因 / 成功提示)