当前位置: 首页 > news >正文

python制作一个股票盯盘系统

没有多少时间,这里简单写一下过程,主要是代码。

一、建立数据库,我采用sqlite3.

一个是记录股票的表,一个是设置股票股价预警的表。

二、采集股票股价变化到数据库,我这里用的是周一到周五开市时间,如果遇到其他时间就没有办法采集。

# -*- coding: utf-8 -*-
"""
Created on Tue Aug 19 16:38:35 2025@author: Yang
"""
import time
import efinance as ef
import random
from apscheduler.schedulers.blocking import BlockingScheduler
from wxauto import WeChat
import sqlite3
from pathlib import Pathwx = WeChat()
who = '楊斐'
db_filepath = Path(__file__).joinpath("../gp.db").resolve()def insertdb(gpdh,gpmc,zxj,gxsj,ts):conn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)c = conn.cursor()insert_query = "INSERT INTO gp(gpdh,gpmc,zxj,gxsj,ts) VALUES(?,?,?,?,?);"insert_data = (gpdh,gpmc,zxj,gxsj,ts) #ts 买入为1,卖出为2c.execute(insert_query,insert_data)conn.commit()c.close()conn.closedef job():global whoconn = sqlite3.connect(db_filepath, timeout=10, check_same_thread=False)c = conn.cursor()sqlget = "select gpdh,gmjg,mcjg,cy from mai where cy <> 2 and gmjg > 0;" #cy为1持有看,2删除,0没有设置c.execute(sqlget)cursor = c.execute(sqlget)rows = cursor.fetchall()for gp in rows:quote = ef.stock.get_latest_quote(gp[0])time.sleep(random.uniform(1.5, 3.5))gpdh = quote.iloc[0, 0]gpmc = quote.iloc[0, 1]gpj = quote.iloc[0, 3]zxj = gpjgxsj = quote.iloc[0, 18]        gpj = quote[['最新价']].iloc[0, 0]if gpj <= gp[1]:print(gp[0]+'--' + str(gpj) + '元,可以买')message = f'{gp[0]}:最新股价{gpj}元,可以买了。原设置买入股价为{gp[1]}'wx.SendMsg(message, who)ts = 1elif gpj >= gp[2] and gp[3] == 1:print(gp[0]+'--' + str(gpj) + '元,可以卖出')message = f'{gp[0]}:最新股价{gpj}元,可以卖出。原设置卖出股价为{gp[2]}'wx.SendMsg(message, who)ts = 2else:print(gp[0]+'--' + str(gpj) + '元')ts = 0insertdb(gpdh,gpmc,zxj,gxsj,ts)job()scheduler = BlockingScheduler()# 上午时段(9:30-11:30)每隔10分钟执行
scheduler.add_job(job,'cron',day_of_week='mon-fri',hour='9',minute='31,36,41,46,51,56',
)
scheduler.add_job(job,'cron',day_of_week='mon-fri',hour='10',minute='1,6,11,16,21,26,31,36,41,46,51',
)
scheduler.add_job(job,'cron',day_of_week='mon-fri',hour='11',minute='1,6,11,16,21,26,31,59',
)
# 下午时段(13:00-15:00)每隔10分钟执行
scheduler.add_job(job,'cron',day_of_week='mon-fri',hour='13-14',minute='1,6,11,16,21,26,31,36,41,46,51,56',
)
scheduler.add_job(job,'cron',day_of_week='mon-fri',hour='15',minute='1',
)print("定时任务已启动...")
scheduler.start()job()

上面程序,在开市时间,每5分钟采集一次股票股价,到达设置买入价格或卖出价格就发送微信给我提醒我操作。

三、网页界面

# -*- coding: utf-8 -*-
"""
Created on Mon Aug 25 09:56:58 2025@author: Yang
"""from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
import reapp = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///C:/Users/Yang/.spyder-py3/gp.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)class gp(db.Model):__tablename__ = 'gp'id = db.Column(db.Integer, primary_key=True)gpdh = db.Column(db.String(10))gpmc = db.Column(db.String(20))zxj = db.Column(db.Numeric(precision=10, scale=2))gxsj = db.Column(db.String(30))ts = db.Column(db.Integer)class mai(db.Model):__tablename__ = 'mai'id = db.Column(db.Integer, primary_key=True)gpdh = db.Column(db.String(10))gmjg = db.Column(db.Numeric(precision=10, scale=2))mcjg = db.Column(db.Numeric(precision=10, scale=2))cy = db.Column(db.Integer, default=0)def validate_six_digit(value):return bool(re.fullmatch(r'^\d{6}$', value))def validate_price(value):try:float_value = float(value)return len(str(float_value).split('.')[1]) <= 2except ValueError:return False@app.route('/')
def index():page = request.args.get('page', 1, type=int)  # 获取页码参数,默认为1per_page = request.args.get('per_page', 20, type=int)  # 获取每页数量,默认为10products = gp.query.order_by(gp.id.desc()).paginate(page=page, per_page=per_page, error_out=False)return render_template('index.html', data=products)@app.route('/sz', methods=['GET', 'POST'])
def sz():if request.method == 'POST':six_digit = request.form.get('six_digit')price1 = request.form.get('price1')price2 = request.form.get('price2')is_checked = 1 if request.form.get('is_checked') == 'on' else 0  # 转换复选框值为1/0errors = []if not validate_six_digit(six_digit):errors.append("6位数字验证失败")if not validate_price(price1):errors.append("价格1格式错误")if not validate_price(price2):errors.append("价格2格式错误")if not errors:new_data = mai(gpdh=six_digit,gmjg=float(price1),mcjg=float(price2),cy=is_checked  # 使用转换后的值)#在添加之前将原有设置为2mai.query.filter_by(gpdh=f'{six_digit}').update({'cy': 2})db.session.commit()db.session.add(new_data)db.session.commit()return redirect(url_for('success'))else:products0 = mai.query.filter(mai.cy < 2).all()return render_template('sz.html', errors=errors, datagp=products0)products0 = mai.query.filter(mai.cy < 2).all()return render_template('sz.html', datagp=products0)@app.route('/success')
def success():return "数据提交成功!<a href='../sz'>返回</a>"if __name__ == '__main__':app.run(host='127.0.0.1',debug=True)

