wodepan / ctp_se_15

ctp 期货 穿透式版本

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

pyctp

ctp wrapper for python (期货版)

CTP版本:MdApi().GetApiVersion(), TraderApi().GetApiVersion()

环境:python2.5 ~ python3.4,Windows或者Linux

编译:python setup.py build

安装:python setup.py install或者复制build下的ctp目录到某个sys.path目录。

ctp_se_15

linux 64位 python 2.7.16 64位,测试通过。 windows 64位, python 2.7.16 64 位,测试通过。

行情服务器测试程序:

from ctp15 import ApiStruct, MdApi import time import traceback import copy

ticks = []

class MyMdApi(MdApi): def init(self, instruments, broker_id, investor_id, passwd, *args, **kwargs): self.requestid = 0 self.instruments = instruments self.broker_id = broker_id self.investor_id = investor_id self.passwd = passwd

def OnRspError(self, info, RequestId, IsLast):
    print
    " Error"
    self.isErrorRspInfo(info)

def isErrorRspInfo(self, info):
    if info.ErrorID != 0:
        print
        "ErrorID=", info.ErrorID, ", ErrorMsg=", info.ErrorMsg
    return info.ErrorID != 0

def OnFrontDisConnected(self, reason):
    print
    "onFrontDisConnected:", reason

def OnHeartBeatWarning(self, time):
    print "onHeartBeatWarning", time

def OnFrontConnected(self):
    print "OnFrontConnected:"
    self.user_login(self.broker_id, self.investor_id, self.passwd)

def user_login(self, broker_id, investor_id, passwd):
    req = ApiStruct.ReqUserLogin(BrokerID=broker_id, UserID=investor_id, Password=passwd)

    self.requestid += 1
    r = self.ReqUserLogin(req, self.requestid)

def OnRspUserLogin(self, userlogin, info, rid, is_last):
    print "OnRspUserLogin", is_last, info
    if is_last and not self.isErrorRspInfo(info):
        print "get today's trading day:", repr(self.GetTradingDay())
        self.subscribe_market_data(self.instruments)

def subscribe_market_data(self, instruments):
    self.SubscribeMarketData(instruments)

# def OnRspSubMarketData(self, spec_instrument, info, requestid, islast):
#    print "OnRspSubMarketData"

# def OnRspUnSubMarketData(self, spec_instrument, info, requestid, islast):
#    print "OnRspUnSubMarketData"

def OnRtnDepthMarketData(self, depth_market_data):
    tick = copy.deepcopy(depth_market_data)
    print  tick
    ticks.append(tick)

inst = [u'rb1910', u'rb1905']

def main(): import json

with open(r'connect_ctp.json') as f:
    acctinfo = json.load(f)
    broker_id = acctinfo['brokerID']
    investor_id = acctinfo['userID']
    password = acctinfo['password']
    mdserver = acctinfo['mdAddress']
    tdserver = acctinfo['tdAddress']

    appID = acctinfo['appID']
    authCode = acctinfo['authCode']

user = MyMdApi(instruments=inst,
               broker_id=broker_id,
               investor_id=investor_id,
               passwd=password)
               
user.Create("data")
user.RegisterFront(mdserver)  # simnow std md server

user.Init()
user.Join()

#说明:行情服务器登录,不需要认证。交易服务器才需要

交易服务器登录程序:

encoding:utf-8

import sys import copy import time, datetime import threading import Queue from ctp15 import ApiStruct, TraderApi, MdApi

mutex = threading.Lock() q_depth_market_data = Queue.Queue() q_rtn_trade = Queue.Queue() q_rtn_order = Queue.Queue() q_positions = Queue.Queue() q_server_info = Queue.Queue()

info = []

class MyMdApi(MdApi): def init(self, instruments, broker_id, investor_id, password, *args, **kwargs): self.request_id = 0 self.instruments = instruments self.broker_id = broker_id self.investor_id = investor_id self.password = password

def OnRspError(self, info, request_id, is_last):
    print " Error: " + info

@staticmethod
def is_error_rsp_info(info):
    if info.ErrorID != 0:
        print "ErrorID=", info.ErrorID, ", ErrorMsg=", info.ErrorMsg
    return info.ErrorID != 0

def OnHeartBeatWarning(self, _time):
    print "onHeartBeatWarning", _time

