Administrator
2025-01-06 2036e22b728376ae33175346d54d6ae38154c9ca
新版本下单方式
11个文件已修改
268 ■■■■■ 已修改文件
api/outside_api_command_callback.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constant.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
huaxin_client/trade_client.py 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/huaxin/huaxin_delegate_postion_manager.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
l2/l2_data_manager_new.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third_data/code_plate_key_manager.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/buy_money_count_setting.py 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/huaxin/huaxin_trade_api.py 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/huaxin/huaxin_trade_record_manager.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/trade_huaxin.py 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
trade/trade_manager.py 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/outside_api_command_callback.py
@@ -1415,6 +1415,15 @@
                                   client_id,
                                   request_id)
            elif ctype == "test_place_order":
                # 获取相同板块的涨停代码数量
                code = data.get("code")
                total_datas = l2_data_util.local_today_datas.get(code)
                trade_manager.test_order(code, total_datas[-1], total_datas[-1]["index"])
                self.send_response({"code": 0, "data": {}},
                                   client_id,
                                   request_id)
        except Exception as e:
constant.py
@@ -223,3 +223,6 @@
RADICAL_BUY_TOP_IN_COUNT_BY_MARKET_STRONG = [(0, 60, 20), (60, 70, 25), (70, 80, 30), (80, 90, 35), (90, 101, 40)]
# 辨识度的票板块最低流入前几
RADICAL_BUY_TOP_IN_INDEX_WITH_SPECIAL = 20
# 是否为新版下单
IS_NEW_VERSION_PLACE_ORDER = True
huaxin_client/trade_client.py
@@ -223,6 +223,87 @@
        return ret
    # sinfo
    def buy_new(self, code, order_info_list):
        """
        批量下单
        @param code:
        @param order_info_list:[(量, 价, order_ref, sinfo)]
        @return:
        """
        if not ENABLE_ORDER:
            return
        async_log_util.info(logger_trade, f"{code}华鑫本地真实下单开始")
        async_log_util.info(logger_local_huaxin_trade_debug,
                            f"进入买入方法:code-{code} order_info_list-{order_info_list}")
        for order_info in order_info_list:
            count = order_info[0]
            price = order_info[1]
            order_ref = order_info[2]
            sinfo = order_info[3]
            if sinfo in self.__buy_sinfo_set:
                raise Exception(f'下单请求已经提交:{sinfo}')
            self.__buy_sinfo_set.add(sinfo)
            self.req_id += 1
            # 请求报单
            req_field = traderapi.CTORATstpInputOrderField()
            # TORA_TSTP_EXD_COMM(0): 通用(内部使用)
            # TORA_TSTP_EXD_SSE(1): 上海交易所
            # TORA_TSTP_EXD_SZSE(2): 深圳交易所
            # TORA_TSTP_EXD_HK(3): 香港交易所
            # TORA_TSTP_EXD_BSE(4): 北京证券交易所
            if tool.is_sz_code(code):
                req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE
                req_field.ShareholderID = SZSE_ShareHolderID
            elif tool.is_sh_code(code):
                req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE
                req_field.ShareholderID = SSE_ShareHolderID
            # 证券代码
            req_field.SecurityID = code
            req_field.Direction = traderapi.TORA_TSTP_D_Buy
            req_field.VolumeTotalOriginal = count
            req_field.SInfo = sinfo
            req_field.OrderRef = order_ref
            '''
            上交所支持限价指令和最优五档剩撤、最优五档剩转限两种市价指令,对于科创板额外支持本方最优和对手方最优两种市价指令和盘后固定价格申报指令
            深交所支持限价指令和立即成交剩余撤销、全额成交或撤销、本方最优、对手方最优和最优五档剩撤五种市价指令
            限价指令和上交所科创板盘后固定价格申报指令需填写报单价格,其它市价指令无需填写报单价格
            以下以上交所限价指令为例,其它指令参考开发指南相关说明填写OrderPriceType、TimeCondition和VolumeCondition三个字段:
            '''
            req_field.LimitPrice = price
            req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_LimitPrice
            req_field.TimeCondition = traderapi.TORA_TSTP_TC_GFD
            req_field.VolumeCondition = traderapi.TORA_TSTP_VC_AV
            '''
            OrderRef为报单引用,类型为整型,该字段报单时为选填
            若不填写,则系统会为每笔报单自动分配一个报单引用
            若填写,则需保证同一个TCP会话下报单引用严格单调递增,不要求连续递增,至少需从1开始编号
            '''
            # req_field.OrderRef = 1
            '''
            InvestorID为选填,若填写则需保证填写正确
            Operway为委托方式,根据券商要求填写,无特殊说明置空即可
            终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在报单回报和查询报单时返回给终端
            '''
            # req_field.SInfo = 'sinfo'
            # req_field.IInfo = 123
            '''
            其它字段置空
            '''
            ret = api.ReqOrderInsert(req_field, self.req_id)
            if ret != 0:
                raise Exception('ReqOrderInsert fail, ret[%d]' % ret)
        async_log_util.info(logger_trade, f"{code}华鑫本地真实下单结束")
    # 撤买
    def cancel_buy(self, code, sinfo, order_sys_id=None, order_ref=None, order_action_ref=None, delay_s=0.0):
        if delay_s > 0:
