aboutsummaryrefslogtreecommitdiffstats
path: root/sql/serenitasdb.sql
blob: 4566d61e9a6b4abe8735cb1244a5f106a16fe9d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
-- -*- mode: sql; sql-product: postgres; -*-
CREATE TABLE tranche_data (
       QuoteDate date,
       TrancheId integer,
       BasketId integer,
       Maturity	 date,
       Tenor varchar(4),
       RefBasketPrice float,
       BPS varchar(1),
       BasketDuration float,
       TQC varchar(1),
       TrancheDuration float,
       TrancheDelta float,
       CorrAtDetachment float,
       Basis float,
       QuoteSource varchar(2),
       Index varchar(4),
       Series smallint,
       Upfront float,
       Running float,
       Attach smallint,
       Detach smallint,
       IndexFactor float,
       CumulativeLoss float
);

GRANT ALL ON tranche_data TO serenitas_user;

CREATE TABLE index_version(
       BasketID serial,
       Index index_type,
       Series smallint,
       Version smallint,
       IndexFactor float,
       CumulativeLoss float,
       lastdate date,
       redindexcode text,
       PRIMARY KEY(BasketID)
);
CREATE TYPE INDEXFAMILY AS ENUM('ITRAXX-Asian', 'LCDXNA', 'MCDXNA',
'ITRAXX-SOVX', 'ITRAXX-SDI', 'ITRAXX-L', 'CDX', 'ITRAXX-European');

CREATE TABLE index_version_markit(
       redindexcode text PRIMARY KEY,
       indexfamily INDEXFAMILY,
       indexsubfamily text,
       indexname text,
       ccy curr,
       indexfactor float,
       recoveryrate float,
       series smallint,
       version smallint,
       annexdate date,
       effectivedate date,
       firstpaymentdate date,
       activeversion bool,
       nextredindexcode text,
       prevredindexcode text)

GRANT ALL ON index_version TO serenitas_users;

CREATE TABLE index_maturity(
       Index index_type,
       series smallint,
       tenor tenor,
       maturity date,
       coupon integer,
       issue_date date,
       PRIMARY KEY(index, series, tenor)
);

CREATE TABLE index_maturity_markit(
       redindexcode text REFERENCES index_version_markit,
       tenor tenor,
       maturity date,
       tradeid text PRIMARY KEY,
       coupon integer,
);

CREATE OR REPLACE VIEW risk_num_per_quote AS
  SELECT a.*, b.trancheupfrontmid, b.trancherunningmid, b.indexrefprice, b.indexrefspread,
    b.tranchedelta, b.quotesource
    FROM risk_numbers_new a
    JOIN tranche_quotes b ON a.tranche_id = b.id;

CREATE OR REPLACE VIEW index_desc AS
 SELECT b.*, a.tenor, a.maturity, a.coupon, a.issue_date
   FROM index_maturity a
   JOIN index_version b USING (index, series);

GRANT ALL ON index_maturity TO serenitas_user;
GRANT ALL ON index_version TO serenitas_user;
GRANT ALL ON index_desc TO serenitas_user;


CREATE TABLE quotes (
-- DEPRECATED
       QuoteDate timestamp,
       Index index_type,
       Series smallint,
       Version smallint,
       tenor tenor,
       attach smallint,
       detach smallint,
       RefBasketPrice float,
       Upfront float,
       Running float,
       BasketDuration float,
       TrancheDuration float,
       TrancheDelta float,
       CorrAtDetachment float,
       Basis float,
       QuoteSource varchar(4)
);

CREATE TABLE tranche_quotes (
       id serial PRIMARY KEY,
       QuoteDate timestamptz,
       Index index_type,
       Series smallint,
       Version smallint,
       Tenor tenor,
       Attach smallint,
       Detach smallint,
       TrancheUpfrontBid float,
       TrancheUpfrontMid float,
       TrancheUpfrontAsk float,
       TrancheRunningBid float,
       TrancheRunningMid float,
       TrancheRunningAsk float,
       IndexRefPrice real,
       IndexRefSpread smallint,
       IndexDuration real,
       TrancheDuration real,
       TrancheDelta real,
       CorrAtDetachment real,
       Basis real,
       QuoteSource varchar(4),
       markit_id integer
       UNIQUE (QuoteDate, Index, Series, Version, Tenor, Attach, Detach, QuoteSource, trancherunningmid, markit_id)
);