def OnFrontConnected(self):
    print u"connecting to the marketdata server ..."
    self.user_login(self.broker_id, self.investor_id, self.password)

def user_login(self, broker_id, investor_id, password):
    req = ApiStruct.ReqUserLogin(BrokerID=broker_id, UserID=investor_id, Password=password)

    self.request_id += 1
    ret = self.ReqUserLogin(req, self.request_id)

def OnRspUserLogin(self, user_login, info, rid, is_last):
    print "OnRspUserLogin", is_last
    print info

    if is_last and not self.is_error_rsp_info(info):
        # print datetime.datetime.now(), u'行情服务器登录成功。订阅合约', self.instruments
        # print "get today's trading day:", repr(self.GetTradingDay())
        self.subscribe_market_data(self.instruments)

def OnFrontDisconnected(self, nReason):
    """当客户端与交易后台通信连接断开时,该方法被调用。当发生这个情况后,API会自动重新连接,客户端可不做处理。
    @param nReason 错误原因
            0x1001 网络读失败
            0x1002 网络写失败
            0x2001 接收心跳超时
            0x2002 发送心跳失败
            0x2003 收到错误报文
    """
    print datetime.datetime.now(), 'Marketdata server connect interrupted...', nReason

def subscribe_market_data(self, instruments):
    self.SubscribeMarketData(instruments)

def OnRtnDepthMarketData(self, depth_market_data):
    if depth_market_data.Volume > 0:
        q_depth_market_data.put(deepcopy(depth_market_data))

    # print u'行情数据发送:',tick.UpdateTime, tick.InstrumentID, tick.LastPrice

class Trader(TraderApi):

def __init__(self, broker_id, investor_id, password, appid, authcode, productinfo, request_id=1):
    self.request_id = request_id
    self.broker_id = broker_id.encode()
    self.investor_id = investor_id.encode()
    self.password = password.encode()
    self.appid = appid.encode()
    self.authcode = authcode.encode()
    self.productinfo = productinfo
    self.q_order = Queue.Queue()

@staticmethod
def is_error_rsp_info(info):
    # print info
    if info.ErrorID != 0:
        print "ErrorID=", info.ErrorID, ", ErrorMsg=", info.ErrorMsg.decode('gbk')
    return info.ErrorID != 0

def OnRspError(self, pRspInfo, nRequestID, bIsLast):

    self.ErrorRspInfo(pRspInfo, nRequestID)

def ErrorRspInfo(self, info, request_id):
    """
    :param info:
    :return:
    """
    if info.ErrorID != 0:
        print('request_id=%s ErrorID=%d, ErrorMsg=%s',
              request_id, info.ErrorID, info.ErrorMsg.decode('gbk'))
    return info.ErrorID != 0

def OnHeartBeatWarning(self, nTimeLapse):
    """心跳超时警告。当长时间未收到报文时,该方法被调用。
    @param nTimeLapse 距离上次接收报文的时间
    """
    print("on OnHeartBeatWarning time: ", nTimeLapse)

def OnFrontDisconnected(self, nReason):
    print("on FrontDisConnected disconnected", nReason)

def OnFrontConnected(self):
    print('Front connected....')
    req = ApiStruct.ReqAuthenticate(BrokerID=self.broker_id,
                                         UserID=self.investor_id,
                                    UserProductInfo = "client_vnpy",
                                         # Password=self.password,
                                            AppID=self.appid,
                                            AuthCode=self.authcode)

    r=self.ReqAuthenticate(req, self.inc_request_id())
    print(r)
    print('Req Authenticate finished...')
    time.sleep(3)

    # req = ApiStructure.ReqUserLoginField(BrokerID=self.broker_id,
    #                                      UserID=self.investor_id,
    #                                      Password=self.password)
    # self.ReqUserLogin(req, self.request_id)
    # print("trader on front connection")
def OnRspAuthenticate(self, pRspAuthenticateField, pRspInfo, nRequestID, bIsLast):
    print(pRspAuthenticateField.AppType)


    info.append(copy.deepcopy(pRspAuthenticateField))
    print('client authenticate done. Req User login....')
    time.sleep(3)
    req = ApiStruct.ReqUserLogin(BrokerID=self.broker_id,
                                         UserID=self.investor_id,
                                         Password=self.password)
    r=self.ReqUserLogin(req, self.inc_request_id())
    print(r)



