diff --git a/.github/workflows/legal-report.yml b/.github/workflows/legal-report.yml index 0bf4b5861..dfc94eb06 100644 --- a/.github/workflows/legal-report.yml +++ b/.github/workflows/legal-report.yml @@ -17,7 +17,7 @@ jobs: java-version: 1.16 cache: maven - name: Build with Maven - run: mvn clean install -Dmaven.test.skip=true + run: mvn clean install - name: License report run: mvn org.apache.maven.plugins:maven-site-plugin:3.12.1:site org.apache.maven.plugins:maven-project-info-reports-plugin:3.4.1:licenses -P legal-report @@ -37,7 +37,7 @@ jobs: - name: Install XQ run: pip install xq - name: Build with Maven - run: mvn clean install -Dmaven.test.skip=true + run: mvn clean install - name: License XML report run: mvn org.codehaus.mojo:license-maven-plugin:2.0.0:download-licenses - name: Validate XML report diff --git a/.semgrepignore b/.semgrepignore index 5b374e053..ded413c74 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -1,6 +1,9 @@ .github/workflows/release-mvn-central.yml vuu/src/main/resources/certs/key.pem +example/main/src/main/resources/certs/key.pem +example/main/src/main/resources/certs/cert.pem vuu/src/main/resources/www/ws-example.html +example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala vuu-ui/packages/vuu-data/src/array-data-source/group-utils.ts vuu-ui/packages/vuu-datagrid-extras/src/column-expression-input/column-language-parser/walkExpressionTree.ts diff --git a/benchmark/pom.xml b/benchmark/pom.xml index 733c759d6..4bf6b0be9 100644 --- a/benchmark/pom.xml +++ b/benchmark/pom.xml @@ -4,7 +4,7 @@ org.finos.vuu vuu-parent - 0.5.09-SNAPSHOT + 0.9.36-SNAPSHOT @@ -22,7 +22,7 @@ org.finos.vuu vuu - 0.5.09-SNAPSHOT + 0.9.36-SNAPSHOT diff --git a/docs/getting_started/developing.md b/docs/getting_started/developing.md index b1e1e6d28..8189bb1b0 100644 --- a/docs/getting_started/developing.md +++ b/docs/getting_started/developing.md @@ -43,7 +43,7 @@ cd vuu #run the maven compile step mvn compile #cd into vuu, child in repo -cd vuu +cd example/main #The server should now be started on your machine with Simulation module mvn exec:exec ``` diff --git a/example/basket/pom.xml b/example/basket/pom.xml new file mode 100644 index 000000000..5da3ef8bd --- /dev/null +++ b/example/basket/pom.xml @@ -0,0 +1,271 @@ + + + 4.0.0 + + + org.finos.vuu + example + 0.9.36-SNAPSHOT + + + basket + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + tests + test-jar + test + + + + org.finos.vuu + price + 0.9.36-SNAPSHOT + + + + org.finos.vuu + order + 0.9.36-SNAPSHOT + + + + org.scala-lang + scala-library + ${scala.version} + + + + org.scala-lang + scala-reflect + ${scala.version} + + + + junit + junit + 4.13.2 + test + + + + org.scalatest + scalatest_2.13 + ${scalatest.version} + test + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + + + + + + + + + sign-it + + + sign + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + + + + legal-report + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + **/*.scala + + + + + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-source-plugin + + + + compile + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.ow2.asm + asm + 6.2 + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + + compile + testCompile + + + + + src/main/scala + src/test/scala + + -Xms64m + -Xmx1024m + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + + test-jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7 + + + + + + + org.scalatest + scalatest-maven-plugin + 2.0.2 + + ${project.build.directory}/surefire-reports + . + test-reports.txt + + + + test + + test + + + + + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + ${scala.version} + + + + + + \ No newline at end of file diff --git a/example/basket/src/main/java/Dummy4JavaDoc.java b/example/basket/src/main/java/Dummy4JavaDoc.java new file mode 100644 index 000000000..00b8d1897 --- /dev/null +++ b/example/basket/src/main/java/Dummy4JavaDoc.java @@ -0,0 +1,2 @@ +public class Dummy4JavaDoc { +} diff --git a/example/basket/src/main/resources/static/ftse100.csv b/example/basket/src/main/resources/static/ftse100.csv new file mode 100644 index 000000000..aa0315f95 --- /dev/null +++ b/example/basket/src/main/resources/static/ftse100.csv @@ -0,0 +1,100 @@ +Symbol,Name,Last Trade,Change,Volume, Weighting +AAL.L,Anglo American PLC,436.35�13:13,�5.35�(1.24%),5799089,0.0278736825813547 +ABF.L,Associated British Foods PLC,"3,435.60�13:12",�7.40�(0.21%),86808,0.000417248060431947 +ADM.L,Admiral Group PLC,"1,627.00�13:13",,86808,0.000417248060431947 +ADN.L,Aberdeen Asset Management PLC,334.00�13:13,�2.50�(0.75%),806880,0.00387831899135251 +AHT.L,Ashtead Group PLC,"1,027.00�13:13",�6.00�(0.59%),331255,0.00159219779580666 +ANTO.L,Antofagasta PLC,484.10�13:13,�11.70�(2.48%),1753976,0.00843059492263598 +ARM.L,ARM Holdings PLC,"1,058.00�13:13",�3.00�(0.28%),475927,0.00228757277736148 +AV.L,Aviva PLC,493.97�13:13,�2.23�(0.45%),2226835,0.0107034211668507 +AZN.L,AstraZeneca PLC,"4,399.50�13:13",�2.50�(0.06%),815133,0.00391798755004232 +BA.L,BAE Systems PLC,478.10�13:13,�4.30�(0.91%),2039934,0.00980506986578636 +BAB.L,Babcock International Group PLC,988.00�13:13,�9.50�(0.97%),209614,0.00100752275066102 +BARC.L,Barclays PLC,226.30�13:13,�1.15�(0.51%),6575664,0.0316063387021032 +BATS.L,British American Tobacco PLC,"3,803.50�13:13",�8.50�(0.22%),465110,0.0022355801929258 +BDEV.L,Barratt Developments PLC,576.00�13:13,�0.50�(0.09%),1044365,0.00501980543997108 +BG.L,BG Group PLC,"1,013.50�13:13",�5.50�(0.55%),1507332,0.00724508516988073 +BKG.L,Berkeley Group Holdings (The) PLC,"3,126.00�13:13",�15.00�(0.48%),95071,0.000456964684744788 +BLND.L,British Land Co PLC,828.06�13:12,�10.44�(1.25%),1802548,0.00866405926683583 +BLT.L,BHP Billiton PLC,881.40�13:13,�4.30�(0.49%),4947287,0.0237794431982097 +BNZL.L,Bunzl PLC,"1,875.40�13:05",�4.60�(0.24%),104541,0.000502482829757812 +BP.L,BP PLC,381.50�13:13,�2.95�(0.78%),10493561,0.0504379547308349 +BRBY.L,Burberry Group PLC,"1,269.00�13:13",�7.00�(0.55%),295647,0.00142104572530785 +BT-A.L,BT Group PLC,489.20�13:13,�3.70�(0.75%),3914982,0.0188176048996174 +CCL.L,Carnival PLC,"3,426.00�13:12",�22.00�(0.64%),86257,0.000414599644602783 +CNA.L,Centrica PLC,212.80�13:13,�0.60�(0.28%),2144540,0.0103078651220939 +CPG.L,Compass Group PLC,"1,054.00�13:08",�5.00�(0.48%),1001167,0.00481217156158961 +CPI.L,Capita PLC,"1,235.00�13:11",�1.00�(0.08%),244591,0.0011756418803464 +CRH.L,CRH PLC,"1,783.20�13:12",�17.80�(0.99%),897325,0.00431304851888186 +DC.L,DIXONS CARPHONE,462.10�13:11,,756906,0.00363811584680332 +DGE.L,Diageo PLC,"1,881.50�13:13",�6.50�(0.34%),756906,0.00363811584680332 +DLG.L,Direct Line Insurance Group PLC,403.80�13:13,�0.40�(0.10%),1095340,0.00526481995338596 +EXPN.L,Experian PLC,"1,191.00�13:12",�2.00�(0.17%),467283,0.00224602485281105 +EZJ.L,easyJet PLC,"1,682.00�13:12",�28.00�(1.64%),1191230,0.00572572121265722 +FRES.L,Fresnillo PLC,678.50�13:12,�6.50�(0.97%),381871,0.00183548675335462 +GFS.L,G4S PLC,232.30�13:03,�2.00�(0.85%),1096551,0.00527064070033535 +GKN.L,GKN PLC,294.80�13:12,�2.50�(0.86%),792247,0.00380798456516713 +GLEN.L,Glencore PLC,90.48�13:13,�1.65�(1.86%),41631528,0.200104533116974 +GSK.L,GlaxoSmithKline PLC,"1,345.00�13:13",�0.50�(0.04%),1767356,0.00849490672625522 +HIK.L,Hikma Pharmaceuticals PLC,"2,010.00�13:04",�57.00�(2.92%),261511,0.00125696891451962 +HL.L,Hargreaves Lansdown PLC,"1,488.03�13:12",�9.97�(0.67%),372261,0.00178929568961912 +HMSO.L,Hammerson PLC,597.50�13:11,�3.50�(0.58%),478301,0.0022989835562697 +HSBA.L,HSBC Holdings PLC,519.70�13:13,�0.50�(0.10%),7415629,0.0356436828072631 +IAG.L,International Consolidated Airlines Group SA,575.40�13:12,�16.10�(2.72%),4311514,0.0207235606629018 +IHG.L,InterContinental Hotels Group PLC,"2,481.00�13:12",�19.00�(0.76%),219918,0.00105704956863507 +III.L,3i Group PLC,487.30�13:11,�4.50�(0.92%),189987,0.000913184352332553 +IMT.L,Imperial Tobacco Group PLC,"3,571.00�13:13",�29.00�(0.81%),926816,0.00445479884777089 +INTU.L,intu properties plc,319.90�13:09,�4.60�(1.42%),514821,0.0024745192115892 +ISAT.L,Inmarsat PLC,"1,054.44�13:13",�3.44�(0.33%),988089,0.00474931133978598 +ITRK.L,Intertek Group PLC,"2,643.00�13:14",�3.00�(0.11%),45868,0.000220467399731505 +ITV.L,ITV PLC,267.30�13:14,�2.60�(0.96%),3453208,0.0165980593985356 +JMAT.L,Johnson Matthey PLC,"2,445.00�13:14",�29.00�(1.20%),276397,0.00132851940096775 +KGF.L,Kingfisher PLC,346.20�13:14,�4.30�(1.23%),1021408,0.00490946118917235 +LAND.L,Land Securities Group PLC,"1,239.00�13:13",�7.00�(0.56%),384973,0.00185039670961971 +LGEN.L,Legal & General Group PLC,266.00�13:14,�1.60�(0.60%),1998399,0.00960542930051541 +LLOY.L,Lloyds Banking Group PLC,73.86�13:14,�0.02�(0.03%),18907878,0.0908818936317375 +LSE.L,London Stock Exchange Group PLC,"2,544.00�13:11",�6.00�(0.24%),129657,0.000623204448569543 +MGGT.L,Meggitt PLC,386.00�13:15,�3.20�(0.84%),611044,0.00293702105610748 +MKS.L,Marks & Spencer Group PLC,514.75�13:12,�3.25�(0.63%),920128,0.00442265255908587 +MNDI.L,Mondi PLC,"1,463.00�13:14",�7.00�(0.48%),383546,0.00184353774521278 +MRW.L,Morrison (Wm) Supermarkets PLC,155.20�13:14,,920128,0.00442265255908587 +NG.L,National Grid PLC,926.40�13:14,�1.10�(0.12%),1659592,0.00797693234619361 +NXT.L,Next PLC,"7,765.00�13:11",�95.00�(1.21%),114062,0.000548246109448308 +OML.L,Old Mutual PLC,198.50�13:14,�0.40�(0.20%),2040849,0.00980946787029396 +PRU.L,Prudential PLC,"1,499.50�13:15",�14.00�(0.93%),580870,0.00279198784516525 +PSON.L,Pearson PLC,794.00�13:09,�5.00�(0.63%),1177953,0.00566190448495522 +RB.L,Reckitt Benckiser Group PLC,"6,293.00�13:14",�34.00�(0.54%),281172,0.0013514707359664 +RBS.L,Royal Bank of Scotland Group PLC,313.40�13:14,�2.40�(0.77%),2100058,0.0100940596177149 +RDSA.L,Royal Dutch Shell PLC,"1,636.00�13:14",�18.00�(1.11%),2467461,0.0118600050276642 +RDSB.L,Royal Dutch Shell PLC,"1,652.00�13:15",�14.50�(0.89%),1457434,0.0070052473240666 +REL.L,Reed Elsevier PLC,"1,170.00�13:14",0.00�(0.00%),908802,0.00436821343443777 +RIO.L,Rio Tinto PLC,"2,235.00�13:15",�21.00�(0.95%),2190722,0.0105298417823887 +RMG.L,Royal Mail PLC,453.50�13:14,�1.20�(0.26%),995316,0.00478404836555252 +RR.L,Rolls-Royce Group PLC,546.63�13:14,�8.38�(1.51%),2792915,0.0134243199555489 +RRS.L,Randgold Resources Ltd,"3,929.00�13:14",0.00�(0.00%),135524,0.000651404549603483 +RSA.L,RSA Insurance Group PLC,437.10�13:14,�0.10�(0.02%),395477,0.00190088484005443 +SAB.L,SABMiller PLC,"4,011.00�13:15",�1.00�(0.02%),892451,0.00428962133421518 +SBRY.L,Sainsbury (J) PLC,255.80�13:14,�7.40�(2.98%),2395670,0.0115149371133421 +SDR.L,Schroders PLC,"2,930.00�13:09",�12.00�(0.41%),44674,0.000214728364341268 +SGE.L,Sage Group (The) PLC,545.50�13:13,�0.50�(0.09%),539717,0.00259418338669419 +SHP.L,Shire PLC,"4,685.00�13:14",�22.00�(0.47%),221318,0.0010637787558598 +SKY.L,SKY,"1,095.00�13:12",�4.00�(0.37%),925016,0.0044461470356248 +SL.L,Standard Life PLC,399.90�13:14,�3.20�(0.79%),861636,0.00414150711683647 +SMIN.L,Smiths Group PLC,992.50�13:14,�27.50�(2.70%),640309,0.00307768510191594 +SN.L,Smith & Nephew PLC,"1,110.00�13:14",�9.00�(0.82%),480018,0.00230723642374461 +SPD.L,Sports Direct International PLC,694.50�13:11,�1.50�(0.22%),157981,0.000759345519250522 +SSE.L,SSE PLC,"1,463.00�13:13",�2.00�(0.14%),562454,0.00270347019378617 +STAN.L,Standard Chartered PLC,583.00�13:14,�0.60�(0.10%),2018697,0.00970299290214945 +STJ.L,St James's Place PLC,964.00�13:14,�11.00�(1.13%),418480,0.00201145019271912 +SVT.L,Severn Trent PLC,"2,199.00�13:12",�1.00�(0.05%),95342,0.000458267263129005 +TPK.L,Travis Perkins PLC,"1,945.00�13:13",�4.00�(0.21%),92916,0.000446606542981001 +TSCO.L,Tesco PLC,171.54�13:14,�2.54�(1.50%),9831136,0.0472539676970174 +TUI.L,TUI AG,"1,115.00�13:10",�5.00�(0.45%),458970,0.00220606790038304 +TW.L,Taylor Wimpey PLC,183.90�13:15,�1.10�(0.59%),3180729,0.0152883721086725 +ULVR.L,Unilever PLC,"2,791.00�13:14",�29.00�(1.03%),824827,0.0039645823650113 +UU.L,United Utilities Group PLC,959.00�13:10,�2.50�(0.26%),436911,0.00210003994253274 +VOD.L,Vodafone Group PLC,224.25�13:15,�1.30�(0.58%),17572036,0.0844610858312637 +WOS.L,Wolseley PLC,"3,657.00�13:14",�4.00�(0.11%),179536,0.000862950969699912 +WPP.L,WPP PLC,"1,502.00�13:15",�12.00�(0.79%),857887,0.0041234873147611 +WTB.L,Whitbread PLC,"4,484.00�13:16",�60.00�(1.32%),141036,0.000677898321019722 +,,,,208048900, diff --git a/example/basket/src/main/resources/static/hsi.csv b/example/basket/src/main/resources/static/hsi.csv new file mode 100644 index 000000000..fcd24d46c --- /dev/null +++ b/example/basket/src/main/resources/static/hsi.csv @@ -0,0 +1,81 @@ +Name,Symbol,Last,Change,Change %,Volume,Turn.,P/E,P/B,Yield,Market Cap,Weighting +CKH HOLDINGS,00001.HK,41.9,1.15,+2.822%,5.15M,215.13M,4.38,0.31,6.98%,160.48B,0.0278736825813547 +CLP HOLDINGS,00002.HK,57.95,-0.1,-0.172%,3.32M,193.19M,156.62,1.39,5.35%,146.41B,0.000417248060431947 +HK & CHINA GAS,00003.HK,5.46,0.13,+2.439%,16.16M,88.00M,19.43,1.66,6.41%,101.88B,0.000417248060431947 +HSBC HOLDINGS,00005.HK,61.7,1.1,+1.815%,22.19M,1.37B,10.54,0.86,4.05%,1,0.00387831899135251 +POWER ASSETS,00006.HK,37.9,-0.25,-0.655%,4.23M,160.75M,14.3,0.93,7.44%,80.77B,0.00159219779580666 +HANG SENG BANK,00011.HK,97.45,2.95,+3.122%,2.54M,247.44M,19.69,1.01,4.21%,186.31B,0.00843059492263598 +HENDERSON LAND,00012.HK,20.65,0.85,+4.293%,5.07M,103.70M,10.81,0.31,8.72%,99.97B,0.00228757277736148 +SHK PPT,00016.HK,83.8,3.25,+4.035%,8.25M,685.41M,10.16,0.4,5.91%,242.83B,0.0107034211668507 +NEW WORLD DEV,00017.HK,15.24,0.8,+5.540%,12.95M,196.19M,30.48,0.18,13.52%,38.35B,0.00391798755004232 +GALAXY ENT,00027.HK,47.15,1.9,+4.199%,11.97M,560.21M,No Profit,3.22,0.00%,206.21B,0.00980506986578636 +MTR CORPORATION,00066.HK,31,0.8,+2.649%,4.68M,144.86M,19.5,1.07,4.23%,192.64B,0.00100752275066102 +HANG LUNG PPT,00101.HK,10.72,0.56,+5.512%,7.68M,81.99M,12.61,0.36,7.28%,48.23B,0.0316063387021032 +GEELY AUTO,00175.HK,9.24,0.17,+1.874%,18.77M,173.30M,16.06,1.15,2.27%,92.99B,0.0022355801929258 +ALI HEALTH,00241.HK,4.88,0.47,+10.658%,53.62M,257.82M,108.09,3.81,0.00%,66.04B,0.00501980543997108 +CITIC,00267.HK,7.2,0.2,+2.857%,11.54M,82.96M,2.78,0.28,9.04%,209.45B,0.00724508516988073 +WH GROUP,00288.HK,4.11,0.08,+1.985%,18.94M,77.65M,4.93,0.7,7.30%,52.73B,0.000456964684744788 +CHINA RES BEER,00291.HK,42.95,1.2,+2.874%,4.83M,207.98M,28.41,4.57,1.41%,139.34B,0.00866405926683583 +OOIL,00316.HK,104.5,-0.4,-0.381%,296.54K,30.98M,0.89,0.66,78.90%,69.01B,0.0237794431982097 +TINGYI,00322.HK,10.94,0.18,+1.673%,2.91M,31.81M,20.75,4.09,9.39%,61.64B,0.000502482829757812 +SINOPEC CORP,00386.HK,4.28,-0.01,-0.233%,92.43M,396.61M,6.94,0.58,9.36%,105.92B,0.0504379547308349 +HKEX,00388.HK,292.6,9,+3.173%,4.61M,1.34B,36.76,7.46,2.44%,370.97B,0.00142104572530785 +TECHTRONIC IND,00669.HK,76,1.35,+1.808%,5.47M,414.78M,16.54,3.43,2.43%,139.45B,0.0188176048996174 +CHINA OVERSEAS,00688.HK,16.24,0.52,+3.308%,13.15M,212.60M,6.76,0.44,4.93%,177.74B,0.000414599644602783 +TENCENT,00700.HK,306.2,8.8,+2.959%,11.25M,3.43B,13.74,3.6,0.78%,2,0.0103078651220939 +CHINA UNICOM,00762.HK,5.68,-0.05,-0.873%,9.23M,52.77M,9.16,0.45,5.44%,173.80B,0.00481217156158961 +LINK REIT,00823.HK,38.4,1.45,+3.924%,12.04M,460.96M,5.42,0.52,7.03%,98.38B,0.0011756418803464 +CHINA RES POWER,00836.HK,14.94,0.32,+2.189%,9.91M,147.81M,10.23,0.87,3.92%,71.87B,0.00431304851888186 +PETROCHINA,00857.HK,5.9,0,0.000%,64.23M,380.44M,6.38,0.7,8.08%,124.48B,0.00363811584680332 +XINYI GLASS,00868.HK,10.14,0.17,+1.705%,3.75M,38.02M,8.01,1.3,6.11%,42.22B,0.00363811584680332 +ZHONGSHENG HLDG,00881.HK,22.05,1.45,+7.039%,6.76M,147.71M,7.08,1.07,4.94%,52.72B,0.00526481995338596 +CNOOC,00883.HK,13.78,-0.02,-0.145%,26.37M,365.08M,4.03,0.97,19.09%,655.47B,0.00224602485281105 +CCB,00939.HK,4.42,0.06,+1.376%,233.61M,1.03B,3.06,0.35,9.93%,1,0.00572572121265722 +CHINA MOBILE,00941.HK,65.7,0.25,+0.382%,7.82M,516.10M,9.91,0.96,6.71%,1,0.00183548675335462 +LONGFOR GROUP,00960.HK,14.08,0.9,+6.829%,10.88M,150.68M,3.06,0.55,9.05%,92.81B,0.00527064070033535 +XINYI SOLAR,00968.HK,5.86,0.28,+5.018%,15.99M,92.88M,13.64,1.75,3.41%,52.17B,0.00380798456516713 +SMIC,00981.HK,20.05,0.25,+1.263%,13.10M,264.32M,11.17,1.06,0.00%,159.31B,0.200104533116974 +LENOVO GROUP,00992.HK,8.07,0.25,+3.197%,33.60M,270.50M,7.61,2.23,4.71%,97.87B,0.00849490672625522 +CKI HOLDINGS,01038.HK,37.05,-0.2,-0.537%,1.44M,53.73M,12.03,0.78,6.83%,93.35B,0.00125696891451962 +HENGAN INT'L,01044.HK,24.95,0.2,+0.808%,2.62M,64.97M,13.35,1.32,6.33%,28.99B,0.00178929568961912 +CHINA SHENHUA,01088.HK,25.4,0.35,+1.397%,7.98M,203.11M,6.14,1.13,11.33%,85.79B,0.0022989835562697 +CSPC PHARMA,01093.HK,5.74,0.05,+0.879%,29.29M,167.41M,9.96,2.01,3.66%,68.32B,0.0356436828072631 +SINOPHARM,01099.HK,22.7,0.2,+0.889%,2.07M,46.80M,7.37,0.92,4.08%,30.46B,0.0207235606629018 +CHINA RES LAND,01109.HK,31.2,1,+3.311%,9.88M,305.88M,7.02,0.81,5.07%,222.49B,0.00105704956863507 +CK ASSET,01113.HK,41.25,1.25,+3.125%,8.57M,352.44M,6.9,0.39,5.53%,146.47B,0.000913184352332553 +SINO BIOPHARM,01177.HK,2.83,0.02,+0.712%,26.30M,74.09M,18.37,1.59,4.24%,53.21B,0.00445479884777089 +CHINA RES MIXC,01209.HK,31.6,1.6,+5.333%,3.07M,96.42M,28.97,4.48,2.87%,72.13B,0.0024745192115892 +BYD COMPANY,01211.HK,242,7,+2.979%,3.90M,938.50M,37.57,5.63,0.53%,265.72B,0.00474931133978598 +AIA,01299.HK,63.85,0.95,+1.510%,38.75M,2.48B,408.88,2.53,2.41%,735.40B,0.000220467399731505 +CHINAHONGQIAO,01378.HK,7.67,0.28,+3.789%,13.05M,99.58M,7.27,0.76,6.65%,72.68B,0.0165980593985356 +ICBC,01398.HK,3.77,0.07,+1.892%,233.48M,881.67M,3.45,0.36,9.08%,327.21B,0.00132851940096775 +XIAOMI-W,01810.HK,12.34,0.62,+5.290%,78.53M,960.98M,109.39,1.9,0.00%,308.83B,0.00490946118917235 +BUD APAC,01876.HK,15.46,0.16,+1.046%,16.17M,250.45M,28.65,2.44,1.91%,204.74B,0.00185039670961971 +SANDS CHINA LTD,01928.HK,24,0.95,+4.121%,19.98M,475.93M,No Profit,N/A,0.00%,194.24B,0.00960542930051541 +CHOW TAI FOOK,01929.HK,11.8,0.28,+2.431%,4.88M,57.68M,21.93,3.64,10.34%,118.00B,0.0908818936317375 +WHARF REIC,01997.HK,30.25,1.4,+4.853%,4.23M,127.31M,No Profit,0.48,4.33%,91.85B,0.000623204448569543 +ANTA SPORTS,02020.HK,88.15,4.4,+5.254%,4.82M,422.51M,27.71,6.16,1.52%,249.70B,0.00293702105610748 +WUXI BIO,02269.HK,45.65,1.55,+3.515%,17.91M,811.49M,38.18,4.88,0.00%,194.01B,0.00442265255908587 +SHENZHOU INTL,02313.HK,75,4.6,+6.534%,5.52M,410.68M,21.87,3.25,2.55%,112.74B,0.00184353774521278 +PING AN,02318.HK,44.85,0.85,+1.932%,23.05M,1.03B,8.28,0.85,6.09%,334.02B,0.00442265255908587 +MENGNIU DAIRY,02319.HK,26.25,1.5,+6.061%,8.58M,223.15M,17.34,2.3,1.73%,103.42B,0.00797693234619361 +LI NING,02331.HK,32.95,1.5,+4.769%,22.54M,738.37M,18.8,3.16,1.58%,86.86B,0.000548246109448308 +SUNNY OPTICAL,02382.HK,54.7,1.05,+1.957%,5.62M,308.60M,22.01,2.44,0.91%,60.00B,0.00980946787029396 +BOC HONG KONG,02388.HK,21.45,0.3,+1.418%,6.53M,140.32M,8.38,0.75,6.33%,226.79B,0.00279198784516525 +CHINA LIFE,02628.HK,12.2,0.24,+2.007%,13.53M,165.07M,9.49,0.7,4.53%,90.78B,0.00566190448495522 +ENN ENERGY,02688.HK,65,1.15,+1.801%,3.06M,198.69M,11.08,1.67,4.48%,73.53B,0.0013514707359664 +ZIJIN MINING,02899.HK,11.98,0.16,+1.354%,16.20M,194.50M,13.97,3.14,1.88%,68.73B,0.0100940596177149 +MEITUAN-W,03690.HK,114.6,3.8,+3.430%,19.17M,2.19B,No Profit,4.89,0.00%,715.43B,0.0118600050276642 +HANSOH PHARMA,03692.HK,10.66,0.16,+1.524%,17.56M,187.72M,21.48,2.47,0.94%,63.25B,0.0070052473240666 +CM BANK,03968.HK,32.7,0.1,+0.307%,11.13M,363.99M,5.51,0.86,6.00%,150.12B,0.00436821343443777 +BANK OF CHINA,03988.HK,2.74,0.05,+1.859%,275.47M,754.54M,3.33,0.33,9.55%,229.13B,0.0105298417823887 +CG SERVICES,06098.HK,8.08,0.25,+3.193%,16.08M,128.87M,12.42,0.65,5.20%,27.01B,0.00478404836555252 +JD HEALTH,06618.HK,40.6,2.95,+7.835%,7.75M,312.36M,299.91,2.56,0.00%,129.12B,0.0134243199555489 +HAIER SMARTHOME,06690.HK,24.65,1.15,+4.894%,7.24M,178.37M,13.83,2.21,2.59%,70.46B,0.000651404549603483 +HAIDILAO,06862.HK,21,0.6,+2.941%,6.86M,143.79M,74.46,13.94,0.55%,117.05B,0.00190088484005443 +JD-SW,09618.HK,115.1,4,+3.600%,7.43M,852.28M,30.73,1.5,6.38%,360.24B,0.00428962133421518 +NONGFU SPRING,09633.HK,45,1.5,+3.448%,3.69M,165.62M,52.49,18.63,1.71%,226.56B,0.0115149371133421 +BIDU-SW,09888.HK,133.4,4.6,+3.571%,5.82M,772.73M,47.3,1.5,0.00%,377.37B,0.000214728364341268 +TRIP.COM-S,09961.HK,279.2,7,+2.572%,1.25M,349.59M,114.05,1.4,0.00%,176.65B,0.00259418338669419 +BABA-SW,09988.HK,85.6,2.6,+3.133%,34.61M,2.96B,21.65,1.62,0.00%,1,0.0010637787558598 +NTES-S,09999.HK,159.5,8.3,+5.489%,5.02M,797.10M,22.7,4.63,1.36%,546.99B,0.0044461470356248 diff --git a/example/basket/src/main/resources/static/nasdaq100.csv b/example/basket/src/main/resources/static/nasdaq100.csv new file mode 100644 index 000000000..6447cbb7a --- /dev/null +++ b/example/basket/src/main/resources/static/nasdaq100.csv @@ -0,0 +1,102 @@ +#,Name,Symbol,Weighting,Last Trade,Chg,% Chg +1,Apple Inc,AAPL,11.007,174.94,0.15,(0.09%) +2,Microsoft Corp,MSFT,9.61,316.98,-0.03,(-0.01%) +3,Amazon.com Inc,AMZN,5.401,129.31,0.19,(0.14%) +4,NVIDIA Corp,NVDA,4.101,415.74,-0.36,(-0.09%) +5,Meta Platforms Inc,META,3.729,299.42,0.34,(0.11%) +6,Tesla Inc,TSLA,3.285,244.13,-0.75,(-0.31%) +7,Alphabet Inc,GOOGL,3.133,130.49,0.24,(0.18%) +8,Alphabet Inc,GOOG,3.085,131.49,0.24,(0.18%) +9,Broadcom Inc,AVGO,2.896,833.04,3.96,(0.48%) +10,Costco Wholesale Corp,COST,2.137,557.85,-0.74,(-0.13%) +11,PepsiCo Inc,PEP,2.096,174.84,-0.43,(-0.25%) +12,Adobe Inc,ADBE,2.033,511.42,-1.48,(-0.29%) +13,Cisco Systems Inc,CSCO,1.887,53.68,0.11,(0.20%) +14,Comcast Corp,CMCSA,1.633,45.30,-0.01,(-0.01%) +15,Netflix Inc,NFLX,1.478,379.89,0.08,(0.02%) +16,T-Mobile US Inc,TMUS,1.43,140.18,0.83,(0.60%) +17,Advanced Micro Devices Inc,AMD,1.348,96.09,-0.11,(-0.12%) +18,Texas Instruments Inc,TXN,1.264,161.00,0.69,(0.43%) +19,Intel Corp,INTC,1.26,34.19,0.01,(0.01%) +20,Amgen Inc,AMGN,1.251,271.18,3.48,(1.30%) +21,Intuit Inc,INTU,1.226,509.00,0.43,(0.08%) +22,Honeywell International Inc,HON,1.103,188.67,-1.12,(-0.59%) +23,QUALCOMM Inc,QCOM,1.046,107.53,-0.16,(-0.14%) +24,Applied Materials Inc,AMAT,0.982,136.32,0.15,(0.11%) +25,Booking Holdings Inc,BKNG,0.941,3,019.20,-43.30,(-1.42%) +26,Starbucks Corp,SBUX,0.926,93.80,0.12,(0.12%) +27,Intuitive Surgical Inc,ISRG,0.867,288.50,0.30,(0.10%) +28,Automatic Data Processing Inc,ADP,0.854,239.45,0.10,(0.04%) +29,Mondelez International Inc,MDLZ,0.835,71.25,0.82,(1.16%) +30,Gilead Sciences Inc,GILD,0.814,75.47,0.46,(0.61%) +31,Vertex Pharmaceuticals Inc,VRTX,0.794,353.67,4.14,(1.18%) +32,Regeneron Pharmaceuticals Inc,REGN,0.763,828.09,3.25,(0.39%) +33,Analog Devices Inc,ADI,0.752,176.82,1.34,(0.76%) +34,Lam Research Corp,LRCX,0.702,620.00,0.89,(0.14%) +35,Micron Technology Inc,MU,0.646,68.90,0.02,(0.03%) +36,Palo Alto Networks Inc,PANW,0.604,228.70,0.19,(0.08%) +37,Synopsys Inc,SNPS,0.587,447.12,0.27,(0.06%) +38,Charter Communications Inc,CHTR,0.581,441.88,-3.33,(-0.75%) +39,MercadoLibre Inc,MELI,0.562,1,275.50,-1.47,(-0.11%) +40,PayPal Holdings Inc,PYPL,0.559,57.90,0.02,(0.03%) +41,CSX Corp,CSX,0.54,31.23,0.03,(0.09%) +42,Cadence Design Systems Inc,CDNS,0.539,230.83,0.17,(0.07%) +43,KLA Corp,KLAC,0.53,456.11,4.29,(0.95%) +44,PDD Holdings Inc ADR,PDD,0.521,95.93,-0.01,(-0.01%) +45,Marriott International Inc/MD,MAR,0.505,193.90,-0.46,(-0.23%) +46,Monster Beverage Corp,MNST,0.498,54.48,-0.04,(-0.08%) +47,Airbnb Inc,ABNB,0.491,132.09,-0.11,(-0.08%) +48,O'Reilly Automotive Inc,ORLY,0.485,936.67,0.65,(0.07%) +49,Cintas Corp,CTAS,0.446,505.27,0.52,(0.10%) +50,ASML Holding NV,ASML,0.438,585.00,-2.10,(-0.36%) +51,NXP Semiconductors NV,NXPI,0.434,196.76,-0.04,(-0.02%) +52,Workday Inc,WDAY,0.414,235.55,4.73,(2.05%) +53,Lululemon Athletica Inc,LULU,0.405,386.36,-1.69,(-0.44%) +54,Keurig Dr Pepper Inc,KDP,0.404,33.25,0.13,(0.39%) +55,Fortinet Inc,FTNT,0.401,58.29,0.05,(0.09%) +56,Marvell Technology Inc,MRVL,0.388,52.38,0.08,(0.14%) +57,PACCAR Inc,PCAR,0.38,84.97,0.04,(0.04%) +58,Old Dominion Freight Line Inc,ODFL,0.38,401.01,0.35,(0.09%) +59,Autodesk Inc,ADSK,0.379,204.07,0.03,(0.01%) +60,Kraft Heinz Co/The,KHC,0.368,34.27,0.11,(0.31%) +61,Microchip Technology Inc,MCHP,0.36,77.00,-0.08,(-0.10%) +62,Copart Inc,CPRT,0.358,43.26,0.10,(0.22%) +63,American Electric Power Co Inc,AEP,0.357,79.23,0.06,(0.08%) +64,Paychex Inc,PAYX,0.355,113.01,0.06,(0.06%) +65,Exelon Corp,EXC,0.35,40.28,0.07,(0.16%) +66,ON Semiconductor Corp,ON,0.341,93.87,0.06,(0.06%) +67,AstraZeneca PLC ADR,AZN,0.339,67.35,-0.49,(-0.72%) +68,Seagen Inc,SGEN,0.336,212.18,-1.52,(-0.71%) +69,Ross Stores Inc,ROST,0.335,111.71,0.05,(0.04%) +70,Moderna Inc,MRNA,0.331,100.32,0.33,(0.33%) +71,Biogen Inc,BIIB,0.326,257.93,0.25,(0.10%) +72,Crowdstrike Holdings Inc,CRWD,0.319,162.85,0.28,(0.17%) +73,IDEXX Laboratories Inc,IDXX,0.316,439.41,3.72,(0.85%) +74,Baker Hughes Co,BKR,0.307,35.44,0.04,(0.10%) +75,Constellation Energy Corp,CEG,0.307,110.41,0.05,(0.04%) +76,Cognizant Technology Solutions Corp,CTSH,0.303,70.19,0.58,(0.83%) +77,Verisk Analytics Inc,VRSK,0.303,242.05,0.10,(0.04%) +78,Dexcom Inc,DXCM,0.3,88.30,0.80,(0.92%) +79,Trade Desk Inc/The,TTD,0.293,76.38,0.03,(0.03%) +80,Xcel Energy Inc,XEL,0.284,59.76,0.03,(0.04%) +81,Electronic Arts Inc,EA,0.279,118.38,-0.63,(-0.53%) +82,CoStar Group Inc,CSGP,0.277,78.18,0.12,(0.15%) +83,GLOBALFOUNDRIES Inc,GFS,0.273,57.21,0.38,(0.67%) +84,Fastenal Co,FAST,0.268,54.32,0.11,(0.20%) +85,Atlassian Corp,TEAM,0.253,196.01,0.55,(0.28%) +86,GE HealthCare Technologies Inc,GEHC,0.252,63.78,-0.56,(-0.86%) +87,Warner Bros Discovery Inc,WBD,0.244,11.09,-0.02,(-0.14%) +88,Diamondback Energy Inc,FANG,0.235,150.70,0.13,(0.09%) +89,Datadog Inc,DDOG,0.23,88.81,0.05,(0.06%) +90,ANSYS Inc,ANSS,0.227,300.60,-2.31,(-0.76%) +91,eBay Inc,EBAY,0.203,43.22,0.09,(0.20%) +92,Dollar Tree Inc,DLTR,0.201,104.77,0.27,(0.25%) +93,Align Technology Inc,ALGN,0.2,297.25,-1.31,(-0.44%) +94,Zscaler Inc,ZS,0.188,151.80,0.09,(0.06%) +95,Illumina Inc,ILMN,0.183,132.31,-0.13,(-0.10%) +96,Walgreens Boots Alliance Inc,WBA,0.161,21.18,0.06,(0.28%) +97,Zoom Video Communications Inc,ZM,0.151,68.57,-0.29,(-0.41%) +98,Enphase Energy Inc,ENPH,0.148,120.41,0.49,(0.41%) +99,Sirius XM Holdings Inc,SIRI,0.137,4.05,0.02,(0.50%) +100,JD.com Inc ADR,JD,0.117,30.43,0.02,(0.05%) +101,Lucid Group Inc,LCID,0.102,5.14,0.03,(0.49%) \ No newline at end of file diff --git a/example/basket/src/main/resources/static/sp500.csv b/example/basket/src/main/resources/static/sp500.csv new file mode 100644 index 000000000..19701b2cc --- /dev/null +++ b/example/basket/src/main/resources/static/sp500.csv @@ -0,0 +1,504 @@ +#,Name,Symbol,Weighting,Price,Change,Change %, +1,Apple Inc,AAPL,6.992488,171.9,1.47,(0.86%), +2,Microsoft Corp,MSFT,6.487978,314.55,1.76,(0.56%), +3,Amazon.com Inc,AMZN,3.193379,126.25,0.27,(0.22%), +4,Nvidia Corp,NVDA,2.928461,433.11,8.43,(1.99%), +5,Alphabet Inc Cl A,GOOGL,2.162218,132.93,2.39,(1.83%), +6,Tesla Inc,TSLA,1.854311,246.56,6.06,(2.52%), +7,Alphabet Inc Cl C,GOOG,1.85251,133.81,2.35,(1.78%), +8,Meta Platforms Inc Class A,META,1.847731,305.93,8.19,(2.75%), +9,Berkshire Hathaway Inc Cl B,BRK.B,1.82184,358.67,0.89,(0.25%), +10,Exxon Mobil Corp,XOM,1.343563,118.97,-1.23,(-1.03%), +11,Unitedhealth Group Inc,UNH,1.302884,510.04,6.31,(1.25%), +12,Eli Lilly & Co,LLY,1.224046,546.65,-3.11,(-0.57%), +13,Jpmorgan Chase & Co,JPM,1.182918,148.23,2.45,(1.68%), +14,Johnson & Johnson W/d,JNJ,1.056344,156.83,-0.28,(-0.18%), +15,Visa Inc Class a Shares,V,1.029636,231.97,2.47,(1.08%), +16,Procter & Gamble Co,PG,0.969793,145.75,-1.59,(-1.08%), +17,Broadcom Inc,AVGO,0.941177,835.33,18.52,(2.27%), +18,Mastercard Inc A,MA,0.918779,400.65,5.17,(1.31%), +19,Chevron Corp,CVX,0.847353,170.55,-0.49,(-0.28%), +20,Home Depot Inc,HD,0.847289,304.35,2.53,(0.84%), +22,Abbvie Inc,ABBV,0.754672,152.14,-0.99,(-0.65%), +23,Merck & Co. Inc.,MRK,0.736434,104.2,0.26,(0.25%), +24,Costco Wholesale Corp,COST,0.697258,569.05,5.52,(0.98%), +25,Pepsico Inc,PEP,0.651768,168.92,-0.65,(-0.38%), +26,Walmart Inc,WMT,0.644449,161.87,0.15,(0.09%), +27,Adobe Inc,ADBE,0.639652,507.17,4.57,(0.91%), +28,Coca Cola Co,KO,0.60801,55.82,-0.13,(-0.23%), +29,Cisco Systems Inc,CSCO,0.605326,53.97,0.77,(1.44%), +30,Accenture Plc Cl A,ACN,0.55372,298.5,-15.9,(-5.05%), +31,Salesforce Inc,CRM,0.551342,204.46,1.73,(0.85%), +32,Thermo Fisher Scientific Inc,TMO,0.536951,503.47,5.18,(1.04%), +33,Mcdonald S Corp,MCD,0.536457,265.83,2.19,(0.83%), +34,Bank of America Corp,BAC,0.526405,27.51,0.24,(0.86%), +35,Comcast Corp Class A,CMCSA,0.512537,45.17,0.57,(1.27%), +36,Linde Plc,LIN,0.506835,375.48,3.47,(0.93%), +37,Pfizer Inc,PFE,0.506043,32.09,-0.02,(-0.05%), +38,Netflix Inc,NFLX,0.467192,377.77,0.18,(0.05%), +39,Abbott Laboratories,ABT,0.462893,97.52,1.99,(2.08%), +40,Oracle Corp,ORCL,0.459877,106.29,1.67,(1.60%), +41,Danaher Corp,DHR,0.454026,248.24,0.8,(0.32%), +42,Advanced Micro Devices,AMD,0.442473,103.74,5.67,(5.78%), +43,Wells Fargo & Co,WFC,0.417428,41.04,0.18,(0.43%), +44,Conocophillips,COP,0.411569,123.32,0.23,(0.18%), +45,Walt Disney Co,DIS,0.408438,80.35,0.45,(0.56%), +46,Intel Corp,INTC,0.404462,35.5,0.89,(2.56%), +47,Amgen Inc,AMGN,0.401904,270.91,1.93,(0.72%), +48,Texas Instruments Inc,TXN,0.400931,160.98,2.84,(1.80%), +49,Intuit Inc,INTU,0.397406,515.11,6.87,(1.35%), +50,Philip Morris International,PM,0.39143,92.66,2.34,(2.59%), +51,Caterpillar Inc,CAT,0.388444,276.34,3.63,(1.33%), +52,Verizon Communications Inc,VZ,0.380327,32.56,0.16,(0.48%), +53,Intl Business Machines Corp,IBM,0.364246,140.89,-2.28,(-1.59%), +54,Honeywell International Inc,HON,0.348317,188.68,0.8,(0.43%), +55,Union Pacific Corp,UNP,0.344419,203.88,1.48,(0.73%), +56,Qualcomm Inc,QCOM,0.340195,111.55,2.36,(2.16%), +57,Nextera Energy Inc,NEE,0.338809,57.64,-2.32,(-3.88%), +58,Lowe S Cos Inc,LOW,0.338613,209.52,2.56,(1.24%), +59,Bristol Myers Squibb Co,BMY,0.337683,58.3,0.41,(0.70%), +60,General Electric Co,GE,0.336989,112.43,1.54,(1.39%), +61,S&p Global Inc,SPGI,0.32985,369.21,6.15,(1.69%), +62,Applied Materials Inc,AMAT,0.316678,139.15,4.09,(3.03%), +63,Servicenow Inc,NOW,0.3112,552.84,6.46,(1.18%), +64,Boeing Co,BA,0.309673,193.12,-2.34,(-1.20%), +65,United Parcel Service Cl B,UPS,0.307795,154.29,1.88,(1.23%), +66,Booking Holdings Inc,BKNG,0.307126,3,86.26,3.6,(0.12%) +67,Nike Inc Cl B,NKE,0.305871,89.63,0.21,(0.24%), +68,At&t Inc,T,0.296603,14.94,0.07,(0.44%), +69,Goldman Sachs Group Inc,GS,0.296356,325.72,3.77,(1.17%), +70,Rtx Corp,RTX,0.296189,72.54,-0.34,(-0.46%), +71,Elevance Health Inc,ELV,0.292632,448.99,4.23,(0.95%), +72,Deere & Co,DE,0.291602,388.36,4,(1.04%), +73,Starbucks Corp,SBUX,0.291579,91.21,0.04,(0.04%), +74,Morgan Stanley,MS,0.29087,82.34,0.69,(0.84%), +75,Medtronic Plc,MDT,0.290688,78.77,0.55,(0.71%), +76,Prologis Inc,PLD,0.286912,112.3,1.05,(0.94%), +77,Intuitive Surgical Inc,ISRG,0.285764,296.31,4.88,(1.67%), +78,Tjx Companies Inc,TJX,0.282733,89.27,1.16,(1.32%), +79,Automatic Data Processing,ADP,0.279113,243.79,1.16,(0.48%), +80,Marsh & Mclennan Cos,MMC,0.266169,193.53,0.55,(0.29%), +81,Mondelez International Inc A,MDLZ,0.26425,69.44,-0.56,(-0.79%), +82,Gilead Sciences Inc,GILD,0.26285,75.96,0.41,(0.54%), +83,Lockheed Martin Corp,LMT,0.255775,410.4,1.68,(0.41%), +84,Blackrock Inc,BLK,0.252096,645.37,1.98,(0.31%), +85,Vertex Pharmaceuticals Inc,VRTX,0.251521,353.91,4.26,(1.22%), +86,Stryker Corp,SYK,0.250789,273.07,6.53,(2.45%), +87,Cvs Health Corp,CVS,0.250255,70.11,0.33,(0.47%), +88,Regeneron Pharmaceuticals,REGN,0.2481,835.67,3.11,(0.37%), +89,American Express Co,AXP,0.243515,150.42,0.52,(0.34%), +90,Chubb Ltd,CB,0.242706,212.92,1.29,(0.61%), +91,Analog Devices Inc,ADI,0.241943,177.01,4.2,(2.43%), +92,Schlumberger Ltd,SLB,0.241232,61.02,0.22,(0.36%), +93,Eaton Corp Plc,ETN,0.238556,216.42,2.06,(0.96%), +94,The Cigna Group,CI,0.238517,291.43,2.82,(0.98%), +95,Progressive Corp,PGR,0.229854,140.76,0.14,(0.10%), +96,Lam Research Corp,LRCX,0.228483,627.46,13.54,(2.20%), +97,Schwab (Charles) Corp,SCHW,0.225784,54.57,0.19,(0.35%), +98,Zoetis Inc,ZTS,0.224522,174.68,0,(-0.00%), +99,Citigroup Inc,C,0.217552,41.24,0.78,(1.92%), +100,Boston Scientific Corp,BSX,0.213003,53.3,1.2,(2.31%), +101,Blackstone Inc,BX,0.211158,108.88,2.33,(2.19%), +102,Eog Resources Inc,EOG,0.21104,130.56,0.75,(0.57%), +103,Becton Dickinson and Co,BDX,0.209627,262.6,3.8,(1.47%), +104,Micron Technology Inc,MU,0.208276,66.25,-1.96,(-2.87%), +105,American Tower Corp,AMT,0.207727,160.73,1.04,(0.65%), +106,Altria Group Inc,MO,0.207666,42.11,0.2,(0.47%), +107,T Mobile Us Inc,TMUS,0.20192,140.3,0.6,(0.43%), +108,Cme Group Inc,CME,0.201368,200.22,-0.14,(-0.07%), +109,Southern Co,SO,0.20116,65.04,-1.1,(-1.67%), +110,Palo Alto Networks Inc,PANW,0.198047,236.42,4.52,(1.95%), +111,Duke Energy Corp,DUK,0.193827,88.87,-1.23,(-1.36%), +112,Fiserv Inc,FI,0.192662,113.67,0.48,(0.42%), +113,Synopsys Inc,SNPS,0.189768,458.88,12.17,(2.72%), +114,Activision Blizzard Inc,ATVI,0.18717,93.71,-0.22,(-0.23%), +115,Aon Plc Class A,AON,0.186896,330.04,0.12,(0.04%), +116,Equinix Inc,EQIX,0.184757,715.84,8.74,(1.24%), +117,Illinois Tool Works,ITW,0.177501,233.17,0.77,(0.33%), +118,Air Products & Chemicals Inc,APD,0.17678,289.15,3.89,(1.36%), +119,Paypal Holdings Inc,PYPL,0.175802,58.3,0.96,(1.67%), +120,Cadence Design Sys Inc,CDNS,0.175052,235.09,4.44,(1.93%), +121,Northrop Grumman Corp,NOC,0.173654,441.3,4.06,(0.93%), +122,Intercontinental Exchange In,ICE,0.172998,109.93,1.66,(1.53%), +123,Humana Inc,HUM,0.170476,495.73,2.16,(0.44%), +124,Marathon Petroleum Corp,MPC,0.170186,155.28,2.85,(1.87%), +125,Kla Corp,KLAC,0.170079,459.61,14.05,(3.15%), +126,Fedex Corp,FDX,0.169747,266.99,4.28,(1.63%), +127,Csx Corp,CSX,0.169632,30.62,0.34,(1.14%), +128,Mckesson Corp,MCK,0.167376,445.58,1.2,(0.27%), +129,Sherwin Williams Co,SHW,0.165389,254.95,4.33,(1.73%), +130,Colgate Palmolive Co,CL,0.164,71.11,0.06,(0.08%), +131,Airbnb Inc Class A,ABNB,0.159553,137.66,3.63,(2.70%), +132,Waste Management Inc,WM,0.15893,154.17,-0.25,(-0.16%), +133,Emerson Electric Co,EMR,0.154857,97.31,0.45,(0.47%), +134,O Reilly Automotive Inc,ORLY,0.154194,918.15,3.98,(0.44%), +135,Pioneer Natural Resources Co,PXD,0.1524,234.43,0.34,(0.14%), +136,Phillips 66,PSX,0.150197,122.81,2.01,(1.66%), +137,Freeport Mcmoran Inc,FCX,0.146185,37.34,0.79,(2.17%), +138,3m Co W/d,MMM,0.144312,93.48,0.02,(0.02%), +139,Roper Technologies Inc,ROP,0.144165,486.61,-0.02,(-0.00%), +140,Valero Energy Corp,VLO,0.141937,147.59,3.64,(2.53%), +141,Nxp Semiconductors Nv,NXPI,0.141583,202.19,5.49,(2.79%), +142,Target Corp,TGT,0.141106,109.31,-0.44,(-0.40%), +143,Parker Hannifin Corp,PH,0.140358,396.29,5.18,(1.32%), +144,Us Bancorp,USB,0.139291,32.59,0.07,(0.20%), +145,General Dynamics Corp,GD,0.139193,223.44,2.44,(1.10%), +146,Chipotle Mexican Grill Inc,CMG,0.139055,1,828.59,22.51,(1.25%) +147,Hca Healthcare Inc,HCA,0.138966,251.59,4.33,(1.75%), +148,Arthur J Gallagher & Co,AJG,0.138231,231.77,1.44,(0.62%), +149,Moody S Corp,MCO,0.138162,319.07,4.56,(1.45%), +150,Amphenol Corp Cl A,APH,0.136941,84.4,2.04,(2.47%), +151,Ford Motor Co,F,0.1362,12.58,0.19,(1.49%), +152,Marriott International Cl A,MAR,0.135619,199.53,5.65,(2.92%), +153,Pnc Financial Services Group,PNC,0.135457,123.09,1.28,(1.05%), +154,Transdigm Group Inc,TDG,0.131273,860.46,8.64,(1.01%), +155,Carrier Global Corp,CARR,0.129065,56.83,1.75,(3.17%), +156,Autozone Inc,AZO,0.128857,2,556.17,15.27,(0.60%) +157,Trane Technologies Plc,TT,0.12759,207.07,7.01,(3.50%), +158,Motorola Solutions Inc,MSI,0.127284,275.18,2.2,(0.81%), +159,Arista Networks Inc,ANET,0.12715,184.23,2.63,(1.45%), +160,Norfolk Southern Corp,NSC,0.124378,197.3,1.08,(0.55%), +161,General Motors Co,GM,0.124282,33.25,0.9,(2.77%), +162,Paccar Inc,PCAR,0.123613,86.12,1.31,(1.54%), +163,Charter Communications Inc A,CHTR,0.123199,442.28,8.86,(2.04%), +164,Hess Corp,HES,0.121942,157.3,-0.74,(-0.47%), +165,Sempra,SRE,0.121909,68.15,-1.26,(-1.81%), +166,Occidental Petroleum Corp,OXY,0.121531,66.03,0.43,(0.66%), +167,American International Group,AIG,0.121272,61.73,0.72,(1.18%), +168,Autodesk Inc,ADSK,0.120711,208.03,5.75,(2.84%), +169,Edwards Lifesciences Corp,EW,0.119074,69.68,-0.43,(-0.62%), +170,Ecolab Inc,ECL,0.118911,169.5,1.63,(0.97%), +171,Public Storage,PSA,0.117206,266.58,1.6,(0.60%), +172,Microchip Technology Inc,MCHP,0.116275,78.91,2.41,(3.15%), +173,Aflac Inc,AFL,0.11627,77.65,0.62,(0.81%), +174,Cintas Corp,CTAS,0.116227,486.83,5.75,(1.19%), +175,Welltower Inc,WELL,0.116157,81.07,0.87,(1.08%), +176,Williams Cos Inc,WMB,0.115685,34.65,0.55,(1.61%), +177,Kimberly Clark Corp,KMB,0.114902,121.11,-0.55,(-0.45%), +178,Archer Daniels Midland Co,ADM,0.114307,76.74,0.38,(0.50%), +179,Msci Inc,MSCI,0.113047,518.97,7.03,(1.37%), +180,Constellation Brands Inc A,STZ,0.112869,251.62,1.03,(0.41%), +181,On Semiconductor,ON,0.111009,95.12,3.07,(3.33%), +182,Metlife Inc,MET,0.110772,63.06,0.26,(0.41%), +183,Monster Beverage Corp,MNST,0.110311,53.31,0.19,(0.35%), +184,Hilton Worldwide Holdings In,HLT,0.109054,153.24,3.88,(2.60%), +185,American Electric Power,AEP,0.108899,74.71,-1.15,(-1.51%), +186,Crown Castle Inc,CCI,0.108512,91.35,1.65,(1.83%), +187,Exelon Corp,EXC,0.107894,38.11,-0.69,(-1.78%), +188,Nucor Corp,NUE,0.107787,158.31,2.6,(1.67%), +189,Travelers Cos Inc,TRV,0.107342,167.42,-0.51,(-0.30%), +190,Dominion Energy Inc,D,0.106001,44.61,-0.86,(-1.88%), +191,Te Connectivity Ltd,TEL,0.105581,123.84,3.4,(2.82%), +192,Halliburton Co,HAL,0.105449,42.18,0.15,(0.37%), +193,Centene Corp,CNC,0.105443,69.87,0.13,(0.18%), +194,Fortinet Inc,FTNT,0.105315,59.07,0.93,(1.59%), +195,Oneok Inc,OKE,0.104854,64.86,0.35,(0.53%), +196,General Mills Inc,GIS,0.104655,63.79,-0.26,(-0.40%), +197,Copart Inc,CPRT,0.104453,43.66,0.61,(1.41%), +198,Paychex Inc,PAYX,0.104412,117.4,0.89,(0.76%), +199,Biogen Inc,BIIB,0.103916,258.95,1.43,(0.55%), +200,Truist Financial Corp,TFC,0.103679,28.15,0.18,(0.63%), +201,Ross Stores Inc,ROST,0.10361,111.18,2.26,(2.07%), +202,Johnson Controls Internation,JCI,0.103601,53.69,-0.85,(-1.55%), +203,Iqvia Holdings Inc,IQV,0.103397,200.11,-2.1,(-1.04%), +204,Capital One Financial Corp,COF,0.101688,96.63,1.14,(1.20%), +205,Baker Hughes Co,BKR,0.101425,36.62,0.37,(1.02%), +206,Idexx Laboratories Inc,IDXX,0.101263,439.37,2.51,(0.57%), +207,Corteva Inc,CTVA,0.100577,50.77,0.02,(0.05%), +208,Dow Inc,DOW,0.100258,50.87,-0.13,(-0.26%), +209,Old Dominion Freight Line,ODFL,0.100037,406.82,6.93,(1.73%), +210,Constellation Energy,CEG,0.099445,109.94,-0.81,(-0.73%), +211,Dexcom Inc,DXCM,0.099384,95.68,3.59,(3.90%), +212,Simon Property Group Inc,SPG,0.098977,108.45,0.26,(0.24%), +213,Digital Realty Trust Inc,DLR,0.098757,117.6,0.76,(0.65%), +214,Realty Income Corp,O,0.098278,49.83,0.17,(0.33%), +215,Kenvue Inc W/i,KVUE,0.097359,20.2,-0.02,(-0.12%), +216,Verisk Analytics Inc,VRSK,0.097203,241.97,2.34,(0.98%), +217,Cognizant Tech Solutions A,CTSH,0.096172,68.15,-0.05,(-0.07%), +218,P G & E Corp,PCG,0.095995,16.36,-0.09,(-0.52%), +219,Prudential Financial Inc,PRU,0.095804,94.93,0.41,(0.43%), +220,Ametek Inc,AME,0.09567,150.03,1.17,(0.79%), +221,Yum Brands Inc,YUM,0.095443,123.55,1.57,(1.29%), +222,Dupont De Nemours Inc,DD,0.094185,74.58,1.11,(1.51%), +223,Ameriprise Financial Inc,AMP,0.093691,332.11,5.16,(1.58%), +224,L3harris Technologies Inc,LHX,0.092512,173.16,-2.04,(-1.16%), +225,Fidelity National Info Serv,FIS,0.09207,56.06,0.52,(0.94%), +226,Sysco Corp,SYY,0.091968,65.99,0.78,(1.20%), +227,Moderna Inc,MRNA,0.091789,100.61,1.17,(1.18%), +228,Bank of New York Mellon Corp,BK,0.091699,42.76,0.59,(1.39%), +229,Agilent Technologies Inc,A,0.091382,111.91,1.41,(1.28%), +230,Otis Worldwide Corp,OTIS,0.091228,80.55,1.2,(1.51%), +231,Rockwell Automation Inc,ROK,0.091103,288.26,3.46,(1.21%), +232,Dr Horton Inc,DHI,0.090974,108.96,1.95,(1.82%), +233,Cummins Inc,CMI,0.090916,232.98,3.03,(1.32%), +234,Estee Lauder Companies Cl A,EL,0.090788,139.94,-0.1,(-0.07%), +235,Kinder Morgan Inc,KMI,0.090175,16.71,0.05,(0.27%), +236,Keurig Dr Pepper Inc,KDP,0.088358,31.51,-0.16,(-0.51%), +237,Fastenal Co,FAST,0.087952,55.72,0.66,(1.21%), +238,Xcel Energy Inc,XEL,0.087474,56.5,-0.71,(-1.25%), +239,Devon Energy Corp,DVN,0.087359,48.84,0,(0.01%), +240,Ww Grainger Inc,GWW,0.086956,704.07,3.96,(0.57%), +241,Costar Group Inc,CSGP,0.086756,77.1,0.75,(0.99%), +242,Cencora Inc,COR,0.086188,183.99,-1.17,(-0.63%), +243,United Rentals Inc,URI,0.085093,454.44,8.22,(1.84%), +244,Hershey Co,HSY,0.084755,201.01,-1.55,(-0.76%), +245,Arch Capital Group Ltd,ACGL,0.083799,81.62,0.54,(0.67%), +246,Ppg Industries Inc,PPG,0.083787,130.49,2.46,(1.92%), +247,Global Payments Inc,GPN,0.083671,116.72,1.47,(1.28%), +248,Consolidated Edison Inc,ED,0.083432,85.06,-1.57,(-1.81%), +249,Newmont Corp,NEM,0.082799,36.78,-0.5,(-1.34%), +250,Republic Services Inc,RSG,0.082765,145.01,0.28,(0.19%), +251,Allstate Corp,ALL,0.08254,112.77,-0.25,(-0.22%), +252,Electronic Arts Inc,EA,0.081213,119.76,1.79,(1.51%), +253,Vici Properties Inc,VICI,0.081127,29.28,0.4,(1.37%), +254,Kroger Co,KR,0.080998,44.96,0.48,(1.07%), +255,Public Service Enterprise Gp,PEG,0.080723,56.88,-1.02,(-1.75%), +256,Lennar Corp A,LEN,0.078759,113.41,1.71,(1.53%), +257,Diamondback Energy Inc,FANG,0.078498,158.01,0.78,(0.50%), +258,West Pharmaceutical Services,WST,0.077362,377.15,1.97,(0.52%), +259,Quanta Services Inc,PWR,0.077074,190.82,0.7,(0.37%), +260,Gartner Inc,IT,0.076911,347.78,-1.41,(-0.40%), +261,Aptiv Plc,APTV,0.0757,99.21,3.35,(3.50%), +262,Vulcan Materials Co,VMC,0.075604,207.6,4,(1.97%), +263,Kraft Heinz Co,KHC,0.075468,33.72,-0.31,(-0.90%), +264,Ge Healthcare Technology,GEHC,0.074734,69.81,1.53,(2.24%), +265,Cdw Corp/de,CDW,0.074375,202.53,3.84,(1.93%), +266,Fortive Corp,FTV,0.072323,74.75,1.16,(1.58%), +267,Ingersoll Rand Inc,IR,0.071683,64.52,1.25,(1.97%), +268,Ansys Inc,ANSS,0.071343,299.19,4.85,(1.65%), +269,Extra Space Storage Inc,EXR,0.071269,120.75,0.24,(0.20%), +270,Wec Energy Group Inc,WEC,0.071007,79.67,-0.91,(-1.12%), +271,Martin Marietta Materials,MLM,0.070759,418,8.05,(1.96%), +272,Edison International,EIX,0.068887,63.92,-1.38,(-2.11%), +273,American Water Works Co Inc,AWK,0.068233,123.27,-3.07,(-2.43%), +274,Warner Bros Discovery Inc,WBD,0.068207,10.89,-0.15,(-1.31%), +275,Lyondellbasell Indu Cl A,LYB,0.067294,94.86,-0.11,(-0.11%), +276,Mettler Toledo International,MTD,0.067028,1,112.26,14.48,(1.32%) +277,Avalonbay Communities Inc,AVB,0.066762,171.85,-0.6,(-0.35%), +278,Delta Air Lines Inc,DAL,0.065781,37.32,0.66,(1.79%), +279,T Rowe Price Group Inc,TROW,0.064996,104.73,1.19,(1.15%), +280,Keysight Technologies In,KEYS,0.064934,133.51,3.11,(2.38%), +281,Zimmer Biomet Holdings Inc,ZBH,0.064476,112.14,1.38,(1.24%), +282,Dollar General Corp,DG,0.064042,105.04,0.7,(0.67%), +283,Corning Inc,GLW,0.064037,30.35,0.29,(0.98%), +284,Ebay Inc,EBAY,0.063728,43.45,0.56,(1.31%), +285,Cbre Group Inc A,CBRE,0.063578,73.84,0.35,(0.48%), +286,Weyerhaeuser Co,WY,0.063312,30.4,-0.64,(-2.05%), +287,Church & Dwight Co Inc,CHD,0.062765,91.68,-0.29,(-0.31%), +288,Cardinal Health Inc,CAH,0.062583,88.18,0.14,(0.16%), +289,Hp Inc,HPQ,0.062013,25.73,0.09,(0.36%), +290,Equifax Inc,EFX,0.061821,185.4,4.68,(2.59%), +291,Tractor Supply Company,TSCO,0.061683,205.07,2.06,(1.02%), +292,Willis Towers Watson Plc,WTW,0.06168,211.96,0.35,(0.17%), +293,Hewlett Packard Enterprise,HPE,0.061499,17.7,0.63,(3.66%), +294,Fair Isaac Corp,FICO,0.061481,890.19,4.58,(0.52%), +295,Dollar Tree Inc,DLTR,0.061287,106.46,1.11,(1.05%), +296,Hartford Financial Svcs Grp,HIG,0.061236,72.24,0.53,(0.73%), +297,Resmed Inc,RMD,0.060853,149.81,1.16,(0.78%), +298,Take Two Interactive Softwre,TTWO,0.060753,139.63,1.85,(1.34%), +299,Royal Caribbean Cruises Ltd,RCL,0.060515,94.38,2.42,(2.64%), +300,Xylem Inc,XYL,0.060192,91.4,1.09,(1.20%), +301,Align Technology Inc,ALGN,0.060095,309.06,7.38,(2.45%), +302,Steris Plc,STE,0.060013,221.57,3.67,(1.69%), +303,Broadridge Financial Solutio,BR,0.059572,181.18,-0.04,(-0.02%), +304,Discover Financial Services,DFS,0.059507,86.35,1.09,(1.28%), +305,State Street Corp,STT,0.059411,67.81,1.03,(1.54%), +306,Sba Communications Corp,SBAC,0.059216,198.11,2.05,(1.05%), +307,Monolithic Power Systems Inc,MPWR,0.058699,457.69,16.51,(3.74%), +308,Illumina Inc,ILMN,0.058584,133.02,-0.28,(-0.21%), +309,Dte Energy Company,DTE,0.058057,98.82,-1.72,(-1.71%), +310,M & T Bank Corp,MTB,0.057846,126.63,2.09,(1.68%), +311,Coterra Energy Inc,CTRA,0.057589,27.48,0.34,(1.23%), +312,Eversource Energy,ES,0.057281,57.54,-1.23,(-2.09%), +313,Genuine Parts Co,GPC,0.055796,142.94,0.63,(0.45%), +314,Equity Residential,EQR,0.055712,58.67,0.23,(0.40%), +315,Entergy Corp,ETR,0.055241,92.23,-1.02,(-1.10%), +316,Dover Corp,DOV,0.055103,141.68,1.09,(0.77%), +317,Ameren Corporation,AEE,0.054981,74.6,-1.51,(-1.98%), +318,Ulta Beauty Inc,ULTA,0.054585,398.17,5.73,(1.46%), +319,Teledyne Technologies Inc,TDY,0.054228,414.36,0.92,(0.22%), +320,Nvr Inc,NVR,0.054188,6,27.42,86.42,(1.45%) +321,Targa Resources Corp,TRGP,0.05408,87.52,0.93,(1.08%), +322,Molina Healthcare Inc,MOH,0.053618,333.09,2.03,(0.61%), +323,Wabtec Corp,WAB,0.053425,108.18,1.35,(1.26%), +324,Fleetcor Technologies Inc,FLT,0.053345,260.14,1.28,(0.49%), +325,Albemarle Corp,ALB,0.053229,172.99,10.36,(6.37%), +326,Baxter International Inc,BAX,0.05272,37.54,0.21,(0.57%), +327,Raymond James Financial Inc,RJF,0.052247,101.39,1.84,(1.85%), +328,Mccormick & Co Non Vtg Shrs,MKC,0.051871,74.55,0.46,(0.63%), +329,Invitation Homes Inc,INVH,0.051153,31.73,0.03,(0.11%), +330,Firstenergy Corp,FE,0.050777,34.56,-0.69,(-1.94%), +331,Laboratory Crp of Amer Hldgs,LH,0.05072,204.23,-0.62,(-0.30%), +332,Howmet Aerospace Inc,HWM,0.050386,46.99,0.91,(1.97%), +333,Verisign Inc,VRSN,0.050215,202.93,2.46,(1.23%), +334,Ppl Corp,PPL,0.04902,23.56,-0.39,(-1.61%), +335,Iron Mountain Inc,IRM,0.047985,59.55,0.56,(0.94%), +336,Jacobs Solutions Inc,J,0.047882,136.45,0.27,(0.20%), +337,Intl Flavors & Fragrances,IFF,0.047868,67.84,0.64,(0.95%), +338,Centerpoint Energy Inc,CNP,0.047827,26.68,-0.48,(-1.75%), +339,Darden Restaurants Inc,DRI,0.047736,143.44,2.01,(1.42%), +340,Hologic Inc,HOLX,0.047358,69.99,0.75,(1.08%), +341,First Solar Inc,FSLR,0.047324,161.9,3.29,(2.07%), +342,Expeditors Intl Wash Inc,EXPD,0.046936,114.74,1.08,(0.95%), +343,Brown & Brown Inc,BRO,0.046675,71.15,0.19,(0.26%), +344,Factset Research Systems Inc,FDS,0.046601,443.66,8.47,(1.95%), +345,Fifth Third Bancorp,FITB,0.046598,25.05,0.19,(0.74%), +346,Ventas Inc,VTR,0.046351,42.18,0.77,(1.85%), +347,Marathon Oil Corp,MRO,0.046321,27.51,0.12,(0.45%), +348,Steel Dynamics Inc,STLD,0.046096,106.96,0.52,(0.48%), +349,Bunge Ltd,BG,0.046038,110.67,1.1,(1.00%), +350,Ptc Inc,PTC,0.045951,140.25,1.78,(1.28%), +351,Everest Group Ltd,EG,0.04587,381.3,-0.42,(-0.11%), +352,Cincinnati Financial Corp,CINF,0.045852,104.4,-0.3,(-0.29%), +353,Enphase Energy Inc,ENPH,0.045679,121.39,1.28,(1.07%), +354,Nasdaq Inc,NDAQ,0.04562,49.07,0.74,(1.52%), +355,Akamai Technologies Inc,AKAM,0.045578,107.75,0.79,(0.74%), +356,Cboe Global Markets Inc,CBOE,0.045525,155.28,0.51,(0.33%), +357,Cf Industries Holdings Inc,CF,0.04496,84.93,1.48,(1.78%), +358,Waters Corp,WAT,0.044936,274.46,2.12,(0.78%), +359,Pultegroup Inc,PHM,0.044848,74.85,1.65,(2.25%), +360,Tyler Technologies Inc,TYL,0.044831,387.74,2.43,(0.63%), +361,Principal Financial Group,PFG,0.044705,72.74,0.74,(1.02%), +362,Clorox Company,CLX,0.04465,128.98,-0.17,(-0.13%), +363,Southwest Airlines Co,LUV,0.044478,27.3,0.49,(1.81%), +364,Regions Financial Corp,RF,0.044397,17.16,0.22,(1.27%), +365,Garmin Ltd,GRMN,0.044336,104.65,1.42,(1.38%), +366,Atmos Energy Corp,ATO,0.044128,106.32,-0.14,(-0.13%), +367,Netapp Inc,NTAP,0.044116,76.49,1.54,(2.05%), +368,Textron Inc,TXT,0.043659,79.27,0.33,(0.41%), +369,Cooper Cos Inc,COO,0.04361,318.15,2.23,(0.71%), +370,Kellogg Co,K,0.043517,58.9,-0.22,(-0.38%), +371,Idex Corp,IEX,0.043484,210.72,3.28,(1.58%), +372,Cms Energy Corp,CMS,0.043476,52.78,-0.57,(-1.07%), +373,Skyworks Solutions Inc,SWKS,0.042974,98.55,2.25,(2.33%), +374,Alexandria Real Estate Equit,ARE,0.042466,99.48,0.59,(0.60%), +375,Hunt (Jb) Transprt Svcs Inc,JBHT,0.042319,186.54,0.95,(0.51%), +376,Las Vegas Sands Corp,LVS,0.042222,45.63,-0.53,(-1.15%), +377,Ball Corp,BALL,0.042202,48.27,0.04,(0.08%), +378,Walgreens Boots Alliance Inc,WBA,0.04215,20.97,-0.06,(-0.26%), +379,Teradyne Inc,TER,0.041494,100.04,3.56,(3.68%), +380,Mid America Apartment Comm,MAA,0.041385,128.55,0.48,(0.37%), +381,Epam Systems Inc,EPAM,0.041006,257.76,0.96,(0.37%), +382,Avery Dennison Corp,AVY,0.040961,183.42,1.39,(0.76%), +383,Omnicom Group,OMC,0.040483,74.6,1.21,(1.65%), +384,Huntington Bancshares Inc,HBAN,0.040444,10.25,0.13,(1.24%), +385,Eqt Corp,EQT,0.040251,40,0.39,(0.99%), +386,Tyson Foods Inc Cl A,TSN,0.040042,49.74,-0.37,(-0.74%), +387,Western Digital Corp,WDC,0.039814,45.5,0.94,(2.11%), +388,Northern Trust Corp,NTRS,0.039557,69.29,0.84,(1.23%), +389,Carnival Corp,CCL,0.039206,14.52,0.54,(3.88%), +390,Expedia Group Inc,EXPE,0.038585,102.75,2.5,(2.49%), +391,United Airlines Holdings Inc,UAL,0.038383,42.84,0.81,(1.94%), +392,Quest Diagnostics Inc,DGX,0.038331,123.71,0.31,(0.25%), +393,Axon Enterprise Inc,AXON,0.03828,195.69,1.04,(0.53%), +394,Packaging Corp of America,PKG,0.038236,152.79,0.9,(0.59%), +395,Revvity Inc,RVTY,0.0378,110.55,1.5,(1.38%), +396,Snap on Inc,SNA,0.037774,257.97,4,(1.58%), +397,Pool Corp,POOL,0.037475,353.56,9.86,(2.87%), +398,Essex Property Trust Inc,ESS,0.03733,210.81,0.07,(0.03%), +399,Domino S Pizza Inc,DPZ,0.037258,382.39,2.18,(0.57%), +400,Amcor Plc,AMCR,0.037101,9.09,0.06,(0.61%), +401,Best Buy Co Inc,BBY,0.037071,68.66,0.29,(0.43%), +402,Apa Corp,APA,0.03662,42.49,0.11,(0.27%), +403,Lamb Weston Holdings Inc,LW,0.036553,91.47,0.09,(0.10%), +404,Wr Berkley Corp,WRB,0.036551,65.21,0.86,(1.33%), +405,Conagra Brands Inc,CAG,0.036484,27.44,-0.1,(-0.35%), +406,Lkq Corp,LKQ,0.036449,49.51,0.72,(1.47%), +407,Jm Smucker Co,SJM,0.035767,124.48,-0.96,(-0.77%), +408,Stanley Black & Decker Inc,SWK,0.035567,83.87,0.97,(1.17%), +409,Synchrony Financial,SYF,0.035241,30.73,0.55,(1.84%), +410,Carmax Inc,KMX,0.035202,71.64,-8.05,(-10.10%), +411,Leidos Holdings Inc,LDOS,0.034943,92.2,0.21,(0.23%), +412,Seagate Technology Holdings,STX,0.034918,65.71,1.42,(2.20%), +413,Paycom Software Inc,PAYC,0.034914,259.42,2.34,(0.91%), +414,Celanese Corp,CE,0.034212,127.11,3.81,(3.09%), +415,Trimble Inc,TRMB,0.034136,52.22,3.01,(6.12%), +416,Alliant Energy Corp,LNT,0.03411,48.06,-0.49,(-1.02%), +417,Citizens Financial Group,CFG,0.033972,26.28,0.52,(2.00%), +418,International Paper Co,IP,0.033961,35.1,0.15,(0.41%), +419,Masco Corp,MAS,0.033414,54.58,1.37,(2.58%), +420,Nordson Corp,NDSN,0.033057,223.81,3.73,(1.69%), +421,Loews Corp,L,0.032942,64.16,0.36,(0.56%), +422,Evergy Inc,EVRG,0.032792,50.48,-0.58,(-1.13%), +423,Mosaic Co,MOS,0.03266,35.63,0.43,(1.22%), +424,Molson Coors Beverage Co B,TAP,0.032624,62.29,-0.12,(-0.19%), +425,Zebra Technologies Corp Cl A,ZBRA,0.03257,236.95,11.04,(4.89%), +426,Viatris Inc,VTRS,0.032115,9.8,0.21,(2.14%), +427,Live Nation Entertainment In,LYV,0.032035,83.73,2.71,(3.34%), +428,Host Hotels & Resorts Inc,HST,0.03173,16.38,0.34,(2.11%), +429,Insulet Corp,PODD,0.031493,166.19,4.49,(2.77%), +430,Match Group Inc,MTCH,0.031269,40.07,0.09,(0.23%), +431,Interpublic Group of Cos Inc,IPG,0.031184,29.12,0.39,(1.35%), +432,Hormel Foods Corp,HRL,0.030887,38.15,-0.19,(-0.48%), +433,Incyte Corp,INCY,0.03067,58.93,-0.18,(-0.30%), +434,Udr Inc,UDR,0.030252,35.67,0.28,(0.79%), +435,Jack Henry & Associates Inc,JKHY,0.030211,150.61,2.17,(1.46%), +436,Kimco Realty Corp,KIM,0.029862,17.73,0.24,(1.34%), +437,Aes Corp,AES,0.029775,15.29,-0.65,(-4.05%), +438,Bio Techne Corp,TECH,0.029742,67.67,0.1,(0.15%), +439,Pentair Plc,PNR,0.029592,65.59,0.87,(1.34%), +440,Rollins Inc,ROL,0.029276,37.64,0.2,(0.52%), +441,Mgm Resorts International,MGM,0.028601,36.76,0.27,(0.74%), +442,Ceridian Hcm Holding Inc,CDAY,0.028589,67.38,0.35,(0.52%), +443,Brown Forman Corp Class B,BF.B,0.028542,56.78,0.14,(0.25%), +444,Nisource Inc,NI,0.028365,24.84,-0.35,(-1.37%), +445,Gen Digital Inc,GEN,0.028124,17.83,-0.07,(-0.37%), +446,C.H. Robinson Worldwide Inc,CHRW,0.028048,86.31,0.02,(0.02%), +447,Camden Property Trust,CPT,0.027984,94.56,-0.32,(-0.34%), +448,Charles River Laboratories,CRL,0.027736,195.69,0.75,(0.38%), +449,Healthpeak Properties Inc,PEAK,0.027617,18.15,0.1,(0.58%), +450,Caesars Entertainment Inc,CZR,0.027217,47.52,1.54,(3.36%), +451,Regency Centers Corp,REG,0.027131,59.98,0.85,(1.43%), +452,Keycorp,KEY,0.0269,10.52,0.22,(2.09%), +453,Henry Schein Inc,HSIC,0.026715,73.88,0.62,(0.84%), +454,Globe Life Inc,GL,0.026574,110.04,0.61,(0.56%), +455,Borgwarner Inc,BWA,0.026416,40.72,0.92,(2.31%), +456,F5 Inc,FFIV,0.026087,160.33,2.74,(1.74%), +457,Qorvo Inc,QRVO,0.025849,96.39,1.83,(1.93%), +458,Teleflex Inc,TFX,0.025796,199.42,2.91,(1.48%), +459,Allegion Plc,ALLE,0.025545,104.97,1.68,(1.63%), +460,Westrock Co,WRK,0.025292,35.98,0.23,(0.64%), +461,Eastman Chemical Co,EMN,0.025003,76.99,2.35,(3.15%), +462,Wynn Resorts Ltd,WYNN,0.024938,92.21,0,(-0.00%), +463,Nrg Energy Inc,NRG,0.024681,38.55,-0.03,(-0.08%), +464,Juniper Networks Inc,JNPR,0.024655,27.92,0.42,(1.52%), +465,Pinnacle West Capital,PNW,0.02321,73.45,-0.71,(-0.95%), +466,Hasbro Inc,HAS,0.02308,65.23,0.24,(0.37%), +467,Catalent Inc,CTLT,0.023069,45.85,0.07,(0.15%), +468,American Airlines Group Inc,AAL,0.02296,13,0.39,(3.05%), +469,Fmc Corp,FMC,0.022942,66.03,0.02,(0.03%), +470,Campbell Soup Co,CPB,0.022776,41.15,-0.31,(-0.76%), +471,Smith (a.O.) Corp,AOS,0.022769,66.99,1.54,(2.35%), +472,Boston Properties Inc,BXP,0.02269,59.66,0.79,(1.34%), +473,Huntington Ingalls Industrie,HII,0.022502,204.41,1.22,(0.60%), +474,Fox Corp Class A,FOXA,0.021902,31.47,0.55,(1.76%), +475,Robert Half Inc,RHI,0.021872,73.78,0.64,(0.87%), +476,Assurant Inc,AIZ,0.021618,145.63,-0.13,(-0.09%), +477,Universal Health Services B,UHS,0.021551,127,2.8,(2.25%), +478,Etsy Inc,ETSY,0.021257,63.53,1.64,(2.65%), +479,Marketaxess Holdings Inc,MKTX,0.021132,205.89,4.11,(2.04%), +480,News Corp Class A,NWSA,0.0209,20,0.35,(1.76%), +481,Bio Rad Laboratories A,BIO,0.020548,356.1,3.63,(1.03%), +482,Bath & Body Works Inc,BBWI,0.020412,33.19,1.04,(3.23%), +483,Dentsply Sirona Inc,XRAY,0.020079,33.94,-0.17,(-0.51%), +484,Solaredge Technologies Inc,SEDG,0.020026,132.35,4.34,(3.39%), +485,Whirlpool Corp,WHR,0.019812,131.66,1.03,(0.79%), +486,Franklin Resources Inc,BEN,0.019128,24.55,0.28,(1.14%), +487,Generac Holdings Inc,GNRC,0.018958,110.73,1.84,(1.69%), +488,Norwegian Cruise Line Holdin,NCLH,0.018812,16.96,0.67,(4.08%), +489,Federal Realty Invs Trust,FRT,0.018475,91.45,1.05,(1.16%), +490,Tapestry Inc,TPR,0.01809,28.18,0.23,(0.84%), +491,Invesco Ltd,IVZ,0.017835,14.31,0.22,(1.53%), +492,Paramount Global Class B,PARA,0.017208,12.89,0.11,(0.89%), +493,Vf Corp,VFC,0.015631,16.59,-0.32,(-1.89%), +494,Comerica Inc,CMA,0.014638,41.07,1.12,(2.81%), +495,Davita Inc,DVA,0.014395,95.75,0.01,(0.01%), +496,Zions Bancorp Na,ZION,0.013918,33.96,0.79,(2.39%), +497,Ralph Lauren Corp,RL,0.013127,115.52,0.26,(0.22%), +498,Sealed Air Corp,SEE,0.012794,32.2,0.46,(1.46%), +499,Alaska Air Group Inc,ALK,0.012574,37.04,0.63,(1.73%), +500,Mohawk Industries Inc,MHK,0.011998,85.15,1.23,(1.46%), +501,Organon & Co,OGN,0.011665,16.93,0.34,(2.02%), +502,Dxc Technology Co,DXC,0.011658,20.64,0.29,(1.40%), +503,Fox Corp Class B,FOX,0.010545,29.16,0.53,(1.85%), +504,News Corp Class B,NWS,0.006575,20.75,0.36,(1.74%), diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketConstants.scala diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala similarity index 83% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala index 20ea87f02..02065bd65 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/BasketModule.scala @@ -2,31 +2,26 @@ package org.finos.vuu.core.module.basket import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.time.Clock -import org.finos.vuu.api.{JoinSpec, JoinTableDef, JoinTo, LeftOuterJoin, Link, TableDef, ViewPortDef, VisualLinks} -import org.finos.vuu.core.module.basket.provider.{AlgoProvider, BasketConstituentProvider, BasketProvider, NullProvider, PriceStrategyProvider} -import org.finos.vuu.core.module.basket.service.{BasketService, BasketTradingConstituentJoinService, BasketTradingConstituentService} +import org.finos.vuu.api._ +import org.finos.vuu.core.module.basket.provider._ +import org.finos.vuu.core.module.basket.service.{BasketService, BasketTradingConstituentJoinService, BasketTradingConstituentService, BasketTradingService} import org.finos.vuu.core.module.price.PriceModule -import org.finos.vuu.core.module.simul.SimulationModule import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule} import org.finos.vuu.core.table.Columns object BasketModule extends DefaultModule { - private final val NAME = "BASKET" + final val NAME = "BASKET" final val BasketTable = "basket" final val BasketTradingTable = "basketTrading" final val BasketConstituentTable = "basketConstituent" - final val BasketTradingConstituent = "basketTradingConstituent" + final val BasketTradingConstituentTable = "basketTradingConstituent" final val BasketTradingConstituentJoin = "basketTradingConstituentJoin" def apply()(implicit clock: Clock, lifecycle: LifecycleContainer, tableDefContainer: TableDefContainer): ViewServerModule = { - import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B} - import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC} - import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingColumnNames => BT} - import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentColumnNames => BTC} - import org.finos.vuu.core.module.basket.BasketModule.{PriceStrategy => PS} + import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B, BasketConstituentColumnNames => BC, BasketTradingColumnNames => BT, BasketTradingConstituentColumnNames => BTC, PriceStrategy => PS} ModuleFactory.withNamespace(NAME) .addTable( @@ -49,7 +44,7 @@ object BasketModule extends DefaultModule { name = BasketConstituentTable, keyField = BC.RicBasketId, columns = Columns.fromNames(BC.RicBasketId.string(), BC.Ric.string(), BC.BasketId.string(), BC.Weighting.double(), BC.LastTrade.string(), BC.Change.string(), - BC.Volume.string(), BC.Side.string()), // we can join to instruments and other tables to get the rest of the data..... + BC.Volume.string(), BC.Side.string(), BC.Description.string()), // we can join to instruments and other tables to get the rest of the data..... VisualLinks(), joinFields = BC.RicBasketId, BC.Ric ), @@ -59,15 +54,19 @@ object BasketModule extends DefaultModule { TableDef( name = BasketTradingTable, keyField = BT.InstanceId, - columns = Columns.fromNames(BT.InstanceId.string(), BT.BasketId.string(), BT.BasketName.string(), BT.Status.string(), BT.Units.int(), BT.FilledPct.double(), BT.FxRateToUsd.double(), BT.TotalNotional.double(), BT.TotalNotionalUsd.double()), // we can join to instruments and other tables to get the rest of the data..... + columns = Columns.fromNames(BT.InstanceId.string(), BT.BasketId.string(), BT.BasketName.string(), BT.Status.string(), BT.Units.int(), BT.FilledPct.double(), BT.FxRateToUsd.double(), BT.TotalNotional.double(), BT.TotalNotionalUsd.double(), BT.Side.string()), // we can join to instruments and other tables to get the rest of the data..... VisualLinks(), joinFields = BT.BasketId ), - (table, vs) => new NullProvider(table), + (table, vs) => new BasketTradingProvider(table, vs.tableContainer), + (table, _, _, tableContainer) => ViewPortDef( + columns = table.getTableDef.columns, + service = new BasketTradingService(table, tableContainer) + ) ) .addTable( TableDef( - name = BasketTradingConstituent, + name = BasketTradingConstituentTable, keyField = BTC.InstanceIdRic, columns = Columns.fromNames(BTC.Quantity.long(), BTC.Side.string(), BTC.InstanceIdRic.string(), BTC.InstanceId.string(), BTC.Ric.string(), @@ -116,8 +115,8 @@ object BasketModule extends DefaultModule { .addJoinTable(tableDefs => JoinTableDef( name = BasketTradingConstituentJoin, - baseTable = tableDefs.get(NAME, BasketTradingConstituent), - joinColumns = Columns.allFrom(tableDefs.get(NAME, BasketTradingConstituent)) ++ Columns.allFromExcept(tableDefs.get(PriceModule.NAME, "prices"), "ric"), + baseTable = tableDefs.get(NAME, BasketTradingConstituentTable), + joinColumns = Columns.allFrom(tableDefs.get(NAME, BasketTradingConstituentTable)) ++ Columns.allFromExcept(tableDefs.get(PriceModule.NAME, "prices"), "ric"), joins = JoinTo( table = tableDefs.get(PriceModule.NAME, "prices"), @@ -170,9 +169,9 @@ object BasketModule extends DefaultModule { final val Units = "units" final val TotalNotionalUsd = "totalNotionalUsd" final val TotalNotional = "totalNotional" - //BasketTrading Screen final val Status = "status" final val FilledPct = "filledPct" + final val Side = "side" } object BasketTradingConstituentColumnNames { @@ -183,9 +182,6 @@ object BasketModule extends DefaultModule { final val Ric = "ric" final val Description = "description" final val Quantity = "quantity" - final val Last = "last" - final val Bid = "bid" - final val Offer = "offer" final val LimitPrice = "limitPrice" final val PriceStrategyId = "priceStrategyId" final val NotionalUsd = "notionalUsd" @@ -197,4 +193,9 @@ object BasketModule extends DefaultModule { final val Weighting = "weighting" final val PriceSpread = "priceSpread" } + + object Sides{ + final val Buy = "Buy" + final val Sell = "Sell" + } } diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala similarity index 92% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala index ac111cf88..13023bffa 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/csv/CsvStaticLoader.scala @@ -1,14 +1,18 @@ package org.finos.vuu.core.module.basket.csv +import com.typesafe.scalalogging.StrictLogging + import scala.io.Source -object CsvStaticLoader { +object CsvStaticLoader extends StrictLogging { def loadConstituent(basketId: String): Array[Map[String, Any]] = { + val staticDirPath = getClass.getResource("/static").getPath val dir = new java.io.File(staticDirPath) val csvFiles = dir.listFiles.filter(_.isFile) .filter(_.getName.endsWith(basketId.replace(".","").toLowerCase + ".csv")) val csvFile = csvFiles(0) + logger.info("Loading basket static:" + basketId + "(" + csvFile + ")") val bufferedSource = Source.fromFile(csvFile) val csv = for (line <- bufferedSource.getLines) yield line.split(",").map(_.trim) val array = csv.toArray @@ -19,7 +23,7 @@ object CsvStaticLoader { val nameInd = header.indexOf("Name") val lastTradeInd = header.indexOf("Last Trade") val volumeInd = header.indexOf("Volume") - val weightInd = header.indexOf("Weight") + val weightInd = header.indexOf("Weighting") val changeInd = header.indexOf("Change") val list = array.tail.map(e => { val weighting = if(getValueFromIndex(weightInd, e) == null) 0.0D else getValueFromIndex(weightInd, e).toDouble @@ -27,7 +31,7 @@ object CsvStaticLoader { "Symbol" -> getValueFromIndex(symbolInd, e), "Last Trade" -> getValueFromIndex(lastTradeInd, e), "Name" -> getValueFromIndex(nameInd, e), - "Weight" -> weighting, + "Weighting" -> weighting, "Volume" -> getValueFromIndex(volumeInd, e), "Change" -> getValueFromIndex(changeInd, e) ) diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/AlgoProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/AlgoProvider.scala similarity index 86% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/AlgoProvider.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/AlgoProvider.scala index 21efb1815..5ae352bc5 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/AlgoProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/AlgoProvider.scala @@ -10,11 +10,12 @@ class AlgoProvider(val table: DataTable)(implicit lifecycle: LifecycleContainer, lifecycle(this) private final val Algos = List( - (0, "Sniper"), - (1, "Dark Liquidity"), - (2, "VWAP"), - (3, "POV"), - (4, "Dynamic CLose"), + (-1, "None"), + (1, "Sniper"), + (2, "Dark Liquidity"), + (3, "VWAP"), + (4, "POV"), + (5, "Dynamic CLose"), ) override def doStart(): Unit = { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala similarity index 97% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala index 182cfe867..4b1ec3d06 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketConstituentProvider.scala @@ -31,7 +31,7 @@ class BasketConstituentProvider(val table: DataTable)(implicit lifecycle: Lifecy val lastTrade = row("Last Trade") val change = row("Change") val volume = row("Volume") - val weighting = row("Weight") + val weighting = row("Weighting") val side = BasketConstants.Side.Buy val ricBasketId = symbol + "." + basketId table.processUpdate(ricBasketId, RowWithData(symbol, Map( diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketProvider.scala diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingProvider.scala new file mode 100644 index 000000000..7e67b3b48 --- /dev/null +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/BasketTradingProvider.scala @@ -0,0 +1,51 @@ +package org.finos.vuu.core.module.basket.provider + +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.thread.LifeCycleRunner +import org.finos.toolbox.time.Clock +import org.finos.vuu.core.module.basket.BasketModule.BasketTradingColumnNames.{TotalNotional, TotalNotionalUsd} +import org.finos.vuu.core.module.basket.BasketModule.BasketTradingConstituentColumnNames.{InstanceId, Quantity} +import org.finos.vuu.core.module.basket.BasketModule.BasketTradingConstituentJoin +import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer} +import org.finos.vuu.provider.DefaultProvider + +class BasketTradingProvider(val table: DataTable, val tableContainer: TableContainer)(implicit lifecycle: LifecycleContainer, clock: Clock) extends DefaultProvider{ + private val runner = new LifeCycleRunner("BasketTradingProvider", runOnce, minCycleTime = 2_000) + + lifecycle(this).dependsOn(runner) + + def runOnce(): Unit = { + + val constituent = tableContainer.getTable(BasketTradingConstituentJoin) + + table.primaryKeys.foreach( key => { + + val sumOfNotional = constituent.primaryKeys.filter( conKey =>{ + val row = constituent.pullRow(conKey) + row.get(InstanceId).asInstanceOf[String] == key + }).map(conKey => { + + val quantity = constituent.pullRow(conKey).get(Quantity).asInstanceOf[Long] + val bid =constituent.pullRow(conKey).get("bid").asInstanceOf[Double] + val ask =constituent.pullRow(conKey).get("ask").asInstanceOf[Double] + val last =constituent.pullRow(conKey).get("last").asInstanceOf[Double] + + if(last > 0){ + quantity * last + }else if(bid > 0){ + quantity * bid + } else if (ask > 0) { + quantity * ask + }else{ + 0 + } + + } ).sum + + table.processUpdate(key, RowWithData(key, Map(InstanceId -> key, TotalNotionalUsd -> sumOfNotional.asInstanceOf[Long], TotalNotional -> sumOfNotional.asInstanceOf[Long])), clock.now()) + }) + + } + + override val lifecycleId: String = "BasketTradingProvider#" + hashCode() +} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/NullProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/NullProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/NullProvider.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/NullProvider.scala diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/PriceStrategyProvider.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/PriceStrategyProvider.scala similarity index 95% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/PriceStrategyProvider.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/PriceStrategyProvider.scala index 90f2ece34..0939b2f23 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/provider/PriceStrategyProvider.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/provider/PriceStrategyProvider.scala @@ -9,7 +9,7 @@ class PriceStrategyProvider(val table: DataTable)(implicit lifecycle: LifecycleC lifecycle(this) - private final val Strategies = List( + final val Strategies = List( (0, "Peg To Near Touch"), (1, "Far Touch"), (2, "Limit"), diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala similarity index 66% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala index 722ee686d..9be3540bb 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketService.scala @@ -3,12 +3,12 @@ package org.finos.vuu.core.module.basket.service import com.typesafe.scalalogging.StrictLogging import org.finos.toolbox.time.Clock import org.finos.vuu.core.module.basket.BasketModule -import org.finos.vuu.core.module.basket.BasketModule.BasketConstituentTable +import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentTable, PriceStrategy, Sides} import org.finos.vuu.core.module.basket.service.BasketService.counter import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer} +import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} import org.finos.vuu.net.{ClientSessionId, RequestContext} -import org.finos.vuu.net.rpc.RpcHandler -import org.finos.vuu.viewport.{NoAction, SelectionViewPortMenuItem, ViewPortAction, ViewPortMenu, ViewPortSelection} +import org.finos.vuu.viewport._ import java.util.concurrent.atomic.AtomicInteger @@ -16,13 +16,15 @@ object BasketService{ val counter = new AtomicInteger(0) } -class BasketService(val table: DataTable, val tableContainer: TableContainer)(implicit clock: Clock) extends RpcHandler with StrictLogging { +trait BasketServiceIF{ + def createBasket(basketKey: String, name: String)(ctx: RequestContext): ViewPortAction +} + +class BasketService(val table: DataTable, val tableContainer: TableContainer)(implicit clock: Clock) extends RpcHandler with BasketServiceIF with StrictLogging { //private val counter = new AtomicInteger(0) - import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingColumnNames => BT} - import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC} - import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentColumnNames => BTC} + import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC, BasketTradingColumnNames => BT, BasketTradingConstituentColumnNames => BTC} private def getAndPadCounter(session: ClientSessionId): String = { val counterValue = counter.incrementAndGet() @@ -35,21 +37,27 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer)(im keys.map( key => table.pullRow(key) ).filter(_.get(BC.BasketId).toString == key) } - private def mkTradingConstituentRow(side: String, basketKey: String, instanceKey: String, constituentKey: String, quantity: Long, basketConsRow: RowData): RowWithData = { - RowWithData(constituentKey, Map(BTC.BasketId -> basketKey, BTC.Ric -> basketConsRow.get(BC.Ric), BTC.InstanceId -> instanceKey, + private def mkTradingConstituentRow(side: String, basketKey: String, instanceKey: String, + constituentKey: String, quantity: Long, weighting: Double, basketConsRow: RowData): RowWithData = { + RowWithData(constituentKey, Map(BTC.BasketId -> basketKey, + BTC.Ric -> basketConsRow.get(BC.Ric), + BTC.InstanceId -> instanceKey, BTC.Quantity -> quantity, BTC.InstanceIdRic -> constituentKey, BTC.Description -> basketConsRow.get(BC.Description), - BTC.Side -> side + BTC.Side -> side, + BTC.Weighting -> weighting, + BTC.PriceStrategyId -> 2, + BTC.Algo -> -1, )) } private def mkTradingBasketRow(instanceKey: String, basketKey: String): RowWithData = { - RowWithData(instanceKey, Map(BT.InstanceId -> instanceKey, BT.Status -> "OFF-MARKET", BT.BasketId -> basketKey)) + RowWithData(instanceKey, Map(BT.InstanceId -> instanceKey, BT.Status -> "OFF-MARKET", BT.BasketId -> basketKey, BT.BasketName -> instanceKey, BT.Side -> Sides.Buy, BT.Units -> 1)) } def createBasketFromRpc(basketKey: String, name: String)(ctx: RequestContext): ViewPortAction = { - createBasket(basketKey, name) + createBasket(basketKey, name)(ctx) } def createBasket(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = { @@ -58,10 +66,14 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer)(im val instanceKey = getAndPadCounter(session) - createBasket(basketKey, instanceKey) + createBasketInternal(basketKey, instanceKey, session) } - private def createBasket(basketKey: String, name: String): ViewPortAction = { + def createBasket(basketKey: String, name: String)(ctx: RequestContext): ViewPortAction = { + createBasketInternal(basketKey, name, ctx.session) + } + + private def createBasketInternal(basketKey: String, name: String, sessionId: ClientSessionId): ViewPortAction = { val constituents = getConstituentsForBasketKey(basketKey) @@ -72,14 +84,14 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer)(im logger.error("Cannot find the Basket Trading table.") } - tableContainer.getTable(BasketModule.BasketTradingConstituent) match { + tableContainer.getTable(BasketModule.BasketTradingConstituentTable) match { case table: DataTable => constituents.foreach( rowData => { val constituentKey = name + "." + rowData.get(BTC.Ric) val weighting = rowData.get(BTC.Weighting).asInstanceOf[Double] val quantity = (weighting * 100).asInstanceOf[Long] val side = rowData.get(BTC.Side).toString - table.processUpdate(constituentKey, mkTradingConstituentRow(side, basketKey, name, constituentKey, quantity, rowData), clock.now()) + table.processUpdate(constituentKey, mkTradingConstituentRow(side, basketKey, name, constituentKey, quantity, weighting, rowData), clock.now()) }) case null => logger.error("Cannot find the Basket Trading Constituent.") @@ -91,4 +103,5 @@ class BasketService(val table: DataTable, val tableContainer: TableContainer)(im override def menuItems(): ViewPortMenu = ViewPortMenu( new SelectionViewPortMenuItem("Create New", "", (sel, sess) => this.createBasket(sel, sess), "CREATE_NEW_BASKET"), ) + } diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala similarity index 87% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala index 5681d8ba7..6a6685641 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentJoinService.scala @@ -76,4 +76,17 @@ class BasketTradingConstituentJoinService(val table: DataTable, val tableContain override def onFormClose(): ViewPortFormCloseAction = ViewPortFormCloseAction("", this.onFormClose) + def setSell(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = { + ViewPortEditSuccess() + } + + def setBuy(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = { + ViewPortEditSuccess() + } + + override def menuItems(): ViewPortMenu = ViewPortMenu("Direction", + new SelectionViewPortMenuItem("Set Sell", "", this.setSell, "SET_SELECTION_SELL"), + new SelectionViewPortMenuItem("Set Buy", "", this.setBuy, "SET_SELECTION_Buy") + ) + } diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentService.scala similarity index 86% rename from vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentService.scala rename to example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentService.scala index faa21347a..2975b4299 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentService.scala +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingConstituentService.scala @@ -69,4 +69,16 @@ class BasketTradingConstituentService(val table: DataTable, val tableContainer: override def onFormClose(): ViewPortFormCloseAction = ViewPortFormCloseAction("", this.onFormClose) + def setSell(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = { + ViewPortEditSuccess() + } + + def setBuy(selection: ViewPortSelection, session: ClientSessionId): ViewPortAction = { + ViewPortEditSuccess() + } + + override def menuItems(): ViewPortMenu = ViewPortMenu("Direction", + new SelectionViewPortMenuItem("Set Sell", "", this.setSell, "SET_SELECTION_SELL"), + new SelectionViewPortMenuItem("Set Buy", "", this.setBuy, "SET_SELECTION_Buy") + ) } diff --git a/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala new file mode 100644 index 000000000..5767db434 --- /dev/null +++ b/example/basket/src/main/scala/org/finos/vuu/core/module/basket/service/BasketTradingService.scala @@ -0,0 +1,63 @@ +package org.finos.vuu.core.module.basket.service + +import com.typesafe.scalalogging.StrictLogging +import org.finos.toolbox.time.Clock +import org.finos.vuu.core.module.basket.BasketModule.{BasketTradingConstituentTable, Sides} +import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer} +import org.finos.vuu.net.ClientSessionId +import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} +import org.finos.vuu.viewport.{ViewPort, ViewPortAddRowAction, ViewPortDeleteCellAction, ViewPortDeleteRowAction, ViewPortEditAction, ViewPortEditCellAction, ViewPortEditRowAction, ViewPortEditSuccess, ViewPortFormCloseAction, ViewPortFormSubmitAction} + +trait BasketTradingServiceIF extends EditRpcHandler{ + +} + +class BasketTradingService(val table: DataTable, val tableContainer: TableContainer)(implicit clock: Clock) extends RpcHandler with BasketTradingServiceIF with StrictLogging { + + import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC, BasketTradingColumnNames => BT, BasketTradingConstituentColumnNames => BTC} + + private def onEditCell(key: String, columnName: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + logger.info("Changing cell value for key:" + key + "(" + columnName + ":" + data + ")") + table.processUpdate(key, RowWithData(key, Map(BT.InstanceId -> key, columnName -> data)), clock.now()) + + columnName match { + case BT.Units => + val constituentTable = tableContainer.getTable(BasketTradingConstituentTable) + val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key) + constituents.foreach( row => { + val unitsAsInt = data.asInstanceOf[Int] + val weighting = row.get(BTC.Weighting) + val quantity = (weighting.asInstanceOf[Double] * unitsAsInt).toLong + constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Quantity -> quantity)), clock.now()) + }) + case BT.Side => + val constituentTable = tableContainer.getTable(BasketTradingConstituentTable) + val constituents = constituentTable.primaryKeys.map(key => constituentTable.pullRow(key)).filter(_.get(BTC.InstanceId) == key) + val side = data.asInstanceOf[String] + constituents.foreach(row => { + val newSide = row.get(BTC.Side) match { + case Sides.Buy => Sides.Sell + case _ => Sides.Buy + } + constituentTable.processUpdate(row.key(), RowWithData(row.key(), Map(BTC.InstanceIdRic -> row.key(), BTC.Side -> newSide)), clock.now()) + }) + + case _ => + } + + ViewPortEditSuccess() + } + override def deleteRowAction(): ViewPortDeleteRowAction = ??? + + override def deleteCellAction(): ViewPortDeleteCellAction = ??? + + override def addRowAction(): ViewPortAddRowAction = ??? + + override def editCellAction(): ViewPortEditCellAction = ViewPortEditCellAction("", onEditCell) + override def editRowAction(): ViewPortEditRowAction = ??? + + override def onFormSubmit(): ViewPortFormSubmitAction = ??? + + override def onFormClose(): ViewPortFormCloseAction = ??? + +} diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala new file mode 100644 index 000000000..43bde891c --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketCreateTest.scala @@ -0,0 +1,75 @@ +package org.finos.vuu.core.module.basket + +import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.time.{Clock, TestFriendlyClock} +import org.finos.vuu.api.ViewPortDef +import org.finos.vuu.core.module.TableDefContainer +import org.finos.vuu.core.module.basket.service.{BasketServiceIF, BasketTradingServiceIF} +import org.finos.vuu.core.module.price.PriceModule +import org.finos.vuu.core.table.TableTestHelper.combineQs +import org.finos.vuu.test.VuuServerTestCase +import org.finos.vuu.util.table.TableAsserts.assertVpEq +import org.scalatest.prop.Tables.Table + +class BasketCreateTest extends VuuServerTestCase { + + Feature("Basket Service Test Case") { + + Scenario("Check the creation of the baskets and constituents") { + + implicit val clock: Clock = new TestFriendlyClock(10001L) + implicit val lifecycle: LifecycleContainer = new LifecycleContainer() + implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map()) + implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl + + import BasketModule.{BasketTradingColumnNames => BT, _} + + withVuuServer(PriceModule(), BasketModule()) { + vuuServer => + + vuuServer.login("testUser", "testToken") + + vuuServer.overrideViewPortDef("prices", (table, _, _, _) => ViewPortDef(table.getTableDef.columns, null)) + + val pricesProvider = vuuServer.getProvider(PriceModule.NAME, "prices") + + pricesProvider.tick("VOD.L", Map("ric" -> "VOD.L", "phase" -> "C")) + + val viewport = vuuServer.createViewPort(PriceModule.NAME, "prices") + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(viewport)) { + Table( + ("ric", "bid", "ask", "bidSize", "askSize", "last", "open", "close", "phase", "scenario"), + ("VOD.L", null, null, null, null, null, null, null, "C", null) + ) + } + + val viewportBasket = vuuServer.createViewPort(BasketModule.NAME, BasketTable) + + val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](viewportBasket) + + val action = basketService.createBasket(".FTSE", "chris-001")(vuuServer.requestContext) + + val viewportBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) + + val basketTradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](viewportBasketTrading) + + //CJS: I don't like this forced cast, need to look at that a bit + basketTradingService.editCellAction().func("chris-001", BT.Units, 100.asInstanceOf[Object], viewportBasketTrading, vuuServer.session) + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(viewportBasketTrading)) { + Table( + ("basketId", "instanceId", "basketName", "units", "status", "filledPct", "totalNotionalUsd", "totalNotional", "fxRateToUsd", "side"), + (".FTSE", "chris-001", "chris-001", 100, "OFF-MARKET", null, null, null, null, "Buy") + ) + } + } + } + } + +} diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala new file mode 100644 index 000000000..93d8e73cc --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketMutateOffMarketTest.scala @@ -0,0 +1,143 @@ +package org.finos.vuu.core.module.basket + +import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.time.{Clock, TestFriendlyClock} +import org.finos.vuu.api.ViewPortDef +import org.finos.vuu.core.module.TableDefContainer +import org.finos.vuu.core.module.basket.service.{BasketServiceIF, BasketTradingServiceIF} +import org.finos.vuu.core.module.price.PriceModule +import org.finos.vuu.test.VuuServerTestCase +import org.finos.vuu.util.table.TableAsserts.assertVpEq +import org.scalatest.prop.Tables.Table + +class BasketMutateOffMarketTest extends VuuServerTestCase { + + import BasketTestCaseHelper._ + + Feature("Basket Service Test Case") { + + Scenario("Check the creation of the baskets and constituents") { + + implicit val clock: Clock = new TestFriendlyClock(10001L) + implicit val lifecycle: LifecycleContainer = new LifecycleContainer() + implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map()) + implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl + + import BasketModule._ + + withVuuServer(PriceModule(), BasketModule()) { + vuuServer => + + vuuServer.login("testUser", "testToken") + + vuuServer.overrideViewPortDef("prices", (table, _, _, _) => ViewPortDef(table.getTableDef.columns, null)) + + val pricesProvider = vuuServer.getProvider(PriceModule.NAME, "prices") + val basketProvider = vuuServer.getProvider(BasketModule.NAME, BasketTable) + val constituentProvider = vuuServer.getProvider(BasketModule.NAME, BasketConstituentTable) + + tickPrices(pricesProvider) + tickBasketDef(basketProvider) + tickConstituentsDef(constituentProvider) + + val vpBasket = vuuServer.createViewPort(BasketModule.NAME, BasketTable) + + vuuServer.runOnce() + + When("we have 2 basket definitions") + assertVpEq(combineQsForVp(vpBasket)) { + Table( + ("id", "name", "notionalValue", "notionalValueUsd"), + (".FTSE", ".FTSE 100", 1000001, 1500001), + (".NASDAQ", ".NASDAQ", 3000001, 3500001) + ) + } + + val vpConstituent = vuuServer.createViewPort(BasketModule.NAME, BasketConstituentTable) + + vuuServer.runOnce() + + And(".FTSE is composed of 3 constituents") + assertVpEq(combineQsForVp(vpConstituent)) { + Table( + ("ricBasketId", "ric", "basketId", "weighting", "lastTrade", "change", "volume", "description", "side"), + ("BP.L.FTSE", "BP.L", ".FTSE", 0.1, null, null, null, "Beyond Petroleum", "Buy"), + ("BT.L.FTSE", "BT.L", ".FTSE", 0.1, null, null, null, "British Telecom", "Sell"), + ("VOD.L.FTSE", "VOD.L", ".FTSE", 0.1, null, null, null, "Vodafone", "Buy") + ) + } + + Then("Get the Basket RPC Service and call create basket") + val basketService = vuuServer.getViewPortRpcServiceProxy[BasketServiceIF](vpBasket) + basketService.createBasket(".FTSE", "chris-001")(vuuServer.requestContext) + + val vpBasketTrading = vuuServer.createViewPort(BasketModule.NAME, BasketTradingTable) + + vuuServer.runOnce() + + And("Check the basket trading record has been created") + //BT.InstanceId.string(), BT.BasketId.string(), BT.BasketName.string(), BT.Status.string(), BT.Units.int(), BT.FilledPct.double(), BT.FxRateToUsd.double(), BT.TotalNotional.double(), BT.TotalNotionalUsd.double(), BT.Side.string() + assertVpEq(combineQsForVp(vpBasketTrading)) { + Table( + ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), + ("chris-001", ".FTSE", "chris-001", "OFF-MARKET", 1, null, null, null, null, "Buy") + ) + } + + val vpBasketTradingCons = vuuServer.createViewPort(BasketModule.NAME, BasketTradingConstituentTable) + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(vpBasketTradingCons)) { + Table( + ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId"), + (10L, "Buy", "chris-001", "chris-001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2), + (10L, "Sell", "chris-001", "chris-001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2), + (10L, "Buy", "chris-001", "chris-001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2) + ) + } + + val basketTradingService = vuuServer.getViewPortRpcServiceProxy[BasketTradingServiceIF](vpBasketTrading) + + When("we edit the side of the parent basket") + basketTradingService.editCellAction().func("chris-001", "side", "Sell", vpBasketTrading, vuuServer.session) + + Then("get all the updates that have occurred for all view ports from the outbound queue") + val updates = combineQs(vpBasketTrading) + + And("assert the basket trading table has flipped side....") + assertVpEq(filterByVp(vpBasketTrading, updates)) { + Table( + ("instanceId", "basketId", "basketName", "status", "units", "filledPct", "fxRateToUsd", "totalNotional", "totalNotionalUsd", "side"), + ("chris-001", ".FTSE", "chris-001", "OFF-MARKET", 1, null, null, null, null, "Sell") + ) + } + + //vuuServer.runOnce() + And("assert the basket trading constituent table has flipped sides also") + assertVpEq(filterByVp(vpBasketTradingCons,updates)) { + Table( + ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId"), + (10L, "Sell", "chris-001", "chris-001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2), + (10L, "Buy", "chris-001", "chris-001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2), + (10L, "Sell", "chris-001", "chris-001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2) + ) + } + + When("we edit the units of the parent basket") + basketTradingService.editCellAction().func("chris-001", "units", 1000L.asInstanceOf[Object], vpBasketTrading, vuuServer.session) + + And("assert the basket trading constituent table has increased the units") + assertVpEq(filterByVp(vpBasketTradingCons, combineQs(vpBasketTrading))) { + Table( + ("quantity", "side", "instanceId", "instanceIdRic", "basketId", "ric", "description", "notionalUsd", "notionalLocal", "venue", "algo", "algoParams", "pctFilled", "weighting", "priceSpread", "limitPrice", "priceStrategyId"), + (100L, "Sell", "chris-001", "chris-001.BP.L", ".FTSE", "BP.L", "Beyond Petroleum", null, null, null, -1, null, null, 0.1, null, null, 2), + (100L, "Buy", "chris-001", "chris-001.BT.L", ".FTSE", "BT.L", "British Telecom", null, null, null, -1, null, null, 0.1, null, null, 2), + (100L, "Sell", "chris-001", "chris-001.VOD.L", ".FTSE", "VOD.L", "Vodafone", null, null, null, -1, null, null, 0.1, null, null, 2) + ) + } + } + } + } +} \ No newline at end of file diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala new file mode 100644 index 000000000..540cb1d2d --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/BasketTestCaseHelper.scala @@ -0,0 +1,27 @@ +package org.finos.vuu.core.module.basket + +import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B, BasketConstituentColumnNames => BC} +import org.finos.vuu.provider.MockProvider + +object BasketTestCaseHelper { + def tickPrices(provider: MockProvider): Unit = { + provider.tick("VOD.L", Map("ric" -> "VOD.L", "phase" -> "C", "bid" -> 100, "ask" -> 101, "last" -> 101.5)) + provider.tick("BT.L", Map("ric" -> "BT.L", "phase" -> "C", "bid" -> 200, "ask" -> 201, "last" -> 201.5)) + provider.tick("BP.L", Map("ric" -> "BP.L", "phase" -> "C", "bid" -> 300, "ask" -> 301, "last" -> 301.5)) + provider.tick("AAPL", Map("ric" -> "AAPL", "phase" -> "C", "bid" -> 1000, "ask" -> 1001, "last" -> 1001.5)) + provider.tick("MSFT", Map("ric" -> "MSFT", "phase" -> "C", "bid" -> 1100, "ask" -> 1001, "last" -> 1001.5)) + } + def tickBasketDef(provider: MockProvider): Unit = { + provider.tick(".FTSE", Map(B.Id -> ".FTSE", B.Name -> ".FTSE 100", B.NotionalValue -> 1000001, B.NotionalValueUsd -> 1500001)) + provider.tick(".NASDAQ", Map(B.Id -> ".NASDAQ", B.Name -> ".NASDAQ", B.NotionalValue -> 3000001, B.NotionalValueUsd -> 3500001)) + } + + def tickConstituentsDef(provider: MockProvider): Unit = { + //symbol + "." + basketId + //Columns.fromNames(BC.RicBasketId.string(), BC.Ric.string(), BC.BasketId.string(), BC.Weighting.double(), BC.LastTrade.string(), BC.Change.string(), + // BC.Volume.string(), BC.Side.string()) + provider.tick("VOD.L.FTSE", Map(BC.RicBasketId -> "VOD.L.FTSE", BC.Ric -> "VOD.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Vodafone")) + provider.tick("BT.L.FTSE", Map(BC.RicBasketId -> "BT.L.FTSE", BC.Ric -> "BT.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "Sell", BC.Description -> "British Telecom")) + provider.tick("BP.L.FTSE", Map(BC.RicBasketId -> "BP.L.FTSE", BC.Ric -> "BP.L", BC.BasketId -> ".FTSE", BC.Weighting -> 0.1, BC.Side -> "Buy", BC.Description -> "Beyond Petroleum")) + } +} diff --git a/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestService.scala b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestService.scala new file mode 100644 index 000000000..a2f66c49e --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/core/module/basket/TestService.scala @@ -0,0 +1,25 @@ +package org.finos.vuu.core.module.basket + +import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} +import org.finos.vuu.viewport.{ViewPortAction, ViewPortAddRowAction, ViewPortDeleteCellAction, ViewPortDeleteRowAction, ViewPortEditCellAction, ViewPortEditRowAction, ViewPortEditSuccess, ViewPortFormCloseAction, ViewPortFormSubmitAction} + +class TestService extends RpcHandler with EditRpcHandler { + def sendBasketToMarket(): ViewPortAction = { + println("test") + ViewPortEditSuccess() + } + + override def deleteRowAction(): ViewPortDeleteRowAction = ??? + + override def deleteCellAction(): ViewPortDeleteCellAction = ??? + + override def addRowAction(): ViewPortAddRowAction = ??? + + override def editCellAction(): ViewPortEditCellAction = ??? + + override def editRowAction(): ViewPortEditRowAction = ??? + + override def onFormSubmit(): ViewPortFormSubmitAction = ??? + + override def onFormClose(): ViewPortFormCloseAction = ??? +} diff --git a/example/basket/src/test/scala/org/finos/vuu/provider/BasketConstituentProviderTest.scala b/example/basket/src/test/scala/org/finos/vuu/provider/BasketConstituentProviderTest.scala new file mode 100644 index 000000000..f8a959b93 --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/provider/BasketConstituentProviderTest.scala @@ -0,0 +1,102 @@ +//package org.finos.vuu.provider +// +//import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} +//import org.finos.toolbox.lifecycle.LifecycleContainer +//import org.finos.toolbox.time.TestFriendlyClock +//import org.finos.vuu.api.{TableDef, VisualLinks} +//import org.finos.vuu.core.module.FieldDefString +//import org.finos.vuu.core.module.basket.BasketModule.{BasketConstituentColumnNames => BC} +//import org.finos.vuu.core.module.basket.provider.BasketConstituentProvider +//import org.finos.vuu.core.table.{Column, Columns, SimpleDataTable, ViewPortColumnCreator} +//import org.scalatest.BeforeAndAfter +//import org.scalatest.featurespec.AnyFeatureSpec +//import org.scalatest.matchers.should.Matchers +// +//class BasketConstituentProviderTest extends AnyFeatureSpec with Matchers with BeforeAndAfter { +// final val TEST_TIME = 1450770869442L +// val joinProvider = new TestFriendlyJoinTableProvider +// implicit val timeProvider: TestFriendlyClock = new TestFriendlyClock(TEST_TIME) +// implicit val metrics: MetricsProvider = new MetricsProviderImpl +// implicit val lifecycleContainer: LifecycleContainer = new LifecycleContainer +// +// val tableDef = TableDef( +// name = "basketConstituent", +// keyField = BC.RicBasketId, +// columns = Columns.fromNames(new FieldDefString(BC.RicBasketId).string(), +// new FieldDefString(BC.Ric).string(), +// new FieldDefString(BC.BasketId).string(), +// new FieldDefString(BC.Weighting).double(), +// new FieldDefString(BC.LastTrade).string(), +// new FieldDefString(BC.Change).string(), +// new FieldDefString(BC.Volume).string()), // we can join to instruments and other tables to get the rest of the data..... +// VisualLinks(), +// joinFields = BC.RicBasketId +// ) +// val table = new SimpleDataTable(tableDef, joinProvider) +// val provider = new BasketConstituentProvider(table) +// val columns: Array[Column] = provider.table.getTableDef.columns +// val headers: Array[String] = columns.map(_.name) +// +// before { +// provider.runOnce +// } +// +// ignore("Able to load basket constituents from .FTSE100 and show on basket constituent table") { +// +// Scenario("display ric") { +// assert(getDataForBasket(".FTSE100")(0)(headers.indexOf(BC.Ric)) == "AAL.L") +// } +// +// Scenario("display basket id") { +// assert(getDataForBasket(".FTSE100")(0)(headers.indexOf(BC.BasketId)) == ".FTSE100") +// } +// +// Scenario("display change") { +// assert(getDataForBasket(".FTSE100")(0)(headers.indexOf(BC.Change)) == "�5.35�(1.24%)") +// } +// +// // TODO emily - volume with , is not parsed correctly +//// Scenario("display volume") { +//// assert(getDataForBasket(".FTSE100")(0)(headers.indexOf(BC.Volume)) == "5,799,089") +//// } +// +// Scenario("display weighting") { +// assert(getDataForBasket(".FTSE100")(0)(headers.indexOf(BC.Weighting)) == null) +// } +// } +// +// ignore("Able to load basket constituents from .NASDAQ100 and show on basket constituent table") { +// +//// Scenario("display ric") { +//// val array = getDataForBasket(".NASDAQ100") +//// assert(array(0)(headers.indexOf(BC.Ric)) == "AAPL") +//// } +// +// Scenario("display basket id") { +// assert(getDataForBasket(".NASDAQ100")(0)(headers.indexOf(BC.BasketId)) == ".NASDAQ100") +// } +// +// Scenario("display change") { +// assert(getDataForBasket(".NASDAQ100")(0)(headers.indexOf(BC.Change)) == null) +// } +// +// Scenario("display volume") { +// assert(getDataForBasket(".NASDAQ100")(0)(headers.indexOf(BC.Volume)) == null) +// } +// +//// Scenario("display weighting") { +//// assert(getDataForBasket(".NASDAQ100")(0)(headers.indexOf(BC.Weighting)) == "11.007") +//// } +// } +// +// +// private def getData = { +// val keys = provider.table.primaryKeys +// val data = keys.toArray.map(key => provider.table.pullRowAsArray(key, ViewPortColumnCreator.create(provider.table, columns.map(_.name).toList))) +// data +// } +// private def getDataForBasket(basketId:String) = { +// val data = getData +// data.filter(e => e(headers.indexOf(BC.BasketId))==basketId) +// } +//} diff --git a/example/basket/src/test/scala/org/finos/vuu/provider/BasketProviderTest.scala b/example/basket/src/test/scala/org/finos/vuu/provider/BasketProviderTest.scala new file mode 100644 index 000000000..04602a52d --- /dev/null +++ b/example/basket/src/test/scala/org/finos/vuu/provider/BasketProviderTest.scala @@ -0,0 +1,55 @@ +//package org.finos.vuu.provider +// +//import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} +//import org.finos.toolbox.lifecycle.LifecycleContainer +//import org.finos.toolbox.time.TestFriendlyClock +//import org.finos.vuu.api.{TableDef, VisualLinks} +//import org.finos.vuu.core.module.FieldDefString +//import org.finos.vuu.core.module.basket.BasketModule.{BasketColumnNames => B} +//import org.finos.vuu.core.module.basket.provider.BasketProvider +//import org.finos.vuu.core.table.{Column, Columns, SimpleDataTable, ViewPortColumnCreator} +//import org.scalatest.BeforeAndAfter +//import org.scalatest.featurespec.AnyFeatureSpec +//import org.scalatest.matchers.should.Matchers +// +//class BasketProviderTest extends AnyFeatureSpec with Matchers with BeforeAndAfter { +// final val TEST_TIME = 1450770869442L +// val joinProvider = new TestFriendlyJoinTableProvider +// implicit val timeProvider: TestFriendlyClock = new TestFriendlyClock(TEST_TIME) +// implicit val metrics: MetricsProvider = new MetricsProviderImpl +// implicit val lifecycleContainer: LifecycleContainer = new LifecycleContainer +// +// val tableDef = TableDef( +// name = "basket", +// keyField = B.Id, +// columns = Columns.fromNames( +// new FieldDefString(B.Id).string(), +// new FieldDefString(B.Name).string(), +// new FieldDefString(B.NotionalValue).double(), +// new FieldDefString(B.NotionalValueUsd).double()), +// VisualLinks(), +// joinFields = B.Id +// ) +// val table = new SimpleDataTable(tableDef, joinProvider) +// val provider = new BasketProvider(table) +// val columns: Array[Column] = provider.table.getTableDef.columns +// val headers: Array[String] = columns.map(_.name) +// +// before { +// provider.runOnce() +// } +// +// Feature("Able to load baskets") { +// +// Scenario("get list of baskets") { +// val ids = getData.map(e => e(headers.indexOf(B.Id))) +//// assert(ids.sameElements(Array(".NASDAQ100", ".FTSE100", ".SP500", ".HSI"))) +// } +// } +// +// private def getData = { +// val keys = provider.table.primaryKeys +// val data = keys.toArray.map(key => provider.table.pullRowAsArray(key, ViewPortColumnCreator.create(provider.table, columns.map(_.name).toList))) +// data +// } +//} diff --git a/example/editable/pom.xml b/example/editable/pom.xml new file mode 100644 index 000000000..ce599c302 --- /dev/null +++ b/example/editable/pom.xml @@ -0,0 +1,246 @@ + + + 4.0.0 + + + org.finos.vuu + example + 0.9.36-SNAPSHOT + + + + editable + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + tests + test-jar + test + + + + org.scala-lang + scala-library + ${scala.version} + + + + org.scala-lang + scala-reflect + ${scala.version} + + + + junit + junit + 4.13.2 + test + + + + org.scalatest + scalatest_2.13 + ${scalatest.version} + test + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + + + + + + + + + legal-report + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + **/*.scala + + + + + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-source-plugin + + + + compile + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.ow2.asm + asm + 6.2 + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + + compile + testCompile + + + + + src/main/scala + src/test/scala + + -Xms64m + -Xmx1024m + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + generate-sources + + add-source + + + + target/generated-sources/antlr4 + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + + test-jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7 + + + + + + + org.scalatest + scalatest-maven-plugin + 2.0.2 + + ${project.build.directory}/surefire-reports + . + test-reports.txt + + + + test + + test + + + + + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + ${scala.version} + + + + + + \ No newline at end of file diff --git a/example/editable/src/main/java/Dummy4JavaDoc.java b/example/editable/src/main/java/Dummy4JavaDoc.java new file mode 100644 index 000000000..00b8d1897 --- /dev/null +++ b/example/editable/src/main/java/Dummy4JavaDoc.java @@ -0,0 +1,2 @@ +public class Dummy4JavaDoc { +} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/editable/EditableModule.scala b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/EditableModule.scala similarity index 93% rename from vuu/src/main/scala/org/finos/vuu/core/module/editable/EditableModule.scala rename to example/editable/src/main/scala/org/finos/vuu/core/module/editable/EditableModule.scala index e7efa02b7..0ce63035b 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/editable/EditableModule.scala +++ b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/EditableModule.scala @@ -1,12 +1,10 @@ package org.finos.vuu.core.module.editable +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.time.Clock import org.finos.vuu.api.{SessionTableDef, TableDef, ViewPortDef, VisualLinks} import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule} import org.finos.vuu.core.table.Columns -import org.finos.vuu.provider.RpcProvider -import org.finos.toolbox.lifecycle.LifecycleContainer -import org.finos.toolbox.time.Clock -import org.finos.vuu.core.module.vui.VuiStateStoreProvider object EditableModule extends DefaultModule { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/editable/FixSequenceRpcService.scala b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/FixSequenceRpcService.scala similarity index 89% rename from vuu/src/main/scala/org/finos/vuu/core/module/editable/FixSequenceRpcService.scala rename to example/editable/src/main/scala/org/finos/vuu/core/module/editable/FixSequenceRpcService.scala index 22b4a1e42..381b747fa 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/editable/FixSequenceRpcService.scala +++ b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/FixSequenceRpcService.scala @@ -4,7 +4,7 @@ import org.finos.toolbox.time.Clock import org.finos.vuu.core.table.RowWithData import org.finos.vuu.net.ClientSessionId import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} -import org.finos.vuu.viewport.{CloseDialogViewPortAction, ViewPort, ViewPortAction, ViewPortAddRowAction, ViewPortDeleteCellAction, ViewPortDeleteRowAction, ViewPortEditAction, ViewPortEditCellAction, ViewPortEditFailure, ViewPortEditRowAction, ViewPortEditSuccess, ViewPortFormCloseAction, ViewPortFormSubmitAction} +import org.finos.vuu.viewport._ class FixSequenceRpcService(implicit clock: Clock) extends RpcHandler with EditRpcHandler{ diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/editable/ProcessProvider.scala b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/ProcessProvider.scala similarity index 93% rename from vuu/src/main/scala/org/finos/vuu/core/module/editable/ProcessProvider.scala rename to example/editable/src/main/scala/org/finos/vuu/core/module/editable/ProcessProvider.scala index 720d504de..629fb0a11 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/editable/ProcessProvider.scala +++ b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/ProcessProvider.scala @@ -1,7 +1,7 @@ package org.finos.vuu.core.module.editable import org.finos.toolbox.lifecycle.LifecycleContainer -import org.finos.toolbox.thread.{LifeCycleRunner, RunOnceLifeCycleRunner} +import org.finos.toolbox.thread.RunOnceLifeCycleRunner import org.finos.toolbox.time.Clock import org.finos.vuu.core.table.{DataTable, RowWithData} import org.finos.vuu.provider.Provider diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/editable/ProcessRpcService.scala b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/ProcessRpcService.scala similarity index 70% rename from vuu/src/main/scala/org/finos/vuu/core/module/editable/ProcessRpcService.scala rename to example/editable/src/main/scala/org/finos/vuu/core/module/editable/ProcessRpcService.scala index d44dcfb68..97701e3da 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/editable/ProcessRpcService.scala +++ b/example/editable/src/main/scala/org/finos/vuu/core/module/editable/ProcessRpcService.scala @@ -1,10 +1,10 @@ package org.finos.vuu.core.module.editable import org.finos.toolbox.time.Clock -import org.finos.vuu.core.table.{DataTable, RowWithData, TableContainer} +import org.finos.vuu.core.table.{RowWithData, TableContainer} import org.finos.vuu.net.ClientSessionId -import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} -import org.finos.vuu.viewport.{OpenDialogViewPortAction, RenderComponent, SelectionViewPortMenuItem, ViewPortAction, ViewPortAddRowAction, ViewPortDeleteCellAction, ViewPortDeleteRowAction, ViewPortEditCellAction, ViewPortEditRowAction, ViewPortFormCloseAction, ViewPortFormSubmitAction, ViewPortMenu, ViewPortSelection, ViewPortTable} +import org.finos.vuu.net.rpc.RpcHandler +import org.finos.vuu.viewport._ class ProcessRpcService(val tableContainer: TableContainer)(implicit clock: Clock) extends RpcHandler{ diff --git a/example/editable/src/test/scala/org/finos/vuu/core/module/editable/EditableTest.scala b/example/editable/src/test/scala/org/finos/vuu/core/module/editable/EditableTest.scala new file mode 100644 index 000000000..2ae309bf3 --- /dev/null +++ b/example/editable/src/test/scala/org/finos/vuu/core/module/editable/EditableTest.scala @@ -0,0 +1,78 @@ +package org.finos.vuu.core.module.editable + +import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.time.{Clock, TestFriendlyClock} +import org.finos.vuu.core.module.TableDefContainer +import org.finos.vuu.core.table.TableTestHelper.combineQs +import org.finos.vuu.test.VuuServerTestCase +import org.finos.vuu.util.table.TableAsserts.assertVpEq +import org.scalatest.prop.Tables.Table + +class EditableTest extends VuuServerTestCase { + + Feature("Editable Test Case") { + + Scenario("Check the editable functionality") { + + implicit val clock: Clock = new TestFriendlyClock(10001L) + implicit val lifecycle: LifecycleContainer = new LifecycleContainer() + implicit val tableDefContainer: TableDefContainer = new TableDefContainer(Map()) + implicit val metricsProvider: MetricsProvider = new MetricsProviderImpl + + withVuuServer(EditableTestModule()) { + vuuServer => + + vuuServer.login("testUser", "testToken") + + val viewport = vuuServer.createViewPort(EditableTestModule.NAME, "editTestTable") + + val service = vuuServer.getViewPortRpcServiceProxy[TestEditableServiceIF](viewport) + + service.addRowAction().func("key1", Map("rowId" -> "key1", "A" -> "TEST", "B" -> 1001D, "C" -> 500, "D" -> true), viewport, vuuServer.session) + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(viewport)) { + Table( + ("rowId", "A", "B", "C", "D"), + ("key1", "TEST", 1001.0, 500, true) + ) + } + + service.editCellAction().func("key1", "B", 200D.asInstanceOf[Object], viewport, vuuServer.session) + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(viewport)) { + Table( + ("rowId", "A", "B", "C", "D"), + ("key1", "TEST", 200.0, 500, true) + ) + } + + service.addRowAction().func("key1", Map("rowId" -> "key2", "A" -> "TEST2", "B" -> 1001D, "C" -> 500, "D" -> true), viewport, vuuServer.session) + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(viewport)) { + Table( + ("rowId", "A", "B", "C", "D"), + ("key2", "TEST2", 1001.0, 500, true) + ) + } + + service.deleteRowAction().func("key1", viewport, vuuServer.session) + + vuuServer.runOnce() + + assertVpEq(combineQsForVp(viewport)) { + Table( + ("rowId", "A", "B", "C", "D") + ) + } + + } + } + } +} diff --git a/example/editable/src/test/scala/org/finos/vuu/core/module/editable/EditableTestModule.scala b/example/editable/src/test/scala/org/finos/vuu/core/module/editable/EditableTestModule.scala new file mode 100644 index 000000000..3b591cab9 --- /dev/null +++ b/example/editable/src/test/scala/org/finos/vuu/core/module/editable/EditableTestModule.scala @@ -0,0 +1,89 @@ +package org.finos.vuu.core.module.editable + +import com.typesafe.scalalogging.StrictLogging +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.time.Clock +import org.finos.vuu.api.{TableDef, ViewPortDef, VisualLinks} +import org.finos.vuu.core.module.{ModuleFactory, TableDefContainer, ViewServerModule} +import org.finos.vuu.core.module.ModuleFactory.stringToString +import org.finos.vuu.core.table.{Columns, DataTable, RowWithData, TableContainer} +import org.finos.vuu.net.ClientSessionId +import org.finos.vuu.net.rpc.{EditRpcHandler, RpcHandler} +import org.finos.vuu.viewport.{ViewPort, ViewPortAddRowAction, ViewPortDeleteCellAction, ViewPortDeleteRowAction, ViewPortEditAction, ViewPortEditCellAction, ViewPortEditRowAction, ViewPortEditSuccess, ViewPortFormCloseAction, ViewPortFormSubmitAction} + +trait TestEditableServiceIF extends EditRpcHandler { + +} + +class TestEditableService(val table: DataTable, val tableContainer: TableContainer)(implicit clock: Clock) extends RpcHandler with TestEditableServiceIF with StrictLogging { + + def addRow(key: String, data: Map[String, Any], vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + table.processUpdate(key, RowWithData(key, data), clock.now()) + ViewPortEditSuccess() + } + + def editRow(key: String, data: Map[String, Any], vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + table.processUpdate(key, RowWithData(key, data), clock.now()) + ViewPortEditSuccess() + } + + def editCell(key: String, column: String, data: Any, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + table.processUpdate(key, RowWithData(key, Map("rowId" -> key, column -> data)), clock.now()) + ViewPortEditSuccess() + } + + def deleteRow(key: String, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + table.processDelete(key) + ViewPortEditSuccess() + } + + def deleteCell(key: String, column: String, vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + table.processUpdate(key, RowWithData(key, Map("rowId" -> key, column -> null)), clock.now()) + ViewPortEditSuccess() + } + + def formSubmit(vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + //table.processUpdate(key, RowWithData(key, Map("rowId" -> key, column -> null)), clock.now()) + ViewPortEditSuccess() + } + + def formClose(vp: ViewPort, session: ClientSessionId): ViewPortEditAction = { + //table.processUpdate(key, RowWithData(key, Map("rowId" -> key, column -> null)), clock.now()) + ViewPortEditSuccess() + } + + override def deleteRowAction(): ViewPortDeleteRowAction = ViewPortDeleteRowAction("", deleteRow) + override def deleteCellAction(): ViewPortDeleteCellAction = ViewPortDeleteCellAction("", deleteCell) + override def addRowAction(): ViewPortAddRowAction = ViewPortAddRowAction("", addRow) + override def editCellAction(): ViewPortEditCellAction = ViewPortEditCellAction("", editCell) + override def editRowAction(): ViewPortEditRowAction = ViewPortEditRowAction("", editRow) + override def onFormSubmit(): ViewPortFormSubmitAction = ViewPortFormSubmitAction("", formSubmit) + override def onFormClose(): ViewPortFormCloseAction = ViewPortFormCloseAction("", formClose) +} + +object EditableTestModule { + + final val NAME = "EDITTEST" + + def apply()(implicit clock: Clock, lifecycle: LifecycleContainer, tableDefContainer: TableDefContainer): ViewServerModule = { + + ModuleFactory.withNamespace(NAME) + .addTable( + //this table should contain one row for each of .FTSE, .DJI, .HSI, .etc... + TableDef( + name = "editTestTable", + keyField = "rowId", + columns = Columns.fromNames("rowId".string(), "A".string(), "B".double(), "C".int(), "D".boolean()), + VisualLinks(), + joinFields = "rowId" + ), + (table, _) => new NullProvider(), + (table, _, _, tableContainer) => ViewPortDef( + columns = table.getTableDef.columns, + service = new TestEditableService(table, tableContainer) + ) + ).asModule() + + } + +} diff --git a/example/editable/src/test/scala/org/finos/vuu/core/module/editable/NullProvider.scala b/example/editable/src/test/scala/org/finos/vuu/core/module/editable/NullProvider.scala new file mode 100644 index 000000000..ead6afcb4 --- /dev/null +++ b/example/editable/src/test/scala/org/finos/vuu/core/module/editable/NullProvider.scala @@ -0,0 +1,17 @@ +package org.finos.vuu.core.module.editable + +import org.finos.vuu.provider.Provider + +class NullProvider extends Provider { + override def subscribe(key: String): Unit = {} + + override def doStart(): Unit = {} + + override def doStop(): Unit = {} + + override def doInitialize(): Unit = {} + + override def doDestroy(): Unit = {} + + override val lifecycleId: String = "NullProvider" +} diff --git a/example/main/pom.xml b/example/main/pom.xml new file mode 100644 index 000000000..a52e54006 --- /dev/null +++ b/example/main/pom.xml @@ -0,0 +1,329 @@ + + + 4.0.0 + + + org.finos.vuu + example + 0.9.36-SNAPSHOT + + + + main + + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + + + + org.finos.vuu + basket + 0.9.36-SNAPSHOT + + + + org.finos.vuu + price + 0.9.36-SNAPSHOT + + + + org.finos.vuu + order + 0.9.36-SNAPSHOT + + + + org.finos.vuu + editable + 0.9.36-SNAPSHOT + + + + org.finos.vuu + permission + 0.9.36-SNAPSHOT + + + + org.scala-lang + scala-library + ${scala.version} + + + + org.scala-lang + scala-reflect + ${scala.version} + + + + junit + junit + 4.13.2 + test + + + + org.scalatest + scalatest_2.13 + ${scalatest.version} + test + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + + + + + + + + + sign-it + + + sign + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + + + + legal-report + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + **/*.scala + + + + + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-source-plugin + + + + compile + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.ow2.asm + asm + 6.2 + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + + compile + testCompile + + + + + src/main/scala + src/test/scala + + -Xms64m + -Xmx1024m + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + generate-sources + + add-source + + + + target/generated-sources/antlr4 + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + + exec + + + + + java + + -Xmx10G + -classpath + + -Dvuu.webroot=../../vuu-ui/deployed_apps/app-vuu-example + -Dvuu.keyPath=src/main/resources/certs/key.pem + -Dvuu.certPath=src/main/resources/certs/cert.pem + -Dlogback.configurationFile=logback-netty.xml + org.finos.vuu.SimulMain + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + + test-jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7 + + + + + + + org.scalatest + scalatest-maven-plugin + 2.0.2 + + ${project.build.directory}/surefire-reports + . + test-reports.txt + + + + test + + test + + + + + + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + ${scala.version} + + + + + + \ No newline at end of file diff --git a/example/main/src/main/java/Dummy4JavaDoc.java b/example/main/src/main/java/Dummy4JavaDoc.java new file mode 100644 index 000000000..00b8d1897 --- /dev/null +++ b/example/main/src/main/java/Dummy4JavaDoc.java @@ -0,0 +1,2 @@ +public class Dummy4JavaDoc { +} diff --git a/example/main/src/main/resources/FilterSpec.txt b/example/main/src/main/resources/FilterSpec.txt new file mode 100644 index 000000000..867fd1d16 --- /dev/null +++ b/example/main/src/main/resources/FilterSpec.txt @@ -0,0 +1,35 @@ +column > {value} +column < {value} +column == {value} +column != {value} +column in [{value},{value2},{value}] +column nin [{value},{value2},{value}] + + +compound clause: +columnA gt {value} && columnB lt {value} && columnC in [{value},{value2},{value}] +columnA gt {value} || columnB lt {value} + + +tradeTime > '2015-09-12 23:59' +quantity > 700 + + +FilterSpec(s: String) +SortSpec(s:String) + + +val pipeline = Pipeline.start(condition) + +Condition.evaluate(row) + +AndCondition() + +OrCondition(AndCondition, AndCondition) + + + + + + + diff --git a/example/main/src/main/resources/application.conf b/example/main/src/main/resources/application.conf new file mode 100644 index 000000000..ae9f4e088 --- /dev/null +++ b/example/main/src/main/resources/application.conf @@ -0,0 +1,3 @@ +vuu.webroot="vuu-ui/deployed_apps/app-vuu-example" +vuu.certPath="example/main/src/main/resources/certs/cert.pem" +vuu.keyPath="example/main/src/main/resources/certs/key.pem" \ No newline at end of file diff --git a/vuu/src/main/resources/certs/cert.pem b/example/main/src/main/resources/certs/cert.pem similarity index 100% rename from vuu/src/main/resources/certs/cert.pem rename to example/main/src/main/resources/certs/cert.pem diff --git a/vuu/src/main/resources/certs/key.pem b/example/main/src/main/resources/certs/key.pem similarity index 100% rename from vuu/src/main/resources/certs/key.pem rename to example/main/src/main/resources/certs/key.pem diff --git a/example/main/src/main/resources/down.gif b/example/main/src/main/resources/down.gif new file mode 100644 index 000000000..284a75533 Binary files /dev/null and b/example/main/src/main/resources/down.gif differ diff --git a/example/main/src/main/resources/icon-arrow-right.png b/example/main/src/main/resources/icon-arrow-right.png new file mode 100644 index 000000000..8908cf456 Binary files /dev/null and b/example/main/src/main/resources/icon-arrow-right.png differ diff --git a/vuu/src/main/resources/logback-netty.xml b/example/main/src/main/resources/logback-netty.xml similarity index 100% rename from vuu/src/main/resources/logback-netty.xml rename to example/main/src/main/resources/logback-netty.xml diff --git a/vuu/src/main/resources/logback-socket.xml b/example/main/src/main/resources/logback-socket.xml similarity index 100% rename from vuu/src/main/resources/logback-socket.xml rename to example/main/src/main/resources/logback-socket.xml diff --git a/vuu/src/main/resources/logback-trace.xml b/example/main/src/main/resources/logback-trace.xml similarity index 100% rename from vuu/src/main/resources/logback-trace.xml rename to example/main/src/main/resources/logback-trace.xml diff --git a/vuu/src/main/resources/logback.xml b/example/main/src/main/resources/logback.xml similarity index 100% rename from vuu/src/main/resources/logback.xml rename to example/main/src/main/resources/logback.xml diff --git a/example/main/src/main/resources/right.png b/example/main/src/main/resources/right.png new file mode 100644 index 000000000..c853585f5 Binary files /dev/null and b/example/main/src/main/resources/right.png differ diff --git a/example/main/src/main/resources/sort-arrow-down.gif b/example/main/src/main/resources/sort-arrow-down.gif new file mode 100644 index 000000000..284a75533 Binary files /dev/null and b/example/main/src/main/resources/sort-arrow-down.gif differ diff --git a/example/main/src/main/resources/sort-arrow-up.gif b/example/main/src/main/resources/sort-arrow-up.gif new file mode 100644 index 000000000..688f4c026 Binary files /dev/null and b/example/main/src/main/resources/sort-arrow-up.gif differ diff --git a/example/main/src/main/resources/static/ftse100.csv b/example/main/src/main/resources/static/ftse100.csv new file mode 100644 index 000000000..aa0315f95 --- /dev/null +++ b/example/main/src/main/resources/static/ftse100.csv @@ -0,0 +1,100 @@ +Symbol,Name,Last Trade,Change,Volume, Weighting +AAL.L,Anglo American PLC,436.35�13:13,�5.35�(1.24%),5799089,0.0278736825813547 +ABF.L,Associated British Foods PLC,"3,435.60�13:12",�7.40�(0.21%),86808,0.000417248060431947 +ADM.L,Admiral Group PLC,"1,627.00�13:13",,86808,0.000417248060431947 +ADN.L,Aberdeen Asset Management PLC,334.00�13:13,�2.50�(0.75%),806880,0.00387831899135251 +AHT.L,Ashtead Group PLC,"1,027.00�13:13",�6.00�(0.59%),331255,0.00159219779580666 +ANTO.L,Antofagasta PLC,484.10�13:13,�11.70�(2.48%),1753976,0.00843059492263598 +ARM.L,ARM Holdings PLC,"1,058.00�13:13",�3.00�(0.28%),475927,0.00228757277736148 +AV.L,Aviva PLC,493.97�13:13,�2.23�(0.45%),2226835,0.0107034211668507 +AZN.L,AstraZeneca PLC,"4,399.50�13:13",�2.50�(0.06%),815133,0.00391798755004232 +BA.L,BAE Systems PLC,478.10�13:13,�4.30�(0.91%),2039934,0.00980506986578636 +BAB.L,Babcock International Group PLC,988.00�13:13,�9.50�(0.97%),209614,0.00100752275066102 +BARC.L,Barclays PLC,226.30�13:13,�1.15�(0.51%),6575664,0.0316063387021032 +BATS.L,British American Tobacco PLC,"3,803.50�13:13",�8.50�(0.22%),465110,0.0022355801929258 +BDEV.L,Barratt Developments PLC,576.00�13:13,�0.50�(0.09%),1044365,0.00501980543997108 +BG.L,BG Group PLC,"1,013.50�13:13",�5.50�(0.55%),1507332,0.00724508516988073 +BKG.L,Berkeley Group Holdings (The) PLC,"3,126.00�13:13",�15.00�(0.48%),95071,0.000456964684744788 +BLND.L,British Land Co PLC,828.06�13:12,�10.44�(1.25%),1802548,0.00866405926683583 +BLT.L,BHP Billiton PLC,881.40�13:13,�4.30�(0.49%),4947287,0.0237794431982097 +BNZL.L,Bunzl PLC,"1,875.40�13:05",�4.60�(0.24%),104541,0.000502482829757812 +BP.L,BP PLC,381.50�13:13,�2.95�(0.78%),10493561,0.0504379547308349 +BRBY.L,Burberry Group PLC,"1,269.00�13:13",�7.00�(0.55%),295647,0.00142104572530785 +BT-A.L,BT Group PLC,489.20�13:13,�3.70�(0.75%),3914982,0.0188176048996174 +CCL.L,Carnival PLC,"3,426.00�13:12",�22.00�(0.64%),86257,0.000414599644602783 +CNA.L,Centrica PLC,212.80�13:13,�0.60�(0.28%),2144540,0.0103078651220939 +CPG.L,Compass Group PLC,"1,054.00�13:08",�5.00�(0.48%),1001167,0.00481217156158961 +CPI.L,Capita PLC,"1,235.00�13:11",�1.00�(0.08%),244591,0.0011756418803464 +CRH.L,CRH PLC,"1,783.20�13:12",�17.80�(0.99%),897325,0.00431304851888186 +DC.L,DIXONS CARPHONE,462.10�13:11,,756906,0.00363811584680332 +DGE.L,Diageo PLC,"1,881.50�13:13",�6.50�(0.34%),756906,0.00363811584680332 +DLG.L,Direct Line Insurance Group PLC,403.80�13:13,�0.40�(0.10%),1095340,0.00526481995338596 +EXPN.L,Experian PLC,"1,191.00�13:12",�2.00�(0.17%),467283,0.00224602485281105 +EZJ.L,easyJet PLC,"1,682.00�13:12",�28.00�(1.64%),1191230,0.00572572121265722 +FRES.L,Fresnillo PLC,678.50�13:12,�6.50�(0.97%),381871,0.00183548675335462 +GFS.L,G4S PLC,232.30�13:03,�2.00�(0.85%),1096551,0.00527064070033535 +GKN.L,GKN PLC,294.80�13:12,�2.50�(0.86%),792247,0.00380798456516713 +GLEN.L,Glencore PLC,90.48�13:13,�1.65�(1.86%),41631528,0.200104533116974 +GSK.L,GlaxoSmithKline PLC,"1,345.00�13:13",�0.50�(0.04%),1767356,0.00849490672625522 +HIK.L,Hikma Pharmaceuticals PLC,"2,010.00�13:04",�57.00�(2.92%),261511,0.00125696891451962 +HL.L,Hargreaves Lansdown PLC,"1,488.03�13:12",�9.97�(0.67%),372261,0.00178929568961912 +HMSO.L,Hammerson PLC,597.50�13:11,�3.50�(0.58%),478301,0.0022989835562697 +HSBA.L,HSBC Holdings PLC,519.70�13:13,�0.50�(0.10%),7415629,0.0356436828072631 +IAG.L,International Consolidated Airlines Group SA,575.40�13:12,�16.10�(2.72%),4311514,0.0207235606629018 +IHG.L,InterContinental Hotels Group PLC,"2,481.00�13:12",�19.00�(0.76%),219918,0.00105704956863507 +III.L,3i Group PLC,487.30�13:11,�4.50�(0.92%),189987,0.000913184352332553 +IMT.L,Imperial Tobacco Group PLC,"3,571.00�13:13",�29.00�(0.81%),926816,0.00445479884777089 +INTU.L,intu properties plc,319.90�13:09,�4.60�(1.42%),514821,0.0024745192115892 +ISAT.L,Inmarsat PLC,"1,054.44�13:13",�3.44�(0.33%),988089,0.00474931133978598 +ITRK.L,Intertek Group PLC,"2,643.00�13:14",�3.00�(0.11%),45868,0.000220467399731505 +ITV.L,ITV PLC,267.30�13:14,�2.60�(0.96%),3453208,0.0165980593985356 +JMAT.L,Johnson Matthey PLC,"2,445.00�13:14",�29.00�(1.20%),276397,0.00132851940096775 +KGF.L,Kingfisher PLC,346.20�13:14,�4.30�(1.23%),1021408,0.00490946118917235 +LAND.L,Land Securities Group PLC,"1,239.00�13:13",�7.00�(0.56%),384973,0.00185039670961971 +LGEN.L,Legal & General Group PLC,266.00�13:14,�1.60�(0.60%),1998399,0.00960542930051541 +LLOY.L,Lloyds Banking Group PLC,73.86�13:14,�0.02�(0.03%),18907878,0.0908818936317375 +LSE.L,London Stock Exchange Group PLC,"2,544.00�13:11",�6.00�(0.24%),129657,0.000623204448569543 +MGGT.L,Meggitt PLC,386.00�13:15,�3.20�(0.84%),611044,0.00293702105610748 +MKS.L,Marks & Spencer Group PLC,514.75�13:12,�3.25�(0.63%),920128,0.00442265255908587 +MNDI.L,Mondi PLC,"1,463.00�13:14",�7.00�(0.48%),383546,0.00184353774521278 +MRW.L,Morrison (Wm) Supermarkets PLC,155.20�13:14,,920128,0.00442265255908587 +NG.L,National Grid PLC,926.40�13:14,�1.10�(0.12%),1659592,0.00797693234619361 +NXT.L,Next PLC,"7,765.00�13:11",�95.00�(1.21%),114062,0.000548246109448308 +OML.L,Old Mutual PLC,198.50�13:14,�0.40�(0.20%),2040849,0.00980946787029396 +PRU.L,Prudential PLC,"1,499.50�13:15",�14.00�(0.93%),580870,0.00279198784516525 +PSON.L,Pearson PLC,794.00�13:09,�5.00�(0.63%),1177953,0.00566190448495522 +RB.L,Reckitt Benckiser Group PLC,"6,293.00�13:14",�34.00�(0.54%),281172,0.0013514707359664 +RBS.L,Royal Bank of Scotland Group PLC,313.40�13:14,�2.40�(0.77%),2100058,0.0100940596177149 +RDSA.L,Royal Dutch Shell PLC,"1,636.00�13:14",�18.00�(1.11%),2467461,0.0118600050276642 +RDSB.L,Royal Dutch Shell PLC,"1,652.00�13:15",�14.50�(0.89%),1457434,0.0070052473240666 +REL.L,Reed Elsevier PLC,"1,170.00�13:14",0.00�(0.00%),908802,0.00436821343443777 +RIO.L,Rio Tinto PLC,"2,235.00�13:15",�21.00�(0.95%),2190722,0.0105298417823887 +RMG.L,Royal Mail PLC,453.50�13:14,�1.20�(0.26%),995316,0.00478404836555252 +RR.L,Rolls-Royce Group PLC,546.63�13:14,�8.38�(1.51%),2792915,0.0134243199555489 +RRS.L,Randgold Resources Ltd,"3,929.00�13:14",0.00�(0.00%),135524,0.000651404549603483 +RSA.L,RSA Insurance Group PLC,437.10�13:14,�0.10�(0.02%),395477,0.00190088484005443 +SAB.L,SABMiller PLC,"4,011.00�13:15",�1.00�(0.02%),892451,0.00428962133421518 +SBRY.L,Sainsbury (J) PLC,255.80�13:14,�7.40�(2.98%),2395670,0.0115149371133421 +SDR.L,Schroders PLC,"2,930.00�13:09",�12.00�(0.41%),44674,0.000214728364341268 +SGE.L,Sage Group (The) PLC,545.50�13:13,�0.50�(0.09%),539717,0.00259418338669419 +SHP.L,Shire PLC,"4,685.00�13:14",�22.00�(0.47%),221318,0.0010637787558598 +SKY.L,SKY,"1,095.00�13:12",�4.00�(0.37%),925016,0.0044461470356248 +SL.L,Standard Life PLC,399.90�13:14,�3.20�(0.79%),861636,0.00414150711683647 +SMIN.L,Smiths Group PLC,992.50�13:14,�27.50�(2.70%),640309,0.00307768510191594 +SN.L,Smith & Nephew PLC,"1,110.00�13:14",�9.00�(0.82%),480018,0.00230723642374461 +SPD.L,Sports Direct International PLC,694.50�13:11,�1.50�(0.22%),157981,0.000759345519250522 +SSE.L,SSE PLC,"1,463.00�13:13",�2.00�(0.14%),562454,0.00270347019378617 +STAN.L,Standard Chartered PLC,583.00�13:14,�0.60�(0.10%),2018697,0.00970299290214945 +STJ.L,St James's Place PLC,964.00�13:14,�11.00�(1.13%),418480,0.00201145019271912 +SVT.L,Severn Trent PLC,"2,199.00�13:12",�1.00�(0.05%),95342,0.000458267263129005 +TPK.L,Travis Perkins PLC,"1,945.00�13:13",�4.00�(0.21%),92916,0.000446606542981001 +TSCO.L,Tesco PLC,171.54�13:14,�2.54�(1.50%),9831136,0.0472539676970174 +TUI.L,TUI AG,"1,115.00�13:10",�5.00�(0.45%),458970,0.00220606790038304 +TW.L,Taylor Wimpey PLC,183.90�13:15,�1.10�(0.59%),3180729,0.0152883721086725 +ULVR.L,Unilever PLC,"2,791.00�13:14",�29.00�(1.03%),824827,0.0039645823650113 +UU.L,United Utilities Group PLC,959.00�13:10,�2.50�(0.26%),436911,0.00210003994253274 +VOD.L,Vodafone Group PLC,224.25�13:15,�1.30�(0.58%),17572036,0.0844610858312637 +WOS.L,Wolseley PLC,"3,657.00�13:14",�4.00�(0.11%),179536,0.000862950969699912 +WPP.L,WPP PLC,"1,502.00�13:15",�12.00�(0.79%),857887,0.0041234873147611 +WTB.L,Whitbread PLC,"4,484.00�13:16",�60.00�(1.32%),141036,0.000677898321019722 +,,,,208048900, diff --git a/example/main/src/main/resources/static/hsi.csv b/example/main/src/main/resources/static/hsi.csv new file mode 100644 index 000000000..fcd24d46c --- /dev/null +++ b/example/main/src/main/resources/static/hsi.csv @@ -0,0 +1,81 @@ +Name,Symbol,Last,Change,Change %,Volume,Turn.,P/E,P/B,Yield,Market Cap,Weighting +CKH HOLDINGS,00001.HK,41.9,1.15,+2.822%,5.15M,215.13M,4.38,0.31,6.98%,160.48B,0.0278736825813547 +CLP HOLDINGS,00002.HK,57.95,-0.1,-0.172%,3.32M,193.19M,156.62,1.39,5.35%,146.41B,0.000417248060431947 +HK & CHINA GAS,00003.HK,5.46,0.13,+2.439%,16.16M,88.00M,19.43,1.66,6.41%,101.88B,0.000417248060431947 +HSBC HOLDINGS,00005.HK,61.7,1.1,+1.815%,22.19M,1.37B,10.54,0.86,4.05%,1,0.00387831899135251 +POWER ASSETS,00006.HK,37.9,-0.25,-0.655%,4.23M,160.75M,14.3,0.93,7.44%,80.77B,0.00159219779580666 +HANG SENG BANK,00011.HK,97.45,2.95,+3.122%,2.54M,247.44M,19.69,1.01,4.21%,186.31B,0.00843059492263598 +HENDERSON LAND,00012.HK,20.65,0.85,+4.293%,5.07M,103.70M,10.81,0.31,8.72%,99.97B,0.00228757277736148 +SHK PPT,00016.HK,83.8,3.25,+4.035%,8.25M,685.41M,10.16,0.4,5.91%,242.83B,0.0107034211668507 +NEW WORLD DEV,00017.HK,15.24,0.8,+5.540%,12.95M,196.19M,30.48,0.18,13.52%,38.35B,0.00391798755004232 +GALAXY ENT,00027.HK,47.15,1.9,+4.199%,11.97M,560.21M,No Profit,3.22,0.00%,206.21B,0.00980506986578636 +MTR CORPORATION,00066.HK,31,0.8,+2.649%,4.68M,144.86M,19.5,1.07,4.23%,192.64B,0.00100752275066102 +HANG LUNG PPT,00101.HK,10.72,0.56,+5.512%,7.68M,81.99M,12.61,0.36,7.28%,48.23B,0.0316063387021032 +GEELY AUTO,00175.HK,9.24,0.17,+1.874%,18.77M,173.30M,16.06,1.15,2.27%,92.99B,0.0022355801929258 +ALI HEALTH,00241.HK,4.88,0.47,+10.658%,53.62M,257.82M,108.09,3.81,0.00%,66.04B,0.00501980543997108 +CITIC,00267.HK,7.2,0.2,+2.857%,11.54M,82.96M,2.78,0.28,9.04%,209.45B,0.00724508516988073 +WH GROUP,00288.HK,4.11,0.08,+1.985%,18.94M,77.65M,4.93,0.7,7.30%,52.73B,0.000456964684744788 +CHINA RES BEER,00291.HK,42.95,1.2,+2.874%,4.83M,207.98M,28.41,4.57,1.41%,139.34B,0.00866405926683583 +OOIL,00316.HK,104.5,-0.4,-0.381%,296.54K,30.98M,0.89,0.66,78.90%,69.01B,0.0237794431982097 +TINGYI,00322.HK,10.94,0.18,+1.673%,2.91M,31.81M,20.75,4.09,9.39%,61.64B,0.000502482829757812 +SINOPEC CORP,00386.HK,4.28,-0.01,-0.233%,92.43M,396.61M,6.94,0.58,9.36%,105.92B,0.0504379547308349 +HKEX,00388.HK,292.6,9,+3.173%,4.61M,1.34B,36.76,7.46,2.44%,370.97B,0.00142104572530785 +TECHTRONIC IND,00669.HK,76,1.35,+1.808%,5.47M,414.78M,16.54,3.43,2.43%,139.45B,0.0188176048996174 +CHINA OVERSEAS,00688.HK,16.24,0.52,+3.308%,13.15M,212.60M,6.76,0.44,4.93%,177.74B,0.000414599644602783 +TENCENT,00700.HK,306.2,8.8,+2.959%,11.25M,3.43B,13.74,3.6,0.78%,2,0.0103078651220939 +CHINA UNICOM,00762.HK,5.68,-0.05,-0.873%,9.23M,52.77M,9.16,0.45,5.44%,173.80B,0.00481217156158961 +LINK REIT,00823.HK,38.4,1.45,+3.924%,12.04M,460.96M,5.42,0.52,7.03%,98.38B,0.0011756418803464 +CHINA RES POWER,00836.HK,14.94,0.32,+2.189%,9.91M,147.81M,10.23,0.87,3.92%,71.87B,0.00431304851888186 +PETROCHINA,00857.HK,5.9,0,0.000%,64.23M,380.44M,6.38,0.7,8.08%,124.48B,0.00363811584680332 +XINYI GLASS,00868.HK,10.14,0.17,+1.705%,3.75M,38.02M,8.01,1.3,6.11%,42.22B,0.00363811584680332 +ZHONGSHENG HLDG,00881.HK,22.05,1.45,+7.039%,6.76M,147.71M,7.08,1.07,4.94%,52.72B,0.00526481995338596 +CNOOC,00883.HK,13.78,-0.02,-0.145%,26.37M,365.08M,4.03,0.97,19.09%,655.47B,0.00224602485281105 +CCB,00939.HK,4.42,0.06,+1.376%,233.61M,1.03B,3.06,0.35,9.93%,1,0.00572572121265722 +CHINA MOBILE,00941.HK,65.7,0.25,+0.382%,7.82M,516.10M,9.91,0.96,6.71%,1,0.00183548675335462 +LONGFOR GROUP,00960.HK,14.08,0.9,+6.829%,10.88M,150.68M,3.06,0.55,9.05%,92.81B,0.00527064070033535 +XINYI SOLAR,00968.HK,5.86,0.28,+5.018%,15.99M,92.88M,13.64,1.75,3.41%,52.17B,0.00380798456516713 +SMIC,00981.HK,20.05,0.25,+1.263%,13.10M,264.32M,11.17,1.06,0.00%,159.31B,0.200104533116974 +LENOVO GROUP,00992.HK,8.07,0.25,+3.197%,33.60M,270.50M,7.61,2.23,4.71%,97.87B,0.00849490672625522 +CKI HOLDINGS,01038.HK,37.05,-0.2,-0.537%,1.44M,53.73M,12.03,0.78,6.83%,93.35B,0.00125696891451962 +HENGAN INT'L,01044.HK,24.95,0.2,+0.808%,2.62M,64.97M,13.35,1.32,6.33%,28.99B,0.00178929568961912 +CHINA SHENHUA,01088.HK,25.4,0.35,+1.397%,7.98M,203.11M,6.14,1.13,11.33%,85.79B,0.0022989835562697 +CSPC PHARMA,01093.HK,5.74,0.05,+0.879%,29.29M,167.41M,9.96,2.01,3.66%,68.32B,0.0356436828072631 +SINOPHARM,01099.HK,22.7,0.2,+0.889%,2.07M,46.80M,7.37,0.92,4.08%,30.46B,0.0207235606629018 +CHINA RES LAND,01109.HK,31.2,1,+3.311%,9.88M,305.88M,7.02,0.81,5.07%,222.49B,0.00105704956863507 +CK ASSET,01113.HK,41.25,1.25,+3.125%,8.57M,352.44M,6.9,0.39,5.53%,146.47B,0.000913184352332553 +SINO BIOPHARM,01177.HK,2.83,0.02,+0.712%,26.30M,74.09M,18.37,1.59,4.24%,53.21B,0.00445479884777089 +CHINA RES MIXC,01209.HK,31.6,1.6,+5.333%,3.07M,96.42M,28.97,4.48,2.87%,72.13B,0.0024745192115892 +BYD COMPANY,01211.HK,242,7,+2.979%,3.90M,938.50M,37.57,5.63,0.53%,265.72B,0.00474931133978598 +AIA,01299.HK,63.85,0.95,+1.510%,38.75M,2.48B,408.88,2.53,2.41%,735.40B,0.000220467399731505 +CHINAHONGQIAO,01378.HK,7.67,0.28,+3.789%,13.05M,99.58M,7.27,0.76,6.65%,72.68B,0.0165980593985356 +ICBC,01398.HK,3.77,0.07,+1.892%,233.48M,881.67M,3.45,0.36,9.08%,327.21B,0.00132851940096775 +XIAOMI-W,01810.HK,12.34,0.62,+5.290%,78.53M,960.98M,109.39,1.9,0.00%,308.83B,0.00490946118917235 +BUD APAC,01876.HK,15.46,0.16,+1.046%,16.17M,250.45M,28.65,2.44,1.91%,204.74B,0.00185039670961971 +SANDS CHINA LTD,01928.HK,24,0.95,+4.121%,19.98M,475.93M,No Profit,N/A,0.00%,194.24B,0.00960542930051541 +CHOW TAI FOOK,01929.HK,11.8,0.28,+2.431%,4.88M,57.68M,21.93,3.64,10.34%,118.00B,0.0908818936317375 +WHARF REIC,01997.HK,30.25,1.4,+4.853%,4.23M,127.31M,No Profit,0.48,4.33%,91.85B,0.000623204448569543 +ANTA SPORTS,02020.HK,88.15,4.4,+5.254%,4.82M,422.51M,27.71,6.16,1.52%,249.70B,0.00293702105610748 +WUXI BIO,02269.HK,45.65,1.55,+3.515%,17.91M,811.49M,38.18,4.88,0.00%,194.01B,0.00442265255908587 +SHENZHOU INTL,02313.HK,75,4.6,+6.534%,5.52M,410.68M,21.87,3.25,2.55%,112.74B,0.00184353774521278 +PING AN,02318.HK,44.85,0.85,+1.932%,23.05M,1.03B,8.28,0.85,6.09%,334.02B,0.00442265255908587 +MENGNIU DAIRY,02319.HK,26.25,1.5,+6.061%,8.58M,223.15M,17.34,2.3,1.73%,103.42B,0.00797693234619361 +LI NING,02331.HK,32.95,1.5,+4.769%,22.54M,738.37M,18.8,3.16,1.58%,86.86B,0.000548246109448308 +SUNNY OPTICAL,02382.HK,54.7,1.05,+1.957%,5.62M,308.60M,22.01,2.44,0.91%,60.00B,0.00980946787029396 +BOC HONG KONG,02388.HK,21.45,0.3,+1.418%,6.53M,140.32M,8.38,0.75,6.33%,226.79B,0.00279198784516525 +CHINA LIFE,02628.HK,12.2,0.24,+2.007%,13.53M,165.07M,9.49,0.7,4.53%,90.78B,0.00566190448495522 +ENN ENERGY,02688.HK,65,1.15,+1.801%,3.06M,198.69M,11.08,1.67,4.48%,73.53B,0.0013514707359664 +ZIJIN MINING,02899.HK,11.98,0.16,+1.354%,16.20M,194.50M,13.97,3.14,1.88%,68.73B,0.0100940596177149 +MEITUAN-W,03690.HK,114.6,3.8,+3.430%,19.17M,2.19B,No Profit,4.89,0.00%,715.43B,0.0118600050276642 +HANSOH PHARMA,03692.HK,10.66,0.16,+1.524%,17.56M,187.72M,21.48,2.47,0.94%,63.25B,0.0070052473240666 +CM BANK,03968.HK,32.7,0.1,+0.307%,11.13M,363.99M,5.51,0.86,6.00%,150.12B,0.00436821343443777 +BANK OF CHINA,03988.HK,2.74,0.05,+1.859%,275.47M,754.54M,3.33,0.33,9.55%,229.13B,0.0105298417823887 +CG SERVICES,06098.HK,8.08,0.25,+3.193%,16.08M,128.87M,12.42,0.65,5.20%,27.01B,0.00478404836555252 +JD HEALTH,06618.HK,40.6,2.95,+7.835%,7.75M,312.36M,299.91,2.56,0.00%,129.12B,0.0134243199555489 +HAIER SMARTHOME,06690.HK,24.65,1.15,+4.894%,7.24M,178.37M,13.83,2.21,2.59%,70.46B,0.000651404549603483 +HAIDILAO,06862.HK,21,0.6,+2.941%,6.86M,143.79M,74.46,13.94,0.55%,117.05B,0.00190088484005443 +JD-SW,09618.HK,115.1,4,+3.600%,7.43M,852.28M,30.73,1.5,6.38%,360.24B,0.00428962133421518 +NONGFU SPRING,09633.HK,45,1.5,+3.448%,3.69M,165.62M,52.49,18.63,1.71%,226.56B,0.0115149371133421 +BIDU-SW,09888.HK,133.4,4.6,+3.571%,5.82M,772.73M,47.3,1.5,0.00%,377.37B,0.000214728364341268 +TRIP.COM-S,09961.HK,279.2,7,+2.572%,1.25M,349.59M,114.05,1.4,0.00%,176.65B,0.00259418338669419 +BABA-SW,09988.HK,85.6,2.6,+3.133%,34.61M,2.96B,21.65,1.62,0.00%,1,0.0010637787558598 +NTES-S,09999.HK,159.5,8.3,+5.489%,5.02M,797.10M,22.7,4.63,1.36%,546.99B,0.0044461470356248 diff --git a/example/main/src/main/resources/static/nasdaq100.csv b/example/main/src/main/resources/static/nasdaq100.csv new file mode 100644 index 000000000..6447cbb7a --- /dev/null +++ b/example/main/src/main/resources/static/nasdaq100.csv @@ -0,0 +1,102 @@ +#,Name,Symbol,Weighting,Last Trade,Chg,% Chg +1,Apple Inc,AAPL,11.007,174.94,0.15,(0.09%) +2,Microsoft Corp,MSFT,9.61,316.98,-0.03,(-0.01%) +3,Amazon.com Inc,AMZN,5.401,129.31,0.19,(0.14%) +4,NVIDIA Corp,NVDA,4.101,415.74,-0.36,(-0.09%) +5,Meta Platforms Inc,META,3.729,299.42,0.34,(0.11%) +6,Tesla Inc,TSLA,3.285,244.13,-0.75,(-0.31%) +7,Alphabet Inc,GOOGL,3.133,130.49,0.24,(0.18%) +8,Alphabet Inc,GOOG,3.085,131.49,0.24,(0.18%) +9,Broadcom Inc,AVGO,2.896,833.04,3.96,(0.48%) +10,Costco Wholesale Corp,COST,2.137,557.85,-0.74,(-0.13%) +11,PepsiCo Inc,PEP,2.096,174.84,-0.43,(-0.25%) +12,Adobe Inc,ADBE,2.033,511.42,-1.48,(-0.29%) +13,Cisco Systems Inc,CSCO,1.887,53.68,0.11,(0.20%) +14,Comcast Corp,CMCSA,1.633,45.30,-0.01,(-0.01%) +15,Netflix Inc,NFLX,1.478,379.89,0.08,(0.02%) +16,T-Mobile US Inc,TMUS,1.43,140.18,0.83,(0.60%) +17,Advanced Micro Devices Inc,AMD,1.348,96.09,-0.11,(-0.12%) +18,Texas Instruments Inc,TXN,1.264,161.00,0.69,(0.43%) +19,Intel Corp,INTC,1.26,34.19,0.01,(0.01%) +20,Amgen Inc,AMGN,1.251,271.18,3.48,(1.30%) +21,Intuit Inc,INTU,1.226,509.00,0.43,(0.08%) +22,Honeywell International Inc,HON,1.103,188.67,-1.12,(-0.59%) +23,QUALCOMM Inc,QCOM,1.046,107.53,-0.16,(-0.14%) +24,Applied Materials Inc,AMAT,0.982,136.32,0.15,(0.11%) +25,Booking Holdings Inc,BKNG,0.941,3,019.20,-43.30,(-1.42%) +26,Starbucks Corp,SBUX,0.926,93.80,0.12,(0.12%) +27,Intuitive Surgical Inc,ISRG,0.867,288.50,0.30,(0.10%) +28,Automatic Data Processing Inc,ADP,0.854,239.45,0.10,(0.04%) +29,Mondelez International Inc,MDLZ,0.835,71.25,0.82,(1.16%) +30,Gilead Sciences Inc,GILD,0.814,75.47,0.46,(0.61%) +31,Vertex Pharmaceuticals Inc,VRTX,0.794,353.67,4.14,(1.18%) +32,Regeneron Pharmaceuticals Inc,REGN,0.763,828.09,3.25,(0.39%) +33,Analog Devices Inc,ADI,0.752,176.82,1.34,(0.76%) +34,Lam Research Corp,LRCX,0.702,620.00,0.89,(0.14%) +35,Micron Technology Inc,MU,0.646,68.90,0.02,(0.03%) +36,Palo Alto Networks Inc,PANW,0.604,228.70,0.19,(0.08%) +37,Synopsys Inc,SNPS,0.587,447.12,0.27,(0.06%) +38,Charter Communications Inc,CHTR,0.581,441.88,-3.33,(-0.75%) +39,MercadoLibre Inc,MELI,0.562,1,275.50,-1.47,(-0.11%) +40,PayPal Holdings Inc,PYPL,0.559,57.90,0.02,(0.03%) +41,CSX Corp,CSX,0.54,31.23,0.03,(0.09%) +42,Cadence Design Systems Inc,CDNS,0.539,230.83,0.17,(0.07%) +43,KLA Corp,KLAC,0.53,456.11,4.29,(0.95%) +44,PDD Holdings Inc ADR,PDD,0.521,95.93,-0.01,(-0.01%) +45,Marriott International Inc/MD,MAR,0.505,193.90,-0.46,(-0.23%) +46,Monster Beverage Corp,MNST,0.498,54.48,-0.04,(-0.08%) +47,Airbnb Inc,ABNB,0.491,132.09,-0.11,(-0.08%) +48,O'Reilly Automotive Inc,ORLY,0.485,936.67,0.65,(0.07%) +49,Cintas Corp,CTAS,0.446,505.27,0.52,(0.10%) +50,ASML Holding NV,ASML,0.438,585.00,-2.10,(-0.36%) +51,NXP Semiconductors NV,NXPI,0.434,196.76,-0.04,(-0.02%) +52,Workday Inc,WDAY,0.414,235.55,4.73,(2.05%) +53,Lululemon Athletica Inc,LULU,0.405,386.36,-1.69,(-0.44%) +54,Keurig Dr Pepper Inc,KDP,0.404,33.25,0.13,(0.39%) +55,Fortinet Inc,FTNT,0.401,58.29,0.05,(0.09%) +56,Marvell Technology Inc,MRVL,0.388,52.38,0.08,(0.14%) +57,PACCAR Inc,PCAR,0.38,84.97,0.04,(0.04%) +58,Old Dominion Freight Line Inc,ODFL,0.38,401.01,0.35,(0.09%) +59,Autodesk Inc,ADSK,0.379,204.07,0.03,(0.01%) +60,Kraft Heinz Co/The,KHC,0.368,34.27,0.11,(0.31%) +61,Microchip Technology Inc,MCHP,0.36,77.00,-0.08,(-0.10%) +62,Copart Inc,CPRT,0.358,43.26,0.10,(0.22%) +63,American Electric Power Co Inc,AEP,0.357,79.23,0.06,(0.08%) +64,Paychex Inc,PAYX,0.355,113.01,0.06,(0.06%) +65,Exelon Corp,EXC,0.35,40.28,0.07,(0.16%) +66,ON Semiconductor Corp,ON,0.341,93.87,0.06,(0.06%) +67,AstraZeneca PLC ADR,AZN,0.339,67.35,-0.49,(-0.72%) +68,Seagen Inc,SGEN,0.336,212.18,-1.52,(-0.71%) +69,Ross Stores Inc,ROST,0.335,111.71,0.05,(0.04%) +70,Moderna Inc,MRNA,0.331,100.32,0.33,(0.33%) +71,Biogen Inc,BIIB,0.326,257.93,0.25,(0.10%) +72,Crowdstrike Holdings Inc,CRWD,0.319,162.85,0.28,(0.17%) +73,IDEXX Laboratories Inc,IDXX,0.316,439.41,3.72,(0.85%) +74,Baker Hughes Co,BKR,0.307,35.44,0.04,(0.10%) +75,Constellation Energy Corp,CEG,0.307,110.41,0.05,(0.04%) +76,Cognizant Technology Solutions Corp,CTSH,0.303,70.19,0.58,(0.83%) +77,Verisk Analytics Inc,VRSK,0.303,242.05,0.10,(0.04%) +78,Dexcom Inc,DXCM,0.3,88.30,0.80,(0.92%) +79,Trade Desk Inc/The,TTD,0.293,76.38,0.03,(0.03%) +80,Xcel Energy Inc,XEL,0.284,59.76,0.03,(0.04%) +81,Electronic Arts Inc,EA,0.279,118.38,-0.63,(-0.53%) +82,CoStar Group Inc,CSGP,0.277,78.18,0.12,(0.15%) +83,GLOBALFOUNDRIES Inc,GFS,0.273,57.21,0.38,(0.67%) +84,Fastenal Co,FAST,0.268,54.32,0.11,(0.20%) +85,Atlassian Corp,TEAM,0.253,196.01,0.55,(0.28%) +86,GE HealthCare Technologies Inc,GEHC,0.252,63.78,-0.56,(-0.86%) +87,Warner Bros Discovery Inc,WBD,0.244,11.09,-0.02,(-0.14%) +88,Diamondback Energy Inc,FANG,0.235,150.70,0.13,(0.09%) +89,Datadog Inc,DDOG,0.23,88.81,0.05,(0.06%) +90,ANSYS Inc,ANSS,0.227,300.60,-2.31,(-0.76%) +91,eBay Inc,EBAY,0.203,43.22,0.09,(0.20%) +92,Dollar Tree Inc,DLTR,0.201,104.77,0.27,(0.25%) +93,Align Technology Inc,ALGN,0.2,297.25,-1.31,(-0.44%) +94,Zscaler Inc,ZS,0.188,151.80,0.09,(0.06%) +95,Illumina Inc,ILMN,0.183,132.31,-0.13,(-0.10%) +96,Walgreens Boots Alliance Inc,WBA,0.161,21.18,0.06,(0.28%) +97,Zoom Video Communications Inc,ZM,0.151,68.57,-0.29,(-0.41%) +98,Enphase Energy Inc,ENPH,0.148,120.41,0.49,(0.41%) +99,Sirius XM Holdings Inc,SIRI,0.137,4.05,0.02,(0.50%) +100,JD.com Inc ADR,JD,0.117,30.43,0.02,(0.05%) +101,Lucid Group Inc,LCID,0.102,5.14,0.03,(0.49%) \ No newline at end of file diff --git a/example/main/src/main/resources/static/sp500.csv b/example/main/src/main/resources/static/sp500.csv new file mode 100644 index 000000000..19701b2cc --- /dev/null +++ b/example/main/src/main/resources/static/sp500.csv @@ -0,0 +1,504 @@ +#,Name,Symbol,Weighting,Price,Change,Change %, +1,Apple Inc,AAPL,6.992488,171.9,1.47,(0.86%), +2,Microsoft Corp,MSFT,6.487978,314.55,1.76,(0.56%), +3,Amazon.com Inc,AMZN,3.193379,126.25,0.27,(0.22%), +4,Nvidia Corp,NVDA,2.928461,433.11,8.43,(1.99%), +5,Alphabet Inc Cl A,GOOGL,2.162218,132.93,2.39,(1.83%), +6,Tesla Inc,TSLA,1.854311,246.56,6.06,(2.52%), +7,Alphabet Inc Cl C,GOOG,1.85251,133.81,2.35,(1.78%), +8,Meta Platforms Inc Class A,META,1.847731,305.93,8.19,(2.75%), +9,Berkshire Hathaway Inc Cl B,BRK.B,1.82184,358.67,0.89,(0.25%), +10,Exxon Mobil Corp,XOM,1.343563,118.97,-1.23,(-1.03%), +11,Unitedhealth Group Inc,UNH,1.302884,510.04,6.31,(1.25%), +12,Eli Lilly & Co,LLY,1.224046,546.65,-3.11,(-0.57%), +13,Jpmorgan Chase & Co,JPM,1.182918,148.23,2.45,(1.68%), +14,Johnson & Johnson W/d,JNJ,1.056344,156.83,-0.28,(-0.18%), +15,Visa Inc Class a Shares,V,1.029636,231.97,2.47,(1.08%), +16,Procter & Gamble Co,PG,0.969793,145.75,-1.59,(-1.08%), +17,Broadcom Inc,AVGO,0.941177,835.33,18.52,(2.27%), +18,Mastercard Inc A,MA,0.918779,400.65,5.17,(1.31%), +19,Chevron Corp,CVX,0.847353,170.55,-0.49,(-0.28%), +20,Home Depot Inc,HD,0.847289,304.35,2.53,(0.84%), +22,Abbvie Inc,ABBV,0.754672,152.14,-0.99,(-0.65%), +23,Merck & Co. Inc.,MRK,0.736434,104.2,0.26,(0.25%), +24,Costco Wholesale Corp,COST,0.697258,569.05,5.52,(0.98%), +25,Pepsico Inc,PEP,0.651768,168.92,-0.65,(-0.38%), +26,Walmart Inc,WMT,0.644449,161.87,0.15,(0.09%), +27,Adobe Inc,ADBE,0.639652,507.17,4.57,(0.91%), +28,Coca Cola Co,KO,0.60801,55.82,-0.13,(-0.23%), +29,Cisco Systems Inc,CSCO,0.605326,53.97,0.77,(1.44%), +30,Accenture Plc Cl A,ACN,0.55372,298.5,-15.9,(-5.05%), +31,Salesforce Inc,CRM,0.551342,204.46,1.73,(0.85%), +32,Thermo Fisher Scientific Inc,TMO,0.536951,503.47,5.18,(1.04%), +33,Mcdonald S Corp,MCD,0.536457,265.83,2.19,(0.83%), +34,Bank of America Corp,BAC,0.526405,27.51,0.24,(0.86%), +35,Comcast Corp Class A,CMCSA,0.512537,45.17,0.57,(1.27%), +36,Linde Plc,LIN,0.506835,375.48,3.47,(0.93%), +37,Pfizer Inc,PFE,0.506043,32.09,-0.02,(-0.05%), +38,Netflix Inc,NFLX,0.467192,377.77,0.18,(0.05%), +39,Abbott Laboratories,ABT,0.462893,97.52,1.99,(2.08%), +40,Oracle Corp,ORCL,0.459877,106.29,1.67,(1.60%), +41,Danaher Corp,DHR,0.454026,248.24,0.8,(0.32%), +42,Advanced Micro Devices,AMD,0.442473,103.74,5.67,(5.78%), +43,Wells Fargo & Co,WFC,0.417428,41.04,0.18,(0.43%), +44,Conocophillips,COP,0.411569,123.32,0.23,(0.18%), +45,Walt Disney Co,DIS,0.408438,80.35,0.45,(0.56%), +46,Intel Corp,INTC,0.404462,35.5,0.89,(2.56%), +47,Amgen Inc,AMGN,0.401904,270.91,1.93,(0.72%), +48,Texas Instruments Inc,TXN,0.400931,160.98,2.84,(1.80%), +49,Intuit Inc,INTU,0.397406,515.11,6.87,(1.35%), +50,Philip Morris International,PM,0.39143,92.66,2.34,(2.59%), +51,Caterpillar Inc,CAT,0.388444,276.34,3.63,(1.33%), +52,Verizon Communications Inc,VZ,0.380327,32.56,0.16,(0.48%), +53,Intl Business Machines Corp,IBM,0.364246,140.89,-2.28,(-1.59%), +54,Honeywell International Inc,HON,0.348317,188.68,0.8,(0.43%), +55,Union Pacific Corp,UNP,0.344419,203.88,1.48,(0.73%), +56,Qualcomm Inc,QCOM,0.340195,111.55,2.36,(2.16%), +57,Nextera Energy Inc,NEE,0.338809,57.64,-2.32,(-3.88%), +58,Lowe S Cos Inc,LOW,0.338613,209.52,2.56,(1.24%), +59,Bristol Myers Squibb Co,BMY,0.337683,58.3,0.41,(0.70%), +60,General Electric Co,GE,0.336989,112.43,1.54,(1.39%), +61,S&p Global Inc,SPGI,0.32985,369.21,6.15,(1.69%), +62,Applied Materials Inc,AMAT,0.316678,139.15,4.09,(3.03%), +63,Servicenow Inc,NOW,0.3112,552.84,6.46,(1.18%), +64,Boeing Co,BA,0.309673,193.12,-2.34,(-1.20%), +65,United Parcel Service Cl B,UPS,0.307795,154.29,1.88,(1.23%), +66,Booking Holdings Inc,BKNG,0.307126,3,86.26,3.6,(0.12%) +67,Nike Inc Cl B,NKE,0.305871,89.63,0.21,(0.24%), +68,At&t Inc,T,0.296603,14.94,0.07,(0.44%), +69,Goldman Sachs Group Inc,GS,0.296356,325.72,3.77,(1.17%), +70,Rtx Corp,RTX,0.296189,72.54,-0.34,(-0.46%), +71,Elevance Health Inc,ELV,0.292632,448.99,4.23,(0.95%), +72,Deere & Co,DE,0.291602,388.36,4,(1.04%), +73,Starbucks Corp,SBUX,0.291579,91.21,0.04,(0.04%), +74,Morgan Stanley,MS,0.29087,82.34,0.69,(0.84%), +75,Medtronic Plc,MDT,0.290688,78.77,0.55,(0.71%), +76,Prologis Inc,PLD,0.286912,112.3,1.05,(0.94%), +77,Intuitive Surgical Inc,ISRG,0.285764,296.31,4.88,(1.67%), +78,Tjx Companies Inc,TJX,0.282733,89.27,1.16,(1.32%), +79,Automatic Data Processing,ADP,0.279113,243.79,1.16,(0.48%), +80,Marsh & Mclennan Cos,MMC,0.266169,193.53,0.55,(0.29%), +81,Mondelez International Inc A,MDLZ,0.26425,69.44,-0.56,(-0.79%), +82,Gilead Sciences Inc,GILD,0.26285,75.96,0.41,(0.54%), +83,Lockheed Martin Corp,LMT,0.255775,410.4,1.68,(0.41%), +84,Blackrock Inc,BLK,0.252096,645.37,1.98,(0.31%), +85,Vertex Pharmaceuticals Inc,VRTX,0.251521,353.91,4.26,(1.22%), +86,Stryker Corp,SYK,0.250789,273.07,6.53,(2.45%), +87,Cvs Health Corp,CVS,0.250255,70.11,0.33,(0.47%), +88,Regeneron Pharmaceuticals,REGN,0.2481,835.67,3.11,(0.37%), +89,American Express Co,AXP,0.243515,150.42,0.52,(0.34%), +90,Chubb Ltd,CB,0.242706,212.92,1.29,(0.61%), +91,Analog Devices Inc,ADI,0.241943,177.01,4.2,(2.43%), +92,Schlumberger Ltd,SLB,0.241232,61.02,0.22,(0.36%), +93,Eaton Corp Plc,ETN,0.238556,216.42,2.06,(0.96%), +94,The Cigna Group,CI,0.238517,291.43,2.82,(0.98%), +95,Progressive Corp,PGR,0.229854,140.76,0.14,(0.10%), +96,Lam Research Corp,LRCX,0.228483,627.46,13.54,(2.20%), +97,Schwab (Charles) Corp,SCHW,0.225784,54.57,0.19,(0.35%), +98,Zoetis Inc,ZTS,0.224522,174.68,0,(-0.00%), +99,Citigroup Inc,C,0.217552,41.24,0.78,(1.92%), +100,Boston Scientific Corp,BSX,0.213003,53.3,1.2,(2.31%), +101,Blackstone Inc,BX,0.211158,108.88,2.33,(2.19%), +102,Eog Resources Inc,EOG,0.21104,130.56,0.75,(0.57%), +103,Becton Dickinson and Co,BDX,0.209627,262.6,3.8,(1.47%), +104,Micron Technology Inc,MU,0.208276,66.25,-1.96,(-2.87%), +105,American Tower Corp,AMT,0.207727,160.73,1.04,(0.65%), +106,Altria Group Inc,MO,0.207666,42.11,0.2,(0.47%), +107,T Mobile Us Inc,TMUS,0.20192,140.3,0.6,(0.43%), +108,Cme Group Inc,CME,0.201368,200.22,-0.14,(-0.07%), +109,Southern Co,SO,0.20116,65.04,-1.1,(-1.67%), +110,Palo Alto Networks Inc,PANW,0.198047,236.42,4.52,(1.95%), +111,Duke Energy Corp,DUK,0.193827,88.87,-1.23,(-1.36%), +112,Fiserv Inc,FI,0.192662,113.67,0.48,(0.42%), +113,Synopsys Inc,SNPS,0.189768,458.88,12.17,(2.72%), +114,Activision Blizzard Inc,ATVI,0.18717,93.71,-0.22,(-0.23%), +115,Aon Plc Class A,AON,0.186896,330.04,0.12,(0.04%), +116,Equinix Inc,EQIX,0.184757,715.84,8.74,(1.24%), +117,Illinois Tool Works,ITW,0.177501,233.17,0.77,(0.33%), +118,Air Products & Chemicals Inc,APD,0.17678,289.15,3.89,(1.36%), +119,Paypal Holdings Inc,PYPL,0.175802,58.3,0.96,(1.67%), +120,Cadence Design Sys Inc,CDNS,0.175052,235.09,4.44,(1.93%), +121,Northrop Grumman Corp,NOC,0.173654,441.3,4.06,(0.93%), +122,Intercontinental Exchange In,ICE,0.172998,109.93,1.66,(1.53%), +123,Humana Inc,HUM,0.170476,495.73,2.16,(0.44%), +124,Marathon Petroleum Corp,MPC,0.170186,155.28,2.85,(1.87%), +125,Kla Corp,KLAC,0.170079,459.61,14.05,(3.15%), +126,Fedex Corp,FDX,0.169747,266.99,4.28,(1.63%), +127,Csx Corp,CSX,0.169632,30.62,0.34,(1.14%), +128,Mckesson Corp,MCK,0.167376,445.58,1.2,(0.27%), +129,Sherwin Williams Co,SHW,0.165389,254.95,4.33,(1.73%), +130,Colgate Palmolive Co,CL,0.164,71.11,0.06,(0.08%), +131,Airbnb Inc Class A,ABNB,0.159553,137.66,3.63,(2.70%), +132,Waste Management Inc,WM,0.15893,154.17,-0.25,(-0.16%), +133,Emerson Electric Co,EMR,0.154857,97.31,0.45,(0.47%), +134,O Reilly Automotive Inc,ORLY,0.154194,918.15,3.98,(0.44%), +135,Pioneer Natural Resources Co,PXD,0.1524,234.43,0.34,(0.14%), +136,Phillips 66,PSX,0.150197,122.81,2.01,(1.66%), +137,Freeport Mcmoran Inc,FCX,0.146185,37.34,0.79,(2.17%), +138,3m Co W/d,MMM,0.144312,93.48,0.02,(0.02%), +139,Roper Technologies Inc,ROP,0.144165,486.61,-0.02,(-0.00%), +140,Valero Energy Corp,VLO,0.141937,147.59,3.64,(2.53%), +141,Nxp Semiconductors Nv,NXPI,0.141583,202.19,5.49,(2.79%), +142,Target Corp,TGT,0.141106,109.31,-0.44,(-0.40%), +143,Parker Hannifin Corp,PH,0.140358,396.29,5.18,(1.32%), +144,Us Bancorp,USB,0.139291,32.59,0.07,(0.20%), +145,General Dynamics Corp,GD,0.139193,223.44,2.44,(1.10%), +146,Chipotle Mexican Grill Inc,CMG,0.139055,1,828.59,22.51,(1.25%) +147,Hca Healthcare Inc,HCA,0.138966,251.59,4.33,(1.75%), +148,Arthur J Gallagher & Co,AJG,0.138231,231.77,1.44,(0.62%), +149,Moody S Corp,MCO,0.138162,319.07,4.56,(1.45%), +150,Amphenol Corp Cl A,APH,0.136941,84.4,2.04,(2.47%), +151,Ford Motor Co,F,0.1362,12.58,0.19,(1.49%), +152,Marriott International Cl A,MAR,0.135619,199.53,5.65,(2.92%), +153,Pnc Financial Services Group,PNC,0.135457,123.09,1.28,(1.05%), +154,Transdigm Group Inc,TDG,0.131273,860.46,8.64,(1.01%), +155,Carrier Global Corp,CARR,0.129065,56.83,1.75,(3.17%), +156,Autozone Inc,AZO,0.128857,2,556.17,15.27,(0.60%) +157,Trane Technologies Plc,TT,0.12759,207.07,7.01,(3.50%), +158,Motorola Solutions Inc,MSI,0.127284,275.18,2.2,(0.81%), +159,Arista Networks Inc,ANET,0.12715,184.23,2.63,(1.45%), +160,Norfolk Southern Corp,NSC,0.124378,197.3,1.08,(0.55%), +161,General Motors Co,GM,0.124282,33.25,0.9,(2.77%), +162,Paccar Inc,PCAR,0.123613,86.12,1.31,(1.54%), +163,Charter Communications Inc A,CHTR,0.123199,442.28,8.86,(2.04%), +164,Hess Corp,HES,0.121942,157.3,-0.74,(-0.47%), +165,Sempra,SRE,0.121909,68.15,-1.26,(-1.81%), +166,Occidental Petroleum Corp,OXY,0.121531,66.03,0.43,(0.66%), +167,American International Group,AIG,0.121272,61.73,0.72,(1.18%), +168,Autodesk Inc,ADSK,0.120711,208.03,5.75,(2.84%), +169,Edwards Lifesciences Corp,EW,0.119074,69.68,-0.43,(-0.62%), +170,Ecolab Inc,ECL,0.118911,169.5,1.63,(0.97%), +171,Public Storage,PSA,0.117206,266.58,1.6,(0.60%), +172,Microchip Technology Inc,MCHP,0.116275,78.91,2.41,(3.15%), +173,Aflac Inc,AFL,0.11627,77.65,0.62,(0.81%), +174,Cintas Corp,CTAS,0.116227,486.83,5.75,(1.19%), +175,Welltower Inc,WELL,0.116157,81.07,0.87,(1.08%), +176,Williams Cos Inc,WMB,0.115685,34.65,0.55,(1.61%), +177,Kimberly Clark Corp,KMB,0.114902,121.11,-0.55,(-0.45%), +178,Archer Daniels Midland Co,ADM,0.114307,76.74,0.38,(0.50%), +179,Msci Inc,MSCI,0.113047,518.97,7.03,(1.37%), +180,Constellation Brands Inc A,STZ,0.112869,251.62,1.03,(0.41%), +181,On Semiconductor,ON,0.111009,95.12,3.07,(3.33%), +182,Metlife Inc,MET,0.110772,63.06,0.26,(0.41%), +183,Monster Beverage Corp,MNST,0.110311,53.31,0.19,(0.35%), +184,Hilton Worldwide Holdings In,HLT,0.109054,153.24,3.88,(2.60%), +185,American Electric Power,AEP,0.108899,74.71,-1.15,(-1.51%), +186,Crown Castle Inc,CCI,0.108512,91.35,1.65,(1.83%), +187,Exelon Corp,EXC,0.107894,38.11,-0.69,(-1.78%), +188,Nucor Corp,NUE,0.107787,158.31,2.6,(1.67%), +189,Travelers Cos Inc,TRV,0.107342,167.42,-0.51,(-0.30%), +190,Dominion Energy Inc,D,0.106001,44.61,-0.86,(-1.88%), +191,Te Connectivity Ltd,TEL,0.105581,123.84,3.4,(2.82%), +192,Halliburton Co,HAL,0.105449,42.18,0.15,(0.37%), +193,Centene Corp,CNC,0.105443,69.87,0.13,(0.18%), +194,Fortinet Inc,FTNT,0.105315,59.07,0.93,(1.59%), +195,Oneok Inc,OKE,0.104854,64.86,0.35,(0.53%), +196,General Mills Inc,GIS,0.104655,63.79,-0.26,(-0.40%), +197,Copart Inc,CPRT,0.104453,43.66,0.61,(1.41%), +198,Paychex Inc,PAYX,0.104412,117.4,0.89,(0.76%), +199,Biogen Inc,BIIB,0.103916,258.95,1.43,(0.55%), +200,Truist Financial Corp,TFC,0.103679,28.15,0.18,(0.63%), +201,Ross Stores Inc,ROST,0.10361,111.18,2.26,(2.07%), +202,Johnson Controls Internation,JCI,0.103601,53.69,-0.85,(-1.55%), +203,Iqvia Holdings Inc,IQV,0.103397,200.11,-2.1,(-1.04%), +204,Capital One Financial Corp,COF,0.101688,96.63,1.14,(1.20%), +205,Baker Hughes Co,BKR,0.101425,36.62,0.37,(1.02%), +206,Idexx Laboratories Inc,IDXX,0.101263,439.37,2.51,(0.57%), +207,Corteva Inc,CTVA,0.100577,50.77,0.02,(0.05%), +208,Dow Inc,DOW,0.100258,50.87,-0.13,(-0.26%), +209,Old Dominion Freight Line,ODFL,0.100037,406.82,6.93,(1.73%), +210,Constellation Energy,CEG,0.099445,109.94,-0.81,(-0.73%), +211,Dexcom Inc,DXCM,0.099384,95.68,3.59,(3.90%), +212,Simon Property Group Inc,SPG,0.098977,108.45,0.26,(0.24%), +213,Digital Realty Trust Inc,DLR,0.098757,117.6,0.76,(0.65%), +214,Realty Income Corp,O,0.098278,49.83,0.17,(0.33%), +215,Kenvue Inc W/i,KVUE,0.097359,20.2,-0.02,(-0.12%), +216,Verisk Analytics Inc,VRSK,0.097203,241.97,2.34,(0.98%), +217,Cognizant Tech Solutions A,CTSH,0.096172,68.15,-0.05,(-0.07%), +218,P G & E Corp,PCG,0.095995,16.36,-0.09,(-0.52%), +219,Prudential Financial Inc,PRU,0.095804,94.93,0.41,(0.43%), +220,Ametek Inc,AME,0.09567,150.03,1.17,(0.79%), +221,Yum Brands Inc,YUM,0.095443,123.55,1.57,(1.29%), +222,Dupont De Nemours Inc,DD,0.094185,74.58,1.11,(1.51%), +223,Ameriprise Financial Inc,AMP,0.093691,332.11,5.16,(1.58%), +224,L3harris Technologies Inc,LHX,0.092512,173.16,-2.04,(-1.16%), +225,Fidelity National Info Serv,FIS,0.09207,56.06,0.52,(0.94%), +226,Sysco Corp,SYY,0.091968,65.99,0.78,(1.20%), +227,Moderna Inc,MRNA,0.091789,100.61,1.17,(1.18%), +228,Bank of New York Mellon Corp,BK,0.091699,42.76,0.59,(1.39%), +229,Agilent Technologies Inc,A,0.091382,111.91,1.41,(1.28%), +230,Otis Worldwide Corp,OTIS,0.091228,80.55,1.2,(1.51%), +231,Rockwell Automation Inc,ROK,0.091103,288.26,3.46,(1.21%), +232,Dr Horton Inc,DHI,0.090974,108.96,1.95,(1.82%), +233,Cummins Inc,CMI,0.090916,232.98,3.03,(1.32%), +234,Estee Lauder Companies Cl A,EL,0.090788,139.94,-0.1,(-0.07%), +235,Kinder Morgan Inc,KMI,0.090175,16.71,0.05,(0.27%), +236,Keurig Dr Pepper Inc,KDP,0.088358,31.51,-0.16,(-0.51%), +237,Fastenal Co,FAST,0.087952,55.72,0.66,(1.21%), +238,Xcel Energy Inc,XEL,0.087474,56.5,-0.71,(-1.25%), +239,Devon Energy Corp,DVN,0.087359,48.84,0,(0.01%), +240,Ww Grainger Inc,GWW,0.086956,704.07,3.96,(0.57%), +241,Costar Group Inc,CSGP,0.086756,77.1,0.75,(0.99%), +242,Cencora Inc,COR,0.086188,183.99,-1.17,(-0.63%), +243,United Rentals Inc,URI,0.085093,454.44,8.22,(1.84%), +244,Hershey Co,HSY,0.084755,201.01,-1.55,(-0.76%), +245,Arch Capital Group Ltd,ACGL,0.083799,81.62,0.54,(0.67%), +246,Ppg Industries Inc,PPG,0.083787,130.49,2.46,(1.92%), +247,Global Payments Inc,GPN,0.083671,116.72,1.47,(1.28%), +248,Consolidated Edison Inc,ED,0.083432,85.06,-1.57,(-1.81%), +249,Newmont Corp,NEM,0.082799,36.78,-0.5,(-1.34%), +250,Republic Services Inc,RSG,0.082765,145.01,0.28,(0.19%), +251,Allstate Corp,ALL,0.08254,112.77,-0.25,(-0.22%), +252,Electronic Arts Inc,EA,0.081213,119.76,1.79,(1.51%), +253,Vici Properties Inc,VICI,0.081127,29.28,0.4,(1.37%), +254,Kroger Co,KR,0.080998,44.96,0.48,(1.07%), +255,Public Service Enterprise Gp,PEG,0.080723,56.88,-1.02,(-1.75%), +256,Lennar Corp A,LEN,0.078759,113.41,1.71,(1.53%), +257,Diamondback Energy Inc,FANG,0.078498,158.01,0.78,(0.50%), +258,West Pharmaceutical Services,WST,0.077362,377.15,1.97,(0.52%), +259,Quanta Services Inc,PWR,0.077074,190.82,0.7,(0.37%), +260,Gartner Inc,IT,0.076911,347.78,-1.41,(-0.40%), +261,Aptiv Plc,APTV,0.0757,99.21,3.35,(3.50%), +262,Vulcan Materials Co,VMC,0.075604,207.6,4,(1.97%), +263,Kraft Heinz Co,KHC,0.075468,33.72,-0.31,(-0.90%), +264,Ge Healthcare Technology,GEHC,0.074734,69.81,1.53,(2.24%), +265,Cdw Corp/de,CDW,0.074375,202.53,3.84,(1.93%), +266,Fortive Corp,FTV,0.072323,74.75,1.16,(1.58%), +267,Ingersoll Rand Inc,IR,0.071683,64.52,1.25,(1.97%), +268,Ansys Inc,ANSS,0.071343,299.19,4.85,(1.65%), +269,Extra Space Storage Inc,EXR,0.071269,120.75,0.24,(0.20%), +270,Wec Energy Group Inc,WEC,0.071007,79.67,-0.91,(-1.12%), +271,Martin Marietta Materials,MLM,0.070759,418,8.05,(1.96%), +272,Edison International,EIX,0.068887,63.92,-1.38,(-2.11%), +273,American Water Works Co Inc,AWK,0.068233,123.27,-3.07,(-2.43%), +274,Warner Bros Discovery Inc,WBD,0.068207,10.89,-0.15,(-1.31%), +275,Lyondellbasell Indu Cl A,LYB,0.067294,94.86,-0.11,(-0.11%), +276,Mettler Toledo International,MTD,0.067028,1,112.26,14.48,(1.32%) +277,Avalonbay Communities Inc,AVB,0.066762,171.85,-0.6,(-0.35%), +278,Delta Air Lines Inc,DAL,0.065781,37.32,0.66,(1.79%), +279,T Rowe Price Group Inc,TROW,0.064996,104.73,1.19,(1.15%), +280,Keysight Technologies In,KEYS,0.064934,133.51,3.11,(2.38%), +281,Zimmer Biomet Holdings Inc,ZBH,0.064476,112.14,1.38,(1.24%), +282,Dollar General Corp,DG,0.064042,105.04,0.7,(0.67%), +283,Corning Inc,GLW,0.064037,30.35,0.29,(0.98%), +284,Ebay Inc,EBAY,0.063728,43.45,0.56,(1.31%), +285,Cbre Group Inc A,CBRE,0.063578,73.84,0.35,(0.48%), +286,Weyerhaeuser Co,WY,0.063312,30.4,-0.64,(-2.05%), +287,Church & Dwight Co Inc,CHD,0.062765,91.68,-0.29,(-0.31%), +288,Cardinal Health Inc,CAH,0.062583,88.18,0.14,(0.16%), +289,Hp Inc,HPQ,0.062013,25.73,0.09,(0.36%), +290,Equifax Inc,EFX,0.061821,185.4,4.68,(2.59%), +291,Tractor Supply Company,TSCO,0.061683,205.07,2.06,(1.02%), +292,Willis Towers Watson Plc,WTW,0.06168,211.96,0.35,(0.17%), +293,Hewlett Packard Enterprise,HPE,0.061499,17.7,0.63,(3.66%), +294,Fair Isaac Corp,FICO,0.061481,890.19,4.58,(0.52%), +295,Dollar Tree Inc,DLTR,0.061287,106.46,1.11,(1.05%), +296,Hartford Financial Svcs Grp,HIG,0.061236,72.24,0.53,(0.73%), +297,Resmed Inc,RMD,0.060853,149.81,1.16,(0.78%), +298,Take Two Interactive Softwre,TTWO,0.060753,139.63,1.85,(1.34%), +299,Royal Caribbean Cruises Ltd,RCL,0.060515,94.38,2.42,(2.64%), +300,Xylem Inc,XYL,0.060192,91.4,1.09,(1.20%), +301,Align Technology Inc,ALGN,0.060095,309.06,7.38,(2.45%), +302,Steris Plc,STE,0.060013,221.57,3.67,(1.69%), +303,Broadridge Financial Solutio,BR,0.059572,181.18,-0.04,(-0.02%), +304,Discover Financial Services,DFS,0.059507,86.35,1.09,(1.28%), +305,State Street Corp,STT,0.059411,67.81,1.03,(1.54%), +306,Sba Communications Corp,SBAC,0.059216,198.11,2.05,(1.05%), +307,Monolithic Power Systems Inc,MPWR,0.058699,457.69,16.51,(3.74%), +308,Illumina Inc,ILMN,0.058584,133.02,-0.28,(-0.21%), +309,Dte Energy Company,DTE,0.058057,98.82,-1.72,(-1.71%), +310,M & T Bank Corp,MTB,0.057846,126.63,2.09,(1.68%), +311,Coterra Energy Inc,CTRA,0.057589,27.48,0.34,(1.23%), +312,Eversource Energy,ES,0.057281,57.54,-1.23,(-2.09%), +313,Genuine Parts Co,GPC,0.055796,142.94,0.63,(0.45%), +314,Equity Residential,EQR,0.055712,58.67,0.23,(0.40%), +315,Entergy Corp,ETR,0.055241,92.23,-1.02,(-1.10%), +316,Dover Corp,DOV,0.055103,141.68,1.09,(0.77%), +317,Ameren Corporation,AEE,0.054981,74.6,-1.51,(-1.98%), +318,Ulta Beauty Inc,ULTA,0.054585,398.17,5.73,(1.46%), +319,Teledyne Technologies Inc,TDY,0.054228,414.36,0.92,(0.22%), +320,Nvr Inc,NVR,0.054188,6,27.42,86.42,(1.45%) +321,Targa Resources Corp,TRGP,0.05408,87.52,0.93,(1.08%), +322,Molina Healthcare Inc,MOH,0.053618,333.09,2.03,(0.61%), +323,Wabtec Corp,WAB,0.053425,108.18,1.35,(1.26%), +324,Fleetcor Technologies Inc,FLT,0.053345,260.14,1.28,(0.49%), +325,Albemarle Corp,ALB,0.053229,172.99,10.36,(6.37%), +326,Baxter International Inc,BAX,0.05272,37.54,0.21,(0.57%), +327,Raymond James Financial Inc,RJF,0.052247,101.39,1.84,(1.85%), +328,Mccormick & Co Non Vtg Shrs,MKC,0.051871,74.55,0.46,(0.63%), +329,Invitation Homes Inc,INVH,0.051153,31.73,0.03,(0.11%), +330,Firstenergy Corp,FE,0.050777,34.56,-0.69,(-1.94%), +331,Laboratory Crp of Amer Hldgs,LH,0.05072,204.23,-0.62,(-0.30%), +332,Howmet Aerospace Inc,HWM,0.050386,46.99,0.91,(1.97%), +333,Verisign Inc,VRSN,0.050215,202.93,2.46,(1.23%), +334,Ppl Corp,PPL,0.04902,23.56,-0.39,(-1.61%), +335,Iron Mountain Inc,IRM,0.047985,59.55,0.56,(0.94%), +336,Jacobs Solutions Inc,J,0.047882,136.45,0.27,(0.20%), +337,Intl Flavors & Fragrances,IFF,0.047868,67.84,0.64,(0.95%), +338,Centerpoint Energy Inc,CNP,0.047827,26.68,-0.48,(-1.75%), +339,Darden Restaurants Inc,DRI,0.047736,143.44,2.01,(1.42%), +340,Hologic Inc,HOLX,0.047358,69.99,0.75,(1.08%), +341,First Solar Inc,FSLR,0.047324,161.9,3.29,(2.07%), +342,Expeditors Intl Wash Inc,EXPD,0.046936,114.74,1.08,(0.95%), +343,Brown & Brown Inc,BRO,0.046675,71.15,0.19,(0.26%), +344,Factset Research Systems Inc,FDS,0.046601,443.66,8.47,(1.95%), +345,Fifth Third Bancorp,FITB,0.046598,25.05,0.19,(0.74%), +346,Ventas Inc,VTR,0.046351,42.18,0.77,(1.85%), +347,Marathon Oil Corp,MRO,0.046321,27.51,0.12,(0.45%), +348,Steel Dynamics Inc,STLD,0.046096,106.96,0.52,(0.48%), +349,Bunge Ltd,BG,0.046038,110.67,1.1,(1.00%), +350,Ptc Inc,PTC,0.045951,140.25,1.78,(1.28%), +351,Everest Group Ltd,EG,0.04587,381.3,-0.42,(-0.11%), +352,Cincinnati Financial Corp,CINF,0.045852,104.4,-0.3,(-0.29%), +353,Enphase Energy Inc,ENPH,0.045679,121.39,1.28,(1.07%), +354,Nasdaq Inc,NDAQ,0.04562,49.07,0.74,(1.52%), +355,Akamai Technologies Inc,AKAM,0.045578,107.75,0.79,(0.74%), +356,Cboe Global Markets Inc,CBOE,0.045525,155.28,0.51,(0.33%), +357,Cf Industries Holdings Inc,CF,0.04496,84.93,1.48,(1.78%), +358,Waters Corp,WAT,0.044936,274.46,2.12,(0.78%), +359,Pultegroup Inc,PHM,0.044848,74.85,1.65,(2.25%), +360,Tyler Technologies Inc,TYL,0.044831,387.74,2.43,(0.63%), +361,Principal Financial Group,PFG,0.044705,72.74,0.74,(1.02%), +362,Clorox Company,CLX,0.04465,128.98,-0.17,(-0.13%), +363,Southwest Airlines Co,LUV,0.044478,27.3,0.49,(1.81%), +364,Regions Financial Corp,RF,0.044397,17.16,0.22,(1.27%), +365,Garmin Ltd,GRMN,0.044336,104.65,1.42,(1.38%), +366,Atmos Energy Corp,ATO,0.044128,106.32,-0.14,(-0.13%), +367,Netapp Inc,NTAP,0.044116,76.49,1.54,(2.05%), +368,Textron Inc,TXT,0.043659,79.27,0.33,(0.41%), +369,Cooper Cos Inc,COO,0.04361,318.15,2.23,(0.71%), +370,Kellogg Co,K,0.043517,58.9,-0.22,(-0.38%), +371,Idex Corp,IEX,0.043484,210.72,3.28,(1.58%), +372,Cms Energy Corp,CMS,0.043476,52.78,-0.57,(-1.07%), +373,Skyworks Solutions Inc,SWKS,0.042974,98.55,2.25,(2.33%), +374,Alexandria Real Estate Equit,ARE,0.042466,99.48,0.59,(0.60%), +375,Hunt (Jb) Transprt Svcs Inc,JBHT,0.042319,186.54,0.95,(0.51%), +376,Las Vegas Sands Corp,LVS,0.042222,45.63,-0.53,(-1.15%), +377,Ball Corp,BALL,0.042202,48.27,0.04,(0.08%), +378,Walgreens Boots Alliance Inc,WBA,0.04215,20.97,-0.06,(-0.26%), +379,Teradyne Inc,TER,0.041494,100.04,3.56,(3.68%), +380,Mid America Apartment Comm,MAA,0.041385,128.55,0.48,(0.37%), +381,Epam Systems Inc,EPAM,0.041006,257.76,0.96,(0.37%), +382,Avery Dennison Corp,AVY,0.040961,183.42,1.39,(0.76%), +383,Omnicom Group,OMC,0.040483,74.6,1.21,(1.65%), +384,Huntington Bancshares Inc,HBAN,0.040444,10.25,0.13,(1.24%), +385,Eqt Corp,EQT,0.040251,40,0.39,(0.99%), +386,Tyson Foods Inc Cl A,TSN,0.040042,49.74,-0.37,(-0.74%), +387,Western Digital Corp,WDC,0.039814,45.5,0.94,(2.11%), +388,Northern Trust Corp,NTRS,0.039557,69.29,0.84,(1.23%), +389,Carnival Corp,CCL,0.039206,14.52,0.54,(3.88%), +390,Expedia Group Inc,EXPE,0.038585,102.75,2.5,(2.49%), +391,United Airlines Holdings Inc,UAL,0.038383,42.84,0.81,(1.94%), +392,Quest Diagnostics Inc,DGX,0.038331,123.71,0.31,(0.25%), +393,Axon Enterprise Inc,AXON,0.03828,195.69,1.04,(0.53%), +394,Packaging Corp of America,PKG,0.038236,152.79,0.9,(0.59%), +395,Revvity Inc,RVTY,0.0378,110.55,1.5,(1.38%), +396,Snap on Inc,SNA,0.037774,257.97,4,(1.58%), +397,Pool Corp,POOL,0.037475,353.56,9.86,(2.87%), +398,Essex Property Trust Inc,ESS,0.03733,210.81,0.07,(0.03%), +399,Domino S Pizza Inc,DPZ,0.037258,382.39,2.18,(0.57%), +400,Amcor Plc,AMCR,0.037101,9.09,0.06,(0.61%), +401,Best Buy Co Inc,BBY,0.037071,68.66,0.29,(0.43%), +402,Apa Corp,APA,0.03662,42.49,0.11,(0.27%), +403,Lamb Weston Holdings Inc,LW,0.036553,91.47,0.09,(0.10%), +404,Wr Berkley Corp,WRB,0.036551,65.21,0.86,(1.33%), +405,Conagra Brands Inc,CAG,0.036484,27.44,-0.1,(-0.35%), +406,Lkq Corp,LKQ,0.036449,49.51,0.72,(1.47%), +407,Jm Smucker Co,SJM,0.035767,124.48,-0.96,(-0.77%), +408,Stanley Black & Decker Inc,SWK,0.035567,83.87,0.97,(1.17%), +409,Synchrony Financial,SYF,0.035241,30.73,0.55,(1.84%), +410,Carmax Inc,KMX,0.035202,71.64,-8.05,(-10.10%), +411,Leidos Holdings Inc,LDOS,0.034943,92.2,0.21,(0.23%), +412,Seagate Technology Holdings,STX,0.034918,65.71,1.42,(2.20%), +413,Paycom Software Inc,PAYC,0.034914,259.42,2.34,(0.91%), +414,Celanese Corp,CE,0.034212,127.11,3.81,(3.09%), +415,Trimble Inc,TRMB,0.034136,52.22,3.01,(6.12%), +416,Alliant Energy Corp,LNT,0.03411,48.06,-0.49,(-1.02%), +417,Citizens Financial Group,CFG,0.033972,26.28,0.52,(2.00%), +418,International Paper Co,IP,0.033961,35.1,0.15,(0.41%), +419,Masco Corp,MAS,0.033414,54.58,1.37,(2.58%), +420,Nordson Corp,NDSN,0.033057,223.81,3.73,(1.69%), +421,Loews Corp,L,0.032942,64.16,0.36,(0.56%), +422,Evergy Inc,EVRG,0.032792,50.48,-0.58,(-1.13%), +423,Mosaic Co,MOS,0.03266,35.63,0.43,(1.22%), +424,Molson Coors Beverage Co B,TAP,0.032624,62.29,-0.12,(-0.19%), +425,Zebra Technologies Corp Cl A,ZBRA,0.03257,236.95,11.04,(4.89%), +426,Viatris Inc,VTRS,0.032115,9.8,0.21,(2.14%), +427,Live Nation Entertainment In,LYV,0.032035,83.73,2.71,(3.34%), +428,Host Hotels & Resorts Inc,HST,0.03173,16.38,0.34,(2.11%), +429,Insulet Corp,PODD,0.031493,166.19,4.49,(2.77%), +430,Match Group Inc,MTCH,0.031269,40.07,0.09,(0.23%), +431,Interpublic Group of Cos Inc,IPG,0.031184,29.12,0.39,(1.35%), +432,Hormel Foods Corp,HRL,0.030887,38.15,-0.19,(-0.48%), +433,Incyte Corp,INCY,0.03067,58.93,-0.18,(-0.30%), +434,Udr Inc,UDR,0.030252,35.67,0.28,(0.79%), +435,Jack Henry & Associates Inc,JKHY,0.030211,150.61,2.17,(1.46%), +436,Kimco Realty Corp,KIM,0.029862,17.73,0.24,(1.34%), +437,Aes Corp,AES,0.029775,15.29,-0.65,(-4.05%), +438,Bio Techne Corp,TECH,0.029742,67.67,0.1,(0.15%), +439,Pentair Plc,PNR,0.029592,65.59,0.87,(1.34%), +440,Rollins Inc,ROL,0.029276,37.64,0.2,(0.52%), +441,Mgm Resorts International,MGM,0.028601,36.76,0.27,(0.74%), +442,Ceridian Hcm Holding Inc,CDAY,0.028589,67.38,0.35,(0.52%), +443,Brown Forman Corp Class B,BF.B,0.028542,56.78,0.14,(0.25%), +444,Nisource Inc,NI,0.028365,24.84,-0.35,(-1.37%), +445,Gen Digital Inc,GEN,0.028124,17.83,-0.07,(-0.37%), +446,C.H. Robinson Worldwide Inc,CHRW,0.028048,86.31,0.02,(0.02%), +447,Camden Property Trust,CPT,0.027984,94.56,-0.32,(-0.34%), +448,Charles River Laboratories,CRL,0.027736,195.69,0.75,(0.38%), +449,Healthpeak Properties Inc,PEAK,0.027617,18.15,0.1,(0.58%), +450,Caesars Entertainment Inc,CZR,0.027217,47.52,1.54,(3.36%), +451,Regency Centers Corp,REG,0.027131,59.98,0.85,(1.43%), +452,Keycorp,KEY,0.0269,10.52,0.22,(2.09%), +453,Henry Schein Inc,HSIC,0.026715,73.88,0.62,(0.84%), +454,Globe Life Inc,GL,0.026574,110.04,0.61,(0.56%), +455,Borgwarner Inc,BWA,0.026416,40.72,0.92,(2.31%), +456,F5 Inc,FFIV,0.026087,160.33,2.74,(1.74%), +457,Qorvo Inc,QRVO,0.025849,96.39,1.83,(1.93%), +458,Teleflex Inc,TFX,0.025796,199.42,2.91,(1.48%), +459,Allegion Plc,ALLE,0.025545,104.97,1.68,(1.63%), +460,Westrock Co,WRK,0.025292,35.98,0.23,(0.64%), +461,Eastman Chemical Co,EMN,0.025003,76.99,2.35,(3.15%), +462,Wynn Resorts Ltd,WYNN,0.024938,92.21,0,(-0.00%), +463,Nrg Energy Inc,NRG,0.024681,38.55,-0.03,(-0.08%), +464,Juniper Networks Inc,JNPR,0.024655,27.92,0.42,(1.52%), +465,Pinnacle West Capital,PNW,0.02321,73.45,-0.71,(-0.95%), +466,Hasbro Inc,HAS,0.02308,65.23,0.24,(0.37%), +467,Catalent Inc,CTLT,0.023069,45.85,0.07,(0.15%), +468,American Airlines Group Inc,AAL,0.02296,13,0.39,(3.05%), +469,Fmc Corp,FMC,0.022942,66.03,0.02,(0.03%), +470,Campbell Soup Co,CPB,0.022776,41.15,-0.31,(-0.76%), +471,Smith (a.O.) Corp,AOS,0.022769,66.99,1.54,(2.35%), +472,Boston Properties Inc,BXP,0.02269,59.66,0.79,(1.34%), +473,Huntington Ingalls Industrie,HII,0.022502,204.41,1.22,(0.60%), +474,Fox Corp Class A,FOXA,0.021902,31.47,0.55,(1.76%), +475,Robert Half Inc,RHI,0.021872,73.78,0.64,(0.87%), +476,Assurant Inc,AIZ,0.021618,145.63,-0.13,(-0.09%), +477,Universal Health Services B,UHS,0.021551,127,2.8,(2.25%), +478,Etsy Inc,ETSY,0.021257,63.53,1.64,(2.65%), +479,Marketaxess Holdings Inc,MKTX,0.021132,205.89,4.11,(2.04%), +480,News Corp Class A,NWSA,0.0209,20,0.35,(1.76%), +481,Bio Rad Laboratories A,BIO,0.020548,356.1,3.63,(1.03%), +482,Bath & Body Works Inc,BBWI,0.020412,33.19,1.04,(3.23%), +483,Dentsply Sirona Inc,XRAY,0.020079,33.94,-0.17,(-0.51%), +484,Solaredge Technologies Inc,SEDG,0.020026,132.35,4.34,(3.39%), +485,Whirlpool Corp,WHR,0.019812,131.66,1.03,(0.79%), +486,Franklin Resources Inc,BEN,0.019128,24.55,0.28,(1.14%), +487,Generac Holdings Inc,GNRC,0.018958,110.73,1.84,(1.69%), +488,Norwegian Cruise Line Holdin,NCLH,0.018812,16.96,0.67,(4.08%), +489,Federal Realty Invs Trust,FRT,0.018475,91.45,1.05,(1.16%), +490,Tapestry Inc,TPR,0.01809,28.18,0.23,(0.84%), +491,Invesco Ltd,IVZ,0.017835,14.31,0.22,(1.53%), +492,Paramount Global Class B,PARA,0.017208,12.89,0.11,(0.89%), +493,Vf Corp,VFC,0.015631,16.59,-0.32,(-1.89%), +494,Comerica Inc,CMA,0.014638,41.07,1.12,(2.81%), +495,Davita Inc,DVA,0.014395,95.75,0.01,(0.01%), +496,Zions Bancorp Na,ZION,0.013918,33.96,0.79,(2.39%), +497,Ralph Lauren Corp,RL,0.013127,115.52,0.26,(0.22%), +498,Sealed Air Corp,SEE,0.012794,32.2,0.46,(1.46%), +499,Alaska Air Group Inc,ALK,0.012574,37.04,0.63,(1.73%), +500,Mohawk Industries Inc,MHK,0.011998,85.15,1.23,(1.46%), +501,Organon & Co,OGN,0.011665,16.93,0.34,(2.02%), +502,Dxc Technology Co,DXC,0.011658,20.64,0.29,(1.40%), +503,Fox Corp Class B,FOX,0.010545,29.16,0.53,(1.85%), +504,News Corp Class B,NWS,0.006575,20.75,0.36,(1.74%), diff --git a/vuu/src/main/scala/org/finos/vuu/SimulMain.scala b/example/main/src/main/scala/org/finos/vuu/SimulMain.scala similarity index 94% rename from vuu/src/main/scala/org/finos/vuu/SimulMain.scala rename to example/main/src/main/scala/org/finos/vuu/SimulMain.scala index dbc666160..f8538e78a 100644 --- a/vuu/src/main/scala/org/finos/vuu/SimulMain.scala +++ b/example/main/src/main/scala/org/finos/vuu/SimulMain.scala @@ -2,24 +2,24 @@ package org.finos.vuu import com.typesafe.config.ConfigFactory import com.typesafe.scalalogging.StrictLogging -import org.finos.vuu.core.module.authn.AuthNModule -import org.finos.vuu.core.module.metrics.MetricsModule -import org.finos.vuu.core.module.simul.SimulationModule -import org.finos.vuu.core.module.typeahead.TypeAheadModule -import org.finos.vuu.core.module.vui.VuiStateModule -import org.finos.vuu.core.{VuuSecurityOptions, VuuServer, VuuServerConfig, VuuThreadingOptions, VuuWebSocketOptions} -import org.finos.vuu.net.{AlwaysHappyLoginValidator, Authenticator, LoggedInTokenValidator} -import org.finos.vuu.net.auth.AlwaysHappyAuthenticator -import org.finos.vuu.net.http.VuuHttp2ServerOptions -import org.finos.vuu.state.{MemoryBackedVuiStateStore, VuiHeader, VuiJsonState, VuiState} import org.finos.toolbox.jmx.{JmxInfra, MetricsProvider, MetricsProviderImpl} import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.time.{Clock, DefaultClock} +import org.finos.vuu.core._ import org.finos.vuu.core.module.TableDefContainer +import org.finos.vuu.core.module.authn.AuthNModule import org.finos.vuu.core.module.auths.PermissionModule import org.finos.vuu.core.module.basket.BasketModule import org.finos.vuu.core.module.editable.EditableModule +import org.finos.vuu.core.module.metrics.MetricsModule import org.finos.vuu.core.module.price.PriceModule +import org.finos.vuu.core.module.simul.SimulationModule +import org.finos.vuu.core.module.typeahead.TypeAheadModule +import org.finos.vuu.core.module.vui.VuiStateModule +import org.finos.vuu.net.auth.AlwaysHappyAuthenticator +import org.finos.vuu.net.http.VuuHttp2ServerOptions +import org.finos.vuu.net.{AlwaysHappyLoginValidator, Authenticator, LoggedInTokenValidator} +import org.finos.vuu.state.MemoryBackedVuiStateStore /* //to allow self signed certs diff --git a/example/order/pom.xml b/example/order/pom.xml new file mode 100644 index 000000000..ca144f61e --- /dev/null +++ b/example/order/pom.xml @@ -0,0 +1,297 @@ + + + 4.0.0 + + + org.finos.vuu + example + 0.9.36-SNAPSHOT + + + + order + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + + + + org.finos.vuu + permission + 0.9.36-SNAPSHOT + + + + org.finos.vuu + price + 0.9.36-SNAPSHOT + + + + org.scala-lang + scala-library + ${scala.version} + + + + org.scala-lang + scala-reflect + ${scala.version} + + + + junit + junit + 4.13.2 + test + + + + org.scalatest + scalatest_2.13 + ${scalatest.version} + test + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + + + + + + + + + sign-it + + + sign + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + + + + legal-report + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + **/*.scala + + + + + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-source-plugin + + + + compile + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.ow2.asm + asm + 6.2 + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + + compile + testCompile + + + + + src/main/scala + src/test/scala + + -Xms64m + -Xmx1024m + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + generate-sources + + add-source + + + + target/generated-sources/antlr4 + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + + test-jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7 + + + + + + + org.scalatest + scalatest-maven-plugin + 2.0.2 + + ${project.build.directory}/surefire-reports + . + test-reports.txt + + + + test + + test + + + + + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + ${scala.version} + + + + + + \ No newline at end of file diff --git a/example/order/src/main/java/Dummy4JavaDoc.java b/example/order/src/main/java/Dummy4JavaDoc.java new file mode 100644 index 000000000..00b8d1897 --- /dev/null +++ b/example/order/src/main/java/Dummy4JavaDoc.java @@ -0,0 +1,2 @@ +public class Dummy4JavaDoc { +} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/SimulationModule.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/SimulationModule.scala similarity index 91% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/SimulationModule.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/SimulationModule.scala index 7719a3e2d..2c4f66d38 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/simul/SimulationModule.scala +++ b/example/order/src/main/scala/org/finos/vuu/core/module/simul/SimulationModule.scala @@ -1,47 +1,22 @@ package org.finos.vuu.core.module.simul import com.typesafe.scalalogging.StrictLogging +import org.finos.toolbox.lifecycle.{DefaultLifecycleEnabled, LifecycleContainer} +import org.finos.toolbox.time.Clock import org.finos.vuu.api._ import org.finos.vuu.client.messages.RequestId +import org.finos.vuu.core.module.auths.OrderPermissionChecker +import org.finos.vuu.core.module.price.PriceModule import org.finos.vuu.core.module.simul.provider._ +import org.finos.vuu.core.module.simul.service.ParentOrdersService import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule} import org.finos.vuu.core.table.{Columns, DataTable, TableContainer} import org.finos.vuu.net.rpc.RpcHandler import org.finos.vuu.net.{ClientSessionId, RequestContext} -import org.finos.vuu.provider.simulation.{SimulatedBigInstrumentsProvider, SimulatedPricesProvider} -import org.finos.vuu.provider.{Provider, ProviderContainer, RpcProvider} +import org.finos.vuu.provider.simulation.SimulatedBigInstrumentsProvider +import org.finos.vuu.provider.{ProviderContainer, RpcProvider} import org.finos.vuu.viewport._ -import org.finos.toolbox.lifecycle.{DefaultLifecycleEnabled, LifecycleContainer} -import org.finos.toolbox.time.Clock -import org.finos.vuu.core.module.auths.OrderPermissionChecker -import org.finos.vuu.core.module.price.PriceModule -import org.finos.vuu.core.module.simul.service.ParentOrdersService - -class PricesService(val table: DataTable, val provider: Provider) extends RpcHandler with StrictLogging { - - private val pricesProvider = provider.asInstanceOf[SimulatedPricesProvider] - def setSpeedSlow(selection: ViewPortSelection, sessionId: ClientSessionId):ViewPortAction = { - pricesProvider.setSpeed(8000) - NoAction() - } - - def setSpeedMedium(selection: ViewPortSelection, sessionId: ClientSessionId):ViewPortAction = { - pricesProvider.setSpeed(2000) - NoAction() - } - - def setSpeedFast(selection: ViewPortSelection, sessionId: ClientSessionId):ViewPortAction = { - pricesProvider.setSpeed(400) - NoAction() - } - - override def menuItems(): ViewPortMenu = ViewPortMenu("Root", - new SelectionViewPortMenuItem("Set Slow", "", this.setSpeedSlow, "SET_SPEED_SLOW"), - new SelectionViewPortMenuItem("Set Medium", "", this.setSpeedMedium, "SET_SPEED_MED"), - new SelectionViewPortMenuItem("Set Fast", "", this.setSpeedFast, "SET_SPEED_FAST") - ) -} class InstrumentsService(val table: DataTable, val providerContainer: ProviderContainer) extends RpcHandler with StrictLogging { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ChildOrdersProvider.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ChildOrdersProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ChildOrdersProvider.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ChildOrdersProvider.scala index 940b01b1c..475ca1fdf 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ChildOrdersProvider.scala +++ b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ChildOrdersProvider.scala @@ -1,9 +1,9 @@ package org.finos.vuu.core.module.simul.provider -import org.finos.vuu.core.table.{DataTable, RowWithData} -import org.finos.vuu.provider.Provider import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.time.Clock +import org.finos.vuu.core.table.{DataTable, RowWithData} +import org.finos.vuu.provider.Provider class ChildOrdersProvider(val table: DataTable, model: ParentChildOrdersModel)(implicit clock: Clock, lifecycleContainer: LifecycleContainer) extends Provider { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/OrdersSimulProvider.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/OrdersSimulProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/OrdersSimulProvider.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/OrdersSimulProvider.scala index 8075f09f4..75ec1dd1c 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/OrdersSimulProvider.scala +++ b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/OrdersSimulProvider.scala @@ -1,10 +1,10 @@ package org.finos.vuu.core.module.simul.provider -import org.finos.vuu.core.table.{DataTable, RowWithData} -import org.finos.vuu.provider.Provider import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.thread.LifeCycleRunner import org.finos.toolbox.time.Clock +import org.finos.vuu.core.table.{DataTable, RowWithData} +import org.finos.vuu.provider.Provider import java.util import java.util.Random diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentChildOrdersModel.scala diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentOrdersProvider.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentOrdersProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentOrdersProvider.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentOrdersProvider.scala index 082fd554f..9f3af7707 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentOrdersProvider.scala +++ b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/ParentOrdersProvider.scala @@ -1,10 +1,10 @@ package org.finos.vuu.core.module.simul.provider -import org.finos.vuu.core.table.{DataTable, RowWithData} -import org.finos.vuu.provider.Provider import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.thread.LifeCycleRunner import org.finos.toolbox.time.Clock +import org.finos.vuu.core.table.{DataTable, RowWithData} +import org.finos.vuu.provider.Provider class ParentOrdersProvider(val table: DataTable, val model: ParentChildOrdersModel)(implicit clock: Clock, lifecycleContainer: LifecycleContainer) extends Provider { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/PermissionedOrdersProvider.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/PermissionedOrdersProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/provider/PermissionedOrdersProvider.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/provider/PermissionedOrdersProvider.scala diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/simul/service/ParentOrdersService.scala b/example/order/src/main/scala/org/finos/vuu/core/module/simul/service/ParentOrdersService.scala similarity index 95% rename from vuu/src/main/scala/org/finos/vuu/core/module/simul/service/ParentOrdersService.scala rename to example/order/src/main/scala/org/finos/vuu/core/module/simul/service/ParentOrdersService.scala index 0b775f2d2..b2ad3c11d 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/simul/service/ParentOrdersService.scala +++ b/example/order/src/main/scala/org/finos/vuu/core/module/simul/service/ParentOrdersService.scala @@ -6,7 +6,7 @@ import org.finos.vuu.core.table.DataTable import org.finos.vuu.net.ClientSessionId import org.finos.vuu.net.rpc.RpcHandler import org.finos.vuu.provider.Provider -import org.finos.vuu.viewport.{NoAction, SelectionViewPortMenuItem, ViewPortAction, ViewPortMenu, ViewPortSelection} +import org.finos.vuu.viewport._ class ParentOrdersService(val table: DataTable, val provider: Provider) extends RpcHandler with StrictLogging { diff --git a/vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala b/example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala rename to example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala index 53516ac55..d2929eb0f 100644 --- a/vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala +++ b/example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedBigInstrumentsProvider.scala @@ -1,12 +1,12 @@ package org.finos.vuu.provider.simulation import com.typesafe.scalalogging.StrictLogging -import org.finos.vuu.core.table.{DataTable, RowWithData} -import org.finos.vuu.provider.Provider import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.logging.LogAtFrequency import org.finos.toolbox.thread.RunOnceLifeCycleRunner import org.finos.toolbox.time.Clock +import org.finos.vuu.core.table.{DataTable, RowWithData} +import org.finos.vuu.provider.Provider import scala.concurrent.duration.DurationInt import scala.util.Random diff --git a/vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedInstrumentProvider.scala b/example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedInstrumentProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedInstrumentProvider.scala rename to example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedInstrumentProvider.scala index f39e77168..e203d4dd2 100644 --- a/vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedInstrumentProvider.scala +++ b/example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedInstrumentProvider.scala @@ -1,9 +1,9 @@ package org.finos.vuu.provider.simulation import com.typesafe.scalalogging.StrictLogging +import org.finos.toolbox.time.Clock import org.finos.vuu.core.table.{DataTable, RowWithData} import org.finos.vuu.provider.Provider -import org.finos.toolbox.time.Clock class SimulatedInstrumentProvider(instruments: Array[Array[String]], table: DataTable)(implicit timeProvider: Clock) extends Provider with StrictLogging { diff --git a/vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala b/example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala rename to example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala index fbe01b429..c7d824eda 100644 --- a/vuu/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala +++ b/example/order/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala @@ -1,12 +1,12 @@ package org.finos.vuu.provider.simulation import com.typesafe.scalalogging.StrictLogging -import org.finos.vuu.core.table.{DataTable, RowWithData} -import org.finos.vuu.provider.Provider import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.logging.LogAtFrequency import org.finos.toolbox.thread.{LifeCycleRunner, RunInThread} import org.finos.toolbox.time.Clock +import org.finos.vuu.core.table.{DataTable, RowWithData} +import org.finos.vuu.provider.Provider import java.util.Random import java.util.concurrent.ConcurrentHashMap diff --git a/example/permission/pom.xml b/example/permission/pom.xml new file mode 100644 index 000000000..80fa52d78 --- /dev/null +++ b/example/permission/pom.xml @@ -0,0 +1,294 @@ + + + 4.0.0 + + + org.finos.vuu + example + 0.9.36-SNAPSHOT + + + + permission + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + tests + test-jar + test + + + + org.scala-lang + scala-library + ${scala.version} + + + + org.scala-lang + scala-reflect + ${scala.version} + + + + junit + junit + 4.13.2 + test + + + + org.scalatest + scalatest_2.13 + ${scalatest.version} + test + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + + + + + + + + + sign-it + + + sign + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + + + + legal-report + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + **/*.scala + + + + + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-source-plugin + + + + compile + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.ow2.asm + asm + 6.2 + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + + compile + testCompile + + + + + src/main/scala + src/test/scala + + -Xms64m + -Xmx1024m + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + generate-sources + + add-source + + + + target/generated-sources/antlr4 + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + + test-jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7 + + + + + + + org.scalatest + scalatest-maven-plugin + 2.0.2 + + ${project.build.directory}/surefire-reports + . + test-reports.txt + + + + test + + test + + + + + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + ${scala.version} + + + + + + \ No newline at end of file diff --git a/example/permission/src/main/java/Dummy4JavaDoc.java b/example/permission/src/main/java/Dummy4JavaDoc.java new file mode 100644 index 000000000..00b8d1897 --- /dev/null +++ b/example/permission/src/main/java/Dummy4JavaDoc.java @@ -0,0 +1,2 @@ +public class Dummy4JavaDoc { +} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/authn/AuthNModule.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/authn/AuthNModule.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/authn/AuthNModule.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/authn/AuthNModule.scala index 0a7233b8d..2af9d7ff2 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/authn/AuthNModule.scala +++ b/example/permission/src/main/scala/org/finos/vuu/core/module/authn/AuthNModule.scala @@ -1,9 +1,9 @@ package org.finos.vuu.core.module.authn -import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule} -import org.finos.vuu.net.{Authenticator, LoggedInTokenValidator} import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.time.Clock +import org.finos.vuu.core.module.{DefaultModule, ModuleFactory, TableDefContainer, ViewServerModule} +import org.finos.vuu.net.{Authenticator, LoggedInTokenValidator} object AuthNModule extends DefaultModule { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/authn/AuthNRestService.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/authn/AuthNRestService.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/authn/AuthNRestService.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/authn/AuthNRestService.scala index 9a3fc4575..b6c785575 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/authn/AuthNRestService.scala +++ b/example/permission/src/main/scala/org/finos/vuu/core/module/authn/AuthNRestService.scala @@ -1,11 +1,11 @@ package org.finos.vuu.core.module.authn import com.typesafe.scalalogging.StrictLogging -import org.finos.vuu.net.{Authenticator, LoggedInTokenValidator, ServerUserPrincipal} -import org.finos.vuu.net.rest.RestService import io.vertx.core.http.Cookie import io.vertx.ext.web.RoutingContext import org.finos.toolbox.time.Clock +import org.finos.vuu.net.rest.RestService +import org.finos.vuu.net.{Authenticator, LoggedInTokenValidator, ServerUserPrincipal} import java.util.concurrent.TimeUnit import scala.util.{Failure, Success, Try} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/authn/VuuAuthHandler.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/authn/VuuAuthHandler.scala similarity index 92% rename from vuu/src/main/scala/org/finos/vuu/core/module/authn/VuuAuthHandler.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/authn/VuuAuthHandler.scala index 7187ebcc2..e8b8350f2 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/authn/VuuAuthHandler.scala +++ b/example/permission/src/main/scala/org/finos/vuu/core/module/authn/VuuAuthHandler.scala @@ -1,3 +1,5 @@ +package org.finos.vuu.core.module.authn + //package org.finos.vuu.core.module.authn // //import io.vertx.core.{AsyncResult, Handler} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/auths/OrderPermissionChecker.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/OrderPermissionChecker.scala similarity index 90% rename from vuu/src/main/scala/org/finos/vuu/core/module/auths/OrderPermissionChecker.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/auths/OrderPermissionChecker.scala index 4d30f79fb..42c33d4a6 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/auths/OrderPermissionChecker.scala +++ b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/OrderPermissionChecker.scala @@ -3,11 +3,9 @@ package org.finos.vuu.core.module.auths import org.finos.toolbox.lifecycle.{DefaultLifecycleEnabled, LifecycleContainer} import org.finos.toolbox.thread.LifeCycleRunner import org.finos.toolbox.time.Clock -import org.finos.vuu.core.VuuServer import org.finos.vuu.core.auths.RowPermissionChecker import org.finos.vuu.core.module.auths.PermissionModule.ColumnNames.Bitmask -import org.finos.vuu.core.sort.UserDefinedFilterAndSort -import org.finos.vuu.core.table.{DataTable, RowData, RowWithData, TableContainer} +import org.finos.vuu.core.table.{RowData, RowWithData, TableContainer} import org.finos.vuu.viewport.ViewPort class OrderPermissionChecker(val vp: ViewPort, tableContainer: TableContainer)(implicit lifecycle: LifecycleContainer, clock: Clock) extends DefaultLifecycleEnabled with RowPermissionChecker { diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/auths/PermissionModule.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/PermissionModule.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/auths/PermissionModule.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/auths/PermissionModule.scala diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/auths/PermissionSet.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/PermissionSet.scala similarity index 99% rename from vuu/src/main/scala/org/finos/vuu/core/module/auths/PermissionSet.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/auths/PermissionSet.scala index 7d82230f9..c7951617e 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/auths/PermissionSet.scala +++ b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/PermissionSet.scala @@ -29,7 +29,6 @@ object PermissionSet { roles.mkString(",") } - def toBinaryString(intRepresentation: Int): String = { val binaryString = Integer.toBinaryString(intRepresentation) padWithZeros(binaryString) diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/auths/provider/PermissionsProvider.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/provider/PermissionsProvider.scala similarity index 100% rename from vuu/src/main/scala/org/finos/vuu/core/module/auths/provider/PermissionsProvider.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/auths/provider/PermissionsProvider.scala diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/auths/service/PermissionsRpcService.scala b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/service/PermissionsRpcService.scala similarity index 93% rename from vuu/src/main/scala/org/finos/vuu/core/module/auths/service/PermissionsRpcService.scala rename to example/permission/src/main/scala/org/finos/vuu/core/module/auths/service/PermissionsRpcService.scala index 583bcc78f..8ca4f71ba 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/auths/service/PermissionsRpcService.scala +++ b/example/permission/src/main/scala/org/finos/vuu/core/module/auths/service/PermissionsRpcService.scala @@ -2,13 +2,13 @@ package org.finos.vuu.core.module.auths.service import com.typesafe.scalalogging.StrictLogging import org.finos.toolbox.time.Clock +import org.finos.vuu.core.module.auths.PermissionModule.ColumnNames._ +import org.finos.vuu.core.module.auths.PermissionSet +import org.finos.vuu.core.module.auths.PermissionSet.{AlgoCoveragePermission, HighTouchPermission, SalesTradingPermission} import org.finos.vuu.core.table.{DataTable, EmptyRowData, RowWithData} import org.finos.vuu.net.ClientSessionId import org.finos.vuu.net.rpc.RpcHandler -import org.finos.vuu.viewport.{NoAction, SelectionViewPortMenuItem, ViewPortAction, ViewPortMenu, ViewPortSelection} -import org.finos.vuu.core.module.auths.PermissionModule.ColumnNames._ -import org.finos.vuu.core.module.auths.PermissionSet -import org.finos.vuu.core.module.auths.PermissionSet.{AlgoCoveragePermission, HighTouchPermission, SalesTradingPermission, SalesTradingPermissionString} +import org.finos.vuu.viewport._ class PermissionsRpcService(val table: DataTable)(implicit clock: Clock) extends RpcHandler with StrictLogging { diff --git a/vuu/src/test/scala/org/finos/vuu/core/module/authn/AuthNServerTest.scala b/example/permission/src/test/scala/org/finos/vuu/core/module/authn/AuthNServerTest.scala similarity index 98% rename from vuu/src/test/scala/org/finos/vuu/core/module/authn/AuthNServerTest.scala rename to example/permission/src/test/scala/org/finos/vuu/core/module/authn/AuthNServerTest.scala index 1890a5f8a..bc58c0f29 100644 --- a/vuu/src/test/scala/org/finos/vuu/core/module/authn/AuthNServerTest.scala +++ b/example/permission/src/test/scala/org/finos/vuu/core/module/authn/AuthNServerTest.scala @@ -1,25 +1,25 @@ package org.finos.vuu.core.module.authn import com.typesafe.scalalogging.StrictLogging -import org.finos.vuu.core.{VuuSecurityOptions, VuuServer, VuuServerConfig, VuuWebSocketOptions} -import org.finos.vuu.core.module.vui.VuiStateModule -import org.finos.vuu.net.{Authenticator, LoggedInTokenValidator} -import org.finos.vuu.net.auth.AlwaysHappyAuthenticator -import org.finos.vuu.net.http.VuuHttp2ServerOptions -import org.finos.vuu.state.MemoryBackedVuiStateStore -import io.vertx.core.{Vertx, VertxOptions} import io.vertx.core.json.JsonObject +import io.vertx.core.{Vertx, VertxOptions} import io.vertx.ext.web.client.WebClientOptions import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.thread.Async import org.finos.toolbox.time.{Clock, DefaultClock} import org.finos.vuu.core.module.TableDefContainer +import org.finos.vuu.core.module.vui.VuiStateModule +import org.finos.vuu.core.{VuuSecurityOptions, VuuServer, VuuServerConfig, VuuWebSocketOptions} +import org.finos.vuu.net.auth.AlwaysHappyAuthenticator +import org.finos.vuu.net.http.VuuHttp2ServerOptions +import org.finos.vuu.net.{Authenticator, LoggedInTokenValidator} +import org.finos.vuu.state.MemoryBackedVuiStateStore import org.scalatest.featurespec.AnyFeatureSpec import org.scalatest.matchers.should.Matchers import java.util.concurrent.atomic.AtomicBoolean -import scala.concurrent.{Await, ExecutionContext} +import scala.concurrent.ExecutionContext class AuthNServerTest extends AnyFeatureSpec with Matchers with StrictLogging { diff --git a/example/permission/src/test/scala/org/finos/vuu/core/module/auths/PermissionFilteredViewport.scala b/example/permission/src/test/scala/org/finos/vuu/core/module/auths/PermissionFilteredViewport.scala new file mode 100644 index 000000000..47a3bc175 --- /dev/null +++ b/example/permission/src/test/scala/org/finos/vuu/core/module/auths/PermissionFilteredViewport.scala @@ -0,0 +1,158 @@ +//package org.finos.vuu.core.module.auths +// +//import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} +//import org.finos.toolbox.lifecycle.LifecycleContainer +//import org.finos.toolbox.time.{Clock, DefaultClock} +//import org.finos.vuu.api.{JoinSpec, JoinTableDef, JoinTo, LeftOuterJoin, TableDef} +//import org.finos.vuu.client.messages.RequestId +//import org.finos.vuu.core.table.{Columns, DataTable, TableContainer, ViewPortColumnCreator} +//import org.finos.vuu.net.ClientSessionId +//import org.finos.vuu.provider.{JoinTableProvider, JoinTableProviderImpl, MockProvider, ProviderContainer} +//import org.finos.vuu.util.OutboundRowPublishQueue +//import org.finos.vuu.viewport.{TestTimeStamp, ViewPortContainer, ViewPortRange} +//import org.joda.time.LocalDateTime +//import org.scalatest.featurespec.AnyFeatureSpec +//import org.scalatest.matchers.should.Matchers +//import org.scalatest.prop.Tables.Table +// +//class PermissionFilteredViewport extends AnyFeatureSpec with Matchers with ViewPortSetup { +// +// import org.finos.vuu.viewport.TestTimeStamp.EPOCH_DEFAULT +// +// def setupPermission()(implicit lifecycleContainer: LifecycleContainer, +// timeProvider: Clock, metrics: MetricsProvider): (JoinTableProvider, DataTable, DataTable, DataTable, MockProvider, MockProvider, ViewPortContainer) = { +// +// val dateTime = new LocalDateTime(2015, 7, 24, 11, 0).toDateTime.toInstant.getMillis +// +// val ordersDef = TableDef( +// name = "orderPermission", +// keyField = "orderId", +// columns = Columns.fromNames("orderId:String", "trader:String", "ric:String", "tradeTime:Long", "quantity:Double", "ownerMask:Int"), +// joinFields = "ric", "orderId" +// ).withPermissions((vp, vs) => new TestFriendlyPermissionChecker(vp)) +// +// val pricesDef = TableDef("prices", "ric", Columns.fromNames("ric:String", "bid:Double", "ask:Double", "last:Double", "open:Double", "close:Double"), "ric") +// +// val joinDef = JoinTableDef( +// name = "orderPrices", +// baseTable = ordersDef, +// joinColumns = Columns.allFrom(ordersDef) ++ Columns.allFromExcept(pricesDef, "ric"), +// joins = +// JoinTo( +// table = pricesDef, +// joinSpec = JoinSpec(left = "ric", right = "ric", LeftOuterJoin) +// ), +// joinFields = Seq() +// ) +// +// val joinProvider = JoinTableProviderImpl() +// +// val tableContainer = new TableContainer(joinProvider) +// +// val orders = tableContainer.createTable(ordersDef) +// val prices = tableContainer.createTable(pricesDef) +// val orderPrices = tableContainer.createJoinTable(joinDef) +// +// val ordersProvider = new MockProvider(orders) +// val pricesProvider = new MockProvider(prices) +// +// val providerContainer = new ProviderContainer(joinProvider) +// +// val viewPortContainer = new ViewPortContainer(tableContainer, providerContainer) +// +// (joinProvider, orders, prices, orderPrices, ordersProvider, pricesProvider, viewPortContainer) +// } +// +// +// def tickInPermissionData(ordersProvider: MockProvider, pricesProvider: MockProvider): Unit = { +// ordersProvider.tick("NYC-0001", Map("orderId" -> "NYC-0001", "trader" -> "chris", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 100, "ric" -> "VOD.L", "ownerMask" -> PermissionSet.AlgoCoveragePermission)) +// ordersProvider.tick("NYC-0002", Map("orderId" -> "NYC-0002", "trader" -> "chris", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 200, "ric" -> "VOD.L", "ownerMask" -> PermissionSet.AlgoCoveragePermission)) +// ordersProvider.tick("NYC-0003", Map("orderId" -> "NYC-0003", "trader" -> "chris", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 300, "ric" -> "VOD.L", "ownerMask" -> PermissionSet.SalesTradingPermission)) +// ordersProvider.tick("NYC-0004", Map("orderId" -> "NYC-0004", "trader" -> "chris", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 400, "ric" -> "VOD.L", "ownerMask" -> PermissionSet.SalesTradingPermission)) +// ordersProvider.tick("NYC-0005", Map("orderId" -> "NYC-0005", "trader" -> "chris", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 500, "ric" -> "VOD.L", "ownerMask" -> PermissionSet.SalesTradingPermission)) +// ordersProvider.tick("NYC-0006", Map("orderId" -> "NYC-0006", "trader" -> "steve", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 600, "ric" -> "VOD.L", "ownerMask" -> PermissionSet.HighTouchPermission)) +// ordersProvider.tick("NYC-0007", Map("orderId" -> "NYC-0007", "trader" -> "steve", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 1000, "ric" -> "BT.L", "ownerMask" -> PermissionSet.HighTouchPermission)) +// ordersProvider.tick("NYC-0008", Map("orderId" -> "NYC-0008", "trader" -> "steve", "tradeTime" -> EPOCH_DEFAULT, "quantity" -> 500, "ric" -> "BT.L", "ownerMask" -> PermissionSet.HighTouchPermission)) +// +// pricesProvider.tick("VOD.L", Map("ric" -> "VOD.L", "bid" -> 220.0, "ask" -> 222.0)) +// pricesProvider.tick("BT.L", Map("ric" -> "BT.L", "bid" -> 500.0, "ask" -> 501.0)) +// } +// +// Feature("Permissioned Vuu Port Feature") { +// +// Scenario("Check filtering table based on permissions") { +// +// implicit val clock: Clock = new DefaultClock +// implicit val lifecycle: LifecycleContainer = new LifecycleContainer +// implicit val metrics: MetricsProvider = new MetricsProviderImpl +// +// val (joinProvider, orders, _, _, ordersProvider, pricesProvider, viewPortContainer) = setupPermission() +// +// joinProvider.start() +// +// tickInPermissionData(ordersProvider, pricesProvider) +// +// joinProvider.runOnce() +// +// val queue = new OutboundRowPublishQueue() +// val session = ClientSessionId("A", "B") +// val columns = ViewPortColumnCreator.create(orders, orders.getTableDef.columns.map(_.name).toList) +// val range = ViewPortRange(0, 20) +// val viewport = viewPortContainer.create(RequestId.oneNew(), session, queue, orders, range, columns) +// +// val permissionChecker = viewport.permissionChecker().get.asInstanceOf[TestFriendlyPermissionChecker] +// permissionChecker.addRole(PermissionSet.SalesTradingPermission) +// +// runContainersOnce(viewPortContainer, joinProvider) +// +// assertVpEq(filterByVpId(combineQs(viewport), viewport)) { +// Table( +// ("orderId" ,"trader" ,"ric" ,"tradeTime","quantity","ownerMask"), +// ("NYC-0003","chris" ,"VOD.L" ,1311544800000L,300 ,1 ), +// ("NYC-0004","chris" ,"VOD.L" ,1311544800000L,400 ,1 ), +// ("NYC-0005","chris" ,"VOD.L" ,1311544800000L,500 ,1 ) +// ) +// } +// +// permissionChecker.addRole(PermissionSet.AlgoCoveragePermission) +// +// runContainersOnce(viewPortContainer, joinProvider) +// +// assertVpEq(filterByVpId(combineQs(viewport), viewport)) { +// Table( +// ("orderId" ,"trader" ,"ric" ,"tradeTime","quantity","ownerMask"), +// ("NYC-0001","chris" ,"VOD.L" ,1311544800000L,100 ,2 ), +// ("NYC-0002","chris" ,"VOD.L" ,1311544800000L,200 ,2 ), +// ("NYC-0003","chris" ,"VOD.L" ,1311544800000L,300 ,1 ), +// ("NYC-0004","chris" ,"VOD.L" ,1311544800000L,400 ,1 ), +// ("NYC-0005","chris" ,"VOD.L" ,1311544800000L,500 ,1 ) +// ) +// } +// +// permissionChecker.removeRole(PermissionSet.AlgoCoveragePermission) +// permissionChecker.removeRole(PermissionSet.SalesTradingPermission) +// +// runContainersOnce(viewPortContainer, joinProvider) +// +// assertVpEq(filterByVpId(combineQs(viewport), viewport)) { +// Table( +// ("orderId", "trader", "ric", "tradeTime", "quantity", "ownerMask"), +// ) +// } +// +// permissionChecker.addRole(PermissionSet.HighTouchPermission) +// +// runContainersOnce(viewPortContainer, joinProvider) +// +// assertVpEq(filterByVpId(combineQs(viewport), viewport)) { +// Table( +// ("orderId" ,"trader" ,"ric" ,"tradeTime","quantity","ownerMask"), +// ("NYC-0006","steve" ,"VOD.L" ,1311544800000L,600 ,4 ), +// ("NYC-0007","steve" ,"BT.L" ,1311544800000L,1000 ,4 ), +// ("NYC-0008","steve" ,"BT.L" ,1311544800000L,500 ,4 ) +// ) +// } +// +// } +// } +//} diff --git a/vuu/src/test/scala/org/finos/vuu/core/module/auths/PermissionsTest.scala b/example/permission/src/test/scala/org/finos/vuu/core/module/auths/PermissionsTest.scala similarity index 99% rename from vuu/src/test/scala/org/finos/vuu/core/module/auths/PermissionsTest.scala rename to example/permission/src/test/scala/org/finos/vuu/core/module/auths/PermissionsTest.scala index 12ddfd34e..66f3b3dab 100644 --- a/vuu/src/test/scala/org/finos/vuu/core/module/auths/PermissionsTest.scala +++ b/example/permission/src/test/scala/org/finos/vuu/core/module/auths/PermissionsTest.scala @@ -1,12 +1,11 @@ package org.finos.vuu.core.module.auths import com.typesafe.scalalogging.StrictLogging +import org.finos.vuu.core.module.auths.PermissionSet._ import org.scalatest.GivenWhenThen import org.scalatest.featurespec.AnyFeatureSpec import org.scalatest.matchers.should.Matchers -import org.finos.vuu.core.module.auths.PermissionSet._ - class PermissionsTest extends AnyFeatureSpec with Matchers with StrictLogging with GivenWhenThen { Feature("Check our example Permission Set"){ diff --git a/vuu/src/test/scala/org/finos/vuu/viewport/auths/TestFriendlyPermissionChecker.scala b/example/permission/src/test/scala/org/finos/vuu/core/module/auths/TestFriendlyPermissionChecker.scala similarity index 91% rename from vuu/src/test/scala/org/finos/vuu/viewport/auths/TestFriendlyPermissionChecker.scala rename to example/permission/src/test/scala/org/finos/vuu/core/module/auths/TestFriendlyPermissionChecker.scala index de9252159..7426bf0af 100644 --- a/vuu/src/test/scala/org/finos/vuu/viewport/auths/TestFriendlyPermissionChecker.scala +++ b/example/permission/src/test/scala/org/finos/vuu/core/module/auths/TestFriendlyPermissionChecker.scala @@ -1,8 +1,7 @@ -package org.finos.vuu.viewport.auths +package org.finos.vuu.core.module.auths import com.typesafe.scalalogging.StrictLogging import org.finos.vuu.core.auths.RowPermissionChecker -import org.finos.vuu.core.module.auths.PermissionSet import org.finos.vuu.core.table.{Column, RowData} import org.finos.vuu.viewport.ViewPort diff --git a/example/pom.xml b/example/pom.xml new file mode 100644 index 000000000..ee65b256e --- /dev/null +++ b/example/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + + org.finos.vuu + vuu-parent + 0.9.36-SNAPSHOT + + + pom + + example + + + editable + main + order + permission + price + basket + + + + + + sign-it + + + sign + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + + + + \ No newline at end of file diff --git a/example/price/pom.xml b/example/price/pom.xml new file mode 100644 index 000000000..76d2577da --- /dev/null +++ b/example/price/pom.xml @@ -0,0 +1,294 @@ + + + 4.0.0 + + + org.finos.vuu + example + 0.9.36-SNAPSHOT + + + + price + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + + + + org.finos.vuu + vuu + 0.9.36-SNAPSHOT + tests + test-jar + test + + + + org.scala-lang + scala-library + ${scala.version} + + + + org.scala-lang + scala-reflect + ${scala.version} + + + + junit + junit + 4.13.2 + test + + + + org.scalatest + scalatest_2.13 + ${scalatest.version} + test + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + + + + + + + + + sign-it + + + sign + true + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.0.1 + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + + + + + legal-report + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + **/*.scala + + + + + + + + + + src/main/java + src/test/java + + + + + org.apache.maven.plugins + maven-source-plugin + + + + compile + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.source} + ${maven.compiler.target} + + + + org.ow2.asm + asm + 6.2 + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + + + compile + testCompile + + + + + src/main/scala + src/test/scala + + -Xms64m + -Xmx1024m + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 3.2.0 + + + generate-sources + + add-source + + + + target/generated-sources/antlr4 + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + + test-jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7 + + + + + + + org.scalatest + scalatest-maven-plugin + 2.0.2 + + ${project.build.directory}/surefire-reports + . + test-reports.txt + + + + test + + test + + + + + + + + + + + org.scala-tools + maven-scala-plugin + ${maven.scala.plugin} + + ${scala.version} + + + + + + \ No newline at end of file diff --git a/example/price/src/main/java/Dummy4JavaDoc.java b/example/price/src/main/java/Dummy4JavaDoc.java new file mode 100644 index 000000000..00b8d1897 --- /dev/null +++ b/example/price/src/main/java/Dummy4JavaDoc.java @@ -0,0 +1,2 @@ +public class Dummy4JavaDoc { +} diff --git a/vuu/src/main/scala/org/finos/vuu/core/module/price/PriceModule.scala b/example/price/src/main/scala/org/finos/vuu/core/module/price/PriceModule.scala similarity index 50% rename from vuu/src/main/scala/org/finos/vuu/core/module/price/PriceModule.scala rename to example/price/src/main/scala/org/finos/vuu/core/module/price/PriceModule.scala index a0693a425..6254f5b59 100644 --- a/vuu/src/main/scala/org/finos/vuu/core/module/price/PriceModule.scala +++ b/example/price/src/main/scala/org/finos/vuu/core/module/price/PriceModule.scala @@ -1,13 +1,44 @@ package org.finos.vuu.core.module.price +import com.typesafe.scalalogging.StrictLogging import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.time.Clock import org.finos.vuu.api.{AutoSubscribeTableDef, ViewPortDef} import org.finos.vuu.core.module.ModuleFactory.stringToString -import org.finos.vuu.core.module.simul.PricesService import org.finos.vuu.core.module.{ModuleFactory, TableDefContainer, ViewServerModule} -import org.finos.vuu.core.table.Columns +import org.finos.vuu.core.table.{Columns, DataTable} +import org.finos.vuu.net.ClientSessionId +import org.finos.vuu.net.rpc.RpcHandler +import org.finos.vuu.provider.Provider import org.finos.vuu.provider.simulation.SimulatedPricesProvider +import org.finos.vuu.viewport._ + + +class PricesService(val table: DataTable, val provider: Provider) extends RpcHandler with StrictLogging { + + private val pricesProvider = provider.asInstanceOf[SimulatedPricesProvider] + + def setSpeedSlow(selection: ViewPortSelection, sessionId: ClientSessionId):ViewPortAction = { + pricesProvider.setSpeed(8000) + NoAction() + } + + def setSpeedMedium(selection: ViewPortSelection, sessionId: ClientSessionId):ViewPortAction = { + pricesProvider.setSpeed(2000) + NoAction() + } + + def setSpeedFast(selection: ViewPortSelection, sessionId: ClientSessionId):ViewPortAction = { + pricesProvider.setSpeed(400) + NoAction() + } + + override def menuItems(): ViewPortMenu = ViewPortMenu("Root", + new SelectionViewPortMenuItem("Set Slow", "", this.setSpeedSlow, "SET_SPEED_SLOW"), + new SelectionViewPortMenuItem("Set Medium", "", this.setSpeedMedium, "SET_SPEED_MED"), + new SelectionViewPortMenuItem("Set Fast", "", this.setSpeedFast, "SET_SPEED_FAST") + ) +} object PriceModule { diff --git a/example/price/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala b/example/price/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala new file mode 100644 index 000000000..c7d824eda --- /dev/null +++ b/example/price/src/main/scala/org/finos/vuu/provider/simulation/SimulatedPricesProvider.scala @@ -0,0 +1,354 @@ +package org.finos.vuu.provider.simulation + +import com.typesafe.scalalogging.StrictLogging +import org.finos.toolbox.lifecycle.LifecycleContainer +import org.finos.toolbox.logging.LogAtFrequency +import org.finos.toolbox.thread.{LifeCycleRunner, RunInThread} +import org.finos.toolbox.time.Clock +import org.finos.vuu.core.table.{DataTable, RowWithData} +import org.finos.vuu.provider.Provider + +import java.util.Random +import java.util.concurrent.ConcurrentHashMap +import scala.jdk.CollectionConverters._ + +trait SimulationMode { + def asCode: Int +} + +case class Simulation(mode: SimulationMode, beganAt: Long, endAt: Long) + +case object TakeAWalk extends SimulationMode { + override def asCode: Int = 1 +} + +case object WidenBidAsk extends SimulationMode { + override def asCode: Int = 2 +} + +case object FastTick extends SimulationMode { + override def asCode: Int = 3 +} + +case object NoOp extends SimulationMode { + override def asCode: Int = 4 +} + +case object Close extends SimulationMode { + override def asCode: Int = 5 +} + +case object Open extends SimulationMode { + override def asCode: Int = 6 +} + +object PricesFields { + final val Ric = "ric" + final val Bid = "bid" + final val Ask = "ask" + final val BidSize = "bidSize" + final val AskSize = "askSize" + final val Last = "last" + final val Close = "close" + final val Open = "open" + final val Scenario = "scenario" + final val Phase = "phase" +} + +class SimulatedPricesProvider(val table: DataTable, @volatile var maxSleep: Int = 400)(implicit val timeProvider: Clock, lifecycle: LifecycleContainer) extends Provider with StrictLogging with RunInThread { + private val currentModes = new ConcurrentHashMap[String, Simulation]() + private val states = new ConcurrentHashMap[String, Map[String, Any]]() + + private var cycleCount = 0 + + val runner = new LifeCycleRunner("pricesProvider", () => runOnce()) + + lifecycle(this).dependsOn(runner) + + val logAt = new LogAtFrequency(10_000) + + val doEvery5Mins = new LogAtFrequency(1000 * 60 * 3) + + def setSpeed(maxSpeed: Int): Unit = { + this.maxSleep = maxSpeed + } + + override def subscribe(key: String): Unit = { + //logger.info(s"Prices Subscribe Called: ${key}") + val began = timeProvider.now() + val end = began + seededRand(began, 100, 1000) + currentModes.put(key, Simulation(NoOp, began, end)) + } + + private def seededRand(seed: Long, low: Int, high: Int): Int = { + val r = new Random(seed) + r.nextInt(high - low) + low + } + + override def runOnce(): Unit = { + + val entrySet = SetHasAsScala(currentModes.entrySet()).asScala + + // if(logAt.shouldLog()){ + // logger.info("Cycle Count = " + cycleCount) + // } + + if (doEvery5Mins.shouldLog()) { + val startOfOpen = timeProvider.now() + 5_000 + logger.info("[PRICES] Moving into Closed Market...") + entrySet.foreach(me => { + closeMarket(me.getKey, startOfOpen) + }) + } + else { + entrySet.foreach(me => { + processOne(me.getKey, me.getValue) + }) + } + + cycleCount += 1 + + timeProvider.sleep(seededRand(timeProvider.now(), 10, maxSleep)) + } + + protected def closeMarket(ric: String, timeToOpen: Long): Unit = { + val newRow = getState(ric) match { + case Some(row) => mergeLeft(row, close(ric, row)) + case None => Map(f.Ric -> ric) //do nothing + } + + currentModes.put(ric, Simulation(Close, this.timeProvider.now(), timeToOpen)) + + setState(ric, newRow) + table.processUpdate(ric, RowWithData(ric, newRow), timeProvider.now()) + } + + protected def processOne(ric: String, simulation: Simulation): Unit = { + val newRow = if (simulation.endAt <= timeProvider.now()) { + if (simulation.mode.equals(Close)) { + assignSpecificSimulation(ric, Open) + } + else { + assignNewSimulation(ric) + } + } else { + simulation.mode match { + case NoOp => doNoOp(ric) + case TakeAWalk => doTakeAWalk(ric) + case WidenBidAsk => + doWidenBidAndAsk(ric) + case FastTick => doFastTick(ric) + case Close => doCloseTick(ric) + case Open => doOpenTick(ric) + } + } + + setState(ric, newRow) + + table.processUpdate(ric, RowWithData(ric, newRow), timeProvider.now()) + } + + private def getState(ric: String): Option[Map[String, Any]] = { + val theState = states.get(ric) + Option(theState) + } + + private def setState(ric: String, row: Map[String, Any]): Unit = { + states.put(ric, row) + } + + protected def doTakeAWalk(ric: String): Map[String, Any] = { + val smallInc = seededRand(timeProvider.now(), 0, 100) + + val newRow = getState(ric) match { + case Some(row) => mergeLeft(row, walkBidAndAsk(ric, row)) + case None => buildSampleRow(ric) + } + newRow + } + + val f: PricesFields.type = PricesFields + + private def close(ric: String, existing: Map[String, Any]): Map[String, Any] = { + + val price = existing.get(f.Bid) match { + case Some(bid) => bid + case None => existing.get(f.Ask) match { + case Some(ask) => ask + case None => existing.get(f.Last) match { + case Some(last) => last + case None => seededRand(timeProvider.now(), 0, 10000) + } + } + } + + Map(f.Ric -> ric, f.Close -> price, f.Open -> null, f.Scenario -> "close", f.Phase -> "X") + } + + private def walkBidAndAsk(ric: String, existing: Map[String, Any]) = { + if (!existing.contains(f.Bid)) + buildSampleRow(existing(f.Ric).asInstanceOf[String]) + else { + val bid = existing(f.Bid).asInstanceOf[Double] + val ask = existing(f.Ask).asInstanceOf[Double] + val diff = ask - bid + val inc = seededRand(timeProvider.now(), 0, 50) + val delta = (inc / 100).asInstanceOf[Double] + + Map(f.Ric -> ric, f.Bid -> (bid + delta), f.Ask -> (ask + delta), f.Scenario -> "walkBidAsk", f.Phase -> "C") + } + } + + def BidAskSize(): Map[String, Any] = { + val bidSize = seededRand(timeProvider.now(), 1, 20) * 100 + val askSize = seededRand(timeProvider.now(), 1, 20) * 100 + Map(f.BidSize -> bidSize, f.AskSize -> askSize) + } + + def BidAskSizeNull(): Map[String, Any] = { + Map(f.BidSize -> null, f.AskSize -> null) + } + + protected def mergeLeft(existing: Map[String, Any], newMap: Map[String, Any]): Map[String, Any] = { + existing ++ newMap + } + + protected def buildSampleRow(ric: String): Map[String, Any] = { + val basePrice = seededRand(timeProvider.now(), 0, 10000) + val adjusted = (basePrice / 100).asInstanceOf[Double] + val spread = seededRand(timeProvider.now(), 0, 100) + val adjustedSpread = (spread / 100).asInstanceOf[Double] + val askSize = seededRand(timeProvider.now(), 0, 1000) + val bidSize = seededRand(timeProvider.now(), 0, 2000) + + Map(f.Ric -> ric, f.Ask -> (adjusted + adjustedSpread), f.Bid -> (adjusted - adjustedSpread), f.Phase -> "C") ++ BidAskSize() + } + + final val MaxSpread = 100 + + protected def doWidenBidAndAsk(ric: String): Map[String, Any] = { + if (!states.get(ric).contains(ric)) { + seedStartValues(ric) + } else { + val spread = seededRand(timeProvider.now(), 1, 80) + getState(ric) match { + case Some(state) => + val bid = state(f.Bid).asInstanceOf[Double] + val ask = state(f.Ask).asInstanceOf[Double] + val spread = ask - bid + val activeSpread = if (spread > MaxSpread) + 0.0 + else + spread + + val newBid = bid - activeSpread + val newAsk = ask + activeSpread + + Map(f.Ric -> ric, f.Ask -> newAsk, f.Bid -> newBid, f.Scenario -> "widenBidAndAsk", f.Phase -> "C") ++ BidAskSize() + case None => throw new Exception("shouldn't get here") + } + } + } + + protected def doFastTick(ric: String): Map[String, Any] = { + + if (!states.get(ric).contains(f.Bid)) + seedStartValues(ric) + else { + val bidAdjust = seededRand(timeProvider.now(), 0, 10) + val askAdjust = seededRand(timeProvider.now(), 0, 20) + val bid = states.get(ric)(f.Bid).asInstanceOf[Double] + bidAdjust + val ask = states.get(ric)(f.Ask).asInstanceOf[Double] + askAdjust + val last = states.get(ric)(f.Ask).asInstanceOf[Double] + (askAdjust / 2) + Map(f.Ric -> ric, f.Ask -> ask, f.Bid -> bid, f.Scenario -> "fastTick", f.Last -> last, f.Phase -> "C") ++ BidAskSize() + } + } + + protected def doOpenTick(ric: String): Map[String, Any] = { + + if (!states.get(ric).contains(f.Bid)) + seedStartValues(ric) + else { + val bidAdjust = seededRand(timeProvider.now(), 0, 10) + val askAdjust = seededRand(timeProvider.now(), 0, 20) + val bid = states.get(ric)(f.Bid).asInstanceOf[Double] + bidAdjust + val ask = states.get(ric)(f.Ask).asInstanceOf[Double] + askAdjust + val open = states.get(ric)(f.Ask).asInstanceOf[Double] + (askAdjust / 2) + Map(f.Ric -> ric, f.Scenario -> "open", f.Open -> open, f.Phase -> "O") ++ BidAskSize() + } + } + + protected def doCloseTick(ric: String): Map[String, Any] = { + + if (!states.get(ric).contains(f.Bid)) + seedStartValues(ric) + else { + val bidAdjust = seededRand(timeProvider.now(), 0, 10) + val askAdjust = seededRand(timeProvider.now(), 0, 20) + val bid = states.get(ric)(f.Bid).asInstanceOf[Double] + bidAdjust + val ask = states.get(ric)(f.Ask).asInstanceOf[Double] + askAdjust + val open = states.get(ric)(f.Ask).asInstanceOf[Double] + (askAdjust / 2) + Map(f.Ric -> ric, f.Scenario -> "close", f.Phase -> "X") ++ BidAskSizeNull() + } + } + + protected def seedStartValues(ric: String): Map[String, Any] = { + val bid: Double = seededRand(timeProvider.now(), 0, 1000) + val ask: Double = bid + (bid / 100) + val bidSize = seededRand(timeProvider.now(), 0, 1000) + val askSize = seededRand(timeProvider.now(), 0, 1000) + Map(f.Ric -> ric, f.Ask -> ask, f.Bid -> bid, f.Phase -> "C") ++ BidAskSize() + } + + protected def doNoOp(ric: String): Map[String, Any] = { + getState(ric) match { + case Some(row) => mergeLeft(row, Map[String, Any](f.Scenario -> "noop")) + case None => buildSampleRow(ric) + } + } + + protected def assignNewSimulation(ric: String): Map[String, Any] = { + val strategy = seededRand(timeProvider.now(), 1, 4) + val impl = strategy match { + case 1 => TakeAWalk + case 2 => WidenBidAsk + case 3 => FastTick + case 4 => NoOp + } + + val begin = timeProvider.now() + val end = seededRand(begin, 10, 10000) + + currentModes.put(ric, Simulation(impl, begin, begin + end)) + + val existing = states.get(ric) + if (existing == null) + buildSampleRow(ric) + else + existing + } + + protected def assignSpecificSimulation(ric: String, impl: SimulationMode): Map[String, Any] = { + + val begin = timeProvider.now() + val end = seededRand(begin, 9_000, 10_000) + + currentModes.put(ric, Simulation(impl, begin, begin + end)) + + val existing = states.get(ric) + if (existing == null) + buildSampleRow(ric) + else + existing + } + + override def doStop(): Unit = {} + + override def doStart(): Unit = {} + + override def doInitialize(): Unit = {} + + override def doDestroy(): Unit = {} + + override val lifecycleId: String = "simulationPrices" +} diff --git a/vuu/src/test/scala/org/finos/vuu/provider/simulation/SimulatedPricesProviderTest.scala b/example/price/src/test/scala/org/finos/vuu/provider/simulation/SimulatedPricesProviderTest.scala similarity index 95% rename from vuu/src/test/scala/org/finos/vuu/provider/simulation/SimulatedPricesProviderTest.scala rename to example/price/src/test/scala/org/finos/vuu/provider/simulation/SimulatedPricesProviderTest.scala index 0143e9fb3..0cada0f1f 100644 --- a/vuu/src/test/scala/org/finos/vuu/provider/simulation/SimulatedPricesProviderTest.scala +++ b/example/price/src/test/scala/org/finos/vuu/provider/simulation/SimulatedPricesProviderTest.scala @@ -1,15 +1,15 @@ package org.finos.vuu.provider.simulation -import org.finos.vuu.api.TableDef -import org.finos.vuu.core.table.{Columns, SimpleDataTable, ViewPortColumnCreator} -import org.finos.vuu.provider.TestFriendlyJoinTableProvider import org.finos.toolbox.jmx.{MetricsProvider, MetricsProviderImpl} import org.finos.toolbox.lifecycle.LifecycleContainer import org.finos.toolbox.text.AsciiUtil -import org.finos.toolbox.time.{Clock, TestFriendlyClock} +import org.finos.toolbox.time.TestFriendlyClock +import org.finos.vuu.api.TableDef +import org.finos.vuu.core.table.{Columns, SimpleDataTable, ViewPortColumnCreator} import org.scalatest.featurespec.AnyFeatureSpec import org.scalatest.matchers.should.Matchers + class SimulatedPricesProviderTest extends AnyFeatureSpec with Matchers { final val TEST_TIME = 1450770869442L diff --git a/example/price/src/test/scala/org/finos/vuu/provider/simulation/TestFriendlyJoinTableProvider.scala b/example/price/src/test/scala/org/finos/vuu/provider/simulation/TestFriendlyJoinTableProvider.scala new file mode 100644 index 000000000..77769a463 --- /dev/null +++ b/example/price/src/test/scala/org/finos/vuu/provider/simulation/TestFriendlyJoinTableProvider.scala @@ -0,0 +1,21 @@ +package org.finos.vuu.provider.simulation + +import org.finos.vuu.core.table.{DataTable, JoinTableUpdate} +import org.finos.vuu.provider.JoinTableProvider + +import java.util + +class TestFriendlyJoinTableProvider extends JoinTableProvider { + override def hasJoins(tableName: String): Boolean = {false} + override def sendEvent(tableName: String, ev: util.HashMap[String, Any]): Unit = {} + override def addJoinTable(join: DataTable): Unit = {} + override def runOnce(): Unit = {} + override def start(): Unit = ??? + + override def doStop(): Unit = ??? + override def doStart(): Unit = ??? + override def doInitialize(): Unit = ??? + override def doDestroy(): Unit = ??? + override val lifecycleId: String = "testFriendlyJoinProvider" + override def drainQueue_ForTesting(): (Int, util.ArrayList[JoinTableUpdate]) = ??? +} diff --git a/pom.xml b/pom.xml index 31a023435..0625fbcf6 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.finos.vuu vuu-parent - 0.5.09-SNAPSHOT + 0.9.36-SNAPSHOT vuu-parent Vuu - A View Server in Scala and React https://github.com/finos/vuu @@ -84,6 +84,7 @@ vuu-ui layout-server benchmark + example diff --git a/toolbox/pom.xml b/toolbox/pom.xml index 570505e93..82c59c8cc 100644 --- a/toolbox/pom.xml +++ b/toolbox/pom.xml @@ -4,7 +4,7 @@ org.finos.vuu vuu-parent - 0.5.09-SNAPSHOT + 0.9.36-SNAPSHOT toolbox diff --git a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts index 23b750484..81d4c7f6c 100644 --- a/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts +++ b/vuu-ui/packages/vuu-data-react/src/hooks/useVuuMenuActions.ts @@ -1,12 +1,7 @@ import { DataSource, - DataSourceMenusMessage, DataSourceVisualLinkCreatedMessage, - DataSourceVisualLinkRemovedMessage, - DataSourceVisualLinksMessage, MenuRpcResponse, - VuuFeatureInvocationMessage, - VuuFeatureMessage, VuuUIMessageInRPCEditReject, VuuUIMessageInRPCEditResponse, } from "@finos/vuu-data"; @@ -16,8 +11,7 @@ import { MenuActionHandler, MenuBuilder, } from "@finos/vuu-data-types"; -import { GridAction } from "@finos/vuu-datagrid-types"; -import { getFilterPredicate } from "@finos/vuu-filter-parser"; +import {getFilterPredicate} from "@finos/vuu-filter-parser"; import { ClientToServerMenuCellRPC, ClientToServerMenuRowRPC, @@ -34,8 +28,8 @@ import { isGroupMenuItemDescriptor, metadataKeys, } from "@finos/vuu-utils"; -import type { MenuActionClosePopup } from "@finos/vuu-popups"; -import { useCallback } from "react"; +import type {MenuActionClosePopup} from "@finos/vuu-popups"; +import {useCallback} from "react"; export const addRowsFromInstruments = "addRowsFromInstruments"; @@ -44,12 +38,13 @@ export interface VuuCellMenuItem extends VuuMenuItem { field: string; value: VuuRowDataItemType; } + export interface VuuRowMenuItem extends VuuMenuItem { rowKey: string; row: { [key: string]: VuuRowDataItemType }; } -const { KEY } = metadataKeys; +const {KEY} = metadataKeys; const NO_CONFIG: MenuActionConfig = {}; @@ -111,7 +106,7 @@ const gridRowMeetsFilterCriteria = ( const getMenuRpcRequest = ( options: VuuMenuItem ): Omit => { - const { rpcName } = options; + const {rpcName} = options; if (isCellMenu(options)) { return { field: options.field, @@ -185,11 +180,11 @@ export type VuuServerMenuOptions = { columnMap: ColumnMap; columnName: string; row: DataSourceRow; - selectedRowsCount: number; + selectedRows: DataSourceRow[]; viewport: string; }; -const hasFilter = ({ filter }: VuuMenuItem) => +const hasFilter = ({filter}: VuuMenuItem) => typeof filter === "string" && filter.length > 0; const getMenuItemOptions = ( @@ -266,12 +261,12 @@ const buildMenuDescriptor = ( }; } else { const children = menu.menus - .map((childMenu) => - buildMenuDescriptor(childMenu, tableLocation, options) - ) - .filter( - (childMenu) => childMenu !== undefined - ) as ContextMenuItemDescriptor[]; + .map((childMenu) => + buildMenuDescriptor(childMenu, tableLocation, options) + ) + .filter( + (childMenu) => childMenu !== undefined + ) as ContextMenuItemDescriptor[]; if (children.length > 0) { return { label: menu.name, @@ -283,20 +278,20 @@ const buildMenuDescriptor = ( }; export const useVuuMenuActions = ({ - clientSideMenuActionHandler, - dataSource, - menuActionConfig = NO_CONFIG, - onRpcResponse, -}: VuuMenuActionHookProps): ViewServerHookResult => { + clientSideMenuActionHandler, + dataSource, + menuActionConfig = NO_CONFIG, + onRpcResponse, + }: VuuMenuActionHookProps): ViewServerHookResult => { const buildViewserverMenuOptions: MenuBuilder = useCallback( (location, options) => { - const { links, menu } = dataSource; - const { visualLink } = menuActionConfig; + const {links, menu} = dataSource; + const {visualLink} = menuActionConfig; const descriptors: ContextMenuItemDescriptor[] = []; if (location === "grid" && links && !visualLink) { links.forEach((linkDescriptor: LinkDescriptorWithLabel) => { - const { link, label: linkLabel } = linkDescriptor; + const {link, label: linkLabel} = linkDescriptor; const label = linkLabel ? linkLabel : link.toTable; descriptors.push({ label: `Link to ${label}`, @@ -325,7 +320,7 @@ export const useVuuMenuActions = ({ ); const handleMenuAction = useCallback( - ({ menuId, options }: MenuActionClosePopup) => { + ({menuId, options}: MenuActionClosePopup) => { if (clientSideMenuActionHandler?.(menuId, options)) { return true; } else if (menuId === "MENU_RPC_CALL") { diff --git a/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts b/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts index efec2dc88..cd47eda97 100644 --- a/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts +++ b/vuu-ui/packages/vuu-data-test/src/TickingArrayDataSource.ts @@ -7,10 +7,6 @@ import { VuuUIMessageInRPCEditReject, VuuUIMessageInRPCEditResponse, } from "@finos/vuu-data"; -import { - UpdateGenerator, - UpdateHandler, -} from "@finos/vuu-data-test/src/rowUpdates"; import { DataSourceRow } from "@finos/vuu-data-types"; import { ClientToServerEditRpc, @@ -19,6 +15,7 @@ import { VuuRange, VuuRowDataItemType, } from "@finos/vuu-protocol-types"; +import { UpdateGenerator, UpdateHandler } from "./rowUpdates"; import { Table } from "./Table"; export type RpcService = { @@ -38,6 +35,7 @@ export interface TickingArrayDataSourceConstructorProps export class TickingArrayDataSource extends ArrayDataSource { #rpcServices: RpcService[] | undefined; #updateGenerator: UpdateGenerator | undefined; + constructor({ data, rpcServices, @@ -87,7 +85,7 @@ export class TickingArrayDataSource extends ArrayDataSource { switch (updateType) { case "U": { const [rowIndex, ...updates] = updateRecord; - const row = data[rowIndex].slice() as DataSourceRow; + const row = data[rowIndex as number].slice() as DataSourceRow; if (row) { for (let i = 0; i < updates.length; i += 2) { const colIdx = updates[i] as number; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/basket-module.ts b/vuu-ui/packages/vuu-data-test/src/basket/basket-module.ts index 6feec1009..4c06d6bb5 100644 --- a/vuu-ui/packages/vuu-data-test/src/basket/basket-module.ts +++ b/vuu-ui/packages/vuu-data-test/src/basket/basket-module.ts @@ -7,7 +7,7 @@ import ftse from "./reference-data/ftse100"; import nasdaq from "./reference-data/nasdaq100"; import sp500 from "./reference-data/sp500"; import hsi from "./reference-data/hsi"; -import { VuuMenu } from "@finos/vuu-protocol-types"; +import { VuuMenu, VuuRowDataItemType } from "@finos/vuu-protocol-types"; import { Table } from "../Table"; // This is a 'local' columnMap @@ -21,7 +21,6 @@ const buildDataColumnMap = (tableName: BasketsTableName) => ); //--------------- -// export const BasketColumnMap = buildColumnMap("basket"); const { KEY } = metadataKeys; @@ -116,18 +115,18 @@ function createTradingBasket(basketId: string, basketName: string) { ); constituents.forEach(([, , description, , ric, , , quantity, weighting]) => { - const algo = undefined; + const algo = ""; const algoParams = ""; const limitPrice = 95; const notionalLocal = 0; const notionalUsd = 0; const pctFilled = 0; const priceSpread = 0; - const priceStrategyId = undefined; - const side = "buy"; + const priceStrategyId = ""; + const side = "BUY"; const venue = "venue"; - const basketTradingConstituentRow = [ + const basketTradingConstituentRow: VuuRowDataItemType[] = [ algo, algoParams, basketId, @@ -157,6 +156,7 @@ function createTradingBasket(basketId: string, basketName: string) { const open = 0; const phase = "market"; const scenario = "scenario"; + const status = "on market"; const basketTradingConstituentJoinRow = [ algo, @@ -183,6 +183,7 @@ function createTradingBasket(basketId: string, basketName: string) { ric, scenario, side, + status, venue, weighting, ]; @@ -201,7 +202,19 @@ async function createNewBasket(rpcRequest: any) { //------------------- -const tables: Record = { +const tableMaps: Record = { + algoType: buildDataColumnMap("algoType"), + basket: buildDataColumnMap("basket"), + basketTrading: buildDataColumnMap("basketTrading"), + basketTradingConstituent: buildDataColumnMap("basketTradingConstituent"), + basketConstituent: buildDataColumnMap("basketConstituent"), + basketTradingConstituentJoin: buildDataColumnMap( + "basketTradingConstituentJoin" + ), + priceStrategyType: buildDataColumnMap("priceStrategyType"), +}; + +export const tables: Record = { algoType: new Table(schemas.algoType, [ ["Sniper", 0], ["Dark Liquidity", 1], @@ -277,10 +290,11 @@ const createDataSource = (tableName: BasketsTableName) => { const { key } = schemas[tableName]; return new TickingArrayDataSource({ columnDescriptors, + dataMap: tableMaps[tableName], keyColumn: key, - table: tables[tableName], menu: menus[tableName], rpcServices: services[tableName], + table: tables[tableName], // updateGenerator: createUpdateGenerator?.(), }); }; diff --git a/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts b/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts index 6141d59d6..a22887943 100644 --- a/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts +++ b/vuu-ui/packages/vuu-data-test/src/basket/basket-schemas.ts @@ -53,6 +53,7 @@ export const schemas: Readonly< { name: "filledPct", serverDataType: "double" }, { name: "fxRateToUsd", serverDataType: "double" }, { name: "instanceId", serverDataType: "string" }, + { name: "side", serverDataType: "string" }, { name: "status", serverDataType: "string" }, { name: "totalNotional", serverDataType: "double" }, { name: "totalNotionalUsd", serverDataType: "double" }, @@ -78,6 +79,7 @@ export const schemas: Readonly< { name: "quantity", serverDataType: "long" }, { name: "ric", serverDataType: "string" }, { name: "side", serverDataType: "string" }, + { name: "status", serverDataType: "string" }, { name: "venue", serverDataType: "string" }, { name: "weighting", serverDataType: "double" }, ], @@ -111,6 +113,7 @@ export const schemas: Readonly< { name: "ric", serverDataType: "string" }, { name: "scenario", serverDataType: "string" }, { name: "side", serverDataType: "string" }, + { name: "status", serverDataType: "string" }, { name: "venue", serverDataType: "string" }, { name: "weighting", serverDataType: "double" }, ], diff --git a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts index fb63f576d..5933c46ae 100644 --- a/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts +++ b/vuu-ui/packages/vuu-data-test/src/basket/data-generators/index.ts @@ -5,11 +5,14 @@ import basketConstituentGenerators from "./basketConstituent-generator"; import basketTradingGenerators from "./basketTrading-generator"; import basketTradingConstituentGenerators from "./basketTradingConstituent-generator"; -const generators: Record = { +const generators: Record = { + algoType: undefined, basket: basketGenerators, basketConstituent: basketConstituentGenerators, basketTrading: basketTradingGenerators, basketTradingConstituent: basketTradingConstituentGenerators, + basketTradingConstituentJoin: basketTradingConstituentGenerators, + priceStrategyType: undefined, }; export default generators; diff --git a/vuu-ui/packages/vuu-data-test/src/simul/OrderUpdateGenerator.ts b/vuu-ui/packages/vuu-data-test/src/simul/OrderUpdateGenerator.ts index 5dfa16b9d..84d8f79b5 100644 --- a/vuu-ui/packages/vuu-data-test/src/simul/OrderUpdateGenerator.ts +++ b/vuu-ui/packages/vuu-data-test/src/simul/OrderUpdateGenerator.ts @@ -8,15 +8,8 @@ import type { UpdateGenerator, UpdateHandler, } from "../rowUpdates"; -import { random } from "./reference-data"; import { metadataKeys } from "@finos/vuu-utils"; -const getNewValue = (value: number) => { - const multiplier = random(0, 100) / 1000; - const direction = random(0, 10) >= 5 ? 1 : -1; - return value + value * multiplier * direction; -}; - let _orderId = 1; const orderId = () => `0000000${_orderId++}`.slice(-3); const createOrder = (): ["I", ...VuuRowDataItemType[]] => { @@ -45,7 +38,7 @@ export class OrderUpdateGenerator implements UpdateGenerator { private timer: number | undefined; private phase: OrderPhase = "create-order"; private orderCount: number; - private columnMap: ColumnMap; + private columnMap?: ColumnMap; constructor(orderCount = 20) { this.orderCount = orderCount; @@ -103,7 +96,7 @@ export class OrderUpdateGenerator implements UpdateGenerator { console.log("fill-order"); const data = this.dataSource?.data; let filledCount = 0; - if (data) { + if (data && this.columnMap) { const count = data.length; const { IDX } = metadataKeys; const { filledQuantity: filledKey, quantity: qtyKey } = @@ -116,8 +109,8 @@ export class OrderUpdateGenerator implements UpdateGenerator { } = order; if (filledQty < quantity) { const newFilledQty = Math.min( - quantity, - Math.max(100, filledQty * 1.1) + quantity as number, + Math.max(100, (filledQty as number) * 1.1) ); updates.push(["U", rowIdx, filledKey, newFilledQty]); } else { diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts b/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts index 7012f9505..839ea1821 100644 --- a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts +++ b/vuu-ui/packages/vuu-data/src/array-data-source/array-data-source.ts @@ -6,7 +6,6 @@ import { ClientToServerMenuRPC, LinkDescriptorWithLabel, VuuAggregation, - VuuColumnDataType, VuuGroupBy, VuuMenu, VuuRange, @@ -19,10 +18,8 @@ import { EventEmitter, getAddedItems, getMissingItems, - getSelectionStatus, KeySet, logger, - metadataKeys, NULL_RANGE, rangeNewItems, resetRange, @@ -54,18 +51,18 @@ import { import { aggregateData } from "./aggregate-utils"; import { collapseGroup, expandGroup, GroupMap, groupRows } from "./group-utils"; import { sortRows } from "./sort-utils"; +import { buildDataToClientMap, toClientRow } from "./array-data-utils"; export interface ArrayDataSourceConstructorProps extends Omit { columnDescriptors: ColumnDescriptor[]; data: Array; + dataMap?: ColumnMap; keyColumn?: string; rangeChangeRowset?: "delta" | "full"; } const { debug } = logger("ArrayDataSource"); -const { RENDER_IDX, SELECTED } = metadataKeys; - const toDataSourceRow = (key: number) => (data: VuuRowDataItemType[], index: number): DataSourceRow => { @@ -88,24 +85,18 @@ const buildTableSchema = ( return schema; }; -const toClientRow = ( - row: DataSourceRow, - keys: KeySet, - selection: Selection -) => { - const [rowIndex] = row; - const clientRow = row.slice() as DataSourceRow; - clientRow[RENDER_IDX] = keys.keyFor(rowIndex); - clientRow[SELECTED] = getSelectionStatus(selection, rowIndex); - return clientRow; -}; - export class ArrayDataSource extends EventEmitter implements DataSource { private clientCallback: SubscribeCallback | undefined; private columnDescriptors: ColumnDescriptor[]; + /** sorted offsets of data within raw data, reflecting sort order + * of columns specified by client. + */ + private dataIndices: number[] | undefined; + /** Map reflecting positions of data items in raw data */ + private dataMap: ColumnMap | undefined; private disabled = false; private groupedData: undefined | DataSourceRow[]; private groupMap: undefined | GroupMap; @@ -117,6 +108,7 @@ export class ArrayDataSource private rangeChangeRowset: "delta" | "full"; private openTreeNodes: string[] = []; + /** Map reflecting positions of columns in client data sent to user */ #columnMap: ColumnMap; #config: WithFullConfig = vanillaConfig; #data: readonly DataSourceRow[]; @@ -140,6 +132,7 @@ export class ArrayDataSource // different from RemoteDataSource columnDescriptors, data, + dataMap, filter, groupBy, keyColumn, @@ -157,20 +150,19 @@ export class ArrayDataSource } this.columnDescriptors = columnDescriptors; + this.dataMap = dataMap; this.key = keyColumn ? this.columnDescriptors.findIndex((col) => col.name === keyColumn) : 0; this.rangeChangeRowset = rangeChangeRowset; this.tableSchema = buildTableSchema(columnDescriptors, keyColumn); this.viewport = viewport || uuid(); - this.#size = data.length; - this.#title = title; const columns = columnDescriptors.map((col) => col.name); - this.#columnMap = buildColumnMap(columns); + this.dataIndices = buildDataToClientMap(this.#columnMap, this.dataMap); this.#data = data.map(toDataSourceRow(this.key)); this.config = { @@ -463,7 +455,9 @@ export class ArrayDataSource const rowsWithinViewport = data .slice(rowRange.from, rowRange.to) - .map((row) => toClientRow(row, this.keys, this.selectedRows)); + .map((row) => + toClientRow(row, this.keys, this.selectedRows, this.dataIndices) + ); this.clientCallback?.({ clientViewportId: this.viewport, @@ -498,9 +492,11 @@ export class ArrayDataSource }); } this.#columnMap = buildColumnMap(columns); - console.log({ - columnMap: this.#columnMap, - }); + this.dataIndices = buildDataToClientMap(this.#columnMap, this.dataMap); + + const dataToClientMap = buildDataToClientMap(this.#columnMap, this.dataMap); + console.log({ dataToClientMap }); + this.config = { ...this.#config, columns, diff --git a/vuu-ui/packages/vuu-data/src/array-data-source/array-data-utils.ts b/vuu-ui/packages/vuu-data/src/array-data-source/array-data-utils.ts new file mode 100644 index 000000000..94b160251 --- /dev/null +++ b/vuu-ui/packages/vuu-data/src/array-data-source/array-data-utils.ts @@ -0,0 +1,69 @@ +import { DataSourceRow } from "@finos/vuu-data-types"; +import { Selection } from "@finos/vuu-datagrid-types"; +import { + ColumnMap, + getSelectionStatus, + KeySet, + metadataKeys, +} from "@finos/vuu-utils"; + +const { RENDER_IDX, SELECTED } = metadataKeys; + +export const toClientRow = ( + row: DataSourceRow, + keys: KeySet, + selection: Selection, + dataIndices?: number[] +) => { + const [rowIndex] = row; + let clientRow; + if (dataIndices) { + // If client has specified a different ordering of columns from the way they are + // ordered inn the underlying data, this is where we effect the ordering. + const { count } = metadataKeys; + clientRow = row + .slice(0, count) + .concat(dataIndices.map((idx) => row[idx])) as DataSourceRow; + } else { + clientRow = row.slice() as DataSourceRow; + } + clientRow[RENDER_IDX] = keys.keyFor(rowIndex); + clientRow[SELECTED] = getSelectionStatus(selection, rowIndex); + return clientRow; +}; + +const divergentMaps = (columnMap: ColumnMap, dataMap?: ColumnMap) => { + if (dataMap) { + const { count: mapOffset } = metadataKeys; + for (const [columnName, index] of Object.entries(columnMap)) { + const dataIdx = dataMap[columnName]; + if (dataIdx === undefined) { + throw Error( + `ArrayDataSource column ${columnName} is not in underlying data set` + ); + } else if (dataIdx !== index - mapOffset) { + return true; + } + } + } + return false; +}; + +const getDataIndices = (columnMap: ColumnMap, dataMap: ColumnMap) => { + const { count: mapOffset } = metadataKeys; + const result: number[] = []; + Object.entries(columnMap).forEach(([columnName]) => { + result.push(dataMap[columnName] + mapOffset); + }); + return result; +}; + +export const buildDataToClientMap = ( + columnMap: ColumnMap, + dataMap?: ColumnMap +): number[] | undefined => { + if (dataMap && divergentMaps(columnMap, dataMap)) { + return getDataIndices(columnMap, dataMap); + } + return undefined; +}; diff --git a/vuu-ui/packages/vuu-data/src/connection-manager.ts b/vuu-ui/packages/vuu-data/src/connection-manager.ts index 33ed5c37d..9f4f71591 100644 --- a/vuu-ui/packages/vuu-data/src/connection-manager.ts +++ b/vuu-ui/packages/vuu-data/src/connection-manager.ts @@ -6,17 +6,14 @@ import { VuuTable, VuuTableList, } from "@finos/vuu-protocol-types"; -import { - EventEmitter, - getLoggingConfigForWorker, - uuid, -} from "@finos/vuu-utils"; +import {EventEmitter, getLoggingConfigForWorker, uuid,} from "@finos/vuu-utils"; import { DataSourceCallbackMessage, shouldMessageBeRoutedToDataSource as messageShouldBeRoutedToDataSource, } from "./data-source"; import * as Message from "./server-proxy/messages"; import { + ConnectionQualityMetrics, ConnectionStatusMessage, isConnectionQualityMetrics, isConnectionStatusMessage, @@ -31,10 +28,9 @@ import { } from "./vuuUIMessageTypes"; // Note: inlined-worker is a generated file, it must be built -import { workerSourceCode } from "./inlined-worker"; -import { ConnectionQualityMetrics } from "./vuuUIMessageTypes"; -import { WebSocketProtocol } from "./websocket-connection"; -import { TableSchema } from "./message-utils"; +import {workerSourceCode} from "./inlined-worker"; +import {WebSocketProtocol} from "./websocket-connection"; +import {TableSchema} from "./message-utils"; const workerBlob = new Blob([getLoggingConfigForWorker() + workerSourceCode], { type: "text/javascript", @@ -89,17 +85,17 @@ type WorkerOptions = { // connection status messages before that, so we forward them to caller // while they wait for worker. const getWorker = async ({ - handleConnectionStatusChange, - protocol, - retryLimitDisconnect, - retryLimitStartup, - token = "", - username, - url, -}: WorkerOptions) => { + handleConnectionStatusChange, + protocol, + retryLimitDisconnect, + retryLimitStartup, + token = "", + username, + url, + }: WorkerOptions) => { if (token === "" && pendingWorker === undefined) { return new Promise((resolve) => { - pendingWorkerNoToken.push({ resolve }); + pendingWorkerNoToken.push({resolve}); }); } //FIXME If we have a pending request already and a new request arrives with a DIFFERENT @@ -119,7 +115,7 @@ const getWorker = async ({ // establishing a connection. When we resolve the worker, a runtime message // handler will replace this (see below) worker.onmessage = (msg: MessageEvent) => { - const { data: message } = msg; + const {data: message} = msg; if (message.type === "ready") { window.clearTimeout(timer); worker.postMessage({ @@ -139,7 +135,7 @@ const getWorker = async ({ } pendingWorkerNoToken.length = 0; } else if (isConnectionStatusMessage(message)) { - handleConnectionStatusChange({ data: message }); + handleConnectionStatusChange({data: message}); } else { console.warn("ConnectionManager: Unexpected message from the worker"); } @@ -150,8 +146,8 @@ const getWorker = async ({ }; function handleMessageFromWorker({ - data: message, -}: MessageEvent) { + data: message, + }: MessageEvent) { if (messageShouldBeRoutedToDataSource(message)) { const viewport = viewports.get(message.clientViewportId); if (viewport) { @@ -164,12 +160,11 @@ function handleMessageFromWorker({ } else if (isConnectionStatusMessage(message)) { ConnectionManager.emit("connection-status", message); } else if (isConnectionQualityMetrics(message)) { - console.log({ message }); ConnectionManager.emit("connection-metrics", message); } else { const requestId = (message as VuuUIMessageInRPC).requestId; if (pendingRequests.has(requestId)) { - const { resolve } = pendingRequests.get(requestId); + const {resolve} = pendingRequests.get(requestId); pendingRequests.delete(requestId); const { type: _1, @@ -214,7 +209,7 @@ const asyncRequest = ( ...msg, }); return new Promise((resolve, reject) => { - pendingRequests.set(requestId, { resolve, reject }); + pendingRequests.set(requestId, {resolve, reject}); }); }; @@ -246,11 +241,11 @@ const connectedServerAPI: ServerAPI = { request: message, postMessageToClientDataSource: callback, }); - worker.postMessage({ type: "subscribe", ...message }); + worker.postMessage({type: "subscribe", ...message}); }, unsubscribe: (viewport) => { - worker.postMessage({ type: "unsubscribe", viewport }); + worker.postMessage({type: "unsubscribe", viewport}); }, send: (message) => { @@ -268,7 +263,7 @@ const connectedServerAPI: ServerAPI = { ) => asyncRequest(message), getTableList: async () => - asyncRequest({ type: "GET_TABLE_LIST" }), + asyncRequest({type: "GET_TABLE_LIST"}), getTableSchema: async (table) => asyncRequest({ @@ -297,13 +292,13 @@ class _ConnectionManager extends EventEmitter { // The first request must have the token. We can change this to block others until // the request with token is received. async connect({ - url, - authToken, - username, - protocol, - retryLimitDisconnect, - retryLimitStartup, - }: ConnectOptions): Promise { + url, + authToken, + username, + protocol, + retryLimitDisconnect, + retryLimitStartup, + }: ConnectOptions): Promise { // By passing handleMessageFromWorker here, we can get connection status //messages while we wait for worker to resolve. worker = await getWorker({ @@ -338,13 +333,13 @@ export const ConnectionManager = new _ConnectionManager(); * @param token */ export const connectToServer = async ({ - url, - protocol = undefined, - authToken, - username, - retryLimitDisconnect, - retryLimitStartup, -}: ConnectOptions) => { + url, + protocol = undefined, + authToken, + username, + retryLimitDisconnect, + retryLimitStartup, + }: ConnectOptions) => { try { const serverAPI = await ConnectionManager.connect({ protocol, diff --git a/vuu-ui/packages/vuu-data/src/data-source.ts b/vuu-ui/packages/vuu-data/src/data-source.ts index 1a5b6ff1a..f04af2e0f 100644 --- a/vuu-ui/packages/vuu-data/src/data-source.ts +++ b/vuu-ui/packages/vuu-data/src/data-source.ts @@ -505,13 +505,6 @@ export type DataSourceStatus = | "suspended" | "unsubscribed"; -export type RpcResponse = - | MenuRpcResponse - | VuuUIMessageInRPCEditReject - | VuuUIMessageInRPCEditResponse; - -export type RpcResponseHandler = (response: RpcResponse) => boolean; - export interface DataSource extends EventEmitter { aggregations: VuuAggregation[]; applyEdit: DataSourceEditHandler; diff --git a/vuu-ui/packages/vuu-data/src/inlined-worker.js b/vuu-ui/packages/vuu-data/src/inlined-worker.js index 5b687bae0..b0715dd93 100644 --- a/vuu-ui/packages/vuu-data/src/inlined-worker.js +++ b/vuu-ui/packages/vuu-data/src/inlined-worker.js @@ -682,7 +682,6 @@ var CHANGE_VP_RANGE_SUCCESS = "CHANGE_VP_RANGE_SUCCESS"; var CLOSE_TREE_NODE = "CLOSE_TREE_NODE"; var CLOSE_TREE_SUCCESS = "CLOSE_TREE_SUCCESS"; var CREATE_VP = "CREATE_VP"; -var CREATE_VP_SUCCESS = "CREATE_VP_SUCCESS"; var DISABLE_VP = "DISABLE_VP"; var DISABLE_VP_SUCCESS = "DISABLE_VP_SUCCESS"; var ENABLE_VP = "ENABLE_VP"; @@ -692,14 +691,11 @@ var GET_VIEW_PORT_MENUS = "GET_VIEW_PORT_MENUS"; var HB = "HB"; var HB_RESP = "HB_RESP"; var LOGIN = "LOGIN"; -var LOGIN_SUCCESS = "LOGIN_SUCCESS"; var OPEN_TREE_NODE = "OPEN_TREE_NODE"; var OPEN_TREE_SUCCESS = "OPEN_TREE_SUCCESS"; var REMOVE_VP = "REMOVE_VP"; var RPC_RESP = "RPC_RESP"; var SET_SELECTION_SUCCESS = "SET_SELECTION_SUCCESS"; -var TABLE_META_RESP = "TABLE_META_RESP"; -var TABLE_LIST_RESP = "TABLE_LIST_RESP"; var TABLE_ROW = "TABLE_ROW"; // src/server-proxy/rpc-services.ts @@ -967,7 +963,6 @@ var Viewport = class { this.pendingRangeRequests = []; this.rowCountChanged = false; this.selectedRows = []; - this.tableSchema = null; this.useBatchMode = true; this.lastUpdateStatus = NO_UPDATE_STATUS; this.updateThrottleTimer = void 0; @@ -1106,7 +1101,7 @@ var Viewport = class { range, sort, groupBy - }) { + }, tableSchema) { this.serverViewportId = viewPortId; this.status = "subscribed"; this.aggregations = aggregations; @@ -1123,7 +1118,7 @@ var Viewport = class { groupBy, range, sort, - tableSchema: this.tableSchema + tableSchema }; } awaitOperation(requestId, msg) { @@ -1329,9 +1324,6 @@ var Viewport = class { clientViewportId: this.clientViewportId }; } - setTableSchema(tableSchema) { - this.tableSchema = tableSchema; - } openTreeNode(requestId, message) { if (this.useBatchMode) { this.batchMode = true; @@ -1659,9 +1651,9 @@ var ServerProxy = class { constructor(connection, callback) { this.authToken = ""; this.user = "user"; - this.pendingTableMetaRequests = /* @__PURE__ */ new Map(); this.pendingRequests = /* @__PURE__ */ new Map(); this.queuedRequests = []; + this.cachedTableMetaRequests = /* @__PURE__ */ new Map(); this.cachedTableSchemas = /* @__PURE__ */ new Map(); this.connection = connection; this.postMessageToClient = callback; @@ -1705,26 +1697,62 @@ var ServerProxy = class { } subscribe(message) { if (!this.mapClientToServerViewport.has(message.viewport)) { - if (!this.hasSchemaForTable(message.table) && // A Session table is never cached - it is limited to a single workflow interaction - // The metadata for a session table is requested even before the subscribe call. - !isSessionTable(message.table)) { - info3 == null ? void 0 : info3( - \`subscribe to \${message.table.table}, no metadata yet, request metadata\` - ); - const requestId = nextRequestId(); - this.sendMessageToServer( - { type: "GET_TABLE_META", table: message.table }, - requestId - ); - this.pendingTableMetaRequests.set(requestId, message.viewport); - } + const pendingTableSchema = this.getTableMeta(message.table); const viewport = new Viewport(message, this.postMessageToClient); this.viewports.set(message.viewport, viewport); - this.sendIfReady( + const pendingSubscription = this.awaitResponseToMessage( viewport.subscribe(), - message.viewport, - this.sessionId !== "" + message.viewport ); + const awaitPendingReponses = Promise.all([ + pendingSubscription, + pendingTableSchema + ]); + awaitPendingReponses.then(([subscribeResponse, tableSchema]) => { + const { viewPortId: serverViewportId } = subscribeResponse; + const { status: viewportStatus } = viewport; + if (message.viewport !== serverViewportId) { + this.viewports.delete(message.viewport); + this.viewports.set(serverViewportId, viewport); + } + this.mapClientToServerViewport.set(message.viewport, serverViewportId); + const clientResponse = viewport.handleSubscribed( + subscribeResponse, + tableSchema + ); + if (clientResponse) { + this.postMessageToClient(clientResponse); + if (debugEnabled4) { + debug4( + \`post DataSourceSubscribedMessage to client: \${JSON.stringify( + clientResponse + )}\` + ); + } + } + if (viewport.disabled) { + this.disableViewport(viewport); + } + if (viewportStatus === "subscribing" && // A session table will never have Visual Links, nor Context Menus + !isSessionTable(viewport.table)) { + this.sendMessageToServer({ + type: GET_VP_VISUAL_LINKS, + vpId: serverViewportId + }); + this.sendMessageToServer({ + type: GET_VIEW_PORT_MENUS, + vpId: serverViewportId + }); + Array.from(this.viewports.entries()).filter( + ([id, { disabled }]) => id !== serverViewportId && !disabled + ).forEach(([vpId]) => { + this.sendMessageToServer({ + type: GET_VP_VISUAL_LINKS, + vpId + }); + }); + } + }); } else { error3(\`spurious subscribe call \${message.viewport}\`); } @@ -1965,6 +1993,7 @@ var ServerProxy = class { this.sendMessageToServer(rpcRequest, requestId, { module }); } handleMessageFromClient(message) { + var _a; if (isViewporttMessage(message)) { if (message.type === "disable") { const viewport = this.getViewportForClient(message.viewport, false); @@ -2016,13 +2045,32 @@ var ServerProxy = class { } else { const { type, requestId } = message; switch (type) { - case "GET_TABLE_LIST": - return this.sendMessageToServer({ type }, requestId); - case "GET_TABLE_META": - return this.sendMessageToServer( - { type, table: message.table }, + case "GET_TABLE_LIST": { + (_a = this.tableList) != null ? _a : this.tableList = this.awaitResponseToMessage( + { type }, requestId ); + this.tableList.then((response) => { + this.postMessageToClient({ + type: "TABLE_LIST_RESP", + tables: response.tables, + requestId + }); + }); + return; + } + case "GET_TABLE_META": { + this.getTableMeta(message.table, requestId).then((tableSchema) => { + if (tableSchema) { + this.postMessageToClient({ + type: "TABLE_META_RESP", + tableSchema, + requestId + }); + } + }); + return; + } case "RPC_CALL": return this.rpcCall(message); default: @@ -2034,9 +2082,23 @@ var ServerProxy = class { )}\` ); } - awaitResponseToMessage(message) { + getTableMeta(table, requestId = nextRequestId()) { + if (isSessionTable(table)) { + return Promise.resolve(void 0); + } + const key = \`\${table.module}:\${table.table}\`; + let tableMetaRequest = this.cachedTableMetaRequests.get(key); + if (!tableMetaRequest) { + tableMetaRequest = this.awaitResponseToMessage( + { type: "GET_TABLE_META", table }, + requestId + ); + this.cachedTableMetaRequests.set(key, tableMetaRequest); + } + return tableMetaRequest == null ? void 0 : tableMetaRequest.then((response) => this.cacheTableMeta(response)); + } + awaitResponseToMessage(message, requestId = nextRequestId()) { return new Promise((resolve, reject) => { - const requestId = nextRequestId(); this.sendMessageToServer(message, requestId); this.pendingRequests.set(requestId, { reject, resolve }); }); @@ -2080,7 +2142,7 @@ var ServerProxy = class { "NA" ); break; - case LOGIN_SUCCESS: + case "LOGIN_SUCCESS": if (sessionId) { this.sessionId = sessionId; (_a = this.pendingLogin) == null ? void 0 : _a.resolve(sessionId); @@ -2089,53 +2151,6 @@ var ServerProxy = class { throw Error("LOGIN_SUCCESS did not provide sessionId"); } break; - case CREATE_VP_SUCCESS: - { - const viewport = viewports.get(requestId); - if (viewport) { - const { status: viewportStatus } = viewport; - const { viewPortId: serverViewportId } = body; - if (requestId !== serverViewportId) { - viewports.delete(requestId); - viewports.set(serverViewportId, viewport); - } - this.mapClientToServerViewport.set(requestId, serverViewportId); - const response = viewport.handleSubscribed(body); - if (response) { - this.postMessageToClient(response); - if (debugEnabled4) { - debug4( - \`post DataSourceSubscribedMessage to client: \${JSON.stringify( - response - )}\` - ); - } - } - if (viewport.disabled) { - this.disableViewport(viewport); - } - if (viewportStatus === "subscribing" && // A session table will never have Visual Links, nor Context Menus - !isSessionTable(viewport.table)) { - this.sendMessageToServer({ - type: GET_VP_VISUAL_LINKS, - vpId: serverViewportId - }); - this.sendMessageToServer({ - type: GET_VIEW_PORT_MENUS, - vpId: serverViewportId - }); - Array.from(viewports.entries()).filter( - ([id, { disabled }]) => id !== serverViewportId && !disabled - ).forEach(([vpId]) => { - this.sendMessageToServer({ - type: GET_VP_VISUAL_LINKS, - vpId - }); - }); - } - } - } - break; case "REMOVE_VP_SUCCESS": { const viewport = viewports.get(body.viewPortId); @@ -2288,36 +2303,6 @@ var ServerProxy = class { } } break; - case TABLE_LIST_RESP: - this.postMessageToClient({ - type: TABLE_LIST_RESP, - tables: body.tables, - requestId - }); - break; - case TABLE_META_RESP: - { - const tableSchema = this.cacheTableMeta(body); - const clientViewportId = this.pendingTableMetaRequests.get(requestId); - if (clientViewportId) { - this.pendingTableMetaRequests.delete(requestId); - const viewport = this.viewports.get(clientViewportId); - if (viewport) { - viewport.setTableSchema(tableSchema); - } else { - warn3 == null ? void 0 : warn3( - "Message has come back AFTER CREATE_VP_SUCCESS, what do we do now" - ); - } - } else { - this.postMessageToClient({ - type: TABLE_META_RESP, - tableSchema, - requestId - }); - } - } - break; case "VP_VISUAL_LINKS_RESP": { const activeLinkDescriptors = this.getActiveLinks(body.links); @@ -2445,9 +2430,6 @@ var ServerProxy = class { infoEnabled3 && info3(\`handleMessageFromServer \${body["type"]}.\`); } } - hasSchemaForTable(table) { - return this.cachedTableSchemas.has(\`\${table.module}:\${table.table}\`); - } cacheTableMeta(messageBody) { const { module, table } = messageBody.table; const key = \`\${module}:\${table}\`; diff --git a/vuu-ui/packages/vuu-data/src/json-data-source.ts b/vuu-ui/packages/vuu-data/src/json-data-source.ts index c50b74078..0055d3d63 100644 --- a/vuu-ui/packages/vuu-data/src/json-data-source.ts +++ b/vuu-ui/packages/vuu-data/src/json-data-source.ts @@ -1,16 +1,15 @@ -import { ColumnDescriptor, Selection } from "@finos/vuu-datagrid-types"; +import {ColumnDescriptor, Selection} from "@finos/vuu-datagrid-types"; import { + ClientToServerEditRpc, + ClientToServerMenuRPC, LinkDescriptorWithLabel, - VuuGroupBy, VuuAggregation, + VuuGroupBy, VuuRange, - VuuSort, - ClientToServerMenuRPC, - ClientToServerEditRpc, - VuuColumnDataType, VuuRowDataItemType, + VuuSort, } from "@finos/vuu-protocol-types"; -import { DataSourceFilter, DataSourceRow } from "@finos/vuu-data-types"; +import {DataSourceFilter, DataSourceRow} from "@finos/vuu-data-types"; import { EventEmitter, isSelected, @@ -29,21 +28,21 @@ import type { SubscribeProps, WithFullConfig, } from "./data-source"; -import { vanillaConfig } from "./data-source"; +import {vanillaConfig} from "./data-source"; import { MenuRpcResponse, VuuUIMessageInRPCEditReject, VuuUIMessageInRPCEditResponse, } from "./vuuUIMessageTypes"; -const NULL_SCHEMA = { columns: [], key: "", table: { module: "", table: "" } }; +const NULL_SCHEMA = {columns: [], key: "", table: {module: "", table: ""}}; export interface JsonDataSourceConstructorProps extends Omit { data: JsonData; } -const { DEPTH, IDX, IS_EXPANDED, IS_LEAF, KEY, SELECTED } = metadataKeys; +const {DEPTH, IDX, IS_EXPANDED, IS_LEAF, KEY, SELECTED} = metadataKeys; const toClientRow = (row: DataSourceRow, keys: KeySet) => { const [rowIndex] = row; @@ -54,8 +53,7 @@ const toClientRow = (row: DataSourceRow, keys: KeySet) => { export class JsonDataSource extends EventEmitter - implements DataSource -{ + implements DataSource { public columnDescriptors: ColumnDescriptor[]; private clientCallback: SubscribeCallback | undefined; private expandedRows = new Set(); @@ -64,12 +62,12 @@ export class JsonDataSource #aggregations: VuuAggregation[] = []; #config: WithFullConfig = vanillaConfig; #data: DataSourceRow[]; - #filter: DataSourceFilter = { filter: "" }; + #filter: DataSourceFilter = {filter: ""}; #groupBy: VuuGroupBy = []; - #range: VuuRange = { from: 0, to: 0 }; + #range: VuuRange = {from: 0, to: 0}; #selectedRowsCount = 0; #size = 0; - #sort: VuuSort = { sortDefs: [] }; + #sort: VuuSort = {sortDefs: []}; #status: DataSourceStatus = "initialising"; #title: string | undefined; @@ -79,14 +77,14 @@ export class JsonDataSource private keys = new KeySet(this.#range); constructor({ - aggregations, - data, - filter, - groupBy, - sort, - title, - viewport, - }: JsonDataSourceConstructorProps) { + aggregations, + data, + filter, + groupBy, + sort, + title, + viewport, + }: JsonDataSourceConstructorProps) { super(); if (!data) { @@ -96,10 +94,10 @@ export class JsonDataSource [this.columnDescriptors, this.#data] = jsonToDataSourceRows(data); this.visibleRows = this.#data - .filter((row) => row[DEPTH] === 0) - .map((row, index) => - ([index, index] as Partial).concat(row.slice(2)) - ) as DataSourceRow[]; + .filter((row) => row[DEPTH] === 0) + .map((row, index) => + ([index, index] as Partial).concat(row.slice(2)) + ) as DataSourceRow[]; this.viewport = viewport || uuid(); if (aggregations) { this.#aggregations = aggregations; @@ -210,14 +208,15 @@ export class JsonDataSource console.log("noop"); return this; } + set data(data: JsonData) { console.log(`set JsonDataSource data`); [this.columnDescriptors, this.#data] = jsonToDataSourceRows(data); this.visibleRows = this.#data - .filter((row) => row[DEPTH] === 0) - .map((row, index) => - ([index, index] as Partial).concat(row.slice(2)) - ) as DataSourceRow[]; + .filter((row) => row[DEPTH] === 0) + .map((row, index) => + ([index, index] as Partial).concat(row.slice(2)) + ) as DataSourceRow[]; requestAnimationFrame(() => { this.sendRowsToClient(); @@ -227,7 +226,7 @@ export class JsonDataSource select(selected: Selection) { const updatedRows: DataSourceRow[] = []; for (const row of this.#data) { - const { [IDX]: rowIndex, [SELECTED]: sel } = row; + const {[IDX]: rowIndex, [SELECTED]: sel} = row; const wasSelected = sel === 1; const nowSelected = isSelected(selected, rowIndex); if (nowSelected !== wasSelected) { @@ -251,14 +250,14 @@ export class JsonDataSource openTreeNode(key: string) { this.expandedRows.add(key); this.visibleRows = getVisibleRows(this.#data, this.expandedRows); - const { from, to } = this.#range; + const {from, to} = this.#range; this.clientCallback?.({ clientViewportId: this.viewport, mode: "batch", rows: this.visibleRows - .slice(from, to) - .map((row) => toClientRow(row, this.keys)), + .slice(from, to) + .map((row) => toClientRow(row, this.keys)), size: this.visibleRows.length, type: "viewport-update", }); @@ -306,13 +305,13 @@ export class JsonDataSource } private sendRowsToClient() { - const { from, to } = this.#range; + const {from, to} = this.#range; this.clientCallback?.({ clientViewportId: this.viewport, mode: "batch", rows: this.visibleRows - .slice(from, to) - .map((row) => toClientRow(row, this.keys)), + .slice(from, to) + .map((row) => toClientRow(row, this.keys)), size: this.visibleRows.length, type: "viewport-update", }); @@ -338,10 +337,6 @@ export class JsonDataSource this.#aggregations = aggregations; } - set data(data: JsonData) { - console.log(`set JsonDataSource data`); - } - get sort() { return this.#sort; } @@ -377,9 +372,9 @@ export class JsonDataSource } createLink({ - parentVpId, - link: { fromColumn, toColumn }, - }: LinkDescriptorWithLabel) { + parentVpId, + link: {fromColumn, toColumn}, + }: LinkDescriptorWithLabel) { console.log("create link", { parentVpId, fromColumn, @@ -419,11 +414,11 @@ export class JsonDataSource getChildRows(rowKey: string) { const parentRow = this.#data.find((row) => row[KEY] === rowKey); if (parentRow) { - const { [IDX]: parentIdx, [DEPTH]: parentDepth } = parentRow; + const {[IDX]: parentIdx, [DEPTH]: parentDepth} = parentRow; let rowIdx = parentIdx + 1; const childRows = []; do { - const { [DEPTH]: depth } = this.#data[rowIdx]; + const {[DEPTH]: depth} = this.#data[rowIdx]; if (depth === parentDepth + 1) { childRows.push(this.#data[rowIdx]); } else if (depth <= parentDepth) { @@ -453,10 +448,10 @@ type Index = { function getVisibleRows(rows: DataSourceRow[], expandedKeys: Set) { const visibleRows: DataSourceRow[] = []; - const index: Index = { value: 0 }; + const index: Index = {value: 0}; for (let i = 0; i < rows.length; i++) { const row = rows[i]; - const { [DEPTH]: depth, [KEY]: key, [IS_LEAF]: isLeaf } = row; + const {[DEPTH]: depth, [KEY]: key, [IS_LEAF]: isLeaf} = row; const isExpanded = expandedKeys.has(key); visibleRows.push(cloneRow(row, index, isExpanded)); if (!isLeaf && !isExpanded) { diff --git a/vuu-ui/packages/vuu-datagrid-types/index.d.ts b/vuu-ui/packages/vuu-datagrid-types/index.d.ts index 65fc21298..630f6dc0f 100644 --- a/vuu-ui/packages/vuu-datagrid-types/index.d.ts +++ b/vuu-ui/packages/vuu-datagrid-types/index.d.ts @@ -38,9 +38,9 @@ export interface TableCellProps { export type CommitResponse = Promise; -export type DataItemCommitHandler = ( - value: VuuRowDataItemType -) => CommitResponse; +export type DataItemCommitHandler< + T extends VuuRowDataItemType = VuuRowDataItemType +> = (value: T) => CommitResponse; export interface TableCellRendererProps extends Omit { diff --git a/vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts b/vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts index 2125ab675..519dde763 100644 --- a/vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts +++ b/vuu-ui/packages/vuu-layout/src/layout-persistence/LocalLayoutPersistenceManager.ts @@ -25,10 +25,6 @@ export class LocalLayoutPersistenceManager implements LayoutPersistenceManager { layout: LayoutJSON ): Promise { return new Promise((resolve) => { - console.log( - `Saving layout as ${metadata.name} to group ${metadata.group}...` - ); - Promise.all([this.loadLayouts(), this.loadMetadata()]).then( ([existingLayouts, existingMetadata]) => { const id = getUniqueId(); diff --git a/vuu-ui/packages/vuu-popups/src/menu/context-menu-provider.tsx b/vuu-ui/packages/vuu-popups/src/menu/context-menu-provider.tsx index a61d6a4f1..9d62dcd76 100644 --- a/vuu-ui/packages/vuu-popups/src/menu/context-menu-provider.tsx +++ b/vuu-ui/packages/vuu-popups/src/menu/context-menu-provider.tsx @@ -9,13 +9,16 @@ export const ContextMenuContext = createContext( null ); -export interface ContextMenuProviderProps { - children: ReactNode; - label?: string; +export interface ContextMenuConfiguration { menuActionHandler?: MenuActionHandler; menuBuilder: MenuBuilder; } +export interface ContextMenuProviderProps extends ContextMenuConfiguration { + children: ReactNode; + label?: string; +} + interface ProviderProps extends ContextMenuProviderProps { context: ContextMenuContextType | null; } diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx index b7ba35643..82721ccd5 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/LayoutList.tsx @@ -48,8 +48,8 @@ export const LayoutsList = (props: HTMLAttributes) => { {layoutMetadata.map((metadata) => (
handleLoadLayout(metadata?.id)} + key={metadata?.id} + onClick={() => handleLoadLayout(metadata?.id)} > ) => { {metadata?.name}
-
{`${metadata?.user}, ${metadata?.created}`}
+
{`${metadata?.user}, ${metadata?.created}`}
diff --git a/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx b/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx index 1c83e8f47..064866046 100644 --- a/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx +++ b/vuu-ui/packages/vuu-shell/src/layout-management/useLayoutManager.tsx @@ -20,12 +20,11 @@ const local = process.env.LOCAL ?? true; let _persistenceManager: LayoutPersistenceManager; const getPersistenceManager = () => { - if (_persistenceManager == undefined) { + if (_persistenceManager === undefined) { _persistenceManager = local ? new LocalLayoutPersistenceManager() : new RemoteLayoutPersistenceManager(); } - return _persistenceManager; }; @@ -67,8 +66,9 @@ export const LayoutManagementProvider = ( ); useEffect(() => { - getPersistenceManager() - .loadMetadata() + const persistenceManager = getPersistenceManager(); + + persistenceManager.loadMetadata() .then((metadata) => { setLayoutMetadata(metadata); }) @@ -77,8 +77,7 @@ export const LayoutManagementProvider = ( console.error("Error occurred while retrieving metadata", error); }); - getPersistenceManager() - .loadApplicationLayout() + persistenceManager.loadApplicationLayout() .then((layout: LayoutJSON) => { setApplicationLayout(layout); }) @@ -93,6 +92,7 @@ export const LayoutManagementProvider = ( const saveApplicationLayout = useCallback( (layout: LayoutJSON) => { + console.log(`save application layout ${JSON.stringify(layout, null, 2)}`); setApplicationLayout(layout, false); getPersistenceManager().saveApplicationLayout(layout); }, diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/CaseValidator.ts b/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/CaseValidator.ts index 3bf15ae23..166611ae3 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/CaseValidator.ts +++ b/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/CaseValidator.ts @@ -1,7 +1,7 @@ import { EditRuleValidator, registerComponent } from "@finos/vuu-utils"; import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; -const isString = (value: VuuRowDataItemType): value is string => +const isString = (value?: VuuRowDataItemType): value is string => typeof value === "string"; export const CaseValidator: EditRuleValidator = (rule, value) => { diff --git a/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/PatternValidator.ts b/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/PatternValidator.ts index 58d34f671..578e717cc 100644 --- a/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/PatternValidator.ts +++ b/vuu-ui/packages/vuu-table-extras/src/cell-edit-validators/PatternValidator.ts @@ -1,7 +1,7 @@ import { EditRuleValidator, registerComponent } from "@finos/vuu-utils"; import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; -const isString = (value: VuuRowDataItemType): value is string => +const isString = (value?: VuuRowDataItemType): value is string => typeof value === "string"; const defaultMessage = "value does not match expected pattern"; diff --git a/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx b/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx index 3f2726f22..5d26c7fb0 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx +++ b/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx @@ -2,7 +2,13 @@ import { ContextMenuProvider } from "@finos/vuu-popups"; import { TableProps } from "@finos/vuu-table"; import { isGroupColumn, metadataKeys, notHidden } from "@finos/vuu-utils"; import cx from "classnames"; -import { CSSProperties, ForwardedRef, forwardRef, useRef } from "react"; +import { + CSSProperties, + ForwardedRef, + forwardRef, + useEffect, + useRef, +} from "react"; import { GroupHeaderCellNext as GroupHeaderCell, HeaderCell, @@ -45,6 +51,7 @@ export const TableNext = forwardRef(function TableNext( forwardedRef: ForwardedRef ) { const id = useId(idProp); + const containerRef = useRef(null); const { columnMap, diff --git a/vuu-ui/packages/vuu-table/src/table-next/header-cell/HeaderCell.css b/vuu-ui/packages/vuu-table/src/table-next/header-cell/HeaderCell.css index e9a9a58cb..854991cc3 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/header-cell/HeaderCell.css +++ b/vuu-ui/packages/vuu-table/src/table-next/header-cell/HeaderCell.css @@ -46,7 +46,7 @@ } .vuuTableNextHeaderCell.vuuPinLeft { - padding-left: 2px;; + padding-left: 2px; } .vuuTableNextHeaderCell.vuuPinLeft.vuuEndPin .vuuColumnResizerNext:before { @@ -79,7 +79,7 @@ width: var(--pin-width); top:0; bottom:0; - right: -1px; + right: 3px; height: var(--height); z-index: -5; } diff --git a/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts b/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts index 4c37b7d4a..ad72ae840 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts +++ b/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts @@ -1,4 +1,5 @@ import { + DataSource, DataSourceConfig, DataSourceSubscribedMessage, JsonDataSource, @@ -36,6 +37,7 @@ import { useCallback, useEffect, useMemo, + useRef, useState, } from "react"; import { @@ -114,9 +116,14 @@ export const useTable = ({ selectionModel, }: TableHookProps) => { const [rowCount, setRowCount] = useState(dataSource.size); + const dataSourceRef = useRef(); if (dataSource === undefined) { throw Error("no data source provided to Vuu Table"); } + // // We track changes to tableConfig. When detected, these trigger an init + // // of model. We will need dataSource for that, but don't want to trigger + // // that logic when dataSource itself changes. + // dataSourceRef.current = dataSource; const [size, setSize] = useState(); const handleResize = useCallback((size: MeasuredSize) => { @@ -560,9 +567,16 @@ export const useTable = ({ [onRowClickProp, selectionHookOnRowClick] ); + useLayoutEffectSkipFirst(() => { + dispatchColumnAction({ + type: "init", + tableConfig: config, + dataSourceConfig: dataSource.config, + }); + }, [config, dataSource, dispatchColumnAction]); + useEffect(() => { dataSource.on("config", (config, confirmed) => { - // expectConfigChangeRef.current = true; dispatchColumnAction({ type: "tableConfig", ...config, diff --git a/vuu-ui/packages/vuu-table/src/table/useTableModel.ts b/vuu-ui/packages/vuu-table/src/table/useTableModel.ts index e2193e310..2d9cf212e 100644 --- a/vuu-ui/packages/vuu-table/src/table/useTableModel.ts +++ b/vuu-ui/packages/vuu-table/src/table/useTableModel.ts @@ -410,7 +410,6 @@ function pinColumn(state: TableModel, action: ColumnActionPin) { const { column, pin } = action; columns = updateColumn(columns, column.name, { pin }); columns = sortPinnedColumns(columns); - console.log({ withPins: columns }); return { ...state, columns, diff --git a/vuu-ui/packages/vuu-theme/fonts/NunitoSans.css b/vuu-ui/packages/vuu-theme/fonts/NunitoSans.css index f422339bd..023d0ba13 100644 --- a/vuu-ui/packages/vuu-theme/fonts/NunitoSans.css +++ b/vuu-ui/packages/vuu-theme/fonts/NunitoSans.css @@ -68,4 +68,4 @@ @font-face { font-family: 'Nunito Sans A-Variant'; src: url('./NunitoSans-Regular.woff') format('opentype'); -} \ No newline at end of file +} diff --git a/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx b/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx index 7615b6306..03d5b71eb 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/cycle-state-button/CycleStateButton.tsx @@ -25,12 +25,19 @@ const getNextValue = (value: string, valueList: string[]) => { }; export const CycleStateButton = forwardRef(function CycleStateButton( - { className, onCommit, value, values, ...buttonProps }: CycleStateButtonProps, + { + className, + onCommit, + value = "", + values, + ...buttonProps + }: CycleStateButtonProps, forwardedRef: ForwardedRef ) { const handleClick = useCallback( (evt: SyntheticEvent) => { const nextValue = getNextValue(value, values); + console.log(`CycleStateButton handleClick ${value} => ${nextValue}`); onCommit(evt, nextValue as VuuColumnDataType).then((response) => { if (response !== true) { console.error(response); diff --git a/vuu-ui/packages/vuu-ui-controls/src/editable/editable-utils.ts b/vuu-ui/packages/vuu-ui-controls/src/editable/editable-utils.ts index 69f210922..3fd94aa4d 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/editable/editable-utils.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/editable/editable-utils.ts @@ -3,19 +3,18 @@ import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; import { getEditRuleValidator } from "@finos/vuu-utils"; export type ClientSideValidationChecker = ( - value: VuuRowDataItemType + value?: VuuRowDataItemType ) => string | false | undefined; export const buildValidationChecker = (rules: EditValidationRule[]): ClientSideValidationChecker => - (value: VuuRowDataItemType) => + (value?: VuuRowDataItemType) => applyRules(rules, value); function applyRules( rules: EditValidationRule[], - value: VuuRowDataItemType + value?: VuuRowDataItemType ): string | false | undefined { - console.log(`apply rules to ${value}`); let result: false | string | undefined = undefined; for (const rule of rules) { const editRuleValidator = getEditRuleValidator(rule.name); @@ -43,6 +42,5 @@ function applyRules( } } - console.log(result); return result; } diff --git a/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts b/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts index 4e1038d6e..616a555be 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/editable/useEditableText.ts @@ -1,6 +1,8 @@ import { VuuRowDataItemType } from "@finos/vuu-protocol-types"; -import { DataItemCommitHandler } from "packages/vuu-datagrid-types"; +import { DataItemCommitHandler } from "@finos/vuu-datagrid-types"; +import { useLayoutEffectSkipFirst } from "@finos/vuu-layout"; import { + FocusEventHandler, FormEventHandler, KeyboardEvent, useCallback, @@ -20,8 +22,9 @@ export interface EditableTextHookProps< T extends VuuRowDataItemType = VuuRowDataItemType > { clientSideEditValidationCheck?: ClientSideValidationChecker; - initialValue: T; - onCommit: DataItemCommitHandler; + initialValue?: T; + onCommit: DataItemCommitHandler; + type?: "string" | "number" | "boolean"; } export const dispatchCommitEvent = (el: HTMLElement) => { @@ -29,43 +32,54 @@ export const dispatchCommitEvent = (el: HTMLElement) => { el.dispatchEvent(commitEvent); }; -export const useEditableText = < - T extends VuuRowDataItemType = VuuRowDataItemType ->({ +export const useEditableText = ({ clientSideEditValidationCheck, initialValue, onCommit, + type, }: EditableTextHookProps) => { const [message, setMessage] = useState(); - const [value, setValue] = useState(initialValue); - const initialValueRef = useRef(initialValue); + const [value, setValue] = useState(initialValue); + const initialValueRef = useRef(initialValue); const isDirtyRef = useRef(false); const hasCommittedRef = useRef(false); + useLayoutEffectSkipFirst(() => { + //TODO this isn't right, review the state we're using + setValue(initialValue); + }, [initialValue]); + + const commit = useCallback( + (target: HTMLElement) => { + if (isDirtyRef.current) { + hasCommittedRef.current = true; + const warningMessage = clientSideEditValidationCheck?.(value); + if (warningMessage) { + setMessage(warningMessage); + } else { + setMessage(undefined); + onCommit(value as T).then((response) => { + if (response === true) { + isDirtyRef.current = false; + dispatchCommitEvent(target); + } else { + setMessage(response); + } + }); + } + } else { + // why, if not dirty ? + dispatchCommitEvent(target); + hasCommittedRef.current = false; + } + }, + [clientSideEditValidationCheck, onCommit, value] + ); + const handleKeyDown = useCallback( (evt: KeyboardEvent) => { if (evt.key === "Enter") { - evt.stopPropagation(); - if (isDirtyRef.current) { - hasCommittedRef.current = true; - const warningMessage = clientSideEditValidationCheck?.(value); - if (warningMessage) { - setMessage(warningMessage); - } else { - setMessage(undefined); - onCommit(value).then((response) => { - if (response === true) { - isDirtyRef.current = false; - dispatchCommitEvent(evt.target as HTMLInputElement); - } else { - setMessage(response); - } - }); - } - } else { - dispatchCommitEvent(evt.target as HTMLInputElement); - hasCommittedRef.current = false; - } + commit(evt.target as HTMLElement); } else if ( evt.key === "ArrowRight" || evt.key === "ArrowLeft" || @@ -81,28 +95,42 @@ export const useEditableText = < } } }, - [clientSideEditValidationCheck, onCommit, value] + [commit] + ); + + const handleBlur = useCallback>( + (evt) => { + commit(evt.target as HTMLElement); + }, + [commit] ); const handleChange = useCallback( (evt) => { - const { value } = evt.target as HTMLInputElement; + let typedValue: VuuRowDataItemType = (evt.target as HTMLInputElement) + .value; + if (type === "number" && !isNaN(parseFloat(typedValue))) { + typedValue = parseFloat(typedValue); + } isDirtyRef.current = value !== initialValueRef.current; - setValue(value as T); - if (hasCommittedRef.current) { + setValue(typedValue as T); + if (hasCommittedRef.current && value !== undefined) { const warningMessage = clientSideEditValidationCheck?.(value); if (warningMessage !== message && warningMessage !== false) { setMessage(warningMessage); } } }, - [clientSideEditValidationCheck, message] + [clientSideEditValidationCheck, message, type, value] ); return { + inputProps: { + onBlur: handleBlur, + onKeyDown: handleKeyDown, + }, onChange: handleChange, - onKeyDown: handleKeyDown, - value, + value: value ?? "", warningMessage: message, }; }; diff --git a/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx b/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx index 5b8bfd0e3..54fa022bd 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/expando-input/ExpandoInput.tsx @@ -19,7 +19,7 @@ export const ExpandoInput = forwardRef(function ExpandoInput( value, inputProps, onCommit = noop, - ...InputProps + ...props }: ExpandoInputProps, forwardedRef: ForwardedRef ) { @@ -31,7 +31,7 @@ export const ExpandoInput = forwardRef(function ExpandoInput( data-text={value} > = ( +export type Commithandler = ( evt: SyntheticEvent, value: T ) => void; -export interface VuuInputProps< - T extends VuuRowDataItemType = VuuRowDataItemType -> extends InputProps { +export interface VuuInputProps + extends InputProps { errorMessage?: string; onCommit: Commithandler; type?: T; diff --git a/vuu-ui/packages/vuu-utils/src/component-registry.ts b/vuu-ui/packages/vuu-utils/src/component-registry.ts index 99b2dc3f6..8e38011b9 100644 --- a/vuu-ui/packages/vuu-utils/src/component-registry.ts +++ b/vuu-ui/packages/vuu-utils/src/component-registry.ts @@ -4,7 +4,6 @@ import { ColumnDescriptorCustomRenderer, ColumnTypeRendering, EditValidationRule, - MappedValueTypeRenderer, TableCellRendererProps, } from "@finos/vuu-datagrid-types"; import { @@ -40,7 +39,7 @@ const optionsMap = new Map(); export type EditRuleValidator = ( editRule: EditValidationRule, - value: VuuRowDataItemType + value?: VuuRowDataItemType ) => boolean | string; export type ComponentType = diff --git a/vuu-ui/pom.xml b/vuu-ui/pom.xml index dcff1ee08..611cae637 100644 --- a/vuu-ui/pom.xml +++ b/vuu-ui/pom.xml @@ -4,7 +4,7 @@ org.finos.vuu vuu-parent - 0.5.09-SNAPSHOT + 0.9.36-SNAPSHOT vuu-ui diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx index d40c26a70..56a3ccf18 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/VuuBasketTradingFeature.tsx @@ -33,6 +33,7 @@ const VuuBasketTradingFeature = (props: BasketTradingFeatureProps) => { activeTabIndex, basket, basketCount, + basketDesignContextMenuConfig, basketSelectorProps, contextMenuProps, dataSourceBasketTradingConstituentJoin, @@ -77,12 +78,12 @@ const VuuBasketTradingFeature = (props: BasketTradingFeatureProps) => { diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx index d12b1b48b..668974f03 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-edit/BasketTableEdit.tsx @@ -1,6 +1,10 @@ import { TableSchema } from "@finos/vuu-data"; -import { ColumnDescriptor, TableConfig } from "@finos/vuu-datagrid-types"; +import { TableConfig } from "@finos/vuu-datagrid-types"; import { TableNext, TableProps } from "@finos/vuu-table"; +import { + ContextMenuConfiguration, + ContextMenuProvider, +} from "@finos/vuu-popups"; import { useMemo } from "react"; import columns from "./basketConstituentEditColumns"; @@ -9,84 +13,16 @@ import "./BasketTableEdit.css"; const classBase = "vuuBasketTableEdit"; export interface BasketTableEditProps extends Omit { + contextMenuConfig: ContextMenuConfiguration; tableSchema: TableSchema; } -const labels: { [key: string]: string } = { - ask: "Ask", - bid: "Bid", - limitPrice: "Limit Price", - priceStrategy: "Price Strategy", - quantity: "Quantity", - weighting: "Weighting", -}; - -const applyColumnDefaults = (tableSchema: TableSchema) => - tableSchema.columns.map((column) => { - switch (column.name) { - case "limitPrice": - return { - ...column, - editable: true, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - alignOnDecimals: true, - decimals: 2, - zeroPad: true, - }, - renderer: { - name: "input-cell", - }, - }, - } as ColumnDescriptor; - case "quantity": - return { - ...column, - editable: true, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - decimals: 0, - }, - renderer: { - name: "input-cell", - }, - }, - }; - case "weighting": - return { - ...column, - editable: true, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - alignOnDecimals: true, - decimals: 2, - zeroPad: true, - }, - renderer: { - name: "input-cell", - }, - }, - }; - default: - return column; - } - }); - export const BasketTableEdit = ({ + contextMenuConfig, dataSource, tableSchema, ...props }: BasketTableEditProps) => { - useMemo(() => { - dataSource.columns = columns.map((col) => col.name); - }, [dataSource]); - const tableConfig = useMemo( () => ({ columns, @@ -96,13 +32,15 @@ export const BasketTableEdit = ({ ); return ( - + + + ); }; diff --git a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx index 4c43ef12a..d54276fd9 100644 --- a/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx +++ b/vuu-ui/sample-apps/feature-basket-trading/src/basket-table-live/BasketTableLive.tsx @@ -1,8 +1,9 @@ import { TableSchema } from "@finos/vuu-data"; -import { ColumnDescriptor, TableConfig } from "@finos/vuu-datagrid-types"; +import { TableConfig } from "@finos/vuu-datagrid-types"; import { TableNext, TableProps } from "@finos/vuu-table"; import { useMemo } from "react"; import { StatusCell } from "../cell-renderers"; +import columns from "./basketConstituentLiveColumns"; console.log(`component loaded StatusCell ${typeof StatusCell}`); import "./BasketTableLive.css"; @@ -13,137 +14,20 @@ export interface BasketTableLiveProps extends Omit { tableSchema: TableSchema; } -const labels: { [key: string]: string } = { - ask: "Ask", - bid: "Bid", - filled: "Pct Filled", - limitPrice: "Limit Price", - priceSpread: "Price Spread", - priceStrategy: "Price Strategy", - quantity: "Quantity", - weighting: "Weighting", -}; - -const applyColumnDefaults = (tableSchema: TableSchema) => - tableSchema.columns.map((column) => { - switch (column.name) { - case "ric": - return { - ...column, - label: "Ticker", - pin: "left", - }; - case "status": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "string", - renderer: { - name: "basket-status", - }, - }, - } as ColumnDescriptor; - case "ask": - case "bid": - case "last": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - alignOnDecimals: true, - decimals: 2, - zeroPad: true, - }, - }, - } as ColumnDescriptor; - case "limitPrice": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - alignOnDecimals: true, - decimals: 2, - zeroPad: true, - }, - }, - } as ColumnDescriptor; - case "priceStrategy": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "string", - }, - }; - case "priceSpread": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "number", - renderer: { - name: "basket-spread", - }, - }, - }; - case "quantity": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - decimals: 0, - }, - }, - }; - case "filled": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "number", - renderer: { - name: "basket-progress", - associatedField: "quantity", - }, - }, - }; - case "weighting": - return { - ...column, - label: labels[column.name] ?? column.name, - type: { - name: "number", - formatting: { - alignOnDecimals: true, - decimals: 2, - zeroPad: true, - }, - }, - }; - default: - return column; - } - }); - export const BasketTableLive = ({ tableSchema, ...props }: BasketTableLiveProps) => { const tableConfig = useMemo( () => ({ - columns: applyColumnDefaults(tableSchema), + columns, rowSeparators: true, }), - [tableSchema] + [] ); + console.log({ columns }); + return (