CREATE INDEX tranche_quotes_idx ON
tranche_quotes(index, series, DATE(quotedate AT TIME ZONE 'localtime'), tenor, attach ASC)

GRANT ALL ON quotes TO serenitas_user;
GRANT ALL ON tranche_quotes TO serenitas_user;

-- Idiosyncracies:

-- for Itraxx 9 index:

--     tr.id	coupon type
-- 3-6 98155	all running
--     98154	U+500
-- 6-9 98160	all running
--     166395 	U+300
--     98159	U+500

-- For IG 9 index:

--        tr.id	coupon type
-- 3-7    162290	all running
--        162291	U+500
-- 7-10   162298	all running
--        162300	U+500
-- 10-15  162301	all running
--        162304	U+500
-- 15-30  162305	all running
--        162306	U+500
-- 30-100 162307	all running
--        162308	U+500

-- All other tranches should have a unique trancheid for a given basketid, attach, detach combination
CREATE TYPE entitytype AS ENUM('Corp', 'Sov', 'State', 'StatBody', 'Supra', 'Insurer',
       'Monoline', 'Index', 'Muni');
CREATE TYPE depthlevel AS ENUM('high', 'med', 'low', 'High', 'Med', 'Low', 'HIGH', 'MED', 'LOW');

CREATE TABLE IF NOT EXISTS RefEntity(
       referenceentity text NOT NULL,
       shortname text NOT NULL,
       ticker text NOT NULL,
       redentitycode varchar(6) NOT NULL PRIMARY KEY,
       entitycusip text NOT NULL,
       lei text,
       entitytype text NOT NULL,
       jurisdiction text NOT NULL,
       depthlevel depthlevel,
       markitsector text,
       isdatradingdefinition text,
       recorddate date,
       ratings text[],
       entityform text,
       companynumber jsonb,
       alternativenames text,
       isdatransactiontypes jsonb,
       validto date,
       validfrom date,
       events jsonb);

CREATE TABLE IF NOT EXISTS RefObligation(
       id serial PRIMARY KEY,
       obligationname text NOT NULL,
       prospectusinfo jsonb,
       refentities text[],
       type text NOT NULL,
       isconvert bool NOT NULL,
       isperp bool NOT NULL,
       coupontype text NOT NULL,
       ccy varchar(3) NOT NULL,
       maturity date,
       issuedate date,
       coupon numeric(8,6) NOT NULL,
       isin varchar(12) NOT NULL,
       cusip varchar(9),
       event text);

CREATE TABLE IF NOT EXISTS RedPairMapping(
       redpaircode varchar(9) PRIMARY KEY,
       role text NOT NULL,
       referenceentity text NOT NULL,
       redentitycode text NOT NULL REFERENCES RefEntity,
       tier text NOT NULL,
       pairiscurrent boolean,
       pairvalidfrom date,
       pairvalidto date,
       ticker text NOT NULL,
       ispreferred boolean,
       preferreddate date,
       indexconstituents text[],
       recorddate date NOT NULL,
       publiccomments text,
       myticker text);

CREATE TYPE curr AS ENUM('USD', 'EUR', 'JPY', 'GBP', 'CAD');
CREATE TYPE sen AS ENUM('Senior', 'Subordinated');
CREATE TYPE tier AS ENUM('SNRFOR', 'SECDOM', 'SUBLT2', 'PREFT1', 'JRSUBUT2');
CREATE TYPE bbgSource AS ENUM('MSG1', 'CBIN', 'CBGN', 'MKIT', 'CMAN');
CREATE TYPE DocClause AS ENUM('No Restructuring', 'Modified Modified Restructurin', 'Full Restructuring');
CREATE TYPE tenor AS ENUM('6mo', '1yr', '2yr', '3yr', '4yr', '5yr', '7yr', '10yr');
CREATE TYPE index_type AS ENUM('IG', 'HY', 'EU', 'LCDX', 'XO');
CREATE TYPE BBG_CC AS ENUM('OC');

