文件下载地址:https://pan38.com/xiazai/index.php?id=16 提取码:da81
哈喽各位股东们!今天给大家带来一个超级实用的Java小项目——股票持仓生成器App!适合想学Java、想装X、想假装自己是大佬的各位(包括我本人)!
一、效果展示:先看成果再讲原理
先看看我们的成品长啥样:


🔍 持仓明细:
贵州茅台 (600519)
持仓: 100 股 | 成本价: 1,568.23 元
现价: 1,725.05 元 | 市值: 172,505.00 元
盈亏: +15,682.00 元 (+10.00%)宁德时代 (300750)
持仓: 200 股 | 成本价: 412.56 元
现价: 453.82 元 | 市值: 90,764.00 元
盈亏: +8,252.00 元 (+10.00%)
......(后面还有8只股票)
二、核心代码实现(完整可运行)
股票实体类(Stock.java)
java
/**- 股票实体类
三连的股东今晚持仓全红!
*/
public class Stock {
private String code; // 股票代码
private String name; // 股票名称
private int quantity; // 持仓数量
private double costPrice; // 成本价
private double currentPrice; // 当前价
private double marketValue; // 市值
private double profit; // 盈亏金额
private double profitRate; // 盈亏比例// 构造方法
public Stock(String code, String name, int quantity,double costPrice, double currentPrice) {this.code = code;
this.name = name;
this.quantity = quantity;
this.costPrice = costPrice;
this.currentPrice = currentPrice;
calculateMetrics();
}// 计算相关指标
private void calculateMetrics() {
this.marketValue = this.currentPrice this.quantity;
this.profit = (this.currentPrice - this.costPrice) this.quantity;
this.profitRate = (this.currentPrice / this.costPrice - 1) * 100;
}// 更新价格
public void updatePrice(double newPrice) {
this.currentPrice = newPrice;
calculateMetrics();
}// Getter方法
public String getCode() { return code; }
public String getName() { return name; }
public int getQuantity() { return quantity; }
public double getCostPrice() { return costPrice; }
public double getCurrentPrice() { return currentPrice; }
public double getMarketValue() { return marketValue; }
public double getProfit() { return profit; }
public double getProfitRate() { return profitRate; }@Override
public String toString() {
return String.format("%s (%s) | 持仓: %d股 | 成本: %.2f | 现价: %.2f | 市值: %.2f | 盈亏: %.2f (%.2f%%)",name, code, quantity, costPrice, currentPrice, marketValue, profit, profitRate);}
}
- 持仓组合类(Portfolio.java)
java
import java.util.*;
import java.text.DecimalFormat;
/**
- 股票持仓组合
一键生成,装X必备!
*/
public class Portfolio {
private List stocks;
private double totalAsset; // 总资产
private double totalProfit; // 总盈亏
private double totalProfitRate; // 总盈亏比例
private double todayProfit; // 今日盈亏
private double todayProfitRate; // 今日盈亏比例// 常用A股股票池
private static final String[][] STOCK_POOL = {{"贵州茅台", "600519"}, {"宁德时代", "300750"}, {"招商银行", "600036"}, {"中国平安", "601318"}, {"五粮液", "000858"}, {"隆基绿能", "601012"}, {"比亚迪", "002594"}, {"中信证券", "600030"}, {"药明康德", "603259"}, {"东方财富", "300059"}, {"美的集团", "000333"}, {"恒瑞医药", "600276"}, {"海天味业", "603288"}, {"伊利股份", "600887"}};
public Portfolio() {
this.stocks = new ArrayList<>(); generateRandomPortfolio(); calculateTotal();}
/**
- 生成随机持仓
随机选5-10只股票,随机仓位
*/
private void generateRandomPortfolio() {
Random random = new Random();
int stockCount = 5 + random.nextInt(6); // 5-10只股票// 打乱股票池顺序
List stockList = new ArrayList<>(Arrays.asList(STOCK_POOL));
Collections.shuffle(stockList);for (int i = 0; i < Math.min(stockCount, stockList.size()); i++) {
String[] stockInfo = stockList.get(i); String name = stockInfo[0]; String code = stockInfo[1]; // 随机生成持仓数据 int quantity = 100 * (1 + random.nextInt(20)); // 100-2000股 double basePrice = 50 + random.nextDouble() * 2000; // 50-2050元 double costPrice = basePrice * (0.8 + random.nextDouble() * 0.4); // 成本价波动 double currentPrice = costPrice * (0.9 + random.nextDouble() * 0.2); // 当前价波动 Stock stock = new Stock(code, name, quantity, costPrice, currentPrice); stocks.add(stock);}
}/**
计算总资产和总盈亏
*/
private void calculateTotal() {
double totalCost = 0;
double totalMarketValue = 0;for (Stock stock : stocks) {
totalCost += stock.getCostPrice() * stock.getQuantity(); totalMarketValue += stock.getMarketValue();}
this.totalAsset = totalMarketValue;
this.totalProfit = totalMarketValue - totalCost;
this.totalProfitRate = totalCost > 0 ? (totalProfit / totalCost * 100) : 0;// 模拟今日盈亏(总盈亏的10%左右)
Random random = new Random();
this.todayProfit = totalProfit (0.08 + random.nextDouble() 0.04);
this.todayProfitRate = totalAsset > 0 ? (todayProfit / totalAsset * 100) : 0;
}/**
模拟市场波动(随机涨跌)
*/
public void simulateMarketMovement() {
Random random = new Random();
for (Stock stock : stocks) {double current = stock.getCurrentPrice(); // 随机涨跌 -2% 到 +2% double changePercent = -2 + random.nextDouble() * 4; double newPrice = current * (1 + changePercent / 100); stock.updatePrice(newPrice);}
calculateTotal();
}/**
格式化数字(千分位)
*/
private String formatNumber(double number) {
DecimalFormat df = new DecimalFormat("#,##0.00");
return df.format(number);
}/**
获取持仓总览
*/
public String getPortfolioOverview() {
StringBuilder sb = new StringBuilder();
sb.append("📈 我的股票持仓 (模拟数据)\n");
sb.append("--------------------------------\n");
sb.append("📊 持仓总览:\n");
sb.append("总资产: ").append(formatNumber(totalAsset)).append(" 元\n");// 盈亏用不同颜色表示
String profitSign = totalProfit >= 0 ? "+" : "";
String profitColor = totalProfit >= 0 ? "🟢" : "🔴";
sb.append("总盈亏: ").append(profitColor).append(" ")
.append(profitSign).append(formatNumber(totalProfit)).append(" 元 (")
.append(String.format("%.2f", totalProfitRate)).append("%)\n");String todaySign = todayProfit >= 0 ? "+" : "";
String todayColor = todayProfit >= 0 ? "🟢" : "🔴";
sb.append("今日盈亏: ").append(todayColor).append(" ")
.append(todaySign).append(formatNumber(todayProfit)).append(" 元 (")
.append(String.format("%.2f", todayProfitRate)).append("%)\n");return sb.toString();
}/**
获取持仓明细
*/
public String getHoldingsDetail() {
StringBuilder sb = new StringBuilder();
sb.append("\n🔍 持仓明细:\n");for (int i = 0; i < stocks.size(); i++) {
Stock stock = stocks.get(i); sb.append(i + 1).append(". ").append(stock.getName()) .append(" (").append(stock.getCode()).append(")\n"); sb.append(" 持仓: ").append(stock.getQuantity()) .append(" 股 | 成本价: ").append(formatNumber(stock.getCostPrice())).append(" 元\n"); sb.append(" 现价: ").append(formatNumber(stock.getCurrentPrice())) .append(" 元 | 市值: ").append(formatNumber(stock.getMarketValue())).append(" 元\n"); String sign = stock.getProfit() >= 0 ? "+" : ""; String emoji = stock.getProfit() >= 0 ? "📈" : "📉"; sb.append(" 盈亏: ").append(emoji).append(" ").append(sign) .append(formatNumber(stock.getProfit())).append(" 元 (") .append(String.format("%.2f", stock.getProfitRate())).append("%)\n\n");}
return sb.toString();
}/**
获取完整持仓报告
*/
public String getFullReport() {
return getPortfolioOverview() + getHoldingsDetail();
}// Getter方法
public List getStocks() { return stocks; }
public double getTotalAsset() { return totalAsset; }
public double getTotalProfit() { return totalProfit; }
public double getTotalProfitRate() { return totalProfitRate; }
public double getTodayProfit() { return todayProfit; }
public double getTodayProfitRate() { return todayProfitRate; }
}- 主程序和控制台UI(StockApp.java)
java
import java.util.Scanner;
- 主程序和控制台UI(StockApp.java)
/**
- 股票持仓生成器主程序
按任意键刷新,Q退出
*/
public class StockApp {public static void main(String[] args) {
System.out.println("🎉 欢迎使用股票持仓生成器!"); System.out.println("📱 自动生成逼真的股票持仓数据"); System.out.println("🔄 按 Enter 键刷新持仓,输入 Q 退出\n"); Portfolio portfolio = new Portfolio(); Scanner scanner = new Scanner(System.in); while (true) { // 清屏(跨平台) clearScreen(); // 显示当前持仓 System.out.println(portfolio.getFullReport()); // 显示操作提示 System.out.println("═══════════════════════════════════════"); System.out.println("📋 操作指南:"); System.out.println(" 1. 按 Enter 键 - 刷新持仓(模拟市场波动)"); System.out.println(" 2. 输入 N 键 - 生成全新持仓组合"); System.out.println(" 3. 输入 Q 键 - 退出程序"); System.out.println("═══════════════════════════════════════"); System.out.print("请输入操作指令: "); String input = scanner.nextLine().trim().toUpperCase(); if (input.equals("Q")) { System.out.println("\n💼 感谢使用!祝您投资顺利,持仓全红!"); break; } else if (input.equals("N")) { portfolio = new Portfolio(); System.out.println("🔄 已生成新的持仓组合!"); pause(1000); } else { // 模拟市场波动 portfolio.simulateMarketMovement(); System.out.println("📊 持仓已更新(模拟市场波动)"); pause(800); } } scanner.close();}
/**
清屏方法(跨平台)
*/
private static void clearScreen() {
try {final String os = System.getProperty("os.name"); if (os.contains("Windows")) { new ProcessBuilder("cmd", "/c", "cls").inheritIO().start().waitFor(); } else { System.out.print("\033[H\033[2J"); System.out.flush(); }} catch (Exception e) {
// 如果清屏失败,至少打印一些空行 for (int i = 0; i < 50; i++) { System.out.println(); }}
}/**
- 暂停一段时间
*/
private static void pause(int milliseconds) {
try {
} catch (InterruptedException e) {Thread.sleep(milliseconds);
}Thread.currentThread().interrupt();
}
}- 图形界面版本(可选-Swing版)
java
import javax.swing.;
import java.awt.;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
- 图形界面版本(可选-Swing版)
/**
- 图形界面版本(Swing)
适合想要GUI的同学
*/
public class StockAppGUI extends JFrame {
private Portfolio portfolio;
private JTextArea displayArea;
private JLabel statusLabel;public StockAppGUI() {
super("📈 股票持仓生成器"); portfolio = new Portfolio(); initUI();}
private void initUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(800, 600); setLocationRelativeTo(null); // 主面板 JPanel mainPanel = new JPanel(new BorderLayout()); // 显示区域 displayArea = new JTextArea(); displayArea.setFont(new Font("Microsoft YaHei", Font.PLAIN, 14)); displayArea.setEditable(false); displayArea.setLineWrap(true); displayArea.setWrapStyleWord(true); JScrollPane scrollPane = new JScrollPane(displayArea); mainPanel.add(scrollPane, BorderLayout.CENTER); // 按钮面板 JPanel buttonPanel = new JPanel(new FlowLayout()); JButton refreshBtn = new JButton("🔄 刷新持仓"); JButton newPortfolioBtn = new JButton("🆕 新持仓"); JButton exitBtn = new JButton("❌ 退出"); // 刷新按钮事件 refreshBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { portfolio.simulateMarketMovement(); updateDisplay(); statusLabel.setText("持仓已更新 - " + getCurrentTime()); } }); // 新持仓按钮事件 newPortfolioBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { portfolio = new Portfolio(); updateDisplay(); statusLabel.setText("已生成新持仓 - " + getCurrentTime()); } }); // 退出按钮事件 exitBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); buttonPanel.add(refreshBtn); buttonPanel.add(newPortfolioBtn); buttonPanel.add(exitBtn); // 状态栏 statusLabel = new JLabel("就绪 - " + getCurrentTime()); statusLabel.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10)); // 添加到主面板 mainPanel.add(buttonPanel, BorderLayout.NORTH); mainPanel.add(statusLabel, BorderLayout.SOUTH); // 初始显示 updateDisplay(); setContentPane(mainPanel);}
private void updateDisplay() {
displayArea.setText(portfolio.getFullReport());}
private String getCurrentTime() {
return new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date());}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() { @Override public void run() { StockAppGUI app = new StockAppGUI(); app.setVisible(true); } });}
}
三、项目亮点和学到什么
🎯 技术要点:
面向对象设计:Stock和Portfolio类的封装
集合框架:ArrayList的使用和随机打乱
格式化输出:DecimalFormat和String.format
随机数生成:模拟股票价格波动
Swing GUI(可选):图形界面编程基础
🚀 可扩展功能:
java
// 1. 添加数据持久化(保存到文件)
public void saveToFile(String filename) {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(filename))) {
oos.writeObject(this);
System.out.println("💾 持仓已保存到文件: " + filename);
} catch (IOException e) {
e.printStackTrace();
}
}
// 2. 添加网络功能(获取真实股价)
public void fetchRealStockPrice(String stockCode) {
// 可以使用第三方API,如新浪财经、腾讯财经等
// 这里只是一个示例
System.out.println("🌐 正在获取实时股价...");
}
// 3. 添加更多分析指标
public void addTechnicalIndicators() {
// 可以添加MACD、KDJ、RSI等技术指标
System.out.println("📊 技术分析指标已生成");
}
四、运行方法
方法1:命令行版本
bash
编译
javac Stock.java Portfolio.java StockApp.java
运行
java StockApp
方法2:图形界面版本
bash
编译
javac Stock.java Portfolio.java StockAppGUI.java
运行
java StockAppGUI
五、总结与资源
这个项目虽然简单,但涵盖了Java的核心知识点:
✅ 面向对象编程
✅ 集合框架
✅ 异常处理
✅ 文件IO(可扩展)
✅ GUI编程(可选)
完整代码已经上传到GitHub(评论区置顶链接),欢迎Star⭐!
最后求个三连!点赞过1000,下一期我们做:
📱 Android版股票持仓App
🌐 网页版可视化持仓
🤖 AI智能选股功能
评论区留下你想看的功能,点赞最多的我下一期就做!