diff --git a/.gitignore b/.gitignore index 8b4c1ece..c0b231cf 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ Release/ *.local *.temp *.vt +*.dat ======= vn.ctp/build/* vn.lts/build/* diff --git a/vn.trader/VT_setting.json b/vn.trader/VT_setting.json index d71864d1..c794cd52 100644 --- a/vn.trader/VT_setting.json +++ b/vn.trader/VT_setting.json @@ -1,4 +1,7 @@ { "fontFamily": "微软雅黑", - "fontSize": 12 + "fontSize": 12, + + "mongoHost": "localhost", + "mongoPort": 27017 } \ No newline at end of file diff --git a/vn.trader/ctaAlgo/ctaBacktesting.py b/vn.trader/ctaAlgo/ctaBacktesting.py index 143e1a40..01995455 100644 --- a/vn.trader/ctaAlgo/ctaBacktesting.py +++ b/vn.trader/ctaAlgo/ctaBacktesting.py @@ -7,7 +7,6 @@ from datetime import datetime, timedelta from collections import OrderedDict -import json import pymongo from ctaBase import * @@ -15,6 +14,7 @@ from ctaSetting import * from vtConstant import * from vtGateway import VtOrderData, VtTradeData +from vtFunction import loadMongoSetting ######################################################################## @@ -51,11 +51,12 @@ class BacktestingEngine(object): self.dbClient = None # 数据库客户端 self.dbCursor = None # 数据库指针 - self.historyData = [] # 历史数据的列表,回测用 + #self.historyData = [] # 历史数据的列表,回测用 self.initData = [] # 初始化用的数据 - self.backtestingData = [] # 回测用的数据 + #self.backtestingData = [] # 回测用的数据 self.dataStartDate = None # 回测数据开始日期,datetime对象 + self.dataEndDate = None # 回测数据结束日期,datetime对象 self.strategyStartDate = None # 策略启动日期(即前面的数据用于初始化),datetime对象 self.limitOrderDict = OrderedDict() # 限价单字典 @@ -80,6 +81,12 @@ class BacktestingEngine(object): initTimeDelta = timedelta(initDays) self.strategyStartDate = self.dataStartDate + initTimeDelta + #---------------------------------------------------------------------- + def setEndDate(self, endDate=''): + """设置回测的结束日期""" + if endDate: + self.dataEndDate= datetime.strptime(endDate, '%Y%m%d') + #---------------------------------------------------------------------- def setBacktestingMode(self, mode): """设置回测模式""" @@ -88,35 +95,53 @@ class BacktestingEngine(object): #---------------------------------------------------------------------- def loadHistoryData(self, dbName, symbol): """载入历史数据""" - self.output(u'开始载入数据') + host, port = loadMongoSetting() + self.dbClient = pymongo.MongoClient(host, port) + collection = self.dbClient[dbName][symbol] + + self.output(u'开始载入数据') + # 首先根据回测模式,确认要使用的数据类 if self.mode == self.BAR_MODE: dataClass = CtaBarData + func = self.newBar else: dataClass = CtaTickData - - # 从数据库进行查询 - self.dbClient = pymongo.MongoClient() - collection = self.dbClient[dbName][symbol] - - flt = {'datetime':{'$gte':self.dataStartDate}} # 数据过滤条件 - self.dbCursor = collection.find(flt) + func = self.newTick + + # 载入初始化需要用的数据 + flt = {'datetime':{'$gte':self.dataStartDate, + '$lt':self.strategyStartDate}} + initCursor = collection.find(flt) # 将数据从查询指针中读取出,并生成列表 - for d in self.dbCursor: + for d in initCursor: data = dataClass() data.__dict__ = d - if data.datetime < self.strategyStartDate: - self.initData.append(data) - else: - self.backtestingData.append(data) + self.initData.append(data) + + # 载入回测数据 + if not self.dataEndDate: + flt = {'datetime':{'$gte':self.strategyStartDate}} # 数据过滤条件 + else: + flt = {'datetime':{'$gte':self.strategyStartDate, + '$lte':self.dataEndDate}} + self.dbCursor = collection.find(flt) + + self.output(u'载入完成,数据量:%s' %(initCursor.count() + self.dbCursor.count())) - self.output(u'载入完成,数据量:%s' %len(self.backtestingData)) - #---------------------------------------------------------------------- def runBacktesting(self): """运行回测""" + # 首先根据回测模式,确认要使用的数据类 + if self.mode == self.BAR_MODE: + dataClass = CtaBarData + func = self.newBar + else: + dataClass = CtaTickData + func = self.newTick + self.output(u'开始回测') self.strategy.inited = True @@ -128,13 +153,13 @@ class BacktestingEngine(object): self.output(u'策略启动完成') self.output(u'开始回放数据') - if self.mode == self.BAR_MODE: - for data in self.backtestingData: - self.newBar(data) - #print str(data.datetime) - else: - for data in self.backtestingData: - self.newTick(data) + + for d in self.dbCursor: + data = dataClass() + data.__dict__ = d + func(data) + + self.output(u'数据回放结束') #---------------------------------------------------------------------- def newBar(self, bar): diff --git a/vn.trader/ctaAlgo/ctaBase.py b/vn.trader/ctaAlgo/ctaBase.py index ef2dbd59..f0fffbca 100644 --- a/vn.trader/ctaAlgo/ctaBase.py +++ b/vn.trader/ctaAlgo/ctaBase.py @@ -45,6 +45,7 @@ class StopOrder(object): def __init__(self): """Constructor""" self.vtSymbol = EMPTY_STRING + self.orderType = EMPTY_UNICODE self.direction = EMPTY_UNICODE self.offset = EMPTY_UNICODE self.price = EMPTY_FLOAT diff --git a/vn.trader/ctaAlgo/ctaEngine.py b/vn.trader/ctaAlgo/ctaEngine.py index 9fa53304..affae16e 100644 --- a/vn.trader/ctaAlgo/ctaEngine.py +++ b/vn.trader/ctaAlgo/ctaEngine.py @@ -118,6 +118,7 @@ class CtaEngine(object): so = StopOrder() so.vtSymbol = vtSymbol + so.orderType = orderType so.price = price so.volume = volume so.strategy = strategy @@ -163,7 +164,7 @@ class CtaEngine(object): for so in self.workingStopOrderDict.values(): if so.vtSymbol == vtSymbol: longTriggered = so.direction==DIRECTION_LONG and tick.lastPrice>=so.price # 多头停止单被触发 - shortTriggered = so.direction==DIRECTION_SHORT and tick.lasatPrice<=so.price # 空头停止单被触发 + shortTriggered = so.direction==DIRECTION_SHORT and tick.lastPrice<=so.price # 空头停止单被触发 if longTriggered or shortTriggered: # 买入和卖出分别以涨停跌停价发单(模拟市价单) diff --git a/vn.trader/ctaAlgo/ctaHistoryData.py b/vn.trader/ctaAlgo/ctaHistoryData.py index c35cc563..18304301 100644 --- a/vn.trader/ctaAlgo/ctaHistoryData.py +++ b/vn.trader/ctaAlgo/ctaHistoryData.py @@ -13,6 +13,7 @@ from multiprocessing.pool import ThreadPool from ctaBase import * from vtConstant import * +from vtFunction import loadMongoSetting from datayesClient import DatayesClient @@ -32,7 +33,9 @@ class HistoryDataEngine(object): #---------------------------------------------------------------------- def __init__(self): """Constructor""" - self.dbClient = pymongo.MongoClient() + host, port = loadMongoSetting() + + self.dbClient = pymongo.MongoClient(host, port) self.datayesClient = DatayesClient() #---------------------------------------------------------------------- @@ -319,7 +322,9 @@ def loadMcCsv(fileName, dbName, symbol): print u'开始读取CSV文件%s中的数据插入到%s的%s中' %(fileName, dbName, symbol) # 锁定集合,并创建索引 - client = pymongo.MongoClient() + host, port = loadMongoSetting() + + client = pymongo.MongoClient(host, port) collection = client[dbName][symbol] collection.ensure_index([('datetime', pymongo.ASCENDING)], unique=True) diff --git a/vn.trader/ltsGateway/ltsGateway.py b/vn.trader/ltsGateway/ltsGateway.py index 10bc0939..d3fa3ea3 100644 --- a/vn.trader/ltsGateway/ltsGateway.py +++ b/vn.trader/ltsGateway/ltsGateway.py @@ -41,6 +41,7 @@ offsetMapReverse = {v:k for k,v in offsetMap.items()} exchangeMap = {} exchangeMap[EXCHANGE_SSE] = 'SSE' exchangeMap[EXCHANGE_SZSE] = 'SZE' +exchangeMap[EXCHANGE_HKEX] = 'HGE' exchangeMapReverse = {v:k for k,v in exchangeMap.items()} # 持仓类型映射 diff --git a/vn.trader/sgitGateway/SGIT_connect.json b/vn.trader/sgitGateway/SGIT_connect.json index 40c3a88d..75007d3c 100644 --- a/vn.trader/sgitGateway/SGIT_connect.json +++ b/vn.trader/sgitGateway/SGIT_connect.json @@ -1,7 +1,7 @@ { "brokerID": "0017", "tdAddress": "tcp://140.206.81.6:17776", - "password": "联系招金投资申请", + "password": "请联系招金投资申请", "mdAddress": "tcp://140.206.81.6:17777", - "userID": "联系招金投资申请" + "userID": "请联系招金投资申请" } \ No newline at end of file diff --git a/vn.trader/sgitGateway/sgitGateway.py b/vn.trader/sgitGateway/sgitGateway.py index 10b8eb71..defe0bb0 100644 --- a/vn.trader/sgitGateway/sgitGateway.py +++ b/vn.trader/sgitGateway/sgitGateway.py @@ -385,6 +385,26 @@ class SgitMdApi(MdApi): tick.bidVolume1 = data['BidVolume1'] tick.askPrice1 = data['AskPrice1'] tick.askVolume1 = data['AskVolume1'] + + tick.bidPrice2 = data['BidPrice2'] + tick.bidVolume2 = data['BidVolume2'] + tick.askPrice2 = data['AskPrice2'] + tick.askVolume2 = data['AskVolume2'] + + tick.bidPrice3 = data['BidPrice3'] + tick.bidVolume3 = data['BidVolume3'] + tick.askPrice3 = data['AskPrice3'] + tick.askVolume3 = data['AskVolume3'] + + tick.bidPrice4 = data['BidPrice4'] + tick.bidVolume4 = data['BidVolume4'] + tick.askPrice4 = data['AskPrice4'] + tick.askVolume4 = data['AskVolume4'] + + tick.bidPrice5 = data['BidPrice5'] + tick.bidVolume5 = data['BidVolume5'] + tick.askPrice5 = data['AskPrice5'] + tick.askVolume5 = data['AskVolume5'] self.gateway.onTick(tick) @@ -411,6 +431,7 @@ class SgitTdApi(TdApi): self.password = EMPTY_STRING # 密码 self.brokerID = EMPTY_STRING # 经纪商代码 self.address = EMPTY_STRING # 服务器地址 + self.investorID = EMPTY_STRING # 投资者代码 self.frontID = EMPTY_INT # 前置机编号 self.sessionID = EMPTY_INT # 会话编号 @@ -500,7 +521,7 @@ class SgitTdApi(TdApi): return '' req['OrderRef'] = strID - req['InvestorID'] = self.userID + req['InvestorID'] = self.investorID req['UserID'] = self.userID req['BrokerID'] = self.brokerID @@ -574,7 +595,7 @@ class SgitTdApi(TdApi): #---------------------------------------------------------------------- def onRspUserLogin(self, data, error, n, last): - """登陆回报""" + '''登陆回报''' # 如果登录成功,推送日志信息 if error['ErrorID'] == 0: self.loginStatus = True @@ -588,9 +609,9 @@ class SgitTdApi(TdApi): # 调用ready self.ready() - # 查询合约代码 + # 查询投资者代码 self.reqID += 1 - self.reqQryInstrument({}, self.reqID) + self.reqQryInvestor({}, self.reqID) # 否则,推送错误信息 else: @@ -702,7 +723,17 @@ class SgitTdApi(TdApi): #---------------------------------------------------------------------- def onRspQryInvestor(self, data, error, n, last): """""" - pass + self.investorID = data['InvestorID'] + + if last: + log = VtLogData() + log.gatewayName = self.gatewayName + log.logContent = u'投资者编码获取完成' + self.gateway.onLog(log) + + # 查询合约 + self.reqID += 1 + self.reqQryInstrument({}, self.reqID) #---------------------------------------------------------------------- def onRspQryInstrument(self, data, error, n, last): diff --git a/vn.trader/uiBasicWidget.py b/vn.trader/uiBasicWidget.py index 0554d692..9701dac3 100644 --- a/vn.trader/uiBasicWidget.py +++ b/vn.trader/uiBasicWidget.py @@ -557,7 +557,6 @@ class OrderMonitor(BasicMonitor): ######################################################################## class PositionMonitor(BasicMonitor): """持仓监控""" - #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine, parent=None): """Constructor""" @@ -577,10 +576,12 @@ class PositionMonitor(BasicMonitor): self.setDataKey('vtPositionName') self.setEventType(EVENT_POSITION) self.setFont(BASIC_FONT) + self.setSaveData(True) + self.initTable() self.registerEvent() - - + + ######################################################################## class AccountMonitor(BasicMonitor): """账户监控""" @@ -635,6 +636,7 @@ class TradingWidget(QtGui.QFrame): EXCHANGE_SSE, EXCHANGE_SZSE, EXCHANGE_SGE, + EXCHANGE_HKEX, EXCHANGE_SMART, EXCHANGE_GLOBEX, EXCHANGE_IDEALPRO] @@ -1008,6 +1010,29 @@ class TradingWidget(QtGui.QFrame): req.sessionID = order.sessionID req.orderID = order.orderID self.mainEngine.cancelOrder(req, order.gatewayName) + + #---------------------------------------------------------------------- + def closePosition(self, cell): + """根据持仓信息自动填写交易组件""" + # 读取持仓数据,cell是一个表格中的单元格对象 + pos = cell.data + symbol = pos.symbol + + # 更新交易组件的显示合约 + self.lineSymbol.setText(symbol) + self.updateSymbol() + + # 自动填写信息 + self.comboPriceType.setCurrentIndex(self.priceTypeList.index(PRICETYPE_LIMITPRICE)) + self.comboOffset.setCurrentIndex(self.offsetList.index(OFFSET_CLOSE)) + self.spinVolume.setValue(pos.position) + + if pos.direction == DIRECTION_LONG or pos.direction == DIRECTION_NET: + self.comboDirection.setCurrentIndex(self.directionList.index(DIRECTION_SHORT)) + else: + self.comboDirection.setCurrentIndex(self.directionList.index(DIRECTION_LONG)) + + # 价格留待更新后由用户输入,防止有误操作 ######################################################################## diff --git a/vn.trader/uiMainWindow.py b/vn.trader/uiMainWindow.py index 3578c7c6..1db5f885 100644 --- a/vn.trader/uiMainWindow.py +++ b/vn.trader/uiMainWindow.py @@ -67,6 +67,9 @@ class MainWindow(QtGui.QMainWindow): central.setLayout(grid) self.setCentralWidget(central) + # 连接组件之间的信号 + positionM.itemDoubleClicked.connect(tradingW.closePosition) + #---------------------------------------------------------------------- def initMenu(self): """初始化菜单""" diff --git a/vn.trader/vtConstant.py b/vn.trader/vtConstant.py index e1467b04..0492cc4b 100644 --- a/vn.trader/vtConstant.py +++ b/vn.trader/vtConstant.py @@ -61,6 +61,7 @@ EXCHANGE_DCE = 'DCE' # 大商所 EXCHANGE_SGE = 'SGE' # 上金所 EXCHANGE_UNKNOWN = 'UNKNOWN'# 未知交易所 EXCHANGE_NONE = '' # 空交易所 +EXCHANGE_HKEX = 'HKEX' # 港交所 EXCHANGE_SMART = 'SMART' # IB智能路由(股票、期权) EXCHANGE_GLOBEX = 'GLOBEX' # CME电子交易平台 diff --git a/vn.trader/vtEngine.py b/vn.trader/vtEngine.py index 938d25b7..c5f353c1 100644 --- a/vn.trader/vtEngine.py +++ b/vn.trader/vtEngine.py @@ -8,6 +8,7 @@ from pymongo.errors import ConnectionFailure from eventEngine import * from vtGateway import * +from vtFunction import loadMongoSetting from ctaAlgo.ctaEngine import CtaEngine from dataRecorder.drEngine import DrEngine @@ -197,8 +198,11 @@ class MainEngine(object): def dbConnect(self): """连接MongoDB数据库""" if not self.dbClient: + # 读取MongoDB的设置 + host, port = loadMongoSetting() + try: - self.dbClient = MongoClient() + self.dbClient = MongoClient(host, port) self.writeLog(u'MongoDB连接成功') except ConnectionFailure: self.writeLog(u'MongoDB连接失败') diff --git a/vn.trader/vtFunction.py b/vn.trader/vtFunction.py index 4ec3942d..89a70df8 100644 --- a/vn.trader/vtFunction.py +++ b/vn.trader/vtFunction.py @@ -23,4 +23,20 @@ def safeUnicode(value): if abs(d.as_tuple().exponent) > MAX_DECIMAL: value = round(value, ndigits=MAX_DECIMAL) - return unicode(value) \ No newline at end of file + return unicode(value) + +#---------------------------------------------------------------------- +def loadMongoSetting(): + """载入MongoDB数据库的配置""" + try: + f = file("VT_setting.json") + setting = json.load(f) + host = setting['mongoHost'] + port = setting['mongoPort'] + except: + host = 'localhost' + port = 27017 + + return host, port + + \ No newline at end of file