做一个 简单的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

  2. 创建并激活虚拟环境(可选但推荐):

    python -m venv venv

    Windows

    venv\Scripts\activate

    Linux/Mac

    source venv/bin/activate

  3. 安装依赖包:

    pip install django akshare pandas

  4. 初始化数据库:

    python manage.py migrate

  5. 启动开发服务器:

    python manage.py runserver

  6. 访问系统:
    打开浏览器,访问 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

python 复制代码
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

python 复制代码
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

python 复制代码
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

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

python 复制代码
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

python 复制代码
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['涨跌幅'])
    
  2. 批量更新价格:

    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. 数据不准确:
    • 确认是否在交易时间
    • 检查数据更新时间
    • 验证股票代码正确性

相关资源

更新记录

  • 2024-01-10: 首次创建文档
  • 使用 akshare 1.15.68 版本
  • 主要实现 A 股实时数据获取功能
相关推荐
疯狂小小小码农1 小时前
C++语言的文件操作
开发语言·后端·golang
莲动渔舟1 小时前
Python自学 - 类进阶(可调用对象)
开发语言·python
Reese_Cool1 小时前
【Python】Python与C的区别
java·c语言·python
ccmjga1 小时前
升级 Spring Boot 3 全项目讲解 — 给项目增加聊天对话功能
java·人工智能·spring boot·后端·spring·spring cloud·mybatis
游客5202 小时前
设计模式-结构型-组合模式
python·设计模式·组合模式
跨海之梦2 小时前
springboot 加载本地jar到maven
开发语言·python·pycharm
weixin_404679312 小时前
Xinference 常见bug: "detail": "Invalid input. Please specify the prompt."
开发语言·python·prompt·bug·pandas
BinaryBardC2 小时前
Objective-C语言的网络编程
开发语言·后端·golang
鹿屿二向箔2 小时前
一个基于Spring Boot的简单网吧管理系统
spring boot·后端·python
java熊猫2 小时前
Clojure语言的多线程编程
开发语言·后端·golang