@@ -914,29 +995,45 @@
            # 1-买 2-卖
            direction = data["direction"]
            code = data["code"]
            sinfo = data["sinfo"]
            # 老版本下单
            volume = data["volume"]
            price = data["price"]
            sinfo = data["sinfo"]
            order_ref = data.get("order_ref")
            shadow_price = data.get("shadow_price")
            shadow_volume = data.get("shadow_volume")
            blocking = data.get("blocking")
            cancel_shadow = data.get("cancel_shadow")
            # 新版下单
            order_info_list = data.get("order_info_list")
            blocking = data.get("blocking")
            if cancel_shadow is None:
                cancel_shadow = True
            if shadow_volume is None:
                shadow_volume = constant.SHADOW_ORDER_VOLUME
            if direction == 1:
                async_log_util.info(logger_trade, f"{code}华鑫本地开始下单")
                # 买
                try:
                    if blocking:
                        if not order_info_list:
                        req_rid_dict[sinfo] = (client_id, request_id, sk, order_ref)
                    # threading.Thread(target=lambda: self.__tradeSimpleApi.buy(code, volume, price, sinfo, order_ref),
                    #                  daemon=True).start()
                    if not order_info_list:
                    self.trade_thread_pool.submit(self.__tradeSimpleApi.buy, code, volume, price, sinfo, order_ref,
                                                  shadow_price, cancel_shadow, shadow_volume)
                    else:
                        if order_info_list:
                            for i in range(len(order_info_list)):
                                order_info = order_info_list[i]
                                order_info_list[i] = (order_info[0], order_info[1], order_info[2], f"{sinfo}_{i}")
                        if blocking:
                            for x in order_info_list:
                                req_rid_dict[x[3]] = (client_id, request_id, sk, x[2])
                        self.trade_thread_pool.submit(self.__tradeSimpleApi.buy_new, code, order_info_list)
                    async_log_util.info(logger_trade, f"{code}华鑫本地下单线程结束")
                except Exception as e:
                    send_response(json.dumps({"code": 1, "msg": str(e)}), TYPE_ORDER, client_id,
@@ -1121,6 +1218,7 @@
        key = data["sinfo"]
    try:
        if req_rid_dict and key in req_rid_dict:
            # TODO 处理批量下单
            temp_params = req_rid_dict.pop(key)
            client_id, request_id = temp_params[0], temp_params[1]
            # 本地订单号-系统订单号映射
l2/huaxin/huaxin_delegate_postion_manager.py
@@ -224,7 +224,7 @@
        @param add_datas: 本批次数据
        @return:
        """
        order_info = get_order_info(code)
        order_info = cls.get_order_info(code)
        if not order_info:
            # 暂无下单信息
            return None, order_info, None
l2/l2_data_manager_new.py
@@ -473,9 +473,15 @@
                                    buy_open_limit_up_strategy.BuyOpenLimitupDataManager().remove_place_order_info(code)
                        # 获取下单位置
                        if constant.IS_NEW_VERSION_PLACE_ORDER:
                            place_order_index, order_info, compute_type = huaxin_delegate_postion_manager.RealDelegateOrderPositionManager.compute_l2_place_order_position(
                                code, add_datas)
                        else:
                        place_order_index, order_info, compute_type = huaxin_delegate_postion_manager.get_l2_place_order_position(
                            code, float(
                                gpcode_manager.get_limit_up_price(code)), add_datas)
                        if place_order_index:
                            order_begin_pos = cls.__get_order_begin_pos(
                                code)
third_data/code_plate_key_manager.py
@@ -429,7 +429,8 @@
                    strong = cls.get_market_strong()
                    if strong is None:
                        strong = 60
                    if data[3] > 3000e4:
                    if data[3] > 3e7:
                        # 大于3千万
                        THRESHOLD_MONEY = int((1 - strong / 200) * data[3])
                    else:
                        THRESHOLD_MONEY = data[3]
trade/buy_money_count_setting.py
@@ -243,6 +243,17 @@
        @return:
        """
        total_volume_unit_100 = tool.get_buy_volume_by_money(limit_up_price, money)//100
        return cls.get_possible_buy_volumes_by_total_volume(total_volume_unit_100*100)
    @classmethod
    def get_possible_buy_volumes_by_total_volume(cls, volume):
        """
        获取所有可能下单的量
        @param volume: 下单的股数
        @param limit_up_price: 涨停价
        @return:
        """
        total_volume_unit_100 = volume // 100
        if total_volume_unit_100 % 2 == 0:
            return 100 * (total_volume_unit_100 // 2 - 1), 100 * (total_volume_unit_100 // 2 + 1)
        else:
trade/huaxin/huaxin_trade_api.py
@@ -83,7 +83,8 @@
            need_cancel = TradeResultProcessor.process_buy_order(order)
            if need_cancel:
                # 需要撤买单
                threading.Thread(target=lambda:  cancel_order(TRADE_DIRECTION_SELL, order.code, order.orderSysID), daemon=True).start()
                threading.Thread(target=lambda: cancel_order(TRADE_DIRECTION_SELL, order.code, order.orderSysID),
                                 daemon=True).start()
            need_watch_cancel = TradeResultProcessor.process_sell_order(order)
            if need_watch_cancel:
                # 需要撤卖单
@@ -526,6 +527,45 @@
        huaxin_trade_data_update.add_money_list()
def order_new(direction, code, order_info_list, price_type=2, blocking=False, sinfo=None, request_id=None):
    """
    下单委托
    @param direction:
    @param code:
    @param order_info_list: 下单信息:[(量,价, order_ref),(量,价, order_ref)]
    @param price_type:
    @param blocking: 是否阻塞进程
    @param sinfo:
    @param request_id:
    @return:
    """
    timestamp = round(time.time() * 1000)
    if not sinfo:
        sinfo = f"b_{code}_{timestamp}"
    if not request_id:
        request_id = __get_request_id(ClientSocketManager.CLIENT_TYPE_TRADE)
    for i in range(1):
        request_id = __request(ClientSocketManager.CLIENT_TYPE_TRADE,
                               {"type": ClientSocketManager.CLIENT_TYPE_TRADE, "trade_type": 1,
                                "direction": direction,
                                "code": code,
                                "order_info_list": order_info_list,
                                "price_type": price_type,
                                "sinfo": sinfo,
                                "blocking": blocking,
                                "cancel_shadow": False},
                               request_id=request_id,
                               is_trade=True)
    try:
        if blocking:
            return __read_response(request_id, blocking)
        else:
            return {"order_ref_list": [x[2] for x in order_info_list]}
    finally:
        # huaxin_trade_data_update.add_delegate_list("下单", delay=0.2)
        huaxin_trade_data_update.add_money_list()
__canceling_order_dict = {}
trade/huaxin/huaxin_trade_record_manager.py
@@ -428,9 +428,12 @@
        # 添加订单ID
    def add_order_ref(self, code, order_ref):
        val = order_ref
        self.add_order_refs(code, [order_ref])
    def add_order_refs(self, code, order_ref_list):
        if code not in self.__huaxin_order_ref_cache:
            self.__huaxin_order_ref_cache[code] = set()
        for val in order_ref_list:
        self.__huaxin_order_ref_cache[code].add(val)
        RedisUtils.sadd_async(self.__db, f"huaxin_order_ref-{code}", val)
        RedisUtils.expire_async(self.__db, f"huaxin_order_ref-{code}", tool.get_expire())
trade/trade_huaxin.py
@@ -9,6 +9,7 @@
from l2.huaxin import huaxin_delegate_postion_manager
from log_module import async_log_util
from log_module.log import logger_juejin_trade, hx_logger_trade_debug, logger_trade
from trade.buy_money_count_setting import BuyMoneyUtil
from trade.huaxin import huaxin_trade_api
from trade.huaxin.huaxin_trade_record_manager import TradeOrderIdManager
from utils import tool, huaxin_util
@@ -84,6 +85,67 @@
        async_log_util.info(logger_trade, f"{code} trade_huaxin.order_volume 结束")
# 通过量下单,返回(代码,账号ID,订单号)
def order_volume_new(code, price, volume, last_data, exec_index=None):
    """
    新版下单:拆分为2个订单
    @param code:
    @param price:
    @param volume: 总股数
    @param last_data: 最后一条L2数据
    @param exec_index: 执行位
    @return:
    """
    async_log_util.info(logger_trade, f"{code} trade_huaxin.order_volume_new 开始")
    try:
        price = round(float(price), 2)
        if not tool.is_can_buy_code(code):
            raise Exception("只支持00开头与60开头的代码下单")
        # 拆单
        v1, v2 = BuyMoneyUtil.get_possible_buy_volumes_by_total_volume(volume)
        oredr_info_list = [(v1, price, huaxin_util.create_order_ref()), (v2, price, huaxin_util.create_order_ref())]
        huaxin.huaxin_delegate_postion_manager.RealDelegateOrderPositionManager.place_order(code, oredr_info_list,
                                                                                            exec_index, last_data)
        if not constant.TRADE_ENABLE:
            return
        result = None
        blocking = False
        try:
            async_log_util.info(logger_trade, f"{code}下单开始")
            result = huaxin_trade_api.order_new(1, code, oredr_info_list, blocking=blocking)
            async_log_util.info(logger_trade, f"{code}下单结束")
        except Exception as e:
            if str(e).find("超时") >= 0:
                # 此处出现超时,需要通过读取委托列表来设置订单信息
                async_log_util.error(hx_logger_trade_debug, f"{code}:下单结果反馈出错-{str(e)}")
            else:
                raise e
        if result:
            if blocking:
                if result['code'] == 0:
                    result = result["data"]
                    if result["orderStatus"] == huaxin_util.TORA_TSTP_OST_Rejected:
                        async_log_util.info(hx_logger_trade_debug, f"{code}:下单失败:{result.get('statusMsg')}")
                        raise Exception(result.get('statusMsg'))
                    else:
                        __TradeOrderIdManager.add_order_id(code, result["accountID"], result["orderSysID"])
                        async_log_util.info(hx_logger_trade_debug, f"{code}:下单成功 orderSysID:{result['orderSysID']}")
                        return result["securityId"], result["accountID"], result["orderSysID"]
                else:
                    raise Exception(result['msg'])
            else:
                order_ref_list = result["order_ref_list"]
                __TradeOrderIdManager.add_order_refs(code, order_ref_list)
                async_log_util.info(hx_logger_trade_debug, f"{code}:下单成功 orderRefs:{order_ref_list}")
                return code, "local", order_ref_list
        else:
            raise Exception("下单失败,无返回")
    finally:
        async_log_util.info(logger_trade, f"{code} trade_huaxin.order_volume_new 结束")
def order_success(code, accountId, orderSysID, orderRef, insertTime):
    # 加入系统订单号
    __TradeOrderIdManager.add_order_id(code, accountId, orderSysID)
trade/trade_manager.py
@@ -406,6 +406,18 @@
        async_log_util.info(logger_trade, "{} trade.manager.start_buy 结束".format(code))
def test_order(code, last_data, exec_index):
    """
    TODO 测试下单
    @param code:
    @param last_data:
    @param exec_index:
    @return:
    """
    price = gpcode_manager.get_limit_up_price(code)
    __buy(code, price, trade_constant.TRADE_STATE_NOT_TRADE, 0, last_data, last_data["index"],  0, exec_index=exec_index)
# 中断买入
def break_buy(code, reason):
    trade_data_manager.TradeBuyDataManager().remove_buy_position_info(code)
@@ -417,7 +429,11 @@
    async_log_util.info(logger_trade, "{} trade_manager.__buy 开始".format(code))
    try:
        if constant.API_TRADE_ENABLE:
            can_buy, money, msg = BuyMoneyUtil.get_buy_data(tool.get_now_time_str(), mode, DealAndDelegateWithBuyModeDataManager().get_deal_codes_info(mode), DealAndDelegateWithBuyModeDataManager().get_delegates_codes_info(mode))
            can_buy, money, msg = BuyMoneyUtil.get_buy_data(tool.get_now_time_str(), mode,
                                                            DealAndDelegateWithBuyModeDataManager().get_deal_codes_info(
                                                                mode),
                                                            DealAndDelegateWithBuyModeDataManager().get_delegates_codes_info(
                                                                mode))
            if not can_buy:
                raise Exception(msg)
            count = tool.get_buy_volume_by_money(price, money)
@@ -428,6 +444,9 @@
            if constant.TRADE_WAY == constant.TRADE_WAY_JUEJIN:
                trade_juejin.order_volume(code, price, count)
            elif constant.TRADE_WAY == constant.TRADE_WAY_HUAXIN:
                if constant.IS_NEW_VERSION_PLACE_ORDER:
                    trade_huaxin.order_volume_new(code, price, count, last_data, exec_index=exec_index)
                else:
                order_ref = huaxin_util.create_order_ref()
                TradeOrderIdManager().add_order_ref(code, order_ref)
                trade_huaxin.order_volume(code, price, count, last_data, order_ref=order_ref, exec_index=exec_index)