CREATE TABLE CDS_Issuers_old(
       --DEPRECATED
       Name text,
       company_id integer,
       ticker text,
       currency curr,
       seniority sen,
       doc_clause DocClause,
       cds_curve text[8] UNIQUE,
       index_list integer[],
       markit_ticker text,
       markit_tier tier,
       spread integer,
       PRIMARY KEY(company_id));

GRANT ALL ON  CDS_Issuers_old to serenitas_user;

CREATE TABLE bbg_issuers(
       Name text,
       company_id integer,
       ticker text,
       currency curr,
       seniority sen,
       doc_clause DocClause,
       cds_curve text[8] UNIQUE,
       index_list integer[],
       PRIMARY KEY(company_id));

GRANT ALL ON  bbg_issuers to serenitas_user;

CREATE TABLE bbg_markit_mapping(
       date date,
       company_id integer REFERENCES bbg_Issuers,
       markit_ticker text,
       markit_tier tier,
       spread integer,
       PRIMARY KEY(company_id, date));

GRANT ALL ON  bbg_markit_mapping to serenitas_user;

CREATE TABLE IF NOT EXISTS cds_quotes(
       Date Date,
       curve_ticker text,
       UpfrontBid float,
       UpfrontAsk float,
       RunningBid float,
       RunningAsk float,
       Source bbgSource,
       Recovery float,
       PRIMARY KEY(curve_ticker, Date, Source));

GRANT ALL ON cds_quotes TO serenitas_user;
CREATE INDEX IF NOT EXISTS cds_quotes_date_index ON cds_quotes(date);

CREATE TABLE markit_tranche_quotes(
       quotedate date,
       basketid integer REFERENCES index_version,
       tenor tenor,
       attach smallint,
       detach smallint,
       upfront_bid float,
       upfront_mid float,
       upfront_ask float,
       tranche_spread smallint,
       index_price float,
       PRIMARY KEY (quotedate, basketid, tenor, attach, detach)
);

GRANT ALL ON markit_tranche_quotes TO serenitas_user;

CREATE TABLE trace_trades(
       cusip varchar(9),
       time timestamptz,
       condition_code BBG_OC,
       size  int,
       price float,
       PRIMARY KEY (cusip, time)
);

CREATE OR REPLACE FUNCTION nameToBasketID(index_name varchar(4), p_date date) RETURNS integer AS $$
       DECLARE
	p_index index_type;
      	p_series smallint;
       	p_basketid integer;
       BEGIN
	p_index := upper(left(index_name, 2))::index_type;
       	p_series := right(index_name, -2);
       	SELECT MIN(basketid) INTO p_basketid FROM index_version WHERE Index=p_index and
	Series=p_series and lastdate>=p_date;
       	RETURN p_basketid;
       END;
       $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION index_redcode(p_index index_type, p_series smallint, p_date date)
       RETURNS varchar AS $$
       DECLARE
       p_redcode varchar;
       BEGIN
         SELECT redindexcode INTO p_redcode
         FROM index_version WHERE index=p_index AND series=p_series AND lastdate>=p_date ORDER BY lastdate LIMIT 1;
         RETURN p_redcode;
       END;
       $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION index_members(index_name varchar(4), p_date date)
       RETURNS SETOF cds_issuers_old AS $$
       DECLARE
	basketid integer;
       BEGIN
	SELECT nameToBasketID(index_name, p_date) INTO basketid;
       	RETURN QUERY SELECT * FROM historical_cds_issuers(p_date)
	WHERE index_list @> Array[basketid];
       END;
       $$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION historical_cds_quotes(date, bbgSource) RETURNS SETOF cds_quotes AS $$
       BEGIN
       	RETURN QUERY SELECT b.*
       	FROM (SELECT max(c.Date) AS latestdate, c.curve_ticker FROM cds_quotes c
       	WHERE (c.Date BETWEEN $1 - interval '40 days' AND $1) AND source=$2 GROUP BY c.curve_ticker) a
       	JOIN cds_quotes b ON a.curve_ticker = b.curve_ticker AND a.latestdate=b.Date
       	WHERE source=$2;
       END;
       -- simpler query but slower
       -- BEGIN
       -- RETURN QUERY SELECT DISTINCT ON (curve_ticker) * from cds_quotes where date<=$1 ORDER BY
       -- curve_ticker, DATE desc;
       -- END;
       $$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION historical_cds_issuers(date DEFAULT current_date)
