diff --git a/.gitignore b/.gitignore index cb93bd44..744e22d8 100644 --- a/.gitignore +++ b/.gitignore @@ -37,8 +37,23 @@ Release/ # 其他文件 *.dump *.vssettings +<<<<<<< HEAD vnpy.pyproj.user .idea/workspace.xml .idea/.name .idea/vnpy.iml -*.xml \ No newline at end of file +*.xml +======= + +<<<<<<< HEAD +# 不想同步的 +*.local +======= +vn.ctp/build/* +vn.lts/build/* +.idea +>>>>>>> 65aac25731772259bf2d4049e7adbe92750ea01d +>>>>>>> refs/remotes/vnpy/master +*.json +*.json +*.json diff --git a/vn.ctp/CMakeLists.txt b/vn.ctp/CMakeLists.txt new file mode 100644 index 00000000..9392bbe1 --- /dev/null +++ b/vn.ctp/CMakeLists.txt @@ -0,0 +1,74 @@ +cmake_minimum_required(VERSION 2.8) +project(vn_ctp_api) + +set(CMAKE_BUILD_TYPE "Release") +if (CMAKE_COMPILER_IS_GNUC OR CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++11") +endif () + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) + +option(USE_64BITS "comiple 64bits" ON) +if (USE_64BITS) + add_definitions(-DUSE_64BITS) + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") +endif() + +set(CTPAPI_PATH ctpapi) +include_directories(${CTPAPI_PATH}) +set(CTPAPI_LIBRARY ) +find_library(CTPAPI_MD_LIBRARY + NAMES thostmduserapi + PATHS ${CTPAPI_PATH}) +find_library(CTPAPI_TD_LIBRARY + NAMES thosttraderapi + PATHS ${CTPAPI_PATH}) + +set (vnctpmd ) +set (vnctptd ) + +option(BUILD_CTP_MD "build ctp md" ON) +if (BUILD_CTP_MD) + add_definitions(-DBUILD_CTP_MD) + set(CTP_MD_PATH vnctpmd/vnctpmd) + include_directories(CTP_MD_PATH) + set(VN_CTP_MD_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/vnctpmd/vnctpmd/vnctpmd.cpp) + add_library(vnctpmd SHARED ${VN_CTP_MD_SOURCE}) +endif() +option(BUILD_CTP_TD "build ctp td" ON) +if (BUILD_CTP_TD) + add_definitions(-DBUILD_CTP_MD) + set(CTP_TD_PATH vnctptd/vnctptd) + include_directories(CTP_TD_PATH) + set(VN_CTP_TD_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/vnctptd/vnctptd/vnctptd.cpp) + add_library(vnctptd SHARED ${VN_CTP_TD_SOURCE}) +endif() + + +set(PYTHON_INCLUDE_PATH C:/Python27/include) +set(PYTHON_LIBRARY ) +find_library(PYTHON_LIBRARY + NAMES python27 + PATHS C:/Python27/libs) +include_directories(${PYTHON_INCLUDE_PATH}) + +# 链接boost库,anaconda +set(Boost_USE_STATIC_LIBS ON) #链接boost静态库 +set(Boost_USE_MULTITHREADED ON) +find_package(Boost 1.57.0 COMPONENTS python thread date_time system chrono REQUIRED) # 如果boost库没有完全编译,需要将编译的库明确地指出,否者message(${Boost_LIBRARIES})会出错 +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) +endif() + +target_link_libraries(vnctpmd ${Boost_LIBRARIES} ${PYTHON_LIBRARY} ${CTPAPI_MD_LIBRARY}) +set(MD_DLL "${LIBRARY_OUTPUT_PATH}/Release/vnctpmd.dll") +if (EXISTS ${MD_DLL}) + file(RENAME ${MD_DLL} ${LIBRARY_OUTPUT_PATH}/Release/vnctpmd.pyd) +endif() +target_link_libraries(vnctptd ${Boost_LIBRARIES} ${PYTHON_LIBRARY} ${CTPAPI_TD_LIBRARY}) +set(TD_DLL ${LIBRARY_OUTPUT_PATH}/Release/vnctptd.dll) +if (EXISTS ${TD_DLL}) + file(RENAME ${TD_DLL} ${LIBRARY_OUTPUT_PATH}/Release/vnctptd.pyd) +endif() diff --git a/vn.ctp/readme.md b/vn.ctp/readme.md new file mode 100644 index 00000000..6ad7996d --- /dev/null +++ b/vn.ctp/readme.md @@ -0,0 +1,30 @@ +# Ŀ¼DZCTP +--------------------- + +# Ŀ¼˵ +------------ +## vnctpmd: API + +# +---------- + +* 鰲װλϱһ£ȫװ32λͬʱ32λ +* cmake:װ°汾cmake,ñ뻷 +* [Boost1.57.0](http://sourceforge.net/projects/boost/files/boost/1.57.0/)⣺ķԲο[Boost Getting Started](http://www.boost.org/doc/libs/1_58_0/more/getting_started/)½ǵ +** ûeg: BOOST_ROOT = C:\boost_1_57_0 +** 32λ⻹64λѡ +** Ҫboost python, thread, system, chrono, date_time5⣺ȫ˷ѴʱӲ̿ռ䡣 +** boost pythonĶ̬64bitsܱ벻ɹѡaddress-model=64߱뾲̬ + +* [Anaconda1.9.2](http://repo.continuum.io/archive/index.html): ذPythonа +* 빤ߣwindowsѡvisual studio 2013linuxʹg++ + +# +------------- + +* vn.ctpĿ¼½ļУΪbuild, ʱļļ +* й룺cmake-gui .. cmakeý +* configure +* generateûдóɹ +* buildĿ¼˫vn_ctp_api.sln򿪽 +* 밴ť,release diff --git a/vn.data/mysqldb.sql b/vn.data/mysqldb.sql index b465e40a..96cf1c46 100644 --- a/vn.data/mysqldb.sql +++ b/vn.data/mysqldb.sql @@ -14,7 +14,7 @@ CREATE TABLE `TB_Trade` ( `fee` float DEFAULT '0', `profit` float DEFAULT '0', `profitRate` float DEFAULT '0' -) +) create table TB_Bar ( diff --git a/vn.datayes/api.py b/vn.datayes/api.py index a2f74e04..667df21f 100644 --- a/vn.datayes/api.py +++ b/vn.datayes/api.py @@ -39,8 +39,7 @@ class Config(object): toke_ = '44ebc0f058981f85382595f9f15f967' + \ '0c7eaf2695de30dd752e8f33e9022baa0' - token = '7c2e59e212dbff90ffd6b382c7afb57' + \ - 'bc987a99307d382b058af6748f591d723' + token = '575593eb7696aec7339224c0fac2313780d8645f68b77369dcb35f8bcb419a0b' body = { 'ssl': False, diff --git a/vn.datayes/tests.py b/vn.datayes/tests.py index 979dd4f6..452a8159 100644 --- a/vn.datayes/tests.py +++ b/vn.datayes/tests.py @@ -101,7 +101,7 @@ def test_mktbar_M1_get_interM(): if __name__ == '__main__': #test_config() - #test_mktbar_D1() + test_mktbar_D1() #test_bond_D1() #test_fut_D1() #test_fund_D1() @@ -116,4 +116,4 @@ if __name__ == '__main__': #test_mongod_get_all() #test_mktbar_M1_get_drudgery() #test_mktbar_M1_get_all() - test_mktbar_M1_get_interM() \ No newline at end of file + #test_mktbar_M1_get_interM() \ No newline at end of file diff --git a/vn.lts/vnltstd/test/vnltstd.pyd b/vn.lts/vnltstd/test/vnltstd.pyd index 7b548cda..3fe5e236 100644 Binary files a/vn.lts/vnltstd/test/vnltstd.pyd and b/vn.lts/vnltstd/test/vnltstd.pyd differ diff --git a/vn.lts/vnltstd/vnltstd/vnltstd.cpp b/vn.lts/vnltstd/vnltstd/vnltstd.cpp index 791d9105..ba301ea7 100644 --- a/vn.lts/vnltstd/vnltstd/vnltstd.cpp +++ b/vn.lts/vnltstd/vnltstd/vnltstd.cpp @@ -1414,7 +1414,7 @@ int TdApi::reqOrderInsert(dict req, int nRequestID) CSecurityFtdcInputOrderField myreq = CSecurityFtdcInputOrderField(); memset(&myreq, 0, sizeof(myreq)); getChar(req, "ContingentCondition", &myreq.ContingentCondition); - getChar(req, "CombOffsetFlag", myreq.CombOffsetFlag); + //getChar(req, "CombOffsetFlag", myreq.CombOffsetFlag); getChar(req, "UserID", myreq.UserID); getChar(req, "LimitPrice", myreq.LimitPrice); getInt(req, "UserForceClose", &myreq.UserForceClose); @@ -1436,6 +1436,19 @@ int TdApi::reqOrderInsert(dict req, int nRequestID) getInt(req, "RequestID", &myreq.RequestID); getChar(req, "Direction", &myreq.Direction); + //CombOffsetFlag + if (req.has_key("CombOffsetFlag")) + { + object o2 = req["CombOffsetFlag"]; + extract x2(o2); + if (x2.check()) + { + string s2 = x2(); + const char *buffer2 = s2.c_str(); + myreq.CombOffsetFlag[0] = *buffer2; + } + } + int i = this->api->ReqOrderInsert(&myreq, nRequestID); return i; }; diff --git a/vn.trader/CTA_setting.json b/vn.trader/CTA_setting.json new file mode 100644 index 00000000..3e8805eb --- /dev/null +++ b/vn.trader/CTA_setting.json @@ -0,0 +1,14 @@ +{ + "Test1": { + "strategyClassName": "TestStrategy", + "vtSymbol": "IF1511" + }, + "Test3": { + "strategyClassName": "TestStrategy", + "vtSymbol": "IF1512" + }, + "Test2": { + "strategyClassName": "TestStrategy", + "vtSymbol": "IH1511" + } +} \ No newline at end of file diff --git a/vn.trader/CTP_connect.json b/vn.trader/CTP_connect.json index ede15644..8cebe175 100644 --- a/vn.trader/CTP_connect.json +++ b/vn.trader/CTP_connect.json @@ -1,7 +1,13 @@ { "brokerID": "9999", "tdAddress": "tcp://180.168.146.187:10000", +<<<<<<< HEAD "password": "19890624", "mdAddress": "tcp://180.168.212.228:41213", "userID": "000300" +======= + "password": "simnow申请", + "mdAddress": "tcp://180.168.212.228:41213", + "userID": "simnow申请" +>>>>>>> refs/remotes/vnpy/master } \ No newline at end of file diff --git a/vn.trader/IB_connect.json b/vn.trader/IB_connect.json new file mode 100644 index 00000000..f911cc5b --- /dev/null +++ b/vn.trader/IB_connect.json @@ -0,0 +1,5 @@ +{ + "host": "localhost", + "port": 7496, + "clientId": 888 +} \ No newline at end of file diff --git a/vn.trader/LTS_connect.json b/vn.trader/LTS_connect.json index c1fd187c..04b43df0 100644 --- a/vn.trader/LTS_connect.json +++ b/vn.trader/LTS_connect.json @@ -5,7 +5,13 @@ "mdAddress": "tcp://211.144.195.163:54513", "productInfo": "LTS-Test", "authCode": "N3EHKP4CYHZGM9VJ", +<<<<<<< HEAD "tdPassword": "150601", "mdPassword": "123", "userID": "020090002037" +======= + "tdPassword": "华宝证券申请", + "mdPassword": "华宝证券申请", + "userID": "华宝证券申请" +>>>>>>> refs/remotes/vnpy/master } \ No newline at end of file diff --git a/vn.trader/ctaEngine.py b/vn.trader/ctaEngine.py index 2dc54524..7bd733f1 100644 --- a/vn.trader/ctaEngine.py +++ b/vn.trader/ctaEngine.py @@ -6,7 +6,11 @@ from collections import OrderedDict from eventEngine import * from vtConstant import * +<<<<<<< HEAD from vtGateway import VtOrderReq, VtCancelOrderReq +======= +from vtGateway import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData +>>>>>>> refs/remotes/vnpy/master from ctaConstant import * from ctaStrategies import strategyClassDict @@ -137,6 +141,12 @@ class CtaEngine(object): self.stopOrderDict = {} # 停止单撤销后不会从本字典中删除 self.workingStopOrderDict = {} # 停止单撤销后会从本字典中删除 +<<<<<<< HEAD +======= + # 注册事件监听 + self.registerEvent() + +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def sendOrder(self, vtSymbol, orderType, price, volume, strategy): """发单""" @@ -243,8 +253,14 @@ class CtaEngine(object): del self.workingStopOrderDict[so.stopOrderID] #---------------------------------------------------------------------- +<<<<<<< HEAD def procecssTick(self, tick): """处理行情推送""" +======= + def procecssTickEvent(self, event): + """处理行情推送""" + tick = event.dict_['data'] +>>>>>>> refs/remotes/vnpy/master # 收到tick行情后,先处理本地停止单(检查是否要立即发出) self.processStopOrder(tick) @@ -254,7 +270,12 @@ class CtaEngine(object): ctaTick = CtaTickData() d = ctaTick.__dict__ for key in d.keys(): +<<<<<<< HEAD d[key] = tick.__getattribute__(key) +======= + if key != 'datetime': + d[key] = tick.__getattribute__(key) +>>>>>>> refs/remotes/vnpy/master # 添加datetime字段 ctaTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') @@ -264,15 +285,29 @@ class CtaEngine(object): strategy.onTick(tick) #---------------------------------------------------------------------- +<<<<<<< HEAD def processOrder(self, order): """处理委托推送""" +======= + def processOrderEvent(self, event): + """处理委托推送""" + order = event.dict_['data'] + +>>>>>>> refs/remotes/vnpy/master if order.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[order.vtOrderID] strategy.onOrder(order) #---------------------------------------------------------------------- +<<<<<<< HEAD def processTrade(self, trade): """处理成交推送""" +======= + def processTradeEvent(self, event): + """处理成交推送""" + trade = event.dict_['data'] + +>>>>>>> refs/remotes/vnpy/master if trade.vtOrderID in self.orderStrategyDict: strategy = self.orderStrategyDict[order.vtOrderID] strategy.onTrade(trade) @@ -280,9 +315,15 @@ class CtaEngine(object): #---------------------------------------------------------------------- def registerEvent(self): """注册事件监听""" +<<<<<<< HEAD self.eventEngine.register(EVENT_TICK, self.procecssTick) self.eventEngine.register(EVENT_ORDER, self.processOrder) self.eventEngine.register(EVENT_TRADE, self.processTrade) +======= + self.eventEngine.register(EVENT_TICK, self.procecssTickEvent) + self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) + self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): @@ -338,7 +379,29 @@ class CtaEngine(object): """初始化策略""" # 防止策略重名 if name not in self.strategyDict: +<<<<<<< HEAD self.strategyDict[name] = strategyClass(self, paramDict) # 创建策略对象 +======= + # 创建策略对象 + strategy = strategyClass(self, name, paramDict) + self.strategyDict[name] = strategy + + # 保存Tick映射关系 + if strategy.vtSymbol in self.tickStrategyDict: + l = self.tickStrategyDict[strategy.vtSymbol] + else: + l = [] + self.tickStrategyDict[strategy.vtSymbol] = l + l.append(strategy) + + # 订阅合约 + contract = self.dataEngine.getContract(strategy.vtSymbol) + if contract: + req = VtSubscribeReq() + req.symbol = contract.symbol + req.exchange = contract.exchange + self.mainEngine.subscribe(req, contract.gatewayName) +>>>>>>> refs/remotes/vnpy/master else: self.writeCtaLog(u'存在策略对象重名:' + name) @@ -409,7 +472,11 @@ class CtaEngine(object): break #---------------------------------------------------------------------- +<<<<<<< HEAD def getStrategyVarialbe(self, name): +======= + def getStrategyVar(self, name): +>>>>>>> refs/remotes/vnpy/master """获取策略当前的变量字典""" if name in self.strategyDict: strategy = self.strategyDict[name] @@ -426,11 +493,16 @@ class CtaEngine(object): return None #---------------------------------------------------------------------- +<<<<<<< HEAD def getStrategyParameter(self, name): +======= + def getStrategyParam(self, name): +>>>>>>> refs/remotes/vnpy/master """获取策略的参数字典""" if name in self.strategyDict: strategy = self.strategyDict[name] d = strategy.__dict__ +<<<<<<< HEAD varDict = OrderedDict() for key in strategy.paramList: @@ -438,6 +510,15 @@ class CtaEngine(object): varDict[key] = d[key] return varDict +======= + paramDict = OrderedDict() + + for key in strategy.paramList: + if key in d: + paramDict[key] = d[key] + + return paramDict +>>>>>>> refs/remotes/vnpy/master else: self.writeCtaLog(u'策略对象不存在:' + name) return None diff --git a/vn.trader/ctaStrategies.py b/vn.trader/ctaStrategies.py index 0c5caf4a..3e4c692d 100644 --- a/vn.trader/ctaStrategies.py +++ b/vn.trader/ctaStrategies.py @@ -4,4 +4,11 @@ 在本文件中引入所有希望在系统中使用的策略类 ''' -strategyClassDict = {} \ No newline at end of file +<<<<<<< HEAD +strategyClassDict = {} +======= +from ctaStrategyTemplate import TestStrategy + +strategyClassDict = {} +strategyClassDict[u'TestStrategy'] = TestStrategy +>>>>>>> refs/remotes/vnpy/master diff --git a/vn.trader/ctaStrategyTemplate.py b/vn.trader/ctaStrategyTemplate.py index 549cf45f..f3056b96 100644 --- a/vn.trader/ctaStrategyTemplate.py +++ b/vn.trader/ctaStrategyTemplate.py @@ -1,5 +1,9 @@ # encoding: UTF-8 +<<<<<<< HEAD +======= +from vtConstant import * +>>>>>>> refs/remotes/vnpy/master from ctaConstant import * @@ -13,12 +17,22 @@ class CtaStrategyTemplate(object): paramList = ['vtSymbol'] # 变量列表,保存了变量的名称 +<<<<<<< HEAD varList = [] #---------------------------------------------------------------------- def __init__(self, ctaEngine, setting=None): """Constructor""" self.ctaEngine = ctaEngine +======= + varList = ['trading'] + + #---------------------------------------------------------------------- + def __init__(self, ctaEngine, name, setting=None): + """Constructor""" + self.ctaEngine = ctaEngine + self.name = name +>>>>>>> refs/remotes/vnpy/master self.vtSymbol = EMPTY_STRING # 交易的合约vt系统代码 @@ -153,12 +167,86 @@ class CtaStrategyTemplate(object): d = self.__dict__ for key in self.paramList: if key in setting: +<<<<<<< HEAD d[key] = paramDict[key] +======= + d[key] = setting[key] +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def getToday(self): """查询当前日期""" return self.ctaEngine.getToday() +<<<<<<< HEAD +======= + #---------------------------------------------------------------------- + def writeCtaLog(self, content): + """记录CTA日志""" + self.ctaEngine.writeCtaLog(content) + + + +######################################################################## +class TestStrategy(CtaStrategyTemplate): + """测试策略""" + + #---------------------------------------------------------------------- + def __init__(self, ctaEngine, name, setting=None): + """Constructor""" + super(TestStrategy, self).__init__(ctaEngine, name, setting) + + self.strategyClassName = 'TestStrategy' + + self.author = u'用Python的交易员' # 作者 + + self.pos = EMPTY_INT # 持仓 + self.lastPrice = EMPTY_FLOAT # 最新价 + + # 参数和变量列表设置 + self.paramList.append(u'author') + + self.varList.append('pos') + self.varList.append('lastPrice') + + #---------------------------------------------------------------------- + def init(self): + """初始化策略(必须由用户继承实现)""" + self.writeCtaLog(u'测试策略%s初始化' %self.name) + + #---------------------------------------------------------------------- + def start(self): + """启动策略(必须由用户继承实现)""" + self.writeCtaLog(u'测试策略%s启动' %self.name) + + #---------------------------------------------------------------------- + def stop(self): + """停止策略(必须由用户继承实现)""" + self.writeCtaLog(u'测试策略%s停止' %self.name) + + #---------------------------------------------------------------------- + def onTick(self, tick): + """收到行情TICK推送(必须由用户继承实现)""" + self.writeCtaLog(u'测试策略%s收到Tick' %self.name) + self.lastPrice = tick.lastPrice + + #---------------------------------------------------------------------- + def onOrder(self, order): + """收到委托变化推送(必须由用户继承实现)""" + self.writeCtaLog(u'onOrder不会被调用') + + #---------------------------------------------------------------------- + def onTrade(self, trade): + """收到成交推送(必须由用户继承实现)""" + self.writeCtaLog(u'onTrade不会被调用') + + #---------------------------------------------------------------------- + def onBar(self, bar): + """收到Bar推送(必须由用户继承实现)""" + self.writeCtaLog(u'测试策略%s收到Bar' %self.name) + + + +>>>>>>> refs/remotes/vnpy/master \ No newline at end of file diff --git a/vn.trader/ctpGateway.py b/vn.trader/ctpGateway.py index edd06025..02156886 100644 --- a/vn.trader/ctpGateway.py +++ b/vn.trader/ctpGateway.py @@ -384,7 +384,14 @@ class CtpMdApi(MdApi): #---------------------------------------------------------------------- def subscribe(self, subscribeReq): """订阅合约""" +<<<<<<< HEAD self.subscribeMarketData(str(subscribeReq.symbol)) +======= + # 这里的设计是,如果尚未登录就调用了订阅方法 + # 则先保存订阅请求,登录完成后会自动订阅 + if self.loginStatus: + self.subscribeMarketData(str(subscribeReq.symbol)) +>>>>>>> refs/remotes/vnpy/master self.subscribedSymbols.add(subscribeReq) #---------------------------------------------------------------------- diff --git a/vn.trader/ibGateway.py b/vn.trader/ibGateway.py new file mode 100644 index 00000000..aa66beea --- /dev/null +++ b/vn.trader/ibGateway.py @@ -0,0 +1,608 @@ +# encoding: UTF-8 + +''' +ibpy的gateway接入 + +注意事项: +1. ib api只能获取和操作当前连接后下的单,并且每次重启程序后,之前下的单子收不到 +2. ib api的成交也只会推送当前连接后的成交 +3. ib api的持仓和账户更新可以订阅成主推模式,因此getAccount和getPosition就用不到了 +4. 目前只支持股票和期货交易,ib api里期权合约的确定是基于Contract对象的多个字段,比较复杂暂时没做 +5. 海外市场的交易规则和国内有很多细节上的不同,所以一些字段类型的映射可能不合理,如果发现问题欢迎指出 +''' + +import json +from time import sleep, strftime, localtime +from copy import copy + +from PyQt4 import QtGui, QtCore + +from ib.ext.Contract import Contract +from ib.ext.Order import Order +from ib.ext.EWrapper import EWrapper +from ib.ext.EClientSocket import EClientSocket + +from vtGateway import * + + +# 以下为一些VT类型和CTP类型的映射字典 +# 价格类型映射 +priceTypeMap = {} +priceTypeMap[PRICETYPE_LIMITPRICE] = 'LMT' +priceTypeMap[PRICETYPE_MARKETPRICE] = 'MKT' +priceTypeMapReverse = {v: k for k, v in priceTypeMap.items()} + +# 方向类型映射 +directionMap = {} +directionMap[DIRECTION_LONG] = 'BUY' +directionMap[DIRECTION_SHORT] = 'SSHORT' +directionMap[DIRECTION_SELL] = 'SELL' +directionMapReverse = {v: k for k, v in directionMap.items()} +directionMapReverse['BOT'] = DIRECTION_LONG +directionMapReverse['SLD'] = DIRECTION_SHORT + +# 交易所类型映射 +exchangeMap = {} +exchangeMap[EXCHANGE_SMART] = 'SMART' +exchangeMap[EXCHANGE_GLOBEX] = 'GLOBEX' +exchangeMap[EXCHANGE_IDEALPRO] = 'IDEALPRO' +exchangeMapReverse = {v:k for k,v in exchangeMap.items()} + +# 报单状态映射 +orderStatusMap = {} +orderStatusMap[STATUS_NOTTRADED] = 'Submitted' +orderStatusMap[STATUS_ALLTRADED] = 'Filled' +orderStatusMap[STATUS_CANCELLED] = 'Cancelled' +orderStatusMapReverse = {v:k for k,v in orderStatusMap.items()} +orderStatusMapReverse['PendingSubmit'] = STATUS_UNKNOWN # 这里未来视乎需求可以拓展vt订单的状态类型 +orderStatusMapReverse['PendingCancel'] = STATUS_UNKNOWN +orderStatusMapReverse['PreSubmitted'] = STATUS_UNKNOWN +orderStatusMapReverse['Inactive'] = STATUS_UNKNOWN + +# 合约类型映射 +productClassMap = {} +productClassMap[PRODUCT_EQUITY] = 'STK' +productClassMap[PRODUCT_FUTURES] = 'FUT' +productClassMap[PRODUCT_OPTION] = 'OPT' +productClassMap[PRODUCT_FOREX] = 'CASH' + +# 期权类型映射 +optionTypeMap = {} +optionTypeMap[OPTION_CALL] = 'CALL' +optionTypeMap[OPTION_PUT] = 'PUT' +optionTypeMap = {v:k for k,v in optionTypeMap.items()} + +# 货币类型映射 +currencyMap = {} +currencyMap[CURRENCY_USD] = 'USD' +currencyMap[CURRENCY_CNY] = 'CNY' +currencyMap = {v:k for k,v in currencyMap.items()} + +# Tick数据的Field和名称映射 +tickFieldMap = {} +tickFieldMap[0] = 'bidVolume1' +tickFieldMap[1] = 'bidPrice1' +tickFieldMap[2] = 'askPrice1' +tickFieldMap[3] = 'askVolume1' +tickFieldMap[4] = 'lastPrice' +tickFieldMap[5] = 'lastVolume' +tickFieldMap[6] = 'highPrice' +tickFieldMap[7] = 'lowPrice' +tickFieldMap[8] = 'volume' +tickFieldMap[14] = 'openPrice' +tickFieldMap[20] = 'openInterest' + +# Account数据Key和名称的映射 +accountKeyMap = {} +accountKeyMap['NetLiquidationByCurrency'] = 'balance' +accountKeyMap['NetLiquidation'] = 'balance' +accountKeyMap['UnrealizedPnL'] = 'positionProfit' +accountKeyMap['AvailableFunds'] = 'available' +accountKeyMap['MaintMarginReq'] = 'margin' + + +######################################################################## +class IbGateway(VtGateway): + """IB接口""" + + #---------------------------------------------------------------------- + def __init__(self, eventEngine, gatewayName='IB'): + """Constructor""" + super(IbGateway, self).__init__(eventEngine, gatewayName) + + self.host = EMPTY_STRING # 连接地址 + self.port = EMPTY_INT # 连接端口 + self.clientId = EMPTY_INT # 用户编号 + + self.tickerId = 0 # 订阅行情时的代码编号 + self.tickDict = {} # tick快照字典,key为tickerId,value为VtTickData对象 + + self.orderId = 0 # 订单编号 + self.orderDict = {} # 报单字典,key为orderId,value为VtOrderData对象 + + self.accountDict = {} # 账户字典 + + self.connected = False # 连接状态 + + self.wrapper = IbWrapper(self) # 回调接口 + self.connection = EClientSocket(self.wrapper) # 主动接口 + + #---------------------------------------------------------------------- + def connect(self): + """连接""" + # 载入json文件 + fileName = self.gatewayName + '_connect.json' + try: + f = file(fileName) + except IOError: + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = u'读取连接配置出错,请检查' + self.onLog(log) + return + + # 解析json文件 + setting = json.load(f) + try: + self.host = str(setting['host']) + self.port = int(setting['port']) + self.clientId = int(setting['clientId']) + except KeyError: + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = u'连接配置缺少字段,请检查' + self.onLog(log) + return + + # 发起连接 + self.connection.eConnect(self.host, self.port, self.clientId) + + # 查询服务器时间 + self.connection.reqCurrentTime() + + # 请求账户数据主推更新 + self.connection.reqAccountUpdates(True, '') + + #---------------------------------------------------------------------- + def subscribe(self, subscribeReq): + """订阅行情""" + # 订阅行情 + self.tickerId += 1 + + contract = Contract() + contract.m_symbol = str(subscribeReq.symbol) + contract.m_exchange = exchangeMap.get(subscribeReq.exchange, '') + contract.m_secType = productClassMap.get(subscribeReq.productClass, '') + contract.m_currency = currencyMap.get(subscribeReq.currency, '') + contract.m_expiry = subscribeReq.expiry + contract.m_strike = subscribeReq.strikePrice + contract.m_right = optionTypeMap.get(subscribeReq.optionType, '') + + self.connection.reqMktData(self.tickerId, contract, '', False) + + # 创建Tick对象并保存到字典中 + tick = VtTickData() + tick.symbol = subscribeReq.symbol + tick.exchange = subscribeReq.exchange + tick.vtSymbol = '.'.join([tick.symbol, tick.exchange]) + tick.gatewayName = self.gatewayName + self.tickDict[self.tickerId] = tick + + #---------------------------------------------------------------------- + def sendOrder(self, orderReq): + """发单""" + # 增加报单号1,最后再次进行查询 + # 这里双重设计的目的是为了防止某些情况下,连续发单时,nextOrderId的回调推送速度慢导致没有更新 + self.orderId += 1 + + # 创建合约对象 + contract = Contract() + contract.m_symbol = str(orderReq.symbol) + contract.m_exchange = exchangeMap.get(orderReq.exchange, '') + contract.m_secType = productClassMap.get(orderReq.productClass, '') + contract.m_currency = currencyMap.get(orderReq.currency, '') + + contract.m_expiry = orderReq.expiry + contract.m_strike = orderReq.strikePrice + contract.m_right = optionTypeMap.get(orderReq.optionType, '') + + # 创建委托对象 + order = Order() + order.m_orderId = self.orderId + order.m_clientId = self.clientId + + order.m_action = directionMap.get(orderReq.direction, '') + order.m_lmtPrice = orderReq.price + order.m_totalQuantity = orderReq.volume + order.m_orderType = priceTypeMap.get(orderReq.priceType, '') + + # 发送委托 + self.connection.placeOrder(self.orderId, contract, order) + + # 查询下一个有效编号 + self.connection.reqIds(1) + + #---------------------------------------------------------------------- + def cancelOrder(self, cancelOrderReq): + """撤单""" + self.connection.cancelOrder(cancelOrderReq.orderID) + + #---------------------------------------------------------------------- + def getAccount(self): + """查询账户资金""" + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = u'IB接口账户信息提供主推更新,无需查询' + self.onLog(log) + + #---------------------------------------------------------------------- + def getPosition(self): + """查询持仓""" + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = u'IB接口持仓信息提供主推更新,无需查询' + self.onLog(log) + + #---------------------------------------------------------------------- + def close(self): + """关闭""" + self.connection.eDisconnect() + + +######################################################################## +class IbWrapper(EWrapper): + """IB回调接口的实现""" + + #---------------------------------------------------------------------- + def __init__(self, gateway): + """Constructor""" + super(IbWrapper, self).__init__() + + self.connectionStatus = False # 连接状态 + + self.gateway = gateway # gateway对象 + self.gatewayName = gateway.gatewayName # gateway对象名称 + + self.tickDict = gateway.tickDict # tick快照字典,key为tickerId,value为VtTickData对象 + self.orderDict = gateway.orderDict # order字典 + self.accountDict = gateway.accountDict # account字典 + + #---------------------------------------------------------------------- + def tickPrice(self, tickerId, field, price, canAutoExecute): + """行情推送(价格相关)""" + if field in tickFieldMap: + tick = self.tickDict[tickerId] + key = tickFieldMap[field] + tick.__setattr__(key, price) + else: + print field + + #---------------------------------------------------------------------- + def tickSize(self, tickerId, field, size): + """行情推送(量相关)""" + if field in tickFieldMap: + tick = self.tickDict[tickerId] + key = tickFieldMap[field] + tick.__setattr__(key, size) + else: + print field + + #---------------------------------------------------------------------- + def tickOptionComputation(self, tickerId, field, impliedVol, delta, optPrice, pvDividend, gamma, vega, theta, undPrice): + """行情推送(期权数值)""" + pass + + #---------------------------------------------------------------------- + def tickGeneric(self, tickerId, tickType, value): + """行情推送(某些通用字段)""" + pass + + #---------------------------------------------------------------------- + def tickString(self, tickerId, tickType, value): + """行情推送,特殊字段相关""" + if tickType == 45: + lt = localtime(int(value)) + + tick = self.tickDict[tickerId] + tick.time = strftime('%H:%M:%S', lt) + tick.date = strftime('%Y%m%d') + + # 这里使用copy的目的是为了保证推送到事件系统中的对象 + # 不会被当前的API线程修改,否则可能出现多线程数据同步错误 + newtick = copy(tick) + self.gateway.onTick(newtick) + + #---------------------------------------------------------------------- + def tickEFP(self, tickerId, tickType, basisPoints, formattedBasisPoints, impliedFuture, holdDays, futureExpiry, dividendImpact, dividendsToExpiry): + """行情推送(合约属性相关)""" + pass + + #---------------------------------------------------------------------- + def orderStatus(self, orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld): + """报单成交回报""" + pass + orderId = str(orderId) + + if orderId in self.orderDict: + od = self.orderDict[orderId] + else: + od = VtOrderData() # od代表orderData + od.orderID = orderId + od.vtOrderID = '.'.join([self.gatewayName, orderId]) + od.gatewayName = self.gatewayName + self.orderDict[orderId] = od + + od.status = orderStatusMapReverse.get(status, STATUS_UNKNOWN) + od.tradedVolume = filled + + newod = copy(od) + self.gateway.onOrder(newod) + + #---------------------------------------------------------------------- + def openOrder(self, orderId, contract, order, orderState): + """报单信息推送""" + orderId = str(orderId) # orderId是整数 + + if orderId in self.orderDict: + od = self.orderDict[orderId] + else: + od = VtOrderData() # od代表orderData + od.orderID = orderId + od.vtOrderID = '.'.join([self.gatewayName, orderId]) + od.symbol = contract.m_symbol + od.exchange = exchangeMapReverse.get(contract.m_exchange, '') + od.vtSymbol = '.'.join([od.symbol, od.exchange]) + od.gatewayName = self.gatewayName + self.orderDict[orderId] = od + + od.direction = directionMapReverse.get(order.m_action, '') + od.price = order.m_lmtPrice + od.totalVolume = order.m_totalQuantity + + newod = copy(od) + self.gateway.onOrder(newod) + + #---------------------------------------------------------------------- + def openOrderEnd(self): + """ generated source for method openOrderEnd """ + pass + + #---------------------------------------------------------------------- + def updateAccountValue(self, key, value, currency, accountName): + """更新账户数据""" + # 仅逐个字段更新数据,这里对于没有currency的推送忽略 + if currency: + name = '.'.join([accountName, currency]) + + if name in self.accountDict: + account = self.accountDict[name] + else: + account = VtAccountData() + account.accountID = name + account.vtAccountID = name + account.gatewayName = self.gatewayName + self.accountDict[name] = account + + if key in accountKeyMap: + k = accountKeyMap[key] + account.__setattr__(k, float(value)) + + #---------------------------------------------------------------------- + def updatePortfolio(self, contract, position, marketPrice, marketValue, averageCost, unrealizedPNL, realizedPNL, accountName): + """持仓更新推送""" + pos = VtPositionData() + + pos.symbol = contract.m_symbol + pos.exchange = exchangeMapReverse.get(contract.m_exchange, contract.m_exchange) + pos.vtSymbol = '.'.join([pos.symbol, pos.exchange]) + pos.direction = DIRECTION_NET + pos.position = position + pos.price = averageCost + pos.vtPositionName = pos.vtSymbol + pos.gatewayName = self.gatewayName + + self.gateway.onPosition(pos) + + #---------------------------------------------------------------------- + def updateAccountTime(self, timeStamp): + """更新账户数据的时间""" + # 推送数据 + for account in self.accountDict.values(): + newaccount = copy(account) + self.gateway.onAccount(newaccount) + + #---------------------------------------------------------------------- + def accountDownloadEnd(self, accountName): + """ generated source for method accountDownloadEnd """ + pass + + #---------------------------------------------------------------------- + def nextValidId(self, orderId): + """下一个有效报单编号更新""" + self.gateway.orderId = orderId + + #---------------------------------------------------------------------- + def contractDetails(self, reqId, contractDetails): + """ generated source for method contractDetails """ + pass + + #---------------------------------------------------------------------- + def bondContractDetails(self, reqId, contractDetails): + """ generated source for method bondContractDetails """ + + #---------------------------------------------------------------------- + def contractDetailsEnd(self, reqId): + """ generated source for method contractDetailsEnd """ + pass + + #---------------------------------------------------------------------- + def execDetails(self, reqId, contract, execution): + """成交推送""" + trade = VtTradeData() + trade.gatewayName = self.gatewayName + trade.tradeID = execution.m_execId + trade.vtTradeID = '.'.join([self.gatewayName, trade.tradeID]) + + trade.symbol = contract.m_symbol + trade.exchange = exchangeMapReverse.get(contract.m_exchange, '') + trade.vtSymbol = '.'.join([trade.symbol, trade.exchange]) + + trade.orderID = str(execution.m_orderId) + trade.direction = directionMapReverse.get(execution.m_side, '') + trade.price = execution.m_price + trade.volume = execution.m_shares + trade.tradeTime = execution.m_time + + self.gateway.onTrade(trade) + + #---------------------------------------------------------------------- + def execDetailsEnd(self, reqId): + """ generated source for method execDetailsEnd """ + pass + + #---------------------------------------------------------------------- + def updateMktDepth(self, tickerId, position, operation, side, price, size): + """ generated source for method updateMktDepth """ + pass + + #---------------------------------------------------------------------- + def updateMktDepthL2(self, tickerId, position, marketMaker, operation, side, price, size): + """ generated source for method updateMktDepthL2 """ + pass + + #---------------------------------------------------------------------- + def updateNewsBulletin(self, msgId, msgType, message, origExchange): + """ generated source for method updateNewsBulletin """ + pass + + #---------------------------------------------------------------------- + def managedAccounts(self, accountsList): + """ generated source for method managedAccounts """ + pass + + #---------------------------------------------------------------------- + def receiveFA(self, faDataType, xml): + """ generated source for method receiveFA """ + pass + + #---------------------------------------------------------------------- + def historicalData(self, reqId, date, open, high, low, close, volume, count, WAP, hasGaps): + """ generated source for method historicalData """ + pass + + #---------------------------------------------------------------------- + def scannerParameters(self, xml): + """ generated source for method scannerParameters """ + pass + + #---------------------------------------------------------------------- + def scannerData(self, reqId, rank, contractDetails, distance, benchmark, projection, legsStr): + ''' generated source for method scannerData ''' + pass + + #---------------------------------------------------------------------- + def scannerDataEnd(self, reqId): + """ generated source for method scannerDataEnd """ + pass + + #---------------------------------------------------------------------- + def realtimeBar(self, reqId, time, open, high, low, close, volume, wap, count): + """ generated source for method realtimeBar """ + pass + + #---------------------------------------------------------------------- + def currentTime(self, time): + """ generated source for method currentTime """ + t = strftime('%H:%M:%S', localtime(time)) + + self.connectionStatus = True + self.gateway.connected = True + + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = (u'IB接口连接成功,当前服务器时间%s' %t) + self.gateway.onLog(log) + + #---------------------------------------------------------------------- + def fundamentalData(self, reqId, data): + """ generated source for method fundamentalData """ + pass + + #---------------------------------------------------------------------- + def deltaNeutralValidation(self, reqId, underComp): + """ generated source for method deltaNeutralValidation """ + pass + + #---------------------------------------------------------------------- + def tickSnapshotEnd(self, reqId): + """ generated source for method tickSnapshotEnd """ + pass + + #---------------------------------------------------------------------- + def marketDataType(self, reqId, marketDataType): + """ generated source for method marketDataType """ + pass + + #---------------------------------------------------------------------- + def commissionReport(self, commissionReport): + """ generated source for method commissionReport """ + pass + + #---------------------------------------------------------------------- + def position(self, account, contract, pos, avgCost): + """ generated source for method position """ + pass + + #---------------------------------------------------------------------- + def positionEnd(self): + """ generated source for method positionEnd """ + pass + + #---------------------------------------------------------------------- + def accountSummary(self, reqId, account, tag, value, currency): + """ generated source for method accountSummary """ + pass + + #---------------------------------------------------------------------- + def accountSummaryEnd(self, reqId): + """ generated source for method accountSummaryEnd """ + pass + + #---------------------------------------------------------------------- + def error(self, id=None, errorCode=None, errorMsg=None): + """错误回报""" + err = VtErrorData() + err.gatewayName = self.gatewayName + err.errorID = errorCode + err.errorMsg = errorMsg + self.gateway.onError(err) + + #---------------------------------------------------------------------- + def error_0(self, strval=None): + """错误回报(单一字符串)""" + err = VtErrorData() + err.gatewayName = self.gatewayName + err.errorMsg = strval + self.gateway.onError(err) + + #---------------------------------------------------------------------- + def error_1(self, id=None, errorCode=None, errorMsg=None): + """错误回报(字符串和代码)""" + err = VtErrorData() + err.gatewayName = self.gatewayName + err.errorID = errorCode + err.errorMsg = errorMsg + self.gateway.onError(err) + + #---------------------------------------------------------------------- + def connectionClosed(self): + """连接断开""" + self.connectionStatus = False + self.gateway.connected = False + + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = (u'IB接口连接断开') + self.gateway.onLog(log) + + \ No newline at end of file diff --git a/vn.trader/ltsGateway.py b/vn.trader/ltsGateway.py index 3bdffb90..b57884f7 100644 --- a/vn.trader/ltsGateway.py +++ b/vn.trader/ltsGateway.py @@ -393,7 +393,15 @@ class LtsMdApi(MdApi): req = {} req['InstrumentID'] = str(subscribeReq.symbol) req['ExchangeID'] = str(subscribeReq.exchange) +<<<<<<< HEAD self.subscribeMarketData(req) +======= + + # 这里的设计是,如果尚未登录就调用了订阅方法 + # 则先保存订阅请求,登录完成后会自动订阅 + if self.loginStatus: + self.subscribeMarketData(req) +>>>>>>> refs/remotes/vnpy/master self.subscribedSymbols.add(subscribeReq) @@ -565,10 +573,13 @@ class LtsTdApi(TdApi): #---------------------------------------------------------------------- def onRtnOrder(self, data): """报单回报""" +<<<<<<< HEAD print '-'*20 for k, v in data.items(): print k, ':', v +======= +>>>>>>> refs/remotes/vnpy/master # 更新最大报单编号 newref = data['OrderRef'] self.orderRef = max(self.orderRef, int(newref)) @@ -662,10 +673,13 @@ class LtsTdApi(TdApi): #---------------------------------------------------------------------- def onErrRtnOrderInsert(self, data, error): """发单错误回报(交易所)""" +<<<<<<< HEAD print '-'*20 for k, v in data.items(): print k, ':', v +======= +>>>>>>> refs/remotes/vnpy/master err = VtErrorData() err.gatewayName = self.gatewayName err.errorID = error['ErrorID'] diff --git a/vn.trader/uiBasicWidget.py b/vn.trader/uiBasicWidget.py index 69153348..d5dcf736 100644 --- a/vn.trader/uiBasicWidget.py +++ b/vn.trader/uiBasicWidget.py @@ -27,7 +27,14 @@ class BasicCell(QtGui.QTableWidgetItem): #---------------------------------------------------------------------- def setContent(self, text): """设置内容""" +<<<<<<< HEAD self.setText(text) +======= + if text == '0' or text == '0.0': + self.setText('') + else: + self.setText(text) +>>>>>>> refs/remotes/vnpy/master ######################################################################## @@ -533,7 +540,24 @@ class TradingWidget(QtGui.QFrame): EXCHANGE_DCE, EXCHANGE_CZCE, EXCHANGE_SSE, +<<<<<<< HEAD EXCHANGE_SZSE] +======= + EXCHANGE_SZSE, + EXCHANGE_SMART, + EXCHANGE_GLOBEX, + EXCHANGE_IDEALPRO] + + currencyList = [CURRENCY_CNY, + CURRENCY_USD] + + productClassList = [PRODUCT_UNKNOWN, + PRODUCT_EQUITY, + PRODUCT_FUTURES, + PRODUCT_OPTION] + + gatewayList = [''] +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine, dataEngine, parent=None): @@ -544,6 +568,12 @@ class TradingWidget(QtGui.QFrame): self.dataEngine = dataEngine self.symbol = '' +<<<<<<< HEAD +======= + + # 添加交易接口 + self.gatewayList.extend(mainEngine.gatewayDict.keys()) +>>>>>>> refs/remotes/vnpy/master self.initUi() self.connectSignal() @@ -565,6 +595,12 @@ class TradingWidget(QtGui.QFrame): labelVolume = QtGui.QLabel(u'数量') labelPriceType = QtGui.QLabel(u'价格类型') labelExchange = QtGui.QLabel(u'交易所') +<<<<<<< HEAD +======= + labelCurrency = QtGui.QLabel(u'货币') + labelProductClass = QtGui.QLabel(u'产品类型') + labelGateway = QtGui.QLabel(u'交易接口') +>>>>>>> refs/remotes/vnpy/master self.lineSymbol = QtGui.QLineEdit() self.lineName = QtGui.QLineEdit() @@ -588,7 +624,20 @@ class TradingWidget(QtGui.QFrame): self.comboPriceType.addItems(self.priceTypeList) self.comboExchange = QtGui.QComboBox() +<<<<<<< HEAD self.comboExchange.addItems(self.exchangeList) +======= + self.comboExchange.addItems(self.exchangeList) + + self.comboCurrency = QtGui.QComboBox() + self.comboCurrency.addItems(self.currencyList) + + self.comboProductClass = QtGui.QComboBox() + self.comboProductClass.addItems(self.productClassList) + + self.comboGateway = QtGui.QComboBox() + self.comboGateway.addItems(self.gatewayList) +>>>>>>> refs/remotes/vnpy/master gridleft = QtGui.QGridLayout() gridleft.addWidget(labelSymbol, 0, 0) @@ -599,6 +648,13 @@ class TradingWidget(QtGui.QFrame): gridleft.addWidget(labelVolume, 5, 0) gridleft.addWidget(labelPriceType, 6, 0) gridleft.addWidget(labelExchange, 7, 0) +<<<<<<< HEAD +======= + gridleft.addWidget(labelCurrency, 8, 0) + gridleft.addWidget(labelProductClass, 9, 0) + gridleft.addWidget(labelGateway, 10, 0) + +>>>>>>> refs/remotes/vnpy/master gridleft.addWidget(self.lineSymbol, 0, 1) gridleft.addWidget(self.lineName, 1, 1) gridleft.addWidget(self.comboDirection, 2, 1) @@ -607,6 +663,12 @@ class TradingWidget(QtGui.QFrame): gridleft.addWidget(self.spinVolume, 5, 1) gridleft.addWidget(self.comboPriceType, 6, 1) gridleft.addWidget(self.comboExchange, 7, 1) +<<<<<<< HEAD +======= + gridleft.addWidget(self.comboCurrency, 8, 1) + gridleft.addWidget(self.comboProductClass, 9, 1) + gridleft.addWidget(self.comboGateway, 10, 1) +>>>>>>> refs/remotes/vnpy/master # 右边部分 labelBid1 = QtGui.QLabel(u'买一') @@ -716,13 +778,25 @@ class TradingWidget(QtGui.QFrame): #---------------------------------------------------------------------- def updateSymbol(self): """合约变化""" +<<<<<<< HEAD symbol = unicode(self.lineSymbol.text()) exchange = unicode(self.comboExchange.currentText()) +======= + # 读取组件数据 + symbol = unicode(self.lineSymbol.text()) + exchange = unicode(self.comboExchange.currentText()) + currency = unicode(self.comboCurrency.currentText()) + productClass = unicode(self.comboProductClass.currentText()) + gatewayName = unicode(self.comboGateway.currentText()) + + # 查询合约 +>>>>>>> refs/remotes/vnpy/master if exchange: vtSymbol = '.'.join([symbol, exchange]) contract = self.dataEngine.getContract(vtSymbol) else: +<<<<<<< HEAD contract = self.dataEngine.getContract(symbol) if contract: @@ -770,6 +844,59 @@ class TradingWidget(QtGui.QFrame): # 更新组件当前交易的合约 self.symbol = contract.vtSymbol +======= + vtSymbol = symbol + contract = self.dataEngine.getContract(symbol) + + if contract: + gatewayName = contract.gatewayName + self.lineName.setText(contract.name) + exchange = contract.exchange # 保证有交易所代码 + + # 清空价格数量 + self.spinPrice.setValue(0) + self.spinVolume.setValue(0) + + # 清空行情显示 + self.labelBidPrice1.setText('') + self.labelBidPrice2.setText('') + self.labelBidPrice3.setText('') + self.labelBidPrice4.setText('') + self.labelBidPrice5.setText('') + self.labelBidVolume1.setText('') + self.labelBidVolume2.setText('') + self.labelBidVolume3.setText('') + self.labelBidVolume4.setText('') + self.labelBidVolume5.setText('') + self.labelAskPrice1.setText('') + self.labelAskPrice2.setText('') + self.labelAskPrice3.setText('') + self.labelAskPrice4.setText('') + self.labelAskPrice5.setText('') + self.labelAskVolume1.setText('') + self.labelAskVolume2.setText('') + self.labelAskVolume3.setText('') + self.labelAskVolume4.setText('') + self.labelAskVolume5.setText('') + self.labelLastPrice.setText('') + self.labelReturn.setText('') + + # 重新注册事件监听 + self.eventEngine.unregister(EVENT_TICK + self.symbol, self.signal.emit) + self.eventEngine.register(EVENT_TICK + vtSymbol, self.signal.emit) + + # 订阅合约 + req = VtSubscribeReq() + req.symbol = symbol + req.exchange = exchange + req.currency = currency + req.productClass = productClass + + self.mainEngine.subscribe(req, gatewayName) + + # 更新组件当前交易的合约 + self.symbol = vtSymbol +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def updateTick(self, event): @@ -804,8 +931,17 @@ class TradingWidget(QtGui.QFrame): self.labelAskVolume5.setText(str(tick.askVolume5)) self.labelLastPrice.setText(str(tick.lastPrice)) +<<<<<<< HEAD rt = (tick.lastPrice/tick.preClosePrice)-1 self.labelReturn.setText(('%.2f' %(rt*100))+'%') +======= + + if tick.preClosePrice: + rt = (tick.lastPrice/tick.preClosePrice)-1 + self.labelReturn.setText(('%.2f' %(rt*100))+'%') + else: + self.labelReturn.setText('') +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def connectSignal(self): @@ -815,13 +951,24 @@ class TradingWidget(QtGui.QFrame): #---------------------------------------------------------------------- def sendOrder(self): """发单""" +<<<<<<< HEAD symbol = str(self.lineSymbol.text()) exchange = str(self.comboExchange.currentText()) +======= + symbol = unicode(self.lineSymbol.text()) + exchange = unicode(self.comboExchange.currentText()) + currency = unicode(self.comboCurrency.currentText()) + productClass = unicode(self.comboProductClass.currentText()) + gatewayName = unicode(self.comboGateway.currentText()) + + # 查询合约 +>>>>>>> refs/remotes/vnpy/master if exchange: vtSymbol = '.'.join([symbol, exchange]) contract = self.dataEngine.getContract(vtSymbol) else: +<<<<<<< HEAD contract = self.dataEngine.getContract(symbol) if contract: @@ -834,6 +981,27 @@ class TradingWidget(QtGui.QFrame): req.priceType = unicode(self.comboPriceType.currentText()) req.offset = unicode(self.comboOffset.currentText()) self.mainEngine.sendOrder(req, contract.gatewayName) +======= + vtSymbol = symbol + contract = self.dataEngine.getContract(symbol) + + if contract: + gatewayName = contract.gatewayName + exchange = contract.exchange # 保证有交易所代码 + + req = VtOrderReq() + req.symbol = symbol + req.exchange = exchange + req.price = self.spinPrice.value() + req.volume = self.spinVolume.value() + req.direction = unicode(self.comboDirection.currentText()) + req.priceType = unicode(self.comboPriceType.currentText()) + req.offset = unicode(self.comboOffset.currentText()) + req.currency = currency + req.productClass = productClass + + self.mainEngine.sendOrder(req, gatewayName) +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def cancelAll(self): diff --git a/vn.trader/uiCtaWidget.py b/vn.trader/uiCtaWidget.py index 91b9a218..3d209fe9 100644 --- a/vn.trader/uiCtaWidget.py +++ b/vn.trader/uiCtaWidget.py @@ -2,3 +2,250 @@ '''CTA模块相关的GUI控制组件''' +<<<<<<< HEAD +======= +from uiBasicWidget import QtGui, QtCore, BasicCell +from eventEngine import * + + +######################################################################## +class ValueMonitor(QtGui.QTableWidget): + """数值监控""" + signal = QtCore.pyqtSignal() + + #---------------------------------------------------------------------- + def __init__(self, parent=None): + """Constructor""" + super(ValueMonitor , self).__init__(parent) + + self.keyCellDict = {} + self.row = 0 + self.data = None + + self.initUi() + self.signal.connect(self.updateTable) + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setColumnCount(2) + + self.verticalHeader().setVisible(False) + self.horizontalHeader().setVisible(False) + + self.setEditTriggers(self.NoEditTriggers) + self.setAlternatingRowColors(True) + + #---------------------------------------------------------------------- + def updateData(self, data): + """更新数据""" + self.data = data + self.signal.emit() + + #---------------------------------------------------------------------- + def updateTable(self): + """更新表格""" + for key, value in self.data.items(): + if key in self.keyCellDict: + cell = self.keyCellDict[key] + cell.setText(unicode(value)) + else: + # 创建并保存单元格 + keyCell = BasicCell(unicode(key)) + cell = BasicCell(unicode(value)) + self.keyCellDict[key] = cell + + # 移动到下一行 + self.insertRow(self.row) + self.setItem(self.row, 0, keyCell) + self.setItem(self.row, 1, cell) + self.row += 1 + + +######################################################################## +class CtaStrategyManager(QtGui.QGroupBox): + """策略管理组件""" + + #---------------------------------------------------------------------- + def __init__(self, ctaEngine, eventEngine, name, parent=None): + """Constructor""" + super(CtaStrategyManager, self).__init__(parent) + + self.ctaEngine = ctaEngine + self.eventEngine = eventEngine + self.name = name + + self.initUi() + self.updateMonitor() + self.registerEvent() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setTitle(self.name) + + paramLabel = QtGui.QLabel(u'参数') + varLabel = QtGui.QLabel(u'变量') + + self.paramMonitor = ValueMonitor(self) + self.varMonitor = ValueMonitor(self) + + buttonStart = QtGui.QPushButton(u'启动') + buttonStop = QtGui.QPushButton(u'停止') + buttonStart.clicked.connect(self.start) + buttonStop.clicked.connect(self.stop) + + hbox = QtGui.QHBoxLayout() + hbox.addWidget(buttonStart) + hbox.addWidget(buttonStop) + hbox.addStretch() + + vbox = QtGui.QVBoxLayout() + vbox.addLayout(hbox) + vbox.addWidget(paramLabel) + vbox.addWidget(self.paramMonitor) + vbox.addWidget(varLabel) + vbox.addWidget(self.varMonitor) + self.setLayout(vbox) + + #---------------------------------------------------------------------- + def updateMonitor(self, event=None): + """显示策略最新状态""" + paramDict = self.ctaEngine.getStrategyParam(self.name) + if paramDict: + self.paramMonitor.updateData(paramDict) + + varDict = self.ctaEngine.getStrategyVar(self.name) + if varDict: + self.varMonitor.updateData(varDict) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.eventEngine.register(EVENT_TIMER, self.updateMonitor) + + #---------------------------------------------------------------------- + def start(self): + """启动策略""" + self.ctaEngine.startStrategy(self.name) + + #---------------------------------------------------------------------- + def stop(self): + """停止策略""" + self.ctaEngine.stopStrategy(self.name) + + + +######################################################################## +class CtaEngineManager(QtGui.QWidget): + """CTA引擎管理组件""" + signal = QtCore.pyqtSignal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, ctaEngine, eventEngine, parent=None): + """Constructor""" + super(CtaEngineManager, self).__init__(parent) + + self.ctaEngine = ctaEngine + self.eventEngine = eventEngine + + self.strategyLoaded = False + + self.initUi() + self.registerEvent() + + # 记录日志 + self.ctaEngine.writeCtaLog(u'CTA引擎启动成功') + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setWindowTitle(u'CTA策略') + + # 按钮 + loadButton = QtGui.QPushButton(u'加载策略') + startAllButton = QtGui.QPushButton(u'全部启动') + stopAllButton = QtGui.QPushButton(u'全部停止') + + loadButton.clicked.connect(self.load) + startAllButton.clicked.connect(self.startAll) + stopAllButton.clicked.connect(self.stopAll) + + # 滚动区域,放置所有的CtaStrategyManager + self.scrollArea = QtGui.QScrollArea() + + # CTA组件的日志监控 + self.ctaLogMonitor = QtGui.QTextEdit() + self.ctaLogMonitor.setReadOnly(True) + + # 设置布局 + hbox2 = QtGui.QHBoxLayout() + hbox2.addWidget(loadButton) + hbox2.addWidget(startAllButton) + hbox2.addWidget(stopAllButton) + hbox2.addStretch() + + vbox = QtGui.QVBoxLayout() + vbox.addLayout(hbox2) + vbox.addWidget(self.scrollArea) + vbox.addWidget(self.ctaLogMonitor) + self.setLayout(vbox) + + #---------------------------------------------------------------------- + def initStrategyManager(self): + """初始化策略管理组件界面""" + w = QtGui.QWidget() + hbox = QtGui.QHBoxLayout() + + for name in self.ctaEngine.strategyDict.keys(): + strategyManager = CtaStrategyManager(self.ctaEngine, self.eventEngine, name) + hbox.addWidget(strategyManager) + + w.setLayout(hbox) + self.scrollArea.setWidget(w) + + #---------------------------------------------------------------------- + def startAll(self): + """全部启动""" + for name in self.ctaEngine.strategyDict.keys(): + self.ctaEngine.startStrategy(name) + + #---------------------------------------------------------------------- + def stopAll(self): + """全部停止""" + for name in self.ctaEngine.strategyDict.keys(): + self.ctaEngine.stopStrategy(name) + + #---------------------------------------------------------------------- + def load(self): + """加载策略""" + if not self.strategyLoaded: + self.ctaEngine.loadStrategySetting() + self.initStrategyManager() + self.strategyLoaded = True + self.ctaEngine.writeCtaLog(u'策略加载成功') + + #---------------------------------------------------------------------- + def updateCtaLog(self, event): + """更新CTA相关日志""" + log = event.dict_['data'] + content = '\t'.join([log.logTime, log.logContent]) + self.ctaLogMonitor.append(content) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.updateCtaLog) + self.eventEngine.register(EVENT_CTA_LOG, self.signal.emit) + + + + + + + + + + + +>>>>>>> refs/remotes/vnpy/master diff --git a/vn.trader/uiMainWindow.py b/vn.trader/uiMainWindow.py index 67c801fb..10fe7216 100644 --- a/vn.trader/uiMainWindow.py +++ b/vn.trader/uiMainWindow.py @@ -3,7 +3,11 @@ import psutil from uiBasicWidget import * +<<<<<<< HEAD +======= +from uiCtaWidget import CtaEngineManager +>>>>>>> refs/remotes/vnpy/master ######################################################################## class MainWindow(QtGui.QMainWindow): @@ -77,6 +81,12 @@ class MainWindow(QtGui.QMainWindow): connectWindAction = QtGui.QAction(u'连接Wind', self) connectWindAction.triggered.connect(self.connectWind) +<<<<<<< HEAD +======= + connectIbAction = QtGui.QAction(u'连接IB', self) + connectIbAction.triggered.connect(self.connectIb) + +>>>>>>> refs/remotes/vnpy/master testAction = QtGui.QAction(u'测试', self) testAction.triggered.connect(self.testSubscribe) @@ -89,6 +99,12 @@ class MainWindow(QtGui.QMainWindow): contractAction = QtGui.QAction(u'查询合约', self) contractAction.triggered.connect(self.openContract) +<<<<<<< HEAD +======= + ctaAction = QtGui.QAction(u'CTA策略', self) + ctaAction.triggered.connect(self.openCta) + +>>>>>>> refs/remotes/vnpy/master # 创建菜单 menubar = self.menuBar() @@ -96,11 +112,19 @@ class MainWindow(QtGui.QMainWindow): sysMenu.addAction(connectCtpAction) sysMenu.addAction(connectLtsAction) sysMenu.addAction(connectWindAction) +<<<<<<< HEAD +======= + sysMenu.addAction(connectIbAction) +>>>>>>> refs/remotes/vnpy/master sysMenu.addAction(testAction) sysMenu.addAction(exitAction) functionMenu = menubar.addMenu(u'功能') functionMenu.addAction(contractAction) +<<<<<<< HEAD +======= + functionMenu.addAction(ctaAction) +>>>>>>> refs/remotes/vnpy/master helpMenu = menubar.addMenu(u'帮助') helpMenu.addAction(aboutAction) @@ -150,6 +174,7 @@ class MainWindow(QtGui.QMainWindow): self.mainEngine.connect('Wind') #---------------------------------------------------------------------- +<<<<<<< HEAD def testSubscribe(self): """测试订阅""" req = VtSubscribeReq() @@ -181,6 +206,33 @@ class MainWindow(QtGui.QMainWindow): req.symbol = 'SR1601' req.exchange = EXCHANGE_CZCE self.mainEngine.subscribe(req, 'Wind') +======= + def connectIb(self): + """连接Ib""" + self.mainEngine.connect('IB') + + #---------------------------------------------------------------------- + def testSubscribe(self): + """测试订阅""" + req = VtSubscribeReq() + req.symbol = 'GOOG' + req.productClass = PRODUCT_EQUITY + req.exchange = EXCHANGE_SMART + req.currency = CURRENCY_USD + self.mainEngine.subscribe(req, 'IB') + + req.symbol = 'AAPL' + self.mainEngine.subscribe(req, 'IB') + + req.symbol = 'YHOO' + self.mainEngine.subscribe(req, 'IB') + + req.symbol = 'MSFT' + self.mainEngine.subscribe(req, 'IB') + + req.symbol = 'GE' + self.mainEngine.subscribe(req, 'IB') +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def openAbout(self): @@ -199,6 +251,18 @@ class MainWindow(QtGui.QMainWindow): except AttributeError: self.contractM = ContractMonitor(self.mainEngine.dataEngine) self.contractM.show() +<<<<<<< HEAD +======= + + #---------------------------------------------------------------------- + def openCta(self): + """打开CTA组件""" + try: + self.ctaM.show() + except AttributeError: + self.ctaM = CtaEngineManager(self.mainEngine.ctaEngine, self.eventEngine) + self.ctaM.show() +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def closeEvent(self, event): diff --git a/vn.trader/vtConstant.py b/vn.trader/vtConstant.py index 10612119..c7b19845 100644 --- a/vn.trader/vtConstant.py +++ b/vn.trader/vtConstant.py @@ -12,6 +12,10 @@ DIRECTION_LONG = u'多' DIRECTION_SHORT = u'空' DIRECTION_UNKNOWN = u'未知' DIRECTION_NET = u'净' +<<<<<<< HEAD +======= +DIRECTION_SELL = u'卖出' # IB接口 +>>>>>>> refs/remotes/vnpy/master # 开平常量 OFFSET_NONE = u'无开平' @@ -34,6 +38,10 @@ PRODUCT_FUTURES = u'期货' PRODUCT_OPTION = u'期权' PRODUCT_INDEX = u'指数' PRODUCT_COMBINATION = u'组合' +<<<<<<< HEAD +======= +PRODUCT_FOREX = u'外汇' +>>>>>>> refs/remotes/vnpy/master PRODUCT_UNKNOWN = u'未知' # 价格类型常量 @@ -53,5 +61,20 @@ EXCHANGE_CFFEX = u'CFFEX' # 中金所 EXCHANGE_SHFE = u'SHFE' # 上期所 EXCHANGE_CZCE = u'CZCE' # 郑商所 EXCHANGE_DCE = u'DCE' # 大商所 +<<<<<<< HEAD EXCHANGE_UNKNOWN = 'UNKNOWN'# 未知交易所 -EXCHANGE_NONE = '' # 空交易所 \ No newline at end of file +EXCHANGE_NONE = '' # 空交易所 +======= + +EXCHANGE_UNKNOWN = 'UNKNOWN'# 未知交易所 +EXCHANGE_NONE = '' # 空交易所 + +EXCHANGE_SMART = u'SMART' # IB智能路由(股票、期权) +EXCHANGE_GLOBEX = u'GLOBEX' # CME电子交易平台 +EXCHANGE_IDEALPRO = u'IDEALPRO' # IB外汇ECN + +# 货币类型 +CURRENCY_USD = 'USD' # 美元 +CURRENCY_CNY = 'CNY' # 人民币 +CURRENCY_UNKNOWN = 'UNKNOWN' # 未知货币 +>>>>>>> refs/remotes/vnpy/master diff --git a/vn.trader/vtEngine.py b/vn.trader/vtEngine.py index 7cfaecd8..ea1cb5c7 100644 --- a/vn.trader/vtEngine.py +++ b/vn.trader/vtEngine.py @@ -1,6 +1,10 @@ # encoding: UTF-8 import shelve +<<<<<<< HEAD +======= +from collections import OrderedDict +>>>>>>> refs/remotes/vnpy/master from pymongo import MongoClient from pymongo.errors import ConnectionFailure @@ -8,9 +12,17 @@ from pymongo.errors import ConnectionFailure from eventEngine import * from ctpGateway import CtpGateway from ltsGateway import LtsGateway +<<<<<<< HEAD from windGateway import WindGateway from vtGateway import * import uiBasicWidget +======= +#from windGateway import WindGateway +from ibGateway import IbGateway +from vtGateway import * +import uiBasicWidget +from ctaEngine import CtaEngine +>>>>>>> refs/remotes/vnpy/master ######################################################################## @@ -29,7 +41,7 @@ class MainEngine(object): uiBasicWidget.NameCell.setDataEngine(uiBasicWidget.NameCell, self.dataEngine) # 将数据引擎对象传给NameCell # 用来保存接口对象的字典 - self.gatewayDict = {} + self.gatewayDict = OrderedDict() # 创建我们想要接入的接口对象 self.addGateway(CtpGateway, 'CTP') @@ -40,8 +52,18 @@ class MainEngine(object): #self.addGateway(WindGateway, 'Wind') # 没有Wind的请注释掉这一行 +<<<<<<< HEAD # MongoDB数据库相关 self.dbClient = None # MongoDB客户端对象 +======= + self.addGateway(IbGateway, 'IB') + + # MongoDB数据库相关 + self.dbClient = None # MongoDB客户端对象 + + # CTA引擎 + self.ctaEngine = CtaEngine(self, self.eventEngine, self.dataEngine) +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def addGateway(self, gateway, gatewayName=None): @@ -56,7 +78,11 @@ class MainEngine(object): gateway.connect() else: self.writeLog(u'接口不存在:%s' %gatewayName) +<<<<<<< HEAD +======= + +>>>>>>> refs/remotes/vnpy/master #---------------------------------------------------------------------- def subscribe(self, subscribeReq, gatewayName): """订阅特定接口的行情""" diff --git a/vn.trader/vtGateway.py b/vn.trader/vtGateway.py index 1afaa8b6..b9a82b3b 100644 --- a/vn.trader/vtGateway.py +++ b/vn.trader/vtGateway.py @@ -164,7 +164,8 @@ class VtTickData(VtBaseData): # 成交数据 self.lastPrice = EMPTY_FLOAT # 最新成交价 - self.volume = EMPTY_INT # 最新成交量 + self.lastVolume = EMPTY_INT # 最新成交量 + self.volume = EMPTY_INT # 今天总成交量 self.openInterest = EMPTY_INT # 持仓量 self.time = EMPTY_STRING # 时间 11:20:56.5 self.date = EMPTY_STRING # 日期 20151009 @@ -370,6 +371,13 @@ class VtSubscribeReq: """Constructor""" self.symbol = EMPTY_STRING # 代码 self.exchange = EMPTY_STRING # 交易所 + + # 以下为IB相关 + self.productClass = EMPTY_UNICODE # 合约类型 + self.currency = EMPTY_STRING # 合约货币 + self.expiry = EMPTY_STRING # 到期日 + self.strikePrice = EMPTY_FLOAT # 行权价 + self.optionType = EMPTY_UNICODE # 期权类型 ######################################################################## @@ -387,6 +395,16 @@ class VtOrderReq: self.priceType = EMPTY_STRING # 价格类型 self.direction = EMPTY_STRING # 买卖 self.offset = EMPTY_STRING # 开平 +<<<<<<< HEAD +======= + + # 以下为IB相关 + self.productClass = EMPTY_UNICODE # 合约类型 + self.currency = EMPTY_STRING # 合约货币 + self.expiry = EMPTY_STRING # 到期日 + self.strikePrice = EMPTY_FLOAT # 行权价 + self.optionType = EMPTY_UNICODE # 期权类型 +>>>>>>> refs/remotes/vnpy/master ########################################################################