做一个 简单的Django 《股票自选助手》显示 用akshare 库(A股数据获取)

 图:

股票自选助手

这是一个基于 Django 开发的 A 股自选股票信息查看系统。系统使用 akshare 库获取实时股票数据,支持添加、删除和更新股票信息。

功能特点

  • 支持添加自选股票
  • 实时显示股票价格和涨跌幅
  • 一键更新所有股票数据
  • 支持删除不需要的股票
  • 使用中国时区显示更新时间
  • 支持简体中文界面

技术栈

  • Python 3.8+
  • Django 5.0.1
  • akshare(A股数据获取)
  • Bootstrap 5.1.3(前端界面)
  • SQLite(数据存储)

安装步骤

  1. 克隆项目到本地:
git clone [项目地址]
cd stock_tracker
  1. 创建并激活虚拟环境(可选但推荐):
python -m venv venv
# Windows
venv\Scripts\activate
# Linux/Mac
source venv/bin/activate
  1. 安装依赖包:
pip install django akshare pandas
  1. 初始化数据库:
python manage.py migrate
  1. 启动开发服务器:
python manage.py runserver
  1. 访问系统:
    打开浏览器,访问 http://127.0.0.1:8000

使用说明

添加股票

  1. 在输入框中输入股票代码,支持以下格式:
    • 直接输入代码:600519(系统会自动判断沪深市场)
    • 带后缀格式:
      • 上证股票:600519.SS
      • 深证股票:000001.SZ
  1. 点击"添加"按钮将股票添加到自选列表

更新股票数据

  • 点击"更新价格"按钮可以一次性更新所有股票的最新数据
  • 系统会显示更新成功和失败的股票数量

删除股票

  • 点击每个股票行右侧的"删除"按钮可以将股票从自选列表中移除

项目结构

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: 更新股票价格

注意事项

  1. 时区设置:
    • 系统使用中国时区 (Asia/Shanghai)
    • 所有时间显示均为本地时间
  1. 数据更新:
    • 使用 akshare 获取实时数据
    • 支持批量更新所有股票
  1. 错误处理:
    • 系统会显示详细的错误信息
    • 包含股票代码格式提示

维护和更新

  1. 数据库备份:
    • 定期备份 SQLite 数据库文件
  1. 依赖更新:
    • 定期检查并更新依赖包
    • 特别注意 akshare 的更新

代码:

stocks\models.py

from django.db import models

class 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 pd

def 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 = symbol
                market = '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 = 0
    error_count = 0
    stocks = 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 += 1
                else:
                    error_count += 1
            except:
                error_count += 1
                continue
    except 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 views