def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast):

    print('系统登录完成。user login done.')
    print datetime.datetime.now(), u"登录交易服务器...", bIsLast, pRspInfo.ErrorMsg.decode('gbk')
    print datetime.datetime.now(), 'user_login:', pRspUserLogin
    print datetime.datetime.now(), info
    print datetime.datetime.now(), nRequestID

    q_server_info.put(copy.deepcopy(pRspInfo))

    # print pRspUserLogin

    if bIsLast and not self.is_error_rsp_info(pRspInfo):

        print datetime.datetime.now(), u'交易服务器登录成功。', pRspUserLogin.BrokerID, pRspUserLogin.UserID

        # Logger.info('OnRspUserLogin %s' % is_last)
        req = ApiStruct.SettlementInfoConfirm(BrokerID=self.broker_id, InvestorID=self.investor_id)
        self.ReqSettlementInfoConfirm(req, self.inc_request_id())
        print datetime.datetime.now(), 'SettlementInfo Confirm Requested.'
        print datetime.datetime.now(), "get today's trading day:", repr(self.GetTradingDay())

    else:
        print('something wrong, connect failed....')



    #
    #
    # if pRspInfo.ErrorID != 0:
    #     print("server OnRspUserLogin failed error_id=%s msg:%s",
    #           pRspInfo.ErrorID, pRspInfo.ErrorMsg.decode('gbk'))
    # else:
    #     print("Trader user login successfully")
    #
    #     inv = ApiStruct.QryInvestor(BrokerID=self.broker_id, InvestorID=self.investor_id)
    #
    #     self.ReqQryInvestor(inv, self.inc_request_id())
    #
    #     req = ApiStruct.SettlementInfoConfirm(BrokerID = self.broker_id, InvestorID = self.investor_id)
    #
    #     self.ReqSettlementInfoConfirm(req, self.inc_request_id())
    #     time.sleep(1)

def OnRspSettlementInfoConfirm(self, pSettlementInfoConfirm, pRspInfo, nRequestID, bIsLast):
    print(pSettlementInfoConfirm, pRspInfo)
    """投资者结算结果确认响应"""
    print datetime.datetime.now(), 'pSettlementInfoConfirm: ', pSettlementInfoConfirm
    print datetime.datetime.now(), 'pRspInfo: ', pRspInfo, pRspInfo.ErrorMsg.decode('gbk')
    print datetime.datetime.now(), 'nRequestID: ', nRequestID
    print datetime.datetime.now(), 'bIsLast: ', bIsLast
    # info.append(pSettlementInfoConfirm)
    print(pRspInfo.ErrorMsg.decode("GBK"))

def inc_request_id(self):
    self.request_id += 1
    return self.request_id

def OnRspQryInvestor(self, pInvestor, pRspInfo, nRequestID, bIsLast):
    print(pInvestor, pRspInfo)
    print pInvestor.InvestorName.decode('gbk'), pInvestor.Address.decode('gbk')

def OnRtnOrder(self, pOrder):
    ''' 报单通知
        CTP、交易所接受报单
        Agent中不区分,所得信息只用于撤单
    '''

    q_rtn_order.put(deepcopy(pOrder))
    self.q_order.put(deepcopy(pOrder))

    # print repr(pOrder)

    self.logger.info(u'报单响应,Order=%s' % str(pOrder))
    # print pOrder
    if pOrder.OrderStatus == 'a':
        # CTP接受,但未发到交易所
        # print u'CTP接受Order,但未发到交易所, BrokerID=%s,BrokerOrderSeq = %s,TraderID=%s, OrderLocalID=%s' % (pOrder.BrokerID, pOrder.BrokerOrderSeq, pOrder.TraderID, pOrder.OrderLocalID)
        self.logger.info(u'TD:CTP接受Order,但未发到交易所, BrokerID=%s,BrokerOrderSeq = %s,TraderID=%s, OrderLocalID=%s' % (
            pOrder.BrokerID, pOrder.BrokerOrderSeq, pOrder.TraderID, pOrder.OrderLocalID))
        # self.agent.rtn_order(pOrder)
    else:
        # print u'交易所接受Order,exchangeID=%s,OrderSysID=%s,TraderID=%s, OrderLocalID=%s' % (pOrder.ExchangeID, pOrder.OrderSysID, pOrder.TraderID, pOrder.OrderLocalID)
        self.logger.info(u'TD:交易所接受Order,exchangeID=%s,OrderSysID=%s,TraderID=%s, OrderLocalID=%s' % (
            pOrder.ExchangeID, pOrder.OrderSysID, pOrder.TraderID, pOrder.OrderLocalID))
        # self.agent.rtn_order_exchange(pOrder)
        # self.agent.rtn_order(pOrder)

