You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现按股票代码从持仓列表扣除卖出列表(FIFO成本法)

基于FIFO成本法计算股票卖出盈亏及持仓扣除

问题背景

现有股票持仓与卖出数据:

  • 持仓列表:
    ['AAPL', 5, 80], ['AAPL', 10, 85], ['CELH', 12, 85], ['CELH', 13, 75], ['BABA', 13, 50]
  • 卖出列表:
    ['CELH', -3, 97], ['AAPL', -8, 100], ['BABA', -8, 60], ['BABA', -3, 40]

需采用**FIFO(先进先出)**成本法,计算每笔卖出的成本基准、总盈亏,同时从持仓列表中扣除对应卖出数量,输出格式要求:
[TICKER, 卖出数量, 卖出价格, 持仓成本明细, 总盈亏]

示例预期输出:

['CELH', 3, 97, 85, 36]
['AAPL', 8, 100, '5*80, 3*85', 145]
['BABA', 8, 60, 50, 80]
['BABA', 3, 40, 50, -30]

此前尝试zip()处理无法按股票代码匹配扣除;尝试转为字典,但因数据需存入sqlite3且通过Tkinter维护,存在字典追加的适配问题。

解决方案

直接基于列表结构按股票代码分组处理,避免字典适配问题,步骤如下:

  1. 按股票代码对持仓列表分组,保留原始FIFO顺序
  2. 遍历每笔卖出记录,匹配对应持仓分组,逐笔扣除持仓并计算成本与盈亏
  3. 同步更新持仓列表,输出每笔卖出的计算结果

代码实现

# 原始持仓列表
holdings = [
    ['AAPL', 5, 80],
    ['AAPL', 10, 85],
    ['CELH', 12, 85],
    ['CELH', 13, 75],
    ['BABA', 13, 50]
]

# 原始卖出列表
sales = [
    ['CELH', -3, 97],
    ['AAPL', -8, 100],
    ['BABA', -8, 60],
    ['BABA', -3, 40]
]

# 按股票代码分组持仓,保留原始顺序
holdings_by_ticker = {}
for pos in holdings:
    ticker = pos[0]
    if ticker not in holdings_by_ticker:
        holdings_by_ticker[ticker] = []
    holdings_by_ticker[ticker].append(pos)

# 处理每笔卖出并生成结果
results = []
for sale in sales:
    ticker, sell_qty_neg, sell_price = sale
    sell_qty = abs(sell_qty_neg)
    remaining_sell = sell_qty
    cost_details = []
    total_profit = 0

    positions = holdings_by_ticker.get(ticker, [])
    i = 0
    while remaining_sell > 0 and i < len(positions):
        pos_qty, pos_cost = positions[i][1], positions[i][2]
        if pos_qty <= remaining_sell:
            # 耗尽当前持仓
            used_qty = pos_qty
            total_profit += used_qty * (sell_price - pos_cost)
            cost_details.append(f"{used_qty}*{pos_cost}")
            remaining_sell -= used_qty
            positions.pop(i)
        else:
            # 部分卖出当前持仓
            used_qty = remaining_sell
            total_profit += used_qty * (sell_price - pos_cost)
            cost_details.append(f"{used_qty}*{pos_cost}")
            positions[i][1] -= used_qty
            remaining_sell = 0
            i += 1

    # 适配结果格式:单一成本显示价格,多成本显示明细
    cost_display = cost_details[0].split('*')[1] if len(cost_details) == 1 else ', '.join(cost_details)
    results.append([ticker, sell_qty, sell_price, cost_display, total_profit])

# 输出计算结果
print("卖出计算结果:")
for res in results:
    print(res)

# 更新后的持仓列表(可直接存入sqlite3或用于Tkinter展示)
updated_holdings = []
for ticker in holdings_by_ticker:
    updated_holdings.extend(holdings_by_ticker[ticker])
print("\n更新后的持仓列表:")
for pos in updated_holdings:
    print(pos)

代码说明

  • 用字典分组持仓但保留原列表引用,最终更新后的持仓可展开为二维列表,完全适配sqlite3和Tkinter的列表操作需求
  • 严格遵循FIFO顺序消耗最早持仓,确保成本计算准确
  • 结果格式匹配示例要求,兼顾单一/多成本来源的展示
  • 更新后的持仓保持原始结构,无需额外转换即可用于存储或界面展示

运行结果

卖出计算结果:
['CELH', 3, 97, '85', 36]
['AAPL', 8, 100, '5*80, 3*85', 145]
['BABA', 8, 60, '50', 80]
['BABA', 3, 40, '50', -30]

更新后的持仓列表:
['AAPL', 7, 85]
['CELH', 9, 85]
['CELH', 13, 75]
['BABA', 2, 50]

内容的提问来源于stack exchange,提问作者Kevindelange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 11:50:23