其中的index.html

<!DOCTYPE html>
<html>
<head><title>情况列表</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body><div class="container mt-4"><h2>情况列表 <a href='./sz'>设置</a></h2><table class="table table-striped"><thead><tr><th>代号</th><th>名称</th><th>价格</th><th>更新时间</th><th>提示</th></tr></thead><tbody>{% for item in data.items %}<tr><td>{{ item.gpdh }}</td><td>{{ item.gpmc }}</td><td>{{ item.zxj }}</td><td>{{ item.gxsj }}</td><td>{% if item.ts == 0 %}--{% elif item.ts == 1 %}买入{% else %}卖出{% endif %}</td></tr>{% endfor %}</tbody></table><nav><ul class="pagination">{% if data.has_prev %}<li class="page-item"><a class="page-link" href="?page={{ data.prev_num }}">上一页</a></li>{% endif %}{% for page_num in data.iter_pages() %}{% if page_num %}<li class="page-item {% if page_num == data.page %}active{% endif %}"><a class="page-link" href="?page={{ page_num }}">{{ page_num }}</a></li>{% else %}<li class="page-item disabled"><span class="page-link">...</span></li>{% endif %}{% endfor %}{% if data.has_next %}<li class="page-item"><a class="page-link" href="?page={{ data.next_num }}">下一页</a></li>{% endif %}</ul></nav></div>
</body>
</html>

其中的sz.html代码

<!DOCTYPE html>
<html>
<head><title>设置</title><style>.error { color: red; }form { max-width: 500px; margin: 20px auto; }label { display: block; margin-top: 10px; }input { width: 100%; padding: 8px; }button { margin-top: 20px; padding: 10px 20px; }</style><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body><div class="container mt-4"><h2>gp设置 <a href='../'>主页</a></h2><table class="table table-striped"><thead><tr><th>代号</th><th>购买价格</th><th>卖出价格</th><th>持有</th></tr></thead><tbody>{% for item in datagp %}<tr><td>{{ item.gpdh }}</td><td>{{ item.gmjg }}</td><td>{{ item.mcjg }}</td><td>{% if item.cy == 0 %}无{% elif item.cy == 1 %}有{% else %}无{% endif %}</td></tr>{% endfor %}</tbody></table>{% if errors %}<div class="error">{% for error in errors %}<p>{{ error }}</p>{% endfor %}</div>{% endif %}<form method="POST"><div><label>代号6位纯数字:</label><input type="text" name="six_digit" required></div><div><label>购买价格(带2位小数):</label><input type="number" step="0.01" name="price1" required></div><div><label>卖出价格(带2位小数):</label><input type="number" step="0.01" name="price2" required></div><div><label><input type="checkbox" name="is_checked">是否持有(1=是/0=否)</label></div><button type="submit">提交</button></form></div>
</body>
</html>

四、采用cpolar挂到公网,制作安卓app获取并显示网页

参考通过beeware制作安卓apk用于获取cpolar网址-CSDN博客

http://www.xdnf.cn/news/1399681.html

相关文章:

  • NV032NV037美光固态闪存NV043NV045
  • 基于开源AI大模型AI智能名片S2B2C商城小程序的产地优势产品销售策略研究
  • 前端代码结构详解
  • 盛最多水的容器,leetCode热题100,C++实现
  • 封装哈希表
  • 基于SpringBoot的流浪动物领养系统【2026最新】
  • macOS 15.6 ARM golang debug 问题
  • Rust Web 模板技术~MiniJinja入门:一款适用于 Rust 语言的轻依赖强大模板引擎
  • Fourier 级数展开(案例:级数展开 AND 求和)
  • Prompt Engineering:高效构建智能文本生成的策略与实践
  • 单例模式的mock类注入单元测试与友元类解决方案
  • Android15适配16kb
  • ros2 foxy没有话题问题解决
  • Axios 实例配置指南
  • Keil5 MDK_541官网最新版下载、安装
  • 从 0 到 1 构建零丢失 RabbitMQ 数据同步堡垒:第三方接口数据零丢失的终极方案
  • comfUI背后的技术——VAE
  • 线性代数理论——状态空间
  • 聊一聊耳机串扰-Crosstalk
  • Vue常用指令和生命周期
  • 118、【OS】【Nuttx】【周边】效果呈现方案解析:作用域?
  • 生成一份关于电脑电池使用情况、健康状况和寿命估算的详细 HTML 报告
  • 软考中级习题与解答——第一章_数据结构与算法基础(2)
  • 【Redisson 加锁源码解析】
  • VuePress添加自定义组件
  • 【MySQL数据库】索引 - 结构 学习记录
  • 加速智能经济发展:如何助力“人工智能+”战略在实时视频领域的落地
  • Swift 解法详解:LeetCode 367《有效的完全平方数》
  • Kafka入门
  • 开源 C++ QT Widget 开发(八)网络--Http文件下载