From 242a97a2b22e694737038885f4dfedf479738034 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Sat, 12 Jan 2019 10:44:53 +0800 Subject: [PATCH] [Add] Email engine for sending email message. --- vnpy/trader/engine.py | 77 ++++++++++++++++++++++++++++++++++- vnpy/trader/setting.py | 9 +++- vnpy/trader/ui/ico/email.ico | Bin 0 -> 34382 bytes vnpy/trader/ui/mainwindow.py | 15 ++++++- vnpy/trader/ui/widget.py | 20 +++++++++ 5 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 vnpy/trader/ui/ico/email.ico diff --git a/vnpy/trader/engine.py b/vnpy/trader/engine.py index b473e33c..82b75484 100644 --- a/vnpy/trader/engine.py +++ b/vnpy/trader/engine.py @@ -5,6 +5,10 @@ import logging from datetime import datetime from abc import ABC from typing import Any +from threading import Thread +from queue import Queue, Empty +import smtplib +from email.message import EmailMessage from vnpy.event import EventEngine, Event @@ -62,6 +66,7 @@ class MainEngine: """ self.add_engine(LogEngine) self.add_engine(OmsEngine) + self.add_engine(EmailEngine) def write_log(self, msg: str): """ @@ -135,6 +140,9 @@ class MainEngine: Make sure every gateway and app is closed properly before programme exit. """ + for engine in self.engines.values(): + engine.close() + for gateway in self.gateways.values(): gateway.close() @@ -157,6 +165,10 @@ class BaseEngine(ABC): self.event_engine = event_engine self.engine_name = engine_name + def close(self): + """""" + pass + class LogEngine(BaseEngine): """ @@ -397,4 +409,67 @@ class OmsEngine(BaseEngine): order for order in self.active_orders.values() if order.vt_symbol == vt_symbol ] - return active_orders \ No newline at end of file + return active_orders + + +class EmailEngine(BaseEngine): + """ + Provides email sending function for VN Trader. + """ + + def __init__(self, main_engine: MainEngine, event_engine: EventEngine): + """""" + super(EmailEngine, self).__init__(main_engine, event_engine, "email") + + self.thread = Thread(target=self.run) + self.queue = Queue() + self.active = False + + self.main_engine.send_email = self.send_email + + def send_email(self, subject: str, content: str, receiver: str = ""): + """""" + # Start email engine when sending first email. + if not self.active: + self.start() + + # Use default receiver if not specified. + if not receiver: + receiver = SETTINGS["email.receiver"] + + msg = EmailMessage() + msg["From"] = SETTINGS["email.sender"] + msg["To"] = SETTINGS["email.receiver"] + msg["Subject"] = subject + msg.set_content(content) + + self.queue.put(msg) + + def run(self): + """""" + while self.active: + try: + msg = self.queue.get(block=True, timeout=1) + + with smtplib.SMTP_SSL(SETTINGS["email.server"], + SETTINGS["email.port"]) as smtp: + smtp.login( + SETTINGS["email.username"], + SETTINGS["email.password"] + ) + smtp.send_message(msg) + except Empty: + pass + + def start(self): + """""" + self.active = True + self.thread.start() + + def close(self): + """""" + if not self.active: + return + + self.active = False + self.thread.join() diff --git a/vnpy/trader/setting.py b/vnpy/trader/setting.py index 6cd288b4..f91d121d 100644 --- a/vnpy/trader/setting.py +++ b/vnpy/trader/setting.py @@ -7,9 +7,14 @@ from logging import CRITICAL SETTINGS = { "font.family": "Arial", "font.size": 12, - "log.active": True, "log.level": CRITICAL, "log.console": True, - "log.file": True + "log.file": True, + "email.server": "smtp.qq.com", + "email.port": 465, + "email.username": "", + "email.password": "", + "email.sender": "", + "email.receiver": "" } \ No newline at end of file diff --git a/vnpy/trader/ui/ico/email.ico b/vnpy/trader/ui/ico/email.ico new file mode 100644 index 0000000000000000000000000000000000000000..ffda3a8f0ccdb96c7e7e1147616c5e4341156702 GIT binary patch literal 34382 zcmeHQX>1h96&_;_1I8E|gAF#eG1$gtA;ExI*j;R{Jy?S|mR(q2m;1hNa~TZgGMF2T zjm-^)h5U#VI}7y?RyaaKz!i>T(DE&2dbqbvOn%9F9Vu8aN8@x=hH-#3>O=F%85t5Ys>> z(Lg-pNCC2eJYZN9fO2L5$v_+sjfpx~2ebk|16}~X2mTNRpqyU=Ujny*CBPsc8qz=r zc?kFl5HUy{{1dB);?6+_7uB!Zbw^hjatrib)EHK`La(%e0;p2E2rM7ag5ZIgMxnz7&1+M>rK)6 z;9iV-i_IhdcUqc7aZ!<>E2rLmh-0LV3ExK9|E2iv+O@0LyL+en&g=WO=b4z=#wcdnto}Avg*(7GZ_pV6k*G~+}$Pk-0tk>27-h2LRo#^Y@5Bw)| zI3*IvN13;q`5!VQOSCk#jrYu)QSSP>(=Kw;H!x$`G|_UiQH~SL_eaV(<+^eGs+ctK zb)yYXADL(eO%2!G>NfAcP=8h=C-*hq9~J!9ojR!<15YR&FRov?9C3AkTwXd~FGi0V zW#&?z4;(m9G~hd6{k|Fe_l++8*`6QWzbj@{yf4`9%{GJQ#YH2eeV~3Kq3yGrr%%+1 z;lqZx$-+MH!jC=_PaZvRlO;^}=U9XN&Cxz$6z;Q|yY$KalT)^Z2X}9a1@q^L?%lh) z=`A~Zh^RSI9rkvB99ADZp!MsrU$+E(9M*Mf+ouk~fPc<8d>{BT@E1SuE8IH|uqL1R zS9O5>{#7fM<6F?%tq!E6rHMVec4&1ME_Pw(_HDBN3Pre-zfYe&V%?h6vfb;r4-@`R zS!(5Q$)Z=5=Pdhz^x-PIBwC9||BG1+`bFO38 zj_qE{8wTzFlC|u9K0lVwqlZ|u@FVf?-W{(xRnP0F zBe|zNU%Y6cb=)rNK_=$+Cps2PtGy*otB$E>DHU>1NoiY-@Dx+X3we+?AJkf7qI_#`ed!oD-AUx~-hFsB?F}1v0#;mCF zs3XUH9RKk?-QVl3g$e&w4%?G&H~-WV^+Lbll(I6duD>;!x<2QZuGMqtbN9C&!Sc{2 zQ96E{wocODL%)wd+^h0P|4$T-|8?!bd`;Qf%Gt9-H;t_wmX{|^)*kao=Zf$8x-(+m zo?UXzL0vPyQ+G~I>7y+!cAKY@z6-|m+-`32sT|hl^Vu=}?PEd65&K%7ELkiVN1$x2 zI%Z^~ivv}AJ+@~)gZ)Ov9&tX3{-(i$28r!kw|E?zkt_0Z;#iHy&CPLpceifc#Jst4 zFlTYwH*OG5z?Zd6Q@>3O*TjtJ)7<)N ztWO`n_jLDGv$pN>S*%+bh+R_kO&$5SpDtY@=lHDeROR;N7~|hN|4NV4^ZtE%1Y^k* z59-*fS1&g{sM}K~j*F2RyRH6?vB$4ZC>574yzI9w{F=a`eFV~-K&m$@vYvt zVVzgop~~&)_zL*%0y!9?)n4Ec+7y)jpPkOAuM@{>MBdP$ZoJSQ a(=a6YHwr<`e z1`HVBb{|UZb}c6-TO8b9CG7|Ok^ENl?(Oc68~}gh-rc+0?2KJ`y|J@+>BH#hQ z^#<+5X*`4DMr-O&{;5yu>|*^n%(K1b#v{M&95Ym6eBRSFrb6CJe>}(Ny0JUw;Aztr zAP%92WNFYrhrVc((gJg#5n;qP_v#bk>e*T*sFHm{W)Iuj)V}##?Vpn&`7U z^et~(zfRmjUwz5qMcTP%)*sz`WMM&pID7h3P`OufgsA_203`XWD|Dmqv zXXku?&Q^2GHoKw%_B`?t4P-#7lHp3c=_ zPPjzdHfgtMzgr))e+>zFCBK|=Am6I}t0UtOSU(ug%W`?**V}I~{yp=rzTH)OcZ;m7 zOgApbNg-lIj@KOZ`knX2h52{&UfO%weZ{@`NS{D0-rF8K5aZvTf5wBc9WGt`vDQ}; z%ywwz-h8h3VgJv}y*gKRC(yNP>iNm-pa1WJGED;(ga{My9{QB6DJcCv>ZRf86;WO` zS^piz-U+nN@;i)rV&*K^=PV2R9h_Ux_B$|c{e(h+zu`SQ z0qa<>-Tc$`(pRU80mS>HJ+2CJKipfLQR5EIGpD85j62{*qCbh8dV8MwJxKgB7BASo zJ*~Z?{!QQ-fS|?yQpc@w9KKc?2hR6))Hq!6;q6GiP98rdibjku>%lmuKY5>zeh0oQ zNc(l0Uyyevv1c`t8b{UJ!`54xNP=Nb)&H}8-Z~m!+^YGV{jM2yY(%#bU2HMB+ zhg)CorLAI2*|JZTVh9(V%j4QU=*NXRXkBfu^m)Mg?-v4Vl_-Fl<-#y0JQU`YNQ>+90jj-CrNZ{F1 z84cMqbzl7*C1WK{(to8L}D6(LVpDqGBHM1XZw^6qV>r7L4VeW!a_q=PQ87B zBjF)^;J1u$e{f0%3Sbl-qz<(_hrf6ifP;?4R0N{QsedB|@7qYiK#&Y=TUvJP}M zJMV8DR_%a3%|7mX!2b?MZAlo6P+4oNMV=-y5CdVD;UPrX%YL$ANPzD+Sjq zT6Kgx*J*TyG!#Po1aOg&>nRvd^UjPJa^K^P>(|P-EyiwjW^7ouR<12$+*msHg0$+z zng1@1DL`jQ+*^oq#CGz=uD{gH=g`xz&O*FNjxjj@0TAO_uLJJ6#dVaqKxa*yE35)I zKOL(FZ8{+D{QqOE0TO{|NI4L4HNbUeKLvgZu)iBEpkL(2Kr_I#_~}42rY;bg`-Wx# zw0qHlOvsu9!~wAs(?CoEF%9^o0ijF(Q;+D|_A8^nWr}ahzi?*J?~v)akv}Z+)kc1@ z%o|yUHJ{Djjn_FG@`bN9|H9GzWqDDa=W=1Q^HK-ot?%