diff --git a/vnpy/trader/app/optionMaster/omBase.py b/vnpy/trader/app/optionMaster/omBase.py index 76116359..f0154e2d 100644 --- a/vnpy/trader/app/optionMaster/omBase.py +++ b/vnpy/trader/app/optionMaster/omBase.py @@ -1,10 +1,18 @@ # encoding: UTF-8 +from copy import copy from collections import OrderedDict from vnpy.trader.vtConstant import * from vnpy.trader.vtObject import VtTickData +from .omFunction import getTimeToMaturity + + +# 常量定义 +CALL = 1 +PUT = -1 + ######################################################################## class OmInstrument(VtTickData): @@ -75,12 +83,21 @@ class OmInstrument(VtTickData): else: self.shortPos = pos.position - self.calculateNetPos() + return self.calculateNetPos() #---------------------------------------------------------------------- def calculateNetPos(self): """计算净持仓""" - self.netPos = self.longPos - self.shortPos + newNetPos = self.longPos - self.shortPos + + # 检查净持仓是否发生变化 + if newNetPos != self.netPos: + netPosChanged = True + self.netPos = newNetPos + else: + netPosChanged = False + + return netPosChanged ######################################################################## @@ -119,17 +136,10 @@ class OmUnderlying(OmInstrument): #---------------------------------------------------------------------- def newPos(self, pos): """持仓更新""" - super(OmUnderlying, self).newPos(pos) - self.calculatePosGreeks() + netPosChanged = super(OmUnderlying, self).newPos(pos) + if netPosChanged: + 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): """计算持仓希腊值""" @@ -154,8 +164,315 @@ class OmFutures(OmUnderlying): def __init__(self, contract, chainList): """Constructor""" super(OmFutures, self).__init__(contract, chainList) + + self.expiryDate = contract.expiryDate + + +######################################################################## +class OmOption(OmInstrument): + """期权""" + + #---------------------------------------------------------------------- + def __init__(self, contract, underlying, model, r): + """Constructor""" + super(OmOption, self).__init__(contract) + + # 期权属性 + self.underlying = underlying # 标的物对象 + self.k = contract.strikePrice # 行权价 + self.r = r # 利率 + + if contract.optionType == OPTION_CALL: + self.cp = CALL # 期权类型 + else: + self.cp = PUT + + self.expiryDate = contract.expiryDate # 到期日(字符串) + self.t = getTimeToMaturity(self.expiryDate) # 剩余时间 + + # 波动率属性 + self.bidImpv = EMPTY_FLOAT + self.askImpv = EMPTY_FLOAT + self.midImpv = EMPTY_FLOAT + + # 定价公式 + self.calculatePrice = model.calculatePrice + self.calculateGreeks = model.calculateGreeks + self.calculateImpv = model.calculateImpv + + # 模型定价 + self.pricingImpv = EMPTY_FLOAT + + self.theoPrice = EMPTY_FLOAT # 理论价 + self.theoDelta = EMPTY_FLOAT # 合约的希腊值(乘以了合约大小) + self.theoGamma = EMPTY_FLOAT + self.theoTheta = EMPTY_FLOAT + self.theoVega = EMPTY_FLOAT + + self.posValue = EMPTY_FLOAT # 持仓市值 + self.posDelta = EMPTY_FLOAT # 持仓的希腊值(乘以了持仓) + self.posGamma = EMPTY_FLOAT + self.posTheta = EMPTY_FLOAT + self.posVega = EMPTY_FLOAT + + #---------------------------------------------------------------------- + def calculateImpv(self): + """计算隐含波动率""" + underlyingPrice = self.underlying.midPrice + if not underlyingPrice: + return + + self.askImpv = self.calculateImpv(self.askPrice1, underlyingPrice, self.k, + self.r, self.t, self.cp) + self.bidImpv = self.calculateImpv(self.bidPrice1, underlyingPrice, self.k, + self.r, self.t, self.cp) + self.midImpv = (self.askImpv + self.bidImpv) / 2 + + #---------------------------------------------------------------------- + def calculateTheoGreeks(self): + """计算理论希腊值""" + underlyingPrice = self.underlying.midPrice + if not underlyingPrice or not self.pricingImpv: + return + + self.theoPrice, self.theoDelta, self.theoGamma, self.theoTheta, self.theoVega = self.calculateGreeks(underlyingPrice, + self.k, + self.r, + self.t, + self.pricingImpv, + self.cp) + + #---------------------------------------------------------------------- + def calculatePosGreeks(self): + """计算持仓希腊值""" + self.posValue = self.theoPrice * self.netPos + self.posDelta = self.theoDelta * self.netPos + self.posGamma = self.theoGamma * self.netPos + self.posTheta = self.theoTheta * self.netPos + self.posVega = self.theoVega * self.netPos + + #---------------------------------------------------------------------- + def newTick(self, tick): + """行情更新""" + super(OmOption, self).newTick(tick) + self.calculateImpv() + + #---------------------------------------------------------------------- + def newUnderlyingTick(self): + """标的行情更新""" + self.calculateImpv() + self.calculateTheoGreeks() + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newTrade(self, trade): + """成交更新""" + super(OmOption, self).newTrade(trade) + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newPos(self, pos): + """持仓更新""" + netPosChanged = super(OmOption, self).newPos(pos) + if netPosChanged: + self.calculatePosGreeks() + + +######################################################################## +class OmChain(object): + """期权链""" + + #---------------------------------------------------------------------- + def __init__(self, symbol, callList, putList): + """Constructor""" + self.symbol = symbol + + # 原始容器 + self.callDict = OrderedDict((option.symbol, option) for option in callList) + self.putDict = OrderedDict((option.symbol, option) for option in putList) + self.optionDict = OrderedDict((option.symbol, option) for option in (callList+putList)) + + # 持仓数据 + self.longPos = EMPTY_INT + self.shortPos = EMPTY_INT + self.netPos = EMPTY_INT + + self.posValue = EMPTY_FLOAT + self.posDelta = EMPTY_FLOAT + self.posGamma = EMPTY_FLOAT + self.posTheta = EMPTY_FLOAT + self.posVega = EMPTY_FLOAT + + #---------------------------------------------------------------------- + def calculatePosGreeks(self): + """计算持仓希腊值""" + # 清空数据 + self.longPos = 0 + self.shortPos = 0 + self.netPos = 0 + self.posDelta = 0 + self.posGamma = 0 + self.posTheta = 0 + self.posVega = 0 + + # 遍历汇总 + for option in self.optionList: + self.longPos += option.longPos + self.shortPos += option.shortPos + + self.posValue += option.posValue + self.posDelta += option.posDelta + self.posGamma += option.posGamma + self.posTheta += option.posTheta + self.posVega += option.posVega + + self.netPos = self.longPos - self.shortPos + + #---------------------------------------------------------------------- + def newTick(self, tick): + """期权行情更新""" + option = self.optionDict[tick.symbol] + option.newTick(tick) + + #---------------------------------------------------------------------- + def newUnderlyingTick(self): + """期货行情更新""" + for option in self.optionList: + option.newUnderlyingTick() + + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newTrade(self, trade): + """期权成交更新""" + option = self.optionDict[trade.symbol] + option.newTrade(trade) + + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newPos(self, pos): + """期权持仓更新""" + option = self.optionDict[pos.symbol] + option.newPos(pos) + + self.calculatePosGreeks() +######################################################################## +class OmPortfolio(object): + """持仓组合""" + + #---------------------------------------------------------------------- + def __init__(self, name): + """Constructor""" + self.name = name + + # 原始容器 + self.futuresDict = OrderedDict() + self.equityDict = OrderedDict() + self.chainDict = OrderedDict() + + # 初始化生成的容器 + self.underlyingDict = OrderedDict() + self.underlyingList = [] + self.chainList = [] + self.contractDict = {} + self.optionChainDict = {} # option symbol: chain object + self.optionDict = {} # option symbol: option object + self.optionList = [] + + # 持仓数据 + self.longPos = EMPTY_INT + self.shortPos = EMPTY_INT + self.netPos = EMPTY_INT + + self.posDelta = EMPTY_FLOAT + self.posGamma = EMPTY_FLOAT + self.posTheta = EMPTY_FLOAT + self.posVega = EMPTY_FLOAT + + #---------------------------------------------------------------------- + def init(self, futuresDict, equityDict, chainDict): + """初始化数据结构""" + self.futuresDict = futuresDict + self.equityDict = equityDict + self.chainDict = chainDict + + self.underlyingDict.update(self.futuresDict) + self.underlyingDict.update(self.equityDict) + self.underlyingList = self.underlyingDict.values() + self.chainList = chainDict.values() + + self.contractDict.update(self.futuresDict) + self.contractDict.update(self.equityDict) + + for chain in self.chainList: + self.contractDict.update(chain.callDict) + self.contractDict.update(chain.putDict) + + for option in chain.optionList: + self.optionChainDict[option.symbol] = chain + self.optionDict[option.symbol] = option + self.optionList.append(option) + + #---------------------------------------------------------------------- + def calculatePosGreeks(self): + """计算持仓希腊值""" + self.longPos = 0 + self.shortPos = 0 + self.netPos = 0 + self.posDelta = 0 + self.posGamma = 0 + self.posTheta = 0 + self.posVega = 0 + + for underlying in self.underlyingList: + self.posDelta += underlying.posDelta + + for chain in self.chainList: + self.longPos += chain.longPos + self.shortPos += chain.shortPos + + self.posDelta += chain.posDelta + self.posGamma += chain.posGamma + self.posTheta += chain.posTheta + self.posVega += chain.posVega + + self.netPos = self.longPos - self.shortPos + + #---------------------------------------------------------------------- + def newTick(self, tick): + """行情推送""" + if tick.symbol in self.optionChainDict: + chain = self.optionChainDict[tick.symbol] + chain.newTick(tick) + elif tick.symbol in self.underlyingDict: + underlying = self.underlyingDict[tick.symbol] + underlying.newTick(tick) + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newTrade(self, trade): + """成交推送""" + if trade.symbol in self.optionChainDict: + chain = self.optionChainDict[trade.symbol] + chain.newTrade(trade) + else: + underlying = self.underlyingDict[trade.symbol] + underlying.newTrade(trade) + self.calculatePosGreeks() + + #---------------------------------------------------------------------- + def newPos(self, pos): + """持仓推送""" + if pos.symbol in self.optionChainDict: + chain = self.optionChainDict[pos.symbol] + chain.newPos(pos) + elif pos.symbol in self.underlyingDict: + underlying = self.underlyingDict[pos.symbol] + underlying.newPos(pos) + self.calculatePosGreeks() \ No newline at end of file diff --git a/vnpy/trader/app/optionMaster/omFunction.py b/vnpy/trader/app/optionMaster/omFunction.py new file mode 100644 index 00000000..4a8fe71d --- /dev/null +++ b/vnpy/trader/app/optionMaster/omFunction.py @@ -0,0 +1,9 @@ +# encoding: UTF-8 + + +#---------------------------------------------------------------------- +def getTimeToMaturity(expiryDate): + """计算期权剩余到期时间""" + t = 0 + return t + \ No newline at end of file diff --git a/vnpy/trader/gateway/futuGateway/Futu_connect.json b/vnpy/trader/gateway/futuGateway/Futu_connect.json index e23525ac..d26a492d 100644 --- a/vnpy/trader/gateway/futuGateway/Futu_connect.json +++ b/vnpy/trader/gateway/futuGateway/Futu_connect.json @@ -1,4 +1,6 @@ { + "host": "127.0.0.1", + "port": 11111, "market": "HK", "password": "123123", "env": 1 diff --git a/vnpy/trader/gateway/futuGateway/futuGateway.py b/vnpy/trader/gateway/futuGateway/futuGateway.py index 91ca527d..830aa380 100644 --- a/vnpy/trader/gateway/futuGateway/futuGateway.py +++ b/vnpy/trader/gateway/futuGateway/futuGateway.py @@ -62,6 +62,8 @@ class FutuGateway(VtGateway): self.quoteCtx = None self.tradeCtx = None + self.host = '' + self.ip = 0 self.market = '' self.password = '' self.env = 1 # 默认仿真交易 @@ -95,6 +97,19 @@ class FutuGateway(VtGateway): #---------------------------------------------------------------------- def connect(self): """连接""" + # 载入配置 + try: + f = open(self.filePath) + setting = json.load(f) + self.host = setting['host'] + self.port = setting['port'] + self.market = setting['market'] + self.password = setting['password'] + self.env = setting['env'] + except: + self.writeLog(u'载入配置文件出错') + return + self.connectQuote() self.connectTrade() @@ -119,7 +134,7 @@ class FutuGateway(VtGateway): #---------------------------------------------------------------------- def connectQuote(self): """连接行情功能""" - self.quoteCtx = ft.OpenQuoteContext() + self.quoteCtx = ft.OpenQuoteContext(self.host, self.port) # 继承实现处理器类 class QuoteHandler(StockQuoteHandlerBase): @@ -156,24 +171,13 @@ class FutuGateway(VtGateway): #---------------------------------------------------------------------- def connectTrade(self): """连接交易功能""" - # 载入配置 - try: - f = open(self.filePath) - setting = json.load(f) - self.market = setting['market'] - self.password = setting['password'] - self.env = setting['env'] - except: - self.writeLog(u'载入配置文件出错') - return - # 连接交易接口 if self.market == 'US': - self.tradeCtx = ft.OpenUSTradeContext() + self.tradeCtx = ft.OpenUSTradeContext(self.host, self.port) OrderHandlerBase = USTradeOrderHandlerBase DealHandlerBase = USTradeDealHandlerBase else: - self.tradeCtx = ft.OpenHKTradeContext() + self.tradeCtx = ft.OpenHKTradeContext(self.host, self.port) OrderHandlerBase = HKTradeOrderHandlerBase DealHandlerBase = HKTradeDealHandlerBase