首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从变量中减去值,直到该变量为0 Excel VBA

从变量中减去值,直到该变量为0 Excel VBA
EN

Stack Overflow用户
提问于 2018-04-05 01:58:45
回答 4查看 1.1K关注 0票数 0

我正在做的工作是基于先进先出( FIFO )会计原则自动处理我的一个账本,其中任何被称为冲销余额的东西都将从第一个条目中减去,然后从第二个条目中减去,直到该变量为零(或者如果有剩余,则开始一个新的会计行)。

一般来说,我一直在做的事情是在这个账本上添加一个新的职位(不删除任何余额,简单地创建一个行项目是这样的……

代码语言:javascript
运行
复制
Tickerstring = TTB 'TTB is the user defined input for the ticker

tickercolumn = HBWS.Cells.Find(What:="Ticker").Column 'Use this to identify 
what column the ticker field is

Set TickerResult = HBWS.Cells.Find(What:=TickerString, LookIn:=xlValues)
If Not TickerResult Is Nothing Then
tickerRow = TickerResult.Row
Else
End If 'Identifies the row which the actual Ticker is in i.e. the TTB

HBWS.Cells(tickerRow, tickercolumn) = TTB

我用同样的概念来定义股票的数量,以及它们是多头还是空头。将用户表单输入插入到相应的单元格中。

我的问题是,假设我运行该代码3次,现在有3行项目,如下所示

AAPL 300长

AAPL 100长

AAPL 100长

然后我想为600空头添加一个新的头寸,这将通过FIFO会计过程,从第一行中删除300,从第二行中删除100,从第三行中删除100,然后创建一个包含100空头的新行。我该怎么做呢?

我想象我将从用户定义的变量中减去,即从第一行中减去300,现在我的定义变量留在300 (当它从600开始时)。

基本上,我认为描述这一点的最好方法是如何根据当前工作簿的值从变量中减去,然后在子过程中继续使用它。

编辑:为清晰起见编辑我的帖子

我的电子表格中有以下条目

我想运行我的宏,采取我在下面的用户表单中指出的空头头寸,从我的电子表格中的当前位置减去它,然后创建一条表示空头头寸剩余部分的残差线

结束状态应如下所示

如果您需要更多信息,请告诉我

EN

回答 4

Stack Overflow用户

发布于 2018-04-06 00:55:00

要求:

先进先出库存维护股票交易的分类帐,由用户表单输入生成( time).

  • Calculate中的一个&使用先进先出库存估值方法显示股票的净头寸。

建议的解决方案:

这些要求可以通过以下方式实现:

  1. 包含事务处理分类帐的ListObject,用于计算每个PivotTable之后的终止位置,以显示股票的终止位置(以及所需的任何其他报表)。

下图显示了建议的ListObjectPivotTable

ListObject字段:

来自用户表单的输入

  • Ticker : Share symbol.
  • L/S : Share position (Long\Short).
  • Lots :股份数量。

由VBA过程计算

  • L/S.Net:净份额头寸(Long\Short).
  • Qty:净份额数量(绝对value).
  • Lots.Net:净份额quantity.
  • T:记录类型(P:之前\ R:残差),用于标记share.
  • TimeStamp:记录的最新事务处理过帐日期和时间,用于应用先进先出估值方法。

VBA过程:请参阅过程中插入的说明\注释。

代码语言:javascript
运行
复制
Option Private Module
Option Compare Text
Option Explicit
Option Base 1
Rem Updated 20180504_121918

Sub ListObject_Stocks_Ledger_FIFO(vRcrd As Variant)
Dim aFlds As Variant, vFld As Variant
aFlds = [{"Ticker","L/S","Lots","T","TimeStamp","Lots.Net","L/S.Net","Qty"}]
Dim lo As ListObject, pt As PivotTable
Dim sTicker As String, lCnt As Long, lPos As Long
Dim lRow As Long, bCol As Byte, b As Byte
Dim sFml As String
Dim vValue As Variant
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False

    Rem Set Objects
    With ThisWorkbook.Worksheets("Sht(0)")      'change as required
        Application.Goto .Cells(1), 1
        Set pt = .PivotTables("ptPositions")
        Set lo = .ListObjects("loPositions")
    End With

    With lo

        Rem Set ListObject New Row
        lRow = 1 + .ListRows.Count
        Select Case lRow
        Case 1
            Rem ListObject with zero records
            .HeaderRowRange.Cells(2, 1).Value2 = "!NEW"

        Case Else
            vFld = "Ticker"
            sTicker = vRcrd(1)
            bCol = .ListColumns(vFld).Index
            lCnt = WorksheetFunction.CountIfs(.DataBodyRange.Columns(bCol), sTicker)

            Rem Flag prior Ticker records
            Select Case lCnt
            Case 0
                Rem New Ticker - NO ACTION

            Case 1
                Rem Ticker with only one prior record
                lPos = WorksheetFunction.Match(sTicker, .DataBodyRange.Columns(bCol), 0)
                .ListColumns("T").DataBodyRange.Cells(lPos).Value2 = "P"

            Case Else
                Rem Ticker with only one prior record
                .Range.AutoFilter Field:=bCol, Criteria1:=sTicker
                .ListColumns("T").DataBodyRange.SpecialCells(xlCellTypeVisible).Value2 = "P"
                .Range.AutoFilter

        End Select: End Select

        Rem Add New Record
        For Each vFld In aFlds
            b = 1 + b
            bCol = .ListColumns(vFld).Index

            Rem Set Field Value\Formula
            sFml = vbNullString
            vValue = vbNullString
            Select Case vFld
            Case "Ticker", "L/S", "Lots":   vValue = vRcrd(b)
            Case "T":                       vValue = "R"
            Case "TimeStamp":               vValue = CDbl(Now)
            Case "L/S.Net"
                sFml = "=IF(NOT(EXACT([@T],'R')),CHAR(39)," & vbLf _
                    & "IF([@[Lots.Net]]<0,'Short',IF([@[Lots.Net]]>0,'Long','Zero')))"

            Case "Qty"
                sFml = "=IF(NOT(EXACT([@T],'R')),CHAR(39)," & vbLf _
                    & "ABS([@[Lots.Net]]))"

            Case "Lots.Net"
                sFml = "=IF(NOT(EXACT([@T],'R')),CHAR(39),SUM(" & vbLf _
                    & "SUMIFS([Lots],[Ticker],[@Ticker],[L/S],'Long',[TimeStamp],'<='&[@TimeStamp])," & vbLf _
                    & "-SUMIFS([Lots],[Ticker],[@Ticker],[L/S],'Short',[TimeStamp],'<='&[@TimeStamp])))"

            End Select

            Rem Apply Field Value\Formula
            Select Case vbNullString
            Case Is <> vValue
                .DataBodyRange.Cells(lRow, bCol).Value2 = vValue

            Case Is <> sFml
                sFml = Replace(sFml, Chr(39), Chr(34))
                With .DataBodyRange.Columns(bCol)
                    .Formula = sFml
                    .Value2 = .Value2

    End With: End Select: Next: End With

    Rem Sort ListObject
    With lo.Sort
        With .SortFields
            .Clear
            .Add Key:=lo.ListColumns("Ticker").DataBodyRange, _
                SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
            .Add Key:=lo.ListColumns("TimeStamp").DataBodyRange, _
                SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
        End With
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

    Rem Refresh PivotTable
    pt.PivotCache.Refresh

    Application.EnableEvents = False
    Application.Calculation = xlCalculationAutomatic
    Application.ScreenUpdating = False

    End Sub

使用以下过程可模拟用户表单中的过帐:

代码语言:javascript
运行
复制
Sub ListObject_Stocks_Ledger_FIFO_TEST()
Dim aDATA As Variant, vRcrd As Variant
aDATA = Array( _
    Array("AAPL", "Long", "300"), _
    Array("AAPL", "Long", "100"), _
    Array("AAPL", "Long", "100"), _
    Array("AAPL", "Short", "600"), _
    Array("BCS", "Long", "300"), _
    Array("BCS", "Long", "100"), _
    Array("BCS", "Short", "500"), _
    Array("Test", "Long", "100"), _
    Array("Test", "Long", "200"), _
    Array("Test", "Long", "300"), _
    Array("Test", "Short", "400"))

    For Each vRcrd In aDATA
        Call ListObject_Stocks_Ledger_FIFO(vRcrd)
: Stop
    Next

    End Sub
票数 1
EN

Stack Overflow用户

发布于 2018-04-05 02:28:18

这可能是你想要做的一个例子,希望对你有用:

代码语言:javascript
运行
复制
Sub test()

Dim reduce_amount As String
reduce_amount = Val(InputBox("Number:"))

Dim cell As Range

For Each cell In Selection

cell_value = Mid(cell.Value, 6, 3)

If IsNumeric(cell_value) Then
    reduce_amount = reduce_amount - cell_value
End If

Next cell

If reduce_amount > 0 Then
 Selection.End(xlDown).Offset(1, 0).Value = "AAPL " & reduce_amount & " Long"
End If

End Sub

票数 0
EN

Stack Overflow用户

发布于 2018-04-05 04:00:48

我认为你应该这样做,这样每个事务都是独立的(除非你有很好的理由这样做)。如果可能的话,我从不在单元格中存储"state“。跟踪每个存储桶怎么样?下面是一个例子

代码语言:javascript
运行
复制
Public Sub AddLots(ByVal Ticker As String, ByVal Lot As Double)

    Dim rCell As Range
    Dim LotRemains As Double
    Dim dc As Scripting.Dictionary
    Dim dToTake As Double
    Dim ThisTicker As String, ThisLS As String, ThisLot As Double, ThisBucket As Long, ThisTotal As Double
    Dim lo As ListObject
    Dim aOutput() As Variant
    Dim MaxBucket As Long
    Dim i As Long

    LotRemains = Lot
    Set dc = New Scripting.Dictionary
    Set lo = Sheet1.ListObjects(1)

    For Each rCell In lo.ListColumns(1).DataBodyRange.Cells
        'Store this row's values
        ThisTicker = rCell.Value: ThisLS = rCell.Offset(0, 1).Value: ThisLot = rCell.Offset(0, 2).Value
        ThisBucket = rCell.Offset(0, 3).Value: ThisTotal = rCell.Offset(0, 4).Value

        'if the ticker is the same
        If ThisTicker = Ticker Then
            'if it's going the opposite way of our transaction
            If (Lot > 0 And ThisLS = "Short") Or _
                (Lot < 0 And ThisLS = "Long") Then

                'if there's still something left in the bucket
                If ThisTotal <> 0 Then
                    If Abs(ThisTotal) >= Abs(LotRemains) Then
                        dToTake = LotRemains
                    Else
                        dToTake = -ThisTotal
                    End If
                    'store this bucket
                    dc.Add ThisTicker & "|" & ThisBucket, dToTake
                    'reduce the amount left to test
                    LotRemains = LotRemains - dToTake
                    'stop looking if we've used it all up
                    If LotRemains = 0 Then Exit For
                End If
            End If
        End If
    Next rCell

    'this is an array we'll write out to the worksheet
    ReDim aOutput(1 To dc.Count + IIf(LotRemains <> 0, 1, 0), 1 To 4)

    'for every bucket we saved, put it in the array
    For i = 1 To dc.Count
        aOutput(i, 1) = Ticker
        aOutput(i, 2) = IIf(Lot > 0, "Long", "Short")
        aOutput(i, 3) = Abs(dc.Items(i - 1))
        aOutput(i, 4) = Split(dc.Keys(i - 1), "|")(1)
    Next i

    'if we couldn't use it all up, get the next bucket number
    If LotRemains <> 0 Then
        For Each rCell In lo.ListColumns(1).DataBodyRange.Cells
            If rCell.Value = Ticker Then
                If rCell.Offset(0, 3).Value > MaxBucket Then
                    MaxBucket = rCell.Offset(0, 3).Value
                End If
            End If
        Next rCell

        'then add a new bucket to the array
        aOutput(dc.Count + 1, 1) = Ticker
        aOutput(dc.Count + 1, 2) = IIf(Lot > 0, "Long", "Short")
        aOutput(dc.Count + 1, 3) = Abs(LotRemains)
        aOutput(dc.Count + 1, 4) = MaxBucket + 1
    End If

    'write out the new transactions to the worksheet
    lo.ListRows.Add.Range.Resize(UBound(aOutput, 1), UBound(aOutput, 2)).Value = aOutput

End Sub

从这里开始

然后运行AddLots "BCS", 400并获取

然后运行AddLots "BCS", -1000并获取

然后使用一个数据透视表来查看您所处的位置,无论是通过报价器、存储桶还是其他任何方式

表的最后一列中的公式为

代码语言:javascript
运行
复制
=SUMPRODUCT(([Ticker]=[@Ticker])*([Bucket]=[@Bucket])*([LS]="Long")*([Lots]))-SUMPRODUCT(([Ticker]=[@Ticker])*([Bucket]=[@Bucket])*([LS]="Short")*([Lots]))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49657526

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档