Exemple #1
0
 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)
Exemple #2
0
    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, {}))
Exemple #3
0
    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)
Exemple #4
0
 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),
     }
Exemple #5
0
    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)