#:!/usr/bin/env python
#:  -*- coding: utf-8 -*-
__author__ = 'chengzhi'

import copy
import json
import warnings

from tqsdk.diff import _get_obj
from tqsdk.entity import Entity
from tqsdk.utils import _query_for_init, _generate_uuid


class QuotesEntity(Entity):

    def __init__(self, api):
        self._api = api
        self._not_send_init_query = True

    def __iter__(self):
        message = """
            不推荐使用 api._data['quotes'] 获取全部合约，该使用方法会在 20201101 之后的版本中放弃维护。
            需要注意：
            * 在同步代码中，初次使用 api._data['quotes'] 获取全部合约会产生一个耗时很长的查询。
            * 在协程中，api._data['quotes'] 这种用法不支持使用。
            请尽快修改使用新的接口，参考链接 http://doc.shinnytech.com/tqsdk/reference/tqsdk.api.html#tqsdk.api.TqApi.query_quotes
        """
        warnings.warn(message, DeprecationWarning, stacklevel=3)
        self._api._logger.warning("deprecation", content="Deprecation Warning in api._data['quotes']")

        # 兼容旧版 tqsdk 所做的修改，来支持用户使用 for k,v in api._data.quotes.items() 类似的用法
        # 从 api._init_() 最后 3 行移到这里
        if self._not_send_init_query and self._api._stock:
            self._not_send_init_query = False
            q = _query_for_init()
            self._api.query_graphql(q, {}, _generate_uuid("PYSDK_quote"))
        return super().__iter__()


class Quote(Entity):
    """ Quote 是一个行情对象 """

    def __init__(self, api):
        self._api = api
        #: 行情从交易所发出的时间(北京时间), 格式为 "2017-07-26 23:04:21.000001"
        self.datetime: str = ""
        #: 卖一价
        self.ask_price1: float = float("nan")
        #: 卖一量
        self.ask_volume1: int = 0
        #: 买一价
        self.bid_price1: float = float("nan")
        #: 买一量
        self.bid_volume1: int = 0
        #: 卖二价
        self.ask_price2: float = float("nan")
        #: 卖二量
        self.ask_volume2: int = 0
        #: 买二价
        self.bid_price2: float = float("nan")
        #: 买二量
        self.bid_volume2: int = 0
        #: 卖三价
        self.ask_price3: float = float("nan")
        #: 卖三量
        self.ask_volume3: int = 0
        #: 买三价
        self.bid_price3: float = float("nan")
        #: 买三量
        self.bid_volume3: int = 0
        #: 卖四价
        self.ask_price4: float = float("nan")
        #: 卖四量
        self.ask_volume4: int = 0
        #: 买四价
        self.bid_price4: float = float("nan")
        #: 买四量
        self.bid_volume4: int = 0
        #: 卖五价
        self.ask_price5: float = float("nan")
        #: 卖五量
        self.ask_volume5: int = 0
        #: 买五价
        self.bid_price5: float = float("nan")
        #: 买五量
        self.bid_volume5: int = 0
        #: 最新价
        self.last_price: float = float("nan")
        #: 当日最高价
        self.highest: float = float("nan")
        #: 当日最低价
        self.lowest: float = float("nan")
        #: 开盘价
        self.open: float = float("nan")
        #: 收盘价
        self.close: float = float("nan")
        #: 当日均价
        self.average: float = float("nan")
        #: 成交量
        self.volume: int = 0
        #: 成交额
        self.amount: float = float("nan")
        #: 持仓量
        self.open_interest: int = 0
        #: 结算价
        self.settlement: float = float("nan")
        #: 涨停价
        self.upper_limit: float = float("nan")
        #: 跌停价
        self.lower_limit: float = float("nan")
        #: 昨持仓量
        self.pre_open_interest: int = 0
        #: 昨结算价
        self.pre_settlement: float = float("nan")
        #: 昨收盘价
        self.pre_close: float = float("nan")
        #: 合约价格变动单位
        self.price_tick: float = float("nan")
        #: 合约价格小数位数
        self.price_decs: int = 0
        #: 合约乘数
        self.volume_multiple: int = 0
        #: 最大限价单手数
        self.max_limit_order_volume: int = 0
        #: 最大市价单手数
        self.max_market_order_volume: int = 0
        #: 最小限价单手数
        self.min_limit_order_volume: int = 0
        #: 最小市价单手数
        self.min_market_order_volume: int = 0
        #: 标的合约
        self.underlying_symbol: str = ""
        #: 行权价
        self.strike_price: float = float("nan")
        #: 合约类型
        self.ins_class: str = ""
        #: 交易所内的合约代码
        self.instrument_id: str = ""
        #: 合约中文名
        self.instrument_name: str = ""
        #: 交易所代码
        self.exchange_id: str = ""
        #: 合约是否已下市
        self.expired: bool = False
        #: 交易时间段
        self.trading_time: TradingTime = TradingTime(self._api)
        #: 到期具体日，以秒为单位的 timestamp 值
        self.expire_datetime: float = float("nan")
        #: 期货交割日年份，只对期货品种有效。期权推荐使用最后行权日年份
        self.delivery_year: int = 0
        #: 期货交割日月份，只对期货品种有效。期权推荐使用最后行权日月份
        self.delivery_month: int = 0
        #: 期权最后行权日，以秒为单位的 timestamp 值
        self.last_exercise_datetime: float = float("nan")
        #: 期权最后行权日年份，只对期权品种有效。
        self.exercise_year: int = 0
        #: 期权最后行权日月份，只对期权品种有效。
        self.exercise_month: int = 0
        #: 期权方向
        self.option_class: str = ""
        #: 期权行权方式，美式:'A'，欧式:'E'
        self.exercise_type: str = ""
        #: 品种代码
        self.product_id: str = ""
        #: ETF实时单位基金净值
        self.iopv: float = float("nan")
        #: 日流通股数，只对证券产品有效。
        self.public_float_share_quantity: int = 0
        #: 除权表 ["20190601,0.15","20200107,0.2"…]
        self.stock_dividend_ratio: list = []
        #: 除息表 ["20190601,0.15","20200107,0.2"…]
        self.cash_dividend_ratio: list = []
        #: 距离到期日的剩余天数（自然日天数），正数表示距离到期日的剩余天数，0表示到期日当天，负数表示距离到期日已经过去的天数
        self.expire_rest_days: int = float('nan')

    def _instance_entity(self, path):
        super(Quote, self)._instance_entity(path)
        self.trading_time = copy.copy(self.trading_time)
        self.trading_time._instance_entity(path + ["trading_time"])

    @property
    def underlying_quote(self):
        """
        标的合约 underlying_symbol 所指定的合约对象，若没有标的合约则为 None

        :return: 标的指定的 :py:class:`~tqsdk.objs.Quote` 对象
        """
        if self.underlying_symbol:
            return self._api.get_quote(self.underlying_symbol)
        return None

    def __await__(self):
        assert self._task
        return self._task.__await__()


