diff --git a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py index 35efcf10..0f159152 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py +++ b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py @@ -956,11 +956,8 @@ class BacktestingEngine(object): return resultDf #---------------------------------------------------------------------- - def showDailyResult(self, df=None): - """显示按日统计的交易结果""" - if df is None: - df = self.calculateDailyResult() - + def calculateDailyStatistics(self, df): + """计算按日统计的结果""" df['balance'] = df['netPnl'].cumsum() + self.capital df['return'] = (np.log(df['balance']) - np.log(df['balance'].shift(1))).fillna(0) df['highlevel'] = df['balance'].rolling(min_periods=1,window=len(df),center=False).max() @@ -1000,37 +997,71 @@ class BacktestingEngine(object): sharpeRatio = dailyReturn / returnStd * np.sqrt(240) else: sharpeRatio = 0 + + # 返回结果 + result = { + 'startDate': startDate, + 'endDate': endDate, + 'totalDays': totalDays, + 'profitDays': profitDays, + 'lossDays': lossDays, + 'endBalance': endBalance, + 'maxDrawdown': maxDrawdown, + 'totalNetPnl': totalNetPnl, + 'dailyNetPnl': dailyNetPnl, + 'totalCommission': totalCommission, + 'dailyCommission': dailyCommission, + 'totalSlippage': totalSlippage, + 'dailySlippage': dailySlippage, + 'totalTurnover': totalTurnover, + 'dailyTurnover': dailyTurnover, + 'totalTradeCount': totalTradeCount, + 'dailyTradeCount': dailyTradeCount, + 'totalReturn': totalReturn, + 'dailyReturn': dailyReturn, + 'returnStd': returnStd, + 'sharpeRatio': sharpeRatio + } + return df, result + + #---------------------------------------------------------------------- + def showDailyResult(self, df=None, result=None): + """显示按日统计的交易结果""" + if df is None: + df = self.calculateDailyResult() + df, result = self.calculateDailyStatistics(df) + # 输出统计结果 self.output('-' * 30) - self.output(u'首个交易日:\t%s' % startDate) - self.output(u'最后交易日:\t%s' % endDate) + self.output(u'首个交易日:\t%s' % result['startDate']) + self.output(u'最后交易日:\t%s' % result['endDate']) - self.output(u'总交易日:\t%s' % totalDays) - self.output(u'盈利交易日\t%s' % profitDays) - self.output(u'亏损交易日:\t%s' % lossDays) + self.output(u'总交易日:\t%s' % result['totalDays']) + self.output(u'盈利交易日\t%s' % result['profitDays']) + self.output(u'亏损交易日:\t%s' % result['lossDays']) self.output(u'起始资金:\t%s' % self.capital) - self.output(u'结束资金:\t%s' % formatNumber(endBalance)) + self.output(u'结束资金:\t%s' % formatNumber(result['endBalance'])) - self.output(u'总收益率:\t%s' % formatNumber(totalReturn)) - self.output(u'总盈亏:\t%s' % formatNumber(totalNetPnl)) - self.output(u'最大回撤: \t%s' % formatNumber(maxDrawdown)) + self.output(u'总收益率:\t%s' % formatNumber(result['totalReturn'])) + self.output(u'总盈亏:\t%s' % formatNumber(result['totalNetPnl'])) + self.output(u'最大回撤: \t%s' % formatNumber(result['maxDrawdown'])) - self.output(u'总手续费:\t%s' % formatNumber(totalCommission)) - self.output(u'总滑点:\t%s' % formatNumber(totalSlippage)) - self.output(u'总成交金额:\t%s' % formatNumber(totalTurnover)) - self.output(u'总成交笔数:\t%s' % formatNumber(totalTradeCount)) + self.output(u'总手续费:\t%s' % formatNumber(result['totalCommission'])) + self.output(u'总滑点:\t%s' % formatNumber(result['totalSlippage'])) + self.output(u'总成交金额:\t%s' % formatNumber(result['totalTurnover'])) + self.output(u'总成交笔数:\t%s' % formatNumber(result['totalTradeCount'])) - self.output(u'日均盈亏:\t%s' % formatNumber(dailyNetPnl)) - self.output(u'日均手续费:\t%s' % formatNumber(dailyCommission)) - self.output(u'日均滑点:\t%s' % formatNumber(dailySlippage)) - self.output(u'日均成交金额:\t%s' % formatNumber(dailyTurnover)) - self.output(u'日均成交笔数:\t%s' % formatNumber(dailyTradeCount)) + self.output(u'日均盈亏:\t%s' % formatNumber(result['dailyNetPnl'])) + self.output(u'日均手续费:\t%s' % formatNumber(result['dailyCommission'])) + self.output(u'日均滑点:\t%s' % formatNumber(result['dailySlippage'])) + self.output(u'日均成交金额:\t%s' % formatNumber(result['dailyTurnover'])) + self.output(u'日均成交笔数:\t%s' % formatNumber(result['dailyTradeCount'])) - self.output(u'日均收益率:\t%s%%' % formatNumber(dailyReturn)) - self.output(u'收益标准差:\t%s%%' % formatNumber(returnStd)) - self.output(u'Sharpe Ratio:\t%s' % formatNumber(sharpeRatio)) + self.output(u'日均收益率:\t%s%%' % formatNumber(result['dailyReturn'])) + self.output(u'收益标准差:\t%s%%' % formatNumber(result['returnStd'])) + self.output(u'Sharpe Ratio:\t%s' % formatNumber(result['sharpeRatio'])) # 绘图 fig = plt.figure(figsize=(10, 16)) @@ -1225,7 +1256,9 @@ def optimize(strategyClass, setting, targetName, engine.initStrategy(strategyClass, setting) engine.runBacktesting() - d = engine.calculateBacktestingResult() + + df = engine.calculateDailyResult() + df, d = engine.calculateDailyStatistics(df) try: targetValue = d[targetName] except KeyError: diff --git a/vnpy/trader/app/optionMaster/omBase.py b/vnpy/trader/app/optionMaster/omBase.py index c7d557ec..76116359 100644 --- a/vnpy/trader/app/optionMaster/omBase.py +++ b/vnpy/trader/app/optionMaster/omBase.py @@ -1,3 +1,161 @@ # encoding: UTF-8 +from collections import OrderedDict +from vnpy.trader.vtConstant import * +from vnpy.trader.vtObject import VtTickData + + +######################################################################## +class OmInstrument(VtTickData): + """交易合约对象""" + + #---------------------------------------------------------------------- + def __init__(self, contract): + """Constructor""" + super(OmInstrument, self).__init__() + + # 初始化合约信息 + self.exchange = contract.exchange + self.vtSymbol = contract.vtSymbol + + self.size = contract.size + self.priceTick = contract.priceTick + self.gatewayName = contract.gatewayName + + # 中间价 + self.midPrice = EMPTY_FLOAT + + # 持仓数据 + self.longPos = EMPTY_INT + self.shortPos = EMPTY_INT + self.netPos = EMPTY_INT + + #---------------------------------------------------------------------- + def newTick(self, tick): + """行情更新""" + if not self.tickInited: + self.date = tick.date + self.openPrice = tick.openPrice + self.upperLimit = tick.upperLimit + self.lowerLimit = tick.lowerLimit + self.tickInited = True + + self.lastPrice = tick.lastPrice + self.volume = tick.volume + self.openInterest = tick.openInterest + self.time = tick.time + + self.bidPrice1 = tick.bidPrice1 + self.askPrice1 = tick.askPrice1 + self.bidVolume1 = tick.bidVolume1 + self.askVolume1 = tick.askVolume1 + + #---------------------------------------------------------------------- + def newTrade(self, trade): + """成交更新""" + if trade.direction is DIRECTION_LONG: + if trade.offset is OFFSET_OPEN: + self.longPos += trade.volume + else: + self.shortPos -= trade.volume + else: + if trade.offset is OFFSET_OPEN: + self.shortPos += trade.volume + else: + self.longPos -= trade.volume + + self.calculateNetPos() + + #---------------------------------------------------------------------- + def newPos(self, pos): + """持仓更新""" + if pos.direction is DIRECTION_LONG: + self.longPos = pos.position + else: + self.shortPos = pos.position + + self.calculateNetPos() + + #---------------------------------------------------------------------- + def calculateNetPos(self): + """计算净持仓""" + self.netPos = self.longPos - self.shortPos + + +######################################################################## +class OmUnderlying(OmInstrument): + """标的物""" + + #---------------------------------------------------------------------- + def __init__(self, contract, chainList): + """Constructor""" + super(OmUnderlying, self).__init__(contract) + + # 以该合约为标的物的期权链字典 + self.chainDict = OrderedDict((chain.symbol, chain) for chain in chainList) + + # 希腊值 + self.theoDelta = EMPTY_FLOAT # 理论delta值 + self.posDelta = EMPTY_FLOAT # 持仓delta值 + + #---------------------------------------------------------------------- + def newTick(self, tick): + """行情更新""" + super(OmUnderlying, self).newTick(tick) + + self.theoDelta = self.size * self.midPrice / 100 + + # 遍历推送自己的行情到期权链中 + for chain in self.chainList: + chain.newUnderlyingTick() + + #---------------------------------------------------------------------- + def newTrade(self, trade): + """成交更新""" + super(OmUnderlying, self).newTrade(trade) + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newPos(self, pos): + """持仓更新""" + super(OmUnderlying, self).newPos(pos) + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def init(self, contract, chainList): + """初始化""" + super(OmUnderlying, self).init(contract) + + self.chainList = chainList + self.chainDict = OrderedDict([(chain.symbol, chain) for chain in chainList]) + + #---------------------------------------------------------------------- + def calculatePosGreeks(self): + """计算持仓希腊值""" + self.posDelta = self.theoDelta * self.netPos + + +######################################################################## +class OmEquity(OmUnderlying): + """股票""" + + #---------------------------------------------------------------------- + def __init__(self, contract, chainList): + """Constructor""" + super(OmEquity, self).__init__(contract, chainList) + + +######################################################################## +class OmFutures(OmUnderlying): + """期货""" + + #---------------------------------------------------------------------- + def __init__(self, contract, chainList): + """Constructor""" + super(OmFutures, self).__init__(contract, chainList) + + + + + \ No newline at end of file