def _on_update_quotes(self, symbol, position, quote, underlying_quote): # 调整持仓保证金和盈亏 position = self._positions.get(symbol) underlying_last_price = underlying_quote[ "last_price"] if underlying_quote else float('nan') future_margin = _get_future_margin(quote) if position["volume_long"] > 0 or position["volume_short"] > 0: if position["last_price"] != quote["last_price"] \ or (math.isnan(future_margin) or future_margin != position["future_margin"]) \ or (underlying_quote and ( math.isnan(underlying_last_price) or underlying_last_price != position["underlying_last_price"])): self._adjust_position_account( symbol, quote, underlying_quote, pre_last_price=position["last_price"], last_price=quote["last_price"], pre_underlying_last_price=position[ "underlying_last_price"], underlying_last_price=underlying_last_price) position["future_margin"] = future_margin position["last_price"] = quote["last_price"] position["underlying_last_price"] = underlying_last_price else: # 修改辅助变量 position["future_margin"] = future_margin position["last_price"] = quote["last_price"] position["underlying_last_price"] = underlying_last_price self._append_to_diffs( ['positions', symbol], position) # 一定要返回 position,下游会用到 future_margin 字段判断修改保证金是否成功 self._append_to_diffs(['accounts', 'CNY'], self._account)
def get_margin(self, symbol: str): """ 获取指定合约模拟交易的每手保证金。 Args: symbol (str): 合约代码 Returns: float: 返回合约模拟交易的每手保证金 Example:: from tqsdk import TqSim, TqApi, TqAuth sim = TqSim() api = TqApi(sim, auth=TqAuth("信易账户", "账户密码")) quote = api.get_quote("SHFE.cu2112") print(sim.get_margin("SHFE.cu2112")) """ return _get_future_margin(self._data.get("quotes", {}).get(symbol, {}))
def _adjust_position_account(self, symbol, quote, underlying_quote=None, pre_last_price=float('nan'), last_price=float('nan'), pre_underlying_last_price=float('nan'), underlying_last_price=float('nan'), buy_open=0, buy_close=0, sell_open=0, sell_close=0): """ 价格变化,使得 position 中的以下计算字段需要修改,这个函数计算出需要修改的差值部分,计算出差值部分修改 position、account 有两种情况下调用 1. 委托单 FINISHED,且全部成交,分为4种:buy_open, buy_close, sell_open, sell_close 2. 行情跳动 """ position = self._positions[symbol] float_profit_long = 0 # 多头浮动盈亏 float_profit_short = 0 # 空头浮动盈亏 position_profit_long = 0 # 多头持仓盈亏,期权持仓盈亏为0 position_profit_short = 0 # 空头持仓盈亏,期权持仓盈亏为0 margin_long = 0 # 多头占用保证金 margin_short = 0 # 空头占用保证金 market_value_long = 0 # 期权权利方市值(始终 >= 0) market_value_short = 0 # 期权义务方市值(始终 <= 0) assert [buy_open, buy_close, sell_open, sell_close ].count(0) >= 3 # 只有一个大于0, 或者都是0,表示价格变化导致的字段修改 if buy_open > 0: # 买开,pre_last_price 应该是成交价格,last_price 应该是 position['last_price'] float_profit_long = (last_price - pre_last_price ) * buy_open * quote["volume_multiple"] if quote["ins_class"].endswith("OPTION"): market_value_long = last_price * buy_open * quote[ "volume_multiple"] else: margin_long = buy_open * _get_future_margin(quote) position_profit_long = (last_price - pre_last_price ) * buy_open * quote["volume_multiple"] elif sell_close > 0: # 卖平,pre_last_price 应该是 position['last_price'],last_price 应该是 0 float_profit_long = -position["float_profit_long"] / position[ "volume_long"] * sell_close if quote["ins_class"].endswith("OPTION"): market_value_long = -pre_last_price * sell_close * quote[ "volume_multiple"] else: margin_long = -sell_close * _get_future_margin(quote) position_profit_long = -position[ "position_profit_long"] / position[ "volume_long"] * sell_close elif sell_open > 0: # 卖开 float_profit_short = (pre_last_price - last_price ) * sell_open * quote["volume_multiple"] if quote["ins_class"].endswith("OPTION"): market_value_short = -last_price * sell_open * quote[ "volume_multiple"] margin_short = sell_open * _get_option_margin( quote, last_price, underlying_last_price) else: margin_short = sell_open * _get_future_margin(quote) position_profit_short = ( pre_last_price - last_price) * sell_open * quote["volume_multiple"] elif buy_close > 0: # 买平 float_profit_short = -position["float_profit_short"] / position[ "volume_short"] * buy_close if quote["ins_class"].endswith("OPTION"): market_value_short = pre_last_price * buy_close * quote[ "volume_multiple"] margin_short = -buy_close * _get_option_margin( quote, pre_last_price, pre_underlying_last_price) else: margin_short = -buy_close * _get_future_margin(quote) position_profit_short = -position[ "position_profit_short"] / position[ "volume_short"] * buy_close else: float_profit_long = ( last_price - pre_last_price ) * position["volume_long"] * quote["volume_multiple"] # 多头浮动盈亏 float_profit_short = ( pre_last_price - last_price ) * position["volume_short"] * quote["volume_multiple"] # 空头浮动盈亏 if quote["ins_class"].endswith("OPTION"): margin_short = _get_option_margin( quote, last_price, underlying_last_price ) * position["volume_short"] - position["margin_short"] market_value_long = ( last_price - pre_last_price ) * position["volume_long"] * quote["volume_multiple"] market_value_short = ( pre_last_price - last_price ) * position["volume_short"] * quote["volume_multiple"] else: # 期权持仓盈亏为 0 position_profit_long = float_profit_long # 多头持仓盈亏 position_profit_short = float_profit_short # 空头持仓盈亏 margin_long = _get_future_margin( quote) * position["volume_long"] - position["margin_long"] margin_short = _get_future_margin(quote) * position[ "volume_short"] - position["margin_short"] if any([buy_open, buy_close, sell_open, sell_close]): # 修改 position volume 相关的计算字段 # 在上面 sell_close buy_close 两种情况,计算浮动盈亏时,用到了修改前的手数,所以需改手数字段的代码放在这个位置 self._adjust_position_volume(position) self._adjust_position(quote, position, float_profit_long, float_profit_short, position_profit_long, position_profit_short, margin_long, margin_short, market_value_long, market_value_short) self._adjust_account_by_position( float_profit=float_profit_long + float_profit_short, position_profit=position_profit_long + position_profit_short, margin=margin_long + margin_short, market_value=market_value_long + market_value_short)
def _generate_position(self, symbol, quote, underlying_quote) -> dict: return { "exchange_id": symbol.split(".", maxsplit=1)[0], "instrument_id": symbol.split(".", maxsplit=1)[1], "pos_long_his": 0, "pos_long_today": 0, "pos_short_his": 0, "pos_short_today": 0, "volume_long_today": 0, "volume_long_his": 0, "volume_long": 0, "volume_long_frozen_today": 0, "volume_long_frozen_his": 0, "volume_long_frozen": 0, "volume_short_today": 0, "volume_short_his": 0, "volume_short": 0, "volume_short_frozen_today": 0, "volume_short_frozen_his": 0, "volume_short_frozen": 0, "open_price_long": float("nan"), "open_price_short": float("nan"), "open_cost_long": 0.0, "open_cost_short": 0.0, "position_price_long": float("nan"), "position_price_short": float("nan"), "position_cost_long": 0.0, "position_cost_short": 0.0, "float_profit_long": 0.0, "float_profit_short": 0.0, "float_profit": 0.0, "position_profit_long": 0.0, "position_profit_short": 0.0, "position_profit": 0.0, "margin_long": 0.0, "margin_short": 0.0, "margin": 0.0, "last_price": quote["last_price"], "underlying_last_price": underlying_quote["last_price"] if underlying_quote else float("nan"), "market_value_long": 0.0, # 权利方市值(始终 >= 0) "market_value_short": 0.0, # 义务方市值(始终 <= 0) "market_value": 0.0, "future_margin": _get_future_margin(quote), }
def _check_insert_order(self, order, symbol, position, quote, underlying_quote=None): # 无法计入 orderbook, 各种账户都需要判断的 if ("commission" not in quote or "margin" not in quote) and not quote["ins_class"].endswith("OPTION"): order["last_msg"] = "不支持的合约类型,TqSim 目前不支持组合,股票,etf期权模拟交易" order["status"] = "FINISHED" if order["status"] == "ALIVE" and not self._is_in_trading_time(quote): order["last_msg"] = "下单失败, 不在可交易时间段内" order["status"] = "FINISHED" if order["status"] == "ALIVE" and order["offset"].startswith('CLOSE'): if order["exchange_id"] in ["SHFE", "INE"]: if order["offset"] == "CLOSETODAY": if order["direction"] == "BUY" and position[ "volume_short_today"] - position[ "volume_long_frozen_today"] < order[ "volume_orign"]: order["last_msg"] = "平今仓手数不足" elif order["direction"] == "SELL" and position[ "volume_long_today"] - position[ "volume_long_frozen_today"] < order[ "volume_orign"]: order["last_msg"] = "平今仓手数不足" if order["offset"] == "CLOSE": if order["direction"] == "BUY" and position[ "volume_short_his"] - position[ "volume_short_frozen_his"] < order[ "volume_orign"]: order["last_msg"] = "平昨仓手数不足" elif order["direction"] == "SELL" and position[ "volume_long_his"] - position[ "volume_long_frozen_his"] < order[ "volume_orign"]: order["last_msg"] = "平昨仓手数不足" else: if order["direction"] == "BUY" and position[ "volume_short"] - position[ "volume_short_frozen"] < order["volume_orign"]: order["last_msg"] = "平仓手数不足" elif order["direction"] == "SELL" and position[ "volume_long"] - position[ "volume_long_frozen"] < order["volume_orign"]: order["last_msg"] = "平仓手数不足" if order["last_msg"].endswith("手数不足"): order["status"] = "FINISHED" if order["status"] == "ALIVE" and order["offset"] == "OPEN": # 计算冻结保证金,冻结权利金 if quote["ins_class"].endswith("OPTION"): if order["direction"] == "SELL": # 期权的SELL义务仓,开仓需要冻结保证金 order["frozen_margin"] = order[ "volume_orign"] * _get_option_margin( quote, quote["last_price"], underlying_quote["last_price"]) else: # 期权的BUY权利仓(市价单使用 last_price 计算需要冻结的权利金) price = quote["last_price"] if order[ "price_type"] == "ANY" else order["limit_price"] order["frozen_premium"] = order["volume_orign"] * quote[ "volume_multiple"] * price else: order["frozen_margin"] = order[ "volume_orign"] * _get_future_margin(quote) if order["frozen_margin"] + order[ "frozen_premium"] > self._account["available"]: order["frozen_margin"] = 0.0 order["frozen_premium"] = 0.0 order["last_msg"] = '开仓资金不足' order["status"] = "FINISHED" if order["status"] == "FINISHED": self._append_to_diffs(['orders', order["order_id"]], order)