计算没有帮手的平均投资价格 columns/tables
Calculate average invested price without helper columns/tables
这篇post确实值得一读。此主题的另一个更好版本可用 。
如果您查看下面的 table,我会尝试在不添加辅助列的情况下查找每笔交易的平均价格。当 Buy 一侧的平均价格是正确的,但在 Sell 一侧显示不正确的平均价格,我正在寻找一个公式,数组公式或平均价格列的 UDF。
日期
侧面
数量
价格
价值
持有
平均价格
7 月 1 日
购买
225
10000
2250000
225
10000
7 月 2 日
购买
75
10200
765000
300
10050
7 月 3 日
卖出
-150
9950
-1492500
150
10150
Value 的公式是 =E3*D3
,Holding 的公式是 =SUM($D:D3)
,Avg price 是 =SUMPRODUCT($D:D3,$E:E3)/SUM($D:$D3)
我往下拉了。除了最后一个值 10150 之外,一切似乎都是正确的。理想情况下,根据下面给出的 FIFO 逻辑,它应该有 10,100。
第一个订单:数量 = 225 |价格 = 卢比10,000.00
二阶:数量 = 75 |价格 = 卢比10,200.00
要计算平均价格,首先计算值(数量 x 价格)。因此:
第一笔交易:卢比。 22,50,000.00
第二笔交易:卢比。 7,65,000.00
总数量 = 300
前两个订单的总价值:Rs。 30,15,000.00
总价值除以总数量:
卢比。 30,15,000.00 ÷ 300 = Rs.10,050.00(是否使用 =sumproduct
公式)
7 月 3 日,我们下了 150 个卖单(共 300 个)。价格:卢比。 9,950.00
这里将采用FIFO(先进先出)的方法。该方法将检查第一笔交易(在买方)。在本例中为225。150卖出的股票将从225(首次持有)中扣除。最初持有的余额为 225,现在为 225 - 150 = 75
经过FIFO后,table扣除卖出数量后就变成这样了。看到第一个 Qty 从 225 变成了 75 因为 150 只股票被卖出了。
日期
侧面
数量
价格
价值
持有
平均价格
7 月 1 日
购买
75
10000
750000
75
10000
7 月 2 日
购买
75
10200
765000
150
10100
请注意: 如果卖出数量大于225,则进入下一笔交易扣除剩余数量。
现在要解决此问题,需要额外的帮助列或帮助 table,我希望根除并找到公式或数组公式或 UDF 来计算平均价格。我请求 excel 专家帮助我解决这个问题。
下面给出了我正在尝试的另一个示例,其中投资价格显示不正确:
日期
侧面
数量
价格
价值
持有
平均价格
7 月 1 日
购买
5
10
50
5
10
7 月 2 日
卖出
-3
17
-51
2
-0.5
7 月 3 日
购买
17
3
51
19
2.63
7 月 4 日
卖出
-15
7.8
-117
4
-16.75
编辑
从@Tom Sharpe 得到解决方案后完成
为了获得平均价格,我将两个变量 avgRate 和 sumRate 声明为 double 并稍微修改了 For Each
代码。如果有有效的方法,请提出建议。如果可以将其转换为 UDF,我将不胜感激,这样我就不必一次又一次地 运行 代码。非常感谢您的精彩解决方案。
For Each bs In queue
Debug.Print ("qty=" & bs.qty)
Debug.Print ("rate=" & bs.rate)
avgRate = avgRate + (bs.qty * bs.rate)
sumRate = sumRate + bs.qty
Debug.Print avgRate / sumRate
Next
好的,这是 VBA 实现的测试版本。
算法:
If 'buy' transaction, just add to the queue.
If 'sell' transaction (negative quantity)
Repeat
Take as much as possible from earliest transaction
If more is required, look at next transaction
until sell amount reduced to zero.
该程序使用 class BuySell,因此您需要创建一个 class 模块,将其重命名为 BuySell 并包含行
Public rate As Double
Public qty As Double
下面是普通模块。
Option Explicit
Sub FifoTrading()
' Create the queue
Dim queue As Object
Set queue = CreateObject("System.Collections.Queue") 'Create the Queue
' Declare some variables
Dim bs As Object
Dim qty As Double
Dim rate As Double
Dim qtySold As Double
Dim qtyBought As Double
Dim qtyRemaining As Double
Dim rateBought As Double
Dim i As Long
For i = 2 To 5
Debug.Print (Cells(i, 3).Value())
Debug.Print (Cells(i, 4).Value())
rate = Cells(i, 4).Value()
qty = Cells(i, 3).Value()
If qty > 0 Then
'Buy
Set bs = New BuySell
bs.rate = rate
bs.qty = qty
queue.Enqueue bs
Else
'Sell
qtyRemaining = -qty
'Work through the 'buy' transactions in the queue starting at the oldest.
While qtyRemaining > 0
If qtyRemaining < queue.peek().qty Then
'More than enough stocks in this 'buy' to cover the sale so just work out what's left
queue.peek().qty = queue.peek().qty - qtyRemaining
qtyRemaining = 0
ElseIf qtyRemaining = queue.peek().qty Then
'Exactly enough stocks in this 'buy' to cover the sale so remove from queue
Set bs = queue.dequeue()
qtyRemaining = 0
Else
'Not enough stocks in this 'buy' to cover the sale so remove from queue and reduce amount of sale remaining
Set bs = queue.dequeue()
qtyRemaining = qtyRemaining - bs.qty
End If
Wend
End If
Next i
For Each bs In queue
Debug.Print ("qty=" & bs.qty)
Debug.Print ("rate=" & bs.rate)
Next
avRate = 0
totQty = 0
For Each bs In queue
avRate = avRate + bs.qty * bs.rate
totQty = totQty + bs.qty
Next
avRate = avRate / totQty
Debug.Print ("average=" & avRate)
End Sub
对于第一个table,输出是
所以平均汇率是 10100。
对于第二个table,输出是
所以平均比率是 3。
编辑
这里是 UDF 版本,称为
=avRate(qtyRange,rateRange)
Function avgRate(qtyRange As Range, rateRange As Range)
' Create the queue
Dim queue As Object
Set queue = CreateObject("System.Collections.Queue") 'Create the Queue
' Declare some variables
Dim bs As Object
Dim qty As Double
Dim rate As Double
Dim qtySold As Double
Dim qtyBought As Double
Dim qtyRemaining As Double
Dim rateBought As Double
Dim i As Long
Dim sumRate As Double, totQty As Double
For i = 1 To qtyRange.Cells().Count
qty = qtyRange.Cells(i).Value()
rate = rateRange.Cells(i).Value()
If qty > 0 Then
'Buy
Set bs = New BuySell
bs.rate = rate
bs.qty = qty
queue.Enqueue bs
Else
'Sell
qtyRemaining = -qty
'Work through the 'buy' transactions in the queue starting at the oldest.
While qtyRemaining > 0
If qtyRemaining < queue.peek().qty Then
'More than enough stocks in this 'buy' to cover the sale so just work out what's left
queue.peek().qty = queue.peek().qty - qtyRemaining
qtyRemaining = 0
ElseIf qtyRemaining = queue.peek().qty Then
'Exactly enough stocks in this 'buy' to cover the sale so remove from queue
Set bs = queue.dequeue()
qtyRemaining = 0
Else
'Not enough stocks in this 'buy' to cover the sale so remove from queue and reduce amount of sale remaining
Set bs = queue.dequeue()
qtyRemaining = qtyRemaining - bs.qty
End If
Wend
End If
Next i
'Calculate average rate over remaining stocks
sumRate = 0
totQty = 0
For Each bs In queue
sumRate = sumRate + bs.qty * bs.rate
totQty = totQty + bs.qty
Next
avgRate = sumRate / totQty
End Function
这篇post确实值得一读。此主题的另一个更好版本可用
如果您查看下面的 table,我会尝试在不添加辅助列的情况下查找每笔交易的平均价格。当 Buy 一侧的平均价格是正确的,但在 Sell 一侧显示不正确的平均价格,我正在寻找一个公式,数组公式或平均价格列的 UDF。
日期 | 侧面 | 数量 | 价格 | 价值 | 持有 | 平均价格 |
---|---|---|---|---|---|---|
7 月 1 日 | 购买 | 225 | 10000 | 2250000 | 225 | 10000 |
7 月 2 日 | 购买 | 75 | 10200 | 765000 | 300 | 10050 |
7 月 3 日 | 卖出 | -150 | 9950 | -1492500 | 150 | 10150 |
Value 的公式是 =E3*D3
,Holding 的公式是 =SUM($D:D3)
,Avg price 是 =SUMPRODUCT($D:D3,$E:E3)/SUM($D:$D3)
我往下拉了。除了最后一个值 10150 之外,一切似乎都是正确的。理想情况下,根据下面给出的 FIFO 逻辑,它应该有 10,100。
第一个订单:数量 = 225 |价格 = 卢比10,000.00
二阶:数量 = 75 |价格 = 卢比10,200.00
要计算平均价格,首先计算值(数量 x 价格)。因此:
第一笔交易:卢比。 22,50,000.00
第二笔交易:卢比。 7,65,000.00
总数量 = 300
前两个订单的总价值:Rs。 30,15,000.00
总价值除以总数量:
卢比。 30,15,000.00 ÷ 300 = Rs.10,050.00(是否使用 =sumproduct
公式)
7 月 3 日,我们下了 150 个卖单(共 300 个)。价格:卢比。 9,950.00
这里将采用FIFO(先进先出)的方法。该方法将检查第一笔交易(在买方)。在本例中为225。150卖出的股票将从225(首次持有)中扣除。最初持有的余额为 225,现在为 225 - 150 = 75
经过FIFO后,table扣除卖出数量后就变成这样了。看到第一个 Qty 从 225 变成了 75 因为 150 只股票被卖出了。
日期 | 侧面 | 数量 | 价格 | 价值 | 持有 | 平均价格 |
---|---|---|---|---|---|---|
7 月 1 日 | 购买 | 75 | 10000 | 750000 | 75 | 10000 |
7 月 2 日 | 购买 | 75 | 10200 | 765000 | 150 | 10100 |
请注意: 如果卖出数量大于225,则进入下一笔交易扣除剩余数量。
现在要解决此问题,需要额外的帮助列或帮助 table,我希望根除并找到公式或数组公式或 UDF 来计算平均价格。我请求 excel 专家帮助我解决这个问题。
下面给出了我正在尝试的另一个示例,其中投资价格显示不正确:
日期 | 侧面 | 数量 | 价格 | 价值 | 持有 | 平均价格 |
---|---|---|---|---|---|---|
7 月 1 日 | 购买 | 5 | 10 | 50 | 5 | 10 |
7 月 2 日 | 卖出 | -3 | 17 | -51 | 2 | -0.5 |
7 月 3 日 | 购买 | 17 | 3 | 51 | 19 | 2.63 |
7 月 4 日 | 卖出 | -15 | 7.8 | -117 | 4 | -16.75 |
编辑
从@Tom Sharpe 得到解决方案后完成
为了获得平均价格,我将两个变量 avgRate 和 sumRate 声明为 double 并稍微修改了 For Each
代码。如果有有效的方法,请提出建议。如果可以将其转换为 UDF,我将不胜感激,这样我就不必一次又一次地 运行 代码。非常感谢您的精彩解决方案。
For Each bs In queue
Debug.Print ("qty=" & bs.qty)
Debug.Print ("rate=" & bs.rate)
avgRate = avgRate + (bs.qty * bs.rate)
sumRate = sumRate + bs.qty
Debug.Print avgRate / sumRate
Next
好的,这是 VBA 实现的测试版本。
算法:
If 'buy' transaction, just add to the queue.
If 'sell' transaction (negative quantity)
Repeat
Take as much as possible from earliest transaction
If more is required, look at next transaction
until sell amount reduced to zero.
该程序使用 class BuySell,因此您需要创建一个 class 模块,将其重命名为 BuySell 并包含行
Public rate As Double
Public qty As Double
下面是普通模块。
Option Explicit
Sub FifoTrading()
' Create the queue
Dim queue As Object
Set queue = CreateObject("System.Collections.Queue") 'Create the Queue
' Declare some variables
Dim bs As Object
Dim qty As Double
Dim rate As Double
Dim qtySold As Double
Dim qtyBought As Double
Dim qtyRemaining As Double
Dim rateBought As Double
Dim i As Long
For i = 2 To 5
Debug.Print (Cells(i, 3).Value())
Debug.Print (Cells(i, 4).Value())
rate = Cells(i, 4).Value()
qty = Cells(i, 3).Value()
If qty > 0 Then
'Buy
Set bs = New BuySell
bs.rate = rate
bs.qty = qty
queue.Enqueue bs
Else
'Sell
qtyRemaining = -qty
'Work through the 'buy' transactions in the queue starting at the oldest.
While qtyRemaining > 0
If qtyRemaining < queue.peek().qty Then
'More than enough stocks in this 'buy' to cover the sale so just work out what's left
queue.peek().qty = queue.peek().qty - qtyRemaining
qtyRemaining = 0
ElseIf qtyRemaining = queue.peek().qty Then
'Exactly enough stocks in this 'buy' to cover the sale so remove from queue
Set bs = queue.dequeue()
qtyRemaining = 0
Else
'Not enough stocks in this 'buy' to cover the sale so remove from queue and reduce amount of sale remaining
Set bs = queue.dequeue()
qtyRemaining = qtyRemaining - bs.qty
End If
Wend
End If
Next i
For Each bs In queue
Debug.Print ("qty=" & bs.qty)
Debug.Print ("rate=" & bs.rate)
Next
avRate = 0
totQty = 0
For Each bs In queue
avRate = avRate + bs.qty * bs.rate
totQty = totQty + bs.qty
Next
avRate = avRate / totQty
Debug.Print ("average=" & avRate)
End Sub
对于第一个table,输出是
所以平均汇率是 10100。
对于第二个table,输出是
所以平均比率是 3。
编辑
这里是 UDF 版本,称为
=avRate(qtyRange,rateRange)
Function avgRate(qtyRange As Range, rateRange As Range)
' Create the queue
Dim queue As Object
Set queue = CreateObject("System.Collections.Queue") 'Create the Queue
' Declare some variables
Dim bs As Object
Dim qty As Double
Dim rate As Double
Dim qtySold As Double
Dim qtyBought As Double
Dim qtyRemaining As Double
Dim rateBought As Double
Dim i As Long
Dim sumRate As Double, totQty As Double
For i = 1 To qtyRange.Cells().Count
qty = qtyRange.Cells(i).Value()
rate = rateRange.Cells(i).Value()
If qty > 0 Then
'Buy
Set bs = New BuySell
bs.rate = rate
bs.qty = qty
queue.Enqueue bs
Else
'Sell
qtyRemaining = -qty
'Work through the 'buy' transactions in the queue starting at the oldest.
While qtyRemaining > 0
If qtyRemaining < queue.peek().qty Then
'More than enough stocks in this 'buy' to cover the sale so just work out what's left
queue.peek().qty = queue.peek().qty - qtyRemaining
qtyRemaining = 0
ElseIf qtyRemaining = queue.peek().qty Then
'Exactly enough stocks in this 'buy' to cover the sale so remove from queue
Set bs = queue.dequeue()
qtyRemaining = 0
Else
'Not enough stocks in this 'buy' to cover the sale so remove from queue and reduce amount of sale remaining
Set bs = queue.dequeue()
qtyRemaining = qtyRemaining - bs.qty
End If
Wend
End If
Next i
'Calculate average rate over remaining stocks
sumRate = 0
totQty = 0
For Each bs In queue
sumRate = sumRate + bs.qty * bs.rate
totQty = totQty + bs.qty
Next
avgRate = sumRate / totQty
End Function