urlpatterns = [
    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, include

urlpatterns = [
    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 = True

USE_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")

# 返回数据包含:
# - 股票代码
# - 股票简称
# - 行业
# - 总市值
# - 流通市值
# - 等基本面信息

本项目中的使用

在本项目中,我们主要使用了以下功能:

  1. 获取实时行情:
# 从 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['涨跌幅'])
  1. 批量更新价格:
# 从 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['涨跌幅'])

注意事项

  1. 数据限制:
    • 接口访问可能有频率限制
    • 建议适当控制请求频率
    • 考虑数据缓存机制
  1. 代码格式:
    • A股代码格式:6位数字
    • 上证股票以 6 开头
    • 深证股票以 0 或 3 开头
  1. 错误处理:
    • 注意处理网络异常
    • 处理数据为空的情况
    • 处理数值转换异常

常见问题

  1. 数据获取失败:
    • 检查网络连接
    • 确认股票代码格式
    • 查看是否触发频率限制
  1. 数据不准确:
    • 确认是否在交易时间
    • 检查数据更新时间
    • 验证股票代码正确性

相关资源

  • AKShare 官方文档
  • GitHub 仓库
  • AKShare 使用教程

更新记录

  • 2024-01-10: 首次创建文档
  • 使用 akshare 1.15.68 版本
  • 主要实现 A 股实时数据获取功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/954055.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C#使用OpenTK绘制3D可拖动旋转图形三棱锥

接上篇,绘制着色矩形 C#使用OpenTK绘制一个着色矩形-CSDN博客 上一篇安装OpenTK.GLControl后,这里可以直接拖动控件GLControl 我们会发现GLControl继承于UserControl //// 摘要:// OpenGL-aware WinForms control. The WinForms designer will always call the default//…

《C++11》nullptr介绍:从NULL说起

在C11之前&#xff0c;我们通常使用NULL来表示空指针。然而&#xff0c;NULL在C中有一些问题和限制&#xff0c;这就是C11引入nullptr的原因。本文将详细介绍nullptr的定义、用法和优点。 1. NULL的问题 在C中&#xff0c;NULL实际上是一个整数0&#xff0c;而不是一个真正的…

Postman 接口测试平替工具,可视化开发省事!

在软件开发的漫长旅程中&#xff0c;接口测试工具一直是开发者的得力助手。Postman 作为全球知名的接口测试工具&#xff0c;长期占据市场主导地位。然而&#xff0c;随着国产工具的崛起&#xff0c;越来越多的开发者开始寻找更适合中国开发者的替代方案。一款 Apifox&#xff…

代码随想录算法训练营day20(0113)

1.二叉搜索树的最近公共祖先 在上次做完二叉树的最近公共祖先后&#xff0c;此题就显得比较简单了。不过要拓展一下&#xff0c;因为二叉搜索树有一些特性的&#xff0c;可以更加方便的解题。 题目 235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节…

使用C# CEFSharp在WPF中开发桌面程序实现同一网站多开功能

在网络商业运营领域&#xff0c;同时运营多个淘宝店铺的现象屡见不鲜。为了满足这一需求&#xff0c;实现同一网址的多开功能变得尤为关键。这一需求虽然实用&#xff0c;但实现起来却面临诸多挑战。在这个过程中&#xff0c;技术人员们也经历了不少喜怒哀乐。 开发经历回顾 …

Shell 经典面试例题

1.shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容&#xff0c;不存在则创建一个文件将创建时间写入。 编写脚本&#xff1a; #!/bin/bash FILE"/tmp/size.log" if [ -f "$FILE" ]; then echo "文件存在&#xff0c;显示文件内容&…

移动云自研云原生数据库入围国采!

近日&#xff0c;中央国家机关2024年度事务型数据库软件框架协议联合征集采购项目产品名单正式公布&#xff0c;移动云自主研发的云原生数据库产品顺利入围。这一成就不仅彰显了移动云在数据库领域深耕多年造就的领先技术优势&#xff0c;更标志着国家权威评审机构对移动云在数…

Centos 宝塔安装

yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 安装成功界面 宝塔说明文档 https://www.bt.cn/admin/servers#wcu 或者可以注册宝塔账号 1 快速部署 安装docker 之后 2 需要在usr/bin下下载do…

ros2笔记-6.2 使用urdf创建机器人模型

本节主要跟着小鱼老师的视频操作&#xff0c;不同的仿真平台有不同的建模语言&#xff0c;但是几乎都支持URDF。 本节使用URDF创建一个机器人模型。 6.2.1 帮机器人创建一个身体 URDF使用XML来描述机器人的结构和传感器、执行器等信息。 在chapt6/chap6_ws/src创建功能包:r…

文章复现—面向配电网韧性提升的移动储能预布局与动态调度策略

目录 一、主要内容&#xff1a; 二、实际运行效果&#xff1a; 三、文章介绍&#xff1a; 四、完整代码数据下载&#xff1a; 一、主要内容&#xff1a; &#xff08;matlab代码&#xff09;该程序复现《面向配电网韧性提升的移动储能预布局与动态调度策略》&#xff0c;具…

【ASP.NET学习】Web Forms创建Web应用

文章目录 什么是 Web Forms&#xff1f;ASP.NET Web Forms - HTML 页面用 ASP.NET 编写的 Hello RUNOOB.COM它是如何工作的&#xff1f;经典 ASP ASP.NET Web Forms - 服务器控件经典 ASP 的局限性ASP.NET - 服务器控件ASP.NET - HTML 服务器控件ASP.NET - Web 服务器控件ASP.N…

python-leetcode-旋转图像

48. 旋转图像 - 力扣&#xff08;LeetCode&#xff09; class Solution:def rotate(self, matrix: List[List[int]]) -> None:"""Do not return anything, modify matrix in-place instead."""n len(matrix)# 矩阵转置for i in range(n):for…

GPT 系列论文精读:从 GPT-1 到 GPT-4

学习 & 参考资料 前置文章 Transformer 论文精读 机器学习 —— 李宏毅老师的 B 站搬运视频 自监督式学习(四) - GPT的野望[DLHLP 2020] 來自猎人暗黑大陆的模型 GPT-3 论文逐段精读 —— 沐神的论文精读合集 GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【论文精读】…

《计算机网络》课后探研题书面报告_了解PPPoE协议

PPPoE协议的工作原理与应用分析 摘 要 PPPoE&#xff08;Point-to-Point Protocol over Ethernet&#xff09;是一种广泛应用于宽带接入的网络协议&#xff0c;特别是在DSL&#xff08;数字用户线路&#xff09;和光纤网络中具有重要的应用价值。PPPoE结合了PPP协议的认证、加…

玩转大语言模型——langchain调用ollama视觉多模态语言模型

系列文章目录 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 langchain调用ollama视觉多模态语言模型 系列文章目录前言使用Ollama下载模型查找模型下载模型 测试模型ollama测试langchain测试加载图片加载模型…

开始使用Panuon开源界面库环境配置并手写VS2019高仿界面

1. Panuon环境配置 1.1. 通过Nuget 安装 Panuon.WPF.UI1.2. xaml引用命名空间1.3. using Panuon.WPF.UI; 2. VS2019 view 2.1. 设置窗体尺寸和title2.2. 添加静态资源 2.2.1. 什么是静态资源 2.3. 主Grid 2.3.1. 盒子模型2.3.2. 嵌套布局 3. 总结 1. Panuon环境配置 1.1. 通…

[Git] 深入理解 Git 的客户端与服务器角色

Git 的一个核心设计理念是 分布式&#xff0c;每个 Git 仓库都可以既是 客户端&#xff0c;也可以是 服务器。为了更好地理解这一特性&#xff0c;我们通过一个实际的 GitHub 远程仓库和本地仓库的场景来详细说明 Git 如何在客户端和服务器之间协作&#xff0c;如何独立地进行版…

基于考研概率论知识解读 Transformer:为何自注意力机制要除以根号 dk

Transformer自注意力机制中除以 d k \sqrt{d_k} dk​ ​深度剖析 【 Transformer 系列&#xff0c;故事从 d k \sqrt{d_k} dk​ ​说起】 LLM这么火&#xff0c;Transformer厥功甚伟&#xff0c;某天心血来潮~&#xff0c;再去看看&#xff01; 它长这个样子&#xff1a; 深入…

使用 selenium-webdriver 开发 Web 自动 UI 测试程序

优缺点 优点 有时候有可能一个改动导致其他的地方的功能失去效果&#xff0c;这样使用 Web 自动 UI 测试程序可以快速的检查并定位问题&#xff0c;节省大量的人工验证时间 缺点 增加了维护成本&#xff0c;如果功能更新过快或者技术更新过快&#xff0c;维护成本也会随之提高…

【Redis】初识分布式系统

目录 单机架构 分布式系统 应用数据分离架构 应用服务集群架构 读写分离/主从分离架构 冷热分离架构 垂直分库 微服务架构 分布式名词概念 本篇博文&#xff0c;将根据分布式系统的演进一步一步介绍每一种架构的形式&#xff0c;最后为大家总结了一些分布式中常用的…