[Add] Email engine for sending email message.
This commit is contained in:
parent
6e1d90b327
commit
242a97a2b2
@ -5,6 +5,10 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import Any
|
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
|
from vnpy.event import EventEngine, Event
|
||||||
|
|
||||||
@ -62,6 +66,7 @@ class MainEngine:
|
|||||||
"""
|
"""
|
||||||
self.add_engine(LogEngine)
|
self.add_engine(LogEngine)
|
||||||
self.add_engine(OmsEngine)
|
self.add_engine(OmsEngine)
|
||||||
|
self.add_engine(EmailEngine)
|
||||||
|
|
||||||
def write_log(self, msg: str):
|
def write_log(self, msg: str):
|
||||||
"""
|
"""
|
||||||
@ -135,6 +140,9 @@ class MainEngine:
|
|||||||
Make sure every gateway and app is closed properly before
|
Make sure every gateway and app is closed properly before
|
||||||
programme exit.
|
programme exit.
|
||||||
"""
|
"""
|
||||||
|
for engine in self.engines.values():
|
||||||
|
engine.close()
|
||||||
|
|
||||||
for gateway in self.gateways.values():
|
for gateway in self.gateways.values():
|
||||||
gateway.close()
|
gateway.close()
|
||||||
|
|
||||||
@ -157,6 +165,10 @@ class BaseEngine(ABC):
|
|||||||
self.event_engine = event_engine
|
self.event_engine = event_engine
|
||||||
self.engine_name = engine_name
|
self.engine_name = engine_name
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class LogEngine(BaseEngine):
|
class LogEngine(BaseEngine):
|
||||||
"""
|
"""
|
||||||
@ -398,3 +410,66 @@ class OmsEngine(BaseEngine):
|
|||||||
if order.vt_symbol == vt_symbol
|
if order.vt_symbol == vt_symbol
|
||||||
]
|
]
|
||||||
return active_orders
|
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()
|
||||||
|
@ -7,9 +7,14 @@ from logging import CRITICAL
|
|||||||
SETTINGS = {
|
SETTINGS = {
|
||||||
"font.family": "Arial",
|
"font.family": "Arial",
|
||||||
"font.size": 12,
|
"font.size": 12,
|
||||||
|
|
||||||
"log.active": True,
|
"log.active": True,
|
||||||
"log.level": CRITICAL,
|
"log.level": CRITICAL,
|
||||||
"log.console": True,
|
"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": ""
|
||||||
}
|
}
|
BIN
vnpy/trader/ui/ico/email.ico
Normal file
BIN
vnpy/trader/ui/ico/email.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
@ -103,6 +103,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.restore_window_setting
|
self.restore_window_setting
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.add_menu_action(
|
||||||
|
help_menu,
|
||||||
|
"测试邮件",
|
||||||
|
"email.ico",
|
||||||
|
self.send_test_email
|
||||||
|
)
|
||||||
|
|
||||||
self.add_menu_action(
|
self.add_menu_action(
|
||||||
help_menu,
|
help_menu,
|
||||||
"关于",
|
"关于",
|
||||||
@ -219,3 +226,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
"""
|
"""
|
||||||
self.load_window_setting("default")
|
self.load_window_setting("default")
|
||||||
self.showMaximized()
|
self.showMaximized()
|
||||||
|
|
||||||
|
def send_test_email(self):
|
||||||
|
"""
|
||||||
|
Sending a test email.
|
||||||
|
"""
|
||||||
|
self.main_engine.send_email("VN Trader", "testing")
|
||||||
|
@ -310,6 +310,11 @@ class TickMonitor(BaseMonitor):
|
|||||||
"cell": BaseCell,
|
"cell": BaseCell,
|
||||||
"update": False
|
"update": False
|
||||||
},
|
},
|
||||||
|
"exchange": {
|
||||||
|
"display": "交易所",
|
||||||
|
"cell": BaseCell,
|
||||||
|
"update": False
|
||||||
|
},
|
||||||
"last_price": {
|
"last_price": {
|
||||||
"display": "最新价",
|
"display": "最新价",
|
||||||
"cell": BaseCell,
|
"cell": BaseCell,
|
||||||
@ -419,6 +424,11 @@ class TradeMonitor(BaseMonitor):
|
|||||||
"cell": BaseCell,
|
"cell": BaseCell,
|
||||||
"update": False
|
"update": False
|
||||||
},
|
},
|
||||||
|
"exchange": {
|
||||||
|
"display": "交易所",
|
||||||
|
"cell": BaseCell,
|
||||||
|
"update": False
|
||||||
|
},
|
||||||
"direction": {
|
"direction": {
|
||||||
"display": "方向",
|
"display": "方向",
|
||||||
"cell": DirectionCell,
|
"cell": DirectionCell,
|
||||||
@ -466,6 +476,11 @@ class OrderMonitor(BaseMonitor):
|
|||||||
"cell": BaseCell,
|
"cell": BaseCell,
|
||||||
"update": False
|
"update": False
|
||||||
},
|
},
|
||||||
|
"exchange": {
|
||||||
|
"display": "交易所",
|
||||||
|
"cell": BaseCell,
|
||||||
|
"update": False
|
||||||
|
},
|
||||||
"direction": {
|
"direction": {
|
||||||
"display": "方向",
|
"display": "方向",
|
||||||
"cell": DirectionCell,
|
"cell": DirectionCell,
|
||||||
@ -540,6 +555,11 @@ class PositionMonitor(BaseMonitor):
|
|||||||
"cell": BaseCell,
|
"cell": BaseCell,
|
||||||
"update": False
|
"update": False
|
||||||
},
|
},
|
||||||
|
"exchange": {
|
||||||
|
"display": "交易所",
|
||||||
|
"cell": BaseCell,
|
||||||
|
"update": False
|
||||||
|
},
|
||||||
"direction": {
|
"direction": {
|
||||||
"display": "方向",
|
"display": "方向",
|
||||||
"cell": DirectionCell,
|
"cell": DirectionCell,
|
||||||
|
Loading…
Reference in New Issue
Block a user