| | |
| | | """ |
| | | import constant |
| | | constant.LOG_DIR = "logs_cb" |
| | | from huaxin_client import l2_client_for_cb |
| | | from huaxin_client.cb import l2_client_for_cb |
| | | from utils import middle_api_protocol |
| | | |
| | | if __name__ == '__main__': |
New file |
| | |
| | | #!/usr/bin/python3 |
| | | # -*- coding: UTF-8 -*- |
| | | |
| | | import traderapi |
| | | |
| | | ''' 注意: 如果提示找不到_tradeapi 且与已发布的库文件不一致时,可自行重命名为_tradeapi.so (windows下为_tradeapi.pyd)''' |
| | | |
| | | # 投资者账户 |
| | | InvestorID = "00032047" |
| | | ''' |
| | | 该默认账号为共用连通测试使用,自有测试账号请到n-sight.com.cn注册并从个人中心获取交易编码,不是网站登录密码,不是手机号 |
| | | 实盘交易时,取客户号,请注意不是资金账号或咨询技术支持 |
| | | ''' |
| | | |
| | | # 操作员账户 |
| | | UserID = "00032047" # 同客户号保持一致即可 |
| | | |
| | | # 资金账户 |
| | | AccountID = "00032047" # 以Req(TradingAccount)查询的为准 |
| | | |
| | | # 登陆密码 |
| | | Password = "59009218" # N视界注册模拟账号的交易密码,不是登录密码 |
| | | |
| | | DepartmentID = "0003" # 生产环境默认客户号的前4位 |
| | | |
| | | SSE_ShareHolderID = 'A00032047' # 不同账号的股东代码需要接口ReqQryShareholderAccount去查询 |
| | | SZ_ShareHolderID = '700032047' # 不同账号的股东代码需要接口ReqQryShareholderAccount去查询 |
| | | |
| | | |
| | | class TraderSpi(traderapi.CTORATstpTraderSpi): |
| | | def __init__(self, api): |
| | | traderapi.CTORATstpTraderSpi.__init__(self) |
| | | self.__api = api |
| | | self.__req_id = 0 |
| | | self.__front_id = 0 |
| | | self.__session_id = 0 |
| | | |
| | | def OnFrontConnected(self) -> "void": |
| | | print('OnFrontConnected') |
| | | |
| | | # 获取终端信息 |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqGetConnectionInfo(self.__req_id) |
| | | if ret != 0: |
| | | print('ReqGetConnectionInfo fail, ret[%d]' % ret) |
| | | |
| | | def OnFrontDisconnected(self, nReason: "int") -> "void": |
| | | print('OnFrontDisconnected: [%d]' % nReason) |
| | | |
| | | def OnRspGetConnectionInfo(self, pConnectionInfoField: "CTORATstpConnectionInfoField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('inner_ip_address[%s]' % pConnectionInfoField.InnerIPAddress) |
| | | print('inner_port[%d]' % pConnectionInfoField.InnerPort) |
| | | print('outer_ip_address[%s]' % pConnectionInfoField.OuterIPAddress) |
| | | print('outer_port[%d]' % pConnectionInfoField.OuterPort) |
| | | print('mac_address[%s]' % pConnectionInfoField.MacAddress) |
| | | |
| | | # 请求登录 |
| | | login_req = traderapi.CTORATstpReqUserLoginField() |
| | | |
| | | # 支持以用户代码、资金账号和股东账号方式登录 |
| | | # (1)以用户代码方式登录 |
| | | login_req.LogInAccount = UserID |
| | | login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_UserID |
| | | # (2)以资金账号方式登录 |
| | | # login_req.DepartmentID = DepartmentID |
| | | # login_req.LogInAccount = AccountID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_AccountID |
| | | # (3)以上海股东账号方式登录 |
| | | # login_req.LogInAccount = SSE_ShareHolderID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SHAStock |
| | | # (4)以深圳股东账号方式登录 |
| | | # login_req.LogInAccount = SZSE_ShareHolderID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SZAStock |
| | | |
| | | # 支持以密码和指纹(移动设备)方式认证 |
| | | # (1)密码认证 |
| | | # 密码认证时AuthMode可不填 |
| | | # login_req.AuthMode = traderapi.TORA_TSTP_AM_Password |
| | | login_req.Password = Password |
| | | # (2)指纹认证 |
| | | # 非密码认证时AuthMode必填 |
| | | # login_req.AuthMode = traderapi.TORA_TSTP_AM_FingerPrint |
| | | # login_req.DeviceID = '03873902' |
| | | # login_req.CertSerial = '9FAC09383D3920CAEFF039' |
| | | |
| | | # 终端信息采集 |
| | | # UserProductInfo填写终端名称 |
| | | login_req.UserProductInfo = 'pyapidemo' |
| | | # 按照监管要求填写终端信息 |
| | | login_req.TerminalInfo = 'PC;IIP=000.000.000.000;IPORT=00000;LIP=x.xx.xxx.xxx;MAC=123ABC456DEF;HD=XXXXXXXXXX' |
| | | # 以下内外网IP地址若不填则柜台系统自动采集,若填写则以终端填值为准报送 |
| | | # login_req.MacAddress = '5C-87-9C-96-F3-E3' |
| | | # login_req.InnerIPAddress = '10.0.1.102' |
| | | # login_req.OuterIPAddress = '58.246.43.50' |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqUserLogin(login_req, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqUserLogin fail, ret[%d]' % ret) |
| | | |
| | | else: |
| | | print('GetConnectionInfo fail, [%d] [%d] [%s]!!!' % ( |
| | | nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspUserLogin(self, pRspUserLoginField: "traderapi.CTORATstpRspUserLoginField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('Login success! [%d]' % nRequestID) |
| | | |
| | | self.__front_id = pRspUserLoginField.FrontID |
| | | self.__session_id = pRspUserLoginField.SessionID |
| | | |
| | | if 0: |
| | | # 修改密码 |
| | | req_field = traderapi.CTORATstpUserPasswordUpdateField() |
| | | req_field.UserID = UserID |
| | | req_field.OldPassword = Password |
| | | req_field.NewPassword = '123456' |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqUserPasswordUpdate(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqUserPasswordUpdate fail, ret[%d]' % ret) |
| | | return |
| | | |
| | | if 0: |
| | | # 查询合约 |
| | | req_field = traderapi.CTORATstpQrySecurityField() |
| | | |
| | | # 以下字段不填表示不设过滤条件,即查询全部合约 |
| | | # req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | # req_field.SecurityID = '600000' |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqQrySecurity(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqQrySecurity fail, ret[%d]' % ret) |
| | | |
| | | if 1: |
| | | # 查询投资者 |
| | | req_field = traderapi.CTORATstpQryInvestorField() |
| | | |
| | | # 以下字段不填表示不设过滤条件 |
| | | # req_field.InvestorID = InvestorID |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqQryInvestor(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqQryInvestor fail, ret[%d]' % ret) |
| | | |
| | | if 1: |
| | | # 查询股东账号 |
| | | req_field = traderapi.CTORATstpQryShareholderAccountField() |
| | | |
| | | # 以下字段不填表示不设过滤条件,即查询所有股东账号 |
| | | # req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqQryShareholderAccount(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqQryShareholderAccount fail, ret[%d]' % ret) |
| | | |
| | | if 1: |
| | | # 查询资金账号 |
| | | req_field = traderapi.CTORATstpQryTradingAccountField() |
| | | |
| | | # 以下字段不填表示不设过滤条件,即查询所有资金账号 |
| | | req_field.InvestorID = InvestorID |
| | | req_field.DepartmentID = DepartmentID |
| | | req_field.AccountID = AccountID |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqQryTradingAccount(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqQryTradingAccount fail, ret[%d]' % ret) |
| | | |
| | | if 1: |
| | | # 查询报单 |
| | | req_field = traderapi.CTORATstpQryOrderField() |
| | | |
| | | # 以下字段不填表示不设过滤条件,即查询所有报单 |
| | | # req_field.SecurityID = '600000' |
| | | # req_field.InsertTimeStart = '09:35:00' |
| | | # req_field.InsertTimeEnd = '10:00:00' |
| | | |
| | | # IsCancel字段填1表示只查询可撤报单 |
| | | # req_field.IsCancel = 1 |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqQryOrder(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqQryOrder fail, ret[%d]' % ret) |
| | | |
| | | if 1: |
| | | # 查询持仓 |
| | | req_field = traderapi.CTORATstpQryPositionField() |
| | | |
| | | # 以下字段不填表示不设过滤条件,即查询所有持仓 |
| | | # req_field.SecurityID = '600000' |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqQryPosition(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqQryPosition fail, ret[%d]' % ret) |
| | | |
| | | if 0: |
| | | # 请求报单 |
| | | req_field = traderapi.CTORATstpInputOrderField() |
| | | |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | req_field.ShareholderID = SSE_ShareHolderID |
| | | req_field.SecurityID = '600000' |
| | | req_field.Direction = traderapi.TORA_TSTP_D_Buy |
| | | req_field.VolumeTotalOriginal = 100 |
| | | |
| | | ''' |
| | | 上交所支持限价指令和最优五档剩撤、最优五档剩转限两种市价指令,对于科创板额外支持本方最优和对手方最优两种市价指令和盘后固定价格申报指令 |
| | | 深交所支持限价指令和立即成交剩余撤销、全额成交或撤销、本方最优、对手方最优和最优五档剩撤五种市价指令 |
| | | 限价指令和上交所科创板盘后固定价格申报指令需填写报单价格,其它市价指令无需填写报单价格 |
| | | 以下以上交所限价指令为例,其它指令参考开发指南相关说明填写OrderPriceType、TimeCondition和VolumeCondition三个字段: |
| | | ''' |
| | | req_field.LimitPrice = 7.29 |
| | | 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 |
| | | |
| | | ''' |
| | | 其它字段置空 |
| | | ''' |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqOrderInsert(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqOrderInsert fail, ret[%d]' % ret) |
| | | |
| | | if 0: |
| | | # 请求撤单 |
| | | req_field = traderapi.CTORATstpInputOrderActionField() |
| | | |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | req_field.ActionFlag = traderapi.TORA_TSTP_AF_Delete |
| | | |
| | | # 撤单支持以下两种方式定位原始报单: |
| | | # (1)报单引用方式 |
| | | # req_field.FrontID = self.__front_id |
| | | # req_field.SessionID = self.__session_id |
| | | # req_field.OrderRef = 1 |
| | | # (2)系统报单编号方式 |
| | | req_field.OrderSysID = '110019400000005' |
| | | |
| | | # OrderActionRef报单操作引用,用法同报单引用,可根据需要选填 |
| | | |
| | | ''' |
| | | 终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在查询撤单时返回给终端 |
| | | ''' |
| | | # req_field.SInfo = 'sinfo' |
| | | # req_field.IInfo = 123 |
| | | |
| | | ''' |
| | | 委托方式字段根据券商要求填写,无特殊说明置空即可 |
| | | 其它字段置空 |
| | | ''' |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqOrderAction(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqOrderAction fail, ret[%d]' % ret) |
| | | |
| | | if 0: |
| | | # 查询集中交易资金 |
| | | req_field = traderapi.CTORATstpReqInquiryJZFundField() |
| | | |
| | | req_field.DepartmentID = DepartmentID |
| | | req_field.AccountID = AccountID |
| | | req_field.CurrencyID = traderapi.TORA_TSTP_CID_CNY |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqInquiryJZFund(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqInquiryJZFund fail, ret[%d]' % ret) |
| | | |
| | | if 0: |
| | | # 资金转移(包括资金调拨和银证转账) |
| | | req_field = traderapi.CTORATstpInputTransferFundField() |
| | | |
| | | req_field.DepartmentID = DepartmentID |
| | | req_field.AccountID = AccountID |
| | | req_field.CurrencyID = traderapi.TORA_TSTP_CID_CNY |
| | | req_field.Amount = 100000.0 |
| | | |
| | | ''' |
| | | 转移方向: |
| | | TORA_TSTP_TRNSD_MoveIn表示资金从集中交易柜台调拨至快速交易柜台 |
| | | TORA_TSTP_TRNSD_MoveOut表示资金从快速交易柜台调拨至集中交易柜台 |
| | | TORA_TSTP_TRNSD_StockToBank表示证券快速交易系统资金转入银行,即出金 |
| | | TORA_TSTP_TRNSD_BankToStock表示银行资金转入证券快速交易系统,即入金 |
| | | 以下说明各场景下字段填值: |
| | | ''' |
| | | # (1)资金从集中交易柜台调拨至快速交易柜台 |
| | | req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_MoveIn |
| | | # (2)资金从快速交易柜台调拨至集中交易柜台 |
| | | # req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_MoveOut |
| | | # (3)证券快速交易系统资金转入银行,需填写银行代码和资金密码 |
| | | # req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_StockToBank |
| | | # req_field.BankID = traderapi.TORA_TSTP_BKID_CCB |
| | | # req_field.AccountPassword = '123456' |
| | | # (4)银行资金转入证券快速交易系统,需填写银行代码和银行卡密码 |
| | | # req_field.TransferDirection = traderapi.TORA_TSTP_TRNSD_BankToStock |
| | | # req_field.BankID = traderapi.TORA_TSTP_BKID_CCB |
| | | # req_field.BankPassword = '123456' |
| | | |
| | | ''' |
| | | 申请流水号ApplySerial字段为选填字段 |
| | | 若不填写则柜台系统会自动生成一个申请流水号 |
| | | 若填写则需保证同一个TCP会话下申请流水号不重复 |
| | | ''' |
| | | # req_field.ApplySerial = 1 |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqTransferFund(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqTransferFund fail, ret[%d]', ret) |
| | | |
| | | if 0: |
| | | '''登出,目前登出成功连接会立即被柜台系统断开,终端不会收到OnRspUserLogout应答 |
| | | 连接断开后接口内部会触发重新连接,为不使连接成功后又触发重新登录,需终端做好逻辑控制 |
| | | 一般情况下若希望登出,直接调用Release接口即可,释放成功连接将被终端强制关闭,Release接口调用注意事项见下文说明 |
| | | ''' |
| | | req_field = traderapi.CTORATstpUserLogoutField() |
| | | |
| | | self.__req_id += 1 |
| | | ret = self.__api.ReqUserLogout(req_field, self.__req_id) |
| | | if ret != 0: |
| | | print('ReqUserLogout fail, ret[%d]' % ret) |
| | | else: |
| | | print('Login fail!!! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | return |
| | | |
| | | def OnRspUserPasswordUpdate(self, pUserPasswordUpdateField: "CTORATstpUserPasswordUpdateField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('OnRspUserPasswordUpdate: OK! [%d]' % nRequestID) |
| | | else: |
| | | print('OnRspUserPasswordUpdate: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspOrderInsert(self, pInputOrderField: "CTORATstpInputOrderField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('OnRspOrderInsert: OK! [%d]' % nRequestID) |
| | | else: |
| | | print('OnRspOrderInsert: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspOrderAction(self, pInputOrderActionField: "CTORATstpInputOrderActionField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('OnRspOrderAction: OK! [%d]' % nRequestID) |
| | | else: |
| | | print('OnRspOrderAction: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspInquiryJZFund(self, pRspInquiryJZFundField: "CTORATstpRspInquiryJZFundField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('OnRspInquiryJZFund: OK! [%d] [%.2f] [%.2f]' |
| | | % (nRequestID, pRspInquiryJZFundField.UsefulMoney, pRspInquiryJZFundField.FetchLimit)) |
| | | else: |
| | | print('OnRspInquiryJZFund: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspTransferFund(self, pInputTransferFundField: "CTORATstpInputTransferFundField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | print('OnRspTransferFund: OK! [%d]' % nRequestID) |
| | | else: |
| | | print('OnRspTransferFund: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRtnOrder(self, pOrderField: "CTORATstpOrderField") -> "void": |
| | | print( |
| | | 'OnRtnOrder: InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] LimitPrice[%.2f] VolumeTotalOriginal[%d] OrderSysID[%s] OrderStatus[%s]' |
| | | % (pOrderField.InvestorID, pOrderField.SecurityID, pOrderField.OrderRef, pOrderField.OrderLocalID, |
| | | pOrderField.LimitPrice, pOrderField.VolumeTotalOriginal, pOrderField.OrderSysID, |
| | | pOrderField.OrderStatus)) |
| | | |
| | | def OnRtnTrade(self, pTradeField: "CTORATstpTradeField") -> "void": |
| | | print( |
| | | 'OnRtnTrade: TradeID[%s] InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] Price[%.2f] Volume[%d]' |
| | | % (pTradeField.TradeID, pTradeField.InvestorID, pTradeField.SecurityID, |
| | | pTradeField.OrderRef, pTradeField.OrderLocalID, pTradeField.Price, pTradeField.Volume)) |
| | | |
| | | def OnRtnMarketStatus(self, pMarketStatusField: "CTORATstpMarketStatusField") -> "void": |
| | | print('OnRtnMarketStatus: MarketID[%s] MarketStatus[%s]' |
| | | % (pMarketStatusField.MarketID, pMarketStatusField.MarketStatus)) |
| | | |
| | | def OnRspQrySecurity(self, pSecurityField: "CTORATstpSecurityField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | print( |
| | | 'OnRspQrySecurity[%d]: SecurityID[%s] SecurityName[%s] MarketID[%s] OrderUnit[%s] OpenDate[%s] UpperLimitPrice[%.2f] LowerLimitPrice[%.2f]' |
| | | % (nRequestID, pSecurityField.SecurityID, pSecurityField.SecurityName, pSecurityField.MarketID, |
| | | pSecurityField.OrderUnit, pSecurityField.OpenDate, pSecurityField.UpperLimitPrice, |
| | | pSecurityField.LowerLimitPrice)) |
| | | else: |
| | | print('查询合约结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryInvestor(self, pInvestorField: "CTORATstpInvestorField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | print('OnRspQryInvestor[%d]: InvestorID[%s] Operways[%s]' |
| | | % (nRequestID, pInvestorField.InvestorID, |
| | | pInvestorField.Operways)) |
| | | else: |
| | | print('查询投资者结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryShareholderAccount(self, pShareholderAccountField: "CTORATstpShareholderAccountField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int", |
| | | bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | print('OnRspQryShareholderAccount[%d]: InvestorID[%s] ExchangeID[%s] ShareholderID[%s]' |
| | | % (nRequestID, pShareholderAccountField.InvestorID, pShareholderAccountField.ExchangeID, |
| | | pShareholderAccountField.ShareholderID)) |
| | | else: |
| | | print('查询股东账户结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryTradingAccount(self, pTradingAccountField: "CTORATstpTradingAccountField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | print( |
| | | 'OnRspQryTradingAccount[%d]: DepartmentID[%s] InvestorID[%s] AccountID[%s] CurrencyID[%s] UsefulMoney[%.2f] FetchLimit[%.2f]' |
| | | % (nRequestID, pTradingAccountField.DepartmentID, pTradingAccountField.InvestorID, |
| | | pTradingAccountField.AccountID, pTradingAccountField.CurrencyID, |
| | | pTradingAccountField.UsefulMoney, pTradingAccountField.FetchLimit)) |
| | | else: |
| | | print('查询资金账号结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryOrder(self, pOrderField: "CTORATstpOrderField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | print( |
| | | 'OnRspQryOrder[%d]: SecurityID[%s] OrderLocalID[%s] OrderRef[%d] OrderSysID[%s] VolumeTraded[%d] OrderStatus[%s] OrderSubmitStatus[%s], StatusMsg[%s]' |
| | | % (nRequestID, pOrderField.SecurityID, pOrderField.OrderLocalID, pOrderField.OrderRef, |
| | | pOrderField.OrderSysID, |
| | | pOrderField.VolumeTraded, pOrderField.OrderStatus, pOrderField.OrderSubmitStatus, |
| | | pOrderField.StatusMsg)) |
| | | else: |
| | | print('查询报单结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryPosition(self, pPositionField: "CTORATstpPositionField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | print('OnRspQryPosition[%d]: InvestorID[%s] SecurityID[%s] HistoryPos[%d] TodayBSPos[%d] TodayPRPos[%d]' |
| | | % (nRequestID, pPositionField.InvestorID, pPositionField.SecurityID, pPositionField.HistoryPos, |
| | | pPositionField.TodayBSPos, pPositionField.TodayPRPos)) |
| | | else: |
| | | print('查询持仓结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | # 打印接口版本号 |
| | | print("TradeAPI Version:::" + traderapi.CTORATstpTraderApi_GetApiVersion()) |
| | | |
| | | # 创建接口对象 |
| | | # pszFlowPath为私有流和公有流文件存储路径,若订阅私有流和公有流且创建多个接口实例,每个接口实例应配置不同的路径 |
| | | # bEncrypt为网络数据是否加密传输,考虑数据安全性,建议以互联网方式接入的终端设置为加密传输 |
| | | api = traderapi.CTORATstpTraderApi.CreateTstpTraderApi('./flow', False) |
| | | |
| | | # 创建回调对象 |
| | | spi = TraderSpi(api) |
| | | |
| | | # 注册回调接口 |
| | | api.RegisterSpi(spi) |
| | | |
| | | if 1: # 模拟环境,TCP 直连Front方式 |
| | | # 注册单个交易前置服务地址 |
| | | TD_TCP_FrontAddress = "tcp://210.14.72.21:4400" # 仿真交易环境 |
| | | # TD_TCP_FrontAddress="tcp://210.14.72.15:4400" #24小时环境A套 |
| | | # TD_TCP_FrontAddress="tcp://210.14.72.16:9500" #24小时环境B套 |
| | | api.RegisterFront(TD_TCP_FrontAddress) |
| | | # 注册多个交易前置服务地址,用逗号隔开 形如: api.RegisterFront("tcp://10.0.1.101:6500,tcp://10.0.1.101:26500") |
| | | print("TD_TCP_FensAddress[sim or 24H]::%s\n" % TD_TCP_FrontAddress) |
| | | |
| | | else: # 模拟环境,FENS名字服务器方式 |
| | | TD_TCP_FensAddress = "tcp://210.14.72.21:42370"; # 模拟环境通用fens地址 |
| | | '''******************************************************************************** |
| | | * 注册 fens 地址前还需注册 fens 用户信息,包括环境编号、节点编号、Fens 用户代码等信息 |
| | | * 使用名字服务器的好处是当券商系统部署方式发生调整时外围终端无需做任何前置地址修改 |
| | | * *****************************************************************************''' |
| | | fens_user_info_field = traderapi.CTORATstpFensUserInfoField() |
| | | fens_user_info_field.FensEnvID = "stock" # 必填项,暂时固定为“stock”表示普通现货柜台 |
| | | fens_user_info_field.FensNodeID = "sim" # 必填项,生产环境需按实际填写,仿真环境为sim |
| | | fens_user_info_field.FensNodeID, = "24a" # 必填项,生产环境需按实际填写,24小时A套环境为24a |
| | | # fens_user_info_field.FensNodeID="24b" #必填项,生产环境需按实际填写,24小时B套环境为24b |
| | | api.RegisterFensUserInfo(fens_user_info_field) |
| | | api.RegisterNameServer(TD_TCP_FensAddress) |
| | | # 注册名字服务器地址,支持多服务地址逗号隔开 形如:api.RegisterNameServer('tcp://10.0.1.101:52370,tcp://10.0.1.101:62370') |
| | | print("TD_TCP_FensAddress[%s]::%s\n" % (fens_user_info_field.FensNodeID, TD_TCP_FensAddress)) |
| | | |
| | | # 订阅私有流 |
| | | api.SubscribePrivateTopic(traderapi.TORA_TERT_QUICK) |
| | | # 订阅公有流 |
| | | api.SubscribePublicTopic(traderapi.TORA_TERT_QUICK) |
| | | '''********************************** |
| | | * TORA_TERT_RESTART, 从日初开始 |
| | | * TORA_TERT_RESUME, 从断开时候开始 |
| | | * TORA_TERT_QUICK, 从最新时刻开始 |
| | | *************************************''' |
| | | # 启动接口 |
| | | api.Init() |
| | | |
| | | # 等待程序结束 |
| | | input() |
| | | |
| | | # 释放接口对象 |
| | | api.Release() |
New file |
| | |
| | | # -*- coding: utf-8 -*- |
| | | import concurrent.futures |
| | | import time |
| | | |
| | | from huaxin_client import constant |
| | | import traderapi |
| | | from huaxin_client.cb import trade_manager |
| | | from huaxin_client.cb.trade_manager import TradeSimpleApi |
| | | |
| | | # 正式账号 |
| | | from huaxin_client.command_manager import TradeCommandManager |
| | | from log_module import async_log_util |
| | | from log_module.log import logger_local_huaxin_trade_debug as logger, logger_system, logger_local_huaxin_trade_debug, logger_info |
| | | |
| | | TEST_TRADE = True |
| | | |
| | | ########B类######## |
| | | UserID = '388000013349' |
| | | # 登陆密码 |
| | | Password = '110808' |
| | | # 投资者账户 |
| | | InvestorID = '388000013349' |
| | | # 经济公司部门代码 |
| | | DepartmentID = '0003' |
| | | # 资金账户 |
| | | AccountID = '388000013349' |
| | | # 沪市股东账号 |
| | | SSE_ShareHolderID = 'A641420991' |
| | | # 深市股东账号 |
| | | SZSE_ShareHolderID = '0345104949' |
| | | |
| | | LOCAL_IP = constant.LOCAL_IP |
| | | FRONT_ADDRESS = "tcp://192.168.84.31:6500" |
| | | FRONT_ADDRESS1 = "tcp://192.168.84.32:26500" |
| | | |
| | | if TEST_TRADE: |
| | | # # 仿真 |
| | | # from mylog import logger_trade_debug |
| | | # |
| | | UserID = '00032047' |
| | | # 登陆密码 |
| | | Password = '59009218' |
| | | # 投资者账户 |
| | | InvestorID = '00032047' |
| | | # 经济公司部门代码 |
| | | DepartmentID = '0003' |
| | | # 资金账户 |
| | | AccountID = '00032047' |
| | | # 沪市股东账号 |
| | | SSE_ShareHolderID = 'A00032047' |
| | | # 深市股东账号 |
| | | SZSE_ShareHolderID = '700032047' |
| | | |
| | | |
| | | class TraderSpi(traderapi.CTORATstpTraderSpi): |
| | | def __init__(self, api, callback): |
| | | traderapi.CTORATstpTraderSpi.__init__(self) |
| | | self.__api= api |
| | | self.__front_id = 0 |
| | | self.__session_id = 0 |
| | | self.__data_callback = callback |
| | | self.__temp_order_list_dict = {} |
| | | self.__temp_position_list_dict = {} |
| | | self.__temp_money_account_list_dict = {} |
| | | self.call_back_thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=10) |
| | | |
| | | def OnFrontConnected(self) -> "void": |
| | | logger_info.debug('Trader OnFrontConnected') |
| | | |
| | | # 获取终端信息 |
| | | TradeSimpleApi.req_id += 1 |
| | | |
| | | ret = self.__api.ReqGetConnectionInfo(TradeSimpleApi.req_id) |
| | | if ret != 0: |
| | | logger_info.info('ReqGetConnectionInfo fail, ret[%d]' % ret) |
| | | |
| | | def OnFrontDisconnected(self, nReason: "int") -> "void": |
| | | logger_info.info('OnFrontDisconnected: [%d]' % nReason) |
| | | |
| | | def OnRspGetConnectionInfo(self, pConnectionInfoField: "CTORATstpConnectionInfoField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | logger.info('inner_ip_address[%s]' % pConnectionInfoField.InnerIPAddress) |
| | | logger.info('inner_port[%d]' % pConnectionInfoField.InnerPort) |
| | | logger.info('outer_ip_address[%s]' % pConnectionInfoField.OuterIPAddress) |
| | | logger.info('outer_port[%d]' % pConnectionInfoField.OuterPort) |
| | | logger.info('mac_address[%s]' % pConnectionInfoField.MacAddress) |
| | | |
| | | # 请求登录 |
| | | login_req = traderapi.CTORATstpReqUserLoginField() |
| | | |
| | | # 支持以用户代码、资金账号和股东账号方式登录 |
| | | # (1)以用户代码方式登录 |
| | | login_req.LogInAccount = UserID |
| | | login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_UserID |
| | | # (2)以资金账号方式登录 |
| | | # login_req.DepartmentID = DepartmentID |
| | | # login_req.LogInAccount = AccountID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_AccountID |
| | | # (3)以上海股东账号方式登录 |
| | | # login_req.LogInAccount = SSE_ShareHolderID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SHAStock |
| | | # (4)以深圳股东账号方式登录 |
| | | # login_req.LogInAccount = SZSE_ShareHolderID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SZAStock |
| | | |
| | | # 支持以密码和指纹(移动设备)方式认证 |
| | | # (1)密码认证 |
| | | # 密码认证时AuthMode可不填 |
| | | # login_req.AuthMode = traderapi.TORA_TSTP_AM_Password |
| | | login_req.Password = Password |
| | | # (2)指纹认证 |
| | | # 非密码认证时AuthMode必填 |
| | | # login_req.AuthMode = traderapi.TORA_TSTP_AM_FingerPrint |
| | | # login_req.DeviceID = '03873902' |
| | | # login_req.CertSerial = '9FAC09383D3920CAEFF039' |
| | | |
| | | # 终端信息采集 |
| | | # UserProductInfo填写终端名称 |
| | | login_req.UserProductInfo = 'jiabei' |
| | | # 按照监管要求填写终端信息 |
| | | login_req.TerminalInfo = f'PC;IIP=NA;IPORT=NA;LIP={LOCAL_IP};MAC=5C6F69CC2B40;HD=004bc76004aff0882b9052ba0eb00506;@jiabei' |
| | | # 以下内外网IP地址若不填则柜台系统自动采集,若填写则以终端填值为准报送 |
| | | # login_req.MacAddress = '5C-87-9C-96-F3-E3' |
| | | # login_req.InnerIPAddress = '10.0.1.102' |
| | | # login_req.OuterIPAddress = '58.246.43.50' |
| | | |
| | | TradeSimpleApi.req_id += 1 |
| | | ret = self.__api.ReqUserLogin(login_req, TradeSimpleApi.req_id) |
| | | if ret != 0: |
| | | logger.info('ReqUserLogin fail, ret[%d]' % ret) |
| | | else: |
| | | logger_info.info('GetConnectionInfo fail, [%d] [%d] [%s]!!!' % ( |
| | | nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspUserLogin(self, pRspUserLoginField: "CTORATstpRspUserLoginField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | logger_info.info('Login success! [%d]' % nRequestID) |
| | | self.__front_id = pRspUserLoginField.FrontID |
| | | self.__session_id = pRspUserLoginField.SessionID |
| | | # TradeSimpleApi.set_login_info(self.__session_id, self.__front_id) |
| | | |
| | | # if 1: |
| | | # # 查询股东账号 |
| | | # req_field = traderapi.CTORATstpQryShareholderAccountField() |
| | | # |
| | | # # 以下字段不填表示不设过滤条件,即查询所有股东账号 |
| | | # # req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | # |
| | | # TradeSimpleApi.req_id += 1 |
| | | # ret = api.ReqQryShareholderAccount(req_field, TradeSimpleApi.req_id) |
| | | # if ret != 0: |
| | | # logger_info.info('ReqQryShareholderAccount fail, ret[%d]' % ret) |
| | | |
| | | else: |
| | | logger_info.info('Login fail!!! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspUserPasswordUpdate(self, pUserPasswordUpdateField: "CTORATstpUserPasswordUpdateField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | if pRspInfoField.ErrorID == 0: |
| | | logger.info('OnRspUserPasswordUpdate: OK! [%d]' % nRequestID) |
| | | else: |
| | | logger.info('OnRspUserPasswordUpdate: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspOrderInsert(self, pInputOrderField: "CTORATstpInputOrderField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int") -> "void": |
| | | try: |
| | | if pRspInfoField.ErrorID == 0: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | '[%d] OnRspOrderInsert: OK! [%d]' % (round(time.time() * 1000), nRequestID)) |
| | | else: |
| | | async_log_util.error(logger_local_huaxin_trade_debug, |
| | | f"OnRspOrderInsert 报单出错:{pRspInfoField.ErrorID}-{pRspInfoField.ErrorMsg}") |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_ORDER, nRequestID, |
| | | {"sinfo": pInputOrderField.SInfo, |
| | | "orderStatus": -1, |
| | | "orderStatusMsg": pRspInfoField.ErrorMsg}) |
| | | except: |
| | | pass |
| | | |
| | | # 撤单响应 |
| | | def OnRspOrderAction(self, pInputOrderActionField: "CTORATstpInputOrderActionField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | try: |
| | | if pRspInfoField.ErrorID == 0: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, 'OnRspOrderAction: OK! [%d]' % nRequestID) |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_CANCEL_ORDER, nRequestID, |
| | | {"sinfo": pInputOrderActionField.SInfo, |
| | | "orderSysID": pInputOrderActionField.OrderSysID, |
| | | "cancel": 1}) |
| | | |
| | | else: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, 'OnRspOrderAction: Error! [%d] [%d] [%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_CANCEL_ORDER, nRequestID, |
| | | {"sinfo": pInputOrderActionField.SInfo, |
| | | "orderSysID": pInputOrderActionField.OrderSysID, |
| | | "cancel": 0, "errorID": pRspInfoField.ErrorID, |
| | | "errorMsg": pRspInfoField.ErrorMsg}) |
| | | except: |
| | | pass |
| | | |
| | | # 撤单错误回报 |
| | | def OnErrRtnOrderAction(self, pInputOrderActionField: "CTORATstpInputOrderActionField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | try: |
| | | if pInputOrderActionField and pRspInfoField: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, 'OnErrRtnOrderAction: Error! [%d] [%d] [%d] [%s]' |
| | | % (nRequestID, pInputOrderActionField.OrderSysID, |
| | | pRspInfoField.ErrorID, |
| | | pRspInfoField.ErrorMsg)) |
| | | except: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, "OnErrRtnOrderAction: 撤单出错") |
| | | |
| | | def OnRspInquiryJZFund(self, pRspInquiryJZFundField: "CTORATstpRspInquiryJZFundField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | # try: |
| | | # if pRspInfoField.ErrorID == 0: |
| | | # logger.info('OnRspInquiryJZFund: OK! [%d] [%.2f] [%.2f]' |
| | | # % (nRequestID, pRspInquiryJZFundField.UsefulMoney, pRspInquiryJZFundField.FetchLimit)) |
| | | # else: |
| | | # logger.info('OnRspInquiryJZFund: Error! [%d] [%d] [%s]' |
| | | # % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | # except: |
| | | # pass |
| | | pass |
| | | |
| | | def OnRspTransferFund(self, pInputTransferFundField: "CTORATstpInputTransferFundField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int") -> "void": |
| | | # try: |
| | | # if pRspInfoField.ErrorID == 0: |
| | | # logger.info('OnRspTransferFund: OK! [%d]' % nRequestID) |
| | | # else: |
| | | # logger.info('OnRspTransferFund: Error! [%d] [%d] [%s]' |
| | | # % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | # except: |
| | | # pass |
| | | pass |
| | | |
| | | def OnRtnOrder(self, pOrderField: "CTORATstpOrderField") -> "void": |
| | | try: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | '[%d] OnRtnOrder: SInfo[%s] InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] LimitPrice[%.2f] VolumeTotalOriginal[%d] OrderSysID[%s] OrderStatus[%s] InsertTime[%s]' |
| | | % (round(time.time() * 1000), pOrderField.SInfo, pOrderField.InvestorID, |
| | | pOrderField.SecurityID, |
| | | pOrderField.OrderRef, pOrderField.OrderLocalID, |
| | | pOrderField.LimitPrice, pOrderField.VolumeTotalOriginal, pOrderField.OrderSysID, |
| | | pOrderField.OrderStatus, pOrderField.InsertTime)) |
| | | if pOrderField.OrderStatus == traderapi.TORA_TSTP_OST_Unknown: |
| | | pass |
| | | # if queue_trade_w_l2_r is not None: |
| | | # queue_trade_w_l2_r.put_nowait( |
| | | # json.dumps({"type": "listen_volume", "data": {"code": pOrderField.SecurityID, |
| | | # "volume": pOrderField.VolumeTotalOriginal}}).encode( |
| | | # 'utf-8')) |
| | | else: |
| | | order_data = {"sinfo": pOrderField.SInfo, "securityID": pOrderField.SecurityID, |
| | | "orderLocalID": pOrderField.OrderLocalID, |
| | | "direction": pOrderField.Direction, "orderSysID": pOrderField.OrderSysID, |
| | | "insertTime": pOrderField.InsertTime, "insertDate": pOrderField.InsertDate, |
| | | "acceptTime": pOrderField.AcceptTime, "cancelTime": pOrderField.CancelTime, |
| | | "limitPrice": pOrderField.LimitPrice, "accountID": pOrderField.AccountID, |
| | | "orderRef": pOrderField.OrderRef, "turnover": pOrderField.Turnover, |
| | | "volume": pOrderField.VolumeTotalOriginal, "volumeTraded": pOrderField.VolumeTraded, |
| | | "orderStatus": pOrderField.OrderStatus, |
| | | "orderSubmitStatus": pOrderField.OrderSubmitStatus, |
| | | "statusMsg": pOrderField.StatusMsg} |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_ORDER, 0, order_data) |
| | | except Exception as e: |
| | | async_log_util.error(logger_local_huaxin_trade_debug, "OnRtnOrder 出错") |
| | | except: |
| | | async_log_util.error(logger_local_huaxin_trade_debug, "OnRtnOrder 出错") |
| | | |
| | | def OnRtnTrade(self, pTradeField: "CTORATstpTradeField") -> "void": |
| | | try: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | 'OnRtnTrade: TradeID[%s] InvestorID[%s] SecurityID[%s] OrderRef[%d] OrderLocalID[%s] Price[%.2f] Volume[%d]' |
| | | % (pTradeField.TradeID, pTradeField.InvestorID, pTradeField.SecurityID, |
| | | pTradeField.OrderRef, pTradeField.OrderLocalID, pTradeField.Price, |
| | | pTradeField.Volume)) |
| | | except: |
| | | pass |
| | | |
| | | def OnRtnMarketStatus(self, pMarketStatusField: "CTORATstpMarketStatusField") -> "void": |
| | | # TORA_TSTP_MKD_SHA(1): 上海A股 |
| | | # TORA_TSTP_MKD_SZA(2): 深圳A股 |
| | | # TORA_TSTP_MKD_BJMain(a):北京主板 |
| | | |
| | | # TORA_TSTP_MST_UnKnown( # ):未知 |
| | | # TORA_TSTP_MST_BeforeTrading(0): 开盘前 |
| | | # TORA_TSTP_MST_Continous(1): 连续交易 |
| | | # TORA_TSTP_MST_Closed(2): 收盘 |
| | | # TORA_TSTP_MST_OpenCallAuction(3): 开盘集合竞价 |
| | | try: |
| | | logger.info('OnRtnMarketStatus: MarketID[%s] MarketStatus[%s]' |
| | | % (pMarketStatusField.MarketID, pMarketStatusField.MarketStatus)) |
| | | except: |
| | | pass |
| | | |
| | | def OnRspQrySecurity(self, pSecurityField: "CTORATstpSecurityField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | logger.info( |
| | | 'OnRspQrySecurity[%d]: SecurityID[%s] SecurityName[%s] MarketID[%s] OrderUnit[%s] OpenDate[%s] UpperLimitPrice[%.2f] LowerLimitPrice[%.2f]' |
| | | % (nRequestID, pSecurityField.SecurityID, pSecurityField.SecurityName, pSecurityField.MarketID, |
| | | pSecurityField.OrderUnit, pSecurityField.OpenDate, pSecurityField.UpperLimitPrice, |
| | | pSecurityField.LowerLimitPrice)) |
| | | else: |
| | | logger.info('查询合约结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryInvestor(self, pInvestorField: "CTORATstpInvestorField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | logger.info('OnRspQryInvestor[%d]: InvestorID[%s] InvestorName[%s] Operways[%s]' |
| | | % (nRequestID, pInvestorField.InvestorID, pInvestorField.InvestorName, |
| | | pInvestorField.Operways)) |
| | | else: |
| | | logger.info('查询投资者结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryShareholderAccount(self, pShareholderAccountField: "CTORATstpShareholderAccountField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int", |
| | | bIsLast: "bool") -> "void": |
| | | if bIsLast != 1: |
| | | logger_local_huaxin_trade_debug.info( |
| | | 'OnRspQryShareholderAccount[%d]: InvestorID[%s] ExchangeID[%s] ShareholderID[%s]' |
| | | % (nRequestID, pShareholderAccountField.InvestorID, pShareholderAccountField.ExchangeID, |
| | | pShareholderAccountField.ShareholderID)) |
| | | else: |
| | | logger.info('查询股东账户结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | |
| | | def OnRspQryTradingAccount(self, pTradingAccountField: "CTORATstpTradingAccountField", |
| | | pRspInfoField: "CTORATstpRspInfoField", nRequestID: "int", bIsLast: "bool") -> "void": |
| | | try: |
| | | if nRequestID not in self.__temp_money_account_list_dict: |
| | | self.__temp_money_account_list_dict[nRequestID] = [] |
| | | if bIsLast != 1: |
| | | self.__temp_money_account_list_dict[nRequestID].append( |
| | | {"departmentID": pTradingAccountField.DepartmentID, "investorID": pTradingAccountField.InvestorID, |
| | | "accountID": pTradingAccountField.AccountID, "currencyID": pTradingAccountField.CurrencyID, |
| | | "usefulMoney": round(pTradingAccountField.UsefulMoney, 2), |
| | | "frozenCash": round(pTradingAccountField.FrozenCash, 2), |
| | | "fetchLimit": round(pTradingAccountField.FetchLimit, 2), |
| | | "preDeposit": round(pTradingAccountField.PreDeposit, 2)}) |
| | | # logger.info( |
| | | # 'OnRspQryTradingAccount[%d]: DepartmentID[%s] InvestorID[%s] AccountID[%s] CurrencyID[%s] UsefulMoney[%.2f] FetchLimit[%.2f]' |
| | | # % (nRequestID, pTradingAccountField.DepartmentID, pTradingAccountField.InvestorID, |
| | | # pTradingAccountField.AccountID, pTradingAccountField.CurrencyID, |
| | | # pTradingAccountField.UsefulMoney, pTradingAccountField.FetchLimit)) |
| | | else: |
| | | results = self.__temp_money_account_list_dict.pop(nRequestID) |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_LIST_MONEY, nRequestID, |
| | | results) |
| | | # logger.info('查询资金账号结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | # % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | except: |
| | | pass |
| | | |
| | | def OnRspQryOrder(self, pOrderField: "CTORATstpOrderField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | try: |
| | | if nRequestID not in self.__temp_order_list_dict: |
| | | self.__temp_order_list_dict[nRequestID] = [] |
| | | if not bIsLast: |
| | | # logger.info( |
| | | # 'OnRspQryOrder[%d]: SecurityID[%s] OrderLocalID[%s] Direction[%s] OrderRef[%d] OrderSysID[%s] VolumeTraded[%d] OrderStatus[%s] OrderSubmitStatus[%s], StatusMsg[%s]' |
| | | # % (nRequestID, pOrderField.SecurityID, pOrderField.OrderLocalID, pOrderField.Direction, |
| | | # pOrderField.OrderRef, pOrderField.OrderSysID, |
| | | # pOrderField.VolumeTraded, pOrderField.OrderStatus, pOrderField.OrderSubmitStatus, |
| | | # pOrderField.StatusMsg)) |
| | | self.__temp_order_list_dict[nRequestID].append( |
| | | {"securityID": pOrderField.SecurityID, "orderLocalID": pOrderField.OrderLocalID, |
| | | "direction": pOrderField.Direction, "orderSysID": pOrderField.OrderSysID, |
| | | "insertTime": pOrderField.InsertTime, "insertDate": pOrderField.InsertDate, |
| | | "acceptTime": pOrderField.AcceptTime, "cancelTime": pOrderField.CancelTime, |
| | | "limitPrice": pOrderField.LimitPrice, "accountID": pOrderField.AccountID, |
| | | "turnover": pOrderField.Turnover, "orderRef": pOrderField.OrderRef, |
| | | "volume": pOrderField.VolumeTotalOriginal, |
| | | "volumeTraded": pOrderField.VolumeTraded, "orderStatus": pOrderField.OrderStatus, |
| | | "orderSubmitStatus": pOrderField.OrderSubmitStatus, "statusMsg": pOrderField.StatusMsg}) |
| | | else: |
| | | # logger.info('查询报单结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | # % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_LIST_DELEGATE, nRequestID, |
| | | self.__temp_order_list_dict[nRequestID]) |
| | | |
| | | self.__temp_order_list_dict.pop(nRequestID) |
| | | except: |
| | | pass |
| | | |
| | | def OnRspQryPosition(self, pPositionField: "CTORATstpPositionField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | try: |
| | | if nRequestID not in self.__temp_position_list_dict: |
| | | self.__temp_position_list_dict[nRequestID] = [] |
| | | if bIsLast != 1: |
| | | self.__temp_position_list_dict[nRequestID].append( |
| | | {"investorID": pPositionField.InvestorID, "tradingDay": pPositionField.TradingDay, |
| | | "securityName": pPositionField.SecurityName, |
| | | "securityID": pPositionField.SecurityID, "historyPos": pPositionField.HistoryPos, |
| | | "historyPosFrozen": pPositionField.HistoryPosFrozen, |
| | | "todayBSPos": pPositionField.TodayBSPos, "todayBSPosFrozen": pPositionField.TodayBSPosFrozen, |
| | | "historyPosPrice": pPositionField.HistoryPosPrice, "totalPosCost": pPositionField.TotalPosCost, |
| | | "prePosition": pPositionField.PrePosition, "availablePosition": pPositionField.AvailablePosition, |
| | | "currentPosition": pPositionField.CurrentPosition, "openPosCost": pPositionField.OpenPosCost, |
| | | "todayCommission": pPositionField.TodayCommission, |
| | | "todayTotalBuyAmount": pPositionField.TodayTotalBuyAmount, |
| | | "todayTotalSellAmount": pPositionField.TodayTotalSellAmount}) |
| | | else: |
| | | # logger.info('查询持仓结束[%d] ErrorID[%d] ErrorMsg[%s]' |
| | | # % (nRequestID, pRspInfoField.ErrorID, pRspInfoField.ErrorMsg)) |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_LIST_POSITION, nRequestID, |
| | | self.__temp_position_list_dict[nRequestID]) |
| | | |
| | | self.__temp_position_list_dict.pop(nRequestID) |
| | | except: |
| | | pass |
| | | |
| | | # 成交回报,参数pTradeField是一个CTORATstpTradeField类对象 |
| | | def OnRtnTrade(self, pTradeField: "CTORATstpTradeField") -> "void": |
| | | pass |
| | | # logger.info("OnRtnTrade") |
| | | |
| | | # 查询成交响应,参数pTradeField是一个CTORATstpTradeField类对象 |
| | | def OnRspQryTrade(self, pTradeField: "CTORATstpTradeField", pRspInfoField: "CTORATstpRspInfoField", |
| | | nRequestID: "int", bIsLast: "bool") -> "void": |
| | | try: |
| | | # logger.info("查询成交响应") |
| | | pass |
| | | if nRequestID not in self.__temp_order_list_dict: |
| | | self.__temp_order_list_dict[nRequestID] = [] |
| | | if not bIsLast: |
| | | self.__temp_order_list_dict[nRequestID].append( |
| | | {"tradeID": pTradeField.TradeID, "securityID": pTradeField.SecurityID, |
| | | "orderLocalID": pTradeField.OrderLocalID, |
| | | "direction": pTradeField.Direction, "orderSysID": pTradeField.OrderSysID, |
| | | "price": pTradeField.Price, |
| | | "tradeTime": pTradeField.TradeTime, |
| | | "volume": pTradeField.Volume, "tradeDate": pTradeField.TradeDate, |
| | | "tradingDay": pTradeField.TradingDay, |
| | | "pbuID": pTradeField.PbuID, "accountID": pTradeField.AccountID}) |
| | | else: |
| | | self.call_back_thread_pool.submit(self.__data_callback, trade_manager.TYPE_LIST_TRADED, nRequestID, |
| | | self.__temp_order_list_dict[nRequestID]) |
| | | self.__temp_order_list_dict.pop(nRequestID) |
| | | except: |
| | | pass |
| | | |
| | | |
| | | def run(queue_strategy_w_trade_r, queue_result): |
| | | """ |
| | | 交易运行 |
| | | :param queue_strategy_w_trade_r: |
| | | :return: |
| | | """ |
| | | # -----------初始化交易环境--------------------- |
| | | trade_manager.set_result_read_queue(queue_result) |
| | | api = traderapi.CTORATstpTraderApi.CreateTstpTraderApi('./flow', False) |
| | | # 创建回调对象 |
| | | spi = TraderSpi(api, trade_manager.traderapi_callback) |
| | | |
| | | # 注册回调接口 |
| | | api.RegisterSpi(spi) |
| | | |
| | | # 注册多个交易前置服务地址,用逗号隔开 |
| | | # api.RegisterFront('tcp://10.0.1.101:6500,tcp://10.0.1.101:26500') |
| | | # 注册名字服务器地址,支持多服务地址逗号隔开 |
| | | # api.RegisterNameServer('tcp://10.0.1.101:52370') |
| | | # api.RegisterNameServer('tcp://10.0.1.101:52370,tcp://10.0.1.101:62370') |
| | | |
| | | if not TEST_TRADE: # 模拟环境,TCP 直连Front方式 |
| | | # 注册单个交易前置服务地址 |
| | | ##B类服务器## |
| | | logger.info(f"注册交易地址:{FRONT_ADDRESS}/{FRONT_ADDRESS1}") |
| | | api.RegisterFront(FRONT_ADDRESS) # 正式环境主地址 |
| | | api.RegisterFront(FRONT_ADDRESS1) # 正式环境备用地址 |
| | | |
| | | ##A类服务器## |
| | | # api.RegisterFront("tcp://10.224.123.143:6500") # 正式环境主地址 |
| | | # api.RegisterFront("tcp://10.224.123.147:26500") # 正式环境备用地址 |
| | | |
| | | # TD_TCP_FrontAddress = "tcp://210.14.72.21:4400" # 仿真交易环境 |
| | | # TD_TCP_FrontAddress = "tcp://210.14.72.15:4400" # 24小时环境A套 |
| | | # TD_TCP_FrontAddress="tcp://210.14.72.16:9500" #24小时环境B套 |
| | | # api.RegisterFront(TD_TCP_FrontAddress) |
| | | # 注册多个交易前置服务地址,用逗号隔开 形如: api.RegisterFront("tcp://10.0.1.101:6500,tcp://10.0.1.101:26500") |
| | | # print("TD_TCP_FensAddress[sim or 24H]::%s\n" % TD_TCP_FrontAddress) |
| | | |
| | | else: # 模拟环境,FENS名字服务器方式 |
| | | TD_TCP_FrontAddress = "tcp://210.14.72.21:4400" # 仿真交易环境 |
| | | # TD_TCP_FrontAddress="tcp://210.14.72.15:4400" #24小时环境A套 |
| | | # TD_TCP_FrontAddress="tcp://210.14.72.16:9500" #24小时环境B套 |
| | | api.RegisterFront(TD_TCP_FrontAddress) |
| | | # 注册多个交易前置服务地址,用逗号隔开 形如: api.RegisterFront("tcp://10.0.1.101:6500,tcp://10.0.1.101:26500") |
| | | print("TD_TCP_FensAddress[sim or 24H]::%s\n" % TD_TCP_FrontAddress) |
| | | |
| | | # 订阅私有流 |
| | | api.SubscribePrivateTopic(traderapi.TORA_TERT_QUICK) |
| | | # 订阅公有流 |
| | | api.SubscribePublicTopic(traderapi.TORA_TERT_QUICK) |
| | | # 启动接口 |
| | | api.Init() |
| | | |
| | | data_callback = trade_manager.MyTradeActionCallback(UserID, Password, SZSE_ShareHolderID, SSE_ShareHolderID, api) |
| | | # 不需要运行命令解析 |
| | | tradeCommandManager = TradeCommandManager() |
| | | tradeCommandManager.init( |
| | | data_callback, |
| | | queue_strategy_w_trade_r) |
| | | logger_info.debug("全部初始化完成") |
| | | tradeCommandManager.run(True) |
| | | while True: |
| | | time.sleep(2) |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | pass |
New file |
| | |
| | | """ |
| | | 华鑫交易管理 |
| | | """ |
| | | import concurrent.futures |
| | | import json |
| | | import logging |
| | | import time |
| | | import multiprocessing |
| | | |
| | | import traderapi |
| | | from huaxin_client.client_network import SendResponseSkManager |
| | | from huaxin_client.command_manager import TradeActionCallback |
| | | from log_module import async_log_util |
| | | from log_module.log import logger_trade, logger_local_huaxin_trade_debug |
| | | from utils import tool, socket_util |
| | | |
| | | ENABLE_ORDER = True |
| | | |
| | | TYPE_ORDER = 0 |
| | | TYPE_CANCEL_ORDER = 1 |
| | | TYPE_LIST_DELEGATE = 2 |
| | | TYPE_LIST_TRADED = 3 |
| | | TYPE_LIST_POSITION = 4 |
| | | TYPE_LIST_MONEY = 5 |
| | | # 成交 |
| | | TYPE_DEAL = 6 |
| | | |
| | | __queue_result: multiprocessing.Queue = None |
| | | |
| | | |
| | | def set_result_read_queue(queue_result): |
| | | """ |
| | | 设置结果读取队列 |
| | | :param queue_result: |
| | | :return: |
| | | """ |
| | | global __queue_result |
| | | __queue_result = queue_result |
| | | |
| | | |
| | | def __send_response(type, data_bytes): |
| | | sk = SendResponseSkManager.create_send_response_sk() |
| | | try: |
| | | data_bytes = socket_util.load_header(data_bytes) |
| | | sk.sendall(data_bytes) |
| | | result, header_str = socket_util.recv_data(sk) |
| | | result = json.loads(result) |
| | | if result["code"] != 0: |
| | | raise Exception(result['msg']) |
| | | finally: |
| | | sk.close() |
| | | |
| | | |
| | | def send_response(data, type, _client_id, _request_id, show_log=True): |
| | | if show_log: |
| | | async_log_util.debug(logger_local_huaxin_trade_debug, f"回调返回内容:{data}") |
| | | __queue_result.put_nowait(data) |
| | | |
| | | |
| | | # 交易反馈回调 |
| | | def __traderapi_callback(type, req_id, data): |
| | | async_log_util.info(logger_local_huaxin_trade_debug, "回调:type-{} req_id-{}", type, req_id) |
| | | key = req_id |
| | | if type == TYPE_ORDER or type == TYPE_CANCEL_ORDER: |
| | | key = data["sinfo"] |
| | | try: |
| | | if req_rid_dict and key in req_rid_dict: |
| | | temp_params = req_rid_dict.pop(key) |
| | | client_id, request_id = temp_params[0], temp_params[1] |
| | | # 本地订单号-系统订单号映射 |
| | | if len(temp_params) >= 4 and type == TYPE_ORDER: |
| | | order_ref = temp_params[3] |
| | | data["orderRef"] = order_ref |
| | | |
| | | async_log_util.info(logger_local_huaxin_trade_debug, "API回调 request_id-{}", request_id) |
| | | # 测试 |
| | | # send_response( |
| | | # json.dumps({"type": "response", "data": {"code": 0, "data": data}, "client_id": client_id, |
| | | # "request_id": request_id}), type, client_id, request_id, temp_params[2]) |
| | | send_response( |
| | | json.dumps({"type": "response", "data": {"code": 0, "data": data}, "client_id": client_id, |
| | | "request_id": request_id}), type, client_id, request_id) |
| | | |
| | | async_log_util.info(logger_local_huaxin_trade_debug, "API回调结束 req_id-{} request_id-{}", req_id, request_id) |
| | | else: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, "非API回调 req_id-{}", req_id) |
| | | send_response( |
| | | json.dumps({"type": "trade_callback", "data": {"code": 0, "data": data, "type": type}}), |
| | | type, |
| | | None, |
| | | req_id) |
| | | except Exception as e: |
| | | logging.exception(e) |
| | | |
| | | |
| | | # 采用异步回调 |
| | | def traderapi_callback(type, req_id, data): |
| | | __traderapi_callback(type, req_id, data) |
| | | |
| | | |
| | | req_rid_dict = {} |
| | | |
| | | |
| | | class TradeSimpleApi: |
| | | req_id = 0 |
| | | __buy_sinfo_set = set() |
| | | __sell_sinfo_set = set() |
| | | __cancel_buy_sinfo_set = set() |
| | | __cancel_sell_sinfo_set = set() |
| | | |
| | | def __init__(self, UserID, Password, SZSE_ShareHolderID, SSE_ShareHolderID, api: traderapi.CTORATstpTraderApi): |
| | | """ |
| | | |
| | | :param SZSE_ShareHolderID: 深证投资者代码 |
| | | :param SSE_ShareHolderID: 上证投资者代码 |
| | | :param api: 交易接口 |
| | | """ |
| | | self.UserID = UserID |
| | | self.Password = Password |
| | | self.SZSE_ShareHolderID = SZSE_ShareHolderID |
| | | self.SSE_ShareHolderID = SSE_ShareHolderID |
| | | self.api = api |
| | | |
| | | |
| | | @classmethod |
| | | def set_login_info(cls, session_id, front_id): |
| | | cls.__session_id = session_id |
| | | cls.__front_id = front_id |
| | | |
| | | # sinfo char(32) |
| | | def buy(self, code, count, price, sinfo, order_ref, shadow_price=None): |
| | | if not ENABLE_ORDER: |
| | | return |
| | | if sinfo in self.__buy_sinfo_set: |
| | | raise Exception(f'下单请求已经提交:{sinfo}') |
| | | async_log_util.info(logger_trade, f"{code}华鑫本地真实下单开始") |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | f"进入买入方法:code-{code} sinfo-{sinfo} order_ref-{order_ref}") |
| | | 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.get_market_type(code) == tool.MARKET_TYPE_SZSE: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE |
| | | req_field.ShareholderID = self.SZSE_ShareHolderID |
| | | elif tool.get_market_type(code) == tool.MARKET_TYPE_SSE: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | req_field.ShareholderID = self.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 |
| | | |
| | | ''' |
| | | 其它字段置空 |
| | | ''' |
| | | # 给L2发送消息 |
| | | |
| | | ret = self.api.ReqOrderInsert(req_field, self.req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqOrderInsert fail, ret[%d]' % ret) |
| | | # 常态化监听不需要单独设置 |
| | | # if queue_other_w_l2_r is not None: |
| | | # queue_other_w_l2_r.put_nowait( |
| | | # json.dumps({"type": "listen_volume", "data": {"code": code, |
| | | # "volume": count}}).encode( |
| | | # 'utf-8')) |
| | | async_log_util.info(logger_trade, f"{code}华鑫本地真实下单结束") |
| | | # --------------------------------影子订单-------------------------------- |
| | | if shadow_price: |
| | | if order_ref: |
| | | # 下一个影子订单 |
| | | shadow_order_ref = order_ref + 1 |
| | | shadow_sinfo = f"s_b_{order_ref}" |
| | | req_field.LimitPrice = shadow_price |
| | | req_field.SInfo = shadow_sinfo |
| | | req_field.OrderRef = shadow_order_ref |
| | | req_field.VolumeTotalOriginal = 100 |
| | | self.req_id += 1 |
| | | ret = self.api.ReqOrderInsert(req_field, self.req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqOrderInsert fail, ret[%d]' % ret) |
| | | # 影子订单撤单 |
| | | # 撤掉影子单 |
| | | shadow_cancel_order_ref = shadow_order_ref + 1 |
| | | # 深证停留50ms上证停留200ms |
| | | delay_s = 0.05 if code.find("00") == 0 else 0.2 |
| | | self.cancel_buy(code, f"s_c_{shadow_order_ref}", order_sys_id=None, |
| | | order_ref=shadow_order_ref, |
| | | order_action_ref=None, delay_s=delay_s) |
| | | |
| | | return ret |
| | | |
| | | # 撤买 |
| | | 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: |
| | | time.sleep(delay_s) |
| | | if sinfo in self.__cancel_buy_sinfo_set: |
| | | raise Exception(f'撤单请求已经提交:{sinfo}') |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | f"进入撤单方法:code-{code} order_sys_id-{order_sys_id} order_ref-{order_ref} sinfo-{sinfo}") |
| | | self.__cancel_buy_sinfo_set.add(sinfo) |
| | | self.req_id += 1 |
| | | # 请求撤单 |
| | | req_field = traderapi.CTORATstpInputOrderActionField() |
| | | if code.find('00') == 0: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE |
| | | elif code.find('60') == 0: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | |
| | | req_field.ActionFlag = traderapi.TORA_TSTP_AF_Delete |
| | | |
| | | # 撤单支持以下两种方式定位原始报单: |
| | | # (1)报单引用方式 |
| | | # req_field.FrontID = self.__front_id |
| | | # req_field.SessionID = self.__session_id |
| | | # req_field.OrderRef = 1 |
| | | # (2)系统报单编号方式 |
| | | if order_sys_id: |
| | | req_field.OrderSysID = order_sys_id |
| | | elif order_ref is not None: |
| | | req_field.OrderRef = order_ref |
| | | req_field.SessionID = self.__session_id |
| | | req_field.FrontID = self.__front_id |
| | | if order_action_ref: |
| | | req_field.OrderActionRef = order_action_ref |
| | | |
| | | # OrderActionRef报单操作引用,用法同报单引用,可根据需要选填 |
| | | |
| | | ''' |
| | | 终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在查询撤单时返回给终端 |
| | | ''' |
| | | req_field.SInfo = sinfo |
| | | # req_field.IInfo = 123 |
| | | |
| | | ''' |
| | | 委托方式字段根据券商要求填写,无特殊说明置空即可 |
| | | 其它字段置空 |
| | | ''' |
| | | ret = self.api.ReqOrderAction(req_field, self.req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqOrderAction fail, ret[%d]' % ret) |
| | | return |
| | | |
| | | # 卖 |
| | | def sell(self, code, count, price, price_type, sinfo, order_ref=None): |
| | | if sinfo in self.__sell_sinfo_set: |
| | | raise Exception(f'下单请求已经提交:{sinfo}') |
| | | self.__sell_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.get_market_type(code) == tool.MARKET_TYPE_SZSE: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE |
| | | req_field.ShareholderID = self.SZSE_ShareHolderID |
| | | elif tool.get_market_type(code) == tool.MARKET_TYPE_SSE: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | req_field.ShareholderID = self.SSE_ShareHolderID |
| | | |
| | | # 证券代码 |
| | | req_field.SecurityID = code |
| | | req_field.Direction = traderapi.TORA_TSTP_D_Sell |
| | | req_field.VolumeTotalOriginal = count |
| | | req_field.SInfo = sinfo |
| | | |
| | | ''' |
| | | 上交所支持限价指令和最优五档剩撤、最优五档剩转限两种市价指令,对于科创板额外支持本方最优和对手方最优两种市价指令和盘后固定价格申报指令 |
| | | 深交所支持限价指令和立即成交剩余撤销、全额成交或撤销、本方最优、对手方最优和最优五档剩撤五种市价指令 |
| | | 限价指令和上交所科创板盘后固定价格申报指令需填写报单价格,其它市价指令无需填写报单价格 |
| | | 以下以上交所限价指令为例,其它指令参考开发指南相关说明填写OrderPriceType、TimeCondition和VolumeCondition三个字段: |
| | | ''' |
| | | |
| | | print('卖 price', price, price_type) |
| | | if price and price > 0: |
| | | req_field.LimitPrice = price |
| | | if price_type == 1: |
| | | req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_AnyPrice |
| | | elif price_type == 2: |
| | | req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_LimitPrice |
| | | elif price_type == 3: |
| | | req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_BestPrice |
| | | elif price_type == 4: |
| | | req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_FixPrice |
| | | elif price_type == 5: |
| | | req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_FiveLevelPrice |
| | | elif price_type == 6: |
| | | req_field.OrderPriceType = traderapi.TORA_TSTP_OPT_HomeBestPrice |
| | | |
| | | req_field.TimeCondition = traderapi.TORA_TSTP_TC_GFD |
| | | req_field.VolumeCondition = traderapi.TORA_TSTP_VC_AV |
| | | if order_ref: |
| | | req_field.OrderRef = order_ref |
| | | |
| | | ''' |
| | | OrderRef为报单引用,类型为整型,该字段报单时为选填 |
| | | 若不填写,则系统会为每笔报单自动分配一个报单引用 |
| | | 若填写,则需保证同一个TCP会话下报单引用严格单调递增,不要求连续递增,至少需从1开始编号 |
| | | ''' |
| | | # req_field.OrderRef = 1 |
| | | |
| | | ''' |
| | | InvestorID为选填,若填写则需保证填写正确 |
| | | Operway为委托方式,根据券商要求填写,无特殊说明置空即可 |
| | | 终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在报单回报和查询报单时返回给终端 |
| | | ''' |
| | | # req_field.SInfo = 'sinfo' |
| | | # req_field.IInfo = 123 |
| | | |
| | | ''' |
| | | 其它字段置空 |
| | | ''' |
| | | ret = self.api.ReqOrderInsert(req_field, self.req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqOrderInsert fail, ret[%d]' % ret) |
| | | return |
| | | |
| | | # 撤卖 |
| | | def cancel_sell(self, code, order_sys_id, sinfo): |
| | | if sinfo in self.__cancel_sell_sinfo_set: |
| | | raise Exception(f'撤单请求已经提交:{sinfo}') |
| | | self.__cancel_sell_sinfo_set.add(sinfo) |
| | | self.req_id += 1 |
| | | # 请求撤单 |
| | | req_field = traderapi.CTORATstpInputOrderActionField() |
| | | if code.find('00') == 0: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SZSE |
| | | elif code.find('60') == 0: |
| | | req_field.ExchangeID = traderapi.TORA_TSTP_EXD_SSE |
| | | |
| | | req_field.ActionFlag = traderapi.TORA_TSTP_AF_Delete |
| | | |
| | | # 撤单支持以下两种方式定位原始报单: |
| | | # (1)报单引用方式 |
| | | # req_field.FrontID = self.__front_id |
| | | # req_field.SessionID = self.__session_id |
| | | # req_field.OrderRef = 1 |
| | | # (2)系统报单编号方式 |
| | | req_field.OrderSysID = order_sys_id |
| | | |
| | | # OrderActionRef报单操作引用,用法同报单引用,可根据需要选填 |
| | | |
| | | ''' |
| | | 终端自定义字段,终端可根据需要填写如下字段的值,该字段值不会被柜台系统修改,在查询撤单时返回给终端 |
| | | ''' |
| | | req_field.SInfo = sinfo |
| | | # req_field.IInfo = 123 |
| | | |
| | | ''' |
| | | 委托方式字段根据券商要求填写,无特殊说明置空即可 |
| | | 其它字段置空 |
| | | ''' |
| | | ret = self.api.ReqOrderAction(req_field, self.req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqOrderAction fail, ret[%d]' % ret) |
| | | return |
| | | |
| | | # 查询当日可撤销的委托 |
| | | def list_delegate_orders(self, is_cancel): |
| | | self.req_id += 1 |
| | | req_id = self.req_id |
| | | req_field = traderapi.CTORATstpQryOrderField() |
| | | # 以下字段不填表示不设过滤条件,即查询所有报单 |
| | | # req_field.SecurityID = '600000' |
| | | req_field.InsertTimeStart = '09:15:00' |
| | | req_field.InsertTimeEnd = '15:00:00' |
| | | # IsCancel字段填1表示只查询可撤报单 |
| | | if is_cancel: |
| | | req_field.IsCancel = 1 |
| | | # req_field.SInfo = sinfo |
| | | ret = self.api.ReqQryOrder(req_field, req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqQryOrder fail, ret[%d]' % ret) |
| | | return req_id |
| | | |
| | | # 查询当日成交的订单 |
| | | def list_traded_orders(self): |
| | | self.req_id += 1 |
| | | req_id = self.req_id |
| | | req_field = traderapi.CTORATstpQryTradeField() |
| | | ret = self.api.ReqQryTrade(req_field, req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqQryTrade fail, ret[%d]' % ret) |
| | | return req_id |
| | | |
| | | # 查询持仓 |
| | | def list_positions(self): |
| | | self.req_id += 1 |
| | | req_id = self.req_id |
| | | req_field = traderapi.CTORATstpQryPositionField() |
| | | ret = self.api.ReqQryPosition(req_field, req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqQryPosition fail, ret[%d]' % ret) |
| | | return req_id |
| | | |
| | | # 查询资金账户 |
| | | def get_money_account(self): |
| | | self.req_id += 1 |
| | | req_id = self.req_id |
| | | req_field = traderapi.CTORATstpQryTradingAccountField() |
| | | req_field.CurrencyID = traderapi.TORA_TSTP_CID_CNY |
| | | ret = self.api.ReqQryTradingAccount(req_field, req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqQryTradingAccount fail, ret[%d]' % ret) |
| | | return req_id |
| | | |
| | | def login(self): |
| | | # 请求登录 |
| | | login_req = traderapi.CTORATstpReqUserLoginField() |
| | | |
| | | # 支持以用户代码、资金账号和股东账号方式登录 |
| | | # (1)以用户代码方式登录 |
| | | login_req.LogInAccount = self.UserID |
| | | login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_UserID |
| | | # (2)以资金账号方式登录 |
| | | # login_req.DepartmentID = DepartmentID |
| | | # login_req.LogInAccount = AccountID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_AccountID |
| | | # (3)以上海股东账号方式登录 |
| | | # login_req.LogInAccount = SSE_ShareHolderID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SHAStock |
| | | # (4)以深圳股东账号方式登录 |
| | | # login_req.LogInAccount = SZSE_ShareHolderID |
| | | # login_req.LogInAccountType = traderapi.TORA_TSTP_LACT_SZAStock |
| | | |
| | | # 支持以密码和指纹(移动设备)方式认证 |
| | | # (1)密码认证 |
| | | # 密码认证时AuthMode可不填 |
| | | # login_req.AuthMode = traderapi.TORA_TSTP_AM_Password |
| | | login_req.Password = self.Password |
| | | # (2)指纹认证 |
| | | # 非密码认证时AuthMode必填 |
| | | # login_req.AuthMode = traderapi.TORA_TSTP_AM_FingerPrint |
| | | # login_req.DeviceID = '03873902' |
| | | # login_req.CertSerial = '9FAC09383D3920CAEFF039' |
| | | |
| | | # 终端信息采集 |
| | | # UserProductInfo填写终端名称 |
| | | login_req.UserProductInfo = 'jiabei' |
| | | # 按照监管要求填写终端信息 |
| | | login_req.TerminalInfo = 'PC;IIP=123.112.154.118;IPORT=50361;LIP=192.168.118.107;MAC=54EE750B1713FCF8AE5CBD58;HD=TF655AY91GHRVL' |
| | | # 以下内外网IP地址若不填则柜台系统自动采集,若填写则以终端填值为准报送 |
| | | # login_req.MacAddress = '5C-87-9C-96-F3-E3' |
| | | # login_req.InnerIPAddress = '10.0.1.102' |
| | | # login_req.OuterIPAddress = '58.246.43.50' |
| | | |
| | | TradeSimpleApi.req_id += 1 |
| | | ret = self.api.ReqUserLogin(login_req, TradeSimpleApi.req_id) |
| | | if ret != 0: |
| | | raise Exception('ReqUserLogin fail, ret[%d]' % ret) |
| | | |
| | | |
| | | class MyTradeActionCallback(TradeActionCallback): |
| | | trade_thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=30) |
| | | |
| | | def __init__(self, UserID, Password, SZSE_ShareHolderID, SSE_ShareHolderID, api: traderapi.CTORATstpTraderApi): |
| | | self.__tradeSimpleApi = TradeSimpleApi(UserID, Password, SZSE_ShareHolderID, SSE_ShareHolderID, api) |
| | | |
| | | |
| | | def OnTrade(self, client_id, request_id, sk, type_, data): |
| | | if type_ == 1: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | f"\n---------------------\n请求下单:client_id-{client_id} request_id-{request_id} data:{data}") |
| | | # 下单 |
| | | # 1-买 2-卖 |
| | | direction = data["direction"] |
| | | code = data["code"] |
| | | volume = data["volume"] |
| | | price = data["price"] |
| | | sinfo = data["sinfo"] |
| | | order_ref = data.get("order_ref") |
| | | shadow_price = data.get("shadow_price") |
| | | blocking = data.get("blocking") |
| | | |
| | | if direction == 1: |
| | | async_log_util.info(logger_trade, f"{code}华鑫本地开始下单") |
| | | # 买 |
| | | try: |
| | | if blocking: |
| | | 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() |
| | | self.trade_thread_pool.submit(self.__tradeSimpleApi.buy, code, volume, price, sinfo, order_ref, |
| | | shadow_price) |
| | | |
| | | 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, |
| | | request_id) |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | f"买入结束:code-{code} sinfo-{sinfo}") |
| | | elif direction == 2: |
| | | try: |
| | | price_type = data["price_type"] |
| | | if blocking: |
| | | req_rid_dict[sinfo] = (client_id, request_id, sk) |
| | | self.__tradeSimpleApi.sell(code, volume, price, price_type, sinfo, order_ref) |
| | | print("sell", req_rid_dict) |
| | | except Exception as e: |
| | | logging.exception(e) |
| | | send_response(json.dumps({"code": 1, "msg": str(e)}), TYPE_ORDER, client_id, |
| | | request_id) |
| | | |
| | | elif type_ == 2: |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | f"\n---------------------\n请求撤单:client_id-{client_id} request_id-{request_id} data-{data}") |
| | | # 撤单 |
| | | direction = data["direction"] |
| | | code = data["code"] |
| | | orderSysID = data.get("orderSysID") |
| | | orderRef = data.get("orderRef") |
| | | orderActionRef = data.get("orderActionRef") |
| | | sinfo = data["sinfo"] |
| | | if direction == 1: |
| | | # 撤买 |
| | | try: |
| | | if not orderSysID and orderRef is None: |
| | | raise Exception("没有找到系统订单号或者报单引用") |
| | | req_rid_dict[sinfo] = (client_id, request_id, sk) |
| | | self.trade_thread_pool.submit( |
| | | lambda: self.__tradeSimpleApi.cancel_buy(code, sinfo, order_sys_id=orderSysID, |
| | | order_ref=orderRef, order_action_ref=orderActionRef)) |
| | | async_log_util.info(logger_local_huaxin_trade_debug, |
| | | f"撤单结束:code-{code} order_sys_id-{orderSysID} sinfo-{sinfo}") |
| | | except Exception as e: |
| | | send_response(json.dumps({"code": 1, "msg": str(e)}), TYPE_CANCEL_ORDER, client_id, |
| | | request_id) |
| | | |
| | | elif direction == 2: |
| | | # 撤卖 |
| | | try: |
| | | req_rid_dict[sinfo] = (client_id, request_id, sk) |
| | | self.__tradeSimpleApi.cancel_sell(code, orderSysID, sinfo) |
| | | except Exception as e: |
| | | send_response(json.dumps({"code": 1, "msg": str(e)}), TYPE_CANCEL_ORDER, client_id, |
| | | request_id) |
| | | |
| | | def OnDealList(self, client_id, request_id, sk): |
| | | async_log_util.info(logger_local_huaxin_trade_debug, f"请求成交列表:client_id-{client_id} request_id-{request_id}") |
| | | try: |
| | | # print("开始请求成交列表") |
| | | req_id = self.__tradeSimpleApi.list_traded_orders() |
| | | req_rid_dict[req_id] = (client_id, request_id, sk) |
| | | except Exception as e: |
| | | logging.exception(e) |
| | | SendResponseSkManager.send_error_response("common", request_id, client_id, str(e)) |
| | | |
| | | def OnDelegateList(self, client_id, request_id, sk, is_cancel): |
| | | async_log_util.info(logger_local_huaxin_trade_debug, f"请求委托列表:client_id-{client_id} request_id-{request_id}") |
| | | try: |
| | | req_id = self.__tradeSimpleApi.list_delegate_orders(is_cancel) |
| | | req_rid_dict[req_id] = (client_id, request_id, sk) |
| | | except Exception as e: |
| | | send_response(json.dumps({"code": 1, "msg": str(e)}), "common", client_id, |
| | | request_id) |
| | | |
| | | def OnMoney(self, client_id, request_id, sk): |
| | | async_log_util.info(logger_local_huaxin_trade_debug, f"请求账户:client_id-{client_id} request_id-{request_id}") |
| | | try: |
| | | req_id = self.__tradeSimpleApi.get_money_account() |
| | | req_rid_dict[req_id] = (client_id, request_id, sk) |
| | | except Exception as e: |
| | | send_response(json.dumps({"code": 1, "msg": str(e)}), "common", client_id, |
| | | request_id) |
| | | |
| | | def OnPositionList(self, client_id, request_id, sk): |
| | | async_log_util.info(logger_local_huaxin_trade_debug, f"请求持仓:client_id-{client_id} request_id-{request_id}") |
| | | try: |
| | | req_id = self.__tradeSimpleApi.list_positions() |
| | | req_rid_dict[req_id] = (client_id, request_id, sk) |
| | | except Exception as e: |
| | | send_response(json.dumps({"code": 1, "msg": str(e)}), "common", client_id, |
| | | request_id) |
| | | |
| | | def OnTest(self, client_id, request_id, data, sk): |
| | | send_response( |
| | | json.dumps({"type": "response", "data": {"code": 0, "data": data}, "client_id": client_id, |
| | | "request_id": request_id}), type, client_id, request_id, show_log=False, sk=sk) |
| | |
| | | import threading |
| | | |
| | | from log_module import async_log_util |
| | | from log_module.log import logger_local_huaxin_trade_debug, logger_trade, logger_local_huaxin_contact_debug |
| | | from log_module.log import logger_local_huaxin_trade_debug, logger_trade, logger_local_huaxin_contact_debug, logger_info |
| | | |
| | | MSG_TYPE_HEART = "heart" |
| | | # 命令信息 |
| | |
| | | _type = val["type"] |
| | | if _type != "test": |
| | | async_log_util.info(logger_local_huaxin_contact_debug, f"接受到信息: {val}") |
| | | # TODO 测试 |
| | | logger_info.info(f"接受到信息: {val}") |
| | | cls.process_command(_type, None, val) |
| | | except Exception as e: |
| | | async_log_util.exception(logger_local_huaxin_trade_debug, e) |
| | |
| | | rotation="00:00", compression="zip", enqueue=True) |
| | | |
| | | # 显示在控制台 |
| | | # logger.add(sys.stdout, |
| | | # filter=lambda record: record["extra"].get("name") == "l2_trade", enqueue=True) |
| | | logger.add(sys.stdout, |
| | | filter=lambda record: record["extra"].get("name") == "info", enqueue=True) |
| | | |
| | | logger.add(self.get_path("l2", "l2_trade_cancel"), |
| | | filter=lambda record: record["extra"].get("name") == "l2_trade_cancel", |
| | |
| | | |
| | | __mylogger = MyLogger() |
| | | |
| | | logger_info = __mylogger.get_logger("info") |
| | | |
| | | logger_trade_gui = __mylogger.get_logger("trade_gui") |
| | | logger_trade = __mylogger.get_logger("trade") |
| | | logger_trade_delegate = __mylogger.get_logger("delegate") |
| | |
| | | from code_atrribute.history_k_data_util import JueJinHttpApi |
| | | from huaxin_client import l2_client_for_cb |
| | | from utils import tool |
| | | import logging |
| | | import multiprocessing |
| | | import time |
| | | |
| | | from huaxin_client.cb import trade_client_for_cb |
| | | from log_module.log import logger_info |
| | | from trade import huaxin_trade_api |
| | | |
| | | if __name__ == "__main__": |
| | | ffresults = l2_client_for_cb.get_subscript_codes() |
| | | try: |
| | | q_s_w_t_r, q_s_r_t_w = multiprocessing.Queue(), multiprocessing.Queue() |
| | | huaxin_trade_api.run_pipe_trade(q_s_r_t_w, q_s_w_t_r) |
| | | tradeProcess = multiprocessing.Process( |
| | | target= trade_client_for_cb.run, |
| | | args=(q_s_w_t_r, q_s_r_t_w)) |
| | | tradeProcess.start() |
| | | time.sleep(3) |
| | | print("获取委托结果", huaxin_trade_api.get_delegate_list()) |
| | | |
| | | print("最终的数量", len(ffresults)) |
| | | time.sleep(2) |
| | | print("获取持仓结果", huaxin_trade_api.get_position_list(True)) |
| | | |
| | | |
| | | |
| | | |
| | | except Exception as e: |
| | | logging.exception(e) |
| | | finally: |
| | | logger_info.debug("程序结束") |
| | |
| | | def get_delegate_list(can_cancel=True, blocking=True, timeout=TIMEOUT): |
| | | request_id = __request(ClientSocketManager.CLIENT_TYPE_DELEGATE_LIST, |
| | | {"type": ClientSocketManager.CLIENT_TYPE_DELEGATE_LIST, |
| | | "can_cancel": 1 if can_cancel else 0}, blocking=blocking, is_pipe=is_pipe_channel_normal()) |
| | | "can_cancel": 1 if can_cancel else 0}, blocking=blocking, is_pipe=is_pipe_channel_normal(), is_trade=True) |
| | | |
| | | return __read_response(request_id, blocking, timeout=timeout) |
| | | |
| | |
| | | def get_deal_list(blocking=True, timeout=TIMEOUT): |
| | | request_id = __request(ClientSocketManager.CLIENT_TYPE_DEAL_LIST, |
| | | {"type": ClientSocketManager.CLIENT_TYPE_DEAL_LIST}, blocking=blocking, |
| | | is_pipe=is_pipe_channel_normal()) |
| | | is_pipe=is_pipe_channel_normal(), is_trade=True) |
| | | return __read_response(request_id, blocking, timeout=timeout) |
| | | |
| | | |
| | |
| | | def get_money(blocking=True): |
| | | request_id = __request(ClientSocketManager.CLIENT_TYPE_MONEY, |
| | | {"type": ClientSocketManager.CLIENT_TYPE_MONEY}, blocking=blocking, |
| | | is_pipe=is_pipe_channel_normal()) |
| | | is_pipe=is_pipe_channel_normal(), is_trade=True) |
| | | return __read_response(request_id, blocking) |
| | | |
| | | |
| | |
| | | return None |
| | | |
| | | |
| | | # 深证 |
| | | MARKET_TYPE_SZSE = 1 |
| | | # 上证 |
| | | MARKET_TYPE_SSE = 0 |
| | | # 未知 |
| | | MARKET_TYPE_UNKNOWN = -1 |
| | | |
| | | |
| | | def get_market_type(code): |
| | | """ |
| | | 根据股票代码 |
| | | :param code: |
| | | :return: |
| | | """ |
| | | if code.find("00") == 0 or code.find("30") == 0 or code.find("12") == 0: |
| | | return MARKET_TYPE_SZSE |
| | | elif code.find("60") == 0 or code.find("68") == 0 or code.find("11") == 0: |
| | | return MARKET_TYPE_SSE |
| | | else: |
| | | return MARKET_TYPE_UNKNOWN |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | pass |