diff --git a/vn.trader/CTA_setting.json b/vn.trader/CTA_setting.json index 3e8805eb..8c245b0b 100644 --- a/vn.trader/CTA_setting.json +++ b/vn.trader/CTA_setting.json @@ -1,14 +1,10 @@ { - "Test1": { - "strategyClassName": "TestStrategy", - "vtSymbol": "IF1511" - }, - "Test3": { - "strategyClassName": "TestStrategy", + "DR_IF1512": { + "strategyClassName": "DataRecorder", "vtSymbol": "IF1512" }, - "Test2": { - "strategyClassName": "TestStrategy", - "vtSymbol": "IH1511" + "DR_IH1512": { + "strategyClassName": "DataRecorder", + "vtSymbol": "IH1512" } } \ No newline at end of file diff --git a/vn.trader/ctaDataRecorder.py b/vn.trader/ctaDataRecorder.py new file mode 100644 index 00000000..7731c4c7 --- /dev/null +++ b/vn.trader/ctaDataRecorder.py @@ -0,0 +1,106 @@ +# encoding: UTF-8 + +from ctaStrategyTemplate import * +from ctaObject import CtaBarData + + +######################################################################## +class DataRecorder(CtaStrategyTemplate): + """ + 纯粹用来记录历史数据的工具(基于CTA策略), + 建议运行在实际交易程序外的一个vn.trader实例中, + 本工具会记录Tick和1分钟K线数据。 + """ + + #---------------------------------------------------------------------- + def __init__(self, ctaEngine, name, setting=None): + """Constructor""" + super(DataRecorder, self).__init__(ctaEngine, name, setting) + + self.strategyClassName = 'DataRecorder' + + self.author = u'用Python的交易员' + self.tickDbName = 'VtTrader_Tick_Db' + self.barDbName = 'VtTrader_1Min_Db' + + self.paramList.append('author') + + # 数据记录相关 + self.bar = None # K线数据对象 + self.barMinute = -1 # 当前的分钟,初始化设为-1 + + #---------------------------------------------------------------------- + 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推送""" + # 收到Tick后,首先插入到数据库里 + self.insertTick(tick) + + # 计算K线 + tickMinute = tick.datetime.minute + + if tickMinute != self.barMinute: # 如果分钟变了,则把旧的K线插入数据库,并生成新的K线 + if self.bar: + self.onBar(self.bar) + + bar = CtaBarData() # 创建新的K线,目的在于防止之前K线对象在插入Mongo中被再次修改,导致出错 + bar.vtSymbol = tick.vtSymbol + bar.symbol = tick.symbol + bar.exchange = tick.exchange + + bar.open = tick.lastPrice + bar.high = tick.lastPrice + bar.low = tick.lastPrice + bar.close = tick.lastPrice + + bar.date = tick.date + bar.time = tick.time + bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间 + + bar.volume = tick.volume + bar.openInterest = tick.openInterest + + self.bar = bar # 这种写法为了减少一层访问,加快速度 + self.barMinute = tickMinute # 更新当前的分钟 + + else: # 否则继续累加新的K线 + bar = self.bar # 写法同样为了加快速度 + + bar.high = max(bar.high, tick.lastPrice) + bar.low = min(bar.low, tick.lastPrice) + bar.close = tick.lastPrice + + bar.volume = bar.volume + tick.volume # 成交量是累加的 + bar.openInterest = tick.openInterest # 持仓量直接更新 + + #---------------------------------------------------------------------- + def onOrder(self, order): + """收到委托变化推送""" + pass + + #---------------------------------------------------------------------- + def onTrade(self, trade): + """收到成交推送""" + pass + + #---------------------------------------------------------------------- + def onBar(self, bar): + """收到Bar推送""" + self.insertBar(bar) + + + \ No newline at end of file diff --git a/vn.trader/ctaEngine.py b/vn.trader/ctaEngine.py index f8980291..fe85eb00 100644 --- a/vn.trader/ctaEngine.py +++ b/vn.trader/ctaEngine.py @@ -10,100 +10,10 @@ from vtConstant import * from vtGateway import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData from ctaConstant import * +from ctaObject import * from ctaStrategies import strategyClassDict -######################################################################## -class StopOrder(object): - """本地停止单""" - - # ---------------------------------------------------------------------- - def __init__(self): - """Constructor""" - self.vtSymbol = EMPTY_STRING - self.orderType = EMPTY_UNICODE - self.price = EMPTY_FLOAT - self.volume = EMPTY_INT - - self.strategy = None # 下停止单的策略对象 - self.stopOrderID = EMPTY_STRING # 停止单的本地编号 - self.status = EMPTY_STRING # 停止单状态 - - -######################################################################## -class CtaBarData(object): - """K线数据""" - - # ---------------------------------------------------------------------- - def __init__(self): - """Constructor""" - self.vtSymbol = EMPTY_STRING # vt系统代码 - self.symbol = EMPTY_STRING # 代码 - self.exchange = EMPTY_STRING # 交易所 - - self.open = EMPTY_FLOAT # OHLC - self.high = EMPTY_FLOAT - self.low = EMPTY_FLOAT - self.close = EMPTY_FLOAT - - self.date = EMPTY_STRING # bar开始的时间,日期 - self.time = EMPTY_STRING # 时间 - self.datetime = None # python的datetime时间对象 - - self.volume = EMPTY_INT # 成交量 - self.openInterest = EMPTY_INT # 持仓量 - - -######################################################################## -class CtaTickData(object): - """Tick数据""" - - # ---------------------------------------------------------------------- - def __init__(self): - """Constructor""" - self.vtSymbol = EMPTY_STRING # vt系统代码 - self.symbol = EMPTY_STRING # 合约代码 - self.exchange = EMPTY_STRING # 交易所代码 - - # 成交数据 - self.lastPrice = EMPTY_FLOAT # 最新成交价 - self.volume = EMPTY_INT # 最新成交量 - self.openInterest = EMPTY_INT # 持仓量 - - self.upperLimit = EMPTY_FLOAT # 涨停价 - self.lowerLimit = EMPTY_FLOAT # 跌停价 - - # tick的时间 - self.date = EMPTY_STRING # 日期 - self.time = EMPTY_STRING # 时间 - self.datetime = None # python的datetime时间对象 - - # 五档行情 - self.bidPrice1 = EMPTY_FLOAT - self.bidPrice2 = EMPTY_FLOAT - self.bidPrice3 = EMPTY_FLOAT - self.bidPrice4 = EMPTY_FLOAT - self.bidPrice5 = EMPTY_FLOAT - - self.askPrice1 = EMPTY_FLOAT - self.askPrice2 = EMPTY_FLOAT - self.askPrice3 = EMPTY_FLOAT - self.askPrice4 = EMPTY_FLOAT - self.askPrice5 = EMPTY_FLOAT - - self.bidVolume1 = EMPTY_INT - self.bidVolume2 = EMPTY_INT - self.bidVolume3 = EMPTY_INT - self.bidVolume4 = EMPTY_INT - self.bidVolume5 = EMPTY_INT - - self.askVolume1 = EMPTY_INT - self.askVolume2 = EMPTY_INT - self.askVolume3 = EMPTY_INT - self.askVolume4 = EMPTY_INT - self.askVolume5 = EMPTY_INT - - ######################################################################## class CtaEngine(object): """CTA策略引擎""" @@ -174,8 +84,10 @@ class CtaEngine(object): req.direction = DIRECTION_LONG req.offset = OFFSET_CLOSE + # 3.调用主引擎的发单接口进行发单,保存OrderID与策略映射关系 - vtOrderID = self.mainEngine.sendOrder(req) # 发单 + vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单 + self.orderDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系 return vtOrderID @@ -308,7 +220,7 @@ class CtaEngine(object): l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: - strategy.onTick(tick) + strategy.onTick(ctaTick) # ---------------------------------------------------------------------- @@ -434,7 +346,8 @@ class CtaEngine(object): # 5.调用主引擎的订阅接口 self.mainEngine.subscribe(req, contract.gatewayName) - + else: + self.writeCtaLog(u'%s的交易合约%s无法找到' %(name, strategy.vtSymbol)) else: self.writeCtaLog(u'存在策略对象重名:' + name) diff --git a/vn.trader/ctaObject.py b/vn.trader/ctaObject.py new file mode 100644 index 00000000..38f64384 --- /dev/null +++ b/vn.trader/ctaObject.py @@ -0,0 +1,95 @@ +# encoding: UTF-8 + +from vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT + + +######################################################################## +class StopOrder(object): + """本地停止单""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.vtSymbol = EMPTY_STRING + self.orderType = EMPTY_UNICODE + self.price = EMPTY_FLOAT + self.volume = EMPTY_INT + + self.strategy = None # 下停止单的策略对象 + self.stopOrderID = EMPTY_STRING # 停止单的本地编号 + self.status = EMPTY_STRING # 停止单状态 + + +######################################################################## +class CtaBarData(object): + """K线数据""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.vtSymbol = EMPTY_STRING # vt系统代码 + self.symbol = EMPTY_STRING # 代码 + self.exchange = EMPTY_STRING # 交易所 + + self.open = EMPTY_FLOAT # OHLC + self.high = EMPTY_FLOAT + self.low = EMPTY_FLOAT + self.close = EMPTY_FLOAT + + self.date = EMPTY_STRING # bar开始的时间,日期 + self.time = EMPTY_STRING # 时间 + self.datetime = None # python的datetime时间对象 + + self.volume = EMPTY_INT # 成交量 + self.openInterest = EMPTY_INT # 持仓量 + + +######################################################################## +class CtaTickData(object): + """Tick数据""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.vtSymbol = EMPTY_STRING # vt系统代码 + self.symbol = EMPTY_STRING # 合约代码 + self.exchange = EMPTY_STRING # 交易所代码 + + # 成交数据 + self.lastPrice = EMPTY_FLOAT # 最新成交价 + self.volume = EMPTY_INT # 最新成交量 + self.openInterest = EMPTY_INT # 持仓量 + + self.upperLimit = EMPTY_FLOAT # 涨停价 + self.lowerLimit = EMPTY_FLOAT # 跌停价 + + # tick的时间 + self.date = EMPTY_STRING # 日期 + self.time = EMPTY_STRING # 时间 + self.datetime = None # python的datetime时间对象 + + # 五档行情 + self.bidPrice1 = EMPTY_FLOAT + self.bidPrice2 = EMPTY_FLOAT + self.bidPrice3 = EMPTY_FLOAT + self.bidPrice4 = EMPTY_FLOAT + self.bidPrice5 = EMPTY_FLOAT + + self.askPrice1 = EMPTY_FLOAT + self.askPrice2 = EMPTY_FLOAT + self.askPrice3 = EMPTY_FLOAT + self.askPrice4 = EMPTY_FLOAT + self.askPrice5 = EMPTY_FLOAT + + self.bidVolume1 = EMPTY_INT + self.bidVolume2 = EMPTY_INT + self.bidVolume3 = EMPTY_INT + self.bidVolume4 = EMPTY_INT + self.bidVolume5 = EMPTY_INT + + self.askVolume1 = EMPTY_INT + self.askVolume2 = EMPTY_INT + self.askVolume3 = EMPTY_INT + self.askVolume4 = EMPTY_INT + self.askVolume5 = EMPTY_INT + diff --git a/vn.trader/ctaStrategies.py b/vn.trader/ctaStrategies.py index fb7bcc85..7a08cb61 100644 --- a/vn.trader/ctaStrategies.py +++ b/vn.trader/ctaStrategies.py @@ -2,10 +2,18 @@ ''' 在本文件中引入所有希望在系统中使用的策略类 -当作配置文件,每次增加删除策略时,需要维护此字典 + + +这个字典中保存了需要运行的策略的名称和策略类的映射关系, +用户的策略类写好后,先在该文件中引入,并设置好名称,然后 +在CTA_setting.json中写入具体每个策略对象的类和合约设置。 + ''' from ctaStrategyTemplate import TestStrategy +from ctaDataRecorder import DataRecorder strategyClassDict = {} -strategyClassDict[u'TestStrategy'] = TestStrategy + +strategyClassDict['TestStrategy'] = TestStrategy +strategyClassDict['DataRecorder'] = DataRecorder diff --git a/vn.trader/ctaStrategyTemplate.py b/vn.trader/ctaStrategyTemplate.py index 28ba2039..2b0917fe 100644 --- a/vn.trader/ctaStrategyTemplate.py +++ b/vn.trader/ctaStrategyTemplate.py @@ -190,7 +190,7 @@ class TestStrategy(CtaStrategyTemplate): self.lastPrice = EMPTY_FLOAT # 最新价 # 参数和变量列表设置 - self.paramList.append(u'author') + self.paramList.append('author') self.varList.append('pos') self.varList.append('lastPrice') diff --git a/vn.trader/ctpGateway.py b/vn.trader/ctpGateway.py index 60c60a1f..0d376d9c 100644 --- a/vn.trader/ctpGateway.py +++ b/vn.trader/ctpGateway.py @@ -640,6 +640,7 @@ class CtpTdApi(TdApi): # 持仓量 pos.position = data['Position'] + pos.ydPosition = data['YdPosition'] # 持仓均价 if pos.position: diff --git a/vn.trader/eventType.py b/vn.trader/eventType.py index 8017a413..f7a8cd41 100644 --- a/vn.trader/eventType.py +++ b/vn.trader/eventType.py @@ -30,6 +30,13 @@ EVENT_CTA_LOG = 'eCtaLog' # CTA相关的日志事件 # Wind接口相关 EVENT_WIND_CONNECTREQ = 'eWindConnectReq' # Wind接口请求连接事件 +# 20151020后更新 +# LTS Gateway相关 +EVENT_LTS_SF = 'eLtsSf.' # SF基金查询推送事件 + +# 分级A算法相关 +EVENT_FUNDA_DATA = 'eFaData.' # 分级A基金更新事件 +EVENT_FUNDA_LOG = 'eFaLog' # 分级A算法日志事件 # ---------------------------------------------------------------------- def test(): diff --git a/vn.trader/ltsGateway.py b/vn.trader/ltsGateway.py index aeea737f..bfcff710 100644 --- a/vn.trader/ltsGateway.py +++ b/vn.trader/ltsGateway.py @@ -321,7 +321,7 @@ class LtsMdApi(MdApi): tick.lastPrice = data['LastPrice'] tick.volume = data['Volume'] tick.openInterest = data['OpenInterest'] - tick.tickTime = '.'.join([data['UpdateTime'], str(data['UpdateMillisec']/100)]) + tick.time = '.'.join([data['UpdateTime'], str(data['UpdateMillisec']/100)]) tick.date = data['TradingDay'] tick.openPrice = data['OpenPrice'] @@ -392,9 +392,9 @@ class LtsMdApi(MdApi): """订阅合约""" req = {} req['InstrumentID'] = str(subscribeReq.symbol) - req['ExchangeID'] = str(subscribeReq.exchange) - + req['ExchangeID'] = exchangeMap.get(str(subscribeReq.exchange), '') + # 这里的设计是,如果尚未登录就调用了订阅方法 # 则先保存订阅请求,登录完成后会自动订阅 if self.loginStatus: @@ -582,7 +582,7 @@ class LtsTdApi(TdApi): # 保存代码和报单号 order.symbol = data['InstrumentID'] - order.exchange = exchangeMapReverse[data['ExchangeID']] + order.exchange = exchangeMapReverse.get(data['ExchangeID'], '') order.vtSymbol = '.'.join([order.symbol, order.exchange]) order.orderID = data['OrderRef'] @@ -616,7 +616,7 @@ class LtsTdApi(TdApi): order.status = STATUS_UNKNOWN # 价格、报单量等数值 - order.price = data['LimitPrice'] + order.price = float(data['LimitPrice']) order.totalVolume = data['VolumeTotalOriginal'] order.tradedVolume = data['VolumeTraded'] order.orderTime = data['InsertTime'] @@ -639,7 +639,7 @@ class LtsTdApi(TdApi): # 保存代码和报单号 trade.symbol = data['InstrumentID'] - trade.exchange = exchangeMapReverse[data['ExchangeID']] + trade.exchange = exchangeMapReverse.get(data['ExchangeID'], '') trade.vtSymbol = '.'.join([trade.symbol, trade.exchange]) trade.tradeID = data['TradeID'] @@ -655,7 +655,7 @@ class LtsTdApi(TdApi): trade.offset = offsetMapReverse.get(data['OffsetFlag'], '') # 价格、报单量等数值 - trade.price = data['Price'] + trade.price = float(data['Price']) trade.volume = data['Volume'] trade.tradeTime = data['TradeTime'] @@ -772,10 +772,10 @@ class LtsTdApi(TdApi): req = {} - req['InstrumentID'] = orderReq.symbol + req['InstrumentID'] = str(orderReq.symbol) req['LimitPrice'] = str(orderReq.price) # LTS里的价格是字符串 - req['VolumeTotalOriginal'] = orderReq.volume - req['ExchangeID'] = orderReq.exchange + req['VolumeTotalOriginal'] = int(orderReq.volume) + req['ExchangeID'] = exchangeMap.get(orderReq.exchange, '') # 下面如果由于传入的类型本接口不支持,则会返回空字符串 try: @@ -1067,11 +1067,21 @@ class LtsQryApi(QryApi): def onRspQryOFInstrument(self, data, error, n, last): """OF合约查询回报""" pass - + # ---------------------------------------------------------------------- def onRspQrySFInstrument(self, data, error, n, last): """SF合约查询回报""" - pass + event1 = Event(type_=EVENT_LTS_SF) + event1.dict_['data'] = data + self.gateway.eventEngine.put(event1) + + symbol = data['InstrumentID'] + exchange = exchangeMapReverse[data['ExchangeID']] + vtSymbol = '.'.join([symbol, exchange]) + + event2 = Event(type_=EVENT_LTS_SF + vtSymbol) + event2.dict_['data'] = data + self.gateway.eventEngine.put(event2) # ---------------------------------------------------------------------- def onRspQryInstrumentUnitMargin(self, data, error, n, last): @@ -1141,11 +1151,12 @@ class LtsQryApi(QryApi): # 保存代码 pos.symbol = data['InstrumentID'] - pos.exchange = data['ExchangeID'] + pos.exchange = exchangeMapReverse.get(data['ExchangeID'], '') pos.vtSymbol = '.'.join([pos.symbol, pos.exchange]) # 方向和持仓冻结数量 pos.direction = posiDirectionMapReverse.get(data['PosiDirection'], '') + if pos.direction == DIRECTION_NET or pos.direction == DIRECTION_LONG: pos.frozen = data['LongFrozen'] elif pos.direction == DIRECTION_SHORT: @@ -1153,6 +1164,7 @@ class LtsQryApi(QryApi): # 持仓量 pos.position = data['Position'] + pos.ydPosition = data['YdPosition'] # 持仓均价 if pos.position: diff --git a/vn.trader/uiBasicWidget.py b/vn.trader/uiBasicWidget.py index 7c34f270..004cf403 100644 --- a/vn.trader/uiBasicWidget.py +++ b/vn.trader/uiBasicWidget.py @@ -473,6 +473,7 @@ class PositionMonitor(BasicMonitor): d['vtSymbol'] = {'chinese':u'名称', 'cellType':NameCell} d['direction'] = {'chinese':u'方向', 'cellType':DirectionCell} d['position'] = {'chinese':u'持仓量', 'cellType':BasicCell} + d['ydPosition'] = {'chinese':u'昨持仓', 'cellType':BasicCell} d['frozen'] = {'chinese':u'冻结量', 'cellType':BasicCell} d['price'] = {'chinese':u'价格', 'cellType':BasicCell} d['gatewayName'] = {'chinese':u'接口', 'cellType':BasicCell} @@ -761,7 +762,7 @@ class TradingWidget(QtGui.QFrame): """合约变化""" # 读取组件数据 - symbol = unicode(self.lineSymbol.text()) + symbol = str(self.lineSymbol.text()) exchange = unicode(self.comboExchange.currentText()) currency = unicode(self.comboCurrency.currentText()) productClass = unicode(self.comboProductClass.currentText()) @@ -923,7 +924,8 @@ class TradingWidget(QtGui.QFrame): def sendOrder(self): """发单""" - symbol = unicode(self.lineSymbol.text()) + symbol = str(self.lineSymbol.text()) + exchange = unicode(self.comboExchange.currentText()) currency = unicode(self.comboCurrency.currentText()) productClass = unicode(self.comboProductClass.currentText()) diff --git a/vn.trader/uiMainWindow.py b/vn.trader/uiMainWindow.py index 2a3194f7..71682c32 100644 --- a/vn.trader/uiMainWindow.py +++ b/vn.trader/uiMainWindow.py @@ -6,6 +6,7 @@ from uiBasicWidget import * from uiCtaWidget import CtaEngineManager + ######################################################################## class MainWindow(QtGui.QMainWindow): """主窗口""" @@ -19,6 +20,8 @@ class MainWindow(QtGui.QMainWindow): self.eventEngine = eventEngine self.dataEngine = dataEngine + self.widgetDict = {} # 用来保存子窗口的字典 + self.initUi() # ---------------------------------------------------------------------- @@ -90,7 +93,10 @@ class MainWindow(QtGui.QMainWindow): connectIbAction = QtGui.QAction(u'连接IB', self) - connectIbAction.triggered.connect(self.connectIb) + connectIbAction.triggered.connect(self.connectIb) + + connectDbAction = QtGui.QAction(u'连接数据库', self) + connectDbAction.triggered.connect(self.mainEngine.dbConnect) testAction = QtGui.QAction(u'测试', self) @@ -124,16 +130,25 @@ class MainWindow(QtGui.QMainWindow): sysMenu.addAction(connectIbAction) + sysMenu.addSeparator() + sysMenu.addAction(connectDbAction) + sysMenu.addSeparator() + sysMenu.addAction(testAction) sysMenu.addAction(exitAction) functionMenu = menubar.addMenu(u'功能') functionMenu.addAction(contractAction) - functionMenu.addAction(ctaAction) + + # 算法相关 + algoMenu = menubar.addMenu(u'算法') + algoMenu.addAction(ctaAction) + + # 帮助 helpMenu = menubar.addMenu(u'帮助') - helpMenu.addAction(aboutAction) + helpMenu.addAction(aboutAction) # ---------------------------------------------------------------------- def initStatusBar(self): @@ -201,54 +216,58 @@ class MainWindow(QtGui.QMainWindow): # ---------------------------------------------------------------------- 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') + api = self.mainEngine.gatewayDict['LTS'].qryApi + api.reqID += 1 + api.reqQryOFInstrument({}, api.reqID) - req.symbol = 'AAPL' - self.mainEngine.subscribe(req, 'IB') + #req = VtSubscribeReq() + #req.symbol = 'GOOG' + #req.productClass = PRODUCT_EQUITY + #req.exchange = EXCHANGE_SMART + #req.currency = CURRENCY_USD + #self.mainEngine.subscribe(req, 'IB') - req.symbol = 'YHOO' - self.mainEngine.subscribe(req, 'IB') + #req.symbol = 'AAPL' + #self.mainEngine.subscribe(req, 'IB') - req.symbol = 'MSFT' - 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') + #req.symbol = 'GE' + #self.mainEngine.subscribe(req, 'IB') + # ---------------------------------------------------------------------- def openAbout(self): """打开关于""" try: - self.aboutW.show() - except AttributeError: - self.aboutW = AboutWidget(self) - self.aboutW.show() + self.widgetDict['aboutW'].show() + except KeyError: + self.widgetDict['aboutW'] = AboutWidget(self) + self.widgetDict['aboutW'].show() # ---------------------------------------------------------------------- def openContract(self): """打开合约查询""" try: - self.contractM.show() - except AttributeError: - self.contractM = ContractMonitor(self.mainEngine.dataEngine) - self.contractM.show() - + self.widgetDict['contractM'].show() + except KeyError: + self.widgetDict['contractM'] = ContractMonitor(self.mainEngine.dataEngine) + self.widgetDict['contractM'].show() + # ---------------------------------------------------------------------- def openCta(self): """打开CTA组件""" try: - self.ctaM.show() - except AttributeError: - self.ctaM = CtaEngineManager(self.mainEngine.ctaEngine, self.eventEngine) - self.ctaM.show() - - + self.widgetDict['ctaM'].show() + except KeyError: + self.widgetDict['ctaM'] = CtaEngineManager(self.mainEngine.ctaEngine, self.eventEngine) + self.widgetDict['ctaM'].show() + # ---------------------------------------------------------------------- def closeEvent(self, event): """关闭事件""" @@ -256,7 +275,9 @@ class MainWindow(QtGui.QMainWindow): u'确认退出?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) - if reply == QtGui.QMessageBox.Yes: + if reply == QtGui.QMessageBox.Yes: + for widget in self.widgetDict.values(): + widget.close() self.mainEngine.exit() event.accept() else: diff --git a/vn.trader/vtConstant.py b/vn.trader/vtConstant.py index 54c631c3..60d3620b 100644 --- a/vn.trader/vtConstant.py +++ b/vn.trader/vtConstant.py @@ -49,18 +49,20 @@ OPTION_CALL = u'看涨期权' OPTION_PUT = u'看跌期权' # 交易所类型 -EXCHANGE_SSE = u'SSE' # 上交所 -EXCHANGE_SZSE = u'SZSE' # 深交所 -EXCHANGE_CFFEX = u'CFFEX' # 中金所 -EXCHANGE_SHFE = u'SHFE' # 上期所 -EXCHANGE_CZCE = u'CZCE' # 郑商所 -EXCHANGE_DCE = u'DCE' # 大商所 + +EXCHANGE_SSE = 'SSE' # 上交所 +EXCHANGE_SZSE = 'SZSE' # 深交所 +EXCHANGE_CFFEX = 'CFFEX' # 中金所 +EXCHANGE_SHFE = 'SHFE' # 上期所 +EXCHANGE_CZCE = 'CZCE' # 郑商所 +EXCHANGE_DCE = 'DCE' # 大商所 + EXCHANGE_UNKNOWN = 'UNKNOWN'# 未知交易所 EXCHANGE_NONE = '' # 空交易所 -EXCHANGE_SMART = u'SMART' # IB智能路由(股票、期权) -EXCHANGE_GLOBEX = u'GLOBEX' # CME电子交易平台 -EXCHANGE_IDEALPRO = u'IDEALPRO' # IB外汇ECN +EXCHANGE_SMART = 'SMART' # IB智能路由(股票、期权) +EXCHANGE_GLOBEX = 'GLOBEX' # CME电子交易平台 +EXCHANGE_IDEALPRO = 'IDEALPRO' # IB外汇ECN # 货币类型 CURRENCY_USD = 'USD' # 美元 diff --git a/vn.trader/vtEngine.py b/vn.trader/vtEngine.py index 1c491f1f..71b8e568 100644 --- a/vn.trader/vtEngine.py +++ b/vn.trader/vtEngine.py @@ -7,10 +7,6 @@ from pymongo import MongoClient from pymongo.errors import ConnectionFailure from eventEngine import * -from ctpGateway import CtpGateway -from ltsGateway import LtsGateway -#from windGateway import WindGateway -from ibGateway import IbGateway from vtGateway import * import uiBasicWidget from ctaEngine import CtaEngine @@ -35,22 +31,44 @@ class MainEngine(object): self.gatewayDict = OrderedDict() # 创建我们想要接入的接口对象 - self.addGateway(CtpGateway, 'CTP') - self.gatewayDict['CTP'].setQryEnabled(True) - self.addGateway(CtpGateway, 'CTP_Prod') - self.gatewayDict['CTP_Prod'].setQryEnabled(True) + try: + from ctpGateway import CtpGateway - self.addGateway(CtpGateway, 'CTP_Post') - self.gatewayDict['CTP_Post'].setQryEnabled(True) + self.addGateway(CtpGateway, 'CTP') + self.gatewayDict['CTP'].setQryEnabled(True) - self.addGateway(CtpGateway, 'CTP_Test') - self.gatewayDict['CTP_Test'].setQryEnabled(True) + self.addGateway(CtpGateway, 'CTP_Prod') + self.gatewayDict['CTP_Prod'].setQryEnabled(True) + + self.addGateway(CtpGateway, 'CTP_Post') + self.gatewayDict['CTP_Post'].setQryEnabled(True) + + self.addGateway(CtpGateway, 'CTP_Test') + self.gatewayDict['CTP_Test'].setQryEnabled(True) + except Exception, e: + print e + + try: + from ltsGateway import LtsGateway + self.addGateway(LtsGateway, 'LTS') + self.gatewayDict['LTS'].setQryEnabled(True) + except Exception, e: + print e - self.addGateway(LtsGateway, 'LTS') - self.gatewayDict['LTS'].setQryEnabled(True) + + try: + from windGateway import WindGateway + self.addGateway(WindGateway, 'Wind') + except Exception, e: + print e + + try: + from ibGateway import IbGateway + self.addGateway(IbGateway, 'IB') + except Exception, e: + print e - #self.addGateway(WindGateway, 'Wind') # 没有Wind的请注释掉这一行 # MongoDB数据库相关 self.dbClient = None # MongoDB客户端对象 diff --git a/vn.trader/vtGateway.py b/vn.trader/vtGateway.py index 666a499f..f968d78f 100644 --- a/vn.trader/vtGateway.py +++ b/vn.trader/vtGateway.py @@ -33,10 +33,15 @@ class VtGateway(object): # ---------------------------------------------------------------------- def onTrade(self, trade): """成交信息推送""" - # 因为成交通常都是事后才会知道成交编号,因此只需要推送通用事件 + # 通用事件 event1 = Event(type_=EVENT_TRADE) event1.dict_['data'] = trade self.eventEngine.put(event1) + + # 特定合约的成交事件 + event2 = Event(type_=EVENT_TRADE+trade.vtSymbol) + event2.dict_['data'] = trade + self.eventEngine.put(event2) # ---------------------------------------------------------------------- def onOrder(self, order): @@ -60,7 +65,7 @@ class VtGateway(object): self.eventEngine.put(event1) # 特定合约代码的事件 - event2 = Event(type_=EVENT_POSITION+position.vtPositionName) + event2 = Event(type_=EVENT_POSITION+position.vtSymbol) event2.dict_['data'] = position self.eventEngine.put(event2) @@ -286,6 +291,9 @@ class VtPositionData(VtBaseData): self.frozen = EMPTY_INT # 冻结数量 self.price = EMPTY_FLOAT # 持仓均价 self.vtPositionName = EMPTY_STRING # 持仓在vt系统中的唯一代码,通常是vtSymbol.方向 + + # 20151020添加 + self.ydPosition = EMPTY_INT # 昨持仓 ######################################################################## @@ -363,7 +371,7 @@ class VtContractData(VtBaseData): ######################################################################## -class VtSubscribeReq: +class VtSubscribeReq(object): """订阅行情时传入的对象类""" # ---------------------------------------------------------------------- @@ -381,7 +389,7 @@ class VtSubscribeReq: ######################################################################## -class VtOrderReq: +class VtOrderReq(object): """发单时传入的对象类""" # ---------------------------------------------------------------------- @@ -405,7 +413,7 @@ class VtOrderReq: ######################################################################## -class VtCancelOrderReq: +class VtCancelOrderReq(object): """撤单时传入的对象类""" # ---------------------------------------------------------------------- @@ -418,9 +426,9 @@ class VtCancelOrderReq: self.orderID = EMPTY_STRING # 报单号 self.frontID = EMPTY_STRING # 前置机号 self.sessionID = EMPTY_STRING # 会话号 - - - + + + diff --git a/vn.trader/windGateway.py b/vn.trader/windGateway.py index 5bcad2a1..3587a214 100644 --- a/vn.trader/windGateway.py +++ b/vn.trader/windGateway.py @@ -3,7 +3,8 @@ ''' Wind Python API的gateway接入 ''' -from threading import Thread + +from copy import copy try: from WindPy import w @@ -166,7 +167,8 @@ class WindGateway(VtGateway): value = values[n][0] d[key] = value - self.onTick(tick) + newtick = copy(tick) + self.onTick(newtick) # ---------------------------------------------------------------------- def wConnect(self, event):