注意:代码有问题,还未解决
一.准备
自己打好SendMail.py脚本和monitor2.py脚本,前者是发送邮件脚本,后者是监控目标股票是否达到止盈点或者止损点(可以为股价例如25.44也可以是幅度例如0.2),还有监控大盘(每上涨/下跌50点)发送一次报告邮件。
因为云服务器上有多个版本的python和pip,所以这里有点疑惑,但是经查发现,使用python3执行脚本的话,只能导入利用pip3命令安装的包。
tushare需要python3版本,所以用pip3版本安装包(另外不知道为什么pip命令失效,安装不了包)。
需要安装以下包:
pip3 install tushare pip3 install numpy pip3 install pandas pip3 install apscheduler
代码所需的bs4和smptlib,前者是tushare的依赖,后者python自带。
pip3 list
可以查看已经安装的依赖包,’pip3 show 包名’可以查看安装的包的位置
二.部署
执行
nohup python3 monitor2.py &
查看结果
三.代码
SendMail.py代码:
import smtplib
from email.mime.text import MIMEText
from email.header import Header
import time
#This file is target to send a mail to target mail.
def sendMail(body):
sender = 'xxxx@163.com' #发送者邮箱
receiver = 'xxx@126.com' #接收者邮箱
subject = '金融播报' #主题
smtpserver = 'smtp.163.com'
username = 'xxxxx@163.com' #用户名
password = 'xxxxx' #密码
msg = MIMEText(body,'plain','utf-8') #中文需参数‘utf-8',单字节字符不需要
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = '闫同学<why_three@163.com>'
msg['To'] = receiver
#腾讯云服务器25端口禁用,所以必须使用SSL连接和465端口
smtp = smtplib.SMTP_SSL('smtp.163.com',465)
smtp.login(username, password)
smtp.sendmail(sender, receiver, msg.as_string())
smtp.quit()
monitor2.py:
import tushare as ts
import numpy as np
import time
import pandas as pd
#获取上证实时指数自行爬取所需依赖包
from urllib.request import urlopen
from bs4 import BeautifulSoup
#定时任务
from datetime import datetime
from datetime import date
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.blocking import BlockingScheduler
from SendMail import *
stocks = []
#股票代号,股票名称,成本,止盈点(可以为目标价位或者是比例,比如35.000或者0.1),止损点(止损价位或者止损比例)
stocks.append(['002389','航天彩虹', 33.476, 31.050, 28.000])
stocks.append(['601989','中国重工', 4.035, 5.100, 0.2])
stocks.append(['600150','中国船舶', 17.977, 19.000,17.300])
stocks_codes = [x[0] for x in stocks] #只能用列表解析的方式读取第一列,而np数组可以用slip
df_data = ts.get_realtime_quotes(stocks_codes) #得到二维股票信息
#以interval分钟监控stocks,若达到止盈/止损点,则发邮件
def notice_by_price(stocks, interval=10):
if_notice = 1 #是否允许通知
if_send = 0 #是否发送过邮件
body = "股价检测情况如下:\n"
old_body = body
while(if_notice):
for stock in stocks:
info = df_data.loc[df_data['code'] == stock[0]]
now_price = info['price'].iat[0] #现在的价位
target_up_price = stock[-2] if stock[-2]>1 else stock[2]*(1+stock[-2]) #如果目标价位为价格的话复制,否则乘以涨跌幅再赋值
target_down_price = stock[-1] if stock[-1]>1 else stock[2]-(stock[2]*stock[-1]) #止损价位
target_up_price = format(target_up_price,'.3f') #保留三位
target_down_price = format(target_down_price, '.3f')
new_notice = stock[1]+":"+"成本:"+str(stock[2])+",现价:"+str(now_price)
new_notice+= ",止盈价:"+target_up_price
if now_price >= target_up_price:
new_notice += "已达到"
new_notice+= ",止损价:"+target_down_price
if now_price <= target_down_price:
new_notice += "已达到"
body += new_notice + "\n"
if (body != old_body): #如果新消息不等于旧消息,得通知一次
if_send = 1
if (if_send): #用if_send解耦一下,说不定以后添加什么新功能
sendMail(body)
if_send = 0
old_body = body #旧消息等于新消息
body = "股价检测情况如下:\n" #消息初始格式
time.sleep(interval*60)
#返回上证实时指数
def get_sh_now():
url = "https://gu.qq.com/sh000001/zs"
html = urlopen(url).read()
soup = BeautifulSoup(html,'html.parser')
#soup的css寻找需要在后面加下划线,因为class在python中是官方保留字
sh = soup.find(class_="data").get_text()
return sh
#监控上证指数,每interval点发送一次邮件,interval必须为5的整数倍,因为大盘点数是小数连续的,而我们只关注
#每interval点的大盘,所以将大盘指数除以interval映射成一个0-100的整数,用于下标
#每inter_time小时监控一次大盘,若间隔过大,比如3小时,可能出现暴涨100点,中间的50点不通知只通知100点
#若间隔过小,可能大盘在盯盘点半小时内反复横跳的话会多次通知
def notice_sh(interval = 50, inter_time = 1):
#初始化
monitor_bit = [0]*int(10000/interval) #监控大盘10000点一下,每变化interval点发送一次提醒邮件
init_sh = int(float(get_sh_now())/interval) #执行脚本当天的初始大盘点数对应的整数
for i in range(init_sh+1):
monitor_bit[i] = 1
times = 8 #每天执行7次,9点开始执行,整点查询一次,下午15:00结束阻塞等待18个小时候继续执行
while(times):
times = times-1
print("times="+str(times))
body = ""
real_sh = 3601#float(get_sh_now()) #上证指数
new_sh = int(real_sh/interval) #循环执行时请求最新的上证点数对应的整数,并且字符串需要先转float再转int
if monitor_bit[new_sh] == 1 and monitor_bit[new_sh+1] == 1: #python逻辑运算符为and、or、not
#当前大盘处于new_sh和new_sh之间且两边为(1,1)(即大盘从new_sh+1跌下来了)
if_send = 1
monitor_bit[new_sh+1]=0
body = "上证指数已下跌至"+str((new_sh+1) * interval)+"以下"
elif monitor_bit[new_sh] == 0 and monitor_bit[new_sh+1] == 0: #python没有else if,只有elif
#当前大盘处于new_sh和new_sh之间且两边为(0,0)(即大盘涨到new_sh以上了)
if_send = 1
monitor_bit[new_sh] = 1
body = "上证指数已上涨至"+str((new_sh) * interval)+"以上"
elif monitor_bit[new_sh] == 0 and monitor_bit[new_sh+1] == 1:
#(new_sh,new_sh+1)=(0,1),这种情况时说明大盘暴在0.5小时内暴涨了50点之后又跌下到new_sh+1了
if_send = 1
monitor_bit[new_sh] = 1
monitor_bit[new_sh+1] = 0
body = "上证指数已下跌至"+str((new_sh+1) * interval)+"以下"
else:
#不通知情况即为(new_sh,new_sh+1)=(1,0)即达到new_sh并且通知过了
if_send = 0
pass
body += ",现在上证指数为:"+str(real_sh)
if (if_send):
print(body)
if (times != 0):
time.sleep(1*60*60) #time!=0即在9:00——15:00,休眠一小时
else:
time.sleep(18*60*60) #time==0即盯盘结束,在15:00——9:00休息18个小时继续盯盘
times = 8
#返回上证实时指数
def get_sh_now():
url = "https://gu.qq.com/sh000001/zs"
html = urlopen(url).read()
soup = BeautifulSoup(html,'html.parser')
#soup的css寻找需要在后面加下划线,因为class在python中是官方保留字
sh = soup.find(class_="data").get_text()
return sh
#APSscheduler有两种调度器,一种时BackgroundScheduler,一种是BlockingScheduler,而如果应用前者的话,
#定时任务会在后台运行,不会阻塞主线程,而我们的程序如果只盯大盘的话,主线程不执行其它程序,所以直接就结束
#线程了,因此定时任务不会执行,而使用BlockingScheduler的话会避免这种情况产生,但是有一个缺点就是不能用ctrl+c
#停止,只能手动杀死进程。
#参考链接https://blog.csdn.net/ybdesire/article/details/82228840#:~:text=%E9%82%A3%E4%BB%96%E4%BB%AC%E4%B9%8B%E9%97%B4%E6%9C%89,%E8%80%8C%20BackgroundScheduler%20%E4%B8%8D%E4%BC%9A%E9%98%BB%E5%A1%9E%E3%80%82&text=BlockingScheduler%20%3A%20%E8%B0%83%E7%94%A8start%E5%87%BD%E6%95%B0%E5%90%8E,%E6%97%B6%EF%BC%88%E5%A6%82%E4%B8%8A%E4%BE%8B%EF%BC%89%E4%BD%BF%E7%94%A8%E3%80%82
scheduler =BlockingScheduler()
#从1月19日开始执行监控大盘程序
job1 = scheduler.add_job(notice_sh, 'date', run_date='2021-01-19 09:00:00')
job2 = scheduler.add_job(notice_by_price, "date", run_date='2021-01-19 09:00:00',args=[stocks,0.5])
#周内媒体那9.30开始执行盯盘股票程序
#job2 = scheduler.add_job(notice_by_price, "cron",week="1-53",day_of_week="0-5",hour="9",minute="30",args=[stocks,0.5])
scheduler.start()
欢迎在评论区中进行批评指正,转载请注明来源,如涉及侵权,请联系作者删除。