diff --git a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py index 4618666..b2c0ce4 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py +++ b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py @@ -260,12 +260,13 @@ def loadHistoryData(self, symbolList, startDate, endDate=None, dataMode=None): self.output(f"{symbol}: 从本地缓存文件实取{acq}, 最大应取{need}, 还需从数据库取{need-acq}") # 如果没有完全从本地文件加载完数据, 则尝试从指定的mongodb下载数据, 并缓存到本地 - if self.dbURI: + dbName = None + if dataMode == self.BAR_MODE: + dbName = self.bardbName + else: + dbName = self.tickdbName + if self.dbURI and dbName is not None: # 有设置从指定数据库和表取数据 import pymongo - if dataMode == self.BAR_MODE: - dbName = self.bardbName - else: - dbName = self.tickdbName self.dbClient = pymongo.MongoClient(self.dbURI)[dbName] for symbol, need_datetimes in symbols_no_data.items(): if len(need_datetimes) > 0: # 需要从数据库取数据 @@ -300,7 +301,7 @@ def loadHistoryData(self, symbolList, startDate, endDate=None, dataMode=None): self.output("数据库没有 %s 这个品种" % symbol) self.output("这些品种在我们的数据库里: %s" % self.dbClient.collection_names()) else: - self.output('没有设置回测数据库URI, 无法回补缓存数据。请在回测设置 engine.setDB_URI("mongodb://localhost:27017")') + self.output('没有设置回测数据库相关信息, 无法回补缓存数据。请在回测入口设置 engine.setDB_URI 和 engine.setDatabase') if len(dataList) > 0: dataList.sort(key=lambda x: x.datetime) diff --git a/vnpy/trader/gateway/okexGateway/spot.py b/vnpy/trader/gateway/okexGateway/spot.py index dc55416..8858f51 100644 --- a/vnpy/trader/gateway/okexGateway/spot.py +++ b/vnpy/trader/gateway/okexGateway/spot.py @@ -27,6 +27,8 @@ # 方向和开平映射 typeMap = {} typeMap[(DIRECTION_LONG, OFFSET_OPEN)] = 'buy' +typeMap[(DIRECTION_LONG, OFFSET_CLOSE)] = 'buy' +typeMap[(DIRECTION_SHORT, OFFSET_OPEN)] = 'sell' typeMap[(DIRECTION_SHORT, OFFSET_CLOSE)] = 'sell' typeMapReverse = {v:k for k,v in typeMap.items()} @@ -740,9 +742,7 @@ def onSpotTick(self, d): tick.volume = float(data['quote_volume_24h']) tick.askPrice1 = float(data['best_ask']) tick.bidPrice1 = float(data['best_bid']) - tick.datetime = datetime.strptime(data['timestamp'], ISO_DATETIME_FORMAT) - tick.date = tick.datetime.strftime('%Y%m%d') - tick.time = tick.datetime.strftime('%H:%M:%S.%f') + tick.datetime, tick.date, tick.time = self.gateway.convertDatetime(data['timestamp']) tick.localTime = datetime.now() tick.volumeChange = 0 tick.lastVolume = 0 @@ -772,9 +772,7 @@ def onSpotDepth(self, d): tick.__setattr__(f'bidPrice{(idx + 1)}', float(price)) tick.__setattr__(f'bidVolume{(idx + 1)}', float(volume)) - tick.datetime = datetime.strptime(data['timestamp'], ISO_DATETIME_FORMAT) - tick.date = tick.datetime.strftime('%Y%m%d') - tick.time = tick.datetime.strftime('%H:%M:%S.%f') + tick.datetime, tick.date, tick.time = self.gateway.convertDatetime(data['timestamp']) tick.localTime = datetime.now() tick.volumeChange = 0 tick.lastVolume = 0 @@ -792,6 +790,7 @@ def onSpotTrades(self,d): tick.lastTradedTime = data['timestamp'] tick.type = data['side'] tick.volumeChange = 1 + tick.datetime, tick.date, tick.time = self.gateway.convertDatetime(data['timestamp']) tick.localTime = datetime.now() if tick.askPrice1: tick=copy(tick) diff --git a/vnpy/trader/utils/templates/Readme.MD b/vnpy/trader/utils/templates/Readme.MD index 730c2cb..15950a0 100644 --- a/vnpy/trader/utils/templates/Readme.MD +++ b/vnpy/trader/utils/templates/Readme.MD @@ -410,13 +410,17 @@ OrderPack.info 用于记录自定义信息,但是有一些字段已被占用 |price|float|限制价格。| |volume|float|下单数。| |expire|float|存在时间,秒数| -|vtOrderIDs|set|与该信息绑定的订单号| +|vtOrderIDs|set|与该信息绑定的未结束的订单号| +|closedOrderIDs|set|结束/有成交的订单号| +|inValidOrderIDs|set|结束/无成交的订单号| + ### 构造方法 **` TimeLimitOrderInfo.__init__(vtSymbol, orderType, volume, price, expire) `** + |name|type|description| |:-|:-|:-| |orderType|str|发单类型,支持ctaBase.CTAORDER_BUY, ctaBase.CTAORDER_COVER, ctaBase.CTAORDER_SELL, ctaBase.CTAORDER_SHORT。| @@ -434,11 +438,16 @@ TimeLimitOrderInfo.__init__(vtSymbol, orderType, volume, price, expire) 基础属性继承自TimeLimitOrderInfo -额外属性: - |name|type|description| |:-|:-|:-| |TYPE|str: "_ComposoryOrderInfo"|强制单单标记字段| +|orderType|str|发单类型,支持ctaBase.CTAORDER_BUY, ctaBase.CTAORDER_COVER, ctaBase.CTAORDER_SELL, ctaBase.CTAORDER_SHORT。| +|vtSymbol|str|品种名。| +|volume|float|下单数。| +|expire|float|存在时间,秒数| +|vtOrderIDs|set|与该信息绑定的未结束的订单号| +|closedOrderIDs|set|结束/有成交的订单号| +|inValidOrderIDs|set|结束/无成交的订单号| ## `class` AutoExitInfo diff --git a/vnpy/trader/utils/templates/orderTemplate.py b/vnpy/trader/utils/templates/orderTemplate.py index c0056c4..836960b 100644 --- a/vnpy/trader/utils/templates/orderTemplate.py +++ b/vnpy/trader/utils/templates/orderTemplate.py @@ -388,6 +388,8 @@ def onOrder(self, order): else: if op.info.get(self._FINISH_TAG, False): return + if order.status in STATUS_FINISHED: + op.info[self._FINISH_TAG] = True op.order = order for name in op.tracks: @@ -400,10 +402,6 @@ def onOrder(self, order): self.onOrderPack(op) - if op.order.status in STATUS_FINISHED: - op.info[self._FINISH_TAG] = True - - def onOrderPack(self, op): pass @@ -418,9 +416,10 @@ def _round(self, value): def makeOrder(self, orderType, vtSymbol, price, volume, priceType=constant.PRICETYPE_LIMITPRICE, stop=False, **info): volume = self._round(volume) - assert volume > 0 + assert volume > 0, volume + price = self.adjustPrice(vtSymbol, price, "send order") - assert price > 0 + assert price > 0, price vtOrderIDList = self.sendOrder(orderType, vtSymbol, price, volume, priceType, stop) logging.debug("%s | makeOrder: %s, %s, %s, %s | into: %s", self.currentTime, orderType, vtSymbol, price, volume, info) @@ -707,9 +706,11 @@ def checkTimeLimitOrders(self): if not tlo.vtOrderIDs: pool.pop(id(tlo)) - def checkComposoryOrders(self): + def checkComposoryOrders(self, vtSymbol): pool = self._infoPool[ComposoryOrderInfo.TYPE] for cpo in list(pool.values()): + if cpo.vtSymbol != vtSymbol: + continue for op in self.iterValidOrderPacks(*cpo.vtOrderIDs): self.onComposoryOrder(op, True) if not cpo.vtOrderIDs: @@ -1041,7 +1042,7 @@ def currentTime(self): def getExecPrice(self, vtSymbol, orderType): if orderType in self._ORDERTYPE_LONG: if vtSymbol in self._tickInstance: - return self._tickInstance[vtSymbol].upperLimit*0.99 + return self._tickInstance[vtSymbol].lastPrice * 1.02 elif vtSymbol in self._barInstance: return self._barInstance[vtSymbol].high else: @@ -1049,7 +1050,7 @@ def getExecPrice(self, vtSymbol, orderType): elif orderType in self._ORDERTYPE_SHORT: if vtSymbol in self._tickInstance: - return self._tickInstance[vtSymbol].lowerLimit*1.01 + return self._tickInstance[vtSymbol].lastPrice * 0.98 elif vtSymbol in self._barInstance: return self._barInstance[vtSymbol].low else: @@ -1154,7 +1155,7 @@ def onJoinOrderChild(self, op): self.onOrder(parent.order) def checkOnPeriodStart(self, bar): - self.checkComposoryOrders() + self.checkComposoryOrders(bar.vtSymbol) self.checkTimeLimitOrders() self.checkAutoExit(bar.vtSymbol) self.checkConditionalClose() diff --git a/vnpy/trader/utils/templates/spotOrderTemplate.py b/vnpy/trader/utils/templates/spotOrderTemplate.py index f442a3d..a9f33b7 100644 --- a/vnpy/trader/utils/templates/spotOrderTemplate.py +++ b/vnpy/trader/utils/templates/spotOrderTemplate.py @@ -1,4 +1,4 @@ -from vnpy.trader.utils.templates.orderTemplate import OrderTemplate, DIRECTION_MAP, ctaBase, constant +from vnpy.trader.utils.templates.orderTemplate import OrderTemplate, DIRECTION_MAP, ctaBase, constant, STATUS_FINISHED, showOrder import numpy as np @@ -15,6 +15,8 @@ class SpotOrderTemplate(OrderTemplate): _MAXIMUM_VOLUME_ADJUST = 1 + _ORIGIN_TRADED_VOLUME = "_ORIGIN_TRADED_VOLUME" + def maximumOrderVolume(self, vtSymbol, orderType, price=None): if self.getEngineType() != ctaBase.ENGINETYPE_TRADING: return np.inf @@ -47,4 +49,12 @@ def adjustVolume(self, vtSymbol, volume): if contract.minVolume: return int(volume/contract.minVolume) * contract.minVolume else: - return volume \ No newline at end of file + return volume + + def composoryClose(self, op, expire=None, volume=None): + if volume: + if op.order.status not in STATUS_FINISHED: + raise ValueError("Order not finished: %s" % showOrder(op.order, "vtOrderID", "status", "tradedVolume")) + op.order.tradedVolume = volume + op.info[self._ORIGIN_TRADED_VOLUME] = op.order.tradedVolume + return super().composoryClose(op, expire)