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维护,存在字典追加的适配问题。
解决方案
直接基于列表结构按股票代码分组处理,避免字典适配问题,步骤如下:
- 按股票代码对持仓列表分组,保留原始FIFO顺序
- 遍历每笔卖出记录,匹配对应持仓分组,逐笔扣除持仓并计算成本与盈亏
- 同步更新持仓列表,输出每笔卖出的计算结果
代码实现
# 原始持仓列表 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
相关产品推荐
相关产品推荐