def OnRtnTrade(self, pTrade):
    '''成交通知'''
    self.logger.info(
        u'TD:成交通知,BrokerID=%s,BrokerOrderSeq = %s,exchangeID=%s,OrderSysID=%s,TraderID=%s, OrderLocalID=%s' % (
            pTrade.BrokerID, pTrade.BrokerOrderSeq, pTrade.ExchangeID, pTrade.OrderSysID, pTrade.TraderID,
            pTrade.OrderLocalID))
    self.logger.info(u'TD:成交回报,Trade=%s' % repr(pTrade))
    pt = deepcopy(pTrade)
    # print u'报单成交:', pt.UserID, pt.InstrumentID, pt.Direction, pt.OffsetFlag, pt.Price
    q_rtn_trade.put(pt)

    # self.agent.rtn_trade(pTrade)

def sendOrder(traderSpi, order):
    global mutex
    mutex.acquire()
    # print order

    traderSpi.ReqOrderInsert(order, traderSpi.inc_request_id())
    # DatabaseController.insert_SendOrder(order)

    # print("sendOrder = " + order.InstrumentID + " dir = " + order.Direction)
    # + " strategy = " + self.__module__)
    # time.sleep(1)
    mutex.release()

def formatOrder(self, inst, direc, open_close, volume, price):

    orderp = ApiStruct.InputOrder(
        InstrumentID=inst,
        Direction=direc,  # ApiStruct.D_Buy or ApiStruct.D_Sell
        OrderRef=str(self.inc_request_id()),
        LimitPrice=price,
        VolumeTotalOriginal=volume,
        OrderPriceType=ApiStruct.OPT_LimitPrice,
        BrokerID=self.broker_id,
        InvestorID=self.investor_id,
        UserID=self.investor_id,
        CombOffsetFlag=open_close,  # OF_Open, OF_Close, OF_CloseToday
        CombHedgeFlag=ApiStruct.HF_Speculation,
        VolumeCondition=ApiStruct.VC_AV,
        MinVolume=1,
        ForceCloseReason=ApiStruct.FCC_NotForceClose,
        IsAutoSuspend=1,
        UserForceClose=0,
        TimeCondition=ApiStruct.TC_GFD
    )
    # print orderp
    return orderp

def PrepareOrder(self, inst, direc, open_close, volume, price):
    order = self.formatOrder(inst, direc, open_close, volume, price)
    # print u'send order:', inst, u'price: ', price, u'amount:', volume
    self.sendOrder(order)

def qryPosition(self, InstrumentID=''):

    self.requestid += 1

    if InstrumentID:
        req = ApiStruct.QryInvestorPosition(BrokerID=self.broker_id, InvestorID=self.investor_id,
                                            InstrumentID=InstrumentID)
    else:
        req = ApiStruct.QryInvestorPosition(BrokerID=self.broker_id, InvestorID=self.investor_id)

    self.ReqQryInvestorPosition(req, self.requestid)

def OnRspQryInvestorPosition(self, pInvestorPosition, pRspInfo, nRequestID, bIsLast):
    # print pInvestorPosition
    if pInvestorPosition is not None:
        q_positions.put(copy.deepcopy(pInvestorPosition))

    # if bIsLast:
    # print pInvestorPosition,'tete'
    # print pRspInfo

def fetch_investor_position_detail(self, instrument_id):
    '''
        获取合约的当前持仓明细,目前没用
    '''
    # logging.info(u'A:获取合约%s的当前持仓..' % (instrument_id,))
    print
    'get posi'
    req = ApiStruct.QryInvestorPositionDetail(BrokerID=self.broker_id, InvestorID=self.investor_id,
                                              InstrumentID=instrument_id)
    self.ReqQryInvestorPositionDetail(req, self.inc_request_id())
    # logging.info(u'A:查询持仓, 函数发出返回值:%s' % r)

