From 1fdddd2033a9fe5f210bae3f8580d61c620df45c Mon Sep 17 00:00:00 2001 From: chenxy123 Date: Wed, 27 Apr 2016 22:49:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B9=8B=E5=89=8D=E4=BF=AE=E6=94=B9=E7=9A=84CT?= =?UTF-8?q?P=E7=9A=84=E4=B8=8A=E6=9C=9F=E6=89=80=E6=8C=81=E4=BB=93?= =?UTF-8?q?=E4=BE=9D=E6=97=A7=E6=9C=89=E6=89=80=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=9F=BA=E4=BA=8E=E6=8C=81=E4=BB=93=E6=95=B0=E6=8D=AE=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E7=9A=84=E6=A8=A1=E5=BC=8F=E8=BF=9B=E8=A1=8C=E4=BA=86?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=8C=E5=90=8C=E6=97=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=9B=9E=E6=B5=8B=E5=BC=95=E6=93=8E=E4=B8=AD=E7=9A=84=E4=B8=80?= =?UTF-8?q?=E4=B8=AAtick=E5=9B=9E=E6=B5=8B=E7=9B=B8=E5=85=B3=E7=9A=84bug?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../settings/Windows Azure Subscriptions.xml | 5 - vn.trader/ctaAlgo/ctaBacktesting.py | 1 + vn.trader/ctpGateway/ctpGateway.py | 113 +++++++++++------- 3 files changed, 73 insertions(+), 46 deletions(-) delete mode 100644 vn.ctp/vnctptd/Visual Studio 2013/settings/Windows Azure Subscriptions.xml diff --git a/vn.ctp/vnctptd/Visual Studio 2013/settings/Windows Azure Subscriptions.xml b/vn.ctp/vnctptd/Visual Studio 2013/settings/Windows Azure Subscriptions.xml deleted file mode 100644 index 5866a6cd..00000000 --- a/vn.ctp/vnctptd/Visual Studio 2013/settings/Windows Azure Subscriptions.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAhE4p+D02F0WYPy8qCmMXxAAAAAACAAAAAAAQZgAAAAEAACAAAABqqZf7eO/8AqQFqurp2lQDI7ZnZtjWpYLxdEZZGWoeTgAAAAAOgAAAAAIAACAAAACO1demA+YL03Dkjrvv0fYv1k0mGB4XD5t7YYCfD7RdCBAAAACmf9hwg57+FQ2Y5W5BmkdtQAAAAO2Nz3wpQbXLHeGtVRYjAqDcPS8ZJZJVEQ17yhmhHxf12PU4Ru3qr5bEI9j6zaanFd0dF00D4aUwUNKJ5o5raII= - \ No newline at end of file diff --git a/vn.trader/ctaAlgo/ctaBacktesting.py b/vn.trader/ctaAlgo/ctaBacktesting.py index 01995455..35220f1b 100644 --- a/vn.trader/ctaAlgo/ctaBacktesting.py +++ b/vn.trader/ctaAlgo/ctaBacktesting.py @@ -174,6 +174,7 @@ class BacktestingEngine(object): def newTick(self, tick): """新的Tick""" self.tick = tick + self.dt = tick.datetime self.crossLimitOrder() self.crossStopOrder() self.strategy.onTick(tick) diff --git a/vn.trader/ctpGateway/ctpGateway.py b/vn.trader/ctpGateway/ctpGateway.py index afe959c2..dcd444ff 100644 --- a/vn.trader/ctpGateway/ctpGateway.py +++ b/vn.trader/ctpGateway/ctpGateway.py @@ -17,6 +17,7 @@ from vnctptd import TdApi from ctpDataType import * from vtGateway import * + # 以下为一些VT类型和CTP类型的映射字典 # 价格类型映射 priceTypeMap = {} @@ -437,7 +438,7 @@ class CtpTdApi(TdApi): self.frontID = EMPTY_INT # 前置机编号 self.sessionID = EMPTY_INT # 会话编号 - self.posDict = {} # 缓存持仓数据的字典 + self.posBufferDict = {} # 缓存持仓数据的字典 #---------------------------------------------------------------------- def onFrontConnected(self): @@ -627,44 +628,18 @@ class CtpTdApi(TdApi): #---------------------------------------------------------------------- def onRspQryInvestorPosition(self, data, error, n, last): """持仓查询回报""" - # 获取缓存字典中的持仓对象,若无则创建并初始化 + # 获取缓存字典中的持仓缓存,若无则创建并初始化 positionName = '.'.join([data['InstrumentID'], data['PosiDirection']]) - if positionName in self.posDict: - pos = self.posDict[positionName] + if positionName in self.posBufferDict: + posBuffer = self.posBufferDict[positionName] else: - pos = VtPositionData() - self.posDict[positionName] = pos - - pos.gatewayName = self.gatewayName + posBuffer = PositionBuffer(data, self.gatewayName) + self.posBufferDict[positionName] = posBuffer - # 保存代码 - pos.symbol = data['InstrumentID'] - pos.vtSymbol = pos.symbol # 这里因为data中没有ExchangeID这个字段 - - # 方向 - pos.direction = posiDirectionMapReverse.get(data['PosiDirection'], '') - - # VT系统持仓名 - pos.vtPositionName = '.'.join([pos.vtSymbol, pos.direction]) - - # 持仓冻结数量 - if pos.direction == DIRECTION_NET or pos.direction == DIRECTION_LONG: - pos.frozen = data['LongFrozen'] - elif pos.direction == DIRECTION_SHORT: - pos.frozen = data['ShortFrozen'] - - # 持仓量 - pos.position = data['Position'] - pos.ydPosition = data['Position'] - data['TodayPosition'] - - # 持仓均价 - if pos.position: - pos.price = data['PositionCost'] / pos.position - - # 推送 - newpos = copy(pos) - self.gateway.onPosition(newpos) + # 更新持仓缓存,并获取VT系统中持仓对象的返回值 + pos = posBuffer.updateBuffer(data) + self.gateway.onPosition(pos) #---------------------------------------------------------------------- def onRspQryTradingAccount(self, data, error, n, last): @@ -1255,12 +1230,9 @@ class CtpTdApi(TdApi): req['VolumeTotalOriginal'] = orderReq.volume # 下面如果由于传入的类型本接口不支持,则会返回空字符串 - try: - req['OrderPriceType'] = priceTypeMap[orderReq.priceType] - req['Direction'] = directionMap[orderReq.direction] - req['CombOffsetFlag'] = offsetMap[orderReq.offset] - except KeyError: - return '' + req['OrderPriceType'] = priceTypeMap.get(orderReq.priceType, '') + req['Direction'] = directionMap.get(orderReq.direction, '') + req['CombOffsetFlag'] = offsetMap.get(orderReq.offset, '') req['OrderRef'] = str(self.orderRef) req['InvestorID'] = self.userID @@ -1275,6 +1247,16 @@ class CtpTdApi(TdApi): req['VolumeCondition'] = defineDict['THOST_FTDC_VC_AV'] # 任意成交量 req['MinVolume'] = 1 # 最小成交量为1 + # 判断FAK和FOK + if orderReq.priceType == PRICETYPE_FAK: + req['OrderPriceType'] = defineDict["THOST_FTDC_OPT_LimitPrice"] + req['TimeCondition'] = defineDict['THOST_FTDC_TC_IOC'] + req['VolumeCondition'] = defineDict['THOST_FTDC_VC_AV'] + if orderReq.priceType == PRICETYPE_FOK: + req['OrderPriceType'] = defineDict["THOST_FTDC_OPT_LimitPrice"] + req['TimeCondition'] = defineDict['THOST_FTDC_TC_IOC'] + req['VolumeCondition'] = defineDict['THOST_FTDC_VC_CV'] + self.reqOrderInsert(req, self.reqID) # 返回订单号(字符串),便于某些算法进行动态管理 @@ -1306,6 +1288,55 @@ class CtpTdApi(TdApi): self.exit() +######################################################################## +class PositionBuffer(object): + """用来缓存持仓的数据,处理上期所的数据返回分今昨的问题""" + + #---------------------------------------------------------------------- + def __init__(self, data, gatewayName): + """Constructor""" + self.symbol = data['InstrumentID'] + self.direction = posiDirectionMapReverse.get(data['PosiDirection'], '') + + self.todayPosition = EMPTY_INT + self.ydPosition = EMPTY_INT + self.todayPositionCost = EMPTY_FLOAT + self.ydPositionCost = EMPTY_FLOAT + + # 通过提前创建持仓数据对象并重复使用的方式来降低开销 + pos = VtPositionData() + pos.symbol = self.symbol + pos.vtSymbol = self.symbol + pos.gatewayName = gatewayName + pos.direction = self.direction + pos.vtPositionName = '.'.join([pos.vtSymbol, pos.direction]) + self.pos = pos + + #---------------------------------------------------------------------- + def updateBuffer(self, data): + """更新缓存,返回更新后的持仓数据""" + # 昨仓和今仓的数据更新是分在两条记录里的,因此需要判断检查该条记录对应仓位 + if data['TodayPosition']: + self.todayPosition = data['Position'] + self.todayPositionCost = data['PositionCost'] + elif data['YdPosition']: + self.ydPosition = data['Position'] + self.ydPositionCost = data['PositionCost'] + + # 持仓的昨仓和今仓相加后为总持仓 + self.pos.position = self.todayPosition + self.ydPosition + self.pos.ydPosition = self.ydPosition + + # 如果手头还有持仓,则通过加权平均方式计算持仓均价 + if self.todayPosition or self.ydPosition: + self.pos.price = ((self.todayPositionCost + self.ydPositionCost)/ + (self.todayPosition + self.ydPosition)) + # 否则价格为0 + else: + self.pos.price = 0 + + return copy(self.pos) + #---------------------------------------------------------------------- def test(): """测试"""