class TradingTime(Entity):
    """ TradingTime 是一个交易时间对象
        它不是一个可单独使用的类，而是用于定义 Quote 的 trading_time 字段的类型

        (每个连续的交易时间段是一个列表，包含两个字符串元素，分别为这个时间段的起止点)"""

    def __init__(self, api):
        self._api = api
        #: 白盘
        self.day: list = []
        #: 夜盘（注意：本字段中过了 24：00 的时间则在其基础往上加，如凌晨1点为 '25:00:00' ）
        self.night: list = []

    def __repr__(self):
        return json.dumps({"day": self.day, "night": self.night})


class TradingStatus(Entity):
    """ TradingStatus 是一个交易状态对象 """

    def __init__(self, api):
        self._api = api
        #: 合约
        self.symbol: str = ""
        #: 交易状态, AUCTIONORDERING: 集合竞价报单; CONTINOUS: 连续交易; NOTRADING: 非交易时段
        self.trade_status: str = ""

    def __await__(self):
        assert self._task
        return self._task.__await__()


class Kline(Entity):
    """ Kline 是一个K线对象 """

    def __init__(self, api):
        self._api = api
        #: K线起点时间(按北京时间)，自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数
        self.datetime: int = 0
        #: K线起始时刻的最新价
        self.open: float = float("nan")
        #: K线时间范围内的最高价
        self.high: float = float("nan")
        #: K线时间范围内的最低价
        self.low: float = float("nan")
        #: K线结束时刻的最新价
        self.close: float = float("nan")
        #: K线时间范围内的成交量
        self.volume: int = 0
        #: K线起始时刻的持仓量
        self.open_oi: int = 0
        #: K线结束时刻的持仓量
        self.close_oi: int = 0