RETURNS SETOF cds_issuers_old AS $$
  BEGIN
	  RETURN QUERY SELECT bbg_issuers.*, map.markit_ticker, map.markit_tier, map.spread FROM
    (SELECT b.* FROM (SELECT min(c.date) AS latestdate, c.company_id FROM bbg_markit_mapping c
    WHERE c.date>=$1 GROUP BY c.company_id) a
    JOIN bbg_markit_mapping b ON a.company_id = b.company_id AND a.latestdate=b.date) map
    JOIN bbg_issuers USING (company_id);
  END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION curve_quotes(varchar(4), date, bbgSource DEFAULT 'MKIT') RETURNS
       TABLE(cds_ticker text, date date, spread_curve float[], upfront_curve float[], recovery_curve float[]) AS $$
       BEGIN
       RETURN QUERY SELECT max(markit_ticker) AS t, max(a.date),
       array_agg((a.runningbid+a.runningask)/2 ORDER BY tenor),
       array_agg((a.upfrontbid+a.upfrontask)/2 ORDER BY tenor),
       array_agg(a.Recovery ORDER BY tenor) FROM historical_cds_quotes($2, $3) a RIGHT JOIN
       (SELECT generate_series(1, 8) AS tenor, unnest(cds_curve) AS curve_ticker, markit_ticker, company_id
       FROM index_members($1, $2)) b
       ON b.curve_ticker = a.curve_ticker GROUP by company_id ORDER BY t;
       END;
       $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION curve_quotes_fmt(varchar(4), date, bbgSource DEFAULT 'MKIT') RETURNS
       TABLE(cds_ticker text, date date, spread_curve text, upfront_curve text, recovery_curve text) AS $$
       BEGIN
       RETURN QUERY SELECT max(markit_ticker) AS t, max(a.date),
       string_agg(to_char((a.runningbid+a.runningask)/2, 'FM999'), ','  ORDER BY tenor),
       string_agg(to_char((a.upfrontbid+a.upfrontask)/2, 'FM99D99'), ','  ORDER BY tenor),
       string_agg(to_char(a.Recovery, 'FM0D99'), ','  ORDER BY tenor) FROM historical_cds_quotes($2, $3) a
       RIGHT JOIN
         (SELECT generate_series(1, 8) AS tenor, unnest(cds_curve) AS curve_ticker, markit_ticker, company_id
       FROM index_members($1, $2)) b
       ON b.curve_ticker = a.curve_ticker GROUP by company_id ORDER BY t;
       END;
       $$ LANGUAGE plpgsql;

CREATE TABLE index_quotes_old(
       date date,
       index index_type,
       series smallint,
       version smallint,
       tenor tenor,
       closeprice float,
       closespread float,
       modelprice float,
       modelspread float,
       adjcloseprice float,
       adjmodelprice float,
       duration float,
       theta float,
       duration2 float,
       theta2 float,
       PRIMARY KEY(date, index, series, tenor, version));

CREATE TABLE index_quotes_pre (
	id serial NOT NULL PRIMARY KEY,
	date date NOT NULL,
	index index_type NOT NULL,
	series smallint NOT NULL,
	version smallint NOT NULL,
	tenor tenor NOT NULL,
	close_price float,
	close_spread float,
	model_price float,
	model_spread float,
	source bbgsource NOT NULL,
    UNIQUE (date, index, series, tenor, version, source)
);

CREATE TABLE index_risk(
	id integer PRIMARY REFERENCES index_quotes_pre,
    theta float,
    duration float);

CREATE TABLE index_risk2(
    id integer PRIMARY REFERENCES index_quotes_pre,
    theta float,
    duration float,
    tweak float
);

