[Mod]修改CTA策略模块的回测目标函数支持使用SharpeRatio

This commit is contained in:
vn.py 2017-11-08 21:43:31 +08:00
parent 0bbb321306
commit e14e35cbef
2 changed files with 218 additions and 27 deletions

View File

@ -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:

View File

@ -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)