class Tick(Entity):
    """ Tick 是一个tick对象 """

    def __init__(self, api):
        self._api = api
        #: tick从交易所发出的时间(按北京时间)，自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数
        self.datetime: int = 0
        #: 最新价
        self.last_price: float = float("nan")
        #: 当日均价
        self.average: float = float("nan")
        #: 当日最高价
        self.highest: float = float("nan")
        #: 当日最低价
        self.lowest: float = float("nan")
        #: 卖1价
        self.ask_price1: float = float("nan")
        #: 卖1量
        self.ask_volume1: int = 0
        #: 买1价
        self.bid_price1: float = float("nan")
        #: 买1量
        self.bid_volume1: int = 0
        #: 卖2价
        self.ask_price2: float = float("nan")
        #: 卖2量
        self.ask_volume2: int = 0
        #: 买2价
        self.bid_price2: float = float("nan")
        #: 买2量
        self.bid_volume2: int = 0
        #: 卖3价
        self.ask_price3: float = float("nan")
        #: 卖3量
        self.ask_volume3: int = 0
        #: 买3价
        self.bid_price3: float = float("nan")
        #: 买3量
        self.bid_volume3: int = 0
        #: 卖4价
        self.ask_price4: float = float("nan")
        #: 卖4量
        self.ask_volume4: int = 0
        #: 买4价
        self.bid_price4: float = float("nan")
        #: 买4量
        self.bid_volume4: int = 0
        #: 卖5价
        self.ask_price5: float = float("nan")
        #: 卖5量
        self.ask_volume5: int = 0
        #: 买5价
        self.bid_price5: float = float("nan")
        #: 买5量
        self.bid_volume5: int = 0
        #: 当日成交量
        self.volume: int = 0
        #: 成交额
        self.amount: float = float("nan")
        #: 持仓量
        self.open_interest: int = 0


class Account(Entity):
    """ Account 是一个账户对象 """

    def __init__(self, api):
        self._api = api
        #: 币种
        self.currency: str = ""
        #: 昨日账户权益(不包含期权)
        self.pre_balance: float = float("nan")
        #: 静态权益 （静态权益 = 昨日结算的权益 + 今日入金 - 今日出金, 以服务器查询ctp后返回的金额为准）(不包含期权)
        self.static_balance: float = float("nan")
        #: 账户权益 （账户权益 = 动态权益 = 静态权益 + 平仓盈亏 + 持仓盈亏 - 手续费 + 权利金 + 期权市值）
        self.balance: float = float("nan")
        #: 可用资金（可用资金 = 账户权益 - 冻结保证金 - 保证金 - 冻结权利金 - 冻结手续费 - 期权市值）
        self.available: float = float("nan")
        #: 期货公司返回的balance（ctp_balance = 静态权益 + 平仓盈亏 + 持仓盈亏 - 手续费 + 权利金）
        self.ctp_balance: float = float("nan")
        #: 期货公司返回的available（ctp_available = ctp_balance - 保证金 - 冻结保证金 - 冻结手续费 - 冻结权利金）
        self.ctp_available: float = float("nan")
        #: 浮动盈亏
        self.float_profit: float = float("nan")
        #: 持仓盈亏
        self.position_profit: float = float("nan")
        #: 本交易日内平仓盈亏
        self.close_profit: float = float("nan")
        #: 冻结保证金
        self.frozen_margin: float = float("nan")
        #: 保证金占用
        self.margin: float = float("nan")
        #: 冻结手续费
        self.frozen_commission: float = float("nan")
        #: 本交易日内交纳的手续费
        self.commission: float = float("nan")
        #: 冻结权利金
        self.frozen_premium: float = float("nan")
        #: 本交易日内收入-交纳的权利金
        self.premium: float = float("nan")
        #: 本交易日内的入金金额
        self.deposit: float = float("nan")
        #: 本交易日内的出金金额
        self.withdraw: float = float("nan")
        #: 风险度（风险度 = 保证金 / 账户权益）
        self.risk_ratio: float = float("nan")
        #: 期权市值
        self.market_value: float = float("nan")


