jofaichow commited on
Commit
c187e7a
1 Parent(s): c100647

0.1.4 - Improved Payout Summary

Browse files
Files changed (2) hide show
  1. Dockerfile +1 -1
  2. app/app.R +208 -47
Dockerfile CHANGED
@@ -9,7 +9,7 @@ RUN R -q -e "install.packages(c('shinyWidgets', 'shinycssloaders'))"
9
 
10
  # other R packages
11
  RUN R -q -e "install.packages(c('DT', 'plotly', 'scico', 'ggthemes', 'scales', 'wesanderson'))"
12
- RUN R -q -e "install.packages(c('data.table', 'dtplyr', 'parallel', 'Rnumerai'))"
13
 
14
  # copy the app to the image
15
  WORKDIR /shinyapp
 
9
 
10
  # other R packages
11
  RUN R -q -e "install.packages(c('DT', 'plotly', 'scico', 'ggthemes', 'scales', 'wesanderson'))"
12
+ RUN R -q -e "install.packages(c('data.table', 'dtplyr', 'Rnumerai'))"
13
 
14
  # copy the app to the image
15
  WORKDIR /shinyapp
app/app.R CHANGED
@@ -298,34 +298,65 @@ ui <- shinydashboardPlus::dashboardPage(
298
 
299
  tabsetPanel(type = "tabs",
300
 
301
- tabPanel("All Models",
 
302
 
303
  br(),
304
 
305
- h3(strong(textOutput(outputId = "text_payout_all_models"))),
 
 
306
 
307
  fluidRow(
308
  class = "text-center",
309
- valueBoxOutput("payout_confirmed", width = 2),
310
- valueBoxOutput("payout_pending", width = 2),
311
- valueBoxOutput("payout_total", width = 2),
312
- valueBoxOutput("payout_n_round", width = 2),
313
- valueBoxOutput("payout_average", width = 2),
314
- valueBoxOutput("payout_avg_ror", width = 2)
 
 
 
 
 
 
 
 
 
315
  ),
316
 
317
  br(),
318
 
319
- shinycssloaders::withSpinner(plotlyOutput("plot_payout_stacked")),
 
 
 
 
 
 
 
 
 
 
 
320
 
321
  br(),
 
 
 
322
  br(),
323
 
324
- DTOutput("dt_payout_summary")
 
 
 
 
 
325
 
326
  ),
327
 
328
- tabPanel("Individual Models",
329
  # br(),
330
  # materialSwitch(inputId = "switch_scale_payout",
331
  # label = "Fixed Scale?",
@@ -425,6 +456,7 @@ ui <- shinydashboardPlus::dashboardPage(
425
  - #### **0.1.1** — Added a functional `Payout Summary` page
426
  - #### **0.1.2** — `Payout Summary` layout updates
427
  - #### **0.1.3** — Added `Raw Data`
 
428
  "),
429
 
430
  br(),
@@ -443,7 +475,7 @@ ui <- shinydashboardPlus::dashboardPage(
443
 
444
  footer = shinydashboardPlus::dashboardFooter(
445
  left = "Powered by ❤️, ☕, Shiny, and 🤗 Spaces",
446
- right = paste0("Version 0.1.3"))
447
 
448
  )
449
 
@@ -614,57 +646,181 @@ server <- function(input, output) {
614
  # Reactive: Payout Value Boxes
615
  # ============================================================================
616
 
 
 
 
 
617
  output$text_payout_all_models <- renderText({
618
- if (nrow(react_d_filter()) >= 1) "Payouts in NMR (All Models)" else " "
619
  })
620
 
621
  output$text_payout_ind_models <- renderText({
622
  if (nrow(react_d_filter()) >= 1) "Payouts in NMR (Individual Models)" else " "
623
  })
624
 
625
- output$payout_confirmed <- renderValueBox({
626
- valueBox(value = round(sum(react_d_filter()[resolved == TRUE, ]$payout, na.rm = T), 2),
627
- subtitle = "Realised",
 
 
 
 
 
 
628
  color = "olive")
629
  })
630
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
631
  output$payout_pending <- renderValueBox({
632
- valueBox(value = round(sum(react_d_filter()[resolved == FALSE, ]$payout, na.rm = T), 2),
633
- subtitle = "Pending",
634
  color = "yellow")
635
  })
636
 
637
  output$payout_total <- renderValueBox({
638
- valueBox(value = round(sum(react_d_filter()$payout, na.rm = T), 2),
639
- subtitle = "Realised + Pending",
640
  color = "light-blue")
641
  })
642
 
643
- output$payout_n_round <- renderValueBox({
 
 
 
 
 
644
  # Use rounds with stake > 0 only
645
- valueBox(value = nrow(react_d_payout_summary()[total_stake > 0, ]),
646
- subtitle = "Staked Rounds",
647
- color = "light-blue")
 
 
 
 
 
 
 
648
  })
649
 
650
  output$payout_average <- renderValueBox({
651
  # Use rounds with stake > 0 only
652
- valueBox(value = round(mean(react_d_payout_summary()[total_stake > 0, ]$net_payout, na.rm = T), 2),
653
- subtitle = "Avg. Round Payout",
654
  color = "light-blue")
655
  })
656
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
  output$payout_avg_ror <- renderValueBox({
658
  # Use rounds with stake > 0 only
659
- valueBox(value = paste(round(mean(react_d_payout_summary()[total_stake > 0, ]$rate_of_return), 2), "%"),
660
- subtitle = "Avg. Round ROR",
661
  color = "light-blue")
662
  })
 
663
 
664
  # ============================================================================
665
  # Reactive: Payout Charts
666
  # ============================================================================
667
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  # Stacked Bar Chart
669
  output$plot_payout_stacked <- renderPlotly({
670
 
@@ -674,14 +830,17 @@ server <- function(input, output) {
674
  # Filter
675
  d_filter <- d_filter[stake > 0]
676
 
 
 
 
677
  # ggplot
678
  p <- ggplot(d_filter,
679
- aes(x = date_resolved, y = payout, fill = payout,
680
  text = paste("Model:", model,
681
  "\nRound:", round,
682
  "\nRound Open Date:", date_open,
683
  "\nRound Resolved Date:", date_resolved,
684
- "\nRound Status:", resolved,
685
  "\nPayout:", round(payout,2), "NMR"))) +
686
  geom_bar(position = "stack", stat = "identity") +
687
  theme(
@@ -697,13 +856,14 @@ server <- function(input, output) {
697
  legend.background = element_rect(fill = 'transparent'),
698
  legend.box.background = element_rect(fill = 'transparent')
699
  ) +
 
700
  geom_hline(aes(yintercept = 0), linewidth = 0.25, color = "grey") +
701
  scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
702
- scale_x_date(breaks = breaks_pretty(10),
703
- labels = label_date_short(format = c("%Y", "%b", "%d"), sep = "\n")
704
- ) +
705
- xlab(" \nDate (Round Resolved / Resolving)") +
706
- ylab("Realised / Pending Payout (NMR)")
707
 
708
  # Generate plotly
709
  ggplotly(p, tooltip = "text")
@@ -730,7 +890,7 @@ server <- function(input, output) {
730
  "\nRound:", round,
731
  "\nRound Open Date:", date_open,
732
  "\nRound Resolved Date:", date_resolved,
733
- "\nRound Status:", resolved,
734
  "\nPayout:", round(payout,2), "NMR"))) +
735
  geom_bar(stat = "identity") +
736
  theme(
@@ -749,17 +909,18 @@ server <- function(input, output) {
749
  geom_hline(aes(yintercept = 0), linewidth = 0.25, color = "grey") +
750
  scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
751
  scale_x_continuous(breaks = breaks_pretty(5)) +
752
- xlab(" \nTournament Round") +
753
- ylab("Realised / Pending Payout (NMR)")
754
 
755
  # Facet setting
756
- if ((n_model %% 4) == 0) {
757
- p <- p + facet_wrap(. ~ model, ncol = 4, scales = "fixed")
758
- } else if ((n_model %% 5) == 0) {
759
- p <- p + facet_wrap(. ~ model, ncol = 5, scales = "fixed")
760
- } else {
761
- p <- p + facet_wrap(. ~ model, ncol = 6, scales = "fixed")
762
- }
 
763
 
764
  # Dynamic height adjustment
765
  height <- 600 # default minimum height
@@ -802,8 +963,8 @@ server <- function(input, output) {
802
  dom = 'Bflrtip', # https://datatables.net/reference/option/dom
803
  buttons = list('csv', 'excel', 'copy', 'print'), # https://rstudio.github.io/DT/003-tabletools-buttons.html
804
  order = list(list(0, 'asc'), list(1, 'asc')),
805
- pageLength = 100,
806
- lengthMenu = c(5, 10, 20, 100, 500, 1000),
807
  columnDefs = list(list(className = 'dt-center', targets = "_all")))
808
  ) |>
809
 
 
298
 
299
  tabsetPanel(type = "tabs",
300
 
301
+
302
+ tabPanel("Net Round Payouts",
303
 
304
  br(),
305
 
306
+ h3(strong(textOutput(outputId = "text_payout_net"))),
307
+
308
+ br(),
309
 
310
  fluidRow(
311
  class = "text-center",
312
+
313
+ valueBoxOutput("payout_n_round_resolved", width = 3),
314
+ valueBoxOutput("payout_resolved", width = 3),
315
+ valueBoxOutput("payout_average_resolved", width = 3),
316
+ valueBoxOutput("payout_avg_ror_resolved", width = 3),
317
+
318
+ valueBoxOutput("payout_n_round_pending", width = 3),
319
+ valueBoxOutput("payout_pending", width = 3),
320
+ valueBoxOutput("payout_average_pending", width = 3),
321
+ valueBoxOutput("payout_avg_ror_pending", width = 3),
322
+
323
+ valueBoxOutput("payout_n_round", width = 3),
324
+ valueBoxOutput("payout_total", width = 3),
325
+ valueBoxOutput("payout_average", width = 3),
326
+ valueBoxOutput("payout_avg_ror", width = 3)
327
  ),
328
 
329
  br(),
330
 
331
+ shinycssloaders::withSpinner(plotlyOutput("plot_payout_net")),
332
+
333
+ br(),
334
+
335
+ DTOutput("dt_payout_summary"),
336
+
337
+ br()
338
+
339
+ ),
340
+
341
+
342
+ tabPanel("Chart (Stacked Payouts)",
343
 
344
  br(),
345
+
346
+ h3(strong(textOutput(outputId = "text_payout_all_models"))),
347
+
348
  br(),
349
 
350
+ shinycssloaders::withSpinner(plotlyOutput("plot_payout_stacked")),
351
+
352
+ br()
353
+ # br(),
354
+
355
+ # DTOutput("dt_payout_summary")
356
 
357
  ),
358
 
359
+ tabPanel("Chart (Individual Models)",
360
  # br(),
361
  # materialSwitch(inputId = "switch_scale_payout",
362
  # label = "Fixed Scale?",
 
456
  - #### **0.1.1** — Added a functional `Payout Summary` page
457
  - #### **0.1.2** — `Payout Summary` layout updates
458
  - #### **0.1.3** — Added `Raw Data`
459
+ - #### **0.1.4** — Improved and sped up `Payout Summary`
460
  "),
461
 
462
  br(),
 
475
 
476
  footer = shinydashboardPlus::dashboardFooter(
477
  left = "Powered by ❤️, ☕, Shiny, and 🤗 Spaces",
478
+ right = paste0("Version 0.1.4"))
479
 
480
  )
481
 
 
646
  # Reactive: Payout Value Boxes
647
  # ============================================================================
648
 
649
+ output$text_payout_net <- renderText({
650
+ if (nrow(react_d_filter()) >= 1) "Net Payouts in NMR" else " "
651
+ })
652
+
653
  output$text_payout_all_models <- renderText({
654
+ if (nrow(react_d_filter()) >= 1) "Payouts in NMR (Stacked)" else " "
655
  })
656
 
657
  output$text_payout_ind_models <- renderText({
658
  if (nrow(react_d_filter()) >= 1) "Payouts in NMR (Individual Models)" else " "
659
  })
660
 
661
+
662
+ # ============================================================================
663
+ # Reactive valueBox outputs: Rounds
664
+ # ============================================================================
665
+
666
+ output$payout_n_round_resolved <- renderValueBox({
667
+ # Use rounds with stake > 0 only
668
+ valueBox(value = nrow(react_d_payout_summary()[resolved == TRUE & total_stake > 0, ]),
669
+ subtitle = "Staked Rounds (Resolved)",
670
  color = "olive")
671
  })
672
 
673
+
674
+ output$payout_n_round_pending <- renderValueBox({
675
+ # Use rounds with stake > 0 only
676
+ valueBox(value = nrow(react_d_payout_summary()[resolved == FALSE & total_stake > 0, ]),
677
+ subtitle = "Staked Rounds (Pending)",
678
+ color = "yellow")
679
+ })
680
+
681
+
682
+ output$payout_n_round <- renderValueBox({
683
+ # Use rounds with stake > 0 only
684
+ valueBox(value = nrow(react_d_payout_summary()[total_stake > 0, ]),
685
+ subtitle = "Staked Rounds (All)",
686
+ color = "light-blue")
687
+ })
688
+
689
+
690
+ # ============================================================================
691
+ # Reactive valueBox outputs: Payouts
692
+ # ============================================================================
693
+
694
+ output$payout_resolved <- renderValueBox({
695
+ valueBox(value = as.character(format(round(sum(react_d_filter()[resolved == T, ]$payout, na.rm = T), 2), nsmall = 2)),
696
+ subtitle = "Total Payout (Resolved)",
697
+ color = "olive")
698
+ })
699
+
700
  output$payout_pending <- renderValueBox({
701
+ valueBox(value = as.character(format(round(sum(react_d_filter()[resolved == F, ]$payout, na.rm = T), 2), nsmall = 2)),
702
+ subtitle = "Total Payout (Pending)",
703
  color = "yellow")
704
  })
705
 
706
  output$payout_total <- renderValueBox({
707
+ valueBox(value = as.character(format(round(sum(react_d_filter()$payout, na.rm = T), 2), nsmall = 2)),
708
+ subtitle = "Total Payout (All)",
709
  color = "light-blue")
710
  })
711
 
712
+
713
+ # ============================================================================
714
+ # Reactive valueBox outputs: Average Round Payouts
715
+ # ============================================================================
716
+
717
+ output$payout_average_resolved <- renderValueBox({
718
  # Use rounds with stake > 0 only
719
+ valueBox(value = as.character(format(round(mean(react_d_payout_summary()[resolved == T & total_stake > 0, ]$net_payout, na.rm = T), 2), nsmall = 2)),
720
+ subtitle = "Avg. Round Payout (Resolved)",
721
+ color = "olive")
722
+ })
723
+
724
+ output$payout_average_pending <- renderValueBox({
725
+ # Use rounds with stake > 0 only
726
+ valueBox(value = as.character(format(round(mean(react_d_payout_summary()[resolved == F & total_stake > 0, ]$net_payout, na.rm = T), 2), nsmall = 2)),
727
+ subtitle = "Avg. Round Payout (Pending)",
728
+ color = "yellow")
729
  })
730
 
731
  output$payout_average <- renderValueBox({
732
  # Use rounds with stake > 0 only
733
+ valueBox(value = as.character(format(round(mean(react_d_payout_summary()[total_stake > 0, ]$net_payout, na.rm = T), 2), nsmall = 2)),
734
+ subtitle = "Avg. Round Payout (All)",
735
  color = "light-blue")
736
  })
737
 
738
+ # ============================================================================
739
+ # Reactive valueBox outputs: Average Rate of Return
740
+ # ============================================================================
741
+
742
+ output$payout_avg_ror_resolved <- renderValueBox({
743
+ # Use rounds with stake > 0 only
744
+ valueBox(value = paste(as.character(format(round(mean(react_d_payout_summary()[resolved == T & total_stake > 0, ]$rate_of_return), 2), nsmall = 2)), "%"),
745
+ subtitle = "Avg. Round ROR (Resolved)",
746
+ color = "olive")
747
+ })
748
+
749
+ output$payout_avg_ror_pending <- renderValueBox({
750
+ # Use rounds with stake > 0 only
751
+ valueBox(value = paste(as.character(format(round(mean(react_d_payout_summary()[resolved == F & total_stake > 0, ]$rate_of_return), 2), nsmall = 2)), "%"),
752
+ subtitle = "Avg. Round ROR (Pending)",
753
+ color = "yellow")
754
+ })
755
+
756
  output$payout_avg_ror <- renderValueBox({
757
  # Use rounds with stake > 0 only
758
+ valueBox(value = paste(as.character(format(round(mean(react_d_payout_summary()[total_stake > 0, ]$rate_of_return), 2), nsmall = 2)), "%"),
759
+ subtitle = "Avg. Round ROR (All)",
760
  color = "light-blue")
761
  })
762
+
763
 
764
  # ============================================================================
765
  # Reactive: Payout Charts
766
  # ============================================================================
767
 
768
+
769
+ # Net Payouts Bar Chart
770
+ output$plot_payout_net <- renderPlotly({
771
+
772
+ # Data
773
+ d_filter <- react_d_payout_summary()
774
+
775
+ # Filter
776
+ d_filter <- d_filter[total_stake > 0]
777
+
778
+ # Divider (resolved vs pending)
779
+ x_marker <- max(d_filter[resolved == TRUE]$round) + 0.5
780
+ y_marker <- max(d_filter$net_payout)
781
+
782
+ # ggplot
783
+ p <- ggplot(d_filter,
784
+ aes(x = round, y = net_payout, fill = net_payout,
785
+ text = paste("Round:", round,
786
+ "\nRound Open Date:", date_open,
787
+ "\nRound Resolved Date:", date_resolved,
788
+ "\nRound Resolved?:", resolved,
789
+ "\nPayout:", round(net_payout,2), "NMR"))) +
790
+
791
+ geom_bar(position = "stack", stat = "identity") +
792
+ theme(
793
+ panel.border = element_rect(fill = 'transparent',
794
+ color = "grey", linewidth = 0.25),
795
+ panel.background = element_rect(fill = 'transparent'),
796
+ plot.background = element_rect(fill = 'transparent', color = NA),
797
+ panel.grid.major = element_blank(),
798
+ panel.grid.minor = element_blank(),
799
+ strip.background = element_rect(fill = 'transparent'),
800
+ strip.text = element_text(),
801
+ strip.clip = "on",
802
+ legend.background = element_rect(fill = 'transparent'),
803
+ legend.box.background = element_rect(fill = 'transparent')
804
+ ) +
805
+
806
+ geom_vline(aes(xintercept = x_marker), linewidth = 0.25, color = "grey", linetype = "dashed") +
807
+ geom_hline(aes(yintercept = 0), linewidth = 0.25, color = "grey") +
808
+
809
+ annotate("text", x = x_marker, y = y_marker*1.2, label = "← Resolved vs. Pending →") +
810
+
811
+ scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
812
+ # scale_x_date(breaks = breaks_pretty(10),
813
+ # labels = label_date_short(format = c("%Y", "%b", "%d"), sep = "\n")
814
+ # ) +
815
+ xlab("\nTournament Round") +
816
+ ylab("Round Payout (NMR)")
817
+
818
+ # Generate plotly
819
+ ggplotly(p, tooltip = "text")
820
+
821
+ })
822
+
823
+
824
  # Stacked Bar Chart
825
  output$plot_payout_stacked <- renderPlotly({
826
 
 
830
  # Filter
831
  d_filter <- d_filter[stake > 0]
832
 
833
+ # Divider (resolved vs pending)
834
+ x_marker <- max(d_filter[resolved == TRUE]$round) + 0.5
835
+
836
  # ggplot
837
  p <- ggplot(d_filter,
838
+ aes(x = round, y = payout, fill = payout,
839
  text = paste("Model:", model,
840
  "\nRound:", round,
841
  "\nRound Open Date:", date_open,
842
  "\nRound Resolved Date:", date_resolved,
843
+ "\nRound Resolved?:", resolved,
844
  "\nPayout:", round(payout,2), "NMR"))) +
845
  geom_bar(position = "stack", stat = "identity") +
846
  theme(
 
856
  legend.background = element_rect(fill = 'transparent'),
857
  legend.box.background = element_rect(fill = 'transparent')
858
  ) +
859
+ geom_vline(aes(xintercept = x_marker), linewidth = 0.25, color = "grey", linetype = "dashed") +
860
  geom_hline(aes(yintercept = 0), linewidth = 0.25, color = "grey") +
861
  scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
862
+ # scale_x_date(breaks = breaks_pretty(10),
863
+ # labels = label_date_short(format = c("%Y", "%b", "%d"), sep = "\n")
864
+ # ) +
865
+ xlab("\nTournament Round") +
866
+ ylab("Round Payout (NMR)")
867
 
868
  # Generate plotly
869
  ggplotly(p, tooltip = "text")
 
890
  "\nRound:", round,
891
  "\nRound Open Date:", date_open,
892
  "\nRound Resolved Date:", date_resolved,
893
+ "\nRound Resolved:", resolved,
894
  "\nPayout:", round(payout,2), "NMR"))) +
895
  geom_bar(stat = "identity") +
896
  theme(
 
909
  geom_hline(aes(yintercept = 0), linewidth = 0.25, color = "grey") +
910
  scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
911
  scale_x_continuous(breaks = breaks_pretty(5)) +
912
+ xlab("\nTournament Round") +
913
+ ylab("Payout (NMR)")
914
 
915
  # Facet setting
916
+ # if ((n_model %% 4) == 0) {
917
+ # p <- p + facet_wrap(. ~ model, ncol = 4, scales = "fixed")
918
+ # } else if ((n_model %% 5) == 0) {
919
+ # p <- p + facet_wrap(. ~ model, ncol = 5, scales = "fixed")
920
+ # } else {
921
+ # p <- p + facet_wrap(. ~ model, ncol = 6, scales = "fixed")
922
+ # }
923
+ p <- p + facet_wrap(. ~ model, ncol = 5, scales = "fixed") # fixed
924
 
925
  # Dynamic height adjustment
926
  height <- 600 # default minimum height
 
963
  dom = 'Bflrtip', # https://datatables.net/reference/option/dom
964
  buttons = list('csv', 'excel', 'copy', 'print'), # https://rstudio.github.io/DT/003-tabletools-buttons.html
965
  order = list(list(0, 'asc'), list(1, 'asc')),
966
+ pageLength = 500,
967
+ lengthMenu = c(10, 50, 100, 500, 1000),
968
  columnDefs = list(list(className = 'dt-center', targets = "_all")))
969
  ) |>
970