├── .gitignore
├── Strategies
├── 6 year mom pp.js
├── accent.js
├── angry mosquito.js
├── correlation.js
├── dash-of-vol-strategy.js
├── drop the mic w different horizons overlaid.js
├── hurst.0.1.js
├── hurst.js
├── investable vix.js
├── irx mo.js
├── jakarta hurst.js
├── logistic map.js
├── meh-momentum.js
├── mojito.js
├── mom autoc.js
├── momentum-pp.js
├── momentumpp.js
├── momersion lbt twist.js
├── momersion.js
├── oz real steady vol.js
├── pca.js
├── realisedVol.js
├── simplest mean reversion.js
├── simplest momentum strategy.js
├── slmo.js
├── smooth mojito.js
├── steady low vol.js
├── steady vol sp500.js
└── stock correlation.js
├── addMarketDataWorker.js
├── clean
├── calendar.js
├── clean.html
├── d3.v3.min.js
├── lodash.min.js
├── moment.min.js
├── quandl-api-key.js
└── testDrop.csv
├── formatWorker.js
├── graph.css
├── index.html
└── lib
├── codemirror.css
├── codemirror.js
├── d3.min.js
├── dataHelpers.js
├── graphs.js
├── javascript.js
├── jstat.min.js
├── lazy.js
├── lodash.min.js
├── networking2.js
├── numeric-1.2.6.min.js
├── strategyHelpers.js
└── utility.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | *.com
4 | *.class
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 |
10 | # Packages #
11 | ############
12 | # it's better to unpack these files and commit the raw source
13 | # git has its own built in compression methods
14 | *.7z
15 | *.dmg
16 | *.gz
17 | *.iso
18 | *.jar
19 | *.rar
20 | *.tar
21 | *.zip
22 |
23 | # Logs and databases #
24 | ######################
25 | *.log
26 | *.sql
27 | *.sqlite
28 |
29 | # OS generated files #
30 | ######################
31 | .DS_Store
32 | .DS_Store?
33 | ._*
34 | .Spotlight-V100
35 | .Trashes
36 | ehthumbs.db
37 | Thumbs.db
38 |
39 | *~
40 | <<<<<<< HEAD
41 | =======
42 |
43 | lib/listeners.js~
44 |
45 | >>>>>>> addf4672b6b714b22df7b38bbfc9d3c3986500a1
46 | *.js~
47 |
--------------------------------------------------------------------------------
/Strategies/6 year mom pp.js:
--------------------------------------------------------------------------------
1 | var m = data.SPCPMTUP.weekly().lookback(53).returns();
2 |
3 | var mean = jStat.mean(m);
4 | var sd = jStat.stdev(m,true);
5 |
6 | //if 'large' previous return
7 | m[0] >= sd+mean || m[0] <= -sd ?
8 | //then 'bet' on mean reversion
9 | //retain positive bias
10 | weight.SPCPMTUP = -m[0]
11 | :
12 | //else invest a 'constant relevant' amount
13 | weight.SPCPMTUP = 0;
14 |
--------------------------------------------------------------------------------
/Strategies/accent.js:
--------------------------------------------------------------------------------
1 | //AMEX_SPY
2 | //MMM,AXP,AAPL,BA,CAT,CVX,CSCO,KO,DD,XOM,GE,GS,HD,INTC,IBM,JPM,JNJ,MCD,MRK,MSFT,NKE,PFE,PG,TRV,UTX,UNH,VZ,V,WMT,DIS
3 |
4 | weight.AMEX_SPY = 0;
5 | var is = data.AMEX_SPY.lookback(21).returns();
6 | var var_i = jStat(is).variance(true);
7 |
8 | Object
9 | .keys(data)
10 | .filter(
11 | function(k){
12 | return k != 'AMEX_SPY';
13 | }
14 | )
15 | .forEach(
16 | function(k){
17 | var rs = data[k].lookback(21).returns();
18 | var vol = jStat(rs).stdev(true);
19 | var cov = jStat.covariance(rs,is);
20 | var b = cov / var_i;
21 | weight[k] = 1/vol;
22 | weight.AMEX_SPY = weight.AMEX_SPY - b * weight[k];
23 | }
24 | );
25 |
--------------------------------------------------------------------------------
/Strategies/angry mosquito.js:
--------------------------------------------------------------------------------
1 | var vxv = data.VXV.daily().lookback(1).prices()[0];
2 | var vix = data.INDEX_VIX.daily().lookback(1).prices()[0];
3 |
4 | var ivts = vix/vxv;
5 |
6 | if(ivts < 0.91){
7 | weight.VXX = -0.7;
8 | weight.NYSEARCA_VXZ = 0.3;
9 | }
10 | else if (ivts < 0.94){
11 | weight.VXX = -0.32;
12 | weight.NYSEARCA_VXZ = 0.68;
13 | }
14 | else if (ivts < 0.97){
15 | weight.VXX = -0.32;
16 | weight.NYSEARCA_VXZ =0.68;
17 | }
18 | else if (ivts < 1.005){
19 | weight.VXX = -0.28;
20 | weight.NYSEARCA_VXZ = 0.72;
21 | }
22 | else {
23 | weight.VXX = 0;
24 | weight.NYSEARCA_VXZ = 1;
25 | }
26 |
27 | weight.INDEX_GSPC = weight.NYSEARCA_VXZ+weight.VXX;
28 |
29 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a daily horizon
30 | weight.INDEX_IRX = -(weight.INDEX_GSPC+weight.VXX+weight.NYSEARCA_VXZ)/(5*13);
31 |
32 |
--------------------------------------------------------------------------------
/Strategies/correlation.js:
--------------------------------------------------------------------------------
1 | var sp = data.INDEX_GSPC.daily().lookback(500).returns();
2 |
3 | var corr = jStat.corrcoeff(Lazy(sp).rest().toArray(),Lazy(sp).initial().toArray());
4 |
5 | var flag = null;
6 |
7 | sp[0] < 0 ?
8 | flag = -1
9 | :
10 | flag = 1;
11 | ;
12 |
13 | weight.INDEX_GSPC = flag * corr;
14 |
15 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
16 | weight.INDEX_IRX = -weight.INDEX_GSPC*(4/13);
17 |
--------------------------------------------------------------------------------
/Strategies/dash-of-vol-strategy.js:
--------------------------------------------------------------------------------
1 | var realisedVol = jStat( data.INDEX_GSPC.daily().lookback(5).returns() ).stdev(true)*100*Math.sqrt(252);
2 |
3 | weight.INDEX_VIX = 1/realisedVol;
4 |
5 | weight.INDEX_GSPC = 1;
6 |
7 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
8 | weight.INDEX_IRX = -(weight.INDEX_GSPC+weight.INDEX_VIX)*(4/13);
9 |
--------------------------------------------------------------------------------
/Strategies/drop the mic w different horizons overlaid.js:
--------------------------------------------------------------------------------
1 | //Two years of history
2 | var d = data.INDEX_GSPC.daily().lookback(500).returns();
3 | var w = data.INDEX_GSPC.weekly().lookback(100).returns();
4 | var m = data.INDEX_GSPC.monthly().lookback(25).returns();
5 | var q = data.INDEX_GSPC.quarterly().lookback(9).returns();
6 |
7 | //Correlations
8 | var cd = jStat.corrcoeff( Lazy(d).initial().toArray(), Lazy(d).rest().toArray() );
9 | var cw = jStat.corrcoeff( Lazy(w).initial().toArray(), Lazy(w).rest().toArray() );
10 | var cm = jStat.corrcoeff( Lazy(m).initial().toArray(), Lazy(m).rest().toArray() );
11 | var cq = jStat.corrcoeff( Lazy(q).initial().toArray(), Lazy(q).rest().toArray() );
12 |
13 | //Results
14 | var result = cd * d[0] / Math.abs(d[0] + 0.00000000001);
15 | result = result + cw * w[0] / Math.abs(w[0] + 0.00000000001)/5;
16 | result = result + cm * m[0] / Math.abs(m[0] + 0.00000000001)/21;
17 | result = result + cq * q[0] / Math.abs(q[0] + 0.00000000001)/63;
18 |
19 | weight.INDEX_GSPC = result;
--------------------------------------------------------------------------------
/Strategies/hurst.0.1.js:
--------------------------------------------------------------------------------
1 | var lb = 300;
2 |
3 | var v = data.INDEX_GSPC.daily().lookback(lb+1).returns();
4 |
5 | var xx = Lazy
6 | .range(1,Math.floor(Math.log2(lb/3))+1)
7 | .map(
8 | function(i){
9 | return Math.pow(2,i);
10 | }
11 | )
12 | ;
13 |
14 | var yy = xx
15 | .map(
16 | function(n){
17 | var rs = Lazy(v)
18 | .chunk(Math.floor(lb/n))
19 | .filter(
20 | function(i){
21 | return i.length >= Math.floor(lb/n);
22 | }
23 | )
24 | .map(
25 | function(t){
26 | var y = numeric.subVS(t,jStat.mean(t));
27 | var s = jStat.stdev(y,true);
28 | var z = y.reduce(
29 | function(a,t){
30 | if (a.length === 0) {
31 | return [t];
32 | }
33 | else {
34 | return a.concat(t+a[a.length-1]);
35 | }
36 | }
37 | , []
38 | );
39 | var r = Lazy(z).max() - Lazy(z).min();
40 | return r/s;
41 | }
42 | )
43 | .toArray();
44 | return Math.log(jStat.mean(rs));
45 | }
46 | )
47 | .toArray()
48 | ;
49 |
50 | var ln_xx = xx.map(
51 | function(i){
52 | return Math.log(i);
53 | }
54 | )
55 | .toArray();
56 |
57 | var h =
58 | jStat.covariance(
59 | yy,
60 | ln_xx
61 | )
62 | /
63 | jStat.variance(
64 | ln_xx,true
65 | );
66 |
67 | var signal = (Math.abs(h)-0.5)/0.5;
68 |
69 | //var r2 = Math.pow(jStat.corrcoeff(yy,ln_xx),2);
70 |
71 | var flag = 0;
72 |
73 | v[0] < 0 ? flag = -1 : flag = 1;
74 |
75 | weight.INDEX_GSPC = signal * flag;
76 |
--------------------------------------------------------------------------------
/Strategies/hurst.js:
--------------------------------------------------------------------------------
1 | var lb = 300;
2 |
3 | var v = data.INDEX_GSPC.daily().lookback(lb+1).returns();
4 |
5 | //find max poss range per lookback size
6 | //ensure bulletproofness
7 | var xx = Lazy.range(2,12);
8 | var yy = xx
9 | .map(
10 | function(n){
11 | var rs = Lazy(v)
12 | .chunk(lb/n)
13 | .map(
14 | function(t){
15 | var y = numeric.subVS(t,jStat.mean(t));
16 | var s = jStat.stdev(y,true);
17 | var z = y.reduce(
18 | function(a,t){
19 | if (a.length === 0) {
20 | return [t];
21 | }
22 | else {
23 | return a.concat(t+a[a.length-1]);
24 | }
25 | }
26 | , []
27 | );
28 | var r = Lazy(z).max() - Lazy(z).min();
29 | return r/s;
30 | }
31 | )
32 | .toArray();
33 | return Math.log(jStat.mean(rs));
34 | }
35 | )
36 | .toArray()
37 | ;
38 |
39 | var ln_xx = xx.map(
40 | function(i){
41 | return Math.log(i);
42 | }
43 | )
44 | .toArray();
45 |
46 | var h =
47 | jStat.covariance(
48 | yy,
49 | ln_xx
50 | )
51 | /
52 | jStat.variance(
53 | ln_xx
54 | );
55 |
56 | //h.print();
57 |
58 | var signal = (Math.abs(h)-0.5)/0.5;
59 |
60 | //var r2 = Math.pow(jStat.corrcoeff(yy,ln_xx),2);
61 |
62 | var flag = 0;
63 |
64 | v[0] < 0 ? flag = -1 : flag = 1;
65 |
66 | weight.INDEX_GSPC = signal * flag
67 |
68 |
--------------------------------------------------------------------------------
/Strategies/investable vix.js:
--------------------------------------------------------------------------------
1 | var v = data.SPVXTSTR.daily().lookback(1).prices()[0];
2 | weight.SPVXTSTR = 360000/v;
3 | weight.INDEX_GSPC = 1;
4 | weight.INDEX_IRX = -(weight.INDEX_GSPC+weight.SPVXTSTR)*(4/13);
--------------------------------------------------------------------------------
/Strategies/irx mo.js:
--------------------------------------------------------------------------------
1 | var i = data.INDEX_IRX.daily().lookback(2).returns()[0];
2 | weight.INDEX_IRX = Math.abs(i)/(i+0.00000000001);
--------------------------------------------------------------------------------
/Strategies/jakarta hurst.js:
--------------------------------------------------------------------------------
1 | var lb = 30;
2 |
3 | var v = data.INDEX_JKSE.daily().lookback(lb+1).returns();
4 |
5 | var xx = Lazy
6 | .range(1,Math.floor(Math.log2(lb/3))+1)
7 | .map(
8 | function(i){
9 | return Math.pow(2,i);
10 | }
11 | )
12 | ;
13 |
14 | var yy = xx
15 | .map(
16 | function(n){
17 | var rs = Lazy(v)
18 | .chunk(Math.floor(lb/n))
19 | .filter(
20 | function(i){
21 | return i.length >= Math.floor(lb/n);
22 | }
23 | )
24 | .map(
25 | function(t){
26 | var y = numeric.subVS(t,jStat.mean(t));
27 | var s = jStat.stdev(y,true);
28 | var z = y.reduce(
29 | function(a,t){
30 | if (a.length === 0) {
31 | return [t];
32 | }
33 | else {
34 | return a.concat(t+a[a.length-1]);
35 | }
36 | }
37 | , []
38 | );
39 | var r = Lazy(z).max() - Lazy(z).min();
40 | return r/s;
41 | }
42 | )
43 | .toArray();
44 | return Math.log(jStat.mean(rs));
45 | }
46 | )
47 | .toArray()
48 | ;
49 |
50 | var ln_xx = xx.map(
51 | function(i){
52 | return Math.log(i);
53 | }
54 | )
55 | .toArray();
56 |
57 | var h =
58 | jStat.covariance(
59 | yy,
60 | ln_xx
61 | )
62 | /
63 | jStat.variance(
64 | ln_xx,true
65 | );
66 |
67 | var signal = (Math.abs(h)-0.5)/0.5;
68 |
69 | //var r2 = Math.pow(jStat.corrcoeff(yy,ln_xx),2);
70 |
71 | var flag = 0;
72 |
73 | v[0] < 0 ? flag = -1 : flag = 1;
74 |
75 | weight.INDEX_JKSE = signal * flag;
--------------------------------------------------------------------------------
/Strategies/logistic map.js:
--------------------------------------------------------------------------------
1 | var w = null;
2 |
3 | history.INDEX_GSPC_weight != null ? w = history.INDEX_GSPC_weight[0] : w = 0.511;
4 |
5 | weight.INDEX_GSPC = 4 * w * (1 - w);
6 |
--------------------------------------------------------------------------------
/Strategies/meh-momentum.js:
--------------------------------------------------------------------------------
1 | //loop keys
2 | //find max
3 |
4 | var maxAsset = Object
5 | .keys(data)
6 | .reduce(
7 | function(a,k){
8 | var m = data[k].period(252).lookback(2).returns()[0];
9 | a.currentMax < m ? r = {key:k, currentMax: m} : r = a;
10 | return r;
11 | }
12 | ,{key:"",currentMax:-Infinity}
13 | )
14 | .key;
15 |
16 | weight[maxAsset] = 1;
17 |
18 | weight.INDEX_IRX = -1*(4/13);
19 |
20 |
--------------------------------------------------------------------------------
/Strategies/mojito.js:
--------------------------------------------------------------------------------
1 | var vxv = data.VXV.daily().lookback(1).prices()[0];
2 | var vix = data.INDEX_VIX.daily().lookback(1).prices()[0];
3 |
4 | var ivts = vix/vxv;
5 |
6 | ivts.print();
7 |
8 | if(ivts < 0.91){
9 | weight.VXX = -0.7;
10 | weight.NYSEARCA_VXZ = 0.3;
11 | }
12 | else if (ivts < 0.94){
13 | weight.VXX = -0.32;
14 | weight.NYSEARCA_VXZ = 0.68;
15 | }
16 | else if (ivts < 0.97){
17 | weight.VXX = -0.32;
18 | weight.NYSEARCA_VXZ =0.68;
19 | }
20 | else if (ivts < 1.005){
21 | weight.VXX = -0.28;
22 | weight.NYSEARCA_VXZ = 0.72;
23 | }
24 | else {
25 | weight.VXX = 0;
26 | weight.NYSEARCA_VXZ = 1;
27 | }
28 |
29 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
30 | weight.INDEX_IRX = -(weight.VXX+weight.NYSEARCA_VXZ)/(5*13);
31 |
32 |
--------------------------------------------------------------------------------
/Strategies/mom autoc.js:
--------------------------------------------------------------------------------
1 | var m = data.SPCPMTUP.daily().lookback(90).returns();
2 |
3 | var c = jStat.corrcoeff( Lazy(m).initial().toArray(), Lazy(m).rest().toArray() );
4 |
5 | var f = 0;
6 | m[0] < 0 ? f = -1 : f = 0;
7 |
8 | weight.SPCPMTUP = c*f;
9 |
10 |
--------------------------------------------------------------------------------
/Strategies/momentum-pp.js:
--------------------------------------------------------------------------------
1 | var m = data.SPCPMTUP.monthly().lookback(2).returns()[0];
2 |
3 | m >= 0.025 || m <= -0.025 ?
4 | weight.SPCPMTUP = -m
5 | :
6 | weight.SPCPMTUP = 0.2;
7 |
8 | //
9 |
10 | var m = data.NYSEARCA_MTUM.monthly().lookback(2).returns()[0];
11 |
12 | m >= 0.025 || m <= -0.025 ?
13 | weight.NYSEARCA_MTUM = -m
14 | :
15 | weight.NYSEARCA_MTUM = 0.2;
16 |
17 |
--------------------------------------------------------------------------------
/Strategies/momentumpp.js:
--------------------------------------------------------------------------------
1 |
2 | var m = data.NYSEARCA_MTUM.monthly().lookback(2).returns()[0];
3 |
4 | var mean = 0.013;
5 | var sd = 0.03;
6 |
7 | m >= 2*sd || m <= -2*sd+mean ?
8 | weight.NYSEARCA_MTUM = -m
9 | :
10 | weight.NYSEARCA_MTUM = mean;
11 |
12 |
--------------------------------------------------------------------------------
/Strategies/momersion lbt twist.js:
--------------------------------------------------------------------------------
1 | var Mc = data
2 | .AMEX_SPY
3 | .daily()
4 | .lookback(21)
5 | .returns()
6 | .reduce(
7 | function(a,c){
8 | //increment in the prescence of momentum
9 | a[0]*c > 0 ? a[1] = a[1]+1 : null;
10 | //update 'prev' return
11 | a[0] = c;
12 | return a;
13 | }
14 | //[prev return, mo count]
15 | ,[0,0]
16 | )
17 | [1];
18 |
19 | weight.AMEX_SPY = Mc/19;
20 |
--------------------------------------------------------------------------------
/Strategies/momersion.js:
--------------------------------------------------------------------------------
1 | var Mc = data
2 | .AMEX_SPY
3 | .daily()
4 | .lookback(20)
5 | .returns()
6 | .reduce(
7 | function(a,c){
8 | //increment in the prescence of momentum
9 | a[0]*c > 0 ? a[1] = a[1]+1 : null;
10 | //update 'prev' return
11 | a[0] = c;
12 | return a;
13 | }
14 | //[prev return, mo count]
15 | ,[0,0]
16 | )
17 | [1];
18 |
19 | //copy over previous weight
20 | if (history.AMEX_SPY_weight != null) {
21 | weight.AMEX_SPY = history.AMEX_SPY_weight[0]
22 | }
23 | else {
24 | //default
25 | weight.AMEX_SPY = 0;
26 | }
27 |
28 | //buy
29 | Mc/19 < 0.3 ? weight.AMEX_SPY = 1 : null;
30 |
31 | //sell
32 | Mc/19 > 0.7 ? weight.AMEX_SPY = 0 : null;
--------------------------------------------------------------------------------
/Strategies/oz real steady vol.js:
--------------------------------------------------------------------------------
1 | var a = data.INDEX_AORD.daily().lookback(6).returns();
2 | weight.INDEX_AORD = 0.005/jStat.stdev(a,true);
--------------------------------------------------------------------------------
/Strategies/pca.js:
--------------------------------------------------------------------------------
1 | var lb = 63;
2 |
3 | var bb = data.AMEX_TLT.daily().lookback(lb).returns();
4 | var cc = data.AMEX_SPY.daily().lookback(lb).returns();
5 | var dd = data.AMEX_GLD.daily().lookback(lb).returns();
6 |
7 | var pss = [bb,cc,dd];
8 |
9 | //demean
10 | var pss_dm = pss.map(
11 | function(i){
12 | var m = jStat(i).mean();
13 | return i.map(function(j){return j-m;});
14 | }
15 | )
16 |
17 | //*********************************************
18 | //find r2, and return 'goodness of spread/diversification' resul
19 | var diversificationMeasure = function(ps){
20 | var r = numeric.svd( numeric.transpose(ps) )
21 | .S
22 | .map(
23 | function(i){
24 | return Math.pow(i,2)
25 | }
26 | )
27 | ;
28 | var sum = r.reduce(function(a,c){return a+c;});
29 |
30 | return r.map(function(i){return i/sum;}).reduce(function(a,c){return a * c;},1);
31 | }
32 |
33 | //*********************************************
34 | //optimise
35 | var objective = function(x){
36 | //shock
37 | return - diversificationMeasure( numeric.dot(numeric.diag(x), pss_dm) );
38 | }
39 |
40 | //start at equal weighting
41 | var sol = numeric.uncmin(objective,numeric.rep([pss.length],1/pss.length)).solution;
42 | sol.print();
43 | //*********************************************
44 |
45 | weight.AMEX_TLT = sol[0];
46 | weight.AMEX_SPY = sol[1];
47 | weight.AMEX_GLD = sol[2];
48 | //netting, in order to calculate sharpe
49 | weight.INDEX_IRX = -sol.reduce(function(a,c){return a+c;},0)*(4/13);
50 |
--------------------------------------------------------------------------------
/Strategies/realisedVol.js:
--------------------------------------------------------------------------------
1 | var realisedVol = jStat( data.INDEX_GSPC.daily().lookback(11).returns() ).stdev(true)*100*Math.sqrt(21);
2 | //var vix = data.INDEX_GSPC.daily().lookback(1).prices();
3 |
4 | weight.INDEX_GSPC = 1/realisedVol;
5 | //weight.INDEX_GSPC = 1/vix;
6 |
7 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
8 | weight.INDEX_IRX = -weight.INDEX_GSPC*(4/13);
9 |
10 |
--------------------------------------------------------------------------------
/Strategies/simplest mean reversion.js:
--------------------------------------------------------------------------------
1 |
2 | var f = data.NYSEARCA_FXI.daily().lookback(2).returns()[0];
3 | weight.NYSEARCA_FXI = -f/Math.abs(f+0.0000000001);
4 |
5 | <<<<<<< HEAD
6 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
7 | weight.INDEX_IRX = -weight.NYSEARCA_FXI*(4/13);
8 | =======
9 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a daily horizon
10 | weight.INDEX_IRX = -weight.NYSEARCA_FXI/(5*13);
11 | >>>>>>> addf4672b6b714b22df7b38bbfc9d3c3986500a1
12 |
13 |
--------------------------------------------------------------------------------
/Strategies/simplest momentum strategy.js:
--------------------------------------------------------------------------------
1 |
2 | var s = data.INDEX_GSPC.daily().lookback(2).returns()[0];
3 | weight.INDEX_GSPC = Math.abs(s)/(s+0.00000001);
4 | weight.INDEX_IRX = -weight.INDEX_GSPC/(5*13);
5 |
6 |
--------------------------------------------------------------------------------
/Strategies/slmo.js:
--------------------------------------------------------------------------------
1 |
2 | var r = data.INDEX_GSPC.daily().lookback(500).returns();
3 |
4 | var c = jStat.corrcoeff( Lazy(r).initial().toArray(), Lazy(r).rest().toArray() );
5 |
6 | weight.INDEX_GSPC = 0;
7 |
8 | //mo
9 | r[0] > 0 && c > 0 ? weight.INDEX_GSPC = 1 : null;
10 |
11 | //mr
12 | r[0] < 0 && c < 0 ? weight.INDEX_GSPC = 1 : null;
13 |
--------------------------------------------------------------------------------
/Strategies/smooth mojito.js:
--------------------------------------------------------------------------------
1 | var vxv = data.VXV.daily().lookback(1).prices()[0];
2 | var vix = data.INDEX_VIX.daily().lookback(1).prices()[0];
3 |
4 | var ivts = vix/vxv;
5 |
6 | weight.VXX = 11*Math.pow(ivts,2)-17*ivts+5.8;
7 | weight.NYSEARCA_VXZ = 11*Math.pow(ivts,2)-17*ivts+6.8;
8 |
9 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
10 | weight.INDEX_IRX = -(weight.VXX+weight.NYSEARCA_VXZ)*4/13;
--------------------------------------------------------------------------------
/Strategies/steady low vol.js:
--------------------------------------------------------------------------------
1 | var a = data.SP5LVI.daily().lookback(6).returns();
2 | weight.SP5LVI = 0.0057/jStat.stdev(a,true);
--------------------------------------------------------------------------------
/Strategies/steady vol sp500.js:
--------------------------------------------------------------------------------
1 | var v = data.INDEX_GSPC.daily().lookback(43).returns();
2 | weight.INDEX_GSPC = 1/jStat.stdev(v,true);
3 | weight.INDEX_IRX = -weight.INDEX_GSPC * (4/13);
--------------------------------------------------------------------------------
/Strategies/stock correlation.js:
--------------------------------------------------------------------------------
1 | var sp = data.INDEX_GSPC.daily().lookback(500).returns();
2 |
3 | var corr = jStat.corrcoeff(Lazy(sp).rest().toArray(),Lazy(sp).initial().toArray());
4 |
5 | var flag = null;
6 |
7 | sp[0] < 0 ?
8 | flag = -1
9 | :
10 | flag = 1;
11 | ;
12 |
13 | weight.INDEX_GSPC = flag * corr;
14 |
15 | //13 week t-bill yield index used to calculate Sharpe ratio. Scaled for a monthly horizon
16 | weight.INDEX_IRX = -weight.INDEX_GSPC*(4/13);
17 |
--------------------------------------------------------------------------------
/addMarketDataWorker.js:
--------------------------------------------------------------------------------
1 | importScripts('lib/lazy.js');
2 | importScripts('lib/strategyHelpers.js');
3 | importScripts('lib/dataHelpers.js');
4 | importScripts('lib/networking2.js');
5 | importScripts('lib/utility.js');
6 |
7 |
8 |
9 |
10 | //*****************************************************
11 |
12 | self.addEventListener(
13 | 'message',
14 | function(e) {
15 | var d = e.data;
16 |
17 | var prices =
18 | //map data from quandl
19 | getQuandlCall(
20 | d.source,
21 | d.ticker,
22 | d.key
23 | )
24 | .xhr()
25 | .map(
26 | function(i){
27 | var r = null;
28 | d.y == true ?
29 | r = {ticker: d.ticker, date: new Date(i[0]), datum:i[1].yieldToDsft()}
30 | :
31 | r = {ticker: d.ticker, date: new Date(i[0]), datum:i[1]};
32 | return r;
33 | }
34 | )
35 | ;
36 |
37 | //console.log(prices);
38 |
39 | self.postMessage({ticker:d.ticker,prices:prices,horizon:d.horizon});
40 | },
41 | false
42 | );
43 |
44 |
45 | //*****************************************************
46 |
47 |
--------------------------------------------------------------------------------
/clean/calendar.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | //need moment.js library
4 |
5 | const easterMonday = y =>
6 | {
7 | const emDaysByYear =
8 | [
9 | 98, 90, 103, 95, 114, 106, 91, 111, 102, // 1901-1909
10 | 87, 107, 99, 83, 103, 95, 115, 99, 91, 111, // 1910-1919
11 | 96, 87, 107, 92, 112, 103, 95, 108, 100, 91, // 1920-1929
12 | 111, 96, 88, 107, 92, 112, 104, 88, 108, 100, // 1930-1939
13 | 85, 104, 96, 116, 101, 92, 112, 97, 89, 108, // 1940-1949
14 | 100, 85, 105, 96, 109, 101, 93, 112, 97, 89, // 1950-1959
15 | 109, 93, 113, 105, 90, 109, 101, 86, 106, 97, // 1960-1969
16 | 89, 102, 94, 113, 105, 90, 110, 101, 86, 106, // 1970-1979
17 | 98, 110, 102, 94, 114, 98, 90, 110, 95, 86, // 1980-1989
18 | 106, 91, 111, 102, 94, 107, 99, 90, 103, 95, // 1990-1999
19 | 115, 106, 91, 111, 103, 87, 107, 99, 84, 103, // 2000-2009
20 | 95, 115, 100, 91, 111, 96, 88, 107, 92, 112, // 2010-2019
21 | 104, 95, 108, 100, 92, 111, 96, 88, 108, 92, // 2020-2029
22 | 112, 104, 89, 108, 100, 85, 105, 96, 116, 101, // 2030-2039
23 | 93, 112, 97, 89, 109, 100, 85, 105, 97, 109, // 2040-2049
24 | 101, 93, 113, 97, 89, 109, 94, 113, 105, 90, // 2050-2059
25 | 110, 101, 86, 106, 98, 89, 102, 94, 114, 105, // 2060-2069
26 | 90, 110, 102, 86, 106, 98, 111, 102, 94, 114, // 2070-2079
27 | 99, 90, 110, 95, 87, 106, 91, 111, 103, 94, // 2080-2089
28 | 107, 99, 91, 103, 95, 115, 107, 91, 111, 103, // 2090-2099
29 | 88, 108, 100, 85, 105, 96, 109, 101, 93, 112, // 2100-2109
30 | 97, 89, 109, 93, 113, 105, 90, 109, 101, 86, // 2110-2119
31 | 106, 97, 89, 102, 94, 113, 105, 90, 110, 101, // 2120-2129
32 | 86, 106, 98, 110, 102, 94, 114, 98, 90, 110, // 2130-2139
33 | 95, 86, 106, 91, 111, 102, 94, 107, 99, 90, // 2140-2149
34 | 103, 95, 115, 106, 91, 111, 103, 87, 107, 99, // 2150-2159
35 | 84, 103, 95, 115, 100, 91, 111, 96, 88, 107, // 2160-2169
36 | 92, 112, 104, 95, 108, 100, 92, 111, 96, 88, // 2170-2179
37 | 108, 92, 112, 104, 89, 108, 100, 85, 105, 96, // 2180-2189
38 | 116, 101, 93, 112, 97, 89, 109, 100, 85, 105 // 2190-2199
39 | ];
40 |
41 | return emDaysByYear[ y - 1901 ];
42 | }
43 |
44 | const isWeekend =
45 | w =>
46 | (w === "Saturday" || w === "Sunday")
47 | ? true
48 | : false;
49 |
50 |
51 | const isBusinessDayNYSE =
52 | input => {
53 | const date = moment(input);
54 |
55 | const w = date.format('dddd');
56 | const d = date.format('D');
57 | const dd = date.format('DDD');
58 | const m = date.format('MMMM');
59 | const y = date.format('YYYY');
60 |
61 | const em = easterMonday( date.format('YYYY') );
62 |
63 | if (
64 | isWeekend(w)
65 | // New Year's Day (possibly moved to Monday if on Sunday)
66 | || ((d == 1 || (d == 2 && w == "Monday")) && m == "January")
67 | // Washington's birthday (third Monday in February)
68 | || ((d >= 15 && d <= 21) && w == "Monday" && m == "February")
69 | // Good Friday
70 | || (dd == em-3)
71 | // Memorial Day (last Monday in May)
72 | || (d >= 25 && w == "Monday" && m == "May")
73 | // Independence Day (Monday if Sunday or Friday if Saturday)
74 | || ((d == 4 || (d == 5 && w == "Monday") ||
75 | (d == 3 && w == "Friday")) && m == "July")
76 | // Labor Day (first Monday in September)
77 | || (d <= 7 && w == "Monday" && m == "September")
78 | // Thanksgiving Day (fourth Thursday in November)
79 | || ((d >= 22 && d <= 28) && w == "Thursday" && m == "November")
80 | // Christmas (Monday if Sunday or Friday if Saturday)
81 | || ((d == 25 || (d == 26 && w == "Monday") ||
82 | (d == 24 && w == "Friday")) && m == "December")
83 | ){
84 | return false;
85 | }
86 | else if (y >= 1998 && (d >= 15 && d <= 21) && w == "Monday" && m == "January")
87 | // Martin Luther King's birthday (third Monday in January)
88 | {return false;}
89 | else if ((y <= 1968 || (y <= 1980 && y % 4 == 0)) && m == "November"
90 | && d <= 7 && w == "Tuesday")
91 | // Presidential election days
92 | {return false;}
93 | // Special closings
94 | else if (// Hurricane Sandy
95 | (y == 2012 && m == "October" && (d == 29 || d == 30))
96 | // President Ford's funeral
97 | || (y == 2007 && m == "January" && d == 2)
98 | // President Reagan's funeral
99 | || (y == 2004 && m == "June" && d == 11)
100 | // September 11-14, 2001
101 | || (y == 2001 && m == "September" && (11 <= d && d <= 14))
102 | // President Nixon's funeral
103 | || (y == 1994 && m == "April" && d == 27)
104 | // Hurricane Gloria
105 | || (y == 1985 && m == "September" && d == 27)
106 | // 1977 Blackout
107 | || (y == 1977 && m == "July" && d == 14)
108 | // Funeral of former President Lyndon B. Johnson.
109 | || (y == 1973 && m == "January" && d == 25)
110 | // Funeral of former President Harry S. Truman
111 | || (y == 1972 && m == "December" && d == 28)
112 | // National Day of Participation for the lunar exploration.
113 | || (y == 1969 && m == "July" && d == 21)
114 | // Funeral of former President Eisenhower.
115 | || (y == 1969 && m == "March" && d == 31)
116 | // Closed all day - heavy snow.
117 | || (y == 1969 && m == "February" && d == 10)
118 | // Day after Independence Day.
119 | || (y == 1968 && m == "July" && d == 5)
120 | // June 12-Dec. 31, 1968
121 | // Four day week (closed on Wednesdays) - Paperwork Crisis
122 | || (y == 1968 && dd >= 163 && w == "Wednesday")
123 | // Day of mourning for Martin Luther King Jr.
124 | || (y == 1968 && m == "April" && d == 9)
125 | // Funeral of President Kennedy
126 | || (y == 1963 && m == "November" && d == 25)
127 | // Day before Decoration Day
128 | || (y == 1961 && m == "May" && d == 29)
129 | // Day after Christmas
130 | || (y == 1958 && m == "December" && d == 26)
131 | // Christmas Eve
132 | || ((y == 1954 || y == 1956 || y == 1965)
133 | && m == "December" && d == 24)
134 | ) {return false;}
135 | else {
136 | return true;
137 | };
138 | }
139 |
--------------------------------------------------------------------------------
/clean/clean.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
88 |
89 |
--------------------------------------------------------------------------------
/clean/moment.min.js:
--------------------------------------------------------------------------------
1 | //! moment.js
2 | //! version : 2.11.0
3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4 | //! license : MIT
5 | //! momentjs.com
6 | !function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Qc.apply(null,arguments)}function b(a){Qc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c0)for(c in Sc)d=Sc[c],e=b[d],m(e)||(a[d]=e);return a}function o(b){n(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),Tc===!1&&(Tc=!0,a.updateOffset(this),Tc=!1)}function p(a){return a instanceof o||null!=a&&null!=a._isAMomentObject}function q(a){return 0>a?Math.ceil(a):Math.floor(a)}function r(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=q(b)),c}function s(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&r(a[d])!==r(b[d]))&&g++;return g+f}function t(){}function u(a){return a?a.toLowerCase().replace("_","-"):a}function v(a){for(var b,c,d,e,f=0;f0;){if(d=w(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&s(e,c,!0)>=b-1)break;b--}f++}return null}function w(a){var b=null;if(!Uc[a]&&!m(module)&&module&&module.exports)try{b=Rc._abbr,require("./locale/"+a),x(b)}catch(c){}return Uc[a]}function x(a,b){var c;return a&&(c=m(b)?z(a):y(a,b),c&&(Rc=c)),Rc._abbr}function y(a,b){return null!==b?(b.abbr=a,Uc[a]=Uc[a]||new t,Uc[a].set(b),x(a),Uc[a]):(delete Uc[a],null)}function z(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Rc;if(!c(a)){if(b=w(a))return b;a=[a]}return v(a)}function A(a,b){var c=a.toLowerCase();Vc[c]=Vc[c+"s"]=Vc[b]=a}function B(a){return"string"==typeof a?Vc[a]||Vc[a.toLowerCase()]:void 0}function C(a){var b,c,d={};for(c in a)f(a,c)&&(b=B(c),b&&(d[b]=a[c]));return d}function D(a){return a instanceof Function||"[object Function]"===Object.prototype.toString.call(a)}function E(b,c){return function(d){return null!=d?(G(this,b,d),a.updateOffset(this,c),this):F(this,b)}}function F(a,b){return a.isValid()?a._d["get"+(a._isUTC?"UTC":"")+b]():NaN}function G(a,b,c){a.isValid()&&a._d["set"+(a._isUTC?"UTC":"")+b](c)}function H(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=B(a),D(this[a]))return this[a](b);return this}function I(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function J(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Zc[a]=e),b&&(Zc[b[0]]=function(){return I(e.apply(this,arguments),b[1],b[2])}),c&&(Zc[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function K(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function L(a){var b,c,d=a.match(Wc);for(b=0,c=d.length;c>b;b++)Zc[d[b]]?d[b]=Zc[d[b]]:d[b]=K(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function M(a,b){return a.isValid()?(b=N(b,a.localeData()),Yc[b]=Yc[b]||L(b),Yc[b](a)):a.localeData().invalidDate()}function N(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Xc.lastIndex=0;d>=0&&Xc.test(a);)a=a.replace(Xc,c),Xc.lastIndex=0,d-=1;return a}function O(a,b,c){pd[a]=D(b)?b:function(a){return a&&c?c:b}}function P(a,b){return f(pd,a)?pd[a](b._strict,b._locale):new RegExp(Q(a))}function Q(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function R(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=r(a)}),c=0;cd;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function Y(a,b){var c;return a.isValid()?"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),U(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a):a}function Z(b){return null!=b?(Y(this,b),a.updateOffset(this,!0),this):F(this,"Month")}function $(){return U(this.year(),this.month())}function _(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[sd]<0||c[sd]>11?sd:c[td]<1||c[td]>U(c[rd],c[sd])?td:c[ud]<0||c[ud]>24||24===c[ud]&&(0!==c[vd]||0!==c[wd]||0!==c[xd])?ud:c[vd]<0||c[vd]>59?vd:c[wd]<0||c[wd]>59?wd:c[xd]<0||c[xd]>999?xd:-1,j(a)._overflowDayOfYear&&(rd>b||b>td)&&(b=td),j(a)._overflowWeeks&&-1===b&&(b=yd),j(a)._overflowWeekday&&-1===b&&(b=zd),j(a).overflow=b),a}function aa(b){a.suppressDeprecationWarnings===!1&&!m(console)&&console.warn&&console.warn("Deprecation warning: "+b)}function ba(a,b){var c=!0;return g(function(){return c&&(aa(a+"\nArguments: "+Array.prototype.slice.call(arguments).join(", ")+"\n"+(new Error).stack),c=!1),b.apply(this,arguments)},b)}function ca(a,b){Dd[a]||(aa(b),Dd[a]=!0)}function da(a){var b,c,d,e,f,g,h=a._i,i=Ed.exec(h)||Fd.exec(h);if(i){for(j(a).iso=!0,b=0,c=Hd.length;c>b;b++)if(Hd[b][1].exec(i[1])){e=Hd[b][0],d=Hd[b][2]!==!1;break}if(null==e)return void(a._isValid=!1);if(i[3]){for(b=0,c=Id.length;c>b;b++)if(Id[b][1].exec(i[3])){f=(i[2]||" ")+Id[b][0];break}if(null==f)return void(a._isValid=!1)}if(!d&&null!=f)return void(a._isValid=!1);if(i[4]){if(!Gd.exec(i[4]))return void(a._isValid=!1);g="Z"}a._f=e+(f||"")+(g||""),sa(a)}else a._isValid=!1}function ea(b){var c=Jd.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(da(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function fa(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 100>a&&a>=0&&isFinite(h.getFullYear())&&h.setFullYear(a),h}function ga(a){var b=new Date(Date.UTC.apply(null,arguments));return 100>a&&a>=0&&isFinite(b.getUTCFullYear())&&b.setUTCFullYear(a),b}function ha(a){return ia(a)?366:365}function ia(a){return a%4===0&&a%100!==0||a%400===0}function ja(){return ia(this.year())}function ka(a,b,c){var d=7+b-c,e=(7+ga(a,0,d).getUTCDay()-b)%7;return-e+d-1}function la(a,b,c,d,e){var f,g,h=(7+c-d)%7,i=ka(a,d,e),j=1+7*(b-1)+h+i;return 0>=j?(f=a-1,g=ha(f)+j):j>ha(a)?(f=a+1,g=j-ha(a)):(f=a,g=j),{year:f,dayOfYear:g}}function ma(a,b,c){var d,e,f=ka(a.year(),b,c),g=Math.floor((a.dayOfYear()-f-1)/7)+1;return 1>g?(e=a.year()-1,d=g+na(e,b,c)):g>na(a.year(),b,c)?(d=g-na(a.year(),b,c),e=a.year()+1):(e=a.year(),d=g),{week:d,year:e}}function na(a,b,c){var d=ka(a,b,c),e=ka(a+1,b,c);return(ha(a)-d+e)/7}function oa(a,b,c){return null!=a?a:null!=b?b:c}function pa(b){var c=new Date(a.now());return b._useUTC?[c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate()]:[c.getFullYear(),c.getMonth(),c.getDate()]}function qa(a){var b,c,d,e,f=[];if(!a._d){for(d=pa(a),a._w&&null==a._a[td]&&null==a._a[sd]&&ra(a),a._dayOfYear&&(e=oa(a._a[rd],d[rd]),a._dayOfYear>ha(e)&&(j(a)._overflowDayOfYear=!0),c=ga(e,0,a._dayOfYear),a._a[sd]=c.getUTCMonth(),a._a[td]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[ud]&&0===a._a[vd]&&0===a._a[wd]&&0===a._a[xd]&&(a._nextDay=!0,a._a[ud]=0),a._d=(a._useUTC?ga:fa).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[ud]=24)}}function ra(a){var b,c,d,e,f,g,h,i;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=oa(b.GG,a._a[rd],ma(Aa(),1,4).year),d=oa(b.W,1),e=oa(b.E,1),(1>e||e>7)&&(i=!0)):(f=a._locale._week.dow,g=a._locale._week.doy,c=oa(b.gg,a._a[rd],ma(Aa(),f,g).year),d=oa(b.w,1),null!=b.d?(e=b.d,(0>e||e>6)&&(i=!0)):null!=b.e?(e=b.e+f,(b.e<0||b.e>6)&&(i=!0)):e=f),1>d||d>na(c,f,g)?j(a)._overflowWeeks=!0:null!=i?j(a)._overflowWeekday=!0:(h=la(c,d,e,f,g),a._a[rd]=h.year,a._dayOfYear=h.dayOfYear)}function sa(b){if(b._f===a.ISO_8601)return void da(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=N(b._f,b._locale).match(Wc)||[],c=0;c0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),Zc[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),T(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[ud]<=12&&b._a[ud]>0&&(j(b).bigHour=void 0),b._a[ud]=ta(b._locale,b._a[ud],b._meridiem),qa(b),_(b)}function ta(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function ua(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;ef)&&(d=f,c=b));g(a,c||b)}function va(a){if(!a._d){var b=C(a._i);a._a=e([b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],function(a){return a&&parseInt(a,10)}),qa(a)}}function wa(a){var b=new o(_(xa(a)));return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function xa(a){var b=a._i,e=a._f;return a._locale=a._locale||z(a._l),null===b||void 0===e&&""===b?l({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),p(b)?new o(_(b)):(c(e)?ua(a):e?sa(a):d(b)?a._d=b:ya(a),k(a)||(a._d=null),a))}function ya(b){var f=b._i;void 0===f?b._d=new Date(a.now()):d(f)?b._d=new Date(+f):"string"==typeof f?ea(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),qa(b)):"object"==typeof f?va(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function za(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,wa(f)}function Aa(a,b,c,d){return za(a,b,c,d,!1)}function Ba(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Aa();for(d=b[0],e=1;ea&&(a=-a,c="-"),c+I(~~(a/60),2)+b+I(~~a%60,2)})}function Ha(a,b){var c=(b||"").match(a)||[],d=c[c.length-1]||[],e=(d+"").match(Od)||["-",0,0],f=+(60*e[1])+r(e[2]);return"+"===e[0]?f:-f}function Ia(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(p(b)||d(b)?+b:+Aa(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Aa(b).local()}function Ja(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Ka(b,c){var d,e=this._offset||0;return this.isValid()?null!=b?("string"==typeof b?b=Ha(md,b):Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ja(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?$a(this,Va(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ja(this):null!=b?this:NaN}function La(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Ma(a){return this.utcOffset(0,a)}function Na(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ja(this),"m")),this}function Oa(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ha(ld,this._i)),this}function Pa(a){return this.isValid()?(a=a?Aa(a).utcOffset():0,(this.utcOffset()-a)%60===0):!1}function Qa(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ra(){if(!m(this._isDSTShifted))return this._isDSTShifted;var a={};if(n(a,this),a=xa(a),a._a){var b=a._isUTC?h(a._a):Aa(a._a);this._isDSTShifted=this.isValid()&&s(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Sa(){return this.isValid()?!this._isUTC:!1}function Ta(){return this.isValid()?this._isUTC:!1}function Ua(){return this.isValid()?this._isUTC&&0===this._offset:!1}function Va(a,b){var c,d,e,g=a,h=null;return Fa(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=Pd.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:r(h[td])*c,h:r(h[ud])*c,m:r(h[vd])*c,s:r(h[wd])*c,ms:r(h[xd])*c}):(h=Qd.exec(a))?(c="-"===h[1]?-1:1,g={y:Wa(h[2],c),M:Wa(h[3],c),d:Wa(h[4],c),h:Wa(h[5],c),m:Wa(h[6],c),s:Wa(h[7],c),w:Wa(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=Ya(Aa(g.from),Aa(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ea(g),Fa(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function Wa(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function Xa(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function Ya(a,b){var c;return a.isValid()&&b.isValid()?(b=Ia(b,a),a.isBefore(b)?c=Xa(a,b):(c=Xa(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c):{milliseconds:0,months:0}}function Za(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(ca(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Va(c,d),$a(this,e,a),this}}function $a(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;b.isValid()&&(e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&G(b,"Date",F(b,"Date")+g*d),h&&Y(b,F(b,"Month")+h*d),e&&a.updateOffset(b,g||h))}function _a(a,b){var c=a||Aa(),d=Ia(c,this).startOf("day"),e=this.diff(d,"days",!0),f=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse",g=b&&(D(b[f])?b[f]():b[f]);return this.format(g||this.localeData().calendar(f,this,Aa(c)))}function ab(){return new o(this)}function bb(a,b){var c=p(a)?a:Aa(a);return this.isValid()&&c.isValid()?(b=B(m(b)?"millisecond":b),"millisecond"===b?+this>+c:+c<+this.clone().startOf(b)):!1}function cb(a,b){var c=p(a)?a:Aa(a);return this.isValid()&&c.isValid()?(b=B(m(b)?"millisecond":b),"millisecond"===b?+c>+this:+this.clone().endOf(b)<+c):!1}function db(a,b,c){return this.isAfter(a,c)&&this.isBefore(b,c)}function eb(a,b){var c,d=p(a)?a:Aa(a);return this.isValid()&&d.isValid()?(b=B(b||"millisecond"),"millisecond"===b?+this===+d:(c=+d,+this.clone().startOf(b)<=c&&c<=+this.clone().endOf(b))):!1}function fb(a,b){return this.isSame(a,b)||this.isAfter(a,b)}function gb(a,b){return this.isSame(a,b)||this.isBefore(a,b)}function hb(a,b,c){var d,e,f,g;return this.isValid()?(d=Ia(a,this),d.isValid()?(e=6e4*(d.utcOffset()-this.utcOffset()),b=B(b),"year"===b||"month"===b||"quarter"===b?(g=ib(this,d),"quarter"===b?g/=3:"year"===b&&(g/=12)):(f=this-d,g="second"===b?f/1e3:"minute"===b?f/6e4:"hour"===b?f/36e5:"day"===b?(f-e)/864e5:"week"===b?(f-e)/6048e5:f),c?g:q(g)):NaN):NaN}function ib(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function jb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function kb(){var a=this.clone().utc();return 0f&&(b=f),Kb.call(this,a,b,c,d,e))}function Kb(a,b,c,d,e){var f=la(a,b,c,d,e),g=ga(f.year,0,f.dayOfYear);return this.year(g.getUTCFullYear()),this.month(g.getUTCMonth()),this.date(g.getUTCDate()),this}function Lb(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)}function Mb(a){return ma(a,this._week.dow,this._week.doy).week}function Nb(){return this._week.dow}function Ob(){return this._week.doy}function Pb(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function Qb(a){var b=ma(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function Rb(a,b){return"string"!=typeof a?a:isNaN(a)?(a=b.weekdaysParse(a),"number"==typeof a?a:null):parseInt(a,10)}function Sb(a,b){return c(this._weekdays)?this._weekdays[a.day()]:this._weekdays[this._weekdays.isFormat.test(b)?"format":"standalone"][a.day()]}function Tb(a){return this._weekdaysShort[a.day()]}function Ub(a){return this._weekdaysMin[a.day()]}function Vb(a,b,c){var d,e,f;for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),d=0;7>d;d++){if(e=Aa([2e3,1]).day(d),c&&!this._fullWeekdaysParse[d]&&(this._fullWeekdaysParse[d]=new RegExp("^"+this.weekdays(e,"").replace(".",".?")+"$","i"),this._shortWeekdaysParse[d]=new RegExp("^"+this.weekdaysShort(e,"").replace(".",".?")+"$","i"),this._minWeekdaysParse[d]=new RegExp("^"+this.weekdaysMin(e,"").replace(".",".?")+"$","i")),this._weekdaysParse[d]||(f="^"+this.weekdays(e,"")+"|^"+this.weekdaysShort(e,"")+"|^"+this.weekdaysMin(e,""),this._weekdaysParse[d]=new RegExp(f.replace(".",""),"i")),c&&"dddd"===b&&this._fullWeekdaysParse[d].test(a))return d;if(c&&"ddd"===b&&this._shortWeekdaysParse[d].test(a))return d;if(c&&"dd"===b&&this._minWeekdaysParse[d].test(a))return d;if(!c&&this._weekdaysParse[d].test(a))return d}}function Wb(a){if(!this.isValid())return null!=a?this:NaN;var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Rb(a,this.localeData()),this.add(a-b,"d")):b}function Xb(a){if(!this.isValid())return null!=a?this:NaN;var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Yb(a){return this.isValid()?null==a?this.day()||7:this.day(this.day()%7?a:a-7):null!=a?this:NaN}function Zb(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function $b(){return this.hours()%12||12}function _b(a,b){J(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function ac(a,b){return b._meridiemParse}function bc(a){return"p"===(a+"").toLowerCase().charAt(0)}function cc(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function dc(a,b){b[xd]=r(1e3*("0."+a))}function ec(){return this._isUTC?"UTC":""}function fc(){return this._isUTC?"Coordinated Universal Time":""}function gc(a){return Aa(1e3*a)}function hc(){return Aa.apply(null,arguments).parseZone()}function ic(a,b,c){var d=this._calendar[a];return D(d)?d.call(b,c):d}function jc(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function kc(){return this._invalidDate}function lc(a){return this._ordinal.replace("%d",a)}function mc(a){return a}function nc(a,b,c,d){var e=this._relativeTime[c];return D(e)?e(a,b,c,d):e.replace(/%d/i,a)}function oc(a,b){var c=this._relativeTime[a>0?"future":"past"];return D(c)?c(b):c.replace(/%s/i,b)}function pc(a){var b,c;for(c in a)b=a[c],D(b)?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function qc(a,b,c,d){var e=z(),f=h().set(d,b);return e[c](f,a)}function rc(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return qc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=qc(a,f,c,e);return g}function sc(a,b){return rc(a,b,"months",12,"month")}function tc(a,b){return rc(a,b,"monthsShort",12,"month")}function uc(a,b){return rc(a,b,"weekdays",7,"day")}function vc(a,b){return rc(a,b,"weekdaysShort",7,"day")}function wc(a,b){return rc(a,b,"weekdaysMin",7,"day")}function xc(){var a=this._data;return this._milliseconds=me(this._milliseconds),this._days=me(this._days),this._months=me(this._months),a.milliseconds=me(a.milliseconds),a.seconds=me(a.seconds),a.minutes=me(a.minutes),a.hours=me(a.hours),a.months=me(a.months),a.years=me(a.years),this}function yc(a,b,c,d){var e=Va(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function zc(a,b){return yc(this,a,b,1)}function Ac(a,b){return yc(this,a,b,-1)}function Bc(a){return 0>a?Math.floor(a):Math.ceil(a)}function Cc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||0>=f&&0>=g&&0>=h||(f+=864e5*Bc(Ec(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=q(f/1e3),i.seconds=a%60,b=q(a/60),i.minutes=b%60,c=q(b/60),i.hours=c%24,g+=q(c/24),e=q(Dc(g)),h+=e,g-=Bc(Ec(e)),d=q(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function Dc(a){return 4800*a/146097}function Ec(a){return 146097*a/4800}function Fc(a){var b,c,d=this._milliseconds;if(a=B(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+Dc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(Ec(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function Gc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*r(this._months/12)}function Hc(a){return function(){return this.as(a)}}function Ic(a){return a=B(a),this[a+"s"]()}function Jc(a){return function(){return this._data[a]}}function Kc(){return q(this.days()/7)}function Lc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function Mc(a,b,c){var d=Va(a).abs(),e=Ce(d.as("s")),f=Ce(d.as("m")),g=Ce(d.as("h")),h=Ce(d.as("d")),i=Ce(d.as("M")),j=Ce(d.as("y")),k=e=f&&["m"]||f=g&&["h"]||g=h&&["d"]||h=i&&["M"]||i=j&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,Lc.apply(null,k)}function Nc(a,b){return void 0===De[a]?!1:void 0===b?De[a]:(De[a]=b,!0)}function Oc(a){var b=this.localeData(),c=Mc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Pc(){var a,b,c,d=Ee(this._milliseconds)/1e3,e=Ee(this._days),f=Ee(this._months);a=q(d/60),b=q(a/60),d%=60,a%=60,c=q(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(0>m?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var Qc,Rc,Sc=a.momentProperties=[],Tc=!1,Uc={},Vc={},Wc=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Xc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Yc={},Zc={},$c=/\d/,_c=/\d\d/,ad=/\d{3}/,bd=/\d{4}/,cd=/[+-]?\d{6}/,dd=/\d\d?/,ed=/\d\d\d\d?/,fd=/\d\d\d\d\d\d?/,gd=/\d{1,3}/,hd=/\d{1,4}/,id=/[+-]?\d{1,6}/,jd=/\d+/,kd=/[+-]?\d+/,ld=/Z|[+-]\d\d:?\d\d/gi,md=/Z|[+-]\d\d(?::?\d\d)?/gi,nd=/[+-]?\d+(\.\d{1,3})?/,od=/[0-9]*(a[mn]\s?)?['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\-]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,pd={},qd={},rd=0,sd=1,td=2,ud=3,vd=4,wd=5,xd=6,yd=7,zd=8;J("M",["MM",2],"Mo",function(){return this.month()+1}),J("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),J("MMMM",0,0,function(a){return this.localeData().months(this,a)}),A("month","M"),O("M",dd),O("MM",dd,_c),O("MMM",od),O("MMMM",od),R(["M","MM"],function(a,b){b[sd]=r(a)-1}),R(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[sd]=e:j(c).invalidMonth=a});var Ad=/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/,Bd="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),Cd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sept_Oct_Nov_Dec".split("_"),Dd={};a.suppressDeprecationWarnings=!1;var Ed=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Fd=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/,Gd=/Z|[+-]\d\d(?::?\d\d)?/,Hd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/]],Id=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],Jd=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=ba("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),J(0,["YY",2],0,function(){return this.year()%100}),J(0,["YYYY",4],0,"year"),J(0,["YYYYY",5],0,"year"),J(0,["YYYYYY",6,!0],0,"year"),A("year","y"),O("Y",kd),O("YY",dd,_c),O("YYYY",hd,bd),O("YYYYY",id,cd),O("YYYYYY",id,cd),R(["YYYYY","YYYYYY"],rd),R("YYYY",function(b,c){c[rd]=2===b.length?a.parseTwoDigitYear(b):r(b)}),R("YY",function(b,c){c[rd]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return r(a)+(r(a)>68?1900:2e3)};var Kd=E("FullYear",!1);a.ISO_8601=function(){};var Ld=ba("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Aa.apply(null,arguments);return this.isValid()&&a.isValid()?this>a?this:a:l()}),Md=ba("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Aa.apply(null,arguments);return this.isValid()&&a.isValid()?a>this?this:a:l()}),Nd=Date.now||function(){return+new Date};Ga("Z",":"),Ga("ZZ",""),O("Z",md),O("ZZ",md),R(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ha(md,a)});var Od=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var Pd=/(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Qd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Va.fn=Ea.prototype;var Rd=Za(1,"add"),Sd=Za(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Td=ba("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});J(0,["gg",2],0,function(){return this.weekYear()%100}),J(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Eb("gggg","weekYear"),Eb("ggggg","weekYear"),Eb("GGGG","isoWeekYear"),Eb("GGGGG","isoWeekYear"),A("weekYear","gg"),A("isoWeekYear","GG"),O("G",kd),O("g",kd),O("GG",dd,_c),O("gg",dd,_c),O("GGGG",hd,bd),O("gggg",hd,bd),O("GGGGG",id,cd),O("ggggg",id,cd),S(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=r(a)}),S(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),J("Q",0,"Qo","quarter"),A("quarter","Q"),O("Q",$c),R("Q",function(a,b){b[sd]=3*(r(a)-1)}),J("w",["ww",2],"wo","week"),J("W",["WW",2],"Wo","isoWeek"),A("week","w"),A("isoWeek","W"),O("w",dd),O("ww",dd,_c),O("W",dd),O("WW",dd,_c),S(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=r(a)});var Ud={dow:0,doy:6};J("D",["DD",2],"Do","date"),A("date","D"),O("D",dd),O("DD",dd,_c),O("Do",function(a,b){
7 | return a?b._ordinalParse:b._ordinalParseLenient}),R(["D","DD"],td),R("Do",function(a,b){b[td]=r(a.match(dd)[0],10)});var Vd=E("Date",!0);J("d",0,"do","day"),J("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),J("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),J("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),J("e",0,0,"weekday"),J("E",0,0,"isoWeekday"),A("day","d"),A("weekday","e"),A("isoWeekday","E"),O("d",dd),O("e",dd),O("E",dd),O("dd",od),O("ddd",od),O("dddd",od),S(["dd","ddd","dddd"],function(a,b,c,d){var e=c._locale.weekdaysParse(a,d,c._strict);null!=e?b.d=e:j(c).invalidWeekday=a}),S(["d","e","E"],function(a,b,c,d){b[d]=r(a)});var Wd="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Xd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Yd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");J("DDD",["DDDD",3],"DDDo","dayOfYear"),A("dayOfYear","DDD"),O("DDD",gd),O("DDDD",ad),R(["DDD","DDDD"],function(a,b,c){c._dayOfYear=r(a)}),J("H",["HH",2],0,"hour"),J("h",["hh",2],0,$b),J("hmm",0,0,function(){return""+$b.apply(this)+I(this.minutes(),2)}),J("hmmss",0,0,function(){return""+$b.apply(this)+I(this.minutes(),2)+I(this.seconds(),2)}),J("Hmm",0,0,function(){return""+this.hours()+I(this.minutes(),2)}),J("Hmmss",0,0,function(){return""+this.hours()+I(this.minutes(),2)+I(this.seconds(),2)}),_b("a",!0),_b("A",!1),A("hour","h"),O("a",ac),O("A",ac),O("H",dd),O("h",dd),O("HH",dd,_c),O("hh",dd,_c),O("hmm",ed),O("hmmss",fd),O("Hmm",ed),O("Hmmss",fd),R(["H","HH"],ud),R(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),R(["h","hh"],function(a,b,c){b[ud]=r(a),j(c).bigHour=!0}),R("hmm",function(a,b,c){var d=a.length-2;b[ud]=r(a.substr(0,d)),b[vd]=r(a.substr(d)),j(c).bigHour=!0}),R("hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[ud]=r(a.substr(0,d)),b[vd]=r(a.substr(d,2)),b[wd]=r(a.substr(e)),j(c).bigHour=!0}),R("Hmm",function(a,b,c){var d=a.length-2;b[ud]=r(a.substr(0,d)),b[vd]=r(a.substr(d))}),R("Hmmss",function(a,b,c){var d=a.length-4,e=a.length-2;b[ud]=r(a.substr(0,d)),b[vd]=r(a.substr(d,2)),b[wd]=r(a.substr(e))});var Zd=/[ap]\.?m?\.?/i,$d=E("Hours",!0);J("m",["mm",2],0,"minute"),A("minute","m"),O("m",dd),O("mm",dd,_c),R(["m","mm"],vd);var _d=E("Minutes",!1);J("s",["ss",2],0,"second"),A("second","s"),O("s",dd),O("ss",dd,_c),R(["s","ss"],wd);var ae=E("Seconds",!1);J("S",0,0,function(){return~~(this.millisecond()/100)}),J(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),J(0,["SSS",3],0,"millisecond"),J(0,["SSSS",4],0,function(){return 10*this.millisecond()}),J(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),J(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),J(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),J(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),J(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),A("millisecond","ms"),O("S",gd,$c),O("SS",gd,_c),O("SSS",gd,ad);var be;for(be="SSSS";be.length<=9;be+="S")O(be,jd);for(be="S";be.length<=9;be+="S")R(be,dc);var ce=E("Milliseconds",!1);J("z",0,0,"zoneAbbr"),J("zz",0,0,"zoneName");var de=o.prototype;de.add=Rd,de.calendar=_a,de.clone=ab,de.diff=hb,de.endOf=tb,de.format=lb,de.from=mb,de.fromNow=nb,de.to=ob,de.toNow=pb,de.get=H,de.invalidAt=Cb,de.isAfter=bb,de.isBefore=cb,de.isBetween=db,de.isSame=eb,de.isSameOrAfter=fb,de.isSameOrBefore=gb,de.isValid=Ab,de.lang=Td,de.locale=qb,de.localeData=rb,de.max=Md,de.min=Ld,de.parsingFlags=Bb,de.set=H,de.startOf=sb,de.subtract=Sd,de.toArray=xb,de.toObject=yb,de.toDate=wb,de.toISOString=kb,de.toJSON=zb,de.toString=jb,de.unix=vb,de.valueOf=ub,de.creationData=Db,de.year=Kd,de.isLeapYear=ja,de.weekYear=Fb,de.isoWeekYear=Gb,de.quarter=de.quarters=Lb,de.month=Z,de.daysInMonth=$,de.week=de.weeks=Pb,de.isoWeek=de.isoWeeks=Qb,de.weeksInYear=Ib,de.isoWeeksInYear=Hb,de.date=Vd,de.day=de.days=Wb,de.weekday=Xb,de.isoWeekday=Yb,de.dayOfYear=Zb,de.hour=de.hours=$d,de.minute=de.minutes=_d,de.second=de.seconds=ae,de.millisecond=de.milliseconds=ce,de.utcOffset=Ka,de.utc=Ma,de.local=Na,de.parseZone=Oa,de.hasAlignedHourOffset=Pa,de.isDST=Qa,de.isDSTShifted=Ra,de.isLocal=Sa,de.isUtcOffset=Ta,de.isUtc=Ua,de.isUTC=Ua,de.zoneAbbr=ec,de.zoneName=fc,de.dates=ba("dates accessor is deprecated. Use date instead.",Vd),de.months=ba("months accessor is deprecated. Use month instead",Z),de.years=ba("years accessor is deprecated. Use year instead",Kd),de.zone=ba("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",La);var ee=de,fe={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},ge={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},he="Invalid date",ie="%d",je=/\d{1,2}/,ke={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},le=t.prototype;le._calendar=fe,le.calendar=ic,le._longDateFormat=ge,le.longDateFormat=jc,le._invalidDate=he,le.invalidDate=kc,le._ordinal=ie,le.ordinal=lc,le._ordinalParse=je,le.preparse=mc,le.postformat=mc,le._relativeTime=ke,le.relativeTime=nc,le.pastFuture=oc,le.set=pc,le.months=V,le._months=Bd,le.monthsShort=W,le._monthsShort=Cd,le.monthsParse=X,le.week=Mb,le._week=Ud,le.firstDayOfYear=Ob,le.firstDayOfWeek=Nb,le.weekdays=Sb,le._weekdays=Wd,le.weekdaysMin=Ub,le._weekdaysMin=Yd,le.weekdaysShort=Tb,le._weekdaysShort=Xd,le.weekdaysParse=Vb,le.isPM=bc,le._meridiemParse=Zd,le.meridiem=cc,x("en",{monthsParse:[/^jan/i,/^feb/i,/^mar/i,/^apr/i,/^may/i,/^jun/i,/^jul/i,/^aug/i,/^sep/i,/^oct/i,/^nov/i,/^dec/i],longMonthsParse:[/^january$/i,/^february$/i,/^march$/i,/^april$/i,/^may$/i,/^june$/i,/^july$/i,/^august$/i,/^september$/i,/^october$/i,/^november$/i,/^december$/i],shortMonthsParse:[/^jan$/i,/^feb$/i,/^mar$/i,/^apr$/i,/^may$/i,/^jun$/i,/^jul$/i,/^aug/i,/^sept?$/i,/^oct$/i,/^nov$/i,/^dec$/i],ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===r(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=ba("moment.lang is deprecated. Use moment.locale instead.",x),a.langData=ba("moment.langData is deprecated. Use moment.localeData instead.",z);var me=Math.abs,ne=Hc("ms"),oe=Hc("s"),pe=Hc("m"),qe=Hc("h"),re=Hc("d"),se=Hc("w"),te=Hc("M"),ue=Hc("y"),ve=Jc("milliseconds"),we=Jc("seconds"),xe=Jc("minutes"),ye=Jc("hours"),ze=Jc("days"),Ae=Jc("months"),Be=Jc("years"),Ce=Math.round,De={s:45,m:45,h:22,d:26,M:11},Ee=Math.abs,Fe=Ea.prototype;Fe.abs=xc,Fe.add=zc,Fe.subtract=Ac,Fe.as=Fc,Fe.asMilliseconds=ne,Fe.asSeconds=oe,Fe.asMinutes=pe,Fe.asHours=qe,Fe.asDays=re,Fe.asWeeks=se,Fe.asMonths=te,Fe.asYears=ue,Fe.valueOf=Gc,Fe._bubble=Cc,Fe.get=Ic,Fe.milliseconds=ve,Fe.seconds=we,Fe.minutes=xe,Fe.hours=ye,Fe.days=ze,Fe.weeks=Kc,Fe.months=Ae,Fe.years=Be,Fe.humanize=Oc,Fe.toISOString=Pc,Fe.toString=Pc,Fe.toJSON=Pc,Fe.locale=qb,Fe.localeData=rb,Fe.toIsoString=ba("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Pc),Fe.lang=Td,J("X",0,0,"unix"),J("x",0,0,"valueOf"),O("x",kd),O("X",nd),R("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),R("x",function(a,b,c){c._d=new Date(r(a))}),a.version="2.11.0",b(Aa),a.fn=ee,a.min=Ca,a.max=Da,a.now=Nd,a.utc=h,a.unix=gc,a.months=sc,a.isDate=d,a.locale=x,a.invalid=l,a.duration=Va,a.isMoment=p,a.weekdays=uc,a.parseZone=hc,a.localeData=z,a.isDuration=Fa,a.monthsShort=tc,a.weekdaysMin=wc,a.defineLocale=y,a.weekdaysShort=vc,a.normalizeUnits=B,a.relativeTimeThreshold=Nc,a.prototype=ee;var Ge=a;return Ge});
--------------------------------------------------------------------------------
/clean/quandl-api-key.js:
--------------------------------------------------------------------------------
1 | var quandlApiKey = 'Fp6cFhibc5xvL2pN3dnu';
--------------------------------------------------------------------------------
/formatWorker.js:
--------------------------------------------------------------------------------
1 | importScripts('lib/lazy.js');
2 | importScripts('lib/strategyHelpers.js');
3 | importScripts('lib/dataHelpers.js');
4 |
5 | //*****************************************************
6 |
7 | self.addEventListener(
8 | 'message',
9 | function(e) {
10 | var data = e.data[0];
11 | var horizon = e.data[1];
12 |
13 | //clean
14 | cd = data.cleanData();
15 | //format
16 | self.postMessage(cd);
17 | },
18 | false
19 | );
20 |
21 |
22 | //*****************************************************
23 |
24 |
--------------------------------------------------------------------------------
/graph.css:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | #graph{
4 | padding-left: 1em;
5 | }
6 | */
7 | .axis path,
8 | .axis line {
9 | fill: none;
10 | stroke: #000;
11 | shape-rendering: crispEdges;
12 | }
13 | .x.axis path {
14 | display: none;
15 | }
16 | .y.axis path {
17 | display: none;
18 | }
19 | .overlay {
20 | fill: none;
21 | pointer-events: all;
22 | }
23 | .line {
24 | fill: none;
25 | stroke-width: 0.1em;
26 | }
27 | .dateLine {
28 | fill: black;
29 | stroke: black;
30 | stroke-width: 0.5;
31 | }
32 | .focus rect {
33 | fill: white;
34 | fill-opacity: 0.75;
35 | stroke:white;
36 | stroke-opacity: 1;
37 | }
38 |
39 | /*
40 | #graph {
41 | margin-left: 1em;
42 | }
43 | */
44 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
21 |
22 |
23 |
24 |
25 | Lazy Backtest IDE
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
45 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
226 |
227 |
228 |
848 |
849 |
--------------------------------------------------------------------------------
/lib/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | }
9 |
10 | /* PADDING */
11 |
12 | .CodeMirror-lines {
13 | padding: 4px 0; /* Vertical padding around content */
14 | }
15 | .CodeMirror pre {
16 | padding: 0 4px; /* Horizontal padding of content */
17 | }
18 |
19 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
20 | background-color: white; /* The little square between H and V scrollbars */
21 | }
22 |
23 | /* GUTTER */
24 |
25 | .CodeMirror-gutters {
26 | border-right: 1px solid #ddd;
27 | background-color: #f7f7f7;
28 | white-space: nowrap;
29 | }
30 | .CodeMirror-linenumbers {}
31 | .CodeMirror-linenumber {
32 | padding: 0 3px 0 5px;
33 | min-width: 20px;
34 | text-align: right;
35 | color: #999;
36 | white-space: nowrap;
37 | }
38 |
39 | .CodeMirror-guttermarker { color: black; }
40 | .CodeMirror-guttermarker-subtle { color: #999; }
41 |
42 | /* CURSOR */
43 |
44 | .CodeMirror div.CodeMirror-cursor {
45 | border-left: 1px solid black;
46 | }
47 | /* Shown when moving in bi-directional text */
48 | .CodeMirror div.CodeMirror-secondarycursor {
49 | border-left: 1px solid silver;
50 | }
51 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
52 | width: auto;
53 | border: 0;
54 | background: #7e7;
55 | }
56 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
57 | z-index: 1;
58 | }
59 |
60 | .cm-animate-fat-cursor {
61 | width: auto;
62 | border: 0;
63 | -webkit-animation: blink 1.06s steps(1) infinite;
64 | -moz-animation: blink 1.06s steps(1) infinite;
65 | animation: blink 1.06s steps(1) infinite;
66 | }
67 | @-moz-keyframes blink {
68 | 0% { background: #7e7; }
69 | 50% { background: none; }
70 | 100% { background: #7e7; }
71 | }
72 | @-webkit-keyframes blink {
73 | 0% { background: #7e7; }
74 | 50% { background: none; }
75 | 100% { background: #7e7; }
76 | }
77 | @keyframes blink {
78 | 0% { background: #7e7; }
79 | 50% { background: none; }
80 | 100% { background: #7e7; }
81 | }
82 |
83 | /* Can style cursor different in overwrite (non-insert) mode */
84 | div.CodeMirror-overwrite div.CodeMirror-cursor {}
85 |
86 | .cm-tab { display: inline-block; text-decoration: inherit; }
87 |
88 | .CodeMirror-ruler {
89 | border-left: 1px solid #ccc;
90 | position: absolute;
91 | }
92 |
93 | /* DEFAULT THEME */
94 |
95 | .cm-s-default .cm-keyword {color: #708;}
96 | .cm-s-default .cm-atom {color: #219;}
97 | .cm-s-default .cm-number {color: #164;}
98 | .cm-s-default .cm-def {color: #00f;}
99 | .cm-s-default .cm-variable,
100 | .cm-s-default .cm-punctuation,
101 | .cm-s-default .cm-property,
102 | .cm-s-default .cm-operator {}
103 | .cm-s-default .cm-variable-2 {color: #05a;}
104 | .cm-s-default .cm-variable-3 {color: #085;}
105 | .cm-s-default .cm-comment {color: #a50;}
106 | .cm-s-default .cm-string {color: #a11;}
107 | .cm-s-default .cm-string-2 {color: #f50;}
108 | .cm-s-default .cm-meta {color: #555;}
109 | .cm-s-default .cm-qualifier {color: #555;}
110 | .cm-s-default .cm-builtin {color: #30a;}
111 | .cm-s-default .cm-bracket {color: #997;}
112 | .cm-s-default .cm-tag {color: #170;}
113 | .cm-s-default .cm-attribute {color: #00c;}
114 | .cm-s-default .cm-header {color: blue;}
115 | .cm-s-default .cm-quote {color: #090;}
116 | .cm-s-default .cm-hr {color: #999;}
117 | .cm-s-default .cm-link {color: #00c;}
118 |
119 | .cm-negative {color: #d44;}
120 | .cm-positive {color: #292;}
121 | .cm-header, .cm-strong {font-weight: bold;}
122 | .cm-em {font-style: italic;}
123 | .cm-link {text-decoration: underline;}
124 | .cm-strikethrough {text-decoration: line-through;}
125 |
126 | .cm-s-default .cm-error {color: #f00;}
127 | .cm-invalidchar {color: #f00;}
128 |
129 | .CodeMirror-composing { border-bottom: 2px solid; }
130 |
131 | /* Default styles for common addons */
132 |
133 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
134 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
135 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
136 | .CodeMirror-activeline-background {background: #e8f2ff;}
137 |
138 | /* STOP */
139 |
140 | /* The rest of this file contains styles related to the mechanics of
141 | the editor. You probably shouldn't touch them. */
142 |
143 | .CodeMirror {
144 | position: relative;
145 | overflow: hidden;
146 | background: white;
147 | }
148 |
149 | .CodeMirror-scroll {
150 | overflow: scroll !important; /* Things will break if this is overridden */
151 | /* 30px is the magic margin used to hide the element's real scrollbars */
152 | /* See overflow: hidden in .CodeMirror */
153 | margin-bottom: -30px; margin-right: -30px;
154 | padding-bottom: 30px;
155 | height: 100%;
156 | outline: none; /* Prevent dragging from highlighting the element */
157 | position: relative;
158 | }
159 | .CodeMirror-sizer {
160 | position: relative;
161 | border-right: 30px solid transparent;
162 | }
163 |
164 | /* The fake, visible scrollbars. Used to force redraw during scrolling
165 | before actuall scrolling happens, thus preventing shaking and
166 | flickering artifacts. */
167 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
168 | position: absolute;
169 | z-index: 6;
170 | display: none;
171 | }
172 | .CodeMirror-vscrollbar {
173 | right: 0; top: 0;
174 | overflow-x: hidden;
175 | overflow-y: scroll;
176 | }
177 | .CodeMirror-hscrollbar {
178 | bottom: 0; left: 0;
179 | overflow-y: hidden;
180 | overflow-x: scroll;
181 | }
182 | .CodeMirror-scrollbar-filler {
183 | right: 0; bottom: 0;
184 | }
185 | .CodeMirror-gutter-filler {
186 | left: 0; bottom: 0;
187 | }
188 |
189 | .CodeMirror-gutters {
190 | position: absolute; left: 0; top: 0;
191 | z-index: 3;
192 | }
193 | .CodeMirror-gutter {
194 | white-space: normal;
195 | height: 100%;
196 | display: inline-block;
197 | margin-bottom: -30px;
198 | /* Hack to make IE7 behave */
199 | *zoom:1;
200 | *display:inline;
201 | }
202 | .CodeMirror-gutter-wrapper {
203 | position: absolute;
204 | z-index: 4;
205 | height: 100%;
206 | }
207 | .CodeMirror-gutter-elt {
208 | position: absolute;
209 | cursor: default;
210 | z-index: 4;
211 | }
212 | .CodeMirror-gutter-wrapper {
213 | -webkit-user-select: none;
214 | -moz-user-select: none;
215 | user-select: none;
216 | }
217 |
218 | .CodeMirror-lines {
219 | cursor: text;
220 | min-height: 1px; /* prevents collapsing before first draw */
221 | }
222 | .CodeMirror pre {
223 | /* Reset some styles that the rest of the page might have set */
224 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
225 | border-width: 0;
226 | background: transparent;
227 | font-family: inherit;
228 | font-size: inherit;
229 | margin: 0;
230 | white-space: pre;
231 | word-wrap: normal;
232 | line-height: inherit;
233 | color: inherit;
234 | z-index: 2;
235 | position: relative;
236 | overflow: visible;
237 | -webkit-tap-highlight-color: transparent;
238 | }
239 | .CodeMirror-wrap pre {
240 | word-wrap: break-word;
241 | white-space: pre-wrap;
242 | word-break: normal;
243 | }
244 |
245 | .CodeMirror-linebackground {
246 | position: absolute;
247 | left: 0; right: 0; top: 0; bottom: 0;
248 | z-index: 0;
249 | }
250 |
251 | .CodeMirror-linewidget {
252 | position: relative;
253 | z-index: 2;
254 | overflow: auto;
255 | }
256 |
257 | .CodeMirror-widget {}
258 |
259 | .CodeMirror-code {
260 | outline: none;
261 | }
262 |
263 | /* Force content-box sizing for the elements where we expect it */
264 | .CodeMirror-scroll,
265 | .CodeMirror-sizer,
266 | .CodeMirror-gutter,
267 | .CodeMirror-gutters,
268 | .CodeMirror-linenumber {
269 | -moz-box-sizing: content-box;
270 | box-sizing: content-box;
271 | }
272 |
273 | .CodeMirror-measure {
274 | position: absolute;
275 | width: 100%;
276 | height: 0;
277 | overflow: hidden;
278 | visibility: hidden;
279 | }
280 | .CodeMirror-measure pre { position: static; }
281 |
282 | .CodeMirror div.CodeMirror-cursor {
283 | position: absolute;
284 | border-right: none;
285 | width: 0;
286 | }
287 |
288 | div.CodeMirror-cursors {
289 | visibility: hidden;
290 | position: relative;
291 | z-index: 3;
292 | }
293 | .CodeMirror-focused div.CodeMirror-cursors {
294 | visibility: visible;
295 | }
296 |
297 | .CodeMirror-selected { background: #d9d9d9; }
298 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
299 | .CodeMirror-crosshair { cursor: crosshair; }
300 | .CodeMirror ::selection { background: #d7d4f0; }
301 | .CodeMirror ::-moz-selection { background: #d7d4f0; }
302 |
303 | .cm-searching {
304 | background: #ffa;
305 | background: rgba(255, 255, 0, .4);
306 | }
307 |
308 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
309 | .CodeMirror span { *vertical-align: text-bottom; }
310 |
311 | /* Used to force a border model for a node */
312 | .cm-force-border { padding-right: .1px; }
313 |
314 | @media print {
315 | /* Hide the cursor when printing */
316 | .CodeMirror div.CodeMirror-cursors {
317 | visibility: hidden;
318 | }
319 | }
320 |
321 | /* See issue #2901 */
322 | .cm-tab-wrap-hack:after { content: ''; }
323 |
324 | /* Help users use markselection to safely style text background */
325 | span.CodeMirror-selectedtext { background: none; }
326 |
--------------------------------------------------------------------------------
/lib/dataHelpers.js:
--------------------------------------------------------------------------------
1 |
2 | //*****************************************************
3 | //ensure all data has a matching date
4 | var cleanData = function(){
5 | var _this = this;
6 | return Lazy(this)
7 | .reduce(function(acc,c){return acc.concat(c.prices);},Lazy([]))
8 | //ensure dates are matched for every assetall the way down the line
9 | .groupBy(function(i){return i.date })
10 | .filter(function(i){return i.length === _this.length;})
11 | .toArray()
12 | .map(
13 | function(i){
14 | return i[1];
15 | }
16 | )
17 | .reverse()
18 | ;
19 | }
20 |
21 | Object.defineProperty(
22 | Object.prototype,
23 | 'cleanData',
24 | {
25 | value: cleanData,
26 | writable: true,
27 | configurable: true,
28 | enumerable: false
29 | }
30 | );
31 |
32 |
--------------------------------------------------------------------------------
/lib/graphs.js:
--------------------------------------------------------------------------------
1 | /*
2 | function resize(){
3 | window.onresize = function(){
4 | document.getElementsByTagName("svg")[0].style.width = window.innerWidth * 0.9;
5 | document.getElementsByTagName("svg")[0].style.height = window.innerHeight * 0.9;
6 | };
7 | }
8 | */
9 |
10 | function shim(ddd,gts){
11 | var d=new Graph();
12 | d.draw(ddd,false,gts);
13 | }
14 |
15 | function Graph(){
16 |
17 | //filter return series or not
18 | //var filter = null;
19 |
20 | //!use check boxes to store this data!
21 | var graphTimeSeries = ["STRATEGY_return"];
22 | datax = null;
23 |
24 | /*
25 | orig data is needed to load up
26 | orig data is global
27 | update/change graphTimeSeries each time
28 | include optional graphTimeSeries input in draw function
29 | */
30 |
31 | //**********************************************************************************************
32 | //setup
33 | function appendCheckBox(timeSeries, allReturns){
34 | var p = document.createElement('p');
35 | var text = document.createTextNode(timeSeries);
36 |
37 | document.getElementById('graph').appendChild(p);
38 |
39 | var input = document.createElement('input');
40 | input.type="checkbox";
41 |
42 | input .addEventListener(
43 | "change",
44 | function(){
45 | //find whether to add or remove
46 | var index = graphTimeSeries.indexOf(timeSeries);
47 | //add or remove
48 | index === -1 ? graphTimeSeries.push(timeSeries) : graphTimeSeries.splice(index,1);
49 |
50 | update(allReturns.slice());
51 | }
52 | );
53 | //check strategy checkbox by default
54 | timeSeries === "STRATEGY_return" ? input.checked = true : input.checked = false;
55 |
56 | p.appendChild(input);
57 | p.appendChild(text);
58 | }
59 |
60 |
61 |
62 | function update(allReturns){
63 |
64 | var _this = this;
65 |
66 | returns = allReturns.filter(
67 | function(i){
68 | return graphTimeSeries.indexOf(i.name) != -1;
69 | }
70 | );
71 |
72 | //need to get relevant data
73 | //add relevant data to tag string
74 | var importString = '';
75 |
76 |
77 | var datay = datax
78 | .slice()
79 | .map(
80 | function(i){
81 | var j = _.pick(i,graphTimeSeries);
82 | j.date = i.date.getFullYear() + "-" + (i.date.getMonth()+1) + "-" + (i.date.getDate());
83 | return j;
84 | }
85 | );
86 |
87 | //console.log(datay);
88 |
89 | var s1 = '';
90 | var s2 = '';
91 |
92 | document.getElementById('codex') != null ? document.getElementById('codex').value = (s1+importString+s2) : null;
93 |
94 | //*******************************************
95 | //update axes
96 | x.domain(d3.extent(returns[0].values, function(d) { return d.date; }));
97 |
98 | y.domain([
99 | d3.min(returns, function(c) { return d3.min(c.values, function(v) { return v.r; }); }),
100 | d3.max(returns, function(c) { return d3.max(c.values, function(v) { return v.r; }); })
101 | ]);
102 |
103 | var xAxis = d3
104 | .svg
105 | .axis()
106 | .scale(x)
107 | .orient("bottom")
108 | .ticks(2);
109 |
110 | var yAxis = d3
111 | .svg
112 | .axis()
113 | .scale(y)
114 | .orient("left")
115 | .ticks(2);
116 |
117 | d3 .select(".x.axis")
118 | .transition()
119 | .duration(750)
120 | .call(xAxis);
121 |
122 | d3 .select(".y.axis")
123 | .transition()
124 | .duration(750)
125 | .call(yAxis.tickFormat( formatAxisLabel ));
126 |
127 | //*******************************************
128 | //return path
129 |
130 | //remove all
131 | d3 .select('#base')
132 | .selectAll(".returnPath")
133 | .remove();
134 |
135 | //append
136 | d3 .select('#base')
137 | .selectAll(".returnPath")
138 | .data( returns )
139 | .enter()
140 | .append("g")
141 | .attr("class", "returnPath")
142 | .attr("id", function(d){return d.name;})
143 | .append("path")
144 | .attr("class", "line")
145 | .style("stroke", function(d) { return color(d.name); })
146 | .attr("d", function(d) { return line(d.values); })
147 | .transition()
148 | .duration(750);
149 | }
150 |
151 | //******************
152 | //choose smallest dimension between parent's width and window height
153 |
154 | var worh = document.querySelector("#graph").parentNode.offsetWidth;
155 |
156 | worh > window.innerHeight ?
157 | worh = window.innerHeight
158 | :
159 | null;
160 |
161 | var margin = {
162 | bottom: worh*0.05,
163 | top: worh*0.05,
164 | right: worh*0,
165 | left: worh*0.1
166 | };
167 |
168 | var width = worh - margin.left - margin.right;
169 |
170 | var height = worh - margin.top - margin.bottom;
171 |
172 | //******************
173 |
174 | var x = d3
175 | .time
176 | .scale()
177 | .range([0, width]);
178 |
179 | var y = d3
180 | .scale
181 | .linear()
182 | .range([height, 0]);
183 |
184 | //******************
185 |
186 |
187 | var color = d3
188 | .scale
189 | .category10();
190 |
191 | var line = d3
192 | .svg
193 | .line()
194 | .interpolate("basis")
195 | .x(function(d) { return x(d.date); })
196 | .y(function(d) { return y(d.r); });
197 |
198 | //******************
199 |
200 |
201 | var formatAxisLabel = function(d){
202 | return (d * 100).toLocaleString()+"%";
203 | }
204 |
205 |
206 | //graph object
207 | //change domain, lines
208 | //update lines and axes
209 |
210 | this.draw = function(data, controlsFlag, gts){
211 | gts != null ? graphTimeSeries = gts : null;
212 |
213 | datax = data.slice();
214 |
215 | //gts != null ? graphTimeSeries = gts : null;
216 |
217 | //if controls then filter
218 | controlsFlag ? filter = true : filter = false;
219 |
220 | //******************
221 |
222 | var xAxis = d3
223 | .svg
224 | .axis()
225 | .scale(x)
226 | .orient("bottom")
227 | .ticks(2);
228 |
229 | var yAxis = d3
230 | .svg
231 | .axis()
232 | .scale(y)
233 | .orient("left")
234 | .ticks(2);
235 |
236 | //******************
237 |
238 | var parseDate = d3.time.format("%Y-%m-%d").parse;
239 |
240 |
241 |
242 | //array with element per time series
243 | var bisectDate = d3
244 | .bisector(function(d) { return d.date; })
245 | .left;
246 |
247 | //**********************************************************************************************
248 | //setup
249 |
250 |
251 | //remove anything pre-existing
252 | d3 .select("svg")
253 | .remove();
254 |
255 | d3 .select("#graph")
256 | .selectAll('p')
257 | .remove();
258 |
259 | //**********************************************************************************************
260 |
261 | var svg = d3
262 | .select("#graph")
263 | .append("svg")
264 | //.attr("viewBox","0 0 "+(width + margin.left + margin.right)+" "+(height + margin.top + margin.bottom))
265 | //.attr("preserveAspectRatio","xMidYMid")
266 | .attr("width", width + margin.left + margin.right)
267 | .attr("height", height + margin.top + margin.bottom)
268 | .append("g")
269 | //.attr('id','base')
270 | .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
271 |
272 | svg .append("g")
273 | .attr('id','base');
274 |
275 | //sets colour(?)
276 | color .domain(
277 | d3 .keys(data[0])
278 | .filter(
279 | function(key) {
280 | return key != "date" && key.indexOf("weight") === -1;
281 | }
282 | )
283 | );
284 |
285 | //convert date format
286 | data .forEach(
287 | function(d) {
288 | d.date = parseDate(d.date);
289 | }
290 | );
291 |
292 | console.log("c");
293 |
294 | //generate cumulative demeaned returns
295 | var allReturns = color
296 | .domain()
297 | .reduce(
298 | function(aa, name) {
299 | //find mean
300 | var av = jStat(
301 | _.pluck(data,name)
302 | .map(function(i){return +i;})
303 | ).mean();
304 |
305 | var factor = null;
306 | var origAv = null;
307 |
308 | aa.length > 0 ? factor = av/aa[0].av : factor = 1;
309 | aa.length > 0 ? origAv = aa[0].av : origAv = av;
310 |
311 | var data2 = data.slice();
312 |
313 | return aa.concat(
314 | {
315 | name: name,
316 | av: av,
317 | values: data2.reverse().reduce(function(a,d) {
318 | var rr = null;
319 | if (a.length>0){
320 | //cumulative and demean
321 | rr = +d[name] / factor + a[a.length-1].r - origAv;
322 | }
323 | else{
324 | rr = +d[name] / factor - origAv;
325 | }
326 | return a.concat({date: d.date, r: rr });
327 | }
328 | ,[])
329 | }
330 | );
331 | }
332 | , []
333 | );
334 |
335 |
336 |
337 |
338 | //************************************************************************************
339 | //************************************************************************************
340 | //************************************************************************************
341 | //create object
342 | //two modes: simple & advanced
343 |
344 |
345 | //initially just show strat returns
346 | /*
347 | var returns = allReturns
348 | .filter(
349 | function(i){
350 | return graphTimeSeries.indexOf(i.name) != -1;
351 | }
352 | )
353 | ;
354 | */
355 |
356 | if (controlsFlag === true){
357 | //append check boxes
358 | color .domain()
359 | .reverse()
360 | .forEach(
361 | function(i){
362 | appendCheckBox(i, allReturns.slice());
363 | }
364 | );
365 | }
366 |
367 | //************************************************************************************
368 | //************************************************************************************
369 | //************************************************************************************
370 |
371 |
372 |
373 |
374 | //initial axis setup
375 |
376 | //xaxis
377 | svg .append("g")
378 | .attr("class", "x axis")
379 | .attr("transform", "translate(0," + height + ")")
380 | .call(xAxis);
381 | //yaxis
382 | svg .append("g")
383 | .attr("class", "y axis")
384 | .call( yAxis.tickFormat( formatAxisLabel ) )
385 | .append("text")
386 | .attr("transform", "rotate(-90)")
387 | .attr("x", 0)
388 | .attr("y", 6)
389 | .attr("dy", "1em")
390 | .style("text-anchor", "end")
391 | .text("Cumulative Demeaned");
392 |
393 |
394 | //************************************************************************************
395 | //setup check boxes
396 |
397 | update( allReturns.slice() );
398 |
399 |
400 | //************************************************************************************
401 | //overlay for mouse movement tracking
402 | var dateBox = svg
403 | .append("g")
404 | .attr("class", "focus")
405 | .style("display", "none");
406 | dateBox
407 | .append("rect")
408 | .attr("width", "8em")
409 | .attr("height", "1.1em");
410 | dateBox
411 | .append("text")
412 | .attr("x", 9)
413 | .attr("dy", "1em");
414 |
415 | var toolTips = svg
416 | .append("g")
417 | .attr("class", "toolTips");
418 |
419 | //append time series tool tips
420 | var f = color .domain()
421 | .reduce(
422 | function(a,i){
423 | a[i] = toolTips
424 | .append("g")
425 | .attr("class", "focus "+i)
426 | .style("display", "none")
427 | ;
428 |
429 | a[i] .append("rect")
430 | .attr("width", "10em")
431 | .attr("height", "1.1em");
432 | a[i] .append("text")
433 | .attr("x", 9)
434 | .attr("dy", "1em");
435 |
436 | return a;
437 | }
438 | , []
439 | );
440 |
441 | //vertical date line
442 | var dateLine = svg
443 | .append("g")
444 | .attr("class", "dateLine")
445 | .style("display", "none");
446 | dateLine
447 | .append("line")
448 | .attr("x1",0)
449 | .attr("y1",0)
450 | .attr("x2",0)
451 | .attr("y2",height);
452 |
453 |
454 |
455 | //append overlay for mouse movement
456 | var overlay = svg
457 | .append("rect")
458 | .attr("class", "overlay");
459 | overlay
460 | .attr("width", width)
461 | .attr("height", height);
462 | overlay
463 | .on("mouseover",
464 | function() {
465 |
466 | //scrub out tool tips
467 | allReturns.forEach(
468 | function(i){
469 | f[i.name].style("display", "none");
470 | }
471 | );
472 | //show relvant tool tips
473 | graphTimeSeries.forEach(
474 | function(i){
475 | f[i].style("display", null);
476 | }
477 | );
478 |
479 | dateBox.style("display", null);
480 | dateLine.style("display", null);
481 | }
482 | )
483 | .on("mousemove", mousemove);
484 |
485 |
486 |
487 |
488 | //************************************************************************************
489 |
490 |
491 |
492 | function mousemove() {
493 | var currentDate = x.invert(d3.mouse(this)[0]);
494 |
495 | //strategy return boxes
496 | allReturns.forEach(
497 | function(i){
498 | var index = bisectDate(i.values, currentDate);
499 | var d = i.values[index];
500 | f[i.name].attr("transform", "translate(" + x(d.date) + "," + y(d.r) + ")");
501 |
502 | //remove returns and exchanges
503 | var cleanedTickers = (i.name).substring(0,i.name.length-7);
504 |
505 | var indexof = cleanedTickers.indexOf("_");
506 | indexof === -1 ? null : cleanedTickers = cleanedTickers.substring(indexof+1);;
507 |
508 | //find first underscore
509 | f[i.name]
510 | .select("text").text(cleanedTickers+": "+Math.round(d.r * 100).toLocaleString()+"%")
511 | .style("stroke", color(i.name) );
512 | }
513 | );
514 |
515 | dateLine.attr("transform", "translate(" + x(currentDate) + "," + 0 + ")");
516 |
517 | dateBox .attr("transform", "translate(" + x(currentDate) + "," + 0 + ")")
518 | .select("text")
519 | .text(currentDate.toLocaleDateString());
520 | }
521 | }
522 | }
523 |
--------------------------------------------------------------------------------
/lib/javascript.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | // TODO actually recognize syntax of TypeScript constructs
5 |
6 | (function(mod) {
7 | if (typeof exports == "object" && typeof module == "object") // CommonJS
8 | mod(require("../../lib/codemirror"));
9 | else if (typeof define == "function" && define.amd) // AMD
10 | define(["../../lib/codemirror"], mod);
11 | else // Plain browser env
12 | mod(CodeMirror);
13 | })(function(CodeMirror) {
14 | "use strict";
15 |
16 | CodeMirror.defineMode("javascript", function(config, parserConfig) {
17 | var indentUnit = config.indentUnit;
18 | var statementIndent = parserConfig.statementIndent;
19 | var jsonldMode = parserConfig.jsonld;
20 | var jsonMode = parserConfig.json || jsonldMode;
21 | var isTS = parserConfig.typescript;
22 | var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
23 |
24 | // Tokenizer
25 |
26 | var keywords = function(){
27 | function kw(type) {return {type: type, style: "keyword"};}
28 | var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
29 | var operator = kw("operator"), atom = {type: "atom", style: "atom"};
30 |
31 | var jsKeywords = {
32 | "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
33 | "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
34 | "var": kw("var"), "const": kw("var"), "let": kw("var"),
35 | "function": kw("function"), "catch": kw("catch"),
36 | "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
37 | "in": operator, "typeof": operator, "instanceof": operator,
38 | "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
39 | "this": kw("this"), "module": kw("module"), "class": kw("class"), "super": kw("atom"),
40 | "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
41 | };
42 |
43 | // Extend the 'normal' keywords with the TypeScript language extensions
44 | if (isTS) {
45 | var type = {type: "variable", style: "variable-3"};
46 | var tsKeywords = {
47 | // object-like things
48 | "interface": kw("interface"),
49 | "extends": kw("extends"),
50 | "constructor": kw("constructor"),
51 |
52 | // scope modifiers
53 | "public": kw("public"),
54 | "private": kw("private"),
55 | "protected": kw("protected"),
56 | "static": kw("static"),
57 |
58 | // types
59 | "string": type, "number": type, "bool": type, "any": type
60 | };
61 |
62 | for (var attr in tsKeywords) {
63 | jsKeywords[attr] = tsKeywords[attr];
64 | }
65 | }
66 |
67 | return jsKeywords;
68 | }();
69 |
70 | var isOperatorChar = /[+\-*&%=<>!?|~^]/;
71 | var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
72 |
73 | function readRegexp(stream) {
74 | var escaped = false, next, inSet = false;
75 | while ((next = stream.next()) != null) {
76 | if (!escaped) {
77 | if (next == "/" && !inSet) return;
78 | if (next == "[") inSet = true;
79 | else if (inSet && next == "]") inSet = false;
80 | }
81 | escaped = !escaped && next == "\\";
82 | }
83 | }
84 |
85 | // Used as scratch variables to communicate multiple values without
86 | // consing up tons of objects.
87 | var type, content;
88 | function ret(tp, style, cont) {
89 | type = tp; content = cont;
90 | return style;
91 | }
92 | function tokenBase(stream, state) {
93 | var ch = stream.next();
94 | if (ch == '"' || ch == "'") {
95 | state.tokenize = tokenString(ch);
96 | return state.tokenize(stream, state);
97 | } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
98 | return ret("number", "number");
99 | } else if (ch == "." && stream.match("..")) {
100 | return ret("spread", "meta");
101 | } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
102 | return ret(ch);
103 | } else if (ch == "=" && stream.eat(">")) {
104 | return ret("=>", "operator");
105 | } else if (ch == "0" && stream.eat(/x/i)) {
106 | stream.eatWhile(/[\da-f]/i);
107 | return ret("number", "number");
108 | } else if (/\d/.test(ch)) {
109 | stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
110 | return ret("number", "number");
111 | } else if (ch == "/") {
112 | if (stream.eat("*")) {
113 | state.tokenize = tokenComment;
114 | return tokenComment(stream, state);
115 | } else if (stream.eat("/")) {
116 | stream.skipToEnd();
117 | return ret("comment", "comment");
118 | } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
119 | state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
120 | readRegexp(stream);
121 | stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
122 | return ret("regexp", "string-2");
123 | } else {
124 | stream.eatWhile(isOperatorChar);
125 | return ret("operator", "operator", stream.current());
126 | }
127 | } else if (ch == "`") {
128 | state.tokenize = tokenQuasi;
129 | return tokenQuasi(stream, state);
130 | } else if (ch == "#") {
131 | stream.skipToEnd();
132 | return ret("error", "error");
133 | } else if (isOperatorChar.test(ch)) {
134 | stream.eatWhile(isOperatorChar);
135 | return ret("operator", "operator", stream.current());
136 | } else if (wordRE.test(ch)) {
137 | stream.eatWhile(wordRE);
138 | var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
139 | return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
140 | ret("variable", "variable", word);
141 | }
142 | }
143 |
144 | function tokenString(quote) {
145 | return function(stream, state) {
146 | var escaped = false, next;
147 | if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
148 | state.tokenize = tokenBase;
149 | return ret("jsonld-keyword", "meta");
150 | }
151 | while ((next = stream.next()) != null) {
152 | if (next == quote && !escaped) break;
153 | escaped = !escaped && next == "\\";
154 | }
155 | if (!escaped) state.tokenize = tokenBase;
156 | return ret("string", "string");
157 | };
158 | }
159 |
160 | function tokenComment(stream, state) {
161 | var maybeEnd = false, ch;
162 | while (ch = stream.next()) {
163 | if (ch == "/" && maybeEnd) {
164 | state.tokenize = tokenBase;
165 | break;
166 | }
167 | maybeEnd = (ch == "*");
168 | }
169 | return ret("comment", "comment");
170 | }
171 |
172 | function tokenQuasi(stream, state) {
173 | var escaped = false, next;
174 | while ((next = stream.next()) != null) {
175 | if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
176 | state.tokenize = tokenBase;
177 | break;
178 | }
179 | escaped = !escaped && next == "\\";
180 | }
181 | return ret("quasi", "string-2", stream.current());
182 | }
183 |
184 | var brackets = "([{}])";
185 | // This is a crude lookahead trick to try and notice that we're
186 | // parsing the argument patterns for a fat-arrow function before we
187 | // actually hit the arrow token. It only works if the arrow is on
188 | // the same line as the arguments and there's no strange noise
189 | // (comments) in between. Fallback is to only notice when we hit the
190 | // arrow, and not declare the arguments as locals for the arrow
191 | // body.
192 | function findFatArrow(stream, state) {
193 | if (state.fatArrowAt) state.fatArrowAt = null;
194 | var arrow = stream.string.indexOf("=>", stream.start);
195 | if (arrow < 0) return;
196 |
197 | var depth = 0, sawSomething = false;
198 | for (var pos = arrow - 1; pos >= 0; --pos) {
199 | var ch = stream.string.charAt(pos);
200 | var bracket = brackets.indexOf(ch);
201 | if (bracket >= 0 && bracket < 3) {
202 | if (!depth) { ++pos; break; }
203 | if (--depth == 0) break;
204 | } else if (bracket >= 3 && bracket < 6) {
205 | ++depth;
206 | } else if (wordRE.test(ch)) {
207 | sawSomething = true;
208 | } else if (/["'\/]/.test(ch)) {
209 | return;
210 | } else if (sawSomething && !depth) {
211 | ++pos;
212 | break;
213 | }
214 | }
215 | if (sawSomething && !depth) state.fatArrowAt = pos;
216 | }
217 |
218 | // Parser
219 |
220 | var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
221 |
222 | function JSLexical(indented, column, type, align, prev, info) {
223 | this.indented = indented;
224 | this.column = column;
225 | this.type = type;
226 | this.prev = prev;
227 | this.info = info;
228 | if (align != null) this.align = align;
229 | }
230 |
231 | function inScope(state, varname) {
232 | for (var v = state.localVars; v; v = v.next)
233 | if (v.name == varname) return true;
234 | for (var cx = state.context; cx; cx = cx.prev) {
235 | for (var v = cx.vars; v; v = v.next)
236 | if (v.name == varname) return true;
237 | }
238 | }
239 |
240 | function parseJS(state, style, type, content, stream) {
241 | var cc = state.cc;
242 | // Communicate our context to the combinators.
243 | // (Less wasteful than consing up a hundred closures on every call.)
244 | cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
245 |
246 | if (!state.lexical.hasOwnProperty("align"))
247 | state.lexical.align = true;
248 |
249 | while(true) {
250 | var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
251 | if (combinator(type, content)) {
252 | while(cc.length && cc[cc.length - 1].lex)
253 | cc.pop()();
254 | if (cx.marked) return cx.marked;
255 | if (type == "variable" && inScope(state, content)) return "variable-2";
256 | return style;
257 | }
258 | }
259 | }
260 |
261 | // Combinator utils
262 |
263 | var cx = {state: null, column: null, marked: null, cc: null};
264 | function pass() {
265 | for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
266 | }
267 | function cont() {
268 | pass.apply(null, arguments);
269 | return true;
270 | }
271 | function register(varname) {
272 | function inList(list) {
273 | for (var v = list; v; v = v.next)
274 | if (v.name == varname) return true;
275 | return false;
276 | }
277 | var state = cx.state;
278 | if (state.context) {
279 | cx.marked = "def";
280 | if (inList(state.localVars)) return;
281 | state.localVars = {name: varname, next: state.localVars};
282 | } else {
283 | if (inList(state.globalVars)) return;
284 | if (parserConfig.globalVars)
285 | state.globalVars = {name: varname, next: state.globalVars};
286 | }
287 | }
288 |
289 | // Combinators
290 |
291 | var defaultVars = {name: "this", next: {name: "arguments"}};
292 | function pushcontext() {
293 | cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
294 | cx.state.localVars = defaultVars;
295 | }
296 | function popcontext() {
297 | cx.state.localVars = cx.state.context.vars;
298 | cx.state.context = cx.state.context.prev;
299 | }
300 | function pushlex(type, info) {
301 | var result = function() {
302 | var state = cx.state, indent = state.indented;
303 | if (state.lexical.type == "stat") indent = state.lexical.indented;
304 | else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
305 | indent = outer.indented;
306 | state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
307 | };
308 | result.lex = true;
309 | return result;
310 | }
311 | function poplex() {
312 | var state = cx.state;
313 | if (state.lexical.prev) {
314 | if (state.lexical.type == ")")
315 | state.indented = state.lexical.indented;
316 | state.lexical = state.lexical.prev;
317 | }
318 | }
319 | poplex.lex = true;
320 |
321 | function expect(wanted) {
322 | function exp(type) {
323 | if (type == wanted) return cont();
324 | else if (wanted == ";") return pass();
325 | else return cont(exp);
326 | };
327 | return exp;
328 | }
329 |
330 | function statement(type, value) {
331 | if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
332 | if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
333 | if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
334 | if (type == "{") return cont(pushlex("}"), block, poplex);
335 | if (type == ";") return cont();
336 | if (type == "if") {
337 | if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
338 | cx.state.cc.pop()();
339 | return cont(pushlex("form"), expression, statement, poplex, maybeelse);
340 | }
341 | if (type == "function") return cont(functiondef);
342 | if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
343 | if (type == "variable") return cont(pushlex("stat"), maybelabel);
344 | if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
345 | block, poplex, poplex);
346 | if (type == "case") return cont(expression, expect(":"));
347 | if (type == "default") return cont(expect(":"));
348 | if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
349 | statement, poplex, popcontext);
350 | if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex);
351 | if (type == "class") return cont(pushlex("form"), className, poplex);
352 | if (type == "export") return cont(pushlex("form"), afterExport, poplex);
353 | if (type == "import") return cont(pushlex("form"), afterImport, poplex);
354 | return pass(pushlex("stat"), expression, expect(";"), poplex);
355 | }
356 | function expression(type) {
357 | return expressionInner(type, false);
358 | }
359 | function expressionNoComma(type) {
360 | return expressionInner(type, true);
361 | }
362 | function expressionInner(type, noComma) {
363 | if (cx.state.fatArrowAt == cx.stream.start) {
364 | var body = noComma ? arrowBodyNoComma : arrowBody;
365 | if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
366 | else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
367 | }
368 |
369 | var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
370 | if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
371 | if (type == "function") return cont(functiondef, maybeop);
372 | if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
373 | if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
374 | if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
375 | if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
376 | if (type == "{") return contCommasep(objprop, "}", null, maybeop);
377 | if (type == "quasi") { return pass(quasi, maybeop); }
378 | return cont();
379 | }
380 | function maybeexpression(type) {
381 | if (type.match(/[;\}\)\],]/)) return pass();
382 | return pass(expression);
383 | }
384 | function maybeexpressionNoComma(type) {
385 | if (type.match(/[;\}\)\],]/)) return pass();
386 | return pass(expressionNoComma);
387 | }
388 |
389 | function maybeoperatorComma(type, value) {
390 | if (type == ",") return cont(expression);
391 | return maybeoperatorNoComma(type, value, false);
392 | }
393 | function maybeoperatorNoComma(type, value, noComma) {
394 | var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
395 | var expr = noComma == false ? expression : expressionNoComma;
396 | if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
397 | if (type == "operator") {
398 | if (/\+\+|--/.test(value)) return cont(me);
399 | if (value == "?") return cont(expression, expect(":"), expr);
400 | return cont(expr);
401 | }
402 | if (type == "quasi") { return pass(quasi, me); }
403 | if (type == ";") return;
404 | if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
405 | if (type == ".") return cont(property, me);
406 | if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
407 | }
408 | function quasi(type, value) {
409 | if (type != "quasi") return pass();
410 | if (value.slice(value.length - 2) != "${") return cont(quasi);
411 | return cont(expression, continueQuasi);
412 | }
413 | function continueQuasi(type) {
414 | if (type == "}") {
415 | cx.marked = "string-2";
416 | cx.state.tokenize = tokenQuasi;
417 | return cont(quasi);
418 | }
419 | }
420 | function arrowBody(type) {
421 | findFatArrow(cx.stream, cx.state);
422 | return pass(type == "{" ? statement : expression);
423 | }
424 | function arrowBodyNoComma(type) {
425 | findFatArrow(cx.stream, cx.state);
426 | return pass(type == "{" ? statement : expressionNoComma);
427 | }
428 | function maybelabel(type) {
429 | if (type == ":") return cont(poplex, statement);
430 | return pass(maybeoperatorComma, expect(";"), poplex);
431 | }
432 | function property(type) {
433 | if (type == "variable") {cx.marked = "property"; return cont();}
434 | }
435 | function objprop(type, value) {
436 | if (type == "variable" || cx.style == "keyword") {
437 | cx.marked = "property";
438 | if (value == "get" || value == "set") return cont(getterSetter);
439 | return cont(afterprop);
440 | } else if (type == "number" || type == "string") {
441 | cx.marked = jsonldMode ? "property" : (cx.style + " property");
442 | return cont(afterprop);
443 | } else if (type == "jsonld-keyword") {
444 | return cont(afterprop);
445 | } else if (type == "[") {
446 | return cont(expression, expect("]"), afterprop);
447 | }
448 | }
449 | function getterSetter(type) {
450 | if (type != "variable") return pass(afterprop);
451 | cx.marked = "property";
452 | return cont(functiondef);
453 | }
454 | function afterprop(type) {
455 | if (type == ":") return cont(expressionNoComma);
456 | if (type == "(") return pass(functiondef);
457 | }
458 | function commasep(what, end) {
459 | function proceed(type) {
460 | if (type == ",") {
461 | var lex = cx.state.lexical;
462 | if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
463 | return cont(what, proceed);
464 | }
465 | if (type == end) return cont();
466 | return cont(expect(end));
467 | }
468 | return function(type) {
469 | if (type == end) return cont();
470 | return pass(what, proceed);
471 | };
472 | }
473 | function contCommasep(what, end, info) {
474 | for (var i = 3; i < arguments.length; i++)
475 | cx.cc.push(arguments[i]);
476 | return cont(pushlex(end, info), commasep(what, end), poplex);
477 | }
478 | function block(type) {
479 | if (type == "}") return cont();
480 | return pass(statement, block);
481 | }
482 | function maybetype(type) {
483 | if (isTS && type == ":") return cont(typedef);
484 | }
485 | function typedef(type) {
486 | if (type == "variable"){cx.marked = "variable-3"; return cont();}
487 | }
488 | function vardef() {
489 | return pass(pattern, maybetype, maybeAssign, vardefCont);
490 | }
491 | function pattern(type, value) {
492 | if (type == "variable") { register(value); return cont(); }
493 | if (type == "[") return contCommasep(pattern, "]");
494 | if (type == "{") return contCommasep(proppattern, "}");
495 | }
496 | function proppattern(type, value) {
497 | if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
498 | register(value);
499 | return cont(maybeAssign);
500 | }
501 | if (type == "variable") cx.marked = "property";
502 | return cont(expect(":"), pattern, maybeAssign);
503 | }
504 | function maybeAssign(_type, value) {
505 | if (value == "=") return cont(expressionNoComma);
506 | }
507 | function vardefCont(type) {
508 | if (type == ",") return cont(vardef);
509 | }
510 | function maybeelse(type, value) {
511 | if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
512 | }
513 | function forspec(type) {
514 | if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
515 | }
516 | function forspec1(type) {
517 | if (type == "var") return cont(vardef, expect(";"), forspec2);
518 | if (type == ";") return cont(forspec2);
519 | if (type == "variable") return cont(formaybeinof);
520 | return pass(expression, expect(";"), forspec2);
521 | }
522 | function formaybeinof(_type, value) {
523 | if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
524 | return cont(maybeoperatorComma, forspec2);
525 | }
526 | function forspec2(type, value) {
527 | if (type == ";") return cont(forspec3);
528 | if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
529 | return pass(expression, expect(";"), forspec3);
530 | }
531 | function forspec3(type) {
532 | if (type != ")") cont(expression);
533 | }
534 | function functiondef(type, value) {
535 | if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
536 | if (type == "variable") {register(value); return cont(functiondef);}
537 | if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
538 | }
539 | function funarg(type) {
540 | if (type == "spread") return cont(funarg);
541 | return pass(pattern, maybetype);
542 | }
543 | function className(type, value) {
544 | if (type == "variable") {register(value); return cont(classNameAfter);}
545 | }
546 | function classNameAfter(type, value) {
547 | if (value == "extends") return cont(expression, classNameAfter);
548 | if (type == "{") return cont(pushlex("}"), classBody, poplex);
549 | }
550 | function classBody(type, value) {
551 | if (type == "variable" || cx.style == "keyword") {
552 | if (value == "static") {
553 | cx.marked = "keyword";
554 | return cont(classBody);
555 | }
556 | cx.marked = "property";
557 | if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
558 | return cont(functiondef, classBody);
559 | }
560 | if (value == "*") {
561 | cx.marked = "keyword";
562 | return cont(classBody);
563 | }
564 | if (type == ";") return cont(classBody);
565 | if (type == "}") return cont();
566 | }
567 | function classGetterSetter(type) {
568 | if (type != "variable") return pass();
569 | cx.marked = "property";
570 | return cont();
571 | }
572 | function afterModule(type, value) {
573 | if (type == "string") return cont(statement);
574 | if (type == "variable") { register(value); return cont(maybeFrom); }
575 | }
576 | function afterExport(_type, value) {
577 | if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
578 | if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
579 | return pass(statement);
580 | }
581 | function afterImport(type) {
582 | if (type == "string") return cont();
583 | return pass(importSpec, maybeFrom);
584 | }
585 | function importSpec(type, value) {
586 | if (type == "{") return contCommasep(importSpec, "}");
587 | if (type == "variable") register(value);
588 | if (value == "*") cx.marked = "keyword";
589 | return cont(maybeAs);
590 | }
591 | function maybeAs(_type, value) {
592 | if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
593 | }
594 | function maybeFrom(_type, value) {
595 | if (value == "from") { cx.marked = "keyword"; return cont(expression); }
596 | }
597 | function arrayLiteral(type) {
598 | if (type == "]") return cont();
599 | return pass(expressionNoComma, maybeArrayComprehension);
600 | }
601 | function maybeArrayComprehension(type) {
602 | if (type == "for") return pass(comprehension, expect("]"));
603 | if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
604 | return pass(commasep(expressionNoComma, "]"));
605 | }
606 | function comprehension(type) {
607 | if (type == "for") return cont(forspec, comprehension);
608 | if (type == "if") return cont(expression, comprehension);
609 | }
610 |
611 | function isContinuedStatement(state, textAfter) {
612 | return state.lastType == "operator" || state.lastType == "," ||
613 | isOperatorChar.test(textAfter.charAt(0)) ||
614 | /[,.]/.test(textAfter.charAt(0));
615 | }
616 |
617 | // Interface
618 |
619 | return {
620 | startState: function(basecolumn) {
621 | var state = {
622 | tokenize: tokenBase,
623 | lastType: "sof",
624 | cc: [],
625 | lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
626 | localVars: parserConfig.localVars,
627 | context: parserConfig.localVars && {vars: parserConfig.localVars},
628 | indented: 0
629 | };
630 | if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
631 | state.globalVars = parserConfig.globalVars;
632 | return state;
633 | },
634 |
635 | token: function(stream, state) {
636 | if (stream.sol()) {
637 | if (!state.lexical.hasOwnProperty("align"))
638 | state.lexical.align = false;
639 | state.indented = stream.indentation();
640 | findFatArrow(stream, state);
641 | }
642 | if (state.tokenize != tokenComment && stream.eatSpace()) return null;
643 | var style = state.tokenize(stream, state);
644 | if (type == "comment") return style;
645 | state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
646 | return parseJS(state, style, type, content, stream);
647 | },
648 |
649 | indent: function(state, textAfter) {
650 | if (state.tokenize == tokenComment) return CodeMirror.Pass;
651 | if (state.tokenize != tokenBase) return 0;
652 | var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
653 | // Kludge to prevent 'maybelse' from blocking lexical scope pops
654 | if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
655 | var c = state.cc[i];
656 | if (c == poplex) lexical = lexical.prev;
657 | else if (c != maybeelse) break;
658 | }
659 | if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
660 | if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
661 | lexical = lexical.prev;
662 | var type = lexical.type, closing = firstChar == type;
663 |
664 | if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
665 | else if (type == "form" && firstChar == "{") return lexical.indented;
666 | else if (type == "form") return lexical.indented + indentUnit;
667 | else if (type == "stat")
668 | return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
669 | else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
670 | return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
671 | else if (lexical.align) return lexical.column + (closing ? 0 : 1);
672 | else return lexical.indented + (closing ? 0 : indentUnit);
673 | },
674 |
675 | electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
676 | blockCommentStart: jsonMode ? null : "/*",
677 | blockCommentEnd: jsonMode ? null : "*/",
678 | lineComment: jsonMode ? null : "//",
679 | fold: "brace",
680 | closeBrackets: "()[]{}''\"\"``",
681 |
682 | helperType: jsonMode ? "json" : "javascript",
683 | jsonldMode: jsonldMode,
684 | jsonMode: jsonMode
685 | };
686 | });
687 |
688 | CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
689 |
690 | CodeMirror.defineMIME("text/javascript", "javascript");
691 | CodeMirror.defineMIME("text/ecmascript", "javascript");
692 | CodeMirror.defineMIME("application/javascript", "javascript");
693 | CodeMirror.defineMIME("application/x-javascript", "javascript");
694 | CodeMirror.defineMIME("application/ecmascript", "javascript");
695 | CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
696 | CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
697 | CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
698 | CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
699 | CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
700 |
701 | });
702 |
--------------------------------------------------------------------------------
/lib/jstat.min.js:
--------------------------------------------------------------------------------
1 | this.j$=this.jStat=function(a,b){function f(b,c){var d=b>c?b:c;return a.pow(10,17-~~(a.log(d>0?d:-d)*a.LOG10E))}function h(a){return e.call(a)==="[object Function]"}function i(a){return typeof a=="number"&&a===a}function j(a){return c.apply([],a)}function k(){return new k._init(arguments)}function l(){return 0}function m(){return 1}function n(a,b){return a===b?1:0}var c=Array.prototype.concat,d=Array.prototype.slice,e=Object.prototype.toString,g=Array.isArray||function(b){return e.call(b)==="[object Array]"};k.fn=k.prototype,k._init=function(b){var c;if(g(b[0]))if(g(b[0][0])){h(b[1])&&(b[0]=k.map(b[0],b[1]));for(c=0;c=0;c--,e++)d[e]=[b[e][c]];return d},k.transpose=function(b){var c=[],d,e,f,h,i;g(b[0])||(b=[b]),e=b.length,f=b[0].length;for(i=0;i0&&(i[e][0]=b[e][0]);for(j=1;j1?d.call(this):d.call(this)[0]},o.map=function(b,c){return k(k.map(this,b,c))},o.cumreduce=function(b,c){return k(k.cumreduce(this,b,c))},o.alter=function(b){return k.alter(this,b),this},function(a){for(var b=0;b=0)g+=a[b];return g},a.sumsqrd=function(b){var c=0,d=b.length;while(--d>=0)c+=b[d]*b[d];return c},a.sumsqerr=function(c){var d=a.mean(c),e=0,f=c.length,g;while(--f>=0)g=c[f]-d,e+=g*g;return e},a.product=function(b){var c=1,d=b.length;while(--d>=0)c*=b[d];return c},a.min=function(b){var c=b[0],d=0;while(++dc&&(c=b[d]);return c},a.mean=function(c){return a.sum(c)/c.length},a.meansqerr=function(c){return a.sumsqerr(c)/c.length},a.geomean=function(d){return b.pow(a.product(d),1/d.length)},a.median=function(b){var c=b.length,e=b.slice().sort(d);return c&1?e[c/2|0]:(e[c/2-1]+e[c/2])/2},a.cumsum=function(c){return a.cumreduce(c,function(a,b){return a+b})},a.cumprod=function(c){return a.cumreduce(c,function(a,b){return a*b})},a.diff=function(b){var c=[],d=b.length,e;for(e=1;eg?(i=[e[j]],g=f,h=0):f===g&&(i.push(e[j]),h++),f=1);return h===0?i[0]:i},a.range=function(c){return a.max(c)-a.min(c)},a.variance=function(c,d){return a.sumsqerr(c)/(c.length-(d?1:0))},a.stdev=function(d,e){return b.sqrt(a.variance(d,e))},a.meandev=function(d){var e=0,f=a.mean(d),g;for(g=d.length-1;g>=0;g--)e+=b.abs(d[g]-f);return e/d.length},a.meddev=function(d){var e=0,f=a.median(d),g;for(g=d.length-1;g>=0;g--)e+=b.abs(d[g]-f);return e/d.length},a.coeffvar=function(c){return a.stdev(c)/a.mean(c)},a.quartiles=function(c){var e=c.length,f=c.slice().sort(d);return[f[b.round(e/4)-1],f[b.round(e/2)-1],f[b.round(e*3/4)-1]]},a.quantiles=function(c,f,g,h){var i=c.slice().sort(d),j=[f.length],k=c.length,l,m,n,o,p,q;typeof g=="undefined"&&(g=3/8),typeof h=="undefined"&&(h=3/8);for(l=0;l1){i=d===!0?this:this.transpose();for(;h1){i=d===!0?this:this.transpose();for(;h1){g=g.transpose();for(;ej)for(k=0;k=1?d:1/d)*8.5+d*.4+17),p,q;if(e<0||d<=0)return NaN;if(e170||e>170?b.exp(a.combinationln(d,e)):a.factorial(d)/a.factorial(e)/a.factorial(d-e)},a.combinationln=function(c,d){return a.factorialln(c)-a.factorialln(d)-a.factorialln(c-d)},a.permutation=function(c,d){return a.factorial(c)/a.factorial(c-d)},a.betafn=function(d,e){return d<=0||e<=0?undefined:d+e>170?b.exp(a.betaln(d,e)):a.gammafn(d)*a.gammafn(e)/a.gammafn(d+e)},a.betaln=function(c,d){return a.gammaln(c)+a.gammaln(d)-a.gammaln(c+d)},a.betacf=function(c,d,e){var f=1e-30,g=1,h=d+e,i=d+1,j=d-1,k=1,l=1-h*c/i,m,n,o,p;b.abs(l)=1)return b.max(100,e+100*b.sqrt(e));if(d<=0)return 0;e>1?(o=b.log(g),p=b.exp(g*(o-1)-i),n=d<.5?d:1-d,l=b.sqrt(-2*b.log(n)),j=(2.30753+l*.27061)/(1+l*(.99229+l*.04481))-l,d<.5&&(j=-j),j=b.max(.001,e*b.pow(1-1/(9*e)-j/(3*b.sqrt(e)),3))):(l=1-e*(.253+e*.12),d1?l=p*b.exp(-(j-g)+g*(b.log(j)-o)):l=b.exp(-j+g*b.log(j)-i),m=k/l,j-=l=m/(1-.5*b.min(1,m*((e-1)/j-1))),j<=0&&(j=.5*(j+l));if(b.abs(l)0;e--)k=g,g=j*g-h+d[e],h=k;return l=i*b.exp(-c*c+.5*(d[0]+j*g)-h),f?l-1:1-l},a.erfc=function(c){return 1-a.erf(c)},a.erfcinv=function(d){var e=0,f,g,h,i;if(d>=2)return-100;if(d<=0)return 100;i=d<1?d:2-d,h=b.sqrt(-2*b.log(i/2)),f=-0.70711*((2.30753+h*.27061)/(1+h*(.99229+h*.04481))-h);for(;e<2;e++)g=a.erfc(f)-i,f+=g/(1.1283791670955126*b.exp(-f*f)-f*g);return d<1?f:-f},a.ibetainv=function(d,e,f){var g=1e-8,h=e-1,i=f-1,j=0,k,l,m,n,o,p,q,r,s,t,u;if(d<=0)return 0;if(d>=1)return 1;e>=1&&f>=1?(m=d<.5?d:1-d,n=b.sqrt(-2*b.log(m)),q=(2.30753+n*.27061)/(1+n*(.99229+n*.04481))-n,d<.5&&(q=-q),r=(q*q-3)/6,s=2/(1/(2*e-1)+1/(2*f-1)),t=q*b.sqrt(r+s)/s-(1/(2*f-1)-1/(2*e-1))*(r+5/6-2/(3*s)),q=e/(e+f*b.exp(2*t))):(k=b.log(e/(e+f)),l=b.log(f/(e+f)),n=b.exp(e*k)/e,o=b.exp(f*l)/f,t=n+o,d=1&&(q=.5*(q+n+1));if(b.abs(n)0)break}return q},a.ibeta=function(d,e,f){var g=d===0||d===1?0:b.exp(a.gammaln(e+f)-a.gammaln(e)-a.gammaln(f)+e*b.log(d)+f*b.log(1-d));return d<0||d>1?!1:d<(e+1)/(e+f+2)?g*a.betacf(d,e,f)/e:1-g*a.betacf(1-d,f,e)/f},a.randn=function(d,e){var f,g,h,i,j,k;e||(e=d);if(d)return a.create(d,e,function(){return a.randn()});do f=b.random(),g=1.7156*(b.random()-.5),h=f-.449871,i=b.abs(g)+.386595,j=h*h+i*(.196*i-.25472*h);while(j>.27597&&(j>.27846||g*g>-4*b.log(f)*f*f));return g/f},a.randg=function(d,e,f){var g=d,h,i,j,k,l,m;f||(f=e),d||(d=1);if(e)return m=a.zeros(e,f),m.alter(function(){return a.randg(d)}),m;d<1&&(d+=1),h=d-1/3,i=1/b.sqrt(9*h);do{do l=a.randn(),k=1+i*l;while(k<=0);k=k*k*k,j=b.random()}while(j>1-.331*b.pow(l,4)&&b.log(j)>.5*l*l+h*(1-k+b.log(k)));if(d==g)return h*k;do j=b.random();while(j===0);return b.pow(j,1/g)*h*k},function(b){for(var c=0;c1||d<0?0:e==1&&f==1?1:e<512||f<512?b.pow(d,e-1)*b.pow(1-d,f-1)/a.betafn(e,f):b.exp((e-1)*b.log(d)+(f-1)*b.log(1-d)-a.betaln(e,f))},cdf:function(c,d,e){return c>1||c<0?(c>1)*1:a.ibeta(c,d,e)},inv:function(c,d,e){return a.ibetainv(c,d,e)},mean:function(b,c){return b/(b+c)},median:function(b,c){throw new Error("median not yet implemented")},mode:function(c,d){return c*d/(b.pow(c+d,2)*(c+d+1))},sample:function(c,d){var e=a.randg(c);return e/(e+a.randg(d))},variance:function(c,d){return c*d/(b.pow(c+d,2)*(c+d+1))}}),a.extend(a.centralF,{pdf:function(d,e,f){var g,h,i;return d<0?undefined:e<=2?e===1&&f===1?Infinity:e===2&&f===1?1:b.sqrt(b.pow(e*d,e)*b.pow(f,f)/b.pow(e*d+f,e+f))/(d*a.betafn(e/2,f/2)):(g=e*d/(f+d*e),h=f/(f+d*e),i=e*h/2,i*a.binomial.pdf((e-2)/2,(e+f-2)/2,g))},cdf:function(c,d,e){return a.ibeta(d*c/(d*c+e),d/2,e/2)},inv:function(c,d,e){return e/(d*(1/a.ibetainv(c,d/2,e/2)-1))},mean:function(b,c){return c>2?c/(c-2):undefined},mode:function(b,c){return b>2?c*(b-2)/(b*(c+2)):undefined},sample:function(c,d){var e=a.randg(c/2)*2,f=a.randg(d/2)*2;return e/c/(f/d)},variance:function(b,c){return c<=4?undefined:2*c*c*(b+c-2)/(b*(c-2)*(c-2)*(c-4))}}),a.extend(a.cauchy,{pdf:function(c,d,e){return e/(b.pow(c-d,2)+b.pow(e,2))/b.PI},cdf:function(c,d,e){return b.atan((c-d)/e)/b.PI+.5},inv:function(a,c,d){return c+d*b.tan(b.PI*(a-.5))},median:function(b,c){return b},mode:function(b,c){return b},sample:function(d,e){return a.randn()*b.sqrt(1/(2*a.randg(.5)))*e+d}}),a.extend(a.chisquare,{pdf:function(d,e){return d===0?0:b.exp((e/2-1)*b.log(d)-d/2-e/2*b.log(2)-a.gammaln(e/2))},cdf:function(c,d){return a.lowRegGamma(d/2,c/2)},inv:function(b,c){return 2*a.gammapinv(b,.5*c)},mean:function(a){return a},median:function(c){return c*b.pow(1-2/(9*c),3)},mode:function(b){return b-2>0?b-2:0},sample:function(c){return a.randg(c/2)*2},variance:function(b){return 2*b}}),a.extend(a.exponential,{pdf:function(c,d){return c<0?0:d*b.exp(-d*c)},cdf:function(c,d){return c<0?0:1-b.exp(-d*c)},inv:function(a,c){return-b.log(1-a)/c},mean:function(a){return 1/a},median:function(a){return 1/a*b.log(2)},mode:function(b){return 0},sample:function(c){return-1/c*b.log(b.random())},variance:function(a){return b.pow(a,-2)}}),a.extend(a.gamma,{pdf:function(d,e,f){return b.exp((e-1)*b.log(d)-d/f-a.gammaln(e)-e*b.log(f))},cdf:function(c,d,e){return a.lowRegGamma(d,c/e)},inv:function(b,c,d){return a.gammapinv(b,c)*d},mean:function(a,b){return a*b},mode:function(b,c){return b>1?(b-1)*c:undefined},sample:function(c,d){return a.randg(c)*d},variance:function(b,c){return b*c*c}}),a.extend(a.invgamma,{pdf:function(d,e,f){return b.exp(-(e+1)*b.log(d)-f/d-a.gammaln(e)+e*b.log(f))},cdf:function(c,d,e){return 1-a.lowRegGamma(d,e/c)},inv:function(b,c,d){return d/a.gammapinv(1-b,c)},mean:function(a,b){return a>1?b/(a-1):undefined},mode:function(b,c){return c/(b+1)},sample:function(c,d){return d/a.randg(c)},variance:function(b,c){return b<=2?undefined:c*c/((b-1)*(b-1)*(b-2))}}),a.extend(a.kumaraswamy,{pdf:function(c,d,e){return b.exp(b.log(d)+b.log(e)+(d-1)*b.log(c)+(e-1)*b.log(1-b.pow(c,d)))},cdf:function(c,d,e){return 1-b.pow(1-b.pow(c,d),e)},mean:function(b,c){return c*a.gammafn(1+1/b)*a.gammafn(c)/a.gammafn(1+1/b+c)},median:function(c,d){return b.pow(1-b.pow(2,-1/d),1/c)},mode:function(c,d){return c>=1&&d>=1&&c!==1&&d!==1?b.pow((c-1)/(c*d-1),1/c):undefined},variance:function(b,c){throw new Error("variance not yet implemented")}}),a.extend(a.lognormal,{pdf:function(c,d,e){return b.exp(-b.log(c)-.5*b.log(2*b.PI)-b.log(e)-b.pow(b.log(c)-d,2)/(2*e*e))},cdf:function(d,e,f){return.5+.5*a.erf((b.log(d)-e)/b.sqrt(2*f*f))},inv:function(c,d,e){return b.exp(-1.4142135623730951*e*a.erfcinv(2*c)+d)},mean:function(c,d){return b.exp(c+d*d/2)},median:function(c,d){return b.exp(c)},mode:function(c,d){return b.exp(c-d*d)},sample:function(d,e){return b.exp(a.randn()*e+d)},variance:function(c,d){return(b.exp(d*d)-1)*b.exp(2*c+d*d)}}),a.extend(a.normal,{pdf:function(c,d,e){return b.exp(-0.5*b.log(2*b.PI)-b.log(e)-b.pow(c-d,2)/(2*e*e))},cdf:function(d,e,f){return.5*(1+a.erf((d-e)/b.sqrt(2*f*f)))},inv:function(b,c,d){return-1.4142135623730951*d*a.erfcinv(2*b)+c},mean:function(a,b){return a},median:function(b,c){return b},mode:function(a,b){return a},sample:function(c,d){return a.randn()*d+c},variance:function(a,b){return b*b}}),a.extend(a.pareto,{pdf:function(c,d,e){return c.5?e:-e},mean:function(b){return b>1?0:undefined},median:function(b){return 0},mode:function(b){return 0},sample:function(d){return a.randn()*b.sqrt(d/(2*a.randg(d/2)))},variance:function(b){return b>2?b/(b-2):b>1?Infinity:undefined}}),a.extend(a.weibull,{pdf:function(c,d,e){return c<0?0:e/d*b.pow(c/d,e-1)*b.exp(-b.pow(c/d,e))},cdf:function(c,d,e){return c<0?0:1-b.exp(-b.pow(c/d,e))},inv:function(a,c,d){return c*b.pow(-b.log(1-a),1/d)},mean:function(b,c){return b*a.gammafn(1+1/c)},median:function(c,d){return c*b.pow(b.log(2),1/d)},mode:function(c,d){return d<=1?undefined:c*b.pow((d-1)/d,1/d)},sample:function(c,d){return c*b.pow(-b.log(b.random()),1/d)},variance:function(d,e){return d*d*a.gammafn(1+2/e)-b.pow(this.mean(d,e),2)}}),a.extend(a.uniform,{pdf:function(b,c,d){return bd?0:1/(d-c)},cdf:function(b,c,d){return bg||d>f)return 0;if(f*2>e)return g*2>e?a.hypgeom.pdf(e-f-g+d,e,e-f,e-g):a.hypgeom.pdf(g-d,e,e-f,g);if(g*2>e)return a.hypgeom.pdf(f-d,e,f,e-g);if(f1&&i=g||d>=f)return 1;if(f*2>e)return g*2>e?a.hypgeom.cdf(e-f-g+d,e,e-f,e-g):1-a.hypgeom.cdf(g-d-1,e,e-f,g);if(g*2>e)return 1-a.hypgeom.cdf(f-d-1,e,f,e-g);if(f1&&jf);return e-1}}),a.extend(a.triangular,{pdf:function(b,c,d,e){return d<=c||ed?undefined:bd?0:b<=e?2*(b-c)/((d-c)*(e-c)):2*(d-b)/((d-c)*(d-e))},cdf:function(c,d,e,f){return e<=d||fe?undefined:c(c+d)/2)return c+b.sqrt((d-c)*(e-c))/b.sqrt(2)},mode:function(b,c,d){return d},sample:function(c,d,e){var f=b.random();return f<(e-c)/(d-c)?c+b.sqrt(f*(d-c)*(e-c)):d-b.sqrt((1-f)*(d-c)*(d-e))},variance:function(b,c,d){return(b*b+c*c+d*d-b*c-b*d-c*d)/18}})}(this.jStat,Math),function(a,b){var d=Array.prototype.push,e=a.utils.isArray;a.extend({add:function(c,d){return e(d)?(e(d[0])||(d=[d]),a.map(c,function(a,b,c){return a+d[b][c]})):a.map(c,function(a){return a+d})},subtract:function(c,d){return e(d)?(e(d[0])||(d=[d]),a.map(c,function(a,b,c){return a-d[b][c]||0})):a.map(c,function(a){return a-d})},divide:function(c,d){return e(d)?(e(d[0])||(d=[d]),a.multiply(c,a.inv(d))):a.map(c,function(a){return a/d})},multiply:function(c,d){var f,g,h,i,j=c.length,k=c[0].length,l=a.zeros(j,h=e(d)?d[0].length:k),m=0;if(e(d)){for(;m=0;f--){k=0;for(g=f+1;g<=h-1;g++)k+=l[g]*d[f][g];l[f]=(d[f][m-1]-k)/d[f][f]}return l},gauss_jordan:function(e,f){var g=a.aug(e,f),h=g.length,i=g[0].length;for(var j=0;jb.abs(g[k][j])&&(k=l);var m=g[j];g[j]=g[k],g[k]=m;for(var l=j+1;l=0;j--){c=g[j][j];for(var l=0;lj-1;n--)g[l][n]-=g[j][n]*g[l][j]/c;g[j][j]/=c;for(var n=h;ni?(k[h][i]=d[h][i],l[h][i]=m[h][i]=0):hg)n=q,q=a.add(a.multiply(p,n),o),h++;return q},gauss_seidel:function(d,e,f,g){var h=0,i=d.length,j=[],k=[],l=[],m,n,o,p,q;for(;hm?(j[h][m]=d[h][m],k[h][m]=l[h][m]=0):hg)n=q,q=a.add(a.multiply(p,n),o),h+=1;return q},SOR:function(d,e,f,g,h){var i=0,j=d.length,k=[],l=[],m=[],n,o,p,q,r;for(;in?(k[i][n]=d[i][n],l[i][n]=m[i][n]=0):ig)o=r,r=a.add(a.multiply(q,o),p),i++;return r},householder:function(d){var e=d.length,f=d[0].length,g=0,h=[],i=[],j,k,l,m,n;for(;g0?-1:1,j=n*b.sqrt(j),k=b.sqrt((j*j-d[g+1][g]*j)/2),h=a.zeros(e,1),h[g+1][0]=(d[g+1][g]-j)/(2*k);for(l=g+2;l0?-1:1,m=p*b.sqrt(m),n=b.sqrt((m*m-d[h+1][h]*m)/2),i=a.zeros(f,1),i[h+1][0]=(d[h+1][h]-m)/(2*n);for(o=h+2;o=0;h--){q=0;for(l=h+1;l<=g-1;l++)q=k[l]*d[h][l];k[h]=e[h][0]/d[h][h]}return k},jacobi:function(d){var e=1,f=0,g=d.length,h=a.identity(g,g),i=[],j,k,l,m,n,o,p,q;while(e===1){f++,o=d[0][1],m=0,n=1;for(k=0;k0?b.PI/4:-b.PI/4:p=b.atan(2*d[m][n]/(d[m][m]-d[n][n]))/2,q=a.identity(g,g),q[m][m]=b.cos(p),q[m][n]=-b.sin(p),q[n][m]=b.sin(p),q[n][n]=b.cos(p),h=a.multiply(h,q),j=a.multiply(a.multiply(a.inv(q),d),q),d=j,e=0;for(k=1;k.001&&(e=1)}for(k=0;k=i)m=g(c,e+f),n=g(c,e),k[j]=(d[m]-2*d[n]+d[2*n-m])/(f*f),f/=2,j++;p=k.length,o=1;while(p!=1){for(q=0;qe)break;return h-=1,d[h]+(e-c[h])*n[h]+a.sq(e-c[h])*l[h]+(e-c[h])*a.sq(e-c[h])*o[h]},gauss_quadrature:function(){throw new Error("gauss_quadrature not yet implemented")},PCA:function(c){var d=c.length,e=c[0].length,f=!1,g=0,h,i,j=[],k=[],l=[],m=[],n=[],o=[],p=[],q=[],r=[],s=[];for(g=0;g.
20 |
21 | */
22 |
23 |
24 | //*****************************************************
25 |
26 | //close prices
27 | //column 11 is 'Adjusted Close' on Y!
28 | //column 4 is 'Close' on Goog
29 |
30 | function getQuandlCall(source, ticker, key){
31 |
32 | if (source == "GOOG"){
33 | var column = 4;
34 | }
35 | else if (source == "YAHOO") {
36 | var column = 6;
37 |
38 | //yahoo doesn't have proper server side setup
39 | /*
40 | var column = 7;
41 | return {
42 | url:'http://crossorigin.me/http://real-chart.finance.yahoo.com/table.csv?s='+ticker,
43 | ticker:ticker
44 | };
45 | */
46 | }
47 | else if (source == "CBOE") {
48 | var column = 1;
49 | }
50 | else if (source == "SPDJ") {
51 | var column = 1;
52 | }
53 |
54 | return {
55 | url:'https://www.quandl.com/api/v1/datasets/'+source+'/'+ticker+'.json?column='+column+'&auth_token='+key,
56 | ticker:ticker
57 | };
58 | }
59 |
60 |
61 |
62 | //*****************************************************
63 | //make api call
64 | xhr = function(){
65 | var xmlhttp = new XMLHttpRequest();
66 | xmlhttp.open("GET", this.url, false);
67 | xmlhttp.send();
68 |
69 |
70 | return JSON.parse(xmlhttp.responseText).data;
71 | }
72 |
73 | Object.defineProperty(
74 | Object.prototype,
75 | 'xhr',
76 | {
77 | value: xhr,
78 | writable: true,
79 | configurable: true,
80 | enumerable: false
81 | }
82 | );
83 |
84 |
--------------------------------------------------------------------------------
/lib/strategyHelpers.js:
--------------------------------------------------------------------------------
1 | /*
2 | (c)2015 John Orford
3 |
4 | This file is part of Lazy Backtesting.
5 |
6 | Lazy Backtesting is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Affero General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | Lazy Backtesting is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Affero General Public License for more details.
15 |
16 | You should have received a copy of the GNU Affero General Public License
17 | along with Lazy Backtesting. If not, see .
18 |
19 | */
20 |
21 | //***************************************************************************
22 |
23 | Array.prototype.returns = function(){
24 | return _.reduce(
25 | this,
26 | function(acc,cur){
27 | if(acc.prev===null){
28 | return {result:[],prev:cur.datum};
29 | }
30 | else{
31 | return {result: acc.result.concat( Math.log(acc.prev/cur.datum) ),
32 | prev:cur.datum
33 | };
34 | }
35 | },
36 | {result:[],prev:null}
37 | )
38 | .result;
39 | }
40 |
41 | Array.prototype.prices = function(){
42 | return _.map( this,
43 | function(cur){
44 | return cur.datum;
45 | }
46 | );
47 | }
48 |
49 | Array.prototype.dsfct = function(){
50 | return _.map(
51 | this,
52 | function(cur){
53 | return Math.exp(-cur.datum/100);
54 | }
55 | );
56 | }
57 |
58 | Array.prototype.prices = function(){
59 | return _.map( this,
60 | function(cur){
61 | return cur.datum;
62 | }
63 | );
64 | }
65 |
66 | Array.prototype.period = function(p){
67 | return _.reduce(
68 | this,
69 | function(acc,cur){
70 |
71 | if (acc.counter%p === 0){
72 | return {result:acc.result.concat(cur),counter:acc.counter+1};
73 | }
74 | else {
75 | return {result:acc.result,counter:acc.counter+1};
76 | }
77 | }
78 | ,{result:[],counter:0}
79 | )
80 | .result;
81 | }
82 |
83 | Array.prototype.quarterly = function(){
84 | return this.period(63);
85 | }
86 | Array.prototype.monthly = function(){
87 | return this.period(21);
88 | }
89 | Array.prototype.weekly = function(){
90 | return this.period(5);
91 | }
92 | Array.prototype.daily = function(){
93 | return this;
94 | }
95 |
96 | Array.prototype.lookback = function(p){
97 | //take a number of elements
98 | //throw error if number of elements is less than amount requested
99 | var r = Lazy(this).take(p).toArray();
100 |
101 | if (r.length === p){return r;}
102 | else {throw "Not enough data left";}
103 | }
104 | //***************************************************************************
105 |
--------------------------------------------------------------------------------
/lib/utility.js:
--------------------------------------------------------------------------------
1 | /*
2 | (c)2015 John Orford
3 |
4 | This file is part of Lazy Backtesting.
5 |
6 | Lazy Backtesting is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU Affero General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | Lazy Backtesting is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU Affero General Public License for more details.
15 |
16 | You should have received a copy of the GNU Affero General Public License
17 | along with Lazy Backtesting. If not, see .
18 |
19 | */
20 |
21 |
22 | //*****************************************************
23 |
24 | Number.prototype.yieldToDsft = function(){
25 | return Math.exp(-this/100);
26 | }
27 |
28 |
29 |
30 | //*****************************************************
31 |
32 |
33 | write = function(desc,id){
34 |
35 | if (id === undefined){
36 | id = "messages";
37 | }
38 |
39 | var p = document.createElement('p');
40 | var text = document.createTextNode(desc+" "+this);
41 | p.appendChild(text);
42 | document.getElementById(id).appendChild(p);
43 |
44 | }
45 |
46 | Object.defineProperty(
47 | Object.prototype,
48 | 'write',
49 | {
50 | value: write,
51 | writable: true,
52 | configurable: true,
53 | enumerable: false
54 | }
55 | );
56 |
57 | //*****************************************************
58 |
59 |
60 | //print between dot passing
61 | tap2 = function(desc,id,status){
62 | this.ticker.write(desc,id);
63 | return this;
64 | }
65 |
66 |
67 | Object.defineProperty(
68 | Object.prototype,
69 | 'tap2',
70 | {
71 | value: tap2,
72 | writable: true,
73 | configurable: true,
74 | enumerable: false
75 | }
76 | );
77 |
78 | //*****************************************************
79 |
80 |
81 | function isFunction(functionToCheck) {
82 | var getType = {};
83 | return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
84 | }
85 |
86 |
--------------------------------------------------------------------------------