使用SQL创建五分位股票投资组合

时间:2017-07-28 17:34:13

标签: sql portfolio quantitative-finance stocks

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

我添加了一个版画屏幕,简要介绍了我如何组织我的Excel工作表。 基本上,它按月排序。enter image description here

2 个答案:

答案 0 :(得分:0)

注意:这适用于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为您的主要子查询,但这是一个完全不同的讨论。

答案 1 :(得分:0)

如果您计算比率,并且您可以使用它们来确定应该使用哪个五分位数,那么它会更容易 。您不必使用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