CREATE OR REPLACE VIEW index_quotes AS
SELECT id, date, index, series, version, tenor, close_price AS closeprice,
close_spread AS closespread,
model_price AS modelprice, model_spread AS modelspread,
index_risk.duration, index_risk.theta,
index_risk2.duration AS duration2, index_risk2.theta AS theta2
FROM index_quotes_pre
LEFT JOIN index_risk USING (id)
LEFT JOIN index_risk2 USING(id)
WHERE SOURCE='MKIT';

CREATE TABLE bbg_ticker_mapping(
       ticker text PRIMARY KEY,
       index index_type,
       series smallint,
       version smallint,
       tenor tenor
);

CREATE TABLE bbg_index_quotes(
       date date,
       ticker text REFERENCES bbg_ticker_mapping,
       index index_type,
       series smallint,
       version smallint,
       tenor tenor,
       last_price float,
       source bbgSource,
       PRIMARY KEY(date, ticker, version));

CREATE OR REPLACE FUNCTION get_tranche_quotes(pg_index_type text, pg_series integer, pg_tenor text,
       pg_date date) RETURNS SETOF tranche_quotes AS
$$
       DECLARE r RECORD;
       DECLARE lower_attach smallint;
       DECLARE flag boolean;
       BEGIN

       IF lower(pg_index_type) ='hy' AND pg_series in (9, 10)
       THEN
       	  lower_attach = 10::smallint;
       ELSE
          lower_attach = 0::smallint;
       END IF;
       flag := FALSE;
       FOR r in EXECUTE
	 'SELECT DISTINCT quotesource, quotedate FROM tranche_quotes
	 WHERE index=$1::index_type AND series=$2 AND date(timezone(''localtime'', quotedate))=$3
	 AND tenor =$4::tenor ORDER BY quotedate desc'
       USING pg_index_type, pg_series, pg_date, pg_tenor LOOP
       IF pg_index_type = 'HY' AND pg_series >=15 THEN
          EXECUTE
          'SELECT array_agg(attach ORDER BY attach ASC)||100::smallint = $6||array_agg(detach ORDER BY detach ASC)
           FROM tranche_quotes
           WHERE index=$1::index_type AND series=$2 AND tenor=$3::tenor
           AND quotedate=$4 AND detach-attach!=5::smallint AND quotesource=$5'
          INTO flag
          USING pg_index_type, pg_series, pg_tenor, r.quotedate, r.quotesource, lower_attach;
          IF flag THEN
             RETURN QUERY
             SELECT * FROM tranche_quotes WHERE index=pg_index_type::index_type AND series= pg_series
             AND tenor=pg_tenor::tenor AND quotedate=r.quotedate AND detach-attach!=5::smallint AND
             quotesource=r.quotesource ORDER BY attach ASC;
             RETURN;
          END IF;
       ELSE
          EXECUTE
          'SELECT array_agg(attach ORDER BY attach asc)||100::smallint = $6||array_agg(detach ORDER BY detach ASC)
           FROM tranche_quotes
           WHERE index=$1::index_type AND series=$2 AND tenor=$3::tenor AND quotedate=$4 AND quotesource=$5'
          INTO flag
          USING pg_index_type, pg_series, pg_tenor, r.quotedate, r.quotesource, lower_attach;
          IF flag THEN
             RETURN QUERY
             SELECT * FROM tranche_quotes WHERE index=pg_index_type::index_type AND series=pg_series
             AND tenor=pg_tenor::tenor AND quotedate=r.quotedate AND quotesource=r.quotesource
             ORDER BY attach asc;
	         RETURN;
          END IF;
       END IF;
       END LOOP;
       END;
$$ language plpgsql;

CREATE TABLE risk_numbers(
       date date,
       index index_type,
       series integer,
       tenor tenor,
       indexprice float,
       indexbasis float,
       indexEL float,
       indexduration float,
       indextheta float,
       attach integer[],
       Skew float[],
       "Dealer Deltas" float[],
       "Model Deltas" float[],
       "Forward Deltas" float[],
       gammas float[],
       thetas float[],
       corr01 float[],
       durations float[],
       el float[],
       PRIMARY KEY(date, index, series, tenor));