class Position(Entity):
    """ Position 是一个持仓对象 """

    def __init__(self, api):
        self._api = api
        #: 交易所
        self.exchange_id: str = ""
        #: 交易所内的合约代码
        self.instrument_id: str = ""
        #: 多头老仓手数
        self.pos_long_his: int = 0
        #: 多头今仓手数
        self.pos_long_today: int = 0
        #: 空头老仓手数
        self.pos_short_his: int = 0
        #: 空头今仓手数
        self.pos_short_today: int = 0
        #: 期货公司查询的多头今仓手数 (不推荐, 推荐使用pos_long_today)
        self.volume_long_today: int = 0
        #: 期货公司查询的多头老仓手数 (不推荐, 推荐使用pos_long_his)
        self.volume_long_his: int = 0
        #: 期货公司查询的多头手数 (不推荐, 推荐使用pos_long)
        self.volume_long: int = 0
        #: 期货公司查询的多头今仓冻结 (不推荐)
        self.volume_long_frozen_today: int = 0
        #: 期货公司查询的多头老仓冻结 (不推荐)
        self.volume_long_frozen_his: int = 0
        #: 期货公司查询的多头持仓冻结 (不推荐)
        self.volume_long_frozen: int = 0
        #: 期货公司查询的空头今仓手数 (不推荐, 推荐使用pos_short_today)
        self.volume_short_today: int = 0
        #: 期货公司查询的空头老仓手数 (不推荐, 推荐使用pos_short_his)
        self.volume_short_his: int = 0
        #: 期货公司查询的空头手数 (不推荐, 推荐使用pos_short)
        self.volume_short: int = 0
        #: 期货公司查询的空头今仓冻结 (不推荐)
        self.volume_short_frozen_today: int = 0
        #: 期货公司查询的空头老仓冻结 (不推荐)
        self.volume_short_frozen_his: int = 0
        #: 期货公司查询的空头持仓冻结 (不推荐)
        self.volume_short_frozen: int = 0
        #: 多头开仓均价,以开仓价来统计
        self.open_price_long: float = float("nan")
        #: 空头开仓均价,以开仓价来统计
        self.open_price_short: float = float("nan")
        #: 多头开仓成本,为开仓价乘以手数
        self.open_cost_long: float = float("nan")
        #: 空头开仓成本,为开仓价乘以手数
        self.open_cost_short: float = float("nan")
        #: 多头持仓均价,为多头持仓成本除以多头数量
        self.position_price_long: float = float("nan")
        #: 空头持仓均价,为空头持仓成本除以空头数量
        self.position_price_short: float = float("nan")
        #: 多头持仓成本,为今仓的开仓价乘以手数加上昨仓的昨结算价乘以手数的和
        self.position_cost_long: float = float("nan")
        #: 空头持仓成本,为今仓的开仓价乘以手数加上昨仓的昨结算价乘以手数的和
        self.position_cost_short: float = float("nan")
        #: 多头浮动盈亏
        self.float_profit_long: float = float("nan")
        #: 空头浮动盈亏
        self.float_profit_short: float = float("nan")
        #: 浮动盈亏 （浮动盈亏: 相对于开仓价的盈亏）
        self.float_profit: float = float("nan")
        #: 多头持仓盈亏
        self.position_profit_long: float = float("nan")
        #: 空头持仓盈亏
        self.position_profit_short: float = float("nan")
        #: 持仓盈亏 （持仓盈亏: 相对于上一交易日结算价的盈亏），期权持仓盈亏为 0
        self.position_profit: float = float("nan")
        #: 多头占用保证金
        self.margin_long: float = float("nan")
        #: 空头占用保证金
        self.margin_short: float = float("nan")
        #: 占用保证金
        self.margin: float = float("nan")
        #: 期权权利方市值(始终 >= 0)
        self.market_value_long: float = float("nan")
        #: 期权义务方市值(始终 <= 0)
        self.market_value_short: float = float("nan")
        #: 期权市值
        self.market_value: float = float("nan")
        #: 净持仓手数, ==0表示无持仓或多空持仓手数相等. <0表示空头持仓大于多头持仓, >0表示多头持仓大于空头持仓
        self.pos: int = 0
        #: 多头持仓手数, ==0表示无多头持仓. >0表示多头持仓手数
        self.pos_long: int = 0
        #: 空头持仓手数, ==0表示无空头持仓. >0表示空头持仓手数
        self.pos_short: int = 0

    @property
    def orders(self):
        """
        与此持仓相关的且目前委托单状态为ALIVE的开仓/平仓挂单

        :return: dict, 其中每个元素的key为委托单ID, value为 :py:class:`~tqsdk.objs.Order`
        """
        tdict = _get_obj(self._api._data, ["trade", self._path[1], "orders"])
        fts = {order_id: order for order_id, order in tdict.items() if (not order_id.startswith(
            "_")) and order.instrument_id == self.instrument_id and order.exchange_id == self.exchange_id and order.status == "ALIVE"}
        return fts


