创建一个函数,根据交易历史使用FIFO方法计算股票的已实现收益



我是新的谷歌应用程序脚本,并试图学习尽可能多的我可以,但我绊倒了一些东西,这是在我的头上.....

我的目标是创建一个函数,根据交易历史的输入数据,以会计风格"fifo"计算股票的已实现收益,"fifo"代表先进先出。

计算已实现收益的公式相对简单

(Total Sell price - Original Cost ) = Realized gains/loss 
Realized Gains/Loss / Original Cost = Profit/loss (%)

如果有人在三个不同的时间以三个不同的价格(x1,x2,x3)购买了一只股票,你希望计算"已实现收益"——你是取x1,x2还是x3的原始成本?FIFO风格将采取X1,因为它是"先进先出"。这一点很重要,因为在美国,有一种叫做资本利得税的东西是基于所有已实现收益的。

这是我的数据:https://docs.google.com/spreadsheets/d/1V7CpCxBH0lg6wi1TAhfZJP5gXE8hj7ivQ8_ULxLSLgs/edit?usp=sharing

const ss = SpreadsheetApp.getActiveSpreadsheet();
const historySheet = ss.getSheetByName('Blad1');
function fifoProject () {
let input = historySheet.getDataRange().getValues();
let onlyBuyRows = input.filter(row => row[2] == 'Buy');
let roundedTotal, priceQuantityMultiplication;
let onlyColABDF = onlyBuyRows.map(row => {
roundedTotal = Math.round(row[5] * 100) / 100;
priceQuantityMultiplication = row[3] * roundedTotal;
return [
row[0], row[1], row[3], roundedTotal, priceQuantityMultiplication
]});
let sorted = onlyColABDF.sort((a, b) => {
if (a[1] > b[1]) return 1;
if (a[1] < b[1]) return -1;
if (a[0] > b[0]) return 1;
if (a[0] < b[0]) return -1;
return 0;
});
let arrayBuyData = [];
arrayBuyData.push(sorted);
console.log(arrayBuyData);
//ss.getSheetByName('output').getRange(1, 1, sorted.length, sorted[0].length).setValues(sorted)
let input2 = historySheet.getRange(2, 1, historySheet.getLastRow() - 1, 4).getValues();
let onlySellRows = input2.filter(row => row[2] == 'Sell');
let sellTotalArray = []
let addAllSellObject = onlySellRows.reduce((acc, curr) => {
if (curr[1] in acc) {
acc[curr[1]] += curr[3]
} else {
acc[curr[1]] = curr[3]
}
return acc;
}, {});
let addAllSellArray = Object.entries(addAllSellObject).sort((a, b) => {
if (a[0] > b[0]) return 1;
if (a[0] < b[0]) return -1;
return 0;
})
sellTotalArray.push(addAllSellArray);
console.log(sellTotalArray[0][1]);
}

下面是我认为函数应该做的:

https://ibb.co/Pr0gC1S

任何方向正确的建议都非常欢迎。

编辑:试图澄清问题。希望这样做:

<style>
.demo {
border:1px solid #C0C0C0;
border-collapse:collapse;
padding:5px;
}
.demo th {
border:1px solid #C0C0C0;
padding:5px;
background:#F0F0F0;
}
.demo td {
border:1px solid #C0C0C0;
padding:5px;
}
</style>
<table class="demo">
<caption></caption> <thead> <tr>        <th>Date</th>
<th>Type</th>
<th>Amount p.p</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<tr>
<td>&nbsp;Jan</td>
<td>&nbsp;Buy</td>
<td>&nbsp;$10</td>
<td>&nbsp;5</td>
</tr>
<tr>
<td>&nbsp;Feb</td>
<td>&nbsp;Buy</td>
<td>&nbsp;$15</td>
<td>&nbsp;8</td>
</tr>
</tbody>
</table>

例如,如果7个数量以23美元的价格出售,结果将是:

