【问题标题】:Creating quintile stock portfolios with SQL使用 SQL 创建五分位股票投资组合
【发布时间】:2018-01-04 20:49:56
【问题描述】:

我想要一个 SQL 代码,可以让我为每月的股票数据形成五分之一的投资组合。五分位投资组合的形成取决于一个比率(在我的电子表格中称为 B/M)。我希望代码自动为每个月生成不同的五分之一投资组合,因为与上个月相比,某个月的股票/公司增加或撤回。比率也可以改变,以便在下个月某个股票可以在另一个五分之一中排名。

我添加了一个打印屏幕来简要展示我是如何组织我的 Excel 工作表的。 基本上是按月排序的。enter image description here

【问题讨论】:

标签: sql portfolio quantitative-finance stocks


【解决方案1】:

如果您计算比率并且您可以使用这些比率来确定某物应该在哪个五分之一,这会使它变得更容易。您不必使用 NTILE(),只需设置一个 CTE,指定将落入每个五分位数的最小和最大比率。

/* Test Data */
IF OBJECT_ID(N'tempdb..#stocks') IS NOT NULL
     DROP TABLE #stocks
;

CREATE TABLE #stocks  (StockName varchar(10), BMratio int, StockMonth datetime) ;
INSERT INTO #stocks (StockName, BMratio, StockMonth)
    /* Jan = 10 = 2 per quint */
    SELECT 'abc' AS StockName, 10 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'def' AS StockName,  9 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'ghi' AS StockName,  8 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'jkl' AS StockName,  7 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'mno' AS StockName,  6 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'pqr' AS StockName,  5 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'stu' AS StockName,  4 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'vwx' AS StockName,  3 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT 'yz1' AS StockName,  2 AS BMratio, '20170101' AS StockMonth UNION ALL
    SELECT '234' AS StockName,  1 AS BMratio, '20170101' AS StockMonth UNION ALL

    /* Feb = 7 = uneven quints */
    SELECT 'abc' AS StockName,  1 AS BMratio, '20170201' AS StockMonth UNION ALL
    SELECT 'def' AS StockName,  2 AS BMratio, '20170201' AS StockMonth UNION ALL
    SELECT 'ghi' AS StockName,  4 AS BMratio, '20170201' AS StockMonth UNION ALL
    SELECT 'jkl' AS StockName,  5 AS BMratio, '20170201' AS StockMonth UNION ALL
    SELECT 'mno' AS StockName,  7 AS BMratio, '20170201' AS StockMonth UNION ALL
    SELECT 'pqr' AS StockName, 10 AS BMratio, '20170201' AS StockMonth UNION ALL
    SELECT 'stu' AS StockName,  9 AS BMratio, '20170201' AS StockMonth UNION ALL

    /* Mar = 3 = not enough for 5 quints. */
    SELECT 'abc' AS StockName, 5 AS BMratio, '20170301' AS StockMonth UNION ALL
    SELECT 'jkl' AS StockName, 5 AS BMratio, '20170301' AS StockMonth UNION ALL
    SELECT 'vwx' AS StockName, 5 AS BMratio, '20170301' AS StockMonth
; 

/* Create CTE query */
; WITH Quint_CTE AS (
    SELECT 1 AS quintNum, 9 AS quintMin, 10 AS quintMax UNION ALL
    SELECT 2 AS quintNum, 7 AS quintMin,  8 AS quintMax UNION ALL
    SELECT 3 AS quintNum, 5 AS quintMin,  6 AS quintMax UNION ALL
    SELECT 4 AS quintNum, 3 AS quintMin,  4 AS quintMax UNION ALL
    SELECT 5 AS quintNum, 0 AS quintMin,  2 AS quintMax 
)
SELECT x.StockName, month(x.StockMonth) AS StockMonth, q.quintNum AS quintile
FROM #stocks x
INNER JOIN Quint_CTE q ON x.BMratio BETWEEN q.quintMin AND q.quintMax
ORDER BY StockMonth, q.quintNum ASC

【讨论】:

    【解决方案2】:

    注意:这适用于 MS SQL 2008+。

    我不知道您的数据结构是什么样的,但可能类似于

    /* Test Data */
    WITH stocks AS (
        /* Jan = 10 = 2 per quint */
        SELECT 'abc' AS StockName, 100.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'def' AS StockName, 99.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'ghi' AS StockName, 50.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'jkl' AS StockName, 50.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'mno' AS StockName, 75.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'pqr' AS StockName, 77.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'stu' AS StockName, 20.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'vwx' AS StockName, 10.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT 'yz1' AS StockName,  2.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
        SELECT '234' AS StockName,  1.00 AS StockPrice, '20170101' AS PriceDate UNION ALL
    
        /* Feb = 7 = uneven quints */
        SELECT 'abc' AS StockName, 1.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
        SELECT 'def' AS StockName, 2.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
        SELECT 'ghi' AS StockName, 20.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
        SELECT 'jkl' AS StockName, 55.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
        SELECT 'mno' AS StockName, 50.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
        SELECT 'pqr' AS StockName, 100.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
        SELECT 'stu' AS StockName, 90.00 AS StockPrice, '20170201' AS PriceDate UNION ALL
    
        /* Mar = 3 = not enough for 5 quints. */
        SELECT 'abc' AS StockName, 42.00 AS StockPrice, '20170301' AS PriceDate UNION ALL
        SELECT 'jkl' AS StockName, 42.00 AS StockPrice, '20170301' AS PriceDate UNION ALL
        SELECT 'vwx' AS StockName, 42.00 AS StockPrice, '20170301' AS PriceDate
    )
    
    /* Query */    
    SELECT y.StockName, y.StockPrice, y.PriceMonth, y.quintile
    FROM (
        SELECT x.StockName, x.StockPrice, month(x.PriceDate) AS PriceMonth 
            , NTILE(5) OVER (PARTITION BY month(x.PriceDate) ORDER BY x.StockPrice DESC) AS quintile
        FROM stocks x
        GROUP BY x.StockName, x.StockPrice, month(x.PriceDate)
    ) y
    ORDER BY y.PriceMonth, y.quintile ASC
    

    给你

    StockName  StockPrice  PriceMonth  quintile
    abc        100.00      1           1
    def         99.00      1           1
    pqr         77.00      1           2
    mno         75.00      1           2
    ghi         50.00      1           3
    jkl         50.00      1           3
    stu         20.00      1           4
    vwx         10.00      1           4
    yz1          2.00      1           5
    234          1.00      1           5
    pqr        100.00      2           1
    stu         90.00      2           1
    jkl         55.00      2           2
    mno         50.00      2           2
    ghi         20.00      2           3
    def          2.00      2           4
    abc          1.00      2           5
    abc         42.00      3           1
    jkl         42.00      3           2
    vwx         42.00      3           3
    

    然后,当您显示它时,您可以按五分位数对其进行排序/分组。

    此外,我上面的示例说明了 NTILE() 不一定会给您所需的内容。您可能必须自己计算然后创建五分位数。请参阅三月组 >> 所有都是 42 美元,但它们被放入了 3 个不同的五分之一。它也低于其他 Quintile 3 的价格。所以检查它是你想要的。

    最后,最好添加一个为您预先计算日期部分的日期维度表,然后将 JOIN 添加到您的主子查询中,但这是一个完全不同的讨论。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 1970-01-01
      • 2014-02-03
      • 1970-01-01
      • 2020-07-28
      • 1970-01-01
      相关资源
      最近更新 更多