class Order(Entity):
    """ Order 是一个委托单对象 """

    def __init__(self, api):
        self._api = api
        #: 委托单ID, 对于一个用户的所有委托单，这个ID都是不重复的
        self.order_id: str = ""
        #: 交易所单号
        self.exchange_order_id: str = ""
        #: 交易所
        self.exchange_id: str = ""
        #: 交易所内的合约代码
        self.instrument_id: str = ""
        #: 下单方向, BUY=买, SELL=卖
        self.direction: str = ""
        #: 开平标志, OPEN=开仓, CLOSE=平仓, CLOSETODAY=平今
        self.offset: str = ""
        #: 总报单手数
        self.volume_orign: int = 0
        #: 未成交手数
        self.volume_left: int = 0
        #: 委托价格, 仅当 price_type = LIMIT 时有效
        self.limit_price: float = float("nan")
        #: 价格类型, ANY=市价, LIMIT=限价
        self.price_type: str = ""
        #: 手数条件, ANY=任何数量, MIN=最小数量, ALL=全部数量
        self.volume_condition: str = ""
        #: 时间条件, IOC=立即完成，否则撤销, GFS=本节有效, GFD=当日有效, GTC=撤销前有效, GFA=集合竞价有效
        self.time_condition: str = ""
        #: 下单时间，自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数.
        self.insert_date_time: int = 0
        #: 委托单状态信息
        self.last_msg: str = ""
        #: 委托单状态, ALIVE=有效, FINISHED=已完
        self.status: str = ""
        #: 委托单是否确定已死亡（以后一定不会再产生成交）(注意，False 不代表委托单还存活，有可能交易所回来的信息还在路上或者丢掉了)
        self.is_dead: bool = None
        #: 委托单是否确定已报入交易所并等待成交 (注意，返回 False 不代表确定未报入交易所，有可能交易所回来的信息还在路上或者丢掉了)
        self.is_online: bool = None
        #: 委托单是否确定是错单（即下单失败，一定不会有成交）(注意，返回 False 不代表确定不是错单，有可能交易所回来的信息还在路上或者丢掉了)
        self.is_error: bool = None
        #: 平均成交价
        self.trade_price: float = float('nan')

        self._this_session = False

    @property
    def trade_records(self):
        """
        成交记录

        :return: dict, 其中每个元素的key为成交ID, value为 :py:class:`~tqsdk.objs.Trade`
        """
        tdict = _get_obj(self._api._data, ["trade", self._path[1], "trades"])
        fts = {trade_id: trade for trade_id, trade in tdict.items() if
               (not trade_id.startswith("_")) and trade.order_id == self.order_id}
        return fts


class Trade(Entity):
    """ Trade 是一个成交对象 """

    def __init__(self, api):
        self._api = api
        #: 委托单ID, 对于一个用户的所有委托单，这个ID都是不重复的
        self.order_id: str = ""
        #: 成交ID, 对于一个用户的所有成交，这个ID都是不重复的
        self.trade_id: str = ""
        #: 交易所成交编号
        self.exchange_trade_id: str = ""
        #: 交易所
        self.exchange_id: str = ""
        #: 交易所内的合约代码
        self.instrument_id: str = ""
        #: 下单方向, BUY=买, SELL=卖
        self.direction: str = ""
        #: 开平标志, OPEN=开仓, CLOSE=平仓, CLOSETODAY=平今
        self.offset: str = ""
        #: 成交价格
        self.price: float = float("nan")
        #: 成交手数
        self.volume: int = 0
        #: 成交时间，自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数
        self.trade_date_time: int = 0


class RiskManagementRule(Entity):

    def __init__(self, api):
        self._api = api
        self.user_id = ""
        self.exchange_id = ""
        self.enable = False
        self.self_trade = SelfTradeRule(self._api)
        self.frequent_cancellation = FrequentCancellationRule(self._api)
        self.trade_position_ratio = TradePositionRatioRule(self._api)

    def _instance_entity(self, path):
        super(RiskManagementRule, self)._instance_entity(path)
        self.self_trade = copy.copy(self.self_trade)
        self.self_trade._instance_entity(path + ["self_trade"])
        self.frequent_cancellation = copy.copy(self.frequent_cancellation)
        self.frequent_cancellation._instance_entity(path + ["frequent_cancellation"])
        self.trade_position_ratio = copy.copy(self.trade_position_ratio)
        self.trade_position_ratio._instance_entity(path + ["trade_position_ratio"])


class SelfTradeRule(Entity):
    """自成交风控规则"""

    def __init__(self, api):
        self._api = api
        #: 最大自成交次数限制
        self.count_limit = 0

    def __repr__(self):
        return json.dumps({"count_limit": self.count_limit})


