def crossStopOrder(self): """基于最新数据撮合停止单""" # 先确定会撮合成交的价格,这里和限价单规则相反 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.high # 若买入方向停止单价格低于该价格,则会成交 sellCrossPrice = self.bar.low # 若卖出方向限价单价格高于该价格,则会成交 bestCrossPrice = self.bar.open # 最优成交价,买入停止单不能低于,卖出停止单不能高于 else: buyCrossPrice = self.tick.lastPrice sellCrossPrice = self.tick.lastPrice bestCrossPrice = self.tick.lastPrice # 遍历停止单字典中的所有停止单 for stopOrderID, so in self.workingStopOrderDict.items(): # 判断是否会成交 buyCross = so.direction == DIRECTION_LONG and so.price <= buyCrossPrice sellCross = so.direction == DIRECTION_SHORT and so.price >= sellCrossPrice # 如果发生了成交 if buyCross or sellCross: # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = so.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID if buyCross: self.strategy.pos += so.volume trade.price = max(bestCrossPrice, so.price) else: self.strategy.pos -= so.volume trade.price = min(bestCrossPrice, so.price) self.limitOrderCount += 1 orderID = str(self.limitOrderCount) trade.orderID = orderID trade.vtOrderID = orderID trade.direction = so.direction trade.offset = so.offset trade.volume = so.volume trade.tradeTime = str(self.dt) trade.dt = self.dt self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 so.status = STOPORDER_TRIGGERED order = VtOrderData() order.vtSymbol = so.vtSymbol order.symbol = so.vtSymbol order.orderID = orderID order.vtOrderID = orderID order.direction = so.direction order.offset = so.offset order.price = so.price order.totalVolume = so.volume order.tradedVolume = so.volume order.status = STATUS_ALLTRADED order.orderTime = trade.tradeTime self.strategy.onOrder(order) self.limitOrderDict[orderID] = order # 从字典中删除该限价单 if stopOrderID in self.workingStopOrderDict: del self.workingStopOrderDict[stopOrderID]
def crossStopOrder(self): """基于最新数据撮合停止单""" # 先确定会撮合成交的价格,这里和限价单规则相反 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.high # 若买入方向停止单价格低于该价格,则会成交 sellCrossPrice = self.bar.low # 若卖出方向限价单价格高于该价格,则会成交 else: buyCrossPrice = self.tick.lastPrice sellCrossPrice = self.tick.lastPrice # 遍历停止单字典中的所有停止单 for stopOrderID, so in self.workingStopOrderDict.items(): # 判断是否会成交 buyCross = so.direction==DIRECTION_LONG and so.price<=buyCrossPrice sellCross = so.direction==DIRECTION_SHORT and so.price>=sellCrossPrice # 如果发生了成交 if buyCross or sellCross: # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = so.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID self.limitOrderCount += 1 orderID = str(self.limitOrderCount) trade.orderID = orderID trade.vtOrderID = orderID trade.direction = so.direction trade.offset = so.offset trade.price = so.price trade.volume = so.volume trade.tradeTime = str(self.dt) trade.dt = self.dt self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 so.status = STOPORDER_TRIGGERED order = VtOrderData() order.vtSymbol = so.vtSymbol order.symbol = so.vtSymbol order.orderID = orderID order.vtOrderID = orderID order.direction = so.direction order.offset = so.offset order.price = so.price order.totalVolume = so.volume order.tradedVolume = so.volume order.status = STATUS_ALLTRADED order.orderTime = trade.tradeTime self.strategy.onOrder(order) self.limitOrderDict[orderID] = order # 从字典中删除该限价单 del self.workingStopOrderDict[stopOrderID]
def crossLimitOrder(self): """基于最新数据撮合限价单""" # 先确定会撮合成交的价格 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.low # 若买入方向限价单价格高于该价格,则会成交 sellCrossPrice = self.bar.high # 若卖出方向限价单价格低于该价格,则会成交 buyBestCrossPrice = self.bar.open # 在当前时间点前发出的买入委托可能的最优成交价 sellBestCrossPrice = self.bar.open # 在当前时间点前发出的卖出委托可能的最优成交价 else: buyCrossPrice = self.tick.askPrice1 sellCrossPrice = self.tick.bidPrice1 buyBestCrossPrice = self.tick.askPrice1 sellBestCrossPrice = self.tick.bidPrice1 # 遍历限价单字典中的所有限价单 for orderID, order in self.workingLimitOrderDict.items(): # 判断是否会成交 buyCross = (order.direction == DIRECTION_LONG and order.price >= buyCrossPrice and buyCrossPrice > 0 ) # 国内的tick行情在涨停时askPrice1为0,此时买无法成交 sellCross = (order.direction == DIRECTION_SHORT and order.price <= sellCrossPrice and sellCrossPrice > 0 ) # 国内的tick行情在跌停时bidPrice1为0,此时卖无法成交 # 如果发生了成交 if buyCross or sellCross: # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = order.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID trade.orderID = order.orderID trade.vtOrderID = order.orderID trade.direction = order.direction trade.offset = order.offset # 以买入为例: # 1. 假设当根K线的OHLC分别为:100, 125, 90, 110 # 2. 假设在上一根K线结束(也是当前K线开始)的时刻,策略发出的委托为限价105 # 3. 则在实际中的成交价会是100而不是105,因为委托发出时市场的最优价格是100 if buyCross: trade.price = min(order.price, buyBestCrossPrice) self.strategy.pos += order.totalVolume else: trade.price = max(order.price, sellBestCrossPrice) self.strategy.pos -= order.totalVolume trade.volume = order.totalVolume trade.tradeTime = str(self.dt) trade.dt = self.dt self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 order.tradedVolume = order.totalVolume order.status = STATUS_ALLTRADED self.strategy.onOrder(order) # 从字典中删除该限价单 del self.workingLimitOrderDict[orderID]
def crossLimitOrder(self): """基于最新数据撮合限价单""" # 先确定会撮合成交的价格 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.low # 若买入方向限价单价格高于该价格,则会成交 sellCrossPrice = self.bar.high # 若卖出方向限价单价格低于该价格,则会成交 bestCrossPrice = self.bar.open # 在当前时间点前发出的委托可能的最优成交价 else: buyCrossPrice = self.tick.lastPrice sellCrossPrice = self.tick.lastPrice bestCrossPrice = self.tick.lastPrice # 遍历限价单字典中的所有限价单 for orderID, order in self.workingLimitOrderDict.items(): # 判断是否会成交 buyCross = order.direction==DIRECTION_LONG and order.price>=buyCrossPrice sellCross = order.direction==DIRECTION_SHORT and order.price<=sellCrossPrice # 如果发生了成交 if buyCross or sellCross: # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = order.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID trade.orderID = order.orderID trade.vtOrderID = order.orderID trade.direction = order.direction trade.offset = order.offset # 以买入为例: # 1. 假设当根K线的OHLC分别为:100, 125, 90, 110 # 2. 假设在上一根K线结束(也是当前K线开始)的时刻,策略发出的委托为限价105 # 3. 则在实际中的成交价会是100而不是105,因为委托发出时市场的最优价格是100 if buyCross: trade.price = min(order.price, bestCrossPrice) else: trade.price = max(order.price, bestCrossPrice) trade.volume = order.totalVolume trade.tradeTime = str(self.dt) trade.dt = self.dt self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 order.tradedVolume = order.totalVolume order.status = STATUS_ALLTRADED self.strategy.onOrder(order) # 从字典中删除该限价单 del self.workingLimitOrderDict[orderID]
def crossLimitOrder(self): """基于最新数据撮合限价单""" # 先确定会撮合成交的价格 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.low # 若买入方向限价单价格高于该价格,则会成交 sellCrossPrice = self.bar.high # 若卖出方向限价单价格低于该价格,则会成交 else: buyCrossPrice = self.tick.lastPrice sellCrossPrice = self.tick.lastPrice # 遍历限价单字典中的所有限价单 for orderID, order in self.workingLimitOrderDict.items(): # 判断是否会成交 buyCross = order.direction == DIRECTION_LONG and order.price >= buyCrossPrice sellCross = order.direction == DIRECTION_SHORT and order.price <= sellCrossPrice # 如果发生了成交 if buyCross or sellCross: # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = order.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID trade.orderID = order.orderID trade.vtOrderID = order.orderID trade.direction = order.direction trade.offset = order.offset trade.price = order.price trade.volume = order.totalVolume trade.tradeTime = str(self.dt) trade.dt = self.dt self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 order.tradedVolume = order.totalVolume order.status = STATUS_ALLTRADED self.strategy.onOrder(order) # 从字典中删除该限价单 del self.workingLimitOrderDict[orderID]
def calculateBacktestingResult(self): """ 计算回测结果 """ #将交易结果化为dataframe tradeResult = [] def todict(t): return t.__dict__ for symbol in self.tradeDict.keys(): tradeResult.extend(self.tradeDict[symbol].values()) tradeResult = map(todict, tradeResult) d = pd.DataFrame(tradeResult) d = d.sort_values('dt') index = pd.Index(np.arange(d.count()[0])) d.index = index self.output(u'计算回测结果') # 首先基于回测后的成交记录,计算每笔交易的盈亏 self.resultList = [] # 交易结果列表 longTrade = {} # 未平仓的多头交易 shortTrade = {} # 未平仓的空头交易 symbolNow = '' # 当前的交易标的 for symbol in self.symbols: longTrade[symbol] = [] shortTrade[symbol] = [] for i in range(d.count()[0]): dict_ = d.ix[i].to_dict() trade = VtTradeData() trade.__dict__ = dict_ # 这些变量会被较多地引用,故先赋值 # if not symbolNow : # symbolNow = trade.vtSymbol if symbolNow != trade.vtSymbol: symbolNow = trade.vtSymbol commission = self.contractInfo[trade.vtSymbol]['commission'] slippage = self.contractInfo[trade.vtSymbol]['slippage'] size = self.contractInfo[trade.vtSymbol]['size'] margin = self.contractInfo[trade.vtSymbol]['margin'] elif symbolNow == trade.vtSymbol: pass # 多头交易 if trade.direction == DIRECTION_LONG: # 如果尚无空头交易 if not shortTrade[symbolNow]: longTrade[symbolNow].append(trade) # 当前多头交易为平空 else: while True: entryTrade = shortTrade[symbolNow][0] exitTrade = trade # 清算开平仓交易 closedVolume = min(exitTrade.volume, entryTrade.volume) result = TradingResult(symbolNow, entryTrade.price, entryTrade.dt, exitTrade.price, exitTrade.dt, -closedVolume, commission, slippage, size, margin) #print BLUEPREFIX + str(result.pnl) #print result.volume self.resultList.append(result) # 计算未清算部分 entryTrade.volume -= closedVolume exitTrade.volume -= closedVolume # 如果开仓交易已经全部清算,则从列表中移除 if not entryTrade.volume: shortTrade[symbolNow].pop(0) # 如果平仓交易已经全部清算,则退出循环 if not exitTrade.volume: break # 如果平仓交易未全部清算, if exitTrade.volume: # 且开仓交易已经全部清算完,则平仓交易剩余的部分 # 等于新的反向开仓交易,添加到队列中 if not shortTrade[symbolNow]: longTrade[symbolNow].append(exitTrade) break # 如果开仓交易还有剩余,则进入下一轮循环 else: pass # 空头交易 else: # 如果尚无多头交易 if not longTrade[symbolNow]: shortTrade[symbolNow].append(trade) # 当前空头交易为平多 else: while True: entryTrade = longTrade[symbolNow][0] exitTrade = trade # 清算开平仓交易 closedVolume = min(exitTrade.volume, entryTrade.volume) result = TradingResult(symbolNow, entryTrade.price, entryTrade.dt, exitTrade.price, exitTrade.dt, closedVolume, commission, slippage, size, margin) #print BLUEPREFIX + str(result.pnl) #print result.volume self.resultList.append(result) # 计算未清算部分 entryTrade.volume -= closedVolume exitTrade.volume -= closedVolume # 如果开仓交易已经全部清算,则从列表中移除 if not entryTrade.volume: longTrade[symbolNow].pop(0) # 如果平仓交易已经全部清算,则退出循环 if not exitTrade.volume: break # 如果平仓交易未全部清算, if exitTrade.volume: # 且开仓交易已经全部清算完,则平仓交易剩余的部分 # 等于新的反向开仓交易,添加到队列中 if not longTrade[symbolNow]: shortTrade[symbolNow].append(exitTrade) break # 如果开仓交易还有剩余,则进入下一轮循环 else: pass # 检查是否有交易 if not self.resultList: self.output(u'无交易结果') return {} #将各标的交易的持仓区间用Series来表示持仓浮盈 floatProfit = defaultdict(list) #key为symbol,value是包含sr的list df = self.dataframe.set_index( 'datetime').sort_index().drop_duplicates() pnlList = [] for result in self.resultList: symbolDf = df[df.symbol == result.symbol] symbolDf = symbolDf[result.entryDt:result.exitDt] #+ delta] symbolDf = symbolDf.drop_duplicates().sort_index() sr = ( symbolDf['close'] - symbolDf.ix[0]['close'] ) * result.size * self.contractInfo[result.symbol][ 'margin'] * result.volume #- result.commission #- result.slippage floatProfit[result.symbol].append(sr) #每笔交易区间的资金变化 pnlList.append(result.pnl) #每笔交易的利润 #=========================================================================== #print str(result.entryDt) + " =====> " + str(result.exitDt) + " ==========>>> " + str(result.pnl) index = np.unique(df.index) capitalSr = pd.Series(0, index=index) for lsSymbol in floatProfit.values(): for floatSr in lsSymbol: #print GREENPREFIX + str(floatSr) + "\n\n" floatSr = pd.Series(floatSr, index=index) floatSr = floatSr.fillna(method='ffill').fillna(0) capitalSr += floatSr capitalSr = capitalSr.drop_duplicates() capitalSr = capitalSr + self.initCapital #可以看到回测期间的资金变化 pnlStat = pd.Series(pnlList) # 盈利序列 drawdownSr = capitalSr.cummax() - capitalSr # 回测序列 #=========================================================================== # 计算盈亏相关数据 winningRate = pnlStat[pnlStat > 0].count() / pnlStat.count() #胜率 averageWinning = pnlStat[pnlStat > 0].mean() # 平均每笔盈利 averageLosing = pnlStat[pnlStat < 0].mean() # 平均每笔亏损 profitLossRatio = -averageWinning / averageLosing # 盈亏比 #稳健指标计算 #回归年度回报率 lenSr = len(capitalSr) m, b = np.polyfit(np.arange(lenSr), capitalSr.tolist(), 1) # 对资金曲线进行简单回归 expectedMonthlyReturn = lenSr * m / b # 回测收益率 testInterval = ((capitalSr.index[-1] - capitalSr.index[0]).days / 30.0 ) # 测试区间对应的时间长度(月) monthlyReturnRatio = expectedMonthlyReturn / testInterval #月化收益率 RAR = (1 + monthlyReturnRatio)**12 - 1 # 回归年度回报率 #稳健风险回报比率 temp = 0 maxDrawdownLs = [] for i in range(1, len(drawdownSr)): if drawdownSr[i] == 0: tempDrawdown = drawdownSr[temp:i].max() if tempDrawdown != 0: maxDrawdownLs.append(tempDrawdown) temp = i if len(maxDrawdownLs) >= 5: aveDrawdown = np.mean(maxDrawdownLs[-5:]) # 五次最大回测的平均值 else: aveDrawdown = np.mean(maxDrawdownLs) # 五次最大回测的平均值 RCube = RAR / aveDrawdown #稳健风险回报比率 # 返回回测结果 d = {} d['capital'] = capitalSr[-1] / self.initCapital d['maxCapital'] = capitalSr.max() d['maxdrawdown'] = (pnlStat.cummax() - pnlStat).max() d['maxdrawdownDay'] = drawdownSr.argmax().isoformat() d['totalResult'] = pnlStat.count() d['pnlList'] = pnlList d['capitalSr'] = capitalSr d['winningRate'] = winningRate d['averageWinning'] = averageWinning d['averageLosing'] = averageLosing d['profitLossRatio'] = profitLossRatio d['floatProfit'] = floatProfit d['RAR'] = RAR d['RCube'] = RCube return d
def crossLimitOrder(self): """基于最新数据撮合限价单""" # 先确定会撮合成交的价格 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.low # 若买入方向限价单价格高于该价格,则会成交 sellCrossPrice = self.bar.high # 若卖出方向限价单价格低于该价格,则会成交 buyBestCrossPrice = self.bar.open # 在当前时间点前发出的买入委托可能的最优成交价 sellBestCrossPrice = self.bar.open # 在当前时间点前发出的卖出委托可能的最优成交价 else: buyCrossPrice = self.tick.askPrice1 sellCrossPrice = self.tick.bidPrice1 buyBestCrossPrice = self.tick.askPrice1 sellBestCrossPrice = self.tick.bidPrice1 # 遍历限价单字典中的所有限价单 for orderID, order in self.workingLimitOrderDict[ self.bar.symbol].items(): # 判断是否会成交 buyCross = order.direction == DIRECTION_LONG and order.price >= buyCrossPrice sellCross = order.direction == DIRECTION_SHORT and order.price <= sellCrossPrice # 如果发生了成交 if buyCross or sellCross: # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = order.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID trade.orderID = order.orderID trade.vtOrderID = order.orderID trade.direction = order.direction trade.offset = order.offset # 以买入为例: # 1. 假设当根K线的OHLC分别为:100, 125, 90, 110 # 2. 假设在上一根K线结束(也是当前K线开始)的时刻,策略发出的委托为限价105 # 3. 则在实际中的成交价会是100而不是105,因为委托发出时市场的最优价格是100 if buyCross: trade.price = min(order.price, buyBestCrossPrice) stra = self.strategyDict[self.bar.symbol] stra.pos += order.totalVolume #print "a" else: trade.price = max(order.price, sellBestCrossPrice) stra = self.strategyDict[self.bar.symbol] stra.pos -= order.totalVolume trade.volume = order.totalVolume trade.tradeTime = str(self.dt) trade.dt = self.dt trade.symbol = self.bar.symbol stra = self.strategyDict[self.bar.symbol] stra.onTrade(trade) #print trade.direction self.tradeDict[trade.vtSymbol][tradeID] = trade '''#在此处更新回测账户''' #print REDPREFIX +str(trade.symbol) + "\t"+ "%.1f"%trade.price + "\t" +\ # trade.direction + "\t" + trade.offset + "\t" + str(trade.volume) self.updateAccount(trade) # 推送委托数据 order.tradedVolume = order.totalVolume order.status = STATUS_ALLTRADED stra = self.strategyDict[self.bar.symbol] stra.onOrder(order) # 从字典中删除该限价单 del self.workingLimitOrderDict[self.bar.symbol][orderID]
def crossLimitOrder(self): """基于最新数据撮合限价单""" """Check LimitOrder base on newest market data""" # 先确定会撮合成交的价格 if self.mode == self.BAR_MODE: buyCrossPrice = self.bar.low # 若买入方向限价单价格高于该价格,则会成交 sellCrossPrice = self.bar.high # 若卖出方向限价单价格低于该价格,则会成交 buyBestCrossPrice = self.bar.open # 在当前时间点前发出的买入委托可能的最优成交价 sellBestCrossPrice = self.bar.open # 在当前时间点前发出的卖出委托可能的最优成交价 else: buyCrossPrice = self.tick.askPrice1 sellCrossPrice = self.tick.bidPrice1 buyBestCrossPrice = self.tick.askPrice1 sellBestCrossPrice = self.tick.bidPrice1 # 遍历限价单字典中的所有限价单 for orderID, order in self.workingLimitOrderDict.items(): # 判断是否会成交 buyCross = order.direction == DIRECTION_LONG and order.price >= buyCrossPrice sellCross = order.direction == DIRECTION_SHORT and order.price <= sellCrossPrice # 如果发生了成交 # If transaction happens if buyCross or sellCross: # 推送成交数据 # Update trade data self.tradeCount += 1 # TradeID increase by 1 tradeID = str(self.tradeCount) trade = VtTradeData() trade.vtSymbol = order.vtSymbol trade.tradeID = tradeID trade.vtTradeID = tradeID trade.orderID = order.orderID trade.vtOrderID = order.orderID trade.direction = order.direction trade.offset = order.offset # Buy as example: # 1. Suppose the OHLC of current Bar are 100, 125, 90, 110 (Open = 100) # 2. Suppose at the end of last Bar(not the start of current Bar), the price of limit order is 105, # (Last Close = 105) # 3. In real trading, the trade price will be 100 instead of 105, because the best market price is 100 if buyCross: trade.price = min(order.price, buyBestCrossPrice) self.strategy.pos += order.totalVolume else: trade.price = max(order.price, sellBestCrossPrice) self.strategy.pos -= order.totalVolume trade.volume = order.totalVolume trade.tradeTime = str(self.dt) trade.dt = self.dt self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 # Upadte order data order.tradedVolume = order.totalVolume order.status = STATUS_ALLTRADED self.strategy.onOrder(order) # 从字典中删除该限价单 # Remove this order from "working limit order dictionary" del self.workingLimitOrderDict[orderID]