如何在mysql中计算投资组合收益?

neekobn8  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(343)

我被mysql问题困住了。我试图使用以下公式计算投资组合的收益率系列:

for(i = startdate+1; i <= enddate; i++) {
   return[i]=0;
   for(n = 0;  n < count(instruments); n++) {
     return[i] += price[i,n] / price[i-1, n] * weight[n];
   }
 }

因此,今天投资组合的回报率计算为今天的价格/昨天的价格*投资组合中工具的权重之和。
我写了一篇潦草的文章http://rextester.com/fuc35243.
如果不起作用,代码是:

DROP TABLE IF EXISTS x_ports;
DROP TABLE IF EXISTS x_weights;
DROP TABLE IF EXISTS x_prices;

CREATE TABLE IF NOT EXISTS x_ports (id INT NOT NULL AUTO_INCREMENT, name VARCHAR(20), PRIMARY KEY (id));
CREATE TABLE IF NOT EXISTS x_weights (id INT NOT NULL AUTO_INCREMENT, port_id INT, inst_id INT, weight DOUBLE, PRIMARY KEY (id));
CREATE TABLE IF NOT EXISTS x_prices (id INT NOT NULL AUTO_INCREMENT, inst_id INT, trade_date DATE, price DOUBLE, PRIMARY KEY (id));

INSERT INTO x_ports (name) VALUES ('PORT A');
INSERT INTO x_ports (name) VALUES ('PORT B');

INSERT INTO x_weights (port_id, inst_id, weight) VALUES (1, 1, 20.0);
INSERT INTO x_weights (port_id, inst_id, weight) VALUES (1, 2, 80.0);
INSERT INTO x_weights (port_id, inst_id, weight) VALUES (2, 1, 100.0);

INSERT INTO x_prices (inst_id, trade_date, price) VALUES (1, '2018-01-01', 1.12);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (1, '2018-01-02', 1.13);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (1, '2018-01-03', 1.12);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (1, '2018-01-04', 1.12);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (1, '2018-01-05', 1.13);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (1, '2018-01-06', 1.14);

INSERT INTO x_prices (inst_id, trade_date, price) VALUES (2, '2018-01-01', 50.23);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (2, '2018-01-02', 50.45);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (2, '2018-01-03', 50.30);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (2, '2018-01-04', 50.29);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (2, '2018-01-05', 50.40);
INSERT INTO x_prices (inst_id, trade_date, price) VALUES (2, '2018-01-06', 50.66);

# GETTING THE DATES

SET @DtShort='2018-01-01';
SET @DtLong=@DtShort;

SELECT
    @DtShort:=@DtLong as date_prev,
    @DtLong:=dt.trade_date as date_curent
FROM
    (SELECT DISTINCT trade_date FROM x_prices ORDER BY trade_date) dt;

# GETTING RETURN FOR SINGLE DAY

SET @DtToday='2018-01-03';
SET @DtYesterday='2018-01-02';

SELECT
    x2.trade_date,
    x2.portfolio,
    sum(x2.val*x2.weight)/sum(x2.weight) as ret
FROM

    (SELECT
        x1.trade_date, 
        x1.portfolio,
        sum(x1.weight)/2.0 as weight,
        sum(x1.val_end)/sum(x1.val_start) as val, 
        sum(x1.val_start) as val_start,
        sum(x1.val_end) as val_end
    FROM

        (SELECT
            @DtToday as trade_date,
            prt.name as portfolio,
            wts.inst_id as iid,
            wts.weight,
            if(prc.trade_date=@DtToday,prc.price*wts.weight,0) as val_start,
            if(prc.trade_date=@DtYesterday,prc.price*wts.weight,0) as val_end
        FROM
            x_ports prt,
            x_weights wts,
            x_prices prc
        WHERE
            wts.port_id=prt.id and 
            prc.inst_id=wts.inst_id and
            (prc.trade_date=@DtToday or prc.trade_date=@DtYesterday)) x1

    GROUP BY x1.portfolio) x2

GROUP BY x2.portfolio;

我希望能够产生这样的结果:

Date        Port A      Port B
--------------------------------------------
01/01/2010      
02/01/2010  1.005289596 1.004379853
03/01/2010  0.995851496 0.997026759
04/01/2010  0.999840954 0.999801193
05/01/2010  1.003535565 1.002187314
06/01/2010  1.005896896 1.00515873