class FrequentCancellationRule(Entity):
    """频繁报撤单风控规则"""

    def __init__(self, api):
        self._api = api
        #: 频繁报撤单起算报单次数
        self.insert_order_count_limit = 0
        #: 频繁报撤单起算撤单次数
        self.cancel_order_count_limit = 0
        #: 频繁报撤单撤单比例限额,为百分比
        self.cancel_order_percent_limit = float("nan")

    def __repr__(self):
        return json.dumps({
            "insert_order_count_limit": self.insert_order_count_limit,
            "cancel_order_count_limit": self.cancel_order_count_limit,
            "cancel_order_percent_limit": self.cancel_order_percent_limit
        })


class TradePositionRatioRule(Entity):
    """成交持仓比风控规则"""

    def __init__(self, api):
        self._api = api
        #: 成交持仓比起算成交手数
        self.trade_units_limit = 0
        #: 成交持仓比例限额,为百分比
        self.trade_position_ratio_limit = float("nan")

    def __repr__(self):
        return json.dumps({
            "trade_units_limit": self.trade_units_limit,
            "trade_position_ratio_limit": self.trade_position_ratio_limit
        })


class RiskManagementData(Entity):

    def __init__(self, api):
        self._api = api
        #: 用户ID
        self.user_id = ""
        #: 交易所ID
        self.exchange_id = ""
        #: 合约ID
        self.instrument_id = ""
        #: 自成交情况
        self.self_trade = SelfTrade(self._api)
        #: 频繁报撤单情况
        self.frequent_cancellation = FrequentCancellation(self._api)
        #: 成交持仓比情况
        self.trade_position_ratio = TradePositionRatio(self._api)

    def _instance_entity(self, path):
        super(RiskManagementData, self)._instance_entity(path)
        self.self_trade = copy.copy(self.self_trade)
        self.self_trade._instance_entity(path + ["self_trade"])
        self.frequent_cancellation = copy.copy(self.frequent_cancellation)
        self.frequent_cancellation._instance_entity(path + ["frequent_cancellation"])
        self.trade_position_ratio = copy.copy(self.trade_position_ratio)
        self.trade_position_ratio._instance_entity(path + ["trade_position_ratio"])


class SelfTrade(Entity):
    """自成交情况"""

    def __init__(self, api):
        self._api = api
        #: 当前最高买价
        self.highest_buy_price = float("nan")
        #: 当前最低卖价
        self.lowest_sell_price = float("nan")
        #: 当天已经发生的自成交次数
        self.self_trade_count = 0
        #: 当天由于自成交而被拒的报单次数
        self.rejected_count = 0

    def __repr__(self):
        return json.dumps({
            "highest_buy_price": self.highest_buy_price,
            "lowest_sell_price": self.lowest_sell_price,
            "self_trade_count": self.self_trade_count,
            "rejected_count": self.rejected_count
        })


class FrequentCancellation(Entity):
    """频繁报撤单情况"""

    def __init__(self, api):
        self._api = api
        #: 当天已经发生的报单次数
        self.insert_order_count = 0
        #: 当天已经发生的撤单次数
        self.cancel_order_count = 0
        #: 当天的撤单比例，为百分比
        self.cancel_order_percent = float("nan")
        #: 当天由于撤单比例超限而被拒的撤单次数
        self.rejected_count = 0

    def __repr__(self):
        return json.dumps({
            "insert_order_count": self.insert_order_count,
            "cancel_order_count": self.cancel_order_count,
            "cancel_order_percent": self.cancel_order_percent,
            "rejected_count": self.rejected_count
        })


class TradePositionRatio(Entity):
    """成交持仓比情况"""

    def __init__(self, api):
        self._api = api
        #: 当天已经发生的成交手数
        self.trade_units = 0
        #: 当前的净持仓手数, 正为多仓, 负为空仓
        self.net_position_units = 0
        #: 当前的成交持仓比, 为百分比
        self.trade_position_ratio = float("nan")
        #: 当天由于成交持仓比超限而被拒的报单次数
        self.rejected_count = 0

    def __repr__(self):
        return json.dumps({
            "trade_units": self.trade_units,
            "net_position_units": self.net_position_units,
            "trade_position_ratio": self.trade_position_ratio,
            "rejected_count": self.rejected_count
        })


