1

新しい SQL Server 2012 関数のいくつかがこの問題に役立つかどうか疑問に思っています。これが私のDDLとサンプルデータです

CREATE TABLE [dbo].[transactions]
(
    [transactionId] [int]            NOT NULL,
    [dt]            [datetime]       NOT NULL,
    [balance]       [decimal](22, 6) NULL
);    
GO

INSERT [dbo].[transactions] ([transactionId], [dt], [balance]) VALUES
 (174, CAST(0x0000A19600000000 AS DateTime), CAST(1000.000000 AS Decimal(22, 6))), 
 (178, CAST(0x0000A19700869520 AS DateTime), CAST(1100.000000 AS Decimal(22, 6))),
 (179, CAST(0x0000A19700933780 AS DateTime), CAST(1212.000000 AS Decimal(22, 6))),
 (180, CAST(0x0000A19700B4B9A0 AS DateTime), CAST(1342.000000 AS Decimal(22, 6))),
 (181, CAST(0x0000A19700BB0AD0 AS DateTime), CAST(1198.000000 AS Decimal(22, 6))),
 (182, CAST(0x0000A19700E67030 AS DateTime), CAST(1234.000000 AS Decimal(22, 6))),
 (183, CAST(0x0000A19700F358E0 AS DateTime), CAST(900.000000  AS Decimal(22, 6))),
 (184, CAST(0x0000A19700F58B60 AS DateTime), CAST(876.000000  AS Decimal(22, 6))),
 (185, CAST(0x0000A19700F9AA10 AS DateTime), CAST(889.000000  AS Decimal(22, 6))),
 (186, CAST(0x0000A19701034700 AS DateTime), CAST(1133.000000 AS Decimal(22, 6))),
 (187, CAST(0x0000A19A0089E0E0 AS DateTime), CAST(1400.000000 AS Decimal(22, 6))),
 (191, CAST(0x0000A19A009450C0 AS DateTime), CAST(1566.000000 AS Decimal(22, 6))),
 (192, CAST(0x0000A19A00A5E4C0 AS DateTime), CAST(1800.000000 AS Decimal(22, 6))),
 (188, CAST(0x0000A19A00AA49C0 AS DateTime), CAST(1900.000000 AS Decimal(22, 6))),
 (189, CAST(0x0000A19A00B54640 AS DateTime), CAST(1456.000000 AS Decimal(22, 6))),
 (190, CAST(0x0000A19A00CAB2A0 AS DateTime), CAST(1234.000000 AS Decimal(22, 6))),
 (193, CAST(0x0000A19A00F12660 AS DateTime), CAST(1400.000000 AS Decimal(22, 6))),
 (195, CAST(0x0000A19A010087E0 AS DateTime), CAST(1444.000000 AS Decimal(22, 6))),
 (196, CAST(0x0000A19E00C7F380 AS DateTime), CAST(1556.000000 AS Decimal(22, 6))),
 (197, CAST(0x0000A19E00FE5560 AS DateTime), CAST(1975.000000 AS Decimal(22, 6)));

私は、dt によって注文された、シリーズのバランスの最大パーセンテージの山谷ドローダウンの後にいます。山から谷へのドローダウンは、前の高値を超える前に、残高の高値から安値までの最大の変化率です。ここで詳しく説明しますhttp://www.investopedia.com/terms/p/peak-to-valley-drawdown.asp このデータ セットには 2 つのドローダウンがあります。

1 つ目は 1342.00 から 876.00 (-34.72%) で、2 つ目は 1900 から 1234 (-35.05%) です。

したがって、このセットの最大の山から谷までのドローダウン率は -35.05% です。この値を提供できる SQL Server クエリが必要です。可能であれば、一時テーブルを使用する必要はありません。何か案は?

4

3 に答える 3

2

SQL Server 2012 の機能がこの値をこれよりも簡潔または効率的に取得できるかどうかはわかりません。

;WITH x AS
(
  SELECT [drop] = ((s.balance-e.balance)*100.0/s.balance)
    FROM dbo.transactions AS s
    INNER JOIN dbo.transactions AS e
    ON s.transactionId < e.transactionId
    AND s.balance > e.balance
)
SELECT [Largest Drawdown] = -MAX([drop]) FROM x;

結果:

Largest Drawdown
----------------
-35.05263157894

ただし、これがサンプル データに対して機能するのは、解決したい問題に対して谷が便利だからです。最後から 4 行目を 875 に変更すると、このクエリはそれをセットの一部と見なします。言い換えれば、ここでは、高値が再び交差するまでの範囲だけでなく、範囲全体のドローダウンを計算しました。

ギャップ/アイランド手法を使用してこのクエリを解決するためのより良い方法があると思われます。十分に集中できるようになったら、それに戻るようにします。

于 2013-04-14T20:12:02.573 に答える
0
select peak_dt, peak_balance, trough_dt, trough_balance, (peak_balance - trough_balance) * 100.0 / peak_balance as drawdown
from (
    select dt as peak_dt, balance as peak_balance, nullif(last_value(dt) over (partition by peak_valley_group order by dt rows between unbounded preceding and unbounded following), dt) as trough_dt, nullif(last_value(balance) over (partition by peak_valley_group order by dt rows between unbounded preceding and unbounded following), balance) as trough_balance, isPeak
    from (
        select *, sum(isPeak) over (order by dt) as peak_valley_group
        from (
            select dt, balance, (case when forward_trend = -1 then 1 else 0 end) as isPeak, max(balance) over (partition by forward_trend order by dt) as current_max_balance
            from (
                -- Nulls for lead/lag here produce the desired result
                select *, (case when lead(balance, 1) over (order by dt) > balance then 1 else -1 end) as forward_trend, (case when lag(balance, 1) over (order by dt) > balance then 1 else -1 end) as backward_trend
                from transactions
            ) t
            where forward_trend = backward_trend
        ) t
        where (isPeak = 1 and balance = current_max_balance) 
        or isPeak = 0
    ) t
) t
where isPeak = 1
order by peak_dt
于 2013-04-15T11:48:25.120 に答える