2018年2月1日a港的回报率应计算为1.13/1.1220/(20+80)+50.45/50.2380/(20+80)。
2018年2月1日b港的回报率应计算为50.45/50.23100/100,或可能为1.13/1.120/(0+100)+50.45/50.23100/(0+100)。
仅供参考,在上面的循环函数中,我只计算指定值(或未标度的权重),因此端口a将被计算为1.13/1.12
20+50.45/50.23*80,我认为这是计算回报的关键步骤。然后将返回值除以权重之和,得到返回值。
虽然这当然可以做得更好,我可以得到日期,我可以计算一天的回报,但我就是不能把两者放在一起。

vltsax25

vltsax251#

模拟分析没有乐趣!演示
这方面的数学在我看来并不正确;因为我没有接近你的“看起来像结果”
我想能够重用curday,但由于版本较低,我不能使用一个共同的表表达式。
它的作用是:
x1生成表的联接
x2给了我们一个投资组合中工具的计数,这些工具后来在数学中使用
r生成一个uservariable,我们可以在其上分配行@rn和@rn2
curday生成一个正确排序的行号以便我们可以加入
nextday生成curday的一个副本,这样我们就可以在rn+1上加入curday到第二天
z允许我们在当天进行数学运算和分组,并为公文包名称的轴心做准备。
最外层的select允许我们透视数据,所以我们有date+2列
.

SELECT Z.Trade_Date
     , sum(case when name = 'Port A' then P_RETURN end) as PortA
     , sum(case when name = 'Port B' then P_RETURN end) as PortB
FROM (

## Raw data

SELECT CurDay.*, NextDay.Price/CurDay.Price*CurDay.Weight/CurDay.Inst_Total_Weight as P_Return
FROM (SELECT x1.*, @RN:=@RN+1 rn,x2.inst_cnt, x2.Inst_Total_Weight
      FROM (SELECT prt.name, W.port_ID, W.inst_ID, W.weight, prc.trade_Date, Prc.Price
            FROM x_ports Prt
            INNER JOIN x_weights W
              on W.Port_ID = prt.ID
            INNER JOIN x_prices Prc
              on Prc.INST_ID = W.INST_ID
            ORDER BY W.port_id, W.inst_id,trade_Date) x1
     CROSS join (SELECT @RN:=0) r
     INNER join (SELECT count(*) inst_Cnt, port_ID, sum(Weight) as Inst_Total_Weight 
                 FROM x_weights
                 GROUP BY Port_ID) x2
        on X1.Port_ID = X2.Port_ID) CurDay
LEFT JOIN (SELECT x1.*, @RN2:=@RN2+1 rn2
           FROM (SELECT prt.name, W.port_ID, W.inst_ID, W.weight, prc.trade_Date, Prc.Price
                 FROM x_ports Prt
                 INNER JOIN x_weights W
                   on W.Port_ID = prt.ID
                 INNER JOIN x_prices Prc
                   on Prc.INST_ID = W.INST_ID
                 ORDER BY W.port_id, W.inst_id,trade_Date) x1
                 CROSS join (SELECT @RN2:=0) r
           ) NextDay
   on NextDay.Port_ID = CurDay.Port_ID
  and NextDay.Inst_ID = curday.Inst_ID
  and NextDay.RN2 = CurDay.RN+1
GROUP BY CurDay.Port_ID,  CurDay.Inst_ID,  CurDay.Trade_Date) Z

## END RAW DATA

GROUP BY Trade_Date;

+----+---------------------+-------------------+-------------------+
|    |     Trade_Date      |       PortA       |       PortB       |
+----+---------------------+-------------------+-------------------+
|  1 | 01.01.2018 00:00:00 | 1,00528959642786  | 1,00892857142857  |
|  2 | 02.01.2018 00:00:00 | 0,995851495829569 | 0,991150442477876 |
|  3 | 03.01.2018 00:00:00 | 0,999840954274354 | 1                 |
|  4 | 04.01.2018 00:00:00 | 1,0035355651507   | 1,00892857142857  |
|  5 | 05.01.2018 00:00:00 | 1,00589689563141  | 1,00884955752212  |
|  6 | 06.01.2018 00:00:00 | NULL              | NULL              |
+----+---------------------+-------------------+-------------------+

相关问题