使用Google Apps Script实现FIFO规则的股票已实现收益计算函数
Google Apps Script FIFO股票已实现收益计算实现
核心逻辑说明
按单只证券独立核算的需求可通过对象结构实现:
- 用
stockQueues对象存储每只股票的FIFO成本队列,键为股票代码,值为按买入顺序排列的每股成本数组 - 用
profitStats对象存储每只股票的收益统计数据,键为股票代码,值包含累计已实现收益、累计抵扣成本、收益率三个字段
完整可运行代码
const ss = SpreadsheetApp.getActiveSpreadsheet(); const historySheet = ss.getSheetByName('Blad1'); const outputSheet = ss.getSheetByName('output') || ss.insertSheet('output'); // 批量向数组推入指定数量的元素 function pushTimes(count, arr, item) { for (let i = 0; i < count; i++) { arr.push(item); } } // 批量从数组头部弹出指定数量的元素,返回弹出的元素数组 function shiftTimes(count, arr) { const result = []; for (let i = 0; i < count; i++) { if (arr.length === 0) break; // 避免卖空场景报错,可根据需求补充卖空逻辑 result.push(arr.shift()); } return result; } function calculateFIFOProfit() { // 读取交易数据:假设列顺序为 日期|股票代码|交易类型|数量|单价,从第3行开始读取(跳过表头) const rawData = historySheet.getRange(3, 1, historySheet.getLastRow() - 2, 5).getValues(); const stockQueues = {}; const profitStats = {}; // 按日期升序排序交易记录,保证交易顺序正确 const sortedTrades = rawData.sort((a, b) => new Date(a[0]) - new Date(b[0])); sortedTrades.forEach(row => { const ticker = row[1].toString().trim(); const action = row[2].toString().trim(); const quantity = Math.round(Number(row[3])); // 数量取整,避免零碎股问题 const price = Number(row[4]); // 初始化当前股票的队列和统计数据 if (!stockQueues[ticker]) stockQueues[ticker] = []; if (!profitStats[ticker]) profitStats[ticker] = { realized: 0, totalCost: 0, profitRate: 0 }; if (action === 'Buy') { // 买入:将对应数量的成本价推入队列 pushTimes(quantity, stockQueues[ticker], price); } else if (action === 'Sell') { // 卖出:从队列头部取出对应数量的成本 const costList = shiftTimes(quantity, stockQueues[ticker]); const currentCost = costList.reduce((sum, cost) => sum + cost, 0); const currentSellIncome = quantity * price; const currentProfit = currentSellIncome - currentCost; // 更新统计数据 profitStats[ticker].realized += currentProfit; profitStats[ticker].totalCost += currentCost; if (profitStats[ticker].totalCost > 0) { profitStats[ticker].profitRate = (profitStats[ticker].realized / profitStats[ticker].totalCost * 100).toFixed(2) + '%'; } } }); // 格式化输出数据到output表 const outputHeaders = ['股票代码', '累计已实现收益', '累计抵扣成本', '收益率']; const outputRows = [outputHeaders]; Object.entries(profitStats).forEach(([ticker, stats]) => { outputRows.push([ ticker, stats.realized.toFixed(2), stats.totalCost.toFixed(2), stats.profitRate ]); }); // 清空旧数据写入新结果 outputSheet.clearContents(); outputSheet.getRange(1, 1, outputRows.length, outputRows[0].length).setValues(outputRows); }
逻辑验证
以你给出的示例为例:
1月买入5股单价10美元,2月买入8股单价15美元,后续以23美元单价卖出7股
代码运行后对应股票的统计结果为:
- 累计抵扣成本:(510)+(215) = 80美元
- 累计已实现收益:7*23 - 80 = 81美元
- 收益率:81/80 = 101.25%
完全符合FIFO规则要求。
调整说明
如果你的表格列顺序与代码假设不一致,只需调整rawData读取时的列索引,以及row[x]的取值序号即可适配。
内容的提问来源于stack exchange,提问作者Pashtun
相关产品推荐
相关产品推荐