class SecurityAccount(Entity):
    """ SecurityAccount 是一个股票账户对象"""

    def __init__(self, api):
        self._api = api
        #: 用户客户号
        self.user_id: str = ""
        #: 币种, CNY=人民币, USD=美元, HKD=港币
        self.currency: str = "CNY"
        #: 当前市值
        self.market_value: float = float("nan")
        #: 当前资产 = 当前市值 + 可用金额 + 委托冻结金额 + 委托冻结费用
        self.asset: float = float("nan")
        #: 期初资产
        self.asset_his: float = float("nan")
        #: 当前可用余额 = 期初可用 + 当日入金 - 当日出金 + 当日分红金额 - 当日买入金额 - 当日买入费用 + 当日卖出金额 - 当日卖出费用 - 委托冻结金额 - 委托冻结手续费
        self.available: float = float("nan")
        #: 期初可用余额
        self.available_his: float = float("nan")
        #: 当前买入成本
        self.cost: float = float("nan")
        #: 当前可取余额 = MAX(期初余额 + 当日入金 – 当日出金 + MIN(0，当日卖出释放资金 - 当日买入占用资金 - 委托冻结金额), 0)
        self.drawable: float = float("nan")
        #: 本交易日内累计入金金额
        self.deposit: float = float("nan")
        #: 本交易日内累计出金金额
        self.withdraw: float = float("nan")
        #: 当前交易冻结金额（不含费用）= sum(order.volume_orign * order.limit_price)
        self.buy_frozen_balance: float = float("nan")
        #: 当前交易冻结费用 = sum(order.frozen_fee)
        self.buy_frozen_fee: float = float("nan")
        #: 当日买入占用资金（不含费用）
        self.buy_balance_today: float = float("nan")
        #: 当日买入累计费用
        self.buy_fee_today: float = float("nan")
        #: 当日卖出释放资金
        self.sell_balance_today: float = float("nan")
        #: 当日卖出累计费用
        self.sell_fee_today: float = float("nan")
        #: 当日持仓盈亏 = 当前市值 - 当前买入成本
        self.hold_profit: float = float("nan")
        #: 当日浮动盈亏 = SUM(持仓当日浮动盈亏)
        self.float_profit_today: float = float("nan")
        #: 当日实现盈亏 = SUM(持仓当日实现盈亏)
        self.real_profit_today: float = float("nan")
        #: 当日盈亏 = 当日浮动盈亏 + 当日实现盈亏
        self.profit_today: float = float("nan")
        #: 当日盈亏比 = 当日盈亏 / (当前买入成本 if 当前买入成本 > 0 else 期初资产)
        self.profit_rate_today: float = float("nan")
        #: 当日分红金额
        self.dividend_balance_today: float = float("nan")


class SecurityPosition(Entity):
    """ SecurityPosition 是一个股票账户持仓对象 """

    def __init__(self, api):
        self._api = api
        #: 用户客户号
        self.user_id: str = ""
        #: 交易所
        self.exchange_id: str = ""
        #: 证券代码
        self.instrument_id: str = ""
        #: 建仓日期
        self.create_date: str = ""
        #: 当前成本 = 昨买入成本 + 今买金额 + 今买费用 - 今卖数量 × (昨买入成本 / 昨持仓数量)
        self.cost: float = float("nan")
        #: 期初成本
        self.cost_his: float = float("nan")
        #: 今持仓数量 = 昨持仓数量 + 今买数量 - 今卖数量 + 送股数量
        self.volume: int = 0
        #: 昨持仓数量
        self.volume_his: int = 0
        #: 最新价
        self.last_price: float = float("nan")
        #: 当日累计买入持仓
        self.buy_volume_today: int = 0
        #: 当日累计买入金额 (不包括费用)
        self.buy_balance_today: float = float("nan")
        #: 当日累计买入费用
        self.buy_fee_today: float = float("nan")
        #: 当日累计卖出持仓
        self.sell_volume_today: int = 0
        #: 当日累计卖出金额(不包括费用)
        self.sell_balance_today: float = float("nan")
        #: 当日累计卖出费用
        self.sell_fee_today: float = float("nan")
        #: 期初累计买入持仓
        self.buy_volume_his: int = 0
        #: 期初累计买入金额
        self.buy_balance_his: float = float("nan")
        #: 期初累计买入费用
        self.buy_fee_his: float = float("nan")
        #: 期初累计卖出持仓
        self.sell_volume_his: int = 0
        #: 期初累计卖出金额
        self.sell_balance_his: float = float("nan")
        #: 期初累计卖出费用
        self.sell_fee_his: float = float("nan")
        #: 今送股数量
        self.shared_volume_today: float = float("nan")
        #: 今分红金额
        self.devidend_balance_today: float = float("nan")
        #: 当前市值 = 持仓数量 × 行情最新价
        self.market_value: float = float("nan")
        #: 期初市值
        self.market_value_his: float = float("nan")
        #: 当日浮动盈亏 = (昨持仓数量 - 今卖数量) * (最新价 - 昨收盘价) + (今持仓数量 - (昨持仓数量 - 今卖数量)) * (最新价 - 买入均价)
        self.float_profit_today: float = float("nan")
        #: 当日实现盈亏 = 今卖数量 * (最新价 - 昨收盘价) - 今卖费用 + 今派息金额
        self.real_profit_today: float = float("nan")
        #: 期初实现盈亏
        self.real_profit_his: float = float("nan")
        #: 当日盈亏 = 当日浮动盈亏 + 当日实现盈亏
        self.profit_today: float = float("nan")
        #: 当日收益率
        self.profit_rate_today: float = float("nan")
        #: 当日持仓盈亏 = 当前持仓市值 – 当前买入成本
        self.hold_profit: float = float("nan")
        #: 累计实现盈亏 += 当日实现盈亏（成本）
        self.real_profit_total: float = float("nan")
        #: 总盈亏 = 累计实现盈亏 + 持仓盈亏
        self.profit_total: float = float("nan")
        #: 累计收益率 = 总盈亏  / (期初成本 if 当前成本==0 else 当前成本)
        self.profit_rate_total: float = float("nan")

    @property
    def orders(self):
        tdict = _get_obj(self._api._data, ["trade", self._path[1], "orders"])
        fts = {order_id: order for order_id, order in tdict.items() if (not order_id.startswith(
            "_")) and order.instrument_id == self.instrument_id and order.exchange_id == self.exchange_id and order.status == "ALIVE"}
        return fts


