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

news2025/1/13 12:38:26

 图:

股票自选助手

这是一个基于 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 股实时数据获取功能

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity + Firebase + GoogleSignIn 导入问题

我目前使用 Unity版本&#xff1a;2021.3.33f1 JDK版本为&#xff1a;1.8 Gradle 版本为&#xff1a;6.1.1 Firebase 版本: 9.6.0 Google Sign In 版本为&#xff1a; 1.0.1 问题1 &#xff1a;手机点击登录报错 apk转化成zip&#xff0c;解压&#xff0c;看到/lib/armeabi-v…

Django学习笔记之数据库(一)

文章目录 安装一、数据库配置二、基本操作步骤1.增加2.查看3.排序4.更新5.删除数据 三、一对多&#xff0c;多对多&#xff0c;一对一1.一对多1.一对一1.多对多 四、查询操作五、聚合操作六、F和Q操作 安装 首先就是安装Mysql和Navicat。 一、数据库配置 其实整个就是连接前端…

SpringBoot日常:集成Kafka

文章目录 1、pom.xml文件2、application.yml3、生产者配置类4、消费者配置类5、消息订阅6、生产者发送消息7、测试发送消息 本章内容主要介绍如何在springboot项目对kafka进行整合&#xff0c;最终能达到的效果就是能够在项目中通过配置相关的kafka配置&#xff0c;就能进行消息…

RK3568 Android 13 内置搜狗输入法小计

问&#xff1a;为什么写&#xff1f; 答&#xff1a;网上搜出来的都试过了&#xff0c;不行&#xff01;下面直接上代码和注意事项&#xff01; 首先到这个目录&#xff08;/RK3568/Rockchip_Android13_SDK_Release/device/rockchip/rk356x/tl3568_evm/preinstall&#xff09…

【opencv】第8章 图像轮廓与图像分割修复

8.1 查找并绘制轮廓 一个轮廓一般对应一系列的点&#xff0c;也就是图像中的一条曲线。其表示方法可能 根据不同的情况而有所不同。在OpenCV 中&#xff0c;可以用findContours()函数从二值图 像中查找轮廓 8.1.1 寻找轮廓&#xff1a; findContours() 函数 findContours) 函…

BGP 泄露

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 目录 1. BGP 是什么&#xff1f; 2. 什么是 BGP 泄露&#xff1f; 3. 今天发生了什么&#xff1f; 4. 正常和被劫持状态下的路由示意图 5. 受影响区域 6. 责任在谁&#xff1f; 7. 有办法避免这…

数据结构与算法之二叉树: LeetCode 572. 另一棵树的子树 (Ts版)

另一棵树的子树 https://leetcode.cn/problems/subtree-of-another-tree/description/ 描述 给你两棵二叉树 root 和 subRoot检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false二叉树 tree …

动植物基因表达调控

1&#xff0c; on and off状态 以及表达的量 2&#xff0c; 基因调控的生物学影响&#xff1f; 超过400多种细胞类型&#xff0c;数目上37万亿 不是所有的基因都表达 为什么多核真核细胞需要基因调控&#xff1f; 单个细胞往多个细胞逐渐进化的过程&#xff0c;形成复杂的…

FreePBX 17 on ubuntu24 with Asterisk 20

版本配置&#xff1a; FreePBX 17&#xff08;最新&#xff09; Asterisk 20&#xff08;最新Asterisk 22&#xff0c;但是FreePBX 17最新只支持Asterisk 21&#xff0c;但是21非LTS版本&#xff0c;所以选择Asterisk 20&#xff09; PHP 8.2 Maria DB (v10.11) Node J…

“AI智能服务平台系统,让生活更便捷、更智能

大家好&#xff0c;我是资深产品经理老王&#xff0c;今天咱们来聊聊一个让生活变得越来越方便的高科技产品——AI智能服务平台系统。这个系统可是现代服务业的一颗璀璨明珠&#xff0c;它究竟有哪些魅力呢&#xff1f;下面我就跟大家伙儿闲聊一下。 一、什么是AI智能服务平台系…

Qt监控系统远程网络登录/请求设备列表/服务器查看实时流/回放视频/验证码请求

一、前言说明 这几个功能是近期定制的功能&#xff0c;也非常具有代表性&#xff0c;核心就是之前登录和设备信息都是在本地&#xff0c;存放在数据库中&#xff0c;数据库可以是本地或者远程的&#xff0c;现在需要改成通过网络API请求的方式&#xff0c;现在很多的服务器很强…

【网络协议】动态路由协议

前言 本文将概述动态路由协议&#xff0c;定义其概念&#xff0c;并了解其与静态路由的区别。同时将讨论动态路由协议相较于静态路由的优势&#xff0c;学习动态路由协议的不同类别以及无类别&#xff08;classless&#xff09;和有类别&#xff08;classful&#xff09;的特性…

安装完docker后,如何拉取ubuntu镜像并创建容器?

1. 先docker拉取ubuntu镜像 docker search ubuntu #搜索ubuntu 镜像 docker pull ubuntu:22.04 #拉取ubuntu 镜像 docker images #下载完成后&#xff0c;查看已经下载的镜像 docker run --name ubuntu_container -dit ubuntu:22.04 /bin/bash # docker container -l 2.…

互联网全景消息(10)之Kafka深度剖析(中)

一、深入应用 1.1 SpringBoot集成Kafka 引入对应的依赖。 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupI…

React Fiber框架中的Render渲染阶段——workLoop(performUnitOfWork【beginWork与completeWork】)

触发渲染过程——renderRoot renderRoot 是一个函数&#xff0c;用于触发渲染工作。它通常会调用并递归地执行一系列的渲染任务&#xff0c;直到完成整个更新过程。这个过程包括执行 Fiber 树中的 beginWork 和 completeWork&#xff0c;以及渲染新状态或 DOM。 function ren…

STM32F1学习——ADC模数转换器

一、ADC模数转换器 ADC的全称 Analog-Digital Converter 模拟-数字转换器&#xff0c;他可以用来将引脚上连续变换的模拟电压转换为内存中存储的数字变量。 ADC有两个重要指标&#xff0c;分辨率和频率。 STM32的ADC是 12位 逐次逼近型&#xff0c;1us转换时间&#xff0c;也就…

[每周一更]-(第131期):Go并发协程总结篇

Go语言的并发是通过协程&#xff08;goroutine&#xff09;实现的。Go协程是轻量级的线程&#xff0c;允许多个任务同时执行&#xff0c;且Go运行时会高效地管理它们。在Go中使用并发协程的方式非常简便&#xff0c;也很强大。以下是一些关于Go协程的基础用法和并发控制方法&am…

Ecdsa密钥在线生成工具

具体前往&#xff1a;ECC公钥私钥对在线生成器

llama.cpp 模型可视化工具 GGUF Visualizer

llama.cpp 模型可视化工具 GGUF Visualizer 1. GGUF Visualizer for VS Code (gguf-viz)1.1. Features1.2. Extension Settings References GGUF Visualizer https://marketplace.visualstudio.com/items?itemNameAgainstEntropy.gguf-viz 1. GGUF Visualizer for VS Code (g…

【DAPM杂谈之三】DAPM的初始化流程

本文主要分析DAPM的设计与实现 内核的版本是&#xff1a;linux-5.15.164&#xff0c;下载链接&#xff1a;Linux内核下载 主要讲解有关于DAPM相关的知识&#xff0c;会给出一些例程并分析内核如何去实现的 /**************************************************************…