CREATE TABLE risk_numbers_new(
       id serial PRIMARY KEY,
       tranche_id integer REFERENCES tranche_quotes(id),
       date date,
       index index_type,
       series integer,
       tenor tenor,
       index_price float,
       index_basis float,
       "index_EL" float,
       index_duration float,
       index_theta float,
       attach smallint,
       detach smallint,
       corr_at_detach float,
       delta float,
       forward_delta float,
       gamma float,
       theta float,
       corr01 float,
       duration float,
       "EL" float);

GRANT ALL ON risk_numbers to serenitas_user;


CREATE OR REPLACE FUNCTION riskmonitor_getindicesinfo2(
    IN p_date date,
    IN p_fromseries smallint,
    IN p_index index_type,
    IN tenorarray tenor[])
  RETURNS TABLE(series smallint, redindexcode text, indexfactor float, t1price float, t1maturity date,
  t1sprd float, t1dur float, t2price float, t2maturity date, t2sprd float, t2dur float,
  t3price float, t3maturity date, t3sprd float, t3dur float) AS $$
  DECLARE
    tenor_cat text;
    what_query text;
BEGIN
  tenor_cat  := format('SELECT * FROM unnest(%L::tenor[])', tenorarray);
  what_query := 'SELECT series, tenor, %I FROM index_quotes where index=%L and series>=%L and date = %L ORDER BY series, tenor';

  RETURN QUERY
   WITH mat AS (SELECT a.series, array_agg(a.maturity order by tenor) AS maturity FROM index_maturity a
                WHERE a.series>=p_fromseries AND a.index=p_index AND a.tenor=ANY(tenorarray) GROUP BY a.series),
	    indic AS (SELECT DISTINCT ON (series) * FROM index_version
                WHERE index_version.series>=p_fromseries AND index_version.index=p_index AND lastdate>=p_date
                ORDER BY series, lastdate),
	  pxtable AS (SELECT * FROM crosstab(format(what_query, 'closeprice', p_index, p_fromseries, p_date), tenor_cat)
                AS ct(series smallint, tenor1 float, tenor2 float, tenor3 float)),
	sprdtable AS (SELECT * from crosstab(format(what_query, 'closespread', p_index, p_fromseries, p_date), tenor_cat)                 AS ct(series smallint, tenor1 float, tenor2 float, tenor3 float)),
	 durtable AS (SELECT * from crosstab(format(what_query, 'duration', p_index, p_fromseries, p_date), tenor_cat)
                AS ct(series smallint, tenor1 float, tenor2 float, tenor3 float))

	SELECT mat.series, indic.redindexcode, indic.indexfactor,
	pxtable.tenor1, mat.maturity[1], sprdtable.tenor1, durtable.tenor1,
	pxtable.tenor2, mat.maturity[2], sprdtable.tenor2, durtable.tenor2,
	pxtable.tenor3, mat.maturity[3], sprdtable.tenor3, durtable.tenor3

	FROM mat JOIN pxtable USING (series) JOIN sprdtable USING (series) JOIN durtable USING (series)
  JOIN indic USING (series) ORDER by mat.series;

END;
  $$
  LANGUAGE plpgsql;

CREATE OR REPLACE function tranche_factor(attach smallint, detach smallint,
                  index_factor float, cumulativeloss float)
RETURNS float AS $$
DECLARE
  newattach float;
  newdetach float;

BEGIN
newattach:=LEAST(GREATEST((attach-100*cumulativeloss)/index_factor, 0), 1);
newdetach:=LEAST(GREATEST((detach-100*cumulativeloss)/index_factor, 0), 1);
RETURN (newdetach-newattach)/(detach-attach)*index_factor;
END;
$$ LANGUAGE plpgsql;


CREATE TABLE USD_rates(
       effective_date date PRIMARY KEY,
       "1M" real,
       "2M" real,
       "3M" real,
       "6M" real,
       "9M" real,
       "1Y" real,
       "2Y" real,
       "3Y" real,
       "4Y" real,
       "5Y" real,
       "6Y" real,
       "7Y" real,
       "8Y" real,
       "9Y" real,
       "10Y" real,
       "12Y" real,
       "15Y" real,
       "20Y" real,
       "25Y" real,
       "30Y" real);

