图:
股票自选助手
这是一个基于 Django 开发的 A 股自选股票信息查看系统。系统使用 akshare 库获取实时股票数据,支持添加、删除和更新股票信息。
功能特点
- 支持添加自选股票
- 实时显示股票价格和涨跌幅
- 一键更新所有股票数据
- 支持删除不需要的股票
- 使用中国时区显示更新时间
- 支持简体中文界面
技术栈
- Python 3.8+
- Django 5.0.1
- akshare(A股数据获取)
- Bootstrap 5.1.3(前端界面)
- SQLite(数据存储)
安装步骤
- 克隆项目到本地:
git clone [项目地址]
cd stock_tracker
- 创建并激活虚拟环境(可选但推荐):
python -m venv venv
# Windows
venv\Scripts\activate
# Linux/Mac
source venv/bin/activate
- 安装依赖包:
pip install django akshare pandas
- 初始化数据库:
python manage.py migrate
- 启动开发服务器:
python manage.py runserver
- 访问系统:
打开浏览器,访问 http://127.0.0.1:8000
使用说明
添加股票
- 在输入框中输入股票代码,支持以下格式:
-
- 直接输入代码:
600519
(系统会自动判断沪深市场) - 带后缀格式:
- 直接输入代码:
-
-
- 上证股票:
600519.SS
- 深证股票:
000001.SZ
- 上证股票:
-
- 点击"添加"按钮将股票添加到自选列表
更新股票数据
- 点击"更新价格"按钮可以一次性更新所有股票的最新数据
- 系统会显示更新成功和失败的股票数量
删除股票
- 点击每个股票行右侧的"删除"按钮可以将股票从自选列表中移除
项目结构
stock_tracker/
├── manage.py
├── stock_tracker/ # 项目配置目录
│ ├── __init__.py
│ ├── settings.py # 项目设置
│ ├── urls.py # URL配置
│ └── wsgi.py
└── stocks/ # 股票应用目录├── __init__.py├── models.py # 数据模型├── views.py # 视图函数├── urls.py # 应用URL配置└── templates/ # 模板文件└── stocks/└── stock_list.html
开发说明
数据模型
Stock
模型包含以下字段:
symbol
: 股票代码name
: 股票名称current_price
: 当前价格change_percent
: 涨跌幅last_updated
: 最后更新时间
主要视图函数
stock_list
: 显示股票列表add_stock
: 添加新股票remove_stock
: 删除股票update_prices
: 更新股票价格
注意事项
- 时区设置:
-
- 系统使用中国时区 (Asia/Shanghai)
- 所有时间显示均为本地时间
- 数据更新:
-
- 使用 akshare 获取实时数据
- 支持批量更新所有股票
- 错误处理:
-
- 系统会显示详细的错误信息
- 包含股票代码格式提示
维护和更新
- 数据库备份:
-
- 定期备份 SQLite 数据库文件
- 依赖更新:
-
- 定期检查并更新依赖包
- 特别注意 akshare 的更新
代码:
stocks\models.py
from django.db import modelsclass Stock(models.Model):symbol = models.CharField(max_length=10, unique=True)name = models.CharField(max_length=100)current_price = models.DecimalField(max_digits=10, decimal_places=2, null=True)change_percent = models.DecimalField(max_digits=5, decimal_places=2, null=True)last_updated = models.DateTimeField(auto_now=True)def __str__(self):return f"{self.symbol} - {self.name}"
stocks\views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from .models import Stock
import akshare as ak
from datetime import datetime
import pandas as pddef stock_list(request):stocks = Stock.objects.all().order_by('symbol')return render(request, 'stocks/stock_list.html', {'stocks': stocks})def add_stock(request):if request.method == 'POST':symbol = request.POST.get('symbol', '').upper()try:# 处理股票代码格式if symbol.endswith('.SZ'):code = symbol.replace('.SZ', '')market = 'sz'elif symbol.endswith('.SS'):code = symbol.replace('.SS', '')market = 'sh'else:code = symbolmarket = 'sh' if code.startswith('6') else 'sz'# 获取实时行情stock_info = ak.stock_zh_a_spot_em()stock_data = stock_info[stock_info['代码'] == code]if stock_data.empty:messages.error(request, f'找不到股票 {symbol} 的信息。请确保:\n1. 股票代码格式正确\n2. 对于上证股票,可以添加.SS后缀\n3. 对于深证股票,可以添加.SZ后缀')return redirect('stock_list')# 获取第一行数据stock_row = stock_data.iloc[0]stock_obj, created = Stock.objects.get_or_create(symbol=symbol,defaults={'name': stock_row['名称']})# 更新股票信息stock_obj.current_price = float(stock_row['最新价'])stock_obj.change_percent = float(stock_row['涨跌幅'])stock_obj.save()if created:messages.success(request, f'成功添加股票 {symbol}({stock_row["名称"]})')else:messages.success(request, f'成功更新股票 {symbol} 的信息')except Exception as e:messages.error(request, f'添加股票时出错: {str(e)}\n建议:\n1. 检查股票代码格式\n2. 确保网络连接正常')return redirect('stock_list')def remove_stock(request, symbol):try:stock = Stock.objects.get(symbol=symbol)stock.delete()messages.success(request, f'已删除股票 {symbol}')except Stock.DoesNotExist:messages.error(request, f'找不到股票 {symbol}')return redirect('stock_list')def update_prices(request):success_count = 0error_count = 0stocks = Stock.objects.all()try:# 获取所有A股实时行情stock_info = ak.stock_zh_a_spot_em()for stock in stocks:try:# 处理股票代码格式if stock.symbol.endswith('.SZ'):code = stock.symbol.replace('.SZ', '')elif stock.symbol.endswith('.SS'):code = stock.symbol.replace('.SS', '')else:code = stock.symbol# 查找对应的股票数据stock_data = stock_info[stock_info['代码'] == code]if not stock_data.empty:stock_row = stock_data.iloc[0]stock.current_price = float(stock_row['最新价'])stock.change_percent = float(stock_row['涨跌幅'])stock.save()success_count += 1else:error_count += 1except:error_count += 1continueexcept Exception as e:messages.error(request, f'更新价格时出错: {str(e)}')return redirect('stock_list')if success_count > 0:messages.success(request, f'成功更新 {success_count} 支股票的价格')if error_count > 0:messages.warning(request, f'有 {error_count} 支股票更新失败')return redirect('stock_list')
stocks\urls.py
from django.urls import path
from . import viewsurlpatterns = [path('', views.stock_list, name='stock_list'),path('add/', views.add_stock, name='add_stock'),path('remove/<str:symbol>/', views.remove_stock, name='remove_stock'),path('update/', views.update_prices, name='update_prices'),
]
stocks\templates\stocks\stock_list.html
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>自选股票</title><link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body><div class="container mt-4"><h1 class="mb-4">我的自选股票</h1>{% if messages %}<div class="messages">{% for message in messages %}<div class="alert alert-{{ message.tags }}">{{ message }}</div>{% endfor %}</div>{% endif %}<!-- 添加新股票的表单 --><div class="card mb-4"><div class="card-body"><h5 class="card-title">添加新股票</h5><form method="post" action="{% url 'add_stock' %}" class="row g-3">{% csrf_token %}<div class="col-auto"><input type="text" name="symbol" class="form-control" placeholder="输入股票代码" required></div><div class="col-auto"><button type="submit" class="btn btn-primary">添加</button></div></form></div></div><!-- 股票列表 --><div class="card"><div class="card-body"><div class="d-flex justify-content-between align-items-center mb-3"><h5 class="card-title">股票列表</h5><a href="{% url 'update_prices' %}" class="btn btn-success">更新价格</a></div>{% if stocks %}<div class="table-responsive"><table class="table table-hover"><thead><tr><th>代码</th><th>名称</th><th>当前价格</th><th>涨跌幅</th><th>最后更新</th><th>操作</th></tr></thead><tbody>{% for stock in stocks %}<tr><td>{{ stock.symbol }}</td><td>{{ stock.name }}</td><td>{{ stock.current_price }}</td><td class="{% if stock.change_percent > 0 %}text-success{% elif stock.change_percent < 0 %}text-danger{% endif %}">{{ stock.change_percent|floatformat:2 }}%</td><td>{{ stock.last_updated|date:"Y-m-d H:i:s" }}</td><td><a href="{% url 'remove_stock' stock.symbol %}" class="btn btn-danger btn-sm" onclick="return confirm('确定要删除这支股票吗?')">删除</a></td></tr>{% endfor %}</tbody></table></div>{% else %}<p class="text-center">暂无自选股票,请添加。</p>{% endif %}</div></div></div><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
stock_tracker\urls.py
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('', include('stocks.urls')),
]
stock_tracker\settings.py
INSTALLED_APPS = [。。。'stocks',
]LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'USE_I18N = TrueUSE_TZ = True
AKShare 使用说明
AKShare 是一个优秀的开源财经数据接口库,用于获取中国金融市场数据。本项目主要使用其 A 股数据接口。
安装方法
pip install akshare
基本使用
import akshare as ak
A股数据获取
1. 实时行情数据
获取所有 A 股实时行情数据:
# 获取所有A股实时行情
stock_info = ak.stock_zh_a_spot_em()# 返回的数据包含以下字段:
# - 代码: 股票代码
# - 名称: 股票名称
# - 最新价: 当前价格
# - 涨跌幅: 涨跌百分比
# - 涨跌额: 价格变动
# - 成交量: 成交股数
# - 成交额: 成交金额
# - 振幅: 价格振幅
# - 最高: 最高价
# - 最低: 最低价
# - 今开: 开盘价
# - 昨收: 昨日收盘价
2. 个股历史数据
获取单个股票的历史数据:
# 获取股票历史数据
stock_history = ak.stock_zh_a_hist(symbol="000001", period="daily", start_date="20240101", end_date="20240110")# 参数说明:
# - symbol: 股票代码(不带市场后缀)
# - period: 周期(daily-日线,weekly-周线,monthly-月线)
# - start_date: 开始日期
# - end_date: 结束日期
3. 股票基本信息
获取股票的基本信息:
# 获取股票基本信息
stock_info = ak.stock_individual_info_em(symbol="000001")# 返回数据包含:
# - 股票代码
# - 股票简称
# - 行业
# - 总市值
# - 流通市值
# - 等基本面信息
本项目中的使用
在本项目中,我们主要使用了以下功能:
- 获取实时行情:
# 从 views.py 中的实现
def add_stock(request):# 获取实时行情数据stock_info = ak.stock_zh_a_spot_em()# 查找特定股票stock_data = stock_info[stock_info['代码'] == code]if not stock_data.empty:# 获取股票信息stock_row = stock_data.iloc[0]current_price = float(stock_row['最新价'])change_percent = float(stock_row['涨跌幅'])
- 批量更新价格:
# 从 views.py 中的实现
def update_prices(request):# 一次获取所有A股数据stock_info = ak.stock_zh_a_spot_em()for stock in stocks:# 查找对应的股票数据stock_data = stock_info[stock_info['代码'] == code]if not stock_data.empty:# 更新价格信息stock_row = stock_data.iloc[0]stock.current_price = float(stock_row['最新价'])stock.change_percent = float(stock_row['涨跌幅'])
注意事项
- 数据限制:
-
- 接口访问可能有频率限制
- 建议适当控制请求频率
- 考虑数据缓存机制
- 代码格式:
-
- A股代码格式:6位数字
- 上证股票以 6 开头
- 深证股票以 0 或 3 开头
- 错误处理:
-
- 注意处理网络异常
- 处理数据为空的情况
- 处理数值转换异常
常见问题
- 数据获取失败:
-
- 检查网络连接
- 确认股票代码格式
- 查看是否触发频率限制
- 数据不准确:
-
- 确认是否在交易时间
- 检查数据更新时间
- 验证股票代码正确性
相关资源
- AKShare 官方文档
- GitHub 仓库
- AKShare 使用教程
更新记录
- 2024-01-10: 首次创建文档
- 使用 akshare 1.15.68 版本
- 主要实现 A 股实时数据获取功能