def fetch_instrument_marginrate(self, instrument_id):
    req = ApiStruct.QryInstrumentMarginRate(BrokerID=self.cuser.broker_id,
                                            InvestorID=self.cuser.investor_id,
                                            InstrumentID=instrument_id,
                                            HedgeFlag=ApiStruct.HF_Speculation
                                            )
    r = self.trader.ReqQryInstrumentMarginRate(req, self.inc_request_id())
    logging.info(u'A:查询保证金率, 函数发出返回值:%s' % r)

def fetch_instrument(self, instrument_id):
    req = ApiStruct.QryInstrument(
        InstrumentID=instrument_id,
    )
    time.sleep(1)
    r = self.trader.ReqQryInstrument(req, self.inc_request_id())
    logging.info(u'A:查询合约, 函数发出返回值:%s' % r)

def rsp_qry_position(self, position):
    '''
        查询持仓回报, 每个合约最多得到4个持仓回报,历史多/空、今日多/空
    '''
    logging.info(u'agent 持仓:%s' % str(position))
    if position != None:
        cur_position = self.instruments[position.InstrumentID].position
        if position.PosiDirection == ApiStruct.PD_Long:
            if position.PositionDate == ApiStruct.PSD_Today:
                cur_position.clong = position.Position  # TodayPosition
            else:
                cur_position.hlong = position.Position  # YdPosition
        else:  # 空头
            if position.PositionDate == ApiStruct.PSD_Today:
                cur_position.cshort = position.Position  # TodayPosition
            else:
                cur_position.hshort = position.Position  # YdPosition
    else:  # 无持仓信息,保持默认设置
        pass
    self.check_qry_commands()

def rsp_qry_instrument_marginrate(self, marginRate):
    '''
        查询保证金率回报.
    '''
    self.instruments[marginRate.InstrumentID].marginrate = (
        marginRate.LongMarginRatioByMoney, marginRate.ShortMarginRatioByMoney)
    # print marginRate.InstrumentID,self.instruments[marginRate.InstrumentID].marginrate
    self.check_qry_commands()

def rsp_qry_trading_account(self, account):
    '''
        查询资金帐户回报
    '''
    self.available = account.Available
    self.check_qry_commands()

def rsp_qry_instrument(self, pinstrument):
    '''
        获得合约数量乘数.
        这里的保证金率应该是和期货公司无关,所以不能使用
    '''
    if pinstrument.InstrumentID not in self.instruments:
        logging.warning(u'A_RQI:收到未监控的合约查询:%s' % (pinstrument.InstrumentID))
        return
    self.instruments[pinstrument.InstrumentID].multiple = pinstrument.VolumeMultiple
    self.instruments[pinstrument.InstrumentID].tick_base = int(pinstrument.PriceTick * 10 + 0.1)
    # print 'tick_base = %s' % (pinstrument.PriceTick,)
    self.check_qry_commands()

def rsp_qry_position_detail(self, position_detail):
    '''
        查询持仓明细回报, 得到每一次成交的持仓,其中若已经平仓,则持量为0,平仓量>=1
        必须忽略
    '''
    print
    str(position_detail)
    self.check_qry_commands()

def rsp_qry_order(self, sorder):
    '''
        查询报单
        可以忽略
    '''
    self.check_qry_commands()

def rsp_qry_trade(self, strade):
    '''
        查询成交
        可以忽略
    '''
    self.check_qry_commands()

def main(): import json

with open(r'connect_ctp.json') as f:
    acctinfo = json.load(f)
    broker_id = acctinfo['brokerID']
    investor_id = acctinfo['userID']
    password = acctinfo['password']
    mdsever = acctinfo['mdAddress']
    tdserver = acctinfo['tdAddress']
    appID = acctinfo['appID']
    authCode = acctinfo['authCode']
    productinfo = acctinfo['productinfo']






td = Trader(broker_id=broker_id, investor_id=investor_id, password=password, appid=appID, authcode=authCode, productinfo = productinfo)

td.Create('data_p')
td.RegisterFront(tdserver)
td.SubscribePrivateTopic(2) # 只传送登录后的流内容
td.SubscribePrivateTopic(2) # 只传送登录后的流内容

td.Init()

print(td.GetTradingDay())




while True:
    if info:
        for i in info:
            print(i)

    time.sleep(5)

if name == "main": main()

About

ctp 期货 穿透式版本


Languages

Language:Python 39.2%Language:C++ 31.3%Language:C 29.5%