CREATE TABLE EUR_rates(
       effective_date date PRIMARY KEY,
       "1M" real,
       "2M" real,
       "3M" real,
       "6M" real,
       "9M" real,
       "1Y" real,
       "2Y" real,
       "3Y" real,
       "4Y" real,
       "5Y" real,
       "6Y" real,
       "7Y" real,
       "8Y" real,
       "9Y" real,
       "10Y" real,
       "12Y" real,
       "15Y" real,
       "20Y" real,
       "25Y" real,
       "30Y" real);

CREATE TABLE USD_curves(
       effective_date date PRIMARY KEY,
       curve bytea);

CREATE TABLE EUR_curves(
       effective_date date PRIMARY KEY,
       curve bytea);

CREATE TABLE USD_swap_fixings(
       fixing_date date PRIMARY KEY,
       "1y" numeric(5, 3),
       "2y" numeric(5, 3),
       "3y" numeric(5, 3),
       "4y" numeric(5, 3),
       "5y" numeric(5, 3),
       "6y" numeric(5, 3),
       "7y" numeric(5, 3),
       "8y" numeric(5, 3),
       "9y" numeric(5, 3),
       "10y" numeric(5, 3),
       "15y" numeric(5, 3),
       "20y" numeric(5, 3),
       "30y" numeric(5, 3)
);

CREATE TYPE VOL_SOURCE AS ENUM('BVOL', 'CMPN', 'BBIR', 'GFIS');

CREATE TABLE swaption_normal_vol(
	date date,
	"1y" float[18],
	"2y" float[18],
	"3y" float[18],
	"4y" float[18],
	"5y" float[18],
	"6y" float[18],
	"7y" float[18],
	"8y" float[18],
	"9y" float[18],
	"10y" float[18],
	"15y" float[18],
	"20y" float[18],
	"25y" float[18],
	"30y" float[18],
    source VOL_SOURCE,
    PRIMARY KEY(date, source));

CREATE TABLE swaption_lognormal_vol(
	date date,
	"1y" float[18],
	"2y" float[18],
	"3y" float[18],
	"4y" float[18],
	"5y" float[18],
	"6y" float[18],
	"7y" float[18],
	"8y" float[18],
	"9y" float[18],
	"10y" float[18],
	"15y" float[18],
	"20y" float[18],
	"25y" float[18],
	"30y" float[18],
    source VOL_SOURCE,
    PRIMARY KEY(date, source));

CREATE TABLE swaption_quotes(
       quote_id SERIAL PRIMARY KEY,
       ref_id integer REFERENCES swaption_ref_quotes,
       strike float,
       delta_pay float,
       delta_rec float,
       pay_bid float,
       pay_offer float,
       rec_bid float,
       rec_offer float,
       vol float,
       price_vol float,
       gamma float,
       tail float);

ALTER TABLE swaption_quotes ADD CONSTRAINT swaption_quotes_unique_ref_id_strike
UNIQUE (ref_id, strike);

CREATE TABLE swaption_ref_quotes(
       ref_id serial PRIMARY KEY,
       quotedate timestamptz,
       index index_type,
       series smallint,
       expiry date,
       ref float,
       fwdprice float,
       fwdspread  float,
       fwdbpv float,
       quote_source varchar(4));

CREATE INDEX  ON swaption_ref_quotes (quotedate, index, series);
ALTER TABLE swaption_ref_quotes ADD CONSTRAINT swaption_ref_quotes_unique_quotedate_index_series_expiry
UNIQUE (quotedate, index, series, expiry);

CREATE TABLE swaption_calib(
       quote_id integer PRIMARY KEY REFERENCES swaption_quotes,
       vol_payer float,
       vol_receiver float,
       vol_payer_black float,
       vol_receiver_black float);


CREATE TABLE swaption_vol_cube(
       id serial PRIMARY KEY,
       date date NOT NULL,
       cube bytea NOT NULL,
       source vol_source,
       UNIQUE (date, vol_source))