From 286a8f72a12a00e3fdf8fdcbbfe5572827c9b852 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Sat, 2 Sep 2017 23:16:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0rpcService=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8AServerClient=E7=9A=84=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/ServerClient/CTP_connect.json | 7 ++ examples/ServerClient/RS_setting.json | 4 + examples/ServerClient/VT_setting.json | 16 ++++ examples/ServerClient/client.py | 42 +++++++++ examples/ServerClient/server.py | 46 ++++++++++ vnpy/trader/app/rpcService/RS_setting.json | 4 + vnpy/trader/app/rpcService/__init__.py | 11 +++ vnpy/trader/app/rpcService/rs.ico | Bin 0 -> 67118 bytes vnpy/trader/app/rpcService/rsClient.py | 102 +++++++++++++++++++++ vnpy/trader/app/rpcService/rsEngine.py | 93 +++++++++++++++++++ 10 files changed, 325 insertions(+) create mode 100644 examples/ServerClient/CTP_connect.json create mode 100644 examples/ServerClient/RS_setting.json create mode 100644 examples/ServerClient/VT_setting.json create mode 100644 examples/ServerClient/client.py create mode 100644 examples/ServerClient/server.py create mode 100644 vnpy/trader/app/rpcService/RS_setting.json create mode 100644 vnpy/trader/app/rpcService/__init__.py create mode 100644 vnpy/trader/app/rpcService/rs.ico create mode 100644 vnpy/trader/app/rpcService/rsClient.py create mode 100644 vnpy/trader/app/rpcService/rsEngine.py diff --git a/examples/ServerClient/CTP_connect.json b/examples/ServerClient/CTP_connect.json new file mode 100644 index 00000000..e4bfa6b8 --- /dev/null +++ b/examples/ServerClient/CTP_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "9999", + "mdAddress": "tcp://180.168.146.187:10011", + "tdAddress": "tcp://180.168.146.187:10001", + "userID": "simnow申请", + "password": "simnow申请" +} \ No newline at end of file diff --git a/examples/ServerClient/RS_setting.json b/examples/ServerClient/RS_setting.json new file mode 100644 index 00000000..d325f36d --- /dev/null +++ b/examples/ServerClient/RS_setting.json @@ -0,0 +1,4 @@ +{ + "repAddress": "tcp://*:2014", + "pubAddress": "tcp://*:0602" +} \ No newline at end of file diff --git a/examples/ServerClient/VT_setting.json b/examples/ServerClient/VT_setting.json new file mode 100644 index 00000000..7f634434 --- /dev/null +++ b/examples/ServerClient/VT_setting.json @@ -0,0 +1,16 @@ +{ + "fontFamily": "微软雅黑", + "fontSize": 12, + + "mongoHost": "localhost", + "mongoPort": 27017, + "mongoLogging": true, + + "darkStyle": true, + "language": "chinese", + + "logActive": true, + "logLevel": "debug", + "logConsole": true, + "logFile": true +} \ No newline at end of file diff --git a/examples/ServerClient/client.py b/examples/ServerClient/client.py new file mode 100644 index 00000000..82573247 --- /dev/null +++ b/examples/ServerClient/client.py @@ -0,0 +1,42 @@ +# encoding: UTF-8 + +# 重载sys模块,设置默认字符串编码方式为utf8 +import sys +reload(sys) +sys.setdefaultencoding('utf8') + +# 判断操作系统 +import platform +system = platform.system() + +# vn.trader模块 +from vnpy.event import EventEngine +from vnpy.trader.uiQt import createQApp +from vnpy.trader.uiMainWindow import MainWindow +from vnpy.trader.app.rpcService.rsClient import MainEngineProxy + +#---------------------------------------------------------------------- +def main(): + """主程序入口""" + # 创建Qt应用对象 + qApp = createQApp() + + # 创建事件引擎 + ee = EventEngine() + + # 创建主引擎 + reqAddress = 'tcp://localhost:2014' + subAddress = 'tcp://localhost:0602' + me = MainEngineProxy(ee) + me.init(reqAddress, subAddress) + + # 创建主窗口 + mw = MainWindow(me, ee) + mw.showMaximized() + + # 在主线程中启动Qt事件循环 + sys.exit(qApp.exec_()) + + +if __name__ == '__main__': + main() diff --git a/examples/ServerClient/server.py b/examples/ServerClient/server.py new file mode 100644 index 00000000..2cd5bdc9 --- /dev/null +++ b/examples/ServerClient/server.py @@ -0,0 +1,46 @@ +# encoding: UTF-8 + +# 重载sys模块,设置默认字符串编码方式为utf8 +import sys +reload(sys) +sys.setdefaultencoding('utf8') + +# 判断操作系统 +import platform +system = platform.system() + +# vn.trader模块 +from vnpy.event import EventEngine2 +from vnpy.trader.vtEngine import MainEngine + +# 加载底层接口 +from vnpy.trader.gateway import ctpGateway + +# 加载上层应用 +from vnpy.trader.app import (riskManager, ctaStrategy, rpcService) + + +#---------------------------------------------------------------------- +def main(): + """主程序入口""" + # 创建事件引擎 + ee = EventEngine2() + + # 创建主引擎 + me = MainEngine(ee) + + # 添加交易接口 + me.addGateway(ctpGateway) + + # 添加上层应用 + #me.addApp(riskManager) + #me.addApp(ctaStrategy) + #me.addApp(rpcService) + + # 阻塞运行 + cmd = '' + while cmd != 'exit': + cmd = raw_input() + +if __name__ == '__main__': + main() diff --git a/vnpy/trader/app/rpcService/RS_setting.json b/vnpy/trader/app/rpcService/RS_setting.json new file mode 100644 index 00000000..d325f36d --- /dev/null +++ b/vnpy/trader/app/rpcService/RS_setting.json @@ -0,0 +1,4 @@ +{ + "repAddress": "tcp://*:2014", + "pubAddress": "tcp://*:0602" +} \ No newline at end of file diff --git a/vnpy/trader/app/rpcService/__init__.py b/vnpy/trader/app/rpcService/__init__.py new file mode 100644 index 00000000..ec044378 --- /dev/null +++ b/vnpy/trader/app/rpcService/__init__.py @@ -0,0 +1,11 @@ +# encoding: UTF-8 + +from rsEngine import RsEngine +#from uiRmWidget import RmEngineManager +from vnpy.trader.uiQt import QtWidgets + +appName = 'RpcService' +appDisplayName = u'RPC服务' +appEngine = RsEngine +appWidget = QtWidgets.QWidget +appIco = 'rs.ico' \ No newline at end of file diff --git a/vnpy/trader/app/rpcService/rs.ico b/vnpy/trader/app/rpcService/rs.ico new file mode 100644 index 0000000000000000000000000000000000000000..2c29748f1963fc9d4c23b90a1c2b14ce234ac929 GIT binary patch literal 67118 zcmeHQ378b+nI4mDvYV_i>+=XE?k+Kxc@Rv{c*bm&?7EvokrB@bLJ&o~f*?eU2MAs< zf?xs)x_}&t7l;qh5RF0c06A3@nBj&Qj$!UT=IH5f-?zH|?&_kdyLzU&ySn+C=jE@e z{_3x)@BOd(`~Ti4D?0}NCX6q`|KBV-@r%clbt@|?`#vxMhypxre6X|m*cf65^#9re z+5_4H+5_4H+5_4Hh4H{8XMMfwXhdPW?Z2zWxjzQ!@j&+y#|e18F97}{qCj^+5rz^Eu$?Cf)S(^hKWWC0y@KK=Hp9+eV$t=Y5!5pf~g6fjGba zh}4$m8Tvqe%6Cw(98=8Ojj*t5)-|uGm zxZW4>Z07O*9_;rh)#r83c+%41i_c@9b0+-V;yWdPQ}GP%1M2;MKeqb<-vUbE`M!bY z;2cLvT}rZ>e#>+o=c)c1SO9DSI8U;#1W<)%XaN-e5p1&zl)|&|8MXq;fI+~QfkZh- z&wN?J4(G7Wj|A!f#|)4KQNwqNx%+G=tLGytaqndn#jKW%xA zTztj}^1$e8Bob*C{V5&~EST}2^gpAU>I1sO|CGCLl4wUq@jSe~Q&}=^x@Yx&%H20= z{)?goA zzD9#SxNu;j%ziGMmKV2Qwl(jQ11s;8ZO@)970;Y16?1#WfbH$iog)X|zgOCW2OP7@ z2miyzG)wuAM!DqI8uS6nz}!V$=RXpvk*YUuFnF(=*IO#*on`@!p&V4d^&5$_)Z3N; zzwqCGaI$UScBZnDjeR+No<;sFtLC;UQ`t?i$8|EYMZCc3Z>MQ+0TZJ_P}~C+-LqTFKbEIx8X4+ zO%59Ejh(%^MpxVa(1Eo^pKsspTgyOij0MhXSAP`sd>VI<}PxT+KbrbVa|JR`Yp9TKi^#A^@ z|Lp(iGxnXFE13L5=KlYYKZOk2={V;>%q^tr{|DdFBva9*GjCqwo`=)-|2N&y9LpQ_ zJZI!x&iy(2qp|k|68Fw=#`U9}?Y(OMJJtX}to<|A{d4`_{iF2yzfKcTpcCg$ z@6!6euY>>3xc-yth==^osj}krm!#%EmDFN=Dc1pO_}2#?uURQ0uli5x`ma9V)9w0S zYB5bC|EdgJ`ID1nMETjm_2oBRs^Lc;kQ>Hm4E)*mtn2^RgGa`1y5*niz)t}_0^)0k zPn7Z^h<(v9O5Ls8hr!`cAlvva+Mfyh4PYFZT1&3e;_*cdcpD2a-rW`dY#@|vJf$Y{ zWx%7rQze4gcn-z@tFlb}#|^-$5&^XhCIjaIjNx|8z3L#;IVGAhHr}lNz?kV?0Ar=8 z&sgmECp<$+JyyJSCbi~O0{f2oei@||lmp5bOdm1%=ZH)R0lDBhV~0qg*jpLAMWzSs)xt_C=t=c)`SJEZ3W)j)!C z&IN1u-v?&Suw4uE1G3@&3$R}Z7~GTd0q2|~*FaZfFn$Xde1V29ePD3YQ!YR6->q|i z?|@5=-7%XI;efmYN`DfhSqE}kvsRdzqdZ7k=Fl&BTR{c4VE5d$hYwuKCycFR8H~jQ#O4{(~_2NK&TPX(b{B3y>Tob{A>M}RILH8;=ejt8)g67x5qUgY~q09+7Jgn zxKBFTQ#B1#f$$6ehMo&GS^(GapPjY0(UmaA8ZxHW(2I%Z&wcav)@`#r?>&>fSNzv+ zn&Tq=zqf3g-$xoNUQ(2&q<-L^S{$SA4H&vC)MmN!fq+os#p-9Z&scA2uF#fX{Pkss zAy?mTE8|1EslJ<<}HrtrD$=$Wk7rFQMK?BS`Q#|)g&?=$by#Qm&8E>Ah40yqR zBwS}`x=`EYNZqGY{SU?k?tOi*Z9m`#{>dlDL+uz6wLw3j`ap+_7;7IxPrnZRO_OZj z6%lH!@SIOJx2M&A83p~G+WM%pBJXyDM!oee^gmE8%)F~@ax>-0khHW$4e)+Ac4d2@ zY|JU^`wL53jQeQCInwEc%JG)P9yy_qpQ-{;m2yUhBWy zZq@(Er2q0%YG3I`{hz?T&gj3a_AUP#HYMMO>QGlR=|5HNPwGEaY={1ngI*ZxC;1PB zlkY+Au1>H2^SFioInZikyI`*OYMc2l{&RB9JA&Jqg!o>k_JZem(f(80bKAl*Gq(M) zzJdBL=NRvZ)&k&%`p>?bx-3io(kidK-YN@UZgK2G+5WRXf984E!Q@n=oR=a>lr<30>~oO9QM0b4CHp3D3h&#msAT41-_Y2SCLYk9$c zd!R~oE&ioT{kL9*Rva~BtRFw{ulz_~Dkxt$rOHmFPIl_JvQw!#ZkKY*sO(f~XQz%S z8Voml_osg7KiRfwG|ENLf99CNi%-kpPi5cop%@4JAXX089sov}nEykm zdSke>)>k-QD%bVDt|4k@yYl^><1meYp(p$5^5mG&ksOy_a4w*+;zj7bkCr`uz6$si z<^{({W91U)J~gDxCD;6;o04EC_Fl|)V~v;(ar&s6KaRk{T{{wv^?f5re%`(rndCQMzIgA_n3^3=Xw~NOg)c%!$OrLl;`36#>?vwkg`+isWdt&9M z8)V0pPh!}LG=WXnPQ^~_@2qgbr})kzR3aY}c46BdM~7|={rb-G#fDaY7xZ6#2>#h_ zX#E$@f0@lshFbq6KYsS>Rl2zTL+iizl~|YeLH9|5C@r8^*^z4I0)-82gq<-@PIrzau=z&Z$ws}mV$v8>7>*bn%t^Z=9|8jMs z%=Re$gW4{KH~dj{yx13UAH5Ox(bE98d5m#ik(PQp>WyRh;9u*%q{gOt75~-I9+ZRc zPl&|;$F*Kkv>;FhD(Cf<1MmJ0F#!SFGT;~f85gEBSGb)i?k^jA#&fE?nP$qLahzs* z?x(w-Z0)_`zhTQFsYHwyIZokyo>~6`-@&F~>+`8(T(beOOBkv|5I(T~U}pW7oqHmNEzjAs1^N%r z1hA{8tm}+DtZ$4O+AoYp`}=$8^ z(f^0`ug+5cFuzf7MUN@%FK(SMn{D5?KKJ=IM5FV91xD_8n2k0dA_SFhbbw?dnc1D_Ee9m*s_IBe0l`m84y?AZ! zMg6C)Z_S!NxE%jM{{?ddb|1g+Z}xwwZ+pW(^k16y8RL5DJ377p@wqxFu70nrE;`f|(O@J|1Q@AXaFUzGzZ#~E5c)C1z2U(=4)@Xp`t$bCNe=leF_ ziKzjjk@NwzXg&Ynx1K0;zN78XmdfzEkGgiQ>%Y2=PW|ZtZ~52yFaBiN`L4RS{)hT6 z4YBoqC&)uu|HawSKK>3S_4;Fm{M^Wwd29I72V;Nz3%MS8O^UmCx(O-Q^k-WBpNJKM?FB$B zkSGJx7SZs(4@~R+$sM&VMgrNy|In5(q{D%OfVDj7{o?RR2;4EA^~-=O{@Fk%+jx2& z(kFqnz-Eo2@WDsmX%SEkurGJbz3L#;Iq{Tj0prKI0n`@J@V5_+2S?QFNvX?1fE8qLLZo_fv;<41T{b*`2 z7#~U9@6nRFe_Vs!H+!Jy{bAv^hlT&2$^`S{mWib7mWkEgnx8H&DGn>O@^YM&e@poo kul8f@*DhUNQi?-a(U*rz_1oGWSjtNeYyXql&1Jv$|1HzUG5`Po literal 0 HcmV?d00001 diff --git a/vnpy/trader/app/rpcService/rsClient.py b/vnpy/trader/app/rpcService/rsClient.py new file mode 100644 index 00000000..f61e3e34 --- /dev/null +++ b/vnpy/trader/app/rpcService/rsClient.py @@ -0,0 +1,102 @@ +# encoding: UTF-8 + +import copy + +from vnpy.rpc import RpcClient + + +######################################################################## +class AttributeProxy(object): + """属性代理""" + + #---------------------------------------------------------------------- + def __init__(self, nameList, client): + """Constructor""" + self.nameList = nameList # 属性名称关系列表 + self.client = client # RPC客户端 + + #---------------------------------------------------------------------- + def __getattr__(self, name): + """获取某个不存在的属性""" + # 生成属性层级列表 + newNameList = copy.copy(self.nameList) + newNameList.append(name) + + # 创建代理对象 + proxy = AttributeProxy(newNameList, self.client) + + # 缓存代理对象 + self.__dict__[name] = proxy + + # 返回 + return proxy + + #---------------------------------------------------------------------- + def __call__(self, *args, **kwargs): + """被当做函数调用时""" + d = {} + d['nameList'] = self.nameList + d['args'] = args + d['kwargs'] = kwargs + return self.client.call(d) + + +######################################################################## +class RsClient(RpcClient): + """""" + + #---------------------------------------------------------------------- + def __init__(self, reqAddress, subAddress): + """Constructor""" + super(RsClient, self).__init__(reqAddress, subAddress) + + self.eventEngine = None + + #---------------------------------------------------------------------- + def callback(self, topic, data): + """""" + self.eventEngine.put(data) + + #---------------------------------------------------------------------- + def init(self, eventEngine): + """""" + self.eventEngine = eventEngine + + self.usePickle() + self.subscribeTopic('') + self.start() + + +######################################################################## +class MainEngineProxy(object): + """""" + + #---------------------------------------------------------------------- + def __init__(self, eventEngine): + """Constructor""" + self.eventEngine = eventEngine + self.eventEngine.start(timer=False) + + self.client = None + + #---------------------------------------------------------------------- + def init(self, reqAddress, subAddress): + """""" + self.client = RsClient(reqAddress, subAddress) + self.client.init(self.eventEngine) + + #---------------------------------------------------------------------- + def __getattr__(self, name): + """""" + # 生成属性名称层级列表 + nameList = [name] + + # 生成属性代理对象 + proxy = AttributeProxy(nameList, self.client) + + # 缓存属性代理对象,使得后续调用无需新建 + self.__dict__[name] = proxy + + # 返回属性代理 + return proxy + \ No newline at end of file diff --git a/vnpy/trader/app/rpcService/rsEngine.py b/vnpy/trader/app/rpcService/rsEngine.py new file mode 100644 index 00000000..07eccf51 --- /dev/null +++ b/vnpy/trader/app/rpcService/rsEngine.py @@ -0,0 +1,93 @@ +# encoding: UTF-8 + +import json + +from vnpy.trader.vtConstant import EMPTY_STRING + +from vnpy.rpc import RpcServer +from vnpy.trader.vtFunction import getJsonPath + + +######################################################################## +class RsEngine(object): + """RPC服务引擎""" + + settingFileName = 'RS_setting.json' + settingFilePath = getJsonPath(settingFileName, __file__) + + name = u'RPC服务' + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine): + """Constructor""" + self.mainEngine = mainEngine + self.eventEngine = eventEngine + + self.server = None # RPC服务对象 + self.repAddress = EMPTY_STRING # REP地址 + self.pubAddress = EMPTY_STRING # PUB地址 + + self.functionDict = {} # 调用过的函数对象缓存字典 + + self.loadSetting() + self.registerEvent() + + #---------------------------------------------------------------------- + def loadSetting(self): + """读取配置""" + with open(self.settingFilePath) as f: + d = json.load(f) + + self.repAddress = d['repAddress'] + self.pubAddress = d['pubAddress'] + + self.server = RpcServer(self.repAddress, self.pubAddress) + self.server.usePickle() + self.server.register(self.call) + self.server.start() + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.eventEngine.registerGeneralHandler(self.processEvent) + + #---------------------------------------------------------------------- + def call(self, d): + """调用函数""" + nameList = d['nameList'] # 对象属性列表 + nameTuple = tuple(nameList) # 转化为元组 + args = d['args'] # 调用参数 + kwargs = d['kwargs'] + + # 如果已经有缓存,则直接调用 + if nameTuple in self.functionDict: + function = self.functionDict[nameTuple] + result = function(*args, **kwargs) + return result + # 逐层寻找函数对象 + else: + # 根对象为主引擎 + obj = self.mainEngine + + # 逐层寻找对象属性 + for name in nameTuple: + obj = self.mainEngine.__getattribute__(name) + + # 缓存结果 + self.functionDict[nameTuple] = obj + + # 调用最终对象 + result = obj(*args, **kwargs) + return result + + #---------------------------------------------------------------------- + def processEvent(self, event): + """处理事件推送""" + self.server.publish('', event) + + #---------------------------------------------------------------------- + def stop(self): + """停止""" + pass + + \ No newline at end of file