<style>
.demo {
border:1px solid #C0C0C0;
border-collapse:collapse;
padding:5px;
}
.demo th {
border:1px solid #C0C0C0;
padding:5px;
background:#F0F0F0;
}
.demo td {
border:1px solid #C0C0C0;
padding:5px;
}
</style>
<table class="demo">
<caption></caption> <thead> <tr>        <th>Date</th>
<th>Amount</th>
<th>Buy price p.p</th>
<th>Profit p.p</th>
</tr>   </thead>    <tbody> <tr>
<td>&nbsp;Jan</td>
<td>&nbsp;5</td>
<td>&nbsp;$10</td>
<td>&nbsp;$13</td>
</tr>
<tr>
<td>&nbsp;Feb</td>
<td>&nbsp;2</td>
<td>&nbsp;$15</td>
<td>&nbsp;$8</td>
</tr>
</tbody>
</table>

总数:

<style>
.demo {
border:1px solid #C0C0C0;
border-collapse:collapse;
padding:5px;
}
.demo th {
border:1px solid #C0C0C0;
padding:5px;
background:#F0F0F0;
}
.demo td {
border:1px solid #C0C0C0;
padding:5px;
}
</style>
<table class="demo">
<caption></caption> <thead> <tr>        <th><br></th>
<th><br></th>
</tr>
</thead>
<tbody>
<tr>
<td>&nbsp;Total buy price</td>
<td>&nbsp;$80</td>
</tr>
<tr>
<td>&nbsp;Total sell price</td>
<td>&nbsp;$161</td>
</tr>
<tr>
<td>&nbsp;Total profit (or loss)</td>
<td>&nbsp;$81</td>
</tr>
<tbody>
</table>

EDIT 2:根据Jacques的回答,我创建了以下代码:

const ss = SpreadsheetApp.getActiveSpreadsheet();
const historySheet = ss.getSheetByName('Blad1');


// Function which pushes item x amount of times based on a number
function pushNumber (number, array, item) {
for(var i = 0; i<number; i++){
array.push(item);
}
}

function shiftNumber (number, array, item) {
for(var i = 0; i<number; i++){
array.shift(item);
}
}

function projectFIFO () {
let input = historySheet.getRange(3,1,historySheet.getLastRow()-1, 5).getValues();
for (var i = 0; i<security.length; i++) {
let action = row[2].toString();
let quantity = Number(row[3]);
let price = Number(row[4]);
let emptyArray = [];
// console.log(quantity);
for (security of array) 
if (action === 'Buy') {
let numberPush = quantity;
pushNumber(quantity, emptyArray, price);
};
console.log(emptyArray);
};
}

基本上,我已经创建了一个帮助函数pushnnumber,它根据Number的数量进行推送。然后在fifo函数中,我创建了一个for循环来遍历每一行,看看是否有购买,并根据数量push购买,push是在一个空数组中。然而,我想学习如何为每一种安全单独做到这一点,而不是整个范围。我想也许一个对象是一个解决方案,但还没有弄清楚。

在研究了您的代码和示例表之后,我看到您非常接近完成您的目标。您只需要编写一个与Transactions表交互的函数,就可以获得所需结果表的数据。

在第一个交互中,过滤Transaction表,只显示您想要的票据(正如您在示例脚本中所做的那样)。继续从上到下与表交互(您可以使用示例中所示的getRange()/getValues())。现在,对于每个Buy行,push()的价格与购买股票的次数相同。例如,如果你以313美元的价格买了3股,你应该推动313, 313, 313。对于每个Sell订单,您只需要shift()数组并计算返回值(买入价格)和卖出价格之间的差异。

使用这种方法,您将有效地开发一个FIFO逻辑来管理买入和卖出订单,因此它们之间的差异将是实现的利润。如果您对这种方法有疑问,请随时留下评论。


更新

您可以使用此方法从数组中删除重复项。如果你事先不知道证券的名称,这将是有用的。

var allTickers = ['AAPL', 'AAPL', 'GOOG', 'MSFT', '2222.SR', 'MSFT', 'AMZN',
'AAPL', '2222.SR', 'MSFT', 'AMZN', '2222.SR'
]
var uniqueTickers = [...new Set(allTickers)];

最新更新