class SecurityOrder(Entity):
    """ SecurityOrder 是一个股票账户委托单对象 """

    def __init__(self, api):
        self._api = api
        #: 用户客户号
        self.user_id: str = ""
        #: 订单号,要求客户端保证其在一个交易日内的唯一性
        self.order_id: str = ""
        #: 交易所委托合同编号
        self.exchange_order_id: str = ""
        #: 交易所代码
        self.exchange_id: str = ""
        #: 证券代码
        self.instrument_id: str = ""
        #: 下单方向, BUY=买, SELL=卖
        self.direction: str = ""
        #: 委托股数（A 股委托数量必须为 100 倍数；科创板股票必须为 200 倍数；零股卖出: 由于部分成交或分红导致持仓数量小于 100 股时，该部分持仓可一次性卖出，数量不为 100 或 200 倍数）
        self.volume_orign: int = 0
        #: 剩余股数
        self.volume_left: int = 0
        #: 报单价格类型，LIMIT=限价单，ANY=市价单
        self.price_type: str = ""
        #: 报单委托价格
        self.limit_price: float = float("nan")
        #: 冻结费用
        self.frozen_fee: float = float("nan")
        #: 委托时间，自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数.
        self.insert_date_time: int = 0
        #: 委托单当前状态
        self.status: str = ""
        #: 委托单状态信息
        self.last_msg: str = ""

    @property
    def trade_records(self):
        """
        成交记录

        :return: dict, 其中每个元素的key为成交ID, value为 :py:class:`~tqsdk.objs.Trade`
        """
        tdict = _get_obj(self._api._data, ["trade", self._path[1], "trades"])
        fts = {trade_id: trade for trade_id, trade in tdict.items() if
               (not trade_id.startswith("_")) and trade.order_id == self.order_id}
        return fts


class SecurityTrade(Entity):
    """ SecurityTrade 是一个股票账户成交对象 """

    def __init__(self, api):
        self._api = api
        #: 用户客户号
        self.user_id: str = ""
        #: 成交编号
        self.trade_id: str = ""
        #: 交易所代码
        self.exchange_id: str = ""
        #: 证券代码
        self.instrument_id: str = ""
        #: 委托单编号
        self.order_id: str = ""
        #: 交易所订单编号
        self.exchange_order_id: str = ""
        #: 下单方向, BUY=买, SELL=卖，SHARED=送股，DEVIDEND=分红
        self.direction: str = ""
        #: 成交数量或者送股数量
        self.volume: int = 0
        #: 成交价格
        self.price: float = float("nan")
        #: 成交发生金额或分红金额
        self.balance: float = float("nan")
        #: 费用
        self.fee: float = float("nan")
        #: 成交时间，自unix epoch(1970-01-01 00:00:00 GMT)以来的纳秒数.
        self.trade_date_time: int = 0
