具有重置价值和平均购买价格的股票钱包

问题描述

我当时正在处理个人投资工作表,并思考了使之有用并能够计算每个资产余额和当前平均值所需的最少信息。

我看到了几个示例,其中大多数依赖于借方和贷方列,或使用单行来添加买/卖价格;第一种情况需要至少两行来说明钱的去向/去向;第二个很难表达部分卖出(例如买入100只股票,卖出50只股票,然后再买入50只;当前头寸和平均买入价是多少?)

考虑到这一点,我想到了I described here

考虑以下数据集:

SELECT  *
FROM    (
VALUES  (1,'2020-08-01','MBIT','POCKET','MONEY',100.00,'Added $100 from my pocket into MBIT broker'),(2,'2020-08-02','XPTO',0.50,'Bought 0.50 XPTO for $100 (thus rate=200)'),(3,'2020-08-03',125.00,'Sold   0.50 XPTO for $125 (thus rate=250,$25 profit)'),(4,'2020-08-04',0.35,85.00,'Bought 0.35 XPTO for $85  (thus rate=~242.85)'),(5,'2020-08-05','WXYZ',1.75,20.00,'Bought 1.75 WXYZ for $20 (rate~=11.43)'),(6,'2020-08-06',1.85,15.00,'Bought 1.85 WXYZ for $15 (new total = 3.6 for $35,rate~=9.72)'))
        Entries([Order#],Date,Broker,Debit,Credit,Quantity,Value,Description)

我想计算每个经纪人/资产的当前平均值和余额;该怎么做?

解决方法

第一步是确定应评估为货币的资产(即固定汇率为1),并存储其他资产的当前报价:

WITH    Coins   AS
(       SELECT  *
        FROM    (
        VALUES  ('POCKET',1,1.00),-- Pocket and money always have $1 price
                ('MONEY',-- Pocket and money always have $1 price
                ('XPTO',200.00),-- Current rate for this asset
                ('WXYZ',8.50))
                Entries(Name,IsMoney,[Current])
)

然后,我们需要从给定的数据集(名为RawData)中拆分每一行,因此我们可以为贷方部分留一行,并为借方留一行。我们还需要计算每个非货币资产的汇率:

,Accounting  AS
(       SELECT  ROW_NUMBER() OVER (ORDER BY Date,Order#,Quantity) Sequence,[Order#],Date,Broker,Account,Description,CASE WHEN Coins.IsMoney = 1 THEN Value ELSE Quantity END Quantity,Value /
                CASE WHEN Coins.IsMoney = 1 THEN Value ELSE Quantity END Rate
        FROM    (   SELECT  [Order#],Debit  AS Account,-Quantity Quantity,-Value Value,Description
                    FROM    RawData
                    UNION   ALL
                    SELECT  [Order#],Credit AS Account,+Quantity Quantity,+Value Value,Description
                    FROM    RawData
                )   Accounting
        LEFT
        JOIN    Coins
            ON  Coins.Name = Accounting.Account
)

非常简单;到目前为止,我们得到了: enter image description here

SuperUser question comments上,我发现计算平均价格会比较棘手,特别是考虑到我需要忽略未平仓头寸。

由于出售资产余额的操作与购买资产余额的操作并不直接相关,所以我陷入了困境。

转折点是当我意识到我不需要匹配这些东西时:我需要的是找出余额何时为零,并仅使用其最新的“版本”。

所以我转向了窗口函数;这里的挑战是确定何时重置天平。进行了一些谷歌搜索,使我进入T-SQL Feature Request: Add RESET WHEN Clause to Reset Window Partition,作者巧妙地描述了请求功能如何帮助进行更简单的查询,并给出了在Microsoft员工点头批准时如何克服它们的提示。

,Balance AS
(   SELECT  *,MAX(BalanceVersion) OVER (PARTITION BY Broker,Account) LatestVersion
    FROM    (   SELECT  *,SUM(BalanceReset) OVER (
                    PARTITION BY Broker,Account
                    ORDER BY Sequence)  BalanceVersion
                FROM    (   SELECT  *,CASE    WHEN    LAG(Total) OVER (
                                                        PARTITION BY Broker,Account
                                                        ORDER BY Sequence) = 0
                                            THEN    1
                                            ELSE    0
                                    END     BalanceReset
                            FROM    (   SELECT  *,SUM (Quantity) OVER (
                                                    PARTITION BY Broker,Account
                                                    ORDER BY Sequence) AS Total
                                        FROM    Accounting
                                    )   Account
                        )   Reset
            )   Versions
)

把这件事分开:

  • 让我们首先计算每种资产的运行总计(Account子选择)
  • 我们使用LAG functionReset子选择)来确定余额为零的时间
  • 现在让我们使用重置标识符将余额分组(Versions子选择)来计算新的运行总计
  • 最后一步是确定每个经纪人/资产组的最新版本

Balance resultset

通过识别“数据岛”,我们又回到了游戏中!

现在让我们计算未平仓头寸的正确平均值和最终余额:

,Final AS
(   SELECT  Broker,SUM(Quantity) Quantity,SUM(CASE WHEN IsMoney = 1 THEN 1.000 ELSE [Rate] * Quantity  END) /
            SUM(CASE WHEN IsMoney = 1 THEN 1.000 ELSE Quantity  END) Rate
    FROM    Balance
    WHERE   BalanceVersion = LatestVersion
    GROUP
        BY  Broker,Account
)

Final resultset

建立正确的XPTO平衡需要所有窗口函数疯狂;对于该计算,我们不能使用第一个买/卖操作,因为它会将头寸清零,我们需要重新开始以获取正确的平均买入价。

其余查询仅是将当前资产价格与计算得出的余额和平均价格放在一起的问题:

SELECT  Final.Broker,Final.Account,Final.Quantity,Final.Rate  [Original],Coins.[Current]    [Current],(Coins.[Current] / Final.Rate)-1 [%],(Coins.[Current] * Final.Quantity) [Value]
FROM    Final
LEFT
JOIN    Coins
    ON  Coins.Name = Final.Account
ORDER
    BY  Final.Broker,Final.Account

结果是这样的: Final report

查看我们可以看到的数据:

  • 我们向该经纪人投资了多少(价值POCKET
  • 我们在经纪人中闲置了多少钱(价值MONEY
  • 余额WXYZ
    • 我们首先以$ 20的价格购买了1.75 WXYZ(汇率:20 / 1.75〜= 11.43)
    • 然后我们以15美元(价格:15 / 1.85〜= 8.10)购买了更多的1.85 WXYZ
    • 因此正确的平均价格为(20 + 15)/(1.75 + 1.85)〜= 9.72
  • 余额XPTO
    • 如果考虑所有操作,则平均值为171.43
    • 这是错误的,因为如果我们购买了一定数量的资产并出售了所有资产,那么这些价格不会影响新的购买价格
    • 因此,该资产的正确平均值约为〜242.85

结论:在这种假设的情况下:

  • 我们投入了100美元;
  • 获利25美元;
  • 购买了一些XPTO
  • 买了一些WXYZ
  • WXYZ市场价格下跌,我们买了更多
  • XPTO自上次购买以来已下降12.57%
  • 考虑到前两次收购的平均价格,WXYZ下跌了17.65%
  • 如果我们将最后一列中的所有值相加,我们可以看到仍然有$ 5.60的利润

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...