Compare commits

..
869 changed files with 18490 additions and 48115 deletions

No files matched your search

+3 -2
View File
@@ -1,6 +1,5 @@
nohup.out
build/**
install/**
build/
.build_proxy/
cmake-build-debug/
.cache/
@@ -41,6 +40,8 @@ trace_data/
.ionide/*
/.ignore
*.rej
/build
/build.*/*
.clangd/
*CMakeDeps.cmake
/sniper.ipynb
+1 -13
View File
@@ -13,7 +13,6 @@ set(SPARK_BIN "${EXTERNALS_ROOT}/bin")
set(SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set(SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
set(BUILD_SDK OFF CACHE BOOL "Build the sdk")
set(BUILD_WEB ON CACHE BOOL "Build the web server")
include_directories(BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
link_directories(${SPARK_LIB})
@@ -48,11 +47,6 @@ else()
# make sparkd look for libspark.so in its directory
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH ".")
set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install/${CMAKE_BUILD_TYPE}/sparkd")
add_compile_definitions(SPARK_ENABLE_CCAPI)
add_compile_definitions(CCAPI_ENABLE_SERVICE_MARKET_DATA)
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_FTX)
add_compile_definitions(CCAPI_ENABLE_LOG_WARN)
# flags
set(
@@ -73,9 +67,7 @@ else()
# subdirs
add_subdirectory(src/server/sparkd)
add_subdirectory(src/lib)
if (BUILD_WEB)
add_subdirectory(src/web)
endif()
add_subdirectory(src/web)
add_subdirectory(doc/user)
if(BUILD_SDK)
add_subdirectory(src/sdk)
@@ -99,8 +91,4 @@ else()
DEPENDS sparkd data_files_dir)
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
install(FILES "${CMAKE_SOURCE_DIR}/externals/src/emumba/sparkd.lic" DESTINATION bin)
endif()
File renamed without changes.
@@ -1,941 +0,0 @@
{
"$schema": "vscode://schemas/color-theme",
"type": "dark",
"colors": {
"activityBar.background": "#111111",
"activityBar.border": "#111111",
"activityBar.foreground": "#888888",
"activityBarBadge.background": "#88cc44",
"activityBarBadge.foreground": "#222222",
"badge.background": "#88cc44",
"badge.foreground": "#222222",
"button.background": "#333333",
"button.foreground": "#888888",
"button.hoverBackground": "#222222",
"debugExceptionWidget.background": "#333333",
"debugExceptionWidget.border": "#222222",
"debugToolBar.background": "#111111",
"diffEditor.insertedTextBackground": "#ffdd440c",
"diffEditor.insertedTextBorder": "#ffdd44",
"diffEditor.removedTextBackground": "#88bbff0c",
"diffEditor.removedTextBorder": "#88bbff",
"dropdown.background": "#222222",
"dropdown.border": "#222222",
"dropdown.foreground": "#888888",
"editor.background": "#222222",
"editor.findMatchBackground": "#44446655",
"editor.findMatchHighlightBackground": "#444466aa",
"editor.foreground": "#ffffff",
"editor.hoverHighlightBackground": "#44446655",
"editor.inactiveSelectionBackground": "#44446655",
"editor.lineHighlightBackground": "#00000066",
"editor.lineHighlightBorder": "#00000000",
"editor.rangeHighlightBackground": "#333333",
"editor.selectionBackground": "#444466",
"editor.selectionHighlightBackground": "#44446655",
"editor.wordHighlightBackground": "#44446655",
"editor.wordHighlightStrongBackground": "#44446655",
"editorBracketMatch.background": "#222222",
"editorBracketMatch.border": "#666666",
"editorCodeLens.foreground": "#666666",
"editorCursor.foreground": "#ffffff",
"editorError.foreground": "#ee5500",
"editorGroup.border": "#111111",
"editorGroup.dropBackground": "#111111bb",
"editorGroupHeader.noTabsBackground": "#111111",
"editorGroupHeader.tabsBackground": "#111111",
"editorGroupHeader.tabsBorder": "#222222",
"editorGutter.addedBackground": "#ffdd44",
"editorGutter.background": "#222222",
"editorGutter.deletedBackground": "#88bbff",
"editorGutter.modifiedBackground": "#88bbff",
"editorHoverWidget.background": "#333333",
"editorHoverWidget.border": "#222222",
"editorIndentGuide.background": "#333333",
"editorLineNumber.foreground": "#555555",
"editorLink.activeForeground": "#bba0ff",
"editorMarkerNavigation.background": "#333333",
"editorMarkerNavigationError.background": "#88bbff",
"editorMarkerNavigationWarning.background": "#88bbff",
"editorOverviewRuler.addedForeground": "#ffdd44",
"editorOverviewRuler.border": "#222222",
"editorOverviewRuler.currentContentForeground": "#333333",
"editorOverviewRuler.deletedForeground": "#88bbff",
"editorOverviewRuler.errorForeground": "#88bbff",
"editorOverviewRuler.findMatchForeground": "#555555",
"editorOverviewRuler.incomingContentForeground": "#333333",
"editorOverviewRuler.infoForeground": "#bba0ff",
"editorOverviewRuler.modifiedForeground": "#88bbff",
"editorOverviewRuler.rangeHighlightForeground": "#333333",
"editorOverviewRuler.selectionHighlightForeground": "#555555",
"editorOverviewRuler.warningForeground": "#88bbff",
"editorOverviewRuler.wordHighlightForeground": "#333333",
"editorOverviewRuler.wordHighlightStrongForeground": "#555555",
"editorRuler.foreground": "#ffffff",
"editorSuggestWidget.background": "#333333",
"editorSuggestWidget.border": "#333333",
"editorSuggestWidget.foreground": "#888888",
"editorSuggestWidget.highlightForeground": "#ffffff",
"editorSuggestWidget.selectedBackground": "#666666",
"editorWarning.border": "#00000000",
"editorWarning.foreground": "#88bbff",
"editorWhitespace.foreground": "#333333",
"editorWidget.background": "#333333",
"editorWidget.border": "#333333",
"errorForeground": "#88bbff",
"extensionButton.prominentBackground": "#333333",
"extensionButton.prominentForeground": "#ffffff",
"extensionButton.prominentHoverBackground": "#555555",
"focusBorder": "#666666",
"foreground": "#ffffff",
"gitDecoration.modifiedResourceForeground": "#cccccc",
"gitDecoration.untrackedResourceForeground": "#cccccc",
"input.background": "#333333",
"input.border": "#333333",
"input.foreground": "#ffffff",
"input.placeholderForeground": "#555555",
"inputOption.activeBorder": "#555555",
"inputValidation.errorBackground": "#333333",
"inputValidation.errorBorder": "#88bbff",
"inputValidation.infoBackground": "#333333",
"inputValidation.infoBorder": "#bba0ff",
"inputValidation.warningBackground": "#333333",
"inputValidation.warningBorder": "#88bbff",
"list.activeSelectionBackground": "#111111",
"list.activeSelectionForeground": "#ffffff",
"list.dropBackground": "#111111bf",
"list.focusBackground": "#222222",
"list.focusForeground": "#ffffff",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#333333",
"list.hoverForeground": "#ffffff",
"list.inactiveSelectionBackground": "#000000",
"list.inactiveSelectionForeground": "#ffffff",
"menu.background": "#333333",
"menu.foreground": "#ffffff",
"merge.border": "#222222",
"merge.currentContentBackground": "#333333",
"merge.currentHeaderBackground": "#555555",
"merge.incomingContentBackground": "#555555",
"merge.incomingHeaderBackground": "#666666",
"panel.background": "#111111",
"panel.border": "#111111",
"panelTitle.activeBorder": "#ffffff",
"panelTitle.activeForeground": "#ffffff",
"panelTitle.inactiveForeground": "#888888",
"peekView.border": "#222222",
"peekViewEditor.background": "#333333",
"peekViewEditor.matchHighlightBackground": "#555555",
"peekViewEditorGutter.background": "#333333",
"peekViewResult.background": "#333333",
"peekViewResult.fileForeground": "#888888",
"peekViewResult.lineForeground": "#888888",
"peekViewResult.matchHighlightBackground": "#555555",
"peekViewResult.selectionBackground": "#333333",
"peekViewResult.selectionForeground": "#ffffff",
"peekViewTitle.background": "#333333",
"peekViewTitleDescription.foreground": "#888888",
"peekViewTitleLabel.foreground": "#ffffff",
"pickerGroup.border": "#222222",
"pickerGroup.foreground": "#555555",
"progressBar.background": "#333333",
"scrollbar.shadow": "#191919",
"scrollbarSlider.activeBackground": "#ffffff12",
"scrollbarSlider.background": "#ffffff12",
"scrollbarSlider.hoverBackground": "#ffffff12",
"selection.background": "#2255aa",
"sideBar.background": "#111111",
"sideBar.border": "#111111",
"sideBar.foreground": "#888888",
"sideBarSectionHeader.background": "#111111",
"sideBarSectionHeader.foreground": "#666666",
"sideBarTitle.foreground": "#555555",
"statusBar.background": "#111111",
"statusBar.border": "#111111",
"statusBar.debuggingBackground": "#666666",
"statusBar.debuggingForeground": "#ffffff",
"statusBar.foreground": "#666666",
"statusBar.noFolderBackground": "#111111",
"statusBar.noFolderForeground": "#666666",
"statusBarItem.activeBackground": "#222222",
"statusBarItem.hoverBackground": "#222222",
"statusBarItem.prominentBackground": "#333333",
"statusBarItem.prominentHoverBackground": "#444444",
"tab.activeBackground": "#222222",
"tab.border": "#111111",
"tab.inactiveBackground": "#111111",
"tab.inactiveForeground": "#888888",
"tab.unfocusedActiveBorder": "#888888",
"tab.unfocusedActiveForeground": "#888888",
"tab.unfocusedInactiveForeground": "#888888",
"terminal.ansiBlack": "#333333",
"terminal.ansiBlue": "#88bbff",
"terminal.ansiBrightBlack": "#666666",
"terminal.ansiBrightBlue": "#88bbff",
"terminal.ansiBrightCyan": "#bba0ff",
"terminal.ansiBrightGreen": "#ffdd44",
"terminal.ansiBrightMagenta": "#88bbff",
"terminal.ansiBrightRed": "#88bbff",
"terminal.ansiBrightWhite": "#ffffff",
"terminal.ansiBrightYellow": "#88cc44",
"terminal.ansiCyan": "#bba0ff",
"terminal.ansiGreen": "#ffdd44",
"terminal.ansiMagenta": "#88bbff",
"terminal.ansiRed": "#88bbff",
"terminal.ansiWhite": "#ffffff",
"terminal.ansiYellow": "#88cc44",
"terminal.background": "#151515",
"terminal.foreground": "#ffffff",
"titleBar.activeBackground": "#111111",
"titleBar.activeForeground": "#888888",
"titleBar.inactiveBackground": "#111111",
"titleBar.inactiveForeground": "#555555",
"walkThrough.embeddedEditorBackground": "#111111",
"widget.shadow": "#111111",
//"activityBar.activeBorder": "#888888",
//"activityBar.dropBorder": "#888888",
//"activityBar.inactiveForeground": "#88888866",
//"banner.background": "#111111",
//"banner.foreground": "#ffffff",
//"banner.iconForeground": "#3794ff",
//"bookmarks.lineBackground": "#00000000",
//"bookmarks.lineBorder": "#00000000",
//"bookmarks.overviewRuler": "#157efb88",
//"breadcrumb.activeSelectionForeground": "#ffffff",
//"breadcrumb.background": "#222222",
//"breadcrumb.focusForeground": "#ffffff",
//"breadcrumb.foreground": "#ffffffcc",
//"breadcrumbPicker.background": "#333333",
//"button.secondaryBackground": "#3a3d41",
//"button.secondaryForeground": "#ffffff",
//"button.secondaryHoverBackground": "#45494e",
//"charts.blue": "#3794ff",
//"charts.foreground": "#ffffff",
//"charts.green": "#89d185",
//"charts.lines": "#ffffff80",
//"charts.orange": "#d18616",
//"charts.purple": "#b180d7",
//"charts.red": "#ee5500",
//"charts.yellow": "#88bbff",
//"checkbox.background": "#222222",
//"checkbox.border": "#222222",
//"checkbox.foreground": "#888888",
//"debugConsole.errorForeground": "#88bbff",
//"debugConsole.infoForeground": "#3794ff",
//"debugConsole.sourceForeground": "#ffffff",
//"debugConsole.warningForeground": "#88bbff",
//"debugConsoleInputIcon.foreground": "#ffffff",
//"debugIcon.breakpointCurrentStackframeForeground": "#ffcc00",
//"debugIcon.breakpointDisabledForeground": "#848484",
//"debugIcon.breakpointForeground": "#e51400",
//"debugIcon.breakpointStackframeForeground": "#89d185",
//"debugIcon.breakpointUnverifiedForeground": "#848484",
//"debugIcon.continueForeground": "#75beff",
//"debugIcon.disconnectForeground": "#f48771",
//"debugIcon.pauseForeground": "#75beff",
//"debugIcon.restartForeground": "#89d185",
//"debugIcon.startForeground": "#89d185",
//"debugIcon.stepBackForeground": "#75beff",
//"debugIcon.stepIntoForeground": "#75beff",
//"debugIcon.stepOutForeground": "#75beff",
//"debugIcon.stepOverForeground": "#75beff",
//"debugIcon.stopForeground": "#f48771",
//"debugTokenExpression.boolean": "#4e94ce",
//"debugTokenExpression.error": "#f48771",
//"debugTokenExpression.name": "#c586c0",
//"debugTokenExpression.number": "#b5cea8",
//"debugTokenExpression.string": "#ce9178",
//"debugTokenExpression.value": "#cccccc99",
//"debugView.exceptionLabelBackground": "#6c2022",
//"debugView.exceptionLabelForeground": "#ffffff",
//"debugView.stateLabelBackground": "#88888844",
//"debugView.stateLabelForeground": "#ffffff",
//"debugView.valueChangedHighlight": "#569cd6",
//"descriptionForeground": "#ffffffb3",
//"diffEditor.diagonalFill": "#cccccc33",
//"editor.findRangeHighlightBackground": "#3a3d4166",
//"editor.focusedStackFrameHighlightBackground": "#7abd7a4d",
//"editor.foldBackground": "#4444664d",
//"editor.inlineValuesBackground": "#ffc80033",
//"editor.inlineValuesForeground": "#ffffff80",
//"editor.linkedEditingBackground": "#ff00004d",
//"editor.snippetFinalTabstopHighlightBorder": "#525252",
//"editor.snippetTabstopHighlightBackground": "#7c7c7c4d",
//"editor.stackFrameHighlightBackground": "#ffff0033",
//"editor.symbolHighlightBackground": "#444466aa",
//"editorActiveLineNumber.foreground": "#c6c6c6",
//"editorBracketHighlight.foreground1": "#ffd700",
//"editorBracketHighlight.foreground2": "#da70d6",
//"editorBracketHighlight.foreground3": "#179fff",
//"editorBracketHighlight.foreground4": "#00000000",
//"editorBracketHighlight.foreground5": "#00000000",
//"editorBracketHighlight.foreground6": "#00000000",
//"editorBracketHighlight.unexpectedBracket.foreground": "#ff1212cc",
//"editorBracketPairGuide.activeBackground1": "#00000000",
//"editorBracketPairGuide.activeBackground2": "#00000000",
//"editorBracketPairGuide.activeBackground3": "#00000000",
//"editorBracketPairGuide.activeBackground4": "#00000000",
//"editorBracketPairGuide.activeBackground5": "#00000000",
//"editorBracketPairGuide.activeBackground6": "#00000000",
//"editorBracketPairGuide.background1": "#00000000",
//"editorBracketPairGuide.background2": "#00000000",
//"editorBracketPairGuide.background3": "#00000000",
//"editorBracketPairGuide.background4": "#00000000",
//"editorBracketPairGuide.background5": "#00000000",
//"editorBracketPairGuide.background6": "#00000000",
//"editorGhostText.foreground": "#ffffff56",
//"editorGutter.commentRangeForeground": "#c5c5c5",
//"editorGutter.foldingControlForeground": "#c5c5c5",
//"editorHint.foreground": "#eeeeeeb3",
//"editorHoverWidget.foreground": "#ffffff",
//"editorHoverWidget.highlightForeground": "#ffffff",
//"editorHoverWidget.statusBarBackground": "#3d3d3d",
//"editorIndentGuide.activeBackground": "#333333",
//"editorInfo.foreground": "#3794ff",
//"editorInlayHint.background": "#88cc4499",
//"editorInlayHint.foreground": "#222222cc",
//"editorInlayHint.parameterBackground": "#88cc4499",
//"editorInlayHint.parameterForeground": "#222222cc",
//"editorInlayHint.typeBackground": "#88cc4499",
//"editorInlayHint.typeForeground": "#222222cc",
//"editorLightBulb.foreground": "#ffcc00",
//"editorLightBulbAutoFix.foreground": "#75beff",
//"editorLineNumber.activeForeground": "#c6c6c6",
//"editorMarkerNavigationError.headerBackground": "#88bbff1a",
//"editorMarkerNavigationInfo.background": "#3794ff",
//"editorMarkerNavigationInfo.headerBackground": "#3794ff1a",
//"editorMarkerNavigationWarning.headerBackground": "#88bbff1a",
//"editorOverviewRuler.bracketMatchForeground": "#a0a0a0",
//"editorOverviewRuler.commonContentForeground": "#60606066",
//"editorOverviewRuler.unicodeForeground": "#d186167e",
//"editorPane.background": "#222222",
//"editorSuggestWidget.focusHighlightForeground": "#ffffff",
//"editorSuggestWidget.selectedForeground": "#ffffff",
//"editorSuggestWidgetStatus.foreground": "#88888880",
//"editorUnicodeHighlight.border": "#bd9b03",
//"editorUnnecessaryCode.opacity": "#000000aa",
//"editorWidget.foreground": "#ffffff",
//"extensionBadge.remoteBackground": "#88cc44",
//"extensionBadge.remoteForeground": "#222222",
//"extensionIcon.preReleaseForeground": "#1d9271",
//"extensionIcon.starForeground": "#ff8e00",
//"extensionIcon.verifiedForeground": "#3794ff",
//"gitDecoration.addedResourceForeground": "#81b88b",
//"gitDecoration.conflictingResourceForeground": "#e4676b",
//"gitDecoration.deletedResourceForeground": "#c74e39",
//"gitDecoration.ignoredResourceForeground": "#8c8c8c",
//"gitDecoration.renamedResourceForeground": "#73c991",
//"gitDecoration.stageDeletedResourceForeground": "#c74e39",
//"gitDecoration.stageModifiedResourceForeground": "#e2c08d",
//"gitDecoration.submoduleResourceForeground": "#8db9e2",
//"gitlens.closedAutolinkedIssueIconColor": "#a371f7",
//"gitlens.closedPullRequestIconColor": "#f85149",
//"gitlens.decorations.addedForegroundColor": "#81b88b",
//"gitlens.decorations.branchAheadForegroundColor": "#35b15e",
//"gitlens.decorations.branchBehindForegroundColor": "#b15e35",
//"gitlens.decorations.branchDivergedForegroundColor": "#d8af1b",
//"gitlens.decorations.branchMissingUpstreamForegroundColor": "#c74e39",
//"gitlens.decorations.branchUnpublishedForegroundColor": "#35b15e",
//"gitlens.decorations.branchUpToDateForegroundColor": "#888888",
//"gitlens.decorations.copiedForegroundColor": "#73c991",
//"gitlens.decorations.deletedForegroundColor": "#c74e39",
//"gitlens.decorations.ignoredForegroundColor": "#8c8c8c",
//"gitlens.decorations.modifiedForegroundColor": "#cccccc",
//"gitlens.decorations.renamedForegroundColor": "#73c991",
//"gitlens.decorations.untrackedForegroundColor": "#cccccc",
//"gitlens.gutterBackgroundColor": "#ffffff13",
//"gitlens.gutterForegroundColor": "#bebebe",
//"gitlens.gutterUncommittedForegroundColor": "#00bcf299",
//"gitlens.lineHighlightBackgroundColor": "#00bcf233",
//"gitlens.lineHighlightOverviewRulerColor": "#00bcf299",
//"gitlens.mergedPullRequestIconColor": "#a371f7",
//"gitlens.openAutolinkedIssueIconColor": "#3fb950",
//"gitlens.openPullRequestIconColor": "#3fb950",
//"gitlens.trailingLineBackgroundColor": "#00000000",
//"gitlens.trailingLineForegroundColor": "#99999959",
//"gitlens.unpublishedCommitIconColor": "#35b15e",
//"gitlens.unpulledChangesIconColor": "#b15e35",
//"gitlens.unpushlishedChangesIconColor": "#35b15e",
//"icon.foreground": "#c5c5c5",
//"inputOption.activeBackground": "#66666666",
//"inputOption.activeForeground": "#ffffff",
//"inputOption.hoverBackground": "#5a5d5e80",
//"interactive.activeCodeBorder": "#222222",
//"interactive.inactiveCodeBorder": "#000000",
//"keybindingLabel.background": "#8080802b",
//"keybindingLabel.border": "#33333399",
//"keybindingLabel.bottomBorder": "#44444499",
//"keybindingLabel.foreground": "#cccccc",
//"keybindingTable.headerBackground": "#ffffff0a",
//"keybindingTable.rowsBackground": "#ffffff0a",
//"list.deemphasizedForeground": "#8c8c8c",
//"list.errorForeground": "#f88070",
//"list.filterMatchBackground": "#444466aa",
//"list.focusHighlightForeground": "#ffffff",
//"list.focusOutline": "#666666",
//"list.invalidItemForeground": "#b89500",
//"list.warningForeground": "#cca700",
//"listFilterWidget.background": "#653723",
//"listFilterWidget.noMatchesOutline": "#be1100",
//"listFilterWidget.outline": "#00000000",
//"menu.selectionBackground": "#111111",
//"menu.selectionForeground": "#ffffff",
//"menu.separatorBackground": "#bbbbbb",
//"menubar.selectionBackground": "#ffffff1a",
//"menubar.selectionForeground": "#888888",
//"merge.commonContentBackground": "#60606029",
//"merge.commonHeaderBackground": "#60606066",
//"minimap.errorHighlight": "#ff1212b3",
//"minimap.findMatchHighlight": "#d18616",
//"minimap.foregroundOpacity": "#000000",
//"minimap.selectionHighlight": "#264f78",
//"minimap.selectionOccurrenceHighlight": "#676767",
//"minimap.unicodeHighlight": "#d18616",
//"minimap.warningHighlight": "#88bbff",
//"minimapGutter.addedBackground": "#587c0c",
//"minimapGutter.deletedBackground": "#94151b",
//"minimapGutter.modifiedBackground": "#0c7d9d",
//"minimapSlider.activeBackground": "#ffffff09",
//"minimapSlider.background": "#ffffff09",
//"minimapSlider.hoverBackground": "#ffffff09",
//"notebook.cellBorderColor": "#000000",
//"notebook.cellEditorBackground": "#111111",
//"notebook.cellInsertionIndicator": "#666666",
//"notebook.cellStatusBarItemHoverBackground": "#ffffff26",
//"notebook.cellToolbarSeparator": "#80808059",
//"notebook.focusedCellBorder": "#666666",
//"notebook.focusedEditorBorder": "#666666",
//"notebook.inactiveFocusedCellBorder": "#000000",
//"notebook.selectedCellBackground": "#000000",
//"notebook.selectedCellBorder": "#000000",
//"notebook.symbolHighlightBackground": "#ffffff0b",
//"notebookScrollbarSlider.activeBackground": "#ffffff12",
//"notebookScrollbarSlider.background": "#ffffff12",
//"notebookScrollbarSlider.hoverBackground": "#ffffff12",
//"notebookStatusErrorIcon.foreground": "#88bbff",
//"notebookStatusRunningIcon.foreground": "#ffffff",
//"notebookStatusSuccessIcon.foreground": "#89d185",
//"notificationCenterHeader.background": "#424242",
//"notificationLink.foreground": "#3794ff",
//"notifications.background": "#333333",
//"notifications.border": "#424242",
//"notifications.foreground": "#ffffff",
//"notificationsErrorIcon.foreground": "#ee5500",
//"notificationsInfoIcon.foreground": "#3794ff",
//"notificationsWarningIcon.foreground": "#88bbff",
//"panel.dropBorder": "#ffffff",
//"panelSection.border": "#111111",
//"panelSection.dropBackground": "#111111bb",
//"panelSectionHeader.background": "#80808033",
//"ports.iconRunningProcessForeground": "#88cc44",
//"problemsErrorIcon.foreground": "#ee5500",
//"problemsInfoIcon.foreground": "#3794ff",
//"problemsWarningIcon.foreground": "#88bbff",
//"quickInput.background": "#333333",
//"quickInput.foreground": "#ffffff",
//"quickInputList.focusBackground": "#111111",
//"quickInputList.focusForeground": "#ffffff",
//"quickInputTitle.background": "#ffffff1b",
//"sash.hoverBorder": "#666666",
//"scm.providerBorder": "#454545",
//"searchEditor.findMatchBackground": "#44446670",
//"searchEditor.textInputBorder": "#333333",
//"settings.checkboxBackground": "#222222",
//"settings.checkboxBorder": "#222222",
//"settings.checkboxForeground": "#888888",
//"settings.dropdownBackground": "#222222",
//"settings.dropdownBorder": "#222222",
//"settings.dropdownForeground": "#888888",
//"settings.dropdownListBorder": "#333333",
//"settings.focusedRowBackground": "#80808024",
//"settings.focusedRowBorder": "#ffffff1f",
//"settings.headerForeground": "#e7e7e7",
//"settings.modifiedItemIndicator": "#0c7d9d",
//"settings.numberInputBackground": "#333333",
//"settings.numberInputBorder": "#333333",
//"settings.numberInputForeground": "#ffffff",
//"settings.rowHoverBackground": "#80808012",
//"settings.textInputBackground": "#333333",
//"settings.textInputBorder": "#333333",
//"settings.textInputForeground": "#ffffff",
//"sideBar.dropBackground": "#111111bb",
//"sideBySideEditor.horizontalBorder": "#111111",
//"sideBySideEditor.verticalBorder": "#111111",
//"statusBar.debuggingBorder": "#111111",
//"statusBar.noFolderBorder": "#111111",
//"statusBarItem.compactHoverBackground": "#ffffff33",
//"statusBarItem.errorBackground": "#0066eb",
//"statusBarItem.errorForeground": "#ffffff",
//"statusBarItem.prominentForeground": "#666666",
//"statusBarItem.remoteBackground": "#88cc44",
//"statusBarItem.remoteForeground": "#222222",
//"statusBarItem.warningBackground": "#0066eb",
//"statusBarItem.warningForeground": "#ffffff",
//"symbolIcon.arrayForeground": "#ffffff",
//"symbolIcon.booleanForeground": "#ffffff",
//"symbolIcon.classForeground": "#ee9d28",
//"symbolIcon.colorForeground": "#ffffff",
//"symbolIcon.constantForeground": "#ffffff",
//"symbolIcon.constructorForeground": "#b180d7",
//"symbolIcon.enumeratorForeground": "#ee9d28",
//"symbolIcon.enumeratorMemberForeground": "#75beff",
//"symbolIcon.eventForeground": "#ee9d28",
//"symbolIcon.fieldForeground": "#75beff",
//"symbolIcon.fileForeground": "#ffffff",
//"symbolIcon.folderForeground": "#ffffff",
//"symbolIcon.functionForeground": "#b180d7",
//"symbolIcon.interfaceForeground": "#75beff",
//"symbolIcon.keyForeground": "#ffffff",
//"symbolIcon.keywordForeground": "#ffffff",
//"symbolIcon.methodForeground": "#b180d7",
//"symbolIcon.moduleForeground": "#ffffff",
//"symbolIcon.namespaceForeground": "#ffffff",
//"symbolIcon.nullForeground": "#ffffff",
//"symbolIcon.numberForeground": "#ffffff",
//"symbolIcon.objectForeground": "#ffffff",
//"symbolIcon.operatorForeground": "#ffffff",
//"symbolIcon.packageForeground": "#ffffff",
//"symbolIcon.propertyForeground": "#ffffff",
//"symbolIcon.referenceForeground": "#ffffff",
//"symbolIcon.snippetForeground": "#ffffff",
//"symbolIcon.stringForeground": "#ffffff",
//"symbolIcon.structForeground": "#ffffff",
//"symbolIcon.textForeground": "#ffffff",
//"symbolIcon.typeParameterForeground": "#ffffff",
//"symbolIcon.unitForeground": "#ffffff",
//"symbolIcon.variableForeground": "#75beff",
//"tab.activeForeground": "#ffffff",
//"tab.activeModifiedBorder": "#3399cc",
//"tab.inactiveModifiedBorder": "#3399cc80",
//"tab.lastPinnedBorder": "#585858",
//"tab.unfocusedActiveBackground": "#222222",
//"tab.unfocusedActiveModifiedBorder": "#3399cc80",
//"tab.unfocusedInactiveBackground": "#111111",
//"tab.unfocusedInactiveModifiedBorder": "#3399cc40",
//"terminal.border": "#111111",
//"terminal.dropBackground": "#111111bb",
//"terminal.selectionBackground": "#ffffff40",
//"testing.iconErrored": "#f14c4c",
//"testing.iconFailed": "#f14c4c",
//"testing.iconPassed": "#73c991",
//"testing.iconQueued": "#cca700",
//"testing.iconSkipped": "#848484",
//"testing.iconUnset": "#848484",
//"testing.message.error.decorationForeground": "#ee5500",
//"testing.message.error.lineBackground": "#ff000033",
//"testing.message.info.decorationForeground": "#ffffff80",
//"testing.peekBorder": "#ee5500",
//"testing.peekHeaderBackground": "#ee55001a",
//"testing.runAction": "#73c991",
//"textBlockQuote.background": "#7f7f7f1a",
//"textBlockQuote.border": "#007acc80",
//"textCodeBlock.background": "#0a0a0a66",
//"textLink.activeForeground": "#3794ff",
//"textLink.foreground": "#3794ff",
//"textPreformat.foreground": "#d7ba7d",
//"textSeparator.foreground": "#ffffff2e",
//"toolbar.activeBackground": "#63666750",
//"toolbar.hoverBackground": "#5a5d5e50",
//"tree.indentGuidesStroke": "#585858",
//"tree.tableColumnsBorder": "#cccccc20",
//"tree.tableOddRowsBackground": "#ffffff0a",
//"welcomePage.progress.background": "#333333",
//"welcomePage.progress.foreground": "#3794ff",
//"welcomePage.tileBackground": "#333333",
//"welcomePage.tileHoverBackground": "#3d3d3d",
//"welcomePage.tileShadow": "#111111",
//"activityBar.activeBackground": null,
//"activityBar.activeFocusBorder": null,
//"button.border": null,
//"contrastActiveBorder": null,
//"contrastBorder": null,
//"debugToolBar.border": null,
//"diffEditor.border": null,
//"dropdown.listBackground": null,
//"editor.findMatchBorder": null,
//"editor.findMatchHighlightBorder": null,
//"editor.findRangeHighlightBorder": null,
//"editor.rangeHighlightBorder": null,
//"editor.selectionForeground": null,
//"editor.selectionHighlightBorder": null,
//"editor.snippetFinalTabstopHighlightBackground": null,
//"editor.snippetTabstopHighlightBorder": null,
//"editor.symbolHighlightBorder": null,
//"editor.wordHighlightBorder": null,
//"editor.wordHighlightStrongBorder": null,
//"editorCursor.background": null,
//"editorError.background": null,
//"editorError.border": null,
//"editorGhostText.background": null,
//"editorGhostText.border": null,
//"editorGroup.emptyBackground": null,
//"editorGroup.focusedEmptyBorder": null,
//"editorGroupHeader.border": null,
//"editorHint.border": null,
//"editorInfo.background": null,
//"editorInfo.border": null,
//"editorOverviewRuler.background": null,
//"editorSuggestWidget.selectedIconForeground": null,
//"editorUnnecessaryCode.border": null,
//"editorWarning.background": null,
//"editorWidget.resizeBorder": null,
//"inputValidation.errorForeground": null,
//"inputValidation.infoForeground": null,
//"inputValidation.warningForeground": null,
//"list.activeSelectionIconForeground": null,
//"list.filterMatchBorder": null,
//"list.inactiveFocusBackground": null,
//"list.inactiveFocusOutline": null,
//"list.inactiveSelectionIconForeground": null,
//"menu.border": null,
//"menu.selectionBorder": null,
//"menubar.selectionBorder": null,
//"minimap.background": null,
//"notebook.cellHoverBackground": null,
//"notebook.focusedCellBackground": null,
//"notebook.inactiveSelectedCellBorder": null,
//"notebook.outputContainerBackgroundColor": null,
//"notebook.outputContainerBorderColor": null,
//"notificationCenter.border": null,
//"notificationCenterHeader.foreground": null,
//"notificationToast.border": null,
//"panelInput.border": null,
//"panelSectionHeader.border": null,
//"panelSectionHeader.foreground": null,
//"peekViewEditor.matchHighlightBorder": null,
//"quickInput.list.focusBackground": null,
//"quickInputList.focusIconForeground": null,
//"searchEditor.findMatchBorder": null,
//"sideBarSectionHeader.border": null,
//"tab.activeBorder": null,
//"tab.activeBorderTop": null,
//"tab.hoverBackground": null,
//"tab.hoverBorder": null,
//"tab.hoverForeground": null,
//"tab.unfocusedActiveBorderTop": null,
//"tab.unfocusedHoverBackground": null,
//"tab.unfocusedHoverBorder": null,
//"tab.unfocusedHoverForeground": null,
//"terminal.tab.activeBorder": null,
//"terminalCursor.background": null,
//"terminalCursor.foreground": null,
//"testing.message.info.lineBackground": null,
//"titleBar.border": null,
//"toolbar.hoverOutline": null,
//"welcomePage.background": null,
//"window.activeBorder": null,
//"window.inactiveBorder": null
},
"tokenColors": [
{
"scope": [
"variable.language.this"
],
"settings": {
"fontStyle": ""
}
},
{
"scope": "markup.bold",
"settings": {
"fontStyle": "bold"
}
},
{
"scope": [
"invalid",
"markup.italic",
"markup.quote"
],
"settings": {
"fontStyle": "italic"
}
},
{
"scope": "markup.underline",
"settings": {
"fontStyle": "underline"
}
},
{
"scope": [
"source.js.jsx punctuation.section.embedded",
"entity.name.tag",
"string.other.link.description.title",
"support.constant",
"support.variable",
"support.type",
"variable.other.class",
"support.class.builtin.js",
"support.class.console.js",
"meta.property-value",
"variable.parameter.keyframe-list",
"meta.at-rule.keyframes entity.name.function",
"expression.embedded.vue punctuation.definition"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": ""
}
},
{
"scope": [
"entity.other.attribute-name.pseudo-class.css",
"entity.name.type.object.console",
"variable.language",
"variable.parameter.function.language.special.self.python",
"storage.type",
"entity.other.attribute-name.pseudo-element.css"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": "italic"
}
},
{
"scope": [
"punctuation.definition.string.template"
],
"settings": {
"foreground": "#BBA0FF",
"fontStyle": "bold"
}
},
{
"scope": [
"entity.other.attribute-name.class.css",
"entity.other.attribute-name.parent-selector-suffix.css",
"entity.other.attribute-name.parent-selector-suffix.css punctuation.definition.entity.css",
"meta.definition.function",
"markup.underline.link",
"markup.inserted",
"meta.function-call",
"meta.instance.constructor",
"meta.attribute-with-value.class string",
"string.other.ref",
"string.other.restructuredtext.ref",
"variable.function",
"entity.name.type",
"entity.name.function",
"variable.other.object.property",
"punctuation.separator.key-value",
"meta.definition.function.js",
"support.class.component.js",
"entity.other.inherited-class",
"support.class",
"support.function.misc",
"support.function",
"entity.other.attribute-name.id.css",
"entity.other.attribute-name.id.css punctuation",
"entity.other.attribute-name.class.css punctuation",
"meta.function-call support.function.construct",
"entity.other.attribute-name"
],
"settings": {
"foreground": "#FFDD44"
}
},
{
"scope": "storage.type.function.arrow",
"settings": {
"foreground": "#FFDD44",
"fontStyle": ""
}
},
{
"scope": [
"entity.name.section",
"constant.numeric.line-number.match.find-in-files",
"markup.heading",
"markup.changed",
"meta.attribute-with-value.id string",
"string",
"punctuation.definition.string.begin",
"punctuation.definition.string.end",
"meta.attribute-selector"
],
"settings": {
"foreground": "#88CC44"
}
},
{
"scope": [
"keyword",
"keyword.control",
"constant",
"constant.numeric",
"constant.language",
"constant.other.property",
"constant.character.escape",
"comment keyword.codetag.notation",
"keyword.other.template.begin",
"keyword.other.template.end",
"markup.raw",
"markup.deleted",
"meta.property-list.css variable.other",
"entity.name.constant.preprocessor",
"meta.preprocessor",
"punctuation.section.embedded",
"punctuation.template-string.element.begin",
"punctuation.template-string.element.end",
"string.quoted.template punctuation.definition.string.begin",
"string.quoted.template punctuation.definition.string.end",
"meta.paragraph.markdown meta.dummy.line-break",
"meta.paragraph.markdown meta.hard-line-break.markdown",
"storage",
"storage.class.restructuredtext.ref",
"string.other.link.title",
"string.other.link.description",
"string.regexp punctuation.definition.string.begin",
"string.regexp punctuation.definition.string.end",
"variable.language.arguments",
"storage.modifier",
"keyword.operator.new",
"keyword.operator",
"keyword.operator.spread",
"punctuation.section.embedded.end.php source.php",
"support.function.construct",
"meta.at-rule.keyframes",
"meta.at-rule.keyframes entity.other.attribute-name"
],
"settings": {
"foreground": "#88BBFF"
}
},
{
"scope": [
"variable.other.substitution"
],
"settings": {
"foreground": "#88BBFF",
"fontStyle": "bold"
}
},
{
"scope": [
"meta.function-call meta.function-call.arguments",
"meta.function-call meta.arguments",
"meta.function-call meta.group",
"source.json meta.structure.dictionary",
"meta.object.member",
"punctuation.definition.group",
"string.unquoted.label",
"variable.other.member",
"entity.name.class",
"entity.name.namespace",
"constant.other",
"variable",
"variable.other",
"variable.other.constant.js",
"text.find-in-files",
"source",
"entity.name.type.module",
"source.sql support.function",
"support.other.namespace.php"
],
"settings": {
"foreground": "#FFFFFF",
"fontStyle": ""
}
},
{
"scope": [
"variable.parameter",
"parameters variable.function"
],
"settings": {
"foreground": "#FFFFFF",
"fontStyle": "italic"
}
},
{
"scope": [
"variable.other.property",
"support.variable.property",
"punctuation.separator.key-value",
"meta.object-literal.key",
"variable.other.object.property",
"variable.object.property",
"text.html.basic",
"text.html.vue-html",
"text.html.php",
"text.html.derivative",
"punctuation.definition.variable",
"punctuation.definition.keyword.scss",
"meta.jsx.children.js",
"meta.tag.attributes keyword.operator.assignment",
"support.type.vendored.property-name.css",
"support.type.property-name.json",
"variable.other.constant.property"
],
"settings": {
"foreground": "#BBBBCC"
}
},
{
"scope": "meta.property-name support.type",
"settings": {
"foreground": "#BBBBCC",
"fontStyle": ""
}
},
{
"scope": [
"keyword.other.substitution",
"keyword.operator.heading.restructuredtext",
"keyword.operator.table.row.restructuredtext",
"keyword.operator.table.data.restructuredtext",
"punctuation",
"markup.ignored",
"markup.untracked",
"meta.brace.round",
"meta.brace.square",
"meta.brace.curly",
"meta.delimiter.comma.js",
"meta.function-call.without-arguments.js",
"meta.function-call.method.without-arguments.js",
"source.scss",
"string source punctuation.section.embedded",
"punctuation.definition.tag.begin source",
"source.php"
],
"settings": {
"foreground": "#9999AA"
}
},
{
"scope": [
"comment",
"comment punctuation"
],
"settings": {
"foreground": "#888899",
"fontStyle": "italic"
}
},
{
"scope": "token.info-token",
"settings": {
"foreground": "#6796E6"
}
},
{
"scope": "token.warn-token",
"settings": {
"foreground": "#CD9731"
}
},
{
"scope": "token.error-token",
"settings": {
"foreground": "#F44747"
}
},
{
"scope": "token.debug-token",
"settings": {
"foreground": "#B267E6"
}
}
]
}
File renamed without changes.
File renamed without changes.
-41
View File
@@ -1,41 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Spark Client",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/build/Debug/bin/net6.0-windows/Spark.exe",
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
"enableStepFiltering": false,
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Spark Test",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/build/Debug/bin/net6.0/sparkcmd.exe",
"args": ["test", "${input:test}"],
"cwd": "${workspaceFolder}/build/Debug/bin/net6.0-windows",
"enableStepFiltering": false,
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": "Attach (.NET Core)",
"type": "coreclr",
"request": "attach"
}
],
"inputs": [
{
"id": "test",
"description": "The test(s) to run",
"type": "promptString"
}
]
}
-37
View File
@@ -1,37 +0,0 @@
{
"cmake.configureOnOpen": false,
"workbench.colorTheme": "Default Dark+",
"C_Cpp.intelliSenseEngine": "Disabled",
"files.associations": {
"*.js": "javascript",
"*.conf": "jsonc",
"array": "cpp",
"xtree": "cpp",
"chrono": "cpp",
"*.ipp": "cpp",
"optional": "cpp",
"regex": "cpp",
"system_error": "cpp",
"format": "cpp",
"future": "cpp",
"istream": "cpp",
"memory": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"variant": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xutility": "cpp",
"xstring": "cpp",
"string": "cpp",
"cstdint": "cpp"
},
"files.exclude": {
"**/.g.cs": true,
"**/.g.i.cs": true
}
}
-44
View File
@@ -1,44 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Spark Client",
"type": "process",
"command": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\Tools\\VsDevCmd.bat",
"args": [
"-arch=x64",
"-host_arch=x64",
"&&",
"${workspaceRoot}\\tools\\buildspark.cmd"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new",
"showReuseMessage": false,
"clear": false,
"close": false
}
},
{
"label": "Run Spark Client",
"type": "process",
"command": "${workspaceRoot}\\build\\Debug\\bin\\net6.0-windows\\Spark.exe",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
},
"problemMatcher": []
}
]
}
+2 -2
View File
@@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.5)
project(doc)
include(${CMAKE_SOURCE_DIR}/cmake/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/cmake/Protobuf.cmake)
include(${CMAKE_SOURCE_DIR}/tools/safe_dep_glob.cmake)
include(${CMAKE_SOURCE_DIR}/tools/Protobuf.cmake)
# DEPENDENCIES
set(DOC_GLOBS
+1 -1
View File
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "6.0.200",
"version": "2.1.508",
"rollForward": "latestMajor"
}
}
-1
View File
@@ -12,7 +12,6 @@
<EnableDefaultContentItems>False</EnableDefaultContentItems>
<ShowMissingItemTypes>false</ShowMissingItemTypes>
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
<EnablePreviewFeatures>true</EnablePreviewFeatures>
</PropertyGroup>
<PropertyGroup Label="Output">
-10
View File
@@ -68,16 +68,6 @@
</ItemGroup>
</Target>
<Target Name="RemoveSystemRuntimeFromRefPack"
BeforeTargets="_HandlePackageFileConflicts"
Condition="'@(Reference -> WithMetadataValue('NugetPackageId', 'System.Runtime.Experimental'))' != ''">
<ItemGroup>
<Reference Remove="@(Reference)"
Condition="$([System.String]::Copy(%(Reference.Identity)).Contains('System.Runtime.dll')) and
'%(Reference.NuGetPackageId)' == 'Microsoft.NETCore.App.Ref'" />
</ItemGroup>
</Target>
<Target
Name="AfterClean"
AfterTargets="Clean">
@@ -1,7 +1,4 @@
#nullable enable
namespace mbts.spark {
using bts.api.analytics;
using mbts.analytics;
using mbts.ui;
using mbts.ui.shell;
@@ -15,9 +12,9 @@ namespace mbts.spark {
readonly AnalyticsExpirationParameters _committed_value;
readonly Property<bool> _is_selected;
readonly Property<ExpirationDriverImmutable?> _driver;
readonly Property<SecurityExpiration?> _deliverable;
readonly Property<SecurityExpiration?> _roll_schedule;
readonly Property<SecurityExpiration> _driver;
readonly Property<SecurityExpiration> _deliverable;
readonly Property<SecurityExpiration> _roll_schedule;
readonly Property<double> _roll_target;
readonly Property<double> _riskless_rate;
readonly Property<double> _settlement_price;
@@ -36,19 +33,18 @@ namespace mbts.spark {
bool _is_last_row_of_month_group;
public AnalyticsExpirationParametersRowVM(
AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
this.owner = owner;
_committed_value = committed_value;
public AnalyticsExpirationParametersRowVM(AnalyticsExpirationParametersVM owner, AnalyticsExpirationParameters committed_value) {
this.owner = owner ?? throw new ArgumentNullException(nameof(owner));
_committed_value = committed_value ?? throw new ArgumentNullException(nameof(committed_value));
security = committed_value.security ?? throw new ArgumentException("security must be non-null", nameof(committed_value));
_is_selected = backing(nameof(is_selected), false);
_is_selected.Changed += (oldval, newval) => is_selected_changed?.Invoke(newval);
var is_dirty_srcs = new List<IObservable<bool>>();
(_driver, _is_driver_dirty) = mk_cell_props<ExpirationDriverImmutable?>(nameof(driver), committed_value.driver);
(_deliverable, _is_deliverable_dirty) = mk_cell_props<SecurityExpiration?>(nameof(deliverable), committed_value.deliverable_security);
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props<SecurityExpiration?>(nameof(roll_schedule), committed_value.roll_schedule_expiration);
(_driver, _is_driver_dirty) = mk_cell_props(nameof(driver), committed_value.driver_security);
(_deliverable, _is_deliverable_dirty) = mk_cell_props(nameof(deliverable), committed_value.deliverable_security);
(_roll_schedule, _is_roll_schedule_dirty) = mk_cell_props(nameof(roll_schedule), committed_value.roll_schedule_expiration);
(_roll_target, _is_roll_target_dirty) = mk_cell_props(nameof(roll_target), committed_value.roll_target);
(_riskless_rate, _is_riskless_rate_dirty) = mk_cell_props(nameof(riskless_rate), committed_value.riskless_rate);
(_settlement_price, _is_settlement_price_dirty) = mk_cell_props(nameof(settlement_price), committed_value.settlement_price);
@@ -68,22 +64,13 @@ namespace mbts.spark {
}
}
public event Action<bool>? is_selected_changed;
public event Action<bool> is_selected_changed;
public AnalyticsExpirationParametersVM owner { get; }
public SecurityExpiration security { get; }
public ExpirationDriverImmutable? driver {
get => _driver.Value;
set => _driver.set(value);
}
public SecurityExpiration? deliverable {
get => _deliverable.Value;
set => _deliverable.set(value);
}
public SecurityExpiration? roll_schedule {
get => _roll_schedule.Value;
set => _roll_schedule.set(value);
}
public SecurityExpiration driver { get => _driver.Value; set => _driver.set(value); }
public SecurityExpiration deliverable { get => _deliverable.Value; set => _deliverable.set(value); }
public SecurityExpiration roll_schedule { get => _roll_schedule.Value; set => _roll_schedule.set(value); }
public AnalyticsExpirationParameters original_params => _committed_value;
public double roll_target { get => _roll_target.Value; set => _roll_target.set(value); }
@@ -115,15 +102,15 @@ namespace mbts.spark {
public AnalyticsExpirationParameters candidate_value => new(
security,
driver,
deliverable?.is_empty() ?? false ? null : deliverable,
roll_schedule?.is_empty() ?? false ? null : roll_schedule,
deliverable.is_empty() ? null : deliverable,
roll_schedule.is_empty() ? null : roll_schedule,
roll_target,
riskless_rate,
settlement_price,
delta_beta,
vega_beta);
public IObservable<SecurityExpiration?> observe_roll_schedule() =>
public IObservable<SecurityExpiration> observe_roll_schedule() =>
_roll_schedule.observe_current(true);
public IObservable<bool> observe_roll_schedule_dirty() =>
@@ -133,7 +120,7 @@ namespace mbts.spark {
_is_dirty.observe_current(true);
public void revert() {
driver = _committed_value.driver;
driver = _committed_value.driver_security;
deliverable = _committed_value.deliverable_security;
roll_schedule = _committed_value.roll_schedule_expiration;
roll_target = _committed_value.roll_target;
@@ -146,11 +133,11 @@ namespace mbts.spark {
public override string ToString() =>
$"sec: {security}; drv: {driver}; dlv: {deliverable}; roll: {roll_schedule} @ {roll_target}";
public bool Equals(AnalyticsExpirationParametersRowVM? other) =>
public bool Equals(AnalyticsExpirationParametersRowVM other) =>
other is not null &&
security.Equals(other.security);
public override bool Equals(object? obj) =>
public override bool Equals(object obj) =>
Equals(obj as AnalyticsExpirationParametersRowVM);
public override int GetHashCode() =>
@@ -1,8 +1,5 @@
#nullable enable
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.reactive;
using bts.utils;
@@ -15,15 +12,11 @@ namespace mbts.spark {
using mbts.ui.utility;
using mbts.utils;
using Spark.Core.Collections;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
@@ -34,32 +27,24 @@ namespace mbts.spark {
readonly IBus _bus;
readonly ObservableCollection<AnalyticsExpirationParameters> _parameters = new();
readonly DeferrableActionWrapper _sync_visible_rows;
readonly Property<AnalyticsExpirationParametersRowVM?> _copy_row_source;
readonly Property<bool> _auto_copy_rolls_is_checked;
readonly Property<bool> _auto_copy_rates_is_checked;
readonly Property<AnalyticsExpirationParametersRowVM> _copy_row_source;
readonly DelegateProperty<bool> _is_dirty;
readonly ObservableHashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
readonly DeferrableActionWrapper _raise_selected_rows_changed;
readonly IRaiseCanExecuteChangedCommand _set_driver_to_nearest_exp_cmd;
readonly HashSet<AnalyticsExpirationParametersRowVM> _selected_rows = new();
AnalyticsExpirationParametersMap? _parameter_map;
AnalyticsExpirationParametersMap _parameter_map;
bool _auto_copy_rolls_is_checked;
bool _auto_copy_rates_is_checked;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_roll_target_to_selection_cmd;
(ICommand cmd, IDisposable can_exe_sub)? _smart_copy_riskless_rate_to_selection_cmd;
public AnalyticsExpirationParametersVM(
IBus bus, AnalyticsExpirationParametersSettings startup_data) {
_bus = bus;
_auto_copy_rates_is_checked = backing(nameof(auto_copy_rates_is_checked), false);
_auto_copy_rolls_is_checked = backing(nameof(auto_copy_rolls_is_checked), false);
_raise_selected_rows_changed = new(() => selected_rows_changed?.Invoke(_selected_rows));
public AnalyticsExpirationParametersVM(IBus bus, AnalyticsExpirationParametersSettings startup_data) {
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
var selected_symbol_ref_count = new RefCountMap<string>();
_sync_visible_rows = new(() =>
visible_rows.sync_with(
rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
visible_rows.sync_with(rows.Where(x => selected_symbol_ref_count.ContainsKey(x.security.symbol))));
non_options_with_empty = new ObservableAggregateCollection<SecurityExpiration>(
new() { SecurityExpiration.empty }, non_options);
_copy_row_source = backing<AnalyticsExpirationParametersRowVM?>(nameof(copy_row_source));
_copy_row_source = backing<AnalyticsExpirationParametersRowVM>(nameof(copy_row_source));
_is_dirty = backing(nameof(is_dirty), () => rows.Any(r => r.is_dirty));
if (startup_data is not null) {
@@ -70,23 +55,11 @@ namespace mbts.spark {
auto_copy_rates_is_checked = startup_data.auto_copy_rates_is_checked;
}
var explicit_drivers = new ObservableCollection<ExpirationDriverImmutable>();
drivers = ObservableAggregateCollection.create(
new() { new ExpirationDriverImmutable(new() { TimeWeightedInterpolated = new() }) },
explicit_drivers);
_set_driver_to_nearest_exp_cmd = new Command(
() => _set_driver_to_nearest_exp(_selected_rows), () => _selected_rows.Count > 0);
commit_cmd = ObservantCommand.create(_commit, out var can_commit_observer);
revert_cmd = ObservantCommand.create(_revert, out var can_revert_observer);
selected_rows_changed += _ => _set_driver_to_nearest_exp_cmd.RaiseCanExecuteChanged();
_dispose = Disposable.Create(
_selected_rows.Subscribe((s, e) => _raise_selected_rows_changed.execute()),
ObservableAutoWrapper.connect(_parameters, rows, p => new(this, p), r => r.Dispose()),
ObservableAutoWrapper.connect(
non_options,
explicit_drivers,
sec => new ExpirationDriverImmutable(new() { Security = sec.to_api_sec_exp() })),
rows.Subscribe((s, e) => _sync_visible_rows.execute()),
_bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(
CompositeObserver.create(
@@ -102,8 +75,7 @@ namespace mbts.spark {
}
});
}),
ObservableAutoWrapper.connect_item_hooks(
rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
ObservableAutoWrapper.connect_item_hooks(rows, r => r.observe_is_dirty().Subscribe(_ => _is_dirty.refresh())),
_is_dirty.observe_current(true).OnDispatcher().Subscribe(can_revert_observer),
Disposable.wrap_collection(rows),
Disposable.Create(() => {
@@ -112,15 +84,12 @@ namespace mbts.spark {
}));
}
public event Action<IReadOnlySet<AnalyticsExpirationParametersRowVM>>? selected_rows_changed;
public ObservableCollection<SecurityExpiration> non_options { get; } = new();
public IReadOnlyObservableCollection<ExpirationDriverImmutable> drivers { get; }
public ObservableCollection<SecurityExpiration> non_options_with_empty { get; } = new();
public ObservableCollection<AnalyticsExpirationParametersRowVM> rows { get; } = new();
public ObservableCollection<AnalyticsExpirationParametersRowVM> visible_rows { get; } = new();
public AnalyticsExpirationParametersRowVM? copy_row_source {
public AnalyticsExpirationParametersRowVM copy_row_source {
get => _copy_row_source.Value;
set => _copy_row_source.set(value);
}
@@ -131,29 +100,18 @@ namespace mbts.spark {
public bool is_dirty => _is_dirty.Value;
public bool auto_copy_rolls_is_checked {
get => _auto_copy_rolls_is_checked.Value;
set => _auto_copy_rolls_is_checked.set(value);
get => _auto_copy_rolls_is_checked;
set => Set(ref _auto_copy_rolls_is_checked, value);
}
public IObservable<bool> observe_auto_copy_rolls() =>
_auto_copy_rolls_is_checked.observe_current(true);
public bool auto_copy_rates_is_checked {
get => _auto_copy_rates_is_checked.Value;
set => _auto_copy_rates_is_checked.set(value);
get => _auto_copy_rates_is_checked;
set => Set(ref _auto_copy_rates_is_checked, value);
}
public IObservable<bool> observe_auto_copy_rates() =>
_auto_copy_rates_is_checked.observe_current(true);
public ICommand toggle_auto_copy_rates_cmd =>
new Command(() => auto_copy_rates_is_checked = !auto_copy_rates_is_checked);
public ICommand toggle_auto_copy_rolls_cmd =>
new Command(() => auto_copy_rolls_is_checked = !auto_copy_rolls_is_checked);
public ICommand commit_cmd { get; }
public ICommand revert_cmd { get; }
public ICommand set_driver_to_nearest_exp_cmd => _set_driver_to_nearest_exp_cmd;
public ICommand copy_driver_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.driver = f.driver);
public ICommand copy_deliverable_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.deliverable = f.deliverable);
public ICommand copy_roll_schedule_to_selection_cmd => _copy_to_selection_cmd((f, t) => t.roll_schedule = f.roll_schedule);
@@ -180,7 +138,7 @@ namespace mbts.spark {
public IEnumerable<SecurityExpiration> get_smart_copy_roll_exps(
SecurityExpiration roll_schedule_expiration) {
foreach (var (exp, exp_params) in (_parameter_map?.exp_map).empty_if_null()) {
foreach (var (exp, exp_params) in _parameter_map?.exp_map.empty_if_null()) {
if (exp_params.roll_schedule_expiration.Equals(roll_schedule_expiration)) {
yield return exp;
}
@@ -194,30 +152,17 @@ namespace mbts.spark {
auto_copy_rolls_is_checked = auto_copy_rolls_is_checked
};
void _set_driver_to_nearest_exp(IEnumerable<AnalyticsExpirationParametersRowVM> rows) {
foreach (var r in rows) {
if (drivers.Where(d => d.HasSecurity).TryGetMinElement(
d => (r.security.expiration - d.Security.Expiration.date_time()).Ticks.abs(),
out var nearest_exp)) {
r.driver = nearest_exp;
}
}
}
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Action<AnalyticsExpirationParametersRowVM> _copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
from_row => {
foreach (var to_row in _selected_rows) {
copy_to_row(from_row, to_row);
}
};
ICommand _copy_to_selection_cmd(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
ICommand _copy_to_selection_cmd(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Command.create(_copy_to_selection(copy_to_row));
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
Action<AnalyticsExpirationParametersRowVM> _smart_copy_to_selection(Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) =>
from_row => {
foreach (var to_row in _get_smart_copy_roll_target_rows(from_row)) {
copy_to_row(from_row, to_row);
@@ -226,26 +171,21 @@ namespace mbts.spark {
(ICommand cmd, IDisposable can_exe_sub) _smart_copy_to_selection_cmd(
Action<AnalyticsExpirationParametersRowVM, AnalyticsExpirationParametersRowVM> copy_to_row) {
var copy_fn = _smart_copy_to_selection(copy_to_row);
var cmd = ObservantCommand.create<AnalyticsExpirationParametersRowVM?>(
r => copy_fn(r ?? throw new InvalidOperationException()),
observe_can_execute,
out var can_exe_observer);
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher()
.Subscribe(can_exe_observer);
var cmd = ObservantCommand.create(
_smart_copy_to_selection(copy_to_row), observe_can_execute, out var can_exe_observer);
var can_exe_sub = _copy_row_source.observe_current(true).OnDispatcher().Subscribe(can_exe_observer);
return (cmd, can_exe_sub);
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM? row) =>
static IObservable<bool> observe_can_execute(AnalyticsExpirationParametersRowVM row) =>
row is null ?
Observable.Return(false) :
row.observe_roll_schedule()
.CombineLatest(row.observe_roll_schedule_dirty(), (rs, rs_dirty) => (rs, rs_dirty))
.Select(tup => !tup.rs?.is_empty() ?? false && !tup.rs_dirty)
.Select(tup => !tup.rs.is_empty() && !tup.rs_dirty)
.OnDispatcher();
}
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(
AnalyticsExpirationParametersRowVM row) {
IEnumerable<AnalyticsExpirationParametersRowVM> _get_smart_copy_roll_target_rows(AnalyticsExpirationParametersRowVM row) {
var target_exps = get_smart_copy_roll_exps(
row.original_params.roll_schedule_expiration)
.ToHashSet();
@@ -267,13 +207,11 @@ namespace mbts.spark {
}
}
[MemberNotNull(nameof(_parameter_map))]
void _on_parameter_map(AnalyticsExpirationParametersMap parameter_map) {
bool is_first_update = _parameter_map is null;
_parameter_map = parameter_map;
_parameter_map = parameter_map ?? throw new ArgumentNullException(nameof(parameter_map));
_parameters.sync_with(parameter_map.get_sorted_exps().Select(parameter_map.get_parameter));
non_options.sync_with(
parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
non_options.sync_with(parameter_map.get_sorted_exps().Where(exp => exp.security_type != SecurityType.Option));
// Set `is_last_row_of_month_group` for each row
foreach (var exp_rows in rows.GroupBy(r => r.security.expiration.Month)) {
@@ -15,33 +15,12 @@
<cv:DoubleTextConverter
x:Key="RisklessRateConverter"
Multiplier="100" />
<CollectionViewSource x:Key="Drivers" Source="{Binding drivers}" />
<CollectionViewSource x:Key="NonOptionsWithEmpty" Source="{Binding non_options_with_empty}" />
<DataTemplate x:Key="DriverTemplate">
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.driver_display_text_converter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger
Property="Text"
Value="None">
<Setter
Property="FontStyle"
Value="Italic" />
<Setter
Property="Foreground"
Value="Gray" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
<shell:ExpTextConverter
x:Key="ExpirationTextConverter"
ShowSymbol="True"
MapExp="True" />
<DataTemplate x:Key="ExpirationTemplate">
<TextBlock Text="{Binding Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}">
<TextBlock Text="{Binding Converter={StaticResource ExpirationTextConverter}}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
@@ -247,7 +226,7 @@
<DataGrid.Columns>
<DataGridTextColumn
Header="Security"
Binding="{Binding security, Converter={x:Static shell:AnalyticsExpirationParametersView.expiration_text_converter}}"
Binding="{Binding security, Converter={StaticResource ExpirationTextConverter}}"
IsReadOnly="True">
<DataGridTextColumn.CellStyle>
<Style
@@ -310,7 +289,7 @@
Value="True">
<Setter
Property="BorderBrush"
Value="{u:BTSColor UI.input_dirty_border}" />
Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
@@ -318,9 +297,8 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Source={StaticResource Drivers}}"
ItemTemplate="{StaticResource DriverTemplate}"
ItemsSource="{Binding DataContext.non_options, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding driver, UpdateSourceTrigger=PropertyChanged}"
Margin="2" />
</DataTemplate>
@@ -350,8 +328,7 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding deliverable, UpdateSourceTrigger=PropertyChanged}"
Margin="2" />
@@ -382,8 +359,7 @@
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
IsSynchronizedWithCurrentItem="False"
ItemsSource="{Binding Source={StaticResource NonOptionsWithEmpty}}"
ItemsSource="{Binding DataContext.non_options_with_empty, RelativeSource={RelativeSource AncestorType=c:DataGridEx}}"
ItemTemplate="{StaticResource ExpirationTemplate}"
SelectedItem="{Binding roll_schedule, UpdateSourceTrigger=PropertyChanged}"
Margin="2" />
@@ -1,10 +1,8 @@
#nullable enable
namespace mbts.ui.shell {
using bts.api.analytics;
namespace mbts.ui.shell {
using bts.api;
using mbts.spark;
using mbts.ui.controls;
using mbts.ui.converters;
using mbts.ui.extensions;
using System;
@@ -18,8 +16,8 @@ namespace mbts.ui.shell {
/// Interaction logic for AnalyticsExpirationParametersView.xaml
/// </summary>
partial class AnalyticsExpirationParametersView : UserControl {
IDisposable? _context_menu_op;
IDisposable? _data_context_hooks;
IDisposable _context_menu_op;
IDisposable _data_context_hooks;
public AnalyticsExpirationParametersView() {
InitializeComponent();
@@ -33,24 +31,6 @@ namespace mbts.ui.shell {
}
}
public static ExpirationTextConverter expiration_text_converter =>
new() {
ShowSymbol = true,
ShowType = true,
MapExp = true
};
public static IValueConverter driver_display_text_converter =>
ValueConverter.create<ExpirationDriverImmutable?, string?>(
d => d.HasValue ?
d.Value.ModeCase switch {
ExpirationDriver.ModeOneofCase.Security =>
expiration_text_converter.convert(d.Value.Security.to_sec_exp()),
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => "Calculate",
_ => null
} :
null);
void _grid_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e) {
Disposable.dispose(ref _context_menu_op);
if (e.OriginalSource is not FrameworkElement el || DataContext is not AnalyticsExpirationParametersVM vm) {
@@ -67,4 +47,30 @@ namespace mbts.ui.shell {
e.Handled = true;
}
}
class ExpTextConverter : IValueConverter {
public ExpTextConverter() {
NullOrEmptyText = "None";
}
public bool ShowType { get; set; }
public bool ShowSymbol { get; set; }
public bool MapExp { get; set; }
public string NullOrEmptyText { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
var exp = value as SecurityExpiration;
if (exp == null || exp.is_empty()) {
return NullOrEmptyText;
}
return ShowSymbol ?
SecurityFormatter.format_future(exp.symbol, exp.expiration) :
DateFormatter.Format(exp.expiration, DateFormat.MonthCodeLastDigitYear);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
}
@@ -1,11 +1,10 @@
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.spark;
using mbts.ui;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
@@ -39,30 +38,11 @@ namespace mbts.spark {
public void thread_init() {
_vm = new AnalyticsExpirationParametersVM(_bus, _init_settings);
var auto_copy_rolls_cmd = new SparkCommandCommand(
"Auto Copy Rolls", null, _vm.toggle_auto_copy_rolls_cmd);
_vm.SubscribeDisposed(_vm.observe_auto_copy_rolls().Subscribe(v =>
auto_copy_rolls_cmd.icon = v ? Icons.RecurringSchedule : Icons.RecurringScheduleGray));
var auto_copy_rates_cmd = new SparkCommandCommand(
"Auto Copy Rates", null, _vm.toggle_auto_copy_rates_cmd);
_vm.SubscribeDisposed(_vm.observe_auto_copy_rates().Subscribe(v =>
auto_copy_rates_cmd.icon = v ? Icons.FinancialGrowth : Icons.FinancialGrowthGray));
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
_commands = new() {
new SparkCommandCommand("Commit", Icons.Disk, _vm.commit_cmd, new KeyGesture(Key.S, ModifierKeys.Control)),
new SparkCommandCommand("Revert", Icons.UndoCircular, _vm.revert_cmd, new KeyGesture(Key.Z, ModifierKeys.Control)),
auto_copy_rates_cmd,
auto_copy_rolls_cmd,
new SparkCommandCommand(
"Set Driver to Nearest Exp", null, _vm.set_driver_to_nearest_exp_cmd) {
show_in_toolbar = false,
show_in_context_menu = true
},
};
_view = new AnalyticsExpirationParametersView { DataContext = _vm };
}
}
}
@@ -1,61 +1,101 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using bts;
using mbts.analytics;
using bts.api.analytics;
using System.Reactive.Linq;
using bts.api;
using System.Threading;
namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
// 1. Reads exp params from the network and publishes
// it to the BB
// 2. Listens to ExpirationParametersCommitTag and
// writes the calls into persistence to save the data
public class AnalyticsParametersManager : IDisposable {
private readonly ThreadedBlackboard _bb;
private AnalyticsService _analytics_service;
private List<IDisposable> _disposables = new List<IDisposable>();
private IDictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
private readonly ITag<IEnumerable<AnalyticsExpirationParameters>>
_in_bb_exp_params_commit_tag = SparkTags.ExpirationParametersCommitTag;
private readonly ITag<SystemContractData> _in_contracts_tag = SparkTags.SystemContractsTag;
private readonly ITag<AnalyticsExpirationParametersMap> _out_exp_params_tag =
SparkTags.ExpirationParametersInputTag;
private HighPerformanceTimer _timer = new HighPerformanceTimer();
using mbts.analytics;
public AnalyticsParametersManager(ThreadedBlackboard bb,
AnalyticsService analytics_server) {
_bb = bb;
_analytics_service = analytics_server;
var exp_params_sub = _analytics_service.subscribei_exp_parameters()
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_on_exp_parameters);
_disposables.Add(exp_params_sub);
_bb.subscribe(_in_bb_exp_params_commit_tag);
_bb.subscribe(_in_contracts_tag);
_bb.data_callback += _on_bb_data;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
/// <summary>
/// Reads exp params from the network and publishes it to the bus; listens to
/// <see cref="SparkTags.ExpirationParametersCommitTag"/> and persists the data
/// </summary>
public sealed class AnalyticsParametersManager : IDisposable {
IDisposable? _dispose;
public AnalyticsParametersManager(IBus bus, AnalyticsService analytics_service) {
var contracts_src = bus.subscribe(SparkTags.SystemContractsTag);
var exp_params_in_src = analytics_service.subscribei_exp_parameters()
.Select(upd => upd.all
.SelectMany(ep => ep.ParamList
.Select(ep => new AnalyticsExpirationParameters(ep)))
.ToDictionary(ep => ep.security));
var exp_params_out_src = bus.subscribe(SparkTags.ExpirationParametersCommitTag)
.Select(eps => eps
.Where(ep => ep.security.expiration.Date >= DateTime.Today - TimeSpan.FromDays(1)));
_dispose = Disposable.Create(
exp_params_in_src.CombineLatest(contracts_src)
.Select(tup => new AnalyticsExpirationParametersMap(tup.First, tup.Second))
.ObserveOn(SynchronizationContext.Current ?? throw new InvalidOperationException())
.Subscribe(bus.post_callback(SparkTags.ExpirationParametersInputTag)),
exp_params_out_src.Subscribe(save_exp_params));
void save_exp_params(IEnumerable<AnalyticsExpirationParameters> exp_params) {
private void _on_bb_data(object tag, object data) {
if (_in_contracts_tag.Equals(tag)) {
_assemble_and_publish();
} else if (_in_bb_exp_params_commit_tag == tag) {
// listens to the commit tag and saves it
Log.Gen.info($"AnalyticsParametersManager received commit req. count:{exp_params.Count()}");
var to_save = new ExpirationParameterEntryList();
IEnumerable<AnalyticsExpirationParameters> exp_params =
data as IEnumerable<AnalyticsExpirationParameters>;
exp_params = exp_params.Where(e => e.security.expiration.Date >=
DateTime.Now.Date.Subtract(TimeSpan.FromDays(1)));
bts.Log.Gen.info(
String.Format("AnalyticsParametersManager._on_bb_data received commit count:{0}",
exp_params.Count()));
ExpirationParameterEntryList to_save = new ExpirationParameterEntryList();
to_save.ParamList.AddRange(exp_params.Select(i => i.to_exp_param_entry()));
Log.Gen.record(
null,
(dt, elapsed, res) => {
var msg = "AnalyticsParametersManager saved exp_params. " +
$"count:{exp_params.Count()} t:{elapsed.TotalMilliseconds:0.000}ms";
return (LogLevel.Info, msg);
},
() => analytics_service.set_exp_parameters(to_save));
_timer.start();
_analytics_service.set_exp_parameters(to_save);
_timer.stop();
bts.Log.Gen.info(
String.Format("AnalyticsParametersManager saved exp_params count:{0} t:{1} msecs",
exp_params.Count(), _timer.lastIntervalTime));
}
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
void _on_exp_parameters(bts.api.core.Update<ExpirationParameterEntryListImmutable, int> update) {
_data = new Dictionary<mbts.SecurityExpiration, AnalyticsExpirationParameters>();
bts.Log.Gen.info(String.Format("AnalyticsParametersManager._on_exp_parameters received count:{0}",
update.all.Count()));
bts.Log.assert(update.all.Count() == 0 || update.all.Count() == 1);
foreach (ExpirationParameterEntryListImmutable l in update.all) {
foreach (ExpirationParameterEntryImmutable e in l.ParamList) {
AnalyticsExpirationParameters new_entry = new AnalyticsExpirationParameters(e);
_data[new_entry.security] = new_entry;
}
break;
}
Log.Gen.info($"AnalyticsParametersManager._on_exp_parameters count: {_data.Count}");
_assemble_and_publish();
// _bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data));
}
private void _assemble_and_publish() {
if (_data != null) {
SystemContractData sc_data = _bb.read_state(_in_contracts_tag);
if (sc_data != null) {
_bb.post(_out_exp_params_tag, new AnalyticsExpirationParametersMap(_data, sc_data));
}
}
}
#region IDisposable
public void Dispose() {
_bb.data_callback -= _on_bb_data;
foreach (IDisposable d in _disposables) {
d.Dispose();
}
}
#endregion
}
}
@@ -125,8 +125,8 @@ namespace mbts.spark {
if (_is_different(res)) {
_last_published = new OptionDriverPriceMap(_sec_tup.security_name, res);
var to_fire = new OptionDriverPriceMap(_sec_tup.security_name, res);
// bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
// $"map:{to_fire.log_string()}");
bts.Log.Gen.info("SingleOptionDriverPricePublisher._compute_and_fire \n" +
$"map:{to_fire.log_string()}");
_logger.stop_default_timer();
_bb.post(SparkTags.OptionDriverBBOTag(_sec_tup.security_name),
new OptionDriverPriceMap(_sec_tup.security_name, res));
@@ -1,19 +1,17 @@
namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
using mbts.analytics;
using Spark.Core.Protobuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts.analytics;
using bts;
using bts.api.analytics;
using System.Reactive.Linq;
using System.Threading;
using bts.api;
using System.Collections;
namespace mbts.spark {
// For a single VolSurface this class
// 1. Listents to commmits and calls the service to persist data
// 2. Gathers the vol surface input from the nw and publishes it
@@ -80,8 +78,11 @@
_snp_shot_map.Values);
}
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) =>
ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs.Volsurface.ToByteArray());
static VolSurfaceInput _to_vs_input(VolSurfaceEntryImmutable vs) {
byte[] vs_bytes = vs.Volsurface.ToByteArray();
return
mbts.analytics.VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_bytes);
}
private void _on_bb_data(object tag, object data) {
if (_in_bb_committ_tag.Equals(tag)) {
@@ -13,28 +13,21 @@ namespace mbts.spark {
bts.Log.Gen.info($"SingleVolSurfaceTimeSource cons vs_id:{vs_id}");
_vs_id = vs_id;
_bb = bb;
_bb.subscribe(SparkTags.VolSurfaceStandardServerTimeTag);
_bb.data_callback += _on_data;
_read_and_publish();
_bb.timer_callback += _on_timer;
}
private void _on_data(object tag, object data) {
if (tag.Equals(SparkTags.VolSurfaceStandardServerTimeTag)) {
_read_and_publish();
}
}
private void _read_and_publish() {
VolSurfaceStandardTime vs_time = _bb.read_state(SparkTags.VolSurfaceStandardServerTimeTag);
if (vs_time != null) {
bts.Log.Gen.info($"SingleVolSurfaceTimeSource vs_id:{_vs_id} posting time:{vs_time.ToString()}");
_bb.post(SparkTags.VolSurfaceStandardTimeTag(_vs_id), vs_time);
private void _on_timer() {
if (DateTime.Now - _last_publish_time >= _publish_period) {
_last_publish_time = DateTime.Now;
VolSurfaceStandardTime time = VolSurfaceStandardTime.get_local_default();
bts.Log.Gen.info($"SingleVolSurfaceTimeSource vs_id:{_vs_id} posting time:{time.ToString()}");
_bb.post(SparkTags.VolSurfaceStandardTimeTag(_vs_id), time);
}
}
#region IDisposable
public void Dispose() {
_bb.data_callback -= _on_data;
_bb.timer_callback -= _on_timer;
}
#endregion
}
@@ -15,7 +15,6 @@ using System.Reactive.Linq;
using System.Collections;
using mbts.spark;
using System.DirectoryServices.ActiveDirectory;
using Spark.Core.Protobuf;
// using mbts.bb;
namespace mbts.spark {
@@ -54,7 +53,6 @@ namespace mbts.spark {
// 2. Listens to the activation tag (also published by the UI) and
// creates the SingleVolSurfaceManager for the VS
public class VolSurfaceBusManager : IDisposable {
private List<IDisposable> _disps = new List<IDisposable>();
private ThreadedBlackboard _bb;
private bts.api.analytics.AnalyticsService _analytics_service;
// in tags
@@ -79,7 +77,7 @@ namespace mbts.spark {
bts.api.analytics.AnalyticsService analytics_service) {
bts.Log.Ui.info("VSBusManager cons tid:{VolSurfaceTroubleshootingFunctions.tid()}");
_bus = bus;
_bb = new ThreadedBlackboard("AW2", bus);
_bb = new ThreadedBlackboard(bus);
_analytics_service = analytics_service;
// subs to bb
_bb.subscribe(_in_scdata_tag);
@@ -96,13 +94,9 @@ namespace mbts.spark {
var vs_usage_sub = _analytics_service.subscribei_volsurface_usage()
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_on_vs_usage_update);
var vs_time_sub = _analytics_service.subscribei_volsurface_time()
.ObserveOn(SynchronizationContext.Current)
.Subscribe(_on_vs_time);
_subs.Add(vs_time_sub);
_subs.Add(vs_sub);
_subs.Add(vs_usage_sub);
_subs.Add(new AnalyticsParametersManager(bus, _analytics_service));
_subs.Add(new AnalyticsParametersManager(_bb, _analytics_service));
_subs.Add(new ResourceAllocator(bus, _bb));
_subs.Add(new SymbolAggregationPublisher<OptionDriverPriceMap>(
_bb, (sym) => SparkTags.OptionDriverBBOTag(sym),
@@ -112,47 +106,38 @@ namespace mbts.spark {
SparkTags.AllInterpGreeks));
_subs.Add(new LiveTheoPublisher(_bb));
_subs.Add(new VolSurfaceInterpGreeksMultiplexer(_bb));
// usage
var list_sub = _bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher().Subscribe(t => {
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
IDictionary<string, int> name_to_ids = new Dictionary<string, int>();
foreach (var kv in t) {
name_to_ids[kv.Value] = kv.Key;
//_subs.Add(new AnalyticsServiceTester(_bb));
// TODO: temporatily publish values
VolSurfaceUsageList ulist = new VolSurfaceUsageList();
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = 6,
SecTup = new bts.api.SecurityTuple() {
Type = SecurityType.Option,
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "BTC"),
Symbol = "BTC"
}
Log.Ui.info($"VolSurfaceUsageList name_to_ids count: {name_to_ids.Count}");
var vs_usage = mbts.config.Configuration.get<bts.config.toggles.VolSurfaceUsage>();
Log.Ui.info($"VolSurfaceUsageList vs_usage acount: {vs_usage.vol_surface_usage.Count}");
foreach (var u in vs_usage.vol_surface_usage) {
string option_name = u.option_name;
string vs_name = u.vs_name;
int vs_key;
if (name_to_ids.TryGetValue(vs_name, out vs_key)) {
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = vs_key,
SecTup = new bts.api.SecurityTuple {
Type = SecurityType.Option,
Venue = Venue.Deribit,
Symbol = option_name
}
});
} else {
Log.Gen.error($"Could not find vol surface with name: {vs_name}");
}
}
var list_imm = new VolSurfaceUsageListImmutable(ulist);
Log.Ui.info(list_imm.log_string());
_bb.post(SparkTags.VolSurfaceUsageTag, list_imm);
});
_disps.Add(list_sub);
}
public ThreadedBlackboard bb() {
return _bb;
ulist.UsageList.Add(new VolSurfaceUsageEntry() {
VsId = 7,
SecTup = new bts.api.SecurityTuple() {
Type = SecurityType.Option,
Venue = VolSurfaceTemp.get_default_venue(SecurityType.Option, "ETH"),
Symbol = "ETH"
}
});
_bb.post(SparkTags.VolSurfaceUsageTag, new VolSurfaceUsageListImmutable(ulist));
}
void _on_vs_usage_update(Update<VolSurfaceUsageListImmutable, int> update) {
// TODO
return;
// int vs_count = update.all.Count();
// Log.Gen.info($"VSBusManager._on_vs_usage_update " +
// $"tid:{Thread.CurrentThread.ManagedThreadId} count:{update.all.Count()}");
// Log.assert(vs_count <= 1);
// if (update.all.TryGetSingle(out var to_write)) {
// _bb.post(SparkTags.VolSurfaceUsageTag, to_write);
// }
}
void _on_vss(bts.api.core.Update<VolSurfaceEntryImmutable, UInt64> update) {
@@ -167,17 +152,6 @@ namespace mbts.spark {
_init_vss(to_publish.Keys);
}
void _on_vs_time(bts.api.core.Update<VolSurfaceServerTimeImmutable, int> update) {
if (update.all.Count() != 1) {
return;
}
VolSurfaceStandardTime vs_time =
new VolSurfaceStandardTime(update.all.ElementAt(0).UtcTime.Seconds);
bts.Log.Gen.info(String.Format("VSBusManager._on_vs_time vs_time: {0}",
vs_time.ToString()));
_bb.post(SparkTags.VolSurfaceStandardServerTimeTag, vs_time);
}
private void _init_vss(IEnumerable<int> vs_ids) {
// we consider every vs in the db as "activated" which might prove to be expensive
// (will take care of it later)
@@ -198,7 +172,7 @@ namespace mbts.spark {
// callback
mbts.analytics.VolSurfaceSettings vs_settings = data as mbts.analytics.VolSurfaceSettings;
bts.Log.Gen.info(String.Format("VSBusManager._on_bb_update received vs creation tag vs:{0}",
ProtobufSerializationHelper.serialize_to_string(vs_settings)));
VolSurfaceUtilityFunctions.serialize_proto_to_text(vs_settings)));
_waiting_creations.Enqueue(vs_settings);
} else if (_in_bb_delete_tag.Equals(tag)) {
int vs_id = (int)data;
+6 -38
View File
@@ -3,8 +3,6 @@ using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using mbts.ui;
using MathNet.Numerics.Providers.FourierTransform;
using BCG;
namespace mbts.spark {
// Publishes theos for all options (on the side, also publishes the theos for TC2)
@@ -17,15 +15,12 @@ namespace mbts.spark {
private readonly HighPerformanceTimer _timer = new HighPerformanceTimer();
private readonly PerfStatsLogger _logger = new PerfStatsLogger(50, 100);
private readonly string _log_id = "LiveTheoPublisher";
private DateTime _last_future_theos_published = DateTime.MinValue;
private TimeSpan _futures_theos_publish_period = TimeSpan.FromMilliseconds(300);
public LiveTheoPublisher(ThreadedBlackboard bb) {
_bb = bb;
_bb.subscribe(_greeks_tag);
_bb.subscribe(_drivers_tag);
_bb.data_callback += _on_data;
_bb.timer_callback += _on_timer;
_interp_and_publish();
}
@@ -36,10 +31,6 @@ namespace mbts.spark {
}
}
private void _on_timer() {
_publish_future_theos();
}
private void _log_interpgreeks(
IReadOnlyDictionary<string, OptionTheoInterpolationData> interp_greeks) {
string log_msg = String.Empty;
@@ -136,18 +127,18 @@ namespace mbts.spark {
var k_theos = new Dictionary<SecurityStrike, TheoPoint>();
foreach (var kv in sc_data.strike_map) {
foreach (SecurityStrike k in kv.Value) {
var (call_id, put_id) = k.call_put_id;
var cp_id = k.call_put_id;
var driver = _get_option_driver(driver_map, k);
var tp = _interp_theo(interp_greeks, k, driver.get_driver());
k_theos[k] = tp;
// put it in the output map
if (call_id.HasValue) {
res.Add(call_id.Value,
if (cp_id.Item1.HasValue) {
res.Add(cp_id.Item1.Value,
new GreeksTuple(tp.vol, tp.driver, tp.call, tp.cdelta, tp.cgamma,
tp.cvega, tp.c_theta, Double.NaN));
}
if (put_id.HasValue) {
res.Add(put_id.Value,
if (cp_id.Item2.HasValue) {
res.Add(cp_id.Item2.Value,
new GreeksTuple(tp.vol, tp.driver, tp.put, tp.pdelta, tp.pgamma,
tp.pvega, tp.p_theta, Double.NaN));
}
@@ -162,31 +153,8 @@ namespace mbts.spark {
_publish_tc2_theos(k_theos);
}
// recomputes and publishes them periodicially
void _publish_future_theos() {
if (DateTime.Now - _last_future_theos_published < _futures_theos_publish_period)
return;
_last_future_theos_published = DateTime.Now;
var rv = new Dictionary<SecurityExpiration, FutureTheoStructure>();
SystemContractData sc_data = _bb.read_state(SparkTags.SystemContractsTag);
if (sc_data == null)
return;
foreach (var kv in sc_data.exp_map) {
var id = kv.Value;
SecurityMD sec_md;
if (sc_data.sec_md_map.TryGetValue(id, out sec_md)) {
if (sec_md.security.HasFuture) {
SecurityExpiration exp = kv.Key;
double pr = sec_md.md.fixing_price;
rv.Add(exp, new FutureTheoStructure(exp.expiration, pr, pr, 1, 0));
}
}
}
_bb.post(SparkTags.TC2Tags.LiveFutureTheosTag, rv);
}
public void Dispose() {
_bb.data_callback -= _on_data;
}
}
}
}
@@ -24,7 +24,7 @@ namespace mbts.spark {
var exp = kv.Key;
if (!temp.ContainsKey(kv.Key)) {
temp.Add(kv.Key,
new AnalyticsExpirationParameters(exp, null, empty, empty, 0, 0, 0, 0, 0));
new AnalyticsExpirationParameters(exp, empty, empty, empty, 0, 0, 0, 0, 0));
}
}
exp_map = temp;
@@ -1,43 +1,58 @@
#nullable enable
using System;
using System.Collections.Generic;
using mbts.analytics;
using bts.api;
using bts.api.persistence;
using System.Linq;
namespace mbts.spark {
using mbts.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
// All driver prices (along with some more info) for an option symbol
public class OptionDriverPriceMap {
public readonly string option_symbol;
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map;
Dictionary<SecurityExpiration, DriverMD>? _unexpired_exp_price_map_backing;
public readonly String option_symbol = null;
public readonly IDictionary<SecurityExpiration, DriverMD> exp_price_map = null;
public OptionDriverPriceMap(
string option_symbol, IDictionary<SecurityExpiration, DriverMD> exp_price_map) {
this.option_symbol = option_symbol;
this.exp_price_map = exp_price_map;
string option_symbol_a,
IDictionary<SecurityExpiration, DriverMD> exp_price_map_a) {
option_symbol = option_symbol_a;
exp_price_map = exp_price_map_a;
}
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map {
get {
return exp_price_map.Where(
kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary(
kv => kv.Key, kv => kv.Value);
}
}
public IDictionary<SecurityExpiration, DriverMD> unexpired_exp_price_map =>
_unexpired_exp_price_map_backing ??=
exp_price_map.Where(kv => kv.Key.expiration >= DateTime.Now.Date).ToDictionary();
// this is the BS needed because of ignoring exchange
public DriverMD get_driver_md(DateTime exp) =>
exp_price_map.FirstOrDefault(kv => kv.Key.expiration == exp).Value ?? DriverMD.empty;
public DriverMD get_driver_md(SecurityExpiration exp) =>
exp_price_map.GetValueOrDefault(exp) ?? DriverMD.empty;
public DriverMD get_driver_md(DateTime exp) {
foreach (var kv in exp_price_map) {
if (kv.Key.expiration == exp) {
return kv.Value;
}
}
return DriverMD.empty;
}
public DriverMD get_driver_md(SecurityExpiration exp) {
if (exp_price_map.TryGetValue(exp, out var d))
return d;
return DriverMD.empty;
}
public static IDictionary<VolSurfaceExpiration, DriverMD> get_vs_price_map(
IReadOnlyDictionary<string, OptionDriverPriceMap> all_sym_map,
Func<string, bool>? sym_filter = null
) {
sym_filter ??= _ => true;
return all_sym_map.SafeWhere(kv => kv.Value is not null && sym_filter(kv.Key))
.SelectMany(kv => kv.Value.exp_price_map)
.ToDictionaryCrushed(kv => kv.Key.to_vs_exp(), kv => kv.Value);
Func<string, bool> sym_filter = null) {
var rv = new Dictionary<VolSurfaceExpiration, DriverMD>();
if (all_sym_map != null)
foreach (var kv in all_sym_map) {
string sym = kv.Key;
OptionDriverPriceMap sym_map = kv.Value;
if (sym_filter == null || sym_filter(sym)) {
foreach (var kv_int in sym_map.exp_price_map) {
rv[new VolSurfaceExpiration(kv_int.Key)] = kv_int.Value;
}
}
}
return rv;
}
}
}
}
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -173,7 +173,7 @@ namespace mbts.spark {
}
IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv_data =
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
return Tuple.Create(exp.to_security_expiration(type: SecurityType.Option), rv_data);
return Tuple.Create(exp.to_security_expiration(), rv_data);
}
internal IDictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> get_option_bbo(
@@ -182,11 +182,12 @@ namespace mbts.spark {
Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>> rv =
new Dictionary<double, Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>>();
foreach (SecurityStrike k in strikes) {
var (call_id, put_id) = k.call_put_id;
// call
uint? call_id = k.call_put_id.Item1;
var call_sec_md = get_sec_md(call_id);
VolSurfaceMDUnit call_bbo = call_sec_md == null ? VolSurfaceMDUnit.empty : call_sec_md.Item2;
// put
uint? put_id = k.call_put_id.Item2;
var put_sec_md = get_sec_md(put_id);
VolSurfaceMDUnit put_bbo = put_sec_md == null ? VolSurfaceMDUnit.empty : put_sec_md.Item2;
rv.Add(k.strike, new Tuple<VolSurfaceMDUnit, VolSurfaceMDUnit>(call_bbo, put_bbo));
@@ -22,7 +22,6 @@ namespace mbts.spark {
/// from the same secondary thread.
/// </summary>
public class ThreadedBlackboard {
private readonly string _bb_name;
private IBus _bus;
private List<IDisposable> _subs = new List<IDisposable>();
private HashSet<object> _tag_map = new HashSet<object>();
@@ -32,10 +31,9 @@ namespace mbts.spark {
private IDictionary<object, object> _cache = new
Dictionary<object, object>();
private static int _tid() { return VolSurfaceTroubleshootingFunctions.tid(); }
public ThreadedBlackboard(string name, IBus bus) {
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{_tid()} bb_name: {name}");
public ThreadedBlackboard(IBus bus) {
bts.Log.Ui.info($"ThreadedBlackBoard.cons tid:{ _tid()}");
_bus = bus;
_bb_name = name;
subscribe(SparkTags.SparkTimer);
System.Threading.Thread timer_thread = new System.Threading.Thread(() => {
DateTime start_time = DateTime.Now;
@@ -63,13 +61,15 @@ namespace mbts.spark {
return;
}
_tag_map.Add(tag);
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{_tid()}");
bts.Log.Ui.info($"ThreadedBlackBoard.subscribe tag:{tag} tid:{ _tid()}");
var observable = _bus.subscribe(tag).OnDispatcher().Subscribe(
data => _on_bus_data(tag, data));
_subs.Add(observable);
}
public void post<T>(ITag<T> tag, T data, bool block_until_written = false) {
bts.Log.Ui.diag($"ThreadedBlackBoard.post tag:{tag} data:{_data_string(data)} " +
$"tid:{_tid()}");
_cache[tag] = data;
_bus.post(tag, data);
}
@@ -92,6 +92,8 @@ namespace mbts.spark {
timer_callback();
return;
}
bts.Log.Ui.diag($"ThreadedBlackBoard._on_bus_data tag:{tag} data:{_data_string(data)} " +
$"tid:{_tid()}");
data_callback(tag, data);
}
@@ -1,25 +1,17 @@
using bts.api;
using bts.api.analytics;
using bts.collections;
using bts.utils;
using IronPython.Compiler.Ast;
using mbts;
using mbts.analytics;
using mbts.spark;
using mbts.ui.controls;
using mbts.ui.converters;
using mbts.ui.shell;
using Spark.Core;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using mbts;
using mbts.analytics;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.spark;
using bts.utils;
using bts.api;
using bts.collections;
using System.Collections.Immutable;
namespace mbts.spark {
/// This contains the list of global values for the vol
@@ -140,7 +132,7 @@ namespace mbts.spark {
internal static string log_string(this Theos t) {
string rv = $"strike: {t.strike} fwd: {t.fwd} driver: {t.driver} " +
$"move: {t.move} vol: {t.vol} c_theo: {t.call} " +
$"move: { t.move} vol: {t.vol} c_theo: {t.call} " +
$"p_theo: {t.put}";
return rv;
}
@@ -159,8 +151,8 @@ namespace mbts.spark {
foreach (var kv in sc_data.strike_map) {
var exp = kv.Key;
foreach (var k in kv.Value) {
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.call)} " +
$"p_id: {k.call_put_id.put}" + "\n";
rv += $"exp: {exp} k: {k} c_id: {k_id(k.call_put_id.Item1)} " +
$"p_id: {k.call_put_id.Item2}" + "\n";
}
}
return rv;
@@ -186,58 +178,6 @@ namespace mbts.spark {
return rv;
}
internal static string log_string(this ComboFullData cf_data) {
string rv = String.Empty;
if (cf_data.option_expirations != null) {
foreach (var kv in cf_data.option_pos_map) {
var exp = kv.Key;
foreach (var kv_in in kv.Value) {
double k = kv_in.Key;
ComboStrikeData kp = kv_in.Value;
rv += $"exp: {exp.ToString()} k: {k} Pos: {kp.call_pos},{kp.put_pos} ({kp.call_raw_pos},{kp.put_raw_pos}) ";
}
}
}
if (cf_data.future_pos_map != null) {
foreach (var kv in cf_data.future_pos_map) {
rv += $"exp: {kv.Key.ToString()} {kv.Value.Item1},{kv.Value.Item2} ";
}
}
return rv;
}
internal static string log_string(this SlideFullData sl_data) {
Func<SlideGreekUnitKey, string> sguk_str = (sguk) => sguk.display_name;
Func<SlideGreekUnit, string> sgu_str = (sgu) => {
if (sgu == null)
return "No Handles";
string rv = $"Handle: {sgu.driver_price} ";
foreach (double d in sgu.position_greeks)
rv += $"{d}, ";
rv = rv.Trim();
if (rv.EndsWith(","))
rv = rv.TrimEnd(',');
return rv;
};
string rv = String.Empty;
foreach (var kv in sl_data.map) {
rv += $"SlideGreekUnitKey: {sguk_str(kv.Key)}\n";
foreach (var i_kv in kv.Value) {
rv += sgu_str(i_kv.Value) + "\n";
}
}
rv += $"Overriden?: {sl_data.ui_override != null}";
return rv;
}
internal static string log_string(this VolSurfaceUsageListImmutable vsu_list) {
string rv = "VolSurfaceUsageList:";
foreach (var u in vsu_list.UsageList) {
rv += $" {u.SecTup.Symbol}:{u.VsId}";
}
return rv;
}
internal static int tid() {
return System.Threading.Thread.CurrentThread.ManagedThreadId;
}
@@ -86,14 +86,9 @@ namespace mbts.spark {
}
private void _save_exp_params() {
var api_driver = new ExpirationDriverImmutable(new() {
Security = driver_exp.to_api_sec_exp()
});
var exp_params = new AnalyticsExpirationParameters[] {
new AnalyticsExpirationParameters(
option_exp1, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
new AnalyticsExpirationParameters(
option_exp2, api_driver, driver_exp, driver_exp, 0, 0, double.NaN, 1, 1),
var exp_params = new AnalyticsExpirationParameters[]{
new AnalyticsExpirationParameters(option_exp1, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
new AnalyticsExpirationParameters(option_exp2, driver_exp, driver_exp, driver_exp, 0, 0, Double.NaN, 1, 1),
};
_bb.post(SparkTags.ExpirationParametersCommitTag, exp_params);
}
@@ -108,4 +103,4 @@ namespace mbts.spark {
}
#endregion
}
}
}
@@ -31,24 +31,11 @@ namespace mbts.ui.controls {
VolSurfaceExpiration exp = p.Key;
VolCurveOutput exp_output = p.Value;
IDictionary<VolSurfaceDisplayGridColumn, object> out_exp_map = VolSurfaceUIAdapterUtils.get_exp_data(ref out_grid, exp);
out_exp_map[_fwd_col] = exp_output?.fwd ?? double.NaN;
out_exp_map[_ref_fwd_col] = exp_output
?.adjusted_curve_parameters
?.core_parameters
?.ref_forward
?? double.NaN;
out_exp_map[_live_driver_col] = exp_output
?.aux_data
?.driver_price
?? double.NaN;
out_exp_map[_driver_override_col] = exp_output
?.adjusted_curve_parameters
?.core_parameters
?.driver_override
?? double.NaN;
out_exp_map[_fwd_col] = exp_output == null ? Double.NaN : exp_output.fwd;
out_exp_map[_ref_fwd_col] = exp_output != null && exp_output.adjusted_curve_parameters != null && exp_output.adjusted_curve_parameters.core_parameters != null ?
exp_output.adjusted_curve_parameters.core_parameters.ref_forward : Double.NaN;
out_exp_map[_live_driver_col] = (exp_output != null && exp_output.aux_data != null) ? exp_output.aux_data.driver_price : Double.NaN;
out_exp_map[_driver_override_col] = exp_output.adjusted_curve_parameters.core_parameters.driver_override;
}
}
@@ -3,11 +3,10 @@ namespace mbts.spark {
using mbts.ui;
using mbts.ui.controls.graph;
using mbts.ui.shell;
using ProtoBuf;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
@@ -111,7 +110,7 @@ namespace mbts.spark {
//}
public object Clone() =>
ProtobufSerializationHelper.clone(this);
ProtoBufSerializationHelper.clone_protobuf(this);
public bool Equals(VolSurfaceGraphSettings other) =>
other != null &&
@@ -26,7 +26,7 @@ namespace mbts.spark.VolSurface {
id = key ?? throw new InvalidOperationException("Column key cannot be null");
}
public VolSurfaceDisplayGridColumn model { get; }
public VolSurfaceDisplayGridColumn model { get; set; }
public VolSurfaceColumnType type => model.type;
public new VolSurfaceColumnSettings create() {
@@ -43,7 +43,7 @@ namespace mbts.spark.VolSurface {
static Thickness _header_cell_padding => new(6, 0, 4, 0);
IValueConverter _data_context_converter =>
ValueConverter.create<VolSurfaceRowVM, object>(row => row?.get_cell(model));
ValueConverter.create<VolSurfaceRowContext, object>(row => row?.get_cell(model));
public override FrameworkElement view_factory() {
return type switch {
@@ -58,7 +58,7 @@ namespace mbts.spark.VolSurface {
HorizontalAlignment = HorizontalAlignment.Left,
Foreground = BTSColors.header_text.to_brush(),
};
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowVM.expiration)));
text.SetBinding(TextBlock.TextProperty, new Binding(nameof(VolSurfaceRowContext.expiration)));
var bd = new Border {
HorizontalAlignment = HorizontalAlignment.Stretch,
Padding = _header_cell_padding,
@@ -1,4 +1,4 @@
namespace mbts.spark.VolSurface {
namespace mbts.spark.VolSurface {
using bts;
using bts.collections;
using bts.utils;
@@ -63,7 +63,7 @@ namespace mbts.spark.VolSurface {
};
_dispose = Disposable.Create(
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowVM(this, exp), row => row.Dispose()),
ObservableAutoWrapper.connect(_expirations, rows, exp => new VolSurfaceRowContext(this, exp), row => row.Dispose()),
sorted_visible_rows.bind(visible_rows),
Disposable.Create(() => {
this.model.on_candidate_grid_change -= _on_grid_updated;
@@ -102,14 +102,14 @@ namespace mbts.spark.VolSurface {
public IReadOnlyObservableCollection<DIYGrid.ColumnBase> columns =>
_columns_model.views_with_header_ro;
public ObservableCollection<VolSurfaceRowVM> rows { get; } = new();
public ObservableCollection<VolSurfaceRowVM> visible_rows { get; } = new();
public ObservableSortedCollection<VolSurfaceRowVM> sorted_visible_rows { get; } = new(_row_comparer);
public ObservableCollection<VolSurfaceRowContext> rows { get; } = new();
public ObservableCollection<VolSurfaceRowContext> visible_rows { get; } = new();
public ObservableSortedCollection<VolSurfaceRowContext> sorted_visible_rows { get; } = new(_row_comparer);
public bool any_masters_selected =>
selected_rows.select_display_exp().where_master().Any();
public IEnumerable<VolSurfaceRowVM> selected_rows =>
public IEnumerable<VolSurfaceRowContext> selected_rows =>
visible_rows.where_selected();
public IEnumerable<DIYGridSuperHeaderVM> super_headers =>
@@ -118,13 +118,13 @@ namespace mbts.spark.VolSurface {
.Select(group => new DIYGridSuperHeaderVM(group.Key, group.Count(), collapsed_content: _short_header(group.Key)))
.ToList();
public ICommand main_settings_cmd => _parent.main_settings_cmd;
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
public ICommand graph_settings_cmd => _parent.vol_curve_vm.settings_command;
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
public ICommand main_settings_command => _parent.main_settings_command;
public ICommand advanced_settings_command => _parent.advanced_settings_command;
public ICommand graph_settings_command => _parent.vol_curve_vm.settings_command;
public ICommand grid_settings_command => _parent.grid_settings_command;
static IComparer<VolSurfaceRowVM> _row_comparer =>
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowVM>(r => r.expiration);
static IComparer<VolSurfaceRowContext> _row_comparer =>
Comparer<VolSurfaceDisplayGridExpiration>.Default.wrap<VolSurfaceDisplayGridExpiration, VolSurfaceRowContext>(r => r.expiration);
public void load_from(VolSurfaceMacroGridSettings grid_settings) {
_hidden_columns = new HashSet<string>(grid_settings.hidden_cols());
@@ -193,23 +193,23 @@ namespace mbts.spark.VolSurface {
}
}
internal void copy_to_selection(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
internal void copy_to_selection(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, selected_rows.select_display_exp().Except(exp), _get_columns(column, set));
}
}
internal void copy_to_masters(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
internal void copy_to_masters(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, _expirations.where_master().Except(exp), _get_columns(column, set));
}
}
internal void copy_to_all(
VolSurfaceDisplayGridExpiration exp,
VolSurfaceDisplayGridColumn column,
GridColumnSet set) =>
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
internal void copy_to_all(VolSurfaceDisplayGridExpiration exp, VolSurfaceDisplayGridColumn column, GridColumnSet set) {
if (column.type == VolSurfaceColumnType.ReadWriteTick) {
_replicate(exp, _expirations.Except(exp), _get_columns(column, set));
}
}
static string _short_header(string header) =>
string.Join("", header.Where(Char.IsUpper));
@@ -299,7 +299,7 @@ namespace mbts.spark.VolSurface {
VolSurfaceDisplayGridExpiration source,
IEnumerable<VolSurfaceDisplayGridExpiration> target_exps,
IEnumerable<VolSurfaceDisplayGridColumn> cols) {
foreach (var col in cols.Where(c => c.type.is_editable())) {
foreach (var col in cols) {
foreach (var exp in target_exps) {
_copy(source, exp, col);
}
@@ -307,14 +307,7 @@ namespace mbts.spark.VolSurface {
_commit();
}
void _copy(
VolSurfaceDisplayGridExpiration source,
VolSurfaceDisplayGridExpiration dest,
VolSurfaceDisplayGridColumn col
) {
if (!col.type.is_editable()) {
throw new ArgumentException("Expected col to be editable", nameof(col));
}
void _copy(VolSurfaceDisplayGridExpiration source, VolSurfaceDisplayGridExpiration dest, VolSurfaceDisplayGridColumn col) {
if (current_grid.read(source, col, out var value)) {
current_grid.set_grid_data(dest, col.unique_col_name, value);
}
@@ -0,0 +1,335 @@
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
using System.Windows.Media;
public struct VolSurfaceCellState {
public bool is_dirty => committed_text != null;
public FormattedText text;
public FormattedText committed_text;
}
class VolSurfaceRowContext : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
/// TODO: remove _text_cache when we are sure that the new row view
/// (<see cref="VolSurfaceRowView"/>) is solid. It must remain in place
/// until then, as it is used by old row view
/// (<see cref="VolSurfaceRowControl"/>).
readonly Dictionary<string, CellData> _cells = new();
MenuContext _context_menu;
bool _is_selected;
public VolSurfaceRowContext(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
});
}
public event Action<bool> is_selected_changed;
public event Action invalidated;
public VolSurfaceDisplayGridExpiration expiration => _exp;
public bool is_selected {
get => _is_selected;
set {
if (_is_selected != value) {
_is_selected = value;
is_selected_changed?.Invoke(value);
_parent.signal_selection_changed();
}
}
}
public MenuContext context_menu =>
_context_menu ??= new(_parent, this);
public VolGridCellVM get_cell(VolSurfaceDisplayGridColumn column) {
if (!_cells.TryGetValue(column.unique_col_name, out var cell_data)) {
_cells.Add(column.unique_col_name, cell_data = _create_cell(column));
}
return cell_data.vm;
}
public void invalidate() {
foreach (var cell in _cells.Values) {
_sync_cell(cell.vm);
}
raise_invalidated();
}
public override string ToString() =>
_exp.ToString();
public string[] get_cell_clipboard_strings() =>
new[] { _exp.ToString() }.Concat(
_parent.columns.OfType<VolSurfaceColumn>()
.Skip(1)
.Select(c => {
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
return c.model.format(val);
}))
.ToArray();
public void raise_invalidated() =>
invalidated?.Invoke();
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
var cell = column.type switch {
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
_ => new VolGridCellVM(column.unique_col_name),
};
_sync_cell(cell);
var dispose = cell.observe_candidate().DistinctUntilChanged().OnDispatcher().Subscribe(value => {
var curr = _parent.current_grid.read(expiration, column);
if (Equals(value, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, column, value);
_parent.model.set_candidate_grid(grid);
});
return new(cell, dispose);
VolGridTickCellVM create_tick_cell() {
var cell = new VolGridTickCellVM(column.unique_col_name);
cell.request_tick += is_up => {
var col = _parent.get_column(column.unique_col_name);
if (col is null) {
throw new InvalidOperationException($"Failed to find column with id {column.unique_col_name}");
}
if (col.model?.tick_move is var tm) {
cell.candidate_value = tm(cell.candidate_value, is_up);
return;
}
throw new InvalidOperationException($"tick_move is not defined");
};
return cell;
}
}
void _sync_cell(VolGridCellVM cell) {
if (cell is null) {
return;
}
cell.committed_value = _parent.committed_grid.read(_exp, cell.column_id);
cell.candidate_value = _parent.current_grid.read(_exp, cell.column_id);
}
public class MenuContext : ViewModelBase {
readonly VolSurfaceRowContext _row;
readonly VolSurfaceGridVM _parent;
VolSurfaceColumn _col;
DIYGridSuperHeaderVM _supercol;
ICommand _revert_command;
ICommand _shift_selection_command;
ICommand _shift_masters_command;
ICommand _shift_all_command;
ICommand _clear_command;
ICommand _copy_to_selection_command;
ICommand _copy_to_masters_command;
ICommand _copy_to_all_command;
ICommand _copy_all_to_clipboard_command;
ICommand _smart_copy_rolls_rates_command;
ICommand _import_csv_command;
public MenuContext(
VolSurfaceGridVM parent,
VolSurfaceRowContext row) {
_parent = parent;
_row = row;
}
public string column_name => _col.model.display_name;
public string group_name => _supercol.id;
public string expiration_name => _row.ToString();
public VolSurfaceColumn column {
get => _col;
set => Set(ref _col, value);
}
public DIYGridSuperHeaderVM super_header {
get => _supercol;
set => Set(ref _supercol, value);
}
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
public class SymbolFilter {
readonly MenuContext _context;
bool? _visible;
public SymbolFilter(MenuContext context, string symbol, int count, int visible_count) {
_context = context;
this.symbol = symbol;
if (count == visible_count) {
_visible = true;
} else if (visible_count == 0) {
_visible = false;
} else {
_visible = null;
}
}
public string symbol { get; private set; }
public bool? visible {
get => _visible;
set {
_visible = value;
if (value == true) {
_context._show_symbol(symbol);
} else if (value == false) {
_context._hide_symbol(symbol);
}
}
}
}
public IEnumerable<SymbolFilter> symbols {
get {
var visible_exps = _parent.visible_rows
.Cast<VolSurfaceRowContext>()
.GroupBy(r => r._exp.symbol)
.ToDictionary(g => g.Key);
var result = _parent.rows
.GroupBy(r => r._exp.symbol)
.OrderBy(g => g.Key)
.Select(g => new SymbolFilter(this, g.Key, g.Count(), visible_exps.ContainsKey(g.Key) ? visible_exps[g.Key].Count() : 0));
return result;
}
}
public bool is_input_cell => _col.type == VolSurfaceColumnType.ReadWriteTick;
public ICommand main_settings_command => _parent.main_settings_command;
public ICommand advanced_settings_command => _parent.advanced_settings_command;
public ICommand grid_settings_command => _parent.grid_settings_command;
public ICommand graph_settings_command => _parent.graph_settings_command;
public ICommand revert_command =>
_revert_command ??= new DelegateCommand(_ => _row.get_cell(_col.model)?.revert());
public ICommand shift_selection_command =>
_shift_selection_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_selection(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_masters_command =>
_shift_masters_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_masters(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_all_command =>
_shift_all_command ??= new DelegateCommand(() => {
if (_col.model.type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_all(_col.model);
}
}, () => _col.model.type == VolSurfaceColumnType.ReadWriteTick);
public ICommand clear_command =>
_clear_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.clear(_col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_selection_command =>
_copy_to_selection_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_selection(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_masters_command =>
_copy_to_masters_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_masters(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_to_all_command =>
_copy_to_all_command ??= new DelegateCommand<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_all(expiration, _col.model, gc);
}
},
_has_editable_cells);
public ICommand copy_all_to_clipboard_command =>
_copy_all_to_clipboard_command ??= new DelegateCommand(() => {
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
_parent.visible_rows
.OfType<VolSurfaceRowContext>()
.Select(r => r.get_cell_clipboard_strings())
.Where(cells => cells != null));
if (!clipboard_text.is_null_or_empty()) {
ClipboardHelper.CopyTextToClipboard(clipboard_text);
}
});
public ICommand smart_copy_rolls_rates_command =>
_smart_copy_rolls_rates_command ??= new DelegateCommand(_ => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
public ICommand import_csv_command =>
_import_csv_command ??= FileDialogCommand.open_file(
_parent.model.import_csv_file,
() => _parent.model.csv_importing_enabled(),
null);
bool _has_editable_cells(string where) =>
!Enum.TryParse(where, out GridColumnSet gc) ||
gc == GridColumnSet.Column || _col.model.type != VolSurfaceColumnType.ReadOnly;
void _hide_symbol(string symbol) {
_parent.visible_rows.RemoveAll(s => ((VolSurfaceRowContext)s).expiration.symbol == symbol);
_parent.signal_selection_changed();
}
void _show_symbol(string symbol) {
// Insert items from rows to visible_Rows that have symbol=true in sorted order
// do this by making the desired collection and then leveraging sync_with
var visible = new HashSet<VolSurfaceDisplayGridExpiration>(_parent.visible_rows.Cast<VolSurfaceRowContext>().Select(row => row.expiration));
var desired = _parent.rows.Where(row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
_parent.visible_rows.sync_with(desired);
}
}
class CellData : IDisposable {
IDisposable _dispose;
VolGridCellVM _vm;
public CellData(VolGridCellVM vm, IDisposable dispose) {
_vm = vm;
_dispose = dispose;
}
public VolGridCellVM vm => _vm;
public void Dispose() {
Disposable.dispose(ref _vm);
Disposable.dispose(ref _dispose);
}
}
}
}
@@ -1,217 +0,0 @@
#nullable enable
namespace mbts.spark {
using bts.collections;
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using mbts.ui.utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Input;
class VolSurfaceRowContextMenuVM : DisposableViewModelBase {
readonly VolSurfaceRowVM _row;
readonly VolSurfaceGridVM _parent;
readonly Property<VolSurfaceColumn?> _column;
readonly Property<DIYGridSuperHeaderVM?> _super_header;
ICommand? _revert_cmd;
ICommand? _shift_selection_cmd;
ICommand? _shift_masters_cmd;
ICommand? _shift_all_cmd;
ICommand? _clear_cmd;
ICommand? _copy_to_selection_cmd;
ICommand? _copy_to_masters_cmd;
ICommand? _copy_to_all_cmd;
ICommand? _copy_all_to_clipboard_cmd;
ICommand? _smart_copy_rolls_rates_cmd;
ICommand? _import_csv_cmd;
public VolSurfaceRowContextMenuVM(VolSurfaceGridVM parent, VolSurfaceRowVM row) {
_parent = parent;
_row = row;
_column = backing<VolSurfaceColumn?>(nameof(column));
_super_header = backing<DIYGridSuperHeaderVM?>(nameof(super_header));
_dispose = Disposable.Create(
_column.invalidate_others_on_change(nameof(column_name)),
_super_header.invalidate_others_on_change(nameof(group_name)),
_parent.visible_rows.ObserveSelf()
.BufferLatest(TimeSpan.FromSeconds(1))
.OnDispatcher()
.Subscribe(_ => sync_symbols()));
void sync_symbols() {
var visible_exps = _parent.visible_rows.Map(r => r.expiration.symbol);
symbols.sync_with_models(
visible_exps,
kv => new SymbolItemVM(this, kv.Key),
(svm, kv) => {
svm.symbol = kv.Key;
svm.visible = SelectAllToggle.is_all_selected(
visible_exps[svm.symbol].Count(),
kv.Value.Count());
return svm;
});
}
}
public string column_name => column?.model?.display_name ?? string.Empty;
public string group_name => super_header?.id ?? string.Empty;
public string expiration_name => _row.ToString();
public VolSurfaceColumn? column {
get => _column.Value;
set => _column.set(value);
}
public DIYGridSuperHeaderVM? super_header {
get => _super_header.Value;
set => _super_header.set(value);
}
public VolSurfaceDisplayGridExpiration expiration => _row.expiration;
public ObservableCollection<SymbolItemVM> symbols { get; } = new();
public bool is_input_cell => column?.type == VolSurfaceColumnType.ReadWriteTick;
public ICommand main_settings_cmd => _parent.main_settings_cmd;
public ICommand advanced_settings_cmd => _parent.advanced_settings_cmd;
public ICommand grid_settings_cmd => _parent.grid_settings_cmd;
public ICommand graph_settings_cmd => _parent.graph_settings_cmd;
public ICommand revert_cmd =>
_revert_cmd ??= new Command(_ => {
_row.get_cell(_assert_model())?.revert();
});
public ICommand shift_selection_cmd =>
_shift_selection_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_selection(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_masters_cmd =>
_shift_masters_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_masters(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand shift_all_cmd =>
_shift_all_cmd ??= new Command(() => {
if (_assert_model().type == VolSurfaceColumnType.ReadWriteTick) {
_parent.shift_all(_assert_model());
}
}, () => _assert_model().type == VolSurfaceColumnType.ReadWriteTick);
public ICommand clear_cmd =>
_clear_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.clear(_assert_model(), gc);
}
},
_has_editable_cells);
public ICommand copy_to_selection_cmd =>
_copy_to_selection_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_selection(expiration, _assert_model(), gc);
}
});
public ICommand copy_to_masters_cmd =>
_copy_to_masters_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_masters(expiration, _assert_model(), gc);
}
});
public ICommand copy_to_all_cmd =>
_copy_to_all_cmd ??= new Command<string>(where => {
if (Enum.TryParse(where, out GridColumnSet gc)) {
_parent.copy_to_all(expiration, _assert_model(), gc);
}
});
public ICommand copy_all_to_clipboard_cmd =>
_copy_all_to_clipboard_cmd ??= new Command(() => {
string clipboard_text = ClipboardHelper.GetExcelFormattedText(
_parent.visible_rows
.OfType<VolSurfaceRowVM>()
.Select(r => r.get_cell_clipboard_strings())
.Where(cells => cells != null));
if (!clipboard_text.is_null_or_empty()) {
ClipboardHelper.CopyTextToClipboard(clipboard_text);
}
});
public ICommand smart_copy_rolls_rates_cmd =>
_smart_copy_rolls_rates_cmd ??= new Command(
() => _parent.model.sync_slave_ref_forwards(expiration.ToVSExp()));
public ICommand import_csv_cmd =>
_import_csv_cmd ??= FileDialogCommand.open_file(
_parent.model.import_csv_file,
_parent.model.csv_importing_enabled,
null);
VolSurfaceDisplayGridColumn _assert_model() =>
column?.model ?? throw new InvalidOperationException();
bool _has_editable_cells(string where) =>
!Enum.TryParse(where, out GridColumnSet gc) ||
gc == GridColumnSet.Column || _assert_model().type != VolSurfaceColumnType.ReadOnly;
void _hide_symbol(string symbol) {
_parent.visible_rows.RemoveAll(s => s.expiration.symbol == symbol);
_parent.signal_selection_changed();
}
void _show_symbol(string symbol) {
// Insert items from rows to visible_Rows that have symbol=true in sorted order
// do this by making the desired collection and then leveraging sync_with
var visible = _parent.visible_rows
.Select(row => row.expiration)
.ToHashSet();
var desired = _parent.rows.Where(
row => row.expiration.symbol == symbol || visible.Contains(row.expiration));
_parent.visible_rows.sync_with(desired);
}
public class SymbolItemVM : ViewModelBase {
readonly VolSurfaceRowContextMenuVM _context;
string _symbol;
bool? _visible;
public SymbolItemVM(
VolSurfaceRowContextMenuVM context, string symbol) {
_context = context;
_symbol = symbol;
}
public string symbol {
get => _symbol;
set => Set(ref _symbol, value);
}
public bool? visible {
get => _visible;
set {
if (Set(ref _visible, value)) {
if (value is true) {
_context._show_symbol(symbol);
} else if (value is false) {
_context._hide_symbol(symbol);
}
}
}
}
}
}
}
@@ -0,0 +1,372 @@
// using mbts;
// using mbts.ui;
// using mbts.ui.controls;
// using mbts.ui.dpi;
// using mbts.ui.utility.text;
// using System;
// using System.Collections.Generic;
// using System.Diagnostics;
// using System.Globalization;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
// using System.Windows;
// using System.Windows.Controls;
// using System.Windows.Input;
// using System.Windows.Media;
// namespace mbts.spark.VolSurface {
// class VolSurfaceRowControl : DIYGrid.HighPerformanceRow<VolSurfaceRowContext> {
// FormattedText _exp_text;
// readonly double _padding = 5.0;
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
// TickUpDown _cell_editor_backing;
// TickUpDown _cell_editor => _cell_editor_backing ??= new ();
// int? _selected_cell;
// public VolSurfaceRowControl() {
// Loaded += (s, e) => ContextMenu = TryFindResource("context_menu") as ContextMenu;
// GotKeyboardFocus += (s, e) => {
// if (e.OriginalSource is not FrameworkElement el) {
// return;
// }
// var cell_tl = el.TranslatePoint(new Point(0, 0), this);
// _on_focus_move(DIYGrid.RowUtils.column_at(_column_layout, cell_tl));
// };
// }
// int? _column_index(DIYGrid.ColumnGeometry col) =>
// _column_layout.TryGetFirst(c => c.Equals(col), out var _, out var idx) ? idx : null;
// //private static int _render_count = 0;
// protected override void OnRender(DrawingContext dc) {
// // Fill with transparent for hit testing
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_layout.Sum(c => c.width), RenderSize.Height));
// string last_group = "";
// foreach (var cell in _column_layout) {
// // Render collapsed columns
// if (cell.column.is_collapsed) {
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
// continue;
// }
// var column = (VolSurfaceSimplifiedColumn)cell.column;
// VolSurfaceCellState celldata;
// // Get the cell text
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
// // Fill in this one
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
// var exp = _row.expiration;
// if (_exp_text == null) {
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
// }
// celldata = new VolSurfaceCellState() {
// text = _exp_text
// };
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
// } else {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
// }
// // If the cell is partly hidden clip the draw
// if (cell.is_partially_obscured) {
// dc.PushClip(new RectangleGeometry(
// new Rect(cell.left, 0, cell.width, Height)));
// }
// // draw text centered vertially
// double total_width = _padding + celldata.text.Width;
// double pad_top = (Height - celldata.text.Height) / 2.0;
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
// if (celldata.committed_text != null) {
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
// total_width += celldata.committed_text.Width;
// }
// // draw grid lines
// double line_width; Brush fill;
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
// // draw dirty rect
// if (celldata.is_dirty) {
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
// }
// // Draw selection
// if (_selected_cell == _column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
// }
// if (cell.is_partially_obscured) { dc.Pop(); }
// total_width += _padding;//right padding
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
// if (total_width > cell.width) {
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
// }
// last_group = cell.group;
// }
// if (_selected_cell != NO_CELL) {
// if (_cell_editor.Visibility == Visibility.Visible) {
// var position = _column_geometry[_selected_cell];
// PositionControlOver(tud, position);
// }
// }
// //++_render_count;
// //dc.DrawText(
// // format_text(_render_count.ToString(), Brushes.Black),
// // new Point(0, 0));
// }
// Func<string, FormattedText> format(Brush brush) =>
// str => format_text(str, brush);
// void _on_focus_move(DIYGrid.ColumnGeometry? new_column) {
// if (new_column != null) {
// enable_edit(new_column.Value);
// }
// InvalidateVisual();
// }
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
// await Task.Yield();
// var col = (VolSurfaceSimplifiedColumn)column.column;
// var tud = _grid.get_edit_control<TickUpDown>();
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
// PositionControlOver(tud, column);
// var fe = tud.Content as TextBox;
// if (fe != null) {
// await Task.Yield();
// fe.Focus();
// fe.SelectAll();
// }
// } else {
// tud.DataContext = null;
// tud.Visibility = Visibility.Collapsed;
// var item = this.find_ancestor_of_type<ListBoxItem>();
// if (item != null) {
// item.Focus();
// }
// }
// }
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
// // _grid.column
// var cell = DIYGrid.RowUtils.column_at(_column_layout, e.GetPosition(this));
// if (ContextMenu != null) {
// if (cell.HasValue && DIYGrid.RowUtils.column_index(_column_layout, cell.Value) > (_grid.FrozenColumnCount - 1)) {
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
// } else {
// e.Handled = true;
// ContextMenu.DataContext = null;
// }
// }
// base.OnMouseRightButtonDown(e);
// }
// FormattedText format_text(string content, Brush fg) {
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
// return ft;
// }
// }
// }
// using mbts;
// using mbts.ui;
// using mbts.ui.controls;
// using mbts.ui.dpi;
// using mbts.ui.utility.text;
// using System;
// using System.Collections.Generic;
// using System.Diagnostics;
// using System.Globalization;
// using System.Linq;
// using System.Text;
// using System.Threading.Tasks;
// using System.Windows;
// using System.Windows.Controls;
// using System.Windows.Input;
// using System.Windows.Media;
// namespace mbts.spark.VolSurface {
// class VolSurfaceRowControl : DIYGrid.RowBase {
// VolSurfaceRowContext _row;
// FormattedText _exp_text;
// readonly double _padding = 5.0;
// readonly Pen _dirty_pen = new Pen(Brushes.Red, 1.0);
// readonly Pen _selection_pen = new Pen(Brushes.Black, 1.0) { DashStyle = DashStyles.Dot };
// public VolSurfaceRowControl() {
// DataContextChanged += OnDataContextChanged;
// Loaded += OnLoaded;
// }
// #region SelectedCell
// public static readonly DependencyProperty SelectedCellProperty =
// WPFHelper.create_dp<object, VolSurfaceRowControl>(nameof(SelectedCell));
// public object SelectedCell {
// get => GetValue(SelectedCellProperty);
// set => SetValue(SelectedCellProperty, value);
// }
// #endregion
// void OnLoaded(object sender, RoutedEventArgs e) {
// ContextMenu = TryFindResource("context_menu") as ContextMenu;
// }
// void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e) {
// var oldrow = e.OldValue as VolSurfaceRowContext;
// if (oldrow != null) {
// oldrow.on_invalidate -= InvalidateVisual;
// }
// _row = DataContext as VolSurfaceRowContext;
// _row.on_invalidate += InvalidateVisual;
// }
// //private static int _render_count = 0;
// protected override void OnRender(DrawingContext dc) {
// if (_grid == null) return;
// // Fill with transparent for hit testing
// dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0, 0, _column_geometry.Sum(g => g.width), RenderSize.Height));
// string last_group = "";
// foreach (var cell in _column_geometry) {
// // Render collapsed columns
// if (cell.column.is_collapsed) {
// dc.DrawRectangle(BTSColors.AW2.collapsed, null, new Rect(cell.left, 0, cell.width, Height));
// continue;
// }
// var column = (VolSurfaceSimplifiedColumn)cell.column;
// VolSurfaceCellState celldata;
// // Get the cell text
// if (column.type == VolSurfaceSimplifiedColumnType.RowHeader) {
// // Fill in this one
// dc.DrawRectangle(BTSColors.header, null, new Rect(cell.left, 0, cell.width, Height));
// var exp = _row.expiration;
// if (_exp_text == null) {
// _exp_text = format_text(exp.ToString(), exp.is_slave ? Brushes.LightGray : Brushes.White);
// }
// celldata = new VolSurfaceCellState() { text = _exp_text };
// } else if (column.type == VolSurfaceSimplifiedColumnType.ReadOnly) {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Blue), _ => null);
// } else {
// celldata = _row.get_value(column.volsurface_column, format(Brushes.Black), format(Brushes.DarkGray));
// }
// // If the cell is partly hidden clip the draw
// if (cell.is_partially_obscured) {
// dc.PushClip(new RectangleGeometry(
// new Rect(cell.left, 0, cell.width, Height)));
// }
// // draw text centered vertially
// double total_width = _padding + celldata.text.Width;
// double pad_top = (Height - celldata.text.Height) / 2.0;
// dc.DrawText(celldata.text, new Point(cell.unclipped_left + _padding, pad_top));
// if (celldata.committed_text != null) {
// pad_top = (Height - celldata.committed_text.Height) / 2.0;
// dc.DrawText(celldata.committed_text, new Point(cell.unclipped_left + total_width, pad_top));
// total_width += celldata.committed_text.Width;
// }
// // draw grid lines
// double line_width; Brush fill;
// if (last_group == cell.group) { line_width = 1; fill = _grid.VerticalGridLineBrush; } else { line_width = 2; fill = _grid.VerticalGroupSeparatorBrush; }
// dc.DrawRectangle(fill, null, new Rect(cell.left - line_width, 0, line_width, Height));
// Rect cell_border_rect = new Rect(cell.unclipped_left + 1, 0, Math.Max(0, cell.width - (line_width * 2)), Height - 1);
// // draw dirty rect
// if (celldata.is_dirty) {
// dc.DrawRectangle(null, _dirty_pen, cell_border_rect);
// }
// // Draw selection
// if (_selected_cell == column_index(cell) && column.type != VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// dc.DrawRectangle(null, _selection_pen, cell_border_rect);
// }
// if (cell.is_partially_obscured) { dc.Pop(); }
// total_width += _padding;//right padding
// if (!celldata.is_dirty && column.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) total_width += 22; // size of buttons on a tickupdown
// if (total_width > cell.width) {
// Dispatcher.BeginInvoke(((Action)(() => cell.column.Width = total_width)));
// }
// last_group = cell.group;
// }
// //++_render_count;
// //dc.DrawText(
// // format_text(_render_count.ToString(), Brushes.Black),
// // new Point(0, 0));
// }
// private Func<string, FormattedText> format(Brush brush) {
// return str => format_text(str, brush);
// }
// protected override void OnClick(DIYGrid.ColumnGeometry column) {
// }
// protected override void OnFocusMove(DIYGrid.ColumnGeometry? new_column) {
// if (new_column != null) enable_edit(new_column.Value);
// InvalidateVisual();
// }
// private async void enable_edit(DIYGrid.ColumnGeometry column) {
// await Task.Yield();
// var col = (VolSurfaceSimplifiedColumn)column.column;
// var tud = _grid.get_edit_control<TickUpDown>();
// if (col.type == VolSurfaceSimplifiedColumnType.ReadWriteTick) {
// tud.DataContext = _row.get_edit_context(col.volsurface_column);
// PositionControlOver(tud, column);
// var fe = tud.Content as TextBox;
// if (fe != null) {
// await Task.Yield();
// fe.Focus();
// fe.SelectAll();
// }
// } else {
// tud.DataContext = null;
// tud.Visibility = Visibility.Collapsed;
// var item = this.find_ancestor_of_type<ListBoxItem>();
// if (item != null) {
// item.Focus();
// }
// }
// }
// protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) {
// var cell = column_at(e.GetPosition(this));
// if (ContextMenu != null) {
// if (cell.HasValue && column_index(cell.Value) > (_grid.FrozenColumnCount - 1)) {
// ContextMenu.DataContext = _row.get_context_menu_context((VolSurfaceSimplifiedColumn)cell.Value.column, cell.Value.super_column);
// } else {
// e.Handled = true;
// ContextMenu.DataContext = null;
// }
// }
// base.OnMouseRightButtonDown(e);
// }
// FormattedText format_text(string content, Brush fg) {
// var ft = new FormattedText(content, CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
// TextUtils.StandardTypeface, FontSizes.Regular, Brushes.Black, HighDpiExtensions.dpi_ratio);
// return ft;
// }
// }
// }
@@ -1,137 +0,0 @@
#nullable enable
namespace mbts.spark.VolSurface {
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Windows.Media;
public struct VolSurfaceCellState {
public bool is_dirty => committed_text is not null;
public FormattedText? text;
public FormattedText? committed_text;
}
class VolSurfaceRowVM : DisposableViewModelBase, ISelectable, IFormatCellsToClipboard, DIYGrid.IRowVM {
readonly VolSurfaceGridVM _parent;
readonly VolSurfaceDisplayGridExpiration _exp;
readonly Dictionary<string, CellData> _cells = new();
VolSurfaceRowContextMenuVM? _context_menu;
bool _is_selected;
public VolSurfaceRowVM(VolSurfaceGridVM parent, VolSurfaceDisplayGridExpiration exp) {
_parent = parent;
_exp = exp;
_dispose = Disposable.Create(() => {
_cells.Values.DisposeAll();
_cells.Clear();
_context_menu?.Dispose();
});
}
public event Action<bool>? is_selected_changed;
public event Action? invalidated;
public VolSurfaceDisplayGridExpiration expiration => _exp;
public bool is_selected {
get => _is_selected;
set {
if (Set(ref _is_selected, value)) {
is_selected_changed?.Invoke(value);
_parent.signal_selection_changed();
}
}
}
public VolSurfaceRowContextMenuVM context_menu =>
_context_menu ??= new(_parent, this);
public VolGridCellVM get_cell(VolSurfaceDisplayGridColumn column) =>
_cells.GetOrAdd(column.unique_col_name, _ => _create_cell(column)).vm;
public void invalidate() {
foreach (var cell in _cells.Values) {
_sync_cell(cell.vm);
}
invalidated?.Invoke();
}
public string[] get_cell_clipboard_strings() =>
new[] { _exp.ToString() }.Concat(
_parent.columns.OfType<VolSurfaceColumn>().Skip(1).Select(c => {
var val = _parent.current_grid.read(_exp, c.model.unique_col_name);
return c.model.format(val);
}))
.ToArray();
public override string ToString() =>
_exp.ToString();
void DIYGrid.IRowVM.raise_invalidated() =>
invalidated?.Invoke();
CellData _create_cell(VolSurfaceDisplayGridColumn column) {
var cell = column.type switch {
VolSurfaceColumnType.ReadWriteTick => create_tick_cell(),
_ => new VolGridCellVM(column.unique_col_name),
};
_sync_cell(cell);
var dispose = cell.observe_candidate().DistinctUntilChanged().OnDispatcher()
.Subscribe(value => {
var curr = _parent.current_grid.read(expiration, column);
if (Equals(value, curr)) {
return;
}
var grid = _parent.current_grid;
grid.write(expiration, column, value);
_parent.model.set_candidate_grid(grid);
});
return new(cell, dispose);
VolGridTickCellVM create_tick_cell() {
var cell = new VolGridTickCellVM(column.unique_col_name);
cell.request_tick += is_up => {
var col = _parent.get_column(column.unique_col_name);
if (col is null) {
throw new InvalidOperationException(
$"Failed to find column with id {column.unique_col_name}");
}
if (col.model?.tick_move is var tm) {
cell.candidate_value = tm?.Invoke(cell.candidate_value, is_up);
return;
}
throw new InvalidOperationException($"tick_move is not defined");
};
return cell;
}
}
void _sync_cell(VolGridCellVM cell) {
if (cell is null) {
return;
}
cell.committed_value = _parent.committed_grid.read(_exp, cell.column_id);
cell.candidate_value = _parent.current_grid.read(_exp, cell.column_id);
}
class CellData : IDisposable {
IDisposable _dispose;
public CellData(VolGridCellVM vm, IDisposable dispose) {
this.vm = vm;
_dispose = Disposable.Create(vm, dispose);
}
public VolGridCellVM vm { get; }
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
}
@@ -3,8 +3,6 @@ using mbts.ui;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -23,7 +21,7 @@ namespace mbts.spark {
if (_settings.precomputed_theo_handles == null)
_settings.precomputed_theo_handles = new List<double>();
vol_surface_name = vs_name;
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtobufSerializationHelper.clone(_settings)));
this.commit = new DelegateCommand(() => request_commit?.Invoke(ProtoBufSerializationHelper.clone_protobuf(_settings)));
}
public event Action<VolSurfaceAdvancedSettings> request_commit;
@@ -9,8 +9,6 @@ namespace mbts.spark {
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -25,9 +23,6 @@ namespace mbts.spark {
readonly VolSurfaceSettings _settings;
readonly VolSurfaceCoreSettings _core_settings;
string _selected_section;
bool _can_edit_name = true;
public VolSurfaceSettingsEditorVM(IBus bus, VolSurfaceSettings settings, Action<VolSurfaceSettings> commit) {
if (settings is null) {
throw new ArgumentNullException(nameof(settings));
@@ -118,23 +113,7 @@ namespace mbts.spark {
}
}
public string vol_surface_name {
get => _core_settings.vol_surface_name;
set {
using var _ = detect_property_change();
_core_settings.vol_surface_name = value;
}
}
public bool can_edit_name {
get => _can_edit_name;
set => Set(ref _can_edit_name, value);
}
public string selected_section {
get => _selected_section;
set => Set(ref _selected_section, value);
}
public string vol_surface_name { get { return _core_settings.vol_surface_name; } }
public VSSymbolStructureVM symbol_structure_vm { get; set; }
public VolModelPolynomialVM vol_model_polynomial_vm { get; } = new();
@@ -374,7 +353,7 @@ namespace mbts.spark {
public ICommand commit { get; }
public VolSurfaceSettings get_settings() {
var rv = ProtobufSerializationHelper.clone(_settings);
var rv = ProtoBufSerializationHelper.clone_protobuf(_settings);
var symbols = symbol_structure_vm.driver_grids
.SelectMany(dg => dg.symbols.Where(sym => sym.is_selected))
.ToList();
@@ -543,16 +522,11 @@ namespace mbts.spark {
}
public class VSSymbolStructureVM : DisposableViewModelBase {
readonly Property<VSSymbolGridVM> _selected_driver_grid;
public VSSymbolStructureVM(IBus bus, VolSurfaceSettings settings) {
driver_grids = new ObservableCollection<VSSymbolGridVM>();
_selected_driver_grid = backing<VSSymbolGridVM>(nameof(selected_driver_grid));
settings.core_settings.master_slave_relationships ??= new List<VolSurfaceSymbolRelationship>();
settings.core_settings.implied_vol_marketdata_relationships ??= new List<VolSurfaceSymbolRelationship>();
_dispose = new DisposableCombo(
driver_grids.Subscribe((s, e) =>
selected_driver_grid ??= driver_grids.FirstOrDefault()),
bus.subscribe(SparkTags.ExpirationParametersInputTag).OnDispatcher().Subscribe(on_exp_params_input)) +
new Action(() => Disposable.dispose(driver_grids));
@@ -612,10 +586,6 @@ namespace mbts.spark {
public IReadOnlyList<VolSurfaceEnums.VolSurfacePricingModel> pricing_models => EnumHelper.get_values<VolSurfaceEnums.VolSurfacePricingModel>();
public ObservableCollection<VSSymbolGridVM> driver_grids { get; private set; }
public VSSymbolGridVM selected_driver_grid {
get => _selected_driver_grid.Value;
set => _selected_driver_grid.set(value);
}
}
public class RotationVM : ViewModelBase, IEquatable<RotationVM> {
@@ -1,15 +1,14 @@
namespace mbts.spark {
using bts;
using bts.utils;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core.Reflection;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
class VolSurfaceMacroActionsVM : ViewModelBase {
readonly VolSurfaceDisplayModel _model;
@@ -77,7 +76,7 @@
public IRaiseCanExecuteChangedCommand vol_shift { get; }
IEnumerable<IRaiseCanExecuteChangedCommand> _commands =>
ReflectionHelper.property_delegates_of_type<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
ObjectSnapshot.property_delegates_of_type<VolSurfaceMacroActionsVM, IRaiseCanExecuteChangedCommand>()
.Select(g => g(this));
public void selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selected) {
@@ -7,8 +7,6 @@
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+93 -126
View File
@@ -1,5 +1,5 @@
#nullable enable
namespace mbts.spark {
using bts;
using bts.api;
using bts.collections;
@@ -8,105 +8,48 @@ namespace mbts.spark {
using mbts.spark.VolSurface;
using mbts.ui;
using mbts.ui.controls;
using mbts.ui.settings;
using mbts.ui.shell;
using Spark.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
class VolSurfaceVM : DisposableViewModelBase {
class VolSurfaceVM : ViewModelBase, IDisposable {
readonly int _vs_id;
readonly IBus _bus;
readonly string _request_id = Guid.NewGuid().ToString();
readonly VolSurfaceDisplayModel _model;
readonly IRaiseCanExecuteChangedCommand _revert_cmd;
readonly IRaiseCanExecuteChangedCommand _commit_cmd;
readonly IDialogCommand _main_settings_cmd;
readonly IDialogCommand _advanced_settings_cmd;
readonly IDialogCommand _grid_settings_cmd;
string? _selected_state = string.Empty;
VolSurfaceDisplayModel _model;
VolSurfaceMacroGridSettings _grid_settings;
bool _ignore_implied_vol_settings;
public VolSurfaceVM(
VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
public VolSurfaceVM(VolSurfaceDisplayModel model, int id, IBus bus, VolSurfaceWindowSettings startup_data) {
Log.notnull(startup_data);
_model = model;
var demux = new VolSurfaceEventDemux(model);
_vs_id = id;
_bus = bus;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
// grid
_grid_settings = startup_data.macro_grid_settings ?? new VolSurfaceMacroGridSettings();
var hidden_exps_set = startup_data.hidden_exps.empty_if_null().ToHashSet();
grid = new VolSurfaceGridVM(
this, _model, _grid_settings.hidden_cols(), hidden_exps_set);
grid.on_selection_changed += _on_grid_selection_changed;
_model.publish_grid_settings(_grid_settings);
// graphs
var demux = new VolSurfaceEventDemux(model);
vol_curve_vm = new VolSurfaceGraphVM(
_model, demux, startup_data, (show_ivol, exp) =>
_model.publish_new_grid_selection(_request_id, exp, show_ivol));
_model, demux, startup_data, (show_ivol, exp) => _model.publish_new_grid_selection(_request_id, exp, show_ivol));
vol_terms_vm = new VolTermsGraphVM(_model, demux);
// command
_revert_cmd = new Command(o => _model.revert(), o => _model.is_dirty);
_commit_cmd = new Command(o => _model.commit(), o => _model.is_dirty);
load_previous_cmd = new Command(
load_previous, () => !selected_previous_state.is_null_or_empty());
_main_settings_cmd = new DialogCommand(mk_main_settings_win);
_advanced_settings_cmd = new DialogCommand(mk_advanced_settings_win);
_grid_settings_cmd = new DialogCommand(mk_grid_settings_win);
_model.on_dirty_change += () => {
RaisePropertyChanged(nameof(is_dirty));
_revert_cmd.RaiseCanExecuteChanged();
_commit_cmd.RaiseCanExecuteChanged();
};
demux.on_candidate_grid_change += () =>
previous_states.sync_with(_model.get_previous_states());
demux.on_schema_change += () => {
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
_grid_settings.set_columns(
model.get_active_grid()
.get_ordered_columns()
.Select(col => existing_cols.GetValueOrDefault(col.unique_col_name) ??
VolSurfaceColumnSettings.from_column_model(col)));
};
_dispose = Disposable.Create(
vol_curve_vm,
vol_terms_vm,
globals,
Disposable.Create(() => grid?.Dispose()),
_main_settings_cmd,
_advanced_settings_cmd,
_grid_settings_cmd,
_model);
Window? mk_main_settings_win() {
revert_command = new DelegateCommand(o => _model.revert(), o => _model.is_dirty);
commit_command = new DelegateCommand(o => _model.commit(), o => _model.is_dirty);
load_previous_command = new DelegateCommand(_ => { var cur = selected_previous_state; selected_previous_state = null; _model.load_previous_state(cur); }, _ => !string.IsNullOrEmpty(selected_previous_state));
main_settings_command = new DialogCommand(() => {
var settings = _model.get_active_settings();
if (settings is null) {
if (settings == null) {
return null;
}
return new VolSurfaceSettingsEditor {
DataContext = new VolSurfaceSettingsEditorVM(
_bus, settings, _model.set_candidate_settings) {
can_edit_name = false
}
};
}
Window? mk_advanced_settings_win() {
return new VolSurfaceSettingsEditor { DataContext = new VolSurfaceSettingsEditorVM(_bus, settings, _model.set_candidate_settings) };
});
advanced_settings_command = new DialogCommand(() => {
var settings = _model.get_active_settings();
if (settings == null) {
return null;
@@ -126,71 +69,76 @@ namespace mbts.spark {
// )
// };
return null;
}
Window? mk_grid_settings_win() {
});
grid_settings_command = new DialogCommand(() => {
var settings = _model.get_active_settings();
if (settings is null) {
if (settings == null) {
return null;
}
var vm = new VolSurfaceGridSettingsEditorVM(
settings.core_settings.vol_surface_name, _grid_settings.Clone());
var vm = new VolSurfaceGridSettingsEditorVM(settings.core_settings.vol_surface_name, _grid_settings.Clone());
vm.request_commit += on_grid_settings;
return new VolSurfaceGridSettingsEditor {
DataContext = vm
};
});
_model.on_dirty_change += raise_dirty_changed;
macro_actions = new VolSurfaceMacroActionsVM(_model);
globals = new VolSurfaceGlobalParameterVM(_model);
demux.on_candidate_grid_change += () => previous_states.sync_with(_model.get_previous_states());
demux.on_schema_change += () => {
// _grid_settings.clear_columns();
var existing_cols = _grid_settings.column_settings.ToDictionary(c => c.id);
_grid_settings.set_columns(
model.get_active_grid()
.get_ordered_columns()
.Select(col => {
if (!existing_cols.TryGetValue(col.unique_col_name, out var rv)) {
rv = VolSurfaceColumnSettings.from_column_model(col);
}
return rv;
}));
};
grid = new VolSurfaceGridVM(this, _model, _grid_settings.hidden_cols(), new HashSet<VolSurfaceExpiration>(startup_data.hidden_exps ?? Enumerable.Empty<VolSurfaceExpiration>()));
grid.on_selection_changed += _on_grid_selection_changed;
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
using var _ = grid.defer_invalidate_rows();
_grid_settings = new_settings;
grid.load_from(_grid_settings);
grid.invalidate_rows();
_model.publish_grid_settings(_grid_settings);
}
}
void load_previous() {
var cur = selected_previous_state;
selected_previous_state = null;
_model.load_previous_state(cur);
void on_grid_settings(VolSurfaceMacroGridSettings new_settings) {
using var _ = grid.defer_invalidate_rows();
_grid_settings = new_settings;
grid.load_from(_grid_settings);
grid.invalidate_rows();
_model.publish_grid_settings(_grid_settings);
}
}
public VolSurfaceGridVM grid { get; }
public VolSurfaceGraphVM vol_curve_vm { get; }
public VolTermsGraphVM vol_terms_vm { get; }
public VolSurfaceMacroActionsVM macro_actions { get; }
public VolSurfaceGlobalParameterVM globals { get; }
public VolSurfaceGridVM grid { get; private set; }
public VolSurfaceGraphVM vol_curve_vm { get; private set; }
public VolTermsGraphVM vol_terms_vm { get; private set; }
public VolSurfaceMacroActionsVM macro_actions { get; private set; }
public VolSurfaceGlobalParameterVM globals { get; private set; }
public bool ignore_implied_vol_settings {
get => _ignore_implied_vol_settings;
set {
if (Set(ref _ignore_implied_vol_settings, value)) {
_model.publish_ignore_implied_vol_settings(_request_id, value);
}
}
}
private bool _ignore_implied_vol_settings;
public bool ignore_implied_vol_settings { get { return _ignore_implied_vol_settings; } set { _model.publish_ignore_implied_vol_settings(_request_id, _ignore_implied_vol_settings = value); } }
public bool is_dirty { get { return _model.is_dirty; } }
public IRaiseCanExecuteChangedCommand revert_command { get; private set; }
public IRaiseCanExecuteChangedCommand commit_command { get; private set; }
public IDialogCommand main_settings_command { get; private set; }
public IDialogCommand advanced_settings_command { get; private set; }
public IDialogCommand grid_settings_command { get; private set; }
public ICommand details_command => new DelegateCommand(_ => _show_details());
public ICommand load_previous_command { get; private set; }
public ObservableCollection<string> previous_states { get; } = new();
public string? selected_previous_state {
get => _selected_state;
private string _selected_state = string.Empty;
public string selected_previous_state {
get { return _selected_state; }
set {
if (Set(ref _selected_state, value)) {
load_previous_cmd.TryRaiseCanExecuteChanged();
}
_selected_state = value;
load_previous_command.TryRaiseCanExecuteChanged();
RaisePropertyChanged();
}
}
public bool is_dirty => _model.is_dirty;
public ICommand revert_cmd => _revert_cmd;
public ICommand commit_cmd => _commit_cmd;
public ICommand main_settings_cmd => _main_settings_cmd;
public ICommand advanced_settings_cmd => _advanced_settings_cmd;
public ICommand grid_settings_cmd => _grid_settings_cmd;
public ICommand details_command => new Command(_show_details);
public ICommand load_previous_cmd { get; }
public VolSurfaceWindowSettings get_startup_data() {
var rv = new VolSurfaceWindowSettings {
id = _vs_id,
@@ -204,20 +152,39 @@ namespace mbts.spark {
return rv;
}
public void Dispose() {
vol_curve_vm.Dispose();
vol_terms_vm.Dispose();
globals.Dispose();
if (grid != null) grid.Dispose();
main_settings_command.Dispose();
advanced_settings_command.Dispose();
grid_settings_command.Dispose();
Disposable.dispose(ref _model);
}
void raise_dirty_changed() {
RaisePropertyChanged("is_dirty");
revert_command.RaiseCanExecuteChanged();
commit_command.RaiseCanExecuteChanged();
}
void _on_grid_selection_changed(IEnumerable<VolSurfaceDisplayGridExpiration> selection) {
if (selection.TryGetFirst(out var selected)) {
var selected = selection.FirstOrDefault();
if (selected != null) {
vol_curve_vm.set_visible_expiration(selected);
_model.publish_new_grid_selection(_request_id, selected, vol_curve_vm.show_implied_vol);
}
macro_actions.selection_changed(selection);
}
void _show_details() =>
_model.show_details();
async Task<VolSurfaceSettings?> _get_volsurface_settings() =>
async Task<VolSurfaceSettings> _get_volsurface_settings() =>
(await _bus.subscribe(SparkTags.VolSurfaceCommittedOutputTag(_vs_id)).FirstOrDefaultAsync())
?.volsurface_input
?.surface_settings;
void _show_details() =>
_model.show_details();
}
}
@@ -1,21 +1,19 @@
namespace mbts.spark {
using bts.api;
using bts.collections;
using bts.api;
using bts.utils;
using mbts.analytics;
using mbts.collections;
using mbts.ui;
using mbts.ui.shell;
using mbts.analytics;
using mbts.collections;
using mbts.ui;
using mbts.ui.shell;
using Spark.Core;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Media;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Media;
namespace mbts.spark {
class VolTermsGraphVM : DisposableViewModelBase {
readonly VolSurfaceDisplayModel _model;
readonly DateTimeAxisVM _exp_terms_x_axis;
@@ -5,8 +5,6 @@
using mbts.analytics;
using mbts.ui.controls;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -298,7 +296,7 @@
bool succ = false;
VolSurfaceInputSnapshot vs_sn = _input_snapshot_list.ToList().Find(v => v.save_marker == state_name);
if (vs_sn != null) {
var vs_inp = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(vs_sn.data);
VolSurfaceInput vs_inp = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(vs_sn.data);
if (vs_inp != null) {
_change_state(DisplayModelState.WaitingForCalcResponse);
_bus.post(SparkTags.VolSurfaceCalculationRequestTag(_vs_id),
@@ -321,7 +319,7 @@
public byte[] get_current_state() {
DisplayModelData curr_data = _get_current_data();
if (curr_data != null && curr_data.vs_output != null && curr_data.vs_output.volsurface_input != null)
return ProtobufSerializationHelper.serialize(curr_data.vs_output.volsurface_input);
return VolSurfaceUtilityFunctions.serialize_proto(curr_data.vs_output.volsurface_input);
else
return null;
}
@@ -329,7 +327,7 @@
/// Sets the state that is passed in bytes form. Returns
/// true is state is set successfully
public bool set_state(byte[] file_data) {
var vs_input = ProtobufSerializationHelper.deserialize<VolSurfaceInput>(file_data);
VolSurfaceInput vs_input = VolSurfaceUtilityFunctions.deserialize_proto<VolSurfaceInput>(file_data);
if (vs_input != null) {
if (_state == DisplayModelState.Idle || _state == DisplayModelState.ResponseReady) {
_change_state(DisplayModelState.WaitingForCalcResponse);
+3 -94
View File
@@ -1,4 +1,4 @@
namespace mbts.spark {
namespace mbts.spark {
using bts.api;
using bts.api.analytics;
using bts.utils;
@@ -34,9 +34,6 @@ namespace mbts.spark {
public static HashSet<string> hidden_cols(this VolSurfaceMacroGridSettings gs) =>
new(gs.column_settings.Where(cc => !cc.is_visible).Select(cc => cc.id));
public static bool is_editable(this VolSurfaceColumnType vs_col_type) =>
vs_col_type is VolSurfaceColumnType.ReadWriteTick;
public static analytics.VolSurfaceExpiration ToVSExp(this VolSurfaceDisplayGridExpiration vsdge) =>
new() { expiration = vsdge.expiration, symbol = vsdge.symbol };
@@ -83,10 +80,10 @@ namespace mbts.spark {
_ => false,
};
public static IEnumerable<VolSurfaceExpiration> select_exp(this IEnumerable<VolSurfaceRowVM> rows) =>
public static IEnumerable<VolSurfaceExpiration> select_exp(this IEnumerable<VolSurfaceRowContext> rows) =>
rows.Select(r => r.expiration.ToVSExp());
public static IEnumerable<VolSurfaceDisplayGridExpiration> select_display_exp(this IEnumerable<VolSurfaceRowVM> rows) =>
public static IEnumerable<VolSurfaceDisplayGridExpiration> select_display_exp(this IEnumerable<VolSurfaceRowContext> rows) =>
rows.Select(r => r.expiration);
public static IEnumerable<VolSurfaceDisplayGridExpiration> where_master(this IEnumerable<VolSurfaceDisplayGridExpiration> rows) =>
@@ -116,94 +113,6 @@ namespace mbts.spark {
public static IEnumerable<(double x, double y)> real_all_points(this VolCurveDisplayGraph graph) =>
_select_real_points(graph.all_points);
public static bool is_delta_greek(this VolSurfaceGreeks g) =>
g switch {
VolSurfaceGreeks.Delta or
VolSurfaceGreeks.Bsmdelta or
VolSurfaceGreeks.FlatVolDelta or
VolSurfaceGreeks.ExpirationDelta or
VolSurfaceGreeks.Charm or
VolSurfaceGreeks.Vanna => true,
_ => false,
};
public static bool is_gamma_greek(this VolSurfaceGreeks g) =>
g switch {
VolSurfaceGreeks.Gamma or
VolSurfaceGreeks.Bsmgamma => true,
_ => false
};
public static bool is_oev_col(this VolSurfaceGreeks g) =>
g switch {
VolSurfaceGreeks.Oev or
VolSurfaceGreeks.Bsmoev => true,
_ => false
};
public static VolSurfaceExpiration to_vs_exp(this SecurityExpiration sec_exp) =>
new() { security_type = sec_exp.security_type, symbol = sec_exp.symbol, expiration = sec_exp.expiration };
public static DriverCalculationType to_driver_calc_type(
this ExpirationDriver.ModeOneofCase driver_mode) =>
driver_mode switch {
ExpirationDriver.ModeOneofCase.Security => DriverCalculationType.Direct,
ExpirationDriver.ModeOneofCase.TimeWeightedInterpolated => DriverCalculationType.TimeWeightedInterp,
_ => throw new NotImplementedException()
};
public static SecurityExpiration to_sec_exp(
this bts.api.domain.SecurityExpiration api_sec_exp) =>
to_sec_exp(new bts.api.domain.SecurityExpirationImmutable(api_sec_exp));
public static SecurityExpiration to_sec_exp(
this bts.api.domain.SecurityExpirationImmutable api_sec_exp) =>
new(
api_sec_exp.Exchange.to_venue(),
api_sec_exp.SecurityType.contract_case(),
api_sec_exp.Symbol,
api_sec_exp.Expiration.date_time());
public static SecurityExpiration to_sec_exp(this Security sec) =>
to_sec_exp(new SecurityImmutable(sec));
public static SecurityExpiration to_sec_exp(this SecurityImmutable sec) {
var exp_date = sec.security_expiration() ?? throw new InvalidOperationException();
return new(sec.Exchange, sec.ContractCase, sec.Symbol, exp_date, sec.Id);
}
public static ExpirationDriver to_exp_driver(this SecurityExpiration sec_exp) =>
new() {
Security = new() {
Symbol = sec_exp.symbol,
Expiration = new() {
ExpirationDay = (uint)sec_exp.expiration.Day,
ExpirationMonth = (uint)sec_exp.expiration.Month,
ExpirationYear = (uint)sec_exp.expiration.Year,
},
Exchange = sec_exp.exchange.to_api_venue(),
}
};
public static ExpirationDriverImmutable to_exp_driveri(this SecurityExpiration sec_exp) =>
new(to_exp_driver(sec_exp));
public static bts.api.domain.SecurityExpiration to_api_sec_exp(this SecurityExpiration sec_exp) =>
new() {
Exchange = sec_exp.exchange.to_api_venue(),
SecurityType = sec_exp.security_type,
Symbol = sec_exp.symbol,
Expiration = new() {
ExpirationDay = (uint)sec_exp.expiration.Day,
ExpirationMonth = (uint)sec_exp.expiration.Month,
ExpirationYear = (uint)sec_exp.expiration.Year
}
};
public static bts.api.domain.SecurityExpirationImmutable to_api_sec_expi(
this SecurityExpiration sec_exp) =>
new(to_api_sec_exp(sec_exp));
static IEnumerable<(double x, double y)> _select_real_points(IEnumerable<Tuple<double, double>> points) =>
points.Where(pt => pt.Item1.is_real() && pt.Item2.is_real()).Select(t => (t.Item1, t.Item2));
}
+5 -6
View File
@@ -24,14 +24,13 @@ Value: OptionDriverPriceMap which is a wrapper around
IDictionary<SecurityExpiration, Tuple<Security, VolSurfaceBBOUnit>>
----------------------------------------------------------------
SingleVolSurfaceInterpGreeksPublisher (for one vs) listens to all inputs and publishes
IDictionary<VolSurfaceExpiration, IEnumerable<Theos>>
SingleVolSurfaceInterpGreeksPublisher listens to all inputs and publishes
exp vs InterpGreeks
VolSurfaceInterpGreeksMultiplexer (for multiple option symbols) listens to all vol
surfaces, resolves symbols and for each option_symbol publishes
OptionTheoInterpolationData*
VolSurfaceInterpGreeksMultiplexer listens to all vol surfaces, resolves symbols and
publishes symbol vs InterpGreeks
SymbolAggregationPublisher is a thin generic class that combines individual symbol data and
SymbolAggregationPublisher is a thin class that combines individual symbol data and
publishes symbol vs data map
LiveTheoPublisher:
+4 -10
View File
@@ -1,8 +1,6 @@
using bts;
using bts.api;
using bts.api.admin;
using bts.api.core;
using bts.collections;
using bts.utils;
using System;
@@ -20,10 +18,10 @@ namespace mbts.spark {
IReadOnlyDictionary<uint, string> _account_map = DictionaryHelper.empty<uint, string>();
[ImportingConstructor]
public AdminModel(IBus bus, AdminService service, Lazy<UserTuple> user)
: this(bus, service, user.Value) { }
public AdminModel(AdminService service, Lazy<UserTuple> user)
: this(service, user.Value) { }
AdminModel(IBus bus, AdminService service, UserTuple user) {
AdminModel(AdminService service, UserTuple user) {
this.user = user;
// accounts
on_accounts = service.subscribei_admin_data()
@@ -50,11 +48,7 @@ namespace mbts.spark {
.Table(UserTuple.key_fn)
.Cache() :
Observable.Return(TableUpdate<UserTuple, uint>.mk_empty(UserTuple.key_fn).with_added(new[] { user }));
_dispose = on_accounts.Subscribe(map => {
_account_map = map;
var account_tuple_map = MappedDictionary.create(map, (id, name) => new AccountTuple(id, name));
bus.post(SparkTags.AccountsTag, account_tuple_map);
});
_dispose = on_accounts.Subscribe(map => _account_map = map);
}
public IObservable<IReadOnlyDictionary<uint, string>> on_users { get; }
@@ -44,7 +44,7 @@ namespace mbts.spark {
new SecurityAlgoTypeSetImmutable(
new SecurityCriteriaClause(
exchanges: new[] { Venue.Glbx },
security_types: new[] { SecurityType.Future, SecurityType.Spread, SecurityType.Option }),
security_types: new[] { SecurityType.Future, SecurityType.Spread }),
new AlgoTypeSetImmutable(
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader }),
full_algo_set.dynamic_types)),
@@ -52,7 +52,7 @@ namespace mbts.spark {
new SecurityAlgoTypeSetImmutable(
new SecurityCriteriaClause(
exchanges: EnumHelper.get_values_except(Venue.Glbx, Venue.Unset).ToArray(),
security_types: new[] { SecurityType.Future, SecurityType.Spread, SecurityType.Option }),
security_types: new[] { SecurityType.Future, SecurityType.Spread }),
new AlgoTypeSetImmutable(
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader, AlgoType.GlbxIceberg }),
full_algo_set.dynamic_types)),
+2 -2
View File
@@ -82,7 +82,7 @@ namespace mbts.spark {
this AlgoTypeSetImmutable algo_set,
DynamicOrderHelper dynamic_helper,
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
double display_qty_divisor = 1) =>
uint display_qty_divisor = 1) =>
//
algo_set.factory_types
.Select(algo_type => {
@@ -109,7 +109,7 @@ namespace mbts.spark {
SecurityCriteriaClause clause,
DynamicOrderHelper dynamic_helper,
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
double display_qty_divisor = 1) {
uint display_qty_divisor = 1) {
//
ImmutableDictionary<AlgoKey, AlgoData> rv = null;
foreach (var set in security_algo_sets) {
+21 -27
View File
@@ -1,5 +1,4 @@
using bts;
using bts.api;
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.utils;
@@ -51,7 +50,9 @@ namespace mbts.spark {
/// <see cref="subscribe_algos"/>,
/// <see cref="subscribe_algos(SecurityCriteriaClause)"/>,
/// <see cref="subscribe_algos(SecurityImmutable)"/>
_studio_algos_source = studio_model.definitions.Cache();
_studio_algos_source = studio_model.definitions
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.Cache();
}
public AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security) =>
@@ -66,11 +67,10 @@ namespace mbts.spark {
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos() =>
_studio_algos_source
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.AppendTable(_security_algo_types
.Select(s => s.algo_type_set)
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
.define_algos(_dynamic_helper));
.AppendTable(_security_algo_types
.Select(s => s.algo_type_set)
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
.define_algos(_dynamic_helper));
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityCriteriaClause security_clause) {
var system_algos = _security_algo_types.match_algos(
@@ -78,13 +78,11 @@ namespace mbts.spark {
_dynamic_helper,
def => _fit_to_type(def, security_clause, _security_algo_types));
return _studio_algos_source
.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.AppendTable(system_algos.Values);
return _studio_algos_source.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
.AppendTable(system_algos.Values);
}
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityImmutable security) {
@@ -98,18 +96,14 @@ namespace mbts.spark {
def => _fit_to_type(def, security, _security_algo_types),
_security_auxiliary_model.get_display_quantity_divisor(security));
var filtered_studio_algos = _studio_algos_source
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security, _security_algo_types)),
tup => tup.algo.key)
// filter out algos that use an unsupported root, because this would have the effect of duplicating the default algo
// (e.g., GlbxIceberg orders would be converted to Limit/Spreader orders for non-Glbx securities).
.Filter(tup => tup.fitted_def.actual().CustomCase == tup.algo.value.actual().CustomCase, tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), AlgoData.key_fn);
return filtered_studio_algos
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
.AppendTable(system_algos.Values);
return _studio_algos_source.Select(
a => (algo: a, fitted_def: _fit_to_type(a.value, security, _security_algo_types)),
tup => tup.algo.key)
// filter out algos that use an unsupported root, because this would have the effect of duplicating the default algo
// (e.g., GlbxIceberg orders would be converted to Limit/Spreader orders for non-Glbx securities).
.Filter(tup => tup.fitted_def.actual().CustomCase == tup.algo.value.actual().CustomCase, tup => tup.algo.key)
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), AlgoData.key_fn)
.AppendTable(system_algos.Values);
}
protected virtual void assign_fallback_algo(CustomOrderDefinition mdef, SecurityCriteriaClause security_clause) {
@@ -1,7 +1,7 @@
namespace mbts.analytics {
using bts;
using Spark.Core.Protobuf;
using mbts.ui.shell;
using System;
using System.Collections.Generic;
@@ -40,7 +40,7 @@
new Dictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData>());
public VolSurfaceOutput Clone() => new(
ProtobufSerializationHelper.clone(volsurface_input),
ProtoBufSerializationHelper.clone_protobuf(volsurface_input),
new Dictionary<VolSurfaceExpiration, VolCurveOutput>(exp_output_map),
new Dictionary<VolSurfaceExpiration, VolSurfaceExpirationAuxiliaryData>(aux_data_map));
@@ -1,194 +1,112 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using bts.api;
using bts.settings;
using bts.spark;
using mbts.spark;
namespace mbts {
using bts.api;
using bts.utils;
using mbts.ui.utility;
using mbts.utils;
using ProtoBuf;
using Spark.Core.Collections;
using Spark.Core.Protobuf;
using System;
using System.Collections.Generic;
using System.Linq;
[ProtoContract]
[ProtoBuf.ProtoContract()]
[Serializable]
public class SecurityExpiration : IProtobuf<SecurityExpiration> {
public readonly static SecurityExpiration empty = new(
SecurityTuple.empty.security_exchange,
SecurityTuple.empty.security_type,
SecurityTuple.empty.security_name,
DateTime.MinValue);
public class SecurityExpiration : IEquatable<SecurityExpiration> {
[ProtoBuf.ProtoMember(1)]
private readonly SecurityTuple _sec_tup;
[ProtoBuf.ProtoMember(2)]
public readonly DateTime expiration;
[ProtoBuf.ProtoMember(2)]
private readonly Nullable<uint> _id;
public readonly static SecurityExpiration empty = new SecurityExpiration(SecurityTuple.empty.security_exchange, SecurityTuple.empty.security_type, SecurityTuple.empty.security_name, DateTime.MinValue);
// for deserialization
SecurityExpiration() =>
security_tuple = SecurityTuple.empty;
// for ProtoBuf deserialization
private SecurityExpiration() { }
public SecurityExpiration(
Venue exchange,
Security.ContractOneofCase type,
string symbol,
DateTime exp,
uint? id = null)
public SecurityExpiration(Venue exchange, Security.ContractOneofCase type, string symbol, DateTime exp, Nullable<uint> id = null)
: this(exchange, type.security_type(), symbol, exp, id) { }
public SecurityExpiration(
Venue exchange, SecurityType type, string symbol, DateTime expiration, uint? id = null)
: this(new SecurityTuple(type, symbol, exchange), expiration, id) { }
public SecurityExpiration(Venue exchange, SecurityType type, string symbol, DateTime exp, Nullable<uint> id = null)
: this(new SecurityTuple(type, symbol, exchange), exp, id) { }
public SecurityExpiration(
SecurityTuple security_tuple, DateTime expiration, uint? id = null) {
this.security_tuple = security_tuple;
this.expiration = expiration;
this.id = id;
public SecurityExpiration(SecurityTuple sec_tup, DateTime exp, Nullable<uint> id = null) {
_sec_tup = sec_tup;
expiration = exp;
_id = id;
}
[ProtoMember(1)]
public SecurityTuple security_tuple { get; }
public SecurityTuple security_tuple { get { return _sec_tup; } }
[ProtoMember(2)]
public DateTime expiration { get; }
public SecurityType security_type { get { return _sec_tup.security_type; } }
[ProtoMember(3)]
public uint? id { get; }
public string symbol { get { return _sec_tup.security_name; } }
public SecurityType security_type => security_tuple?.security_type ?? SecurityType.Unset;
public string symbol => security_tuple?.security_name ?? string.Empty;
public Venue exchange => security_tuple?.security_exchange ?? Venue.Unset;
public Venue exchange { get { return _sec_tup.security_exchange; } }
[Flags]
public enum Properties {
Type = 1,
Symbol = 1 << 1,
Expiration = 1 << 2,
Venue = 1 << 3,
Id = 1 << 4
public bool is_empty() { return Equals(empty); }
public Nullable<uint> id() { return _id; }
public SecurityExpiration unset_exchange() {
return new SecurityExpiration(Venue.Unset, security_type, symbol, expiration);
}
public static IEqualityComparer<SecurityExpiration> get_eq_comparer() =>
get_eq_comparer(
Properties.Type, Properties.Symbol, Properties.Expiration, Properties.Venue);
public static IEqualityComparer<SecurityExpiration> get_eq_comparer(Properties props) {
return EqualityComparerBuilder.create_comparer(
EnumHelper.split_flags(props).Select(get_prop_comparer));
static IEqualityComparer<SecurityExpiration> get_prop_comparer(Properties single_prop) =>
single_prop switch {
Properties.Type => wrap(s => s.security_type),
Properties.Symbol => wrap(s => s.symbol).to_safe(),
Properties.Expiration => wrap(s => s.expiration),
Properties.Venue => wrap(s => s.exchange),
Properties.Id => wrap(s => s.id).to_safe(),
_ => throw new NotImplementedException()
};
static IEqualityComparer<SecurityExpiration> wrap<T>(
Func<SecurityExpiration, T> selector, IEqualityComparer<T>? comparer = null) =>
EqualityComparer.Create(selector, comparer ?? EqualityComparer<T>.Default);
public bool Equals(SecurityExpiration other) {
if (other != null)
return _sec_tup.Equals(other._sec_tup) && expiration.Equals(other.expiration);
else
return false;
}
public static IEqualityComparer<SecurityExpiration> get_eq_comparer(params Properties[] hierarchy) =>
EqualityComparerBuilder.create(hierarchy.Select(get_eq_comparer)).to_comparer();
#region Object overrides
public static IComparer<SecurityExpiration> get_comparer() =>
get_comparer(Properties.Venue, Properties.Type, Properties.Symbol, Properties.Expiration);
public override int GetHashCode() { return _sec_tup.GetHashCode() ^ expiration.GetHashCode(); }
public static IComparer<SecurityExpiration> get_comparer(Properties prop) {
return prop switch {
Properties.Type => wrap(s => s.security_type),
Properties.Symbol => wrap(s => s.symbol),
Properties.Expiration => wrap(s => s.expiration),
Properties.Venue => wrap(s => s.exchange),
Properties.Id => wrap(s => s.id).to_safe(),
_ => throw new NotImplementedException()
};
static IComparer<SecurityExpiration> wrap<T>(
Func<SecurityExpiration, T> selector, IComparer<T>? comparer = null) =>
(comparer ?? Comparer<T>.Default).wrap(selector);
public override bool Equals(object obj) {
return Equals(obj as SecurityExpiration);
}
public static IComparer<SecurityExpiration> get_comparer(params Properties[] hierarchy) =>
ComparerBuilder.create(hierarchy.Select(get_comparer)).to_comparer();
public static bool operator ==(SecurityExpiration x, SecurityExpiration y) {
if (Object.ReferenceEquals(x, null)) return Object.ReferenceEquals(y, null);
if (Object.ReferenceEquals(y, null)) return false;
return x.Equals(y);
}
public static bool operator !=(SecurityExpiration x, SecurityExpiration y) { return !(x == y); }
public static IComparer<SecurityExpiration> get_exp_based_comparer() =>
get_comparer(Properties.Expiration, Properties.Venue, Properties.Type, Properties.Symbol);
public override string ToString() {
return String.Format("{0} {1}", _sec_tup.ToString(), expiration.ToShortDateString());
}
#endregion
public bool is_empty() => Equals(empty);
public static int ExpBasedCompare(SecurityExpiration x, SecurityExpiration y) {
if (y == null) return 1;
if (x == null) return -1;
int rv = x.expiration.CompareTo(y.expiration);
if (rv == 0)
rv = x._sec_tup.CompareTo(y._sec_tup);
return rv;
}
public SecurityExpiration unset_exchange() =>
new(Venue.Unset, security_type, symbol, expiration);
public SecurityExpiration Clone() =>
new(security_tuple.Clone(), expiration, id);
public bool Equals(SecurityExpiration? other) =>
other is not null &&
security_tuple.safe_equals(other.security_tuple) &&
expiration == other.expiration;
public override bool Equals(object? obj) =>
Equals(obj as SecurityExpiration);
public override int GetHashCode() =>
HashCode.Combine(security_tuple, expiration);
object ICloneable.Clone() =>
Clone();
public static bool operator ==(SecurityExpiration? x, SecurityExpiration? y) =>
x is null ? y is null : x.Equals(y);
public static bool operator !=(SecurityExpiration x, SecurityExpiration y) =>
!(x == y);
public override string ToString() =>
$"{security_tuple} {expiration.ToShortDateString()}";
}
[ProtoContract]
public class SecurityExpirationProto : IProtobuf<SecurityExpirationProto> {
[ProtoMember(1)]
public SecurityTuple? security { get; set; }
[ProtoMember(2)]
public double expiration_oa_date { get; set; }
public SecurityExpirationProto Clone() =>
new() { security = security, expiration_oa_date = expiration_oa_date};
public bool Equals(SecurityExpirationProto? other) =>
other is not null &&
security.safe_equals(other.security) &&
expiration_oa_date.Equals(other.expiration_oa_date);
public override bool Equals(object? obj) =>
Equals(obj as SecurityExpirationProto);
public override int GetHashCode() =>
HashCode.Combine(security, expiration_oa_date);
object ICloneable.Clone() {
throw new NotImplementedException();
public static int SecBasedCompare(SecurityExpiration x, SecurityExpiration y) {
if (y == null) return 1;
if (x == null) return -1;
int rv = x._sec_tup.CompareTo(y._sec_tup);
if (rv == 0)
rv = x.expiration.CompareTo(y.expiration);
return rv;
}
}
public static class SecurityExpirationExtensions {
public static SecurityExpiration with(
this SecurityExpiration sec_exp,
Venue? exchange = null,
SecurityType? security_type = null,
string? symbol = null,
DateTime? expiration = null,
Optional<uint> id = default) => new(
exchange ?? sec_exp.exchange, security_type ?? sec_exp.security_type,
symbol ?? sec_exp.symbol,
expiration ?? sec_exp.expiration,
id.has_value ? id.value : sec_exp.id);
[ProtoBuf.ProtoContract]
public class SecurityExpirationProto {
[ProtoBuf.ProtoMember(1)]
public SecurityTuple security;
[ProtoBuf.ProtoMember(2)]
public double expiration_oa_date;
}
}
@@ -1,50 +1,58 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using bts.api;
using bts.settings;
using bts.spark;
using mbts.spark;
namespace mbts {
using bts.api;
using Spark.Core.Data;
using System;
public class SecurityStrike : IEquatable<SecurityStrike> {
public SecurityStrike(
SecurityExpiration expiration, double strike, CallPutTuple<uint?> call_put_id = default) {
public readonly SecurityExpiration expiration;
public readonly double strike;
public readonly Tuple<UInt32?, UInt32?> call_put_id;
public SecurityStrike(SecurityExpiration expiration, double strike,
Tuple<UInt32?, UInt32?> call_put_id = null) {
this.expiration = expiration;
this.strike = strike;
this.call_put_id = call_put_id;
}
public SecurityStrike(
string symbol, DateTime exp, double strike, CallPutTuple<uint?> call_put_id = default)
: this(new(Venue.Unset, SecurityType.Option, symbol, exp), strike, call_put_id) { }
public SecurityStrike(string symbol, DateTime exp, double strike,
Tuple<UInt32?, UInt32?> call_put_id = null)
: this(new SecurityExpiration(
Venue.Unset, SecurityType.Option, symbol, exp), strike, call_put_id) { }
public SecurityExpiration expiration { get; }
public double strike { get; }
public CallPutTuple<uint?> call_put_id { get; }
public bool Equals(SecurityStrike other) {
if (other != null)
return expiration.Equals(other.expiration) && strike.Equals(other.strike);
else
return false;
}
/// TODO: figure out why <see cref="call_put_id"/> is excluded from equality logic
/// (was it an accident, or intentional? if the latter, why?)
public bool Equals(SecurityStrike? other) =>
other is not null &&
expiration.Equals(other.expiration) &&
strike.Equals(other.strike);
public override int GetHashCode() { return expiration.GetHashCode() ^ strike.GetHashCode(); }
public override int GetHashCode() =>
HashCode.Combine(expiration, strike);
public override bool Equals(object obj) {
return Equals(obj as SecurityStrike);
}
public override bool Equals(object? obj) =>
Equals(obj as SecurityStrike);
public static bool operator ==(SecurityStrike x, SecurityStrike y) {
if ((object)x == null) return (object)y == null;
return x.Equals(y);
}
public static bool operator ==(SecurityStrike x, SecurityStrike y) =>
x is null ? y is null : x.Equals(y);
public static bool operator !=(SecurityStrike x, SecurityStrike y) { return !(x == y); }
public static bool operator !=(SecurityStrike x, SecurityStrike y) =>
!(x == y);
public override string ToString() {
return String.Format("{0} {1}", expiration.ToString(), strike.ToString());
}
public override string ToString() =>
$"{expiration} {strike}";
public SecurityStrike unset_exchange() =>
new(expiration.with(exchange: Venue.Unset), strike);
public SecurityStrike unset_exchange() { return new SecurityStrike(expiration.unset_exchange(), strike); }
}
}
}
@@ -5,29 +5,6 @@ namespace mbts.analytics {
/// they all in a way "derive" from core
[ProtoContract]
public class VolSurfaceSettings {
public static VolSurfaceSettings Default(string name) => new() {
core_settings = new VolSurfaceCoreSettings {
vol_surface_name = name,
vol_surface_model = VolSurfaceEnums.VolSurfaceModel.Polynomial,
call_rotation = new() { strike_vol_movement_pairs = new() },
put_rotation = new() { strike_vol_movement_pairs = new() },
strangle = new() { strike_vol_movement_pairs = new() },
full_rotation = new() { strike_vol_movement_pairs = new() },
atm_shift = new() { strike_vol_movement_pairs = new() },
symbols = new(),
symbol_structure_list = new(),
wing_settings = new() {
explicit_slope_wing_settings = new(),
implicit_slope_wing_settings = new(),
onepoint_slope_wing_settings = new()
},
unset_expiration_calculation_settings = new(),
volpath_settings = new(),
safety_limits = new(),
},
polynomial_model_settings = new()
};
[ProtoMember(10)]
public VolSurfaceCoreSettings core_settings;
[ProtoMember(15)]
@@ -1,19 +1,19 @@
using bts.api;
using bts.settings;
using bts.spark;
using bts.utils;
using mbts.spark;
using mbts.ui.converters;
using ProtoBuf;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using bts.api;
using bts.settings;
using bts.spark;
using mbts.spark;
using mbts.ui.converters;
using bts.utils;
namespace mbts.analytics {
/// <summary>
/// An expiration in the Vol Surface is expressed
@@ -26,13 +26,7 @@ namespace mbts.analytics {
public class VolSurfaceExpiration : IEquatable<VolSurfaceExpiration>, IComparable<VolSurfaceExpiration> {
public VolSurfaceExpiration() : this(string.Empty, default(DateTime)) { }
public VolSurfaceExpiration(string symbol, DateTime expiration)
:
this(bts.api.SecurityType.Option, symbol, expiration) {
}
public VolSurfaceExpiration(bts.api.SecurityType security_type, string symbol, DateTime expiration) {
this.security_type = security_type;
public VolSurfaceExpiration(string symbol, DateTime expiration) {
this.symbol = symbol;
this.expiration = expiration;
}
@@ -42,31 +36,28 @@ namespace mbts.analytics {
expiration = exp.expiration;
}
public SecurityExpiration to_security_expiration(
Venue exchange = Venue.Unset, SecurityType type = SecurityType.Unset) =>
new(exchange, security_type, symbol, expiration);
public SecurityExpiration to_security_expiration() {
// TODO
return new SecurityExpiration(Venue.Unset, SecurityType.Option, symbol, expiration);
}
[ProtoBuf.ProtoMember(10)]
public string symbol;
[ProtoBuf.ProtoMember(20)]
public DateTime expiration;
[ProtoBuf.ProtoMember(30)]
public bts.api.SecurityType security_type = bts.api.SecurityType.Option;
public bool Equals(VolSurfaceExpiration other) {
return other != null && symbol.Equals(other.symbol) && expiration.Equals(other.expiration);
}
public override int GetHashCode() { return security_type.GetHashCode() ^ symbol.GetHashCode() ^ expiration.GetHashCode(); }
public override int GetHashCode() { return symbol.GetHashCode() ^ expiration.GetHashCode(); }
public override bool Equals(object obj) {
return Equals(obj as VolSurfaceExpiration);
}
public override string ToString() {
return String.Format("{0} {1} {2}",
security_type.ToString().ToUpper().First(), symbol, expiration.ToShortDateString());
return String.Format("{0} {1}", symbol, expiration.ToShortDateString());
}
public int CompareTo(VolSurfaceExpiration other) {
@@ -77,11 +68,15 @@ namespace mbts.analytics {
}
public static class VolSurfaceExpirationExtensions {
public static SecurityExpiration ToSecurityExp(
this VolSurfaceExpiration vs_exp, SecurityType type) =>
new(Venue.Unset, type, vs_exp.symbol, vs_exp.expiration);
public static SecurityExpiration ToSecurityExp(this VolSurfaceExpiration vs_exp) {
var type = SecurityType.Unset;
if (!string.IsNullOrWhiteSpace(vs_exp.symbol)) {
if (Char.IsLower(vs_exp.symbol.First())) type = SecurityType.Option;
else if (Char.IsUpper(vs_exp.symbol.First())) type = SecurityType.Future;
}
return new SecurityExpiration(Venue.Unset, type, vs_exp.symbol, vs_exp.expiration);
}
}
public class VolSurfaceStrikeMap {
public readonly IDictionary<VolSurfaceExpiration, IEnumerable<double>> strike_map = null;
public VolSurfaceStrikeMap(IEnumerable<string> option_names, SystemContractData sc_data) {
@@ -17,18 +17,9 @@ namespace mbts.analytics {
this.server_time_utc = server_time_utc;
}
public VolSurfaceStandardTime(long seconds_from_epoch) {
timezone = TimeZoneInfo.Local;
server_time_utc =
DateTimeOffset.FromUnixTimeSeconds(seconds_from_epoch).DateTime;
server_time = server_time_utc.ToLocalTime();
}
public static VolSurfaceStandardTime get_local_default() {
DateTime local_rounded = VolSurfaceUtilityFunctions.round_time_mins(
DateTime.Now, VolSurfaceConstants.vol_time_sample_mins);
return new VolSurfaceStandardTime(
TimeZoneInfo.Local, local_rounded, local_rounded.ToUniversalTime());
DateTime local_rounded = VolSurfaceUtilityFunctions.round_time_mins(DateTime.Now, VolSurfaceConstants.vol_time_sample_mins);
return new VolSurfaceStandardTime(TimeZoneInfo.Local, local_rounded, local_rounded);
}
public override string ToString() {
@@ -1,6 +1,4 @@
using Spark.Core.Collections;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -21,11 +19,9 @@ namespace mbts.analytics
{
HashSet<VolSurfaceExpiration> vs_exp_map = new HashSet<VolSurfaceExpiration>(vs_input.surface_parameters.curve_parameters_map.Select(t => t.Item1)),
sys_exp_map = new HashSet<VolSurfaceExpiration>(system_exp_list);
sys_exp_map.difference(
vs_exp_map,
out HashSet<VolSurfaceExpiration> deleted_exps,
out HashSet<VolSurfaceExpiration> added_exps);
if (deleted_exps.Any() || added_exps.Any()) {
HashSet<VolSurfaceExpiration> deleted_exps, added_exps;
if (VolSurfaceUtilityFunctions.compare_hashsets(sys_exp_map, vs_exp_map, out deleted_exps, out added_exps))
{
VolSurfaceInput rv = VolSurfaceUtilityFunctions.clone_proto(vs_input);
rv.surface_parameters.curve_parameters_map = rv.surface_parameters.curve_parameters_map ?? new List<Tuple<VolSurfaceExpiration, VolCurveParameters>>();
rv.surface_parameters.curve_parameters_map.RemoveAll(t => deleted_exps.Contains(t.Item1));
@@ -104,11 +100,7 @@ namespace mbts.analytics
else if (vs_settings.core_settings.vol_surface_model == VolSurfaceEnums.VolSurfaceModel.Polynomial)
{
rv.spline_model_parameters = null;
rv.polynomial_model_parameters ??= new PolynomialModelVolCurveParameters() {
atm_vol = double.NaN
};
rv.polynomial_model_parameters.put_points ??= new();
rv.polynomial_model_parameters.call_points ??= new();
rv.polynomial_model_parameters = rv.polynomial_model_parameters ?? new PolynomialModelVolCurveParameters() { atm_vol = Double.NaN, put_points = new List<Tuple<double, double>>(), call_points = new List<Tuple<double, double>>() };
if (rv.polynomial_model_parameters.put_points.Count != vs_settings.polynomial_model_settings.n_put_points)
rv.polynomial_model_parameters.put_points = _sync_volpoints_to_settings(rv.polynomial_model_parameters.put_points, false, vs_settings.polynomial_model_settings.strike_axis, (int)vs_settings.polynomial_model_settings.n_put_points).ToList();
if (rv.polynomial_model_parameters.call_points.Count != vs_settings.polynomial_model_settings.n_call_points)
@@ -236,8 +228,10 @@ namespace mbts.analytics
return vs_input != null ? get_symbols(vs_input.surface_settings) : new string[] { };
}
public static IEnumerable<string> get_symbols(VolSurfaceSettings vs_settings) =>
vs_settings.core_settings.symbol_pricing_model_map.empty_if_null().Select(i => i.Item1);
public static IEnumerable<string> get_symbols(VolSurfaceSettings vs_settings)
{
return vs_settings.core_settings.symbol_pricing_model_map.Select(i => i.Item1);
}
public static VolCurveParameters get_curve_parameters(VolSurfaceInput vs_input, VolSurfaceExpiration exp)
{
@@ -681,4 +675,4 @@ namespace mbts.analytics
#endregion
}
}
}
@@ -1,58 +0,0 @@
namespace mbts.analytics {
using bts.utils;
using mbts.spark.filters;
using System;
public class VolSurfaceDriverTheo {
public static readonly VolSurfaceDriverTheo empty = new(
SecurityExpiration.empty, SecurityExpiration.empty);
public readonly SecurityExpiration exp;
public readonly SecurityExpiration driver_exp;
public readonly double market_price;
public readonly double driver_market_price;
public readonly double roll;
public readonly double theo;
public readonly double delta;
public readonly double settlement_price;
public readonly double settlement_theo;
public readonly double settlement_delta;
public VolSurfaceDriverTheo(
SecurityExpiration exp,
SecurityExpiration driver_exp,
double market_price = double.NaN,
double driver_market_price = double.NaN,
double roll = double.NaN,
double theo = double.NaN,
double delta = double.NaN,
double settlement_price = double.NaN,
double settlement_theo = double.NaN,
double settlement_delta = double.NaN
) {
this.exp = exp;
this.driver_exp = driver_exp;
this.market_price = market_price;
this.driver_market_price = driver_market_price;
this.roll = roll;
this.theo = theo;
this.delta = delta;
this.settlement_price = settlement_price;
this.settlement_theo = settlement_theo;
this.settlement_delta = settlement_delta;
}
public bool is_settlement_populated {
get {
bool non_populated = double.IsNaN(settlement_price) ||
Math.Abs(settlement_price) < 0.0000001;
return !non_populated;
}
}
public double effective_theo => is_settlement_populated ? settlement_price : theo;
public double effective_delta => is_settlement_populated ? 0 : delta;
}
}
@@ -19,35 +19,25 @@ namespace mbts.analytics {
}
private class TimeCalculator : IVolSurfaceTimeCalculator {
// TODO, this should be passed in the exp itself
private Dictionary<string, TimeSpan> utc_time_of_exp_map = new Dictionary<string, TimeSpan>() {
{"BTC", TimeSpan.FromHours(8)},
{"ETH", TimeSpan.FromHours(8)}
};
public void compute_vol_time(VolSurfaceInput vs_input, VolSurfaceExpiration exp,
DateTime voltime, double days_shift,
out double yrs, out double days_per_yr) {
DateTime voltime, double days_shift, out double yrs, out double days_per_yr) {
// TODO (shortcut to avoid calling into Calendar config)
days_per_yr = 365;
TimeSpan time_of_exp = TimeSpan.Zero;
utc_time_of_exp_map.TryGetValue(exp.symbol, out time_of_exp);
// assumes exp is the utc date of expiration
DateTime exp_adjusted = exp.expiration.Date.Add(time_of_exp);
double days_to_exp = (exp_adjusted - voltime).TotalDays;
days_to_exp += days_shift;
yrs = days_to_exp / days_per_yr;
yrs = (exp.expiration - voltime).TotalDays / days_per_yr;
// var time_measure = VolSurfaceDataFunctions.get_vol_time_measure(vs_input.surface_settings);
// days_per_yr = time_measure.days_per_year;
// yrs = VolSurfaceTimeFunctions.get_vol_years_remaining(exp, voltime, time_measure, days_shift);
}
public void compute_interest_time(VolSurfaceInput vs_input, VolSurfaceExpiration exp,
DateTime voltime, double days_shift,
out double yrs, out double days_per_yr) {
DateTime voltime, double days_shift, out double yrs, out double days_per_yr) {
// TODO
days_per_yr = 365;
TimeSpan time_of_exp = TimeSpan.Zero;
utc_time_of_exp_map.TryGetValue(exp.symbol, out time_of_exp);
// assumes exp is the utc date of expiration
DateTime exp_adjusted = exp.expiration.Date.Add(time_of_exp);
double days_to_exp = (exp_adjusted - voltime).TotalDays;
days_to_exp += days_shift;
yrs = days_to_exp / days_per_yr;
yrs = (exp.expiration - voltime).TotalDays / days_per_yr;
days_per_yr = 365;
// var time_measure = VolSurfaceDataFunctions.get_interest_time_measure(vs_input.surface_settings);
// days_per_yr = time_measure.days_per_year;
// yrs = VolSurfaceTimeFunctions.get_interest_years_remaining(exp, voltime, time_measure, days_shift);
}
}
}
File diff suppressed because it is too large. Load diff
@@ -5,9 +5,6 @@ using System.Text;
using System.Threading.Tasks;
using bts;
using bts.utils;
using mbts.utils;
namespace mbts.analytics
{
@@ -155,8 +152,12 @@ namespace mbts.analytics
out double adjusted_ref_fwd,
out double adjusted_ref_vol)
{
var comp = new ComparerBuilder<ControlPoint>()
.to_comparer(cp => cp.standard_strike.abs().if_nan(double.PositiveInfinity));
IComparer<ControlPoint> comp = VolSurfaceUtilityFunctions.get_comparer<ControlPoint>(
(cp1, cp2) =>
{
double d1 = Math.Abs(cp1.standard_strike), d2 = Math.Abs(cp2.standard_strike);
return (Double.IsNaN(d1) ? Double.PositiveInfinity : d1).CompareTo((Double.IsNaN(d2) ? Double.PositiveInfinity : d2));
});
adjusted_atm_vol = input_atm_vol + parallel_curve_move + (is_rebuild ? volpath_move : 0.0);
adjusted_put_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Put).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
adjusted_call_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Call).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
@@ -305,8 +306,12 @@ namespace mbts.analytics
IEnumerable<ControlPoint> calculated_controlpoints)
{
curve_parameters = VolSurfaceUtilityFunctions.clone_proto(curve_parameters);
var comp = new ComparerBuilder<ControlPoint>()
.to_comparer(cp => cp.standard_strike.abs().if_nan(double.PositiveInfinity));
IComparer<ControlPoint> comp = VolSurfaceUtilityFunctions.get_comparer<ControlPoint>(
(cp1, cp2) =>
{
double d1 = Math.Abs(cp1.standard_strike), d2 = Math.Abs(cp2.standard_strike);
return (Double.IsNaN(d1) ? Double.PositiveInfinity : d1).CompareTo((Double.IsNaN(d2) ? Double.PositiveInfinity : d2));
});
var adjusted_put_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Put).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
var adjusted_call_points = calculated_controlpoints.Where(cp => cp.point_type == CoordinatesBasedModelHelper.ControlPoint.PointType.Call).OrderBy(cp => cp, comp).Select(cp => Tuple.Create(cp.input_strike, cp.input_abstract_vol));
if (surface_settings.core_settings.vol_surface_model == VolSurfaceEnums.VolSurfaceModel.CubicSpline)
@@ -462,4 +467,4 @@ namespace mbts.analytics
#endregion
}
}
}
@@ -1,11 +1,65 @@
namespace mbts.analytics {
using bts.api.analytics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.ComponentModel;
using System;
using System.Collections.Generic;
namespace mbts.analytics
{
/// move this out later
public enum VolSurfaceGreeks
{
/* *********************Primary Greeks*********************/
Vol,
Moneyness,
Theo,
Delta,
[Description("BSM Delta")]
BSMDelta,
FlatVolDelta,
Vega,
[Description("BSM Vega")]
BSMVega,
AdjustedVega, /// adjusted_vega = vega * (atm_vega/n_days_atm_vega)
Theta,
AdjustedTheta, /// what is that ? (its in slide)
RollRho,
DiscountRho,
TimeValue,
/* *********************Second Order*********************/
Gamma,
[Description("BSM Gamma")]
BSMGamma,
OEV,
[Description("BSM OEV")]
BSMOEV,
Vanna,
Volga,
Charm,
[Description("Vol/Und")]
DVolDUnd,
[Description("Vol²/DUnd²")]
D2VolDUnd2,
/* *********************Curve Operations******************/
[Description("Price/DRR")]
DPriceDRiskReversal,
[Description("Price/Strangle")]
DPriceDStrangle,
[Description("Price/Put Tilt")]
DPriceDPutTilt,
[Description("Price/Call Tilt")]
DPriceDCallTilt,
/* *********************Risk*******************************/
[Description("PnL")]
PNL,
ExpirationDelta
}
[ProtoBuf.ProtoContract(Name = "VolSurfaceStrikeTheo")]
public class VolSurfaceStrikeTheo {
public class VolSurfaceStrikeTheo
{
[ProtoBuf.ProtoMember(10)]
public DateTime exp;
[ProtoBuf.ProtoMember(20)]
@@ -19,8 +73,9 @@
}
[ProtoBuf.ProtoContract(Name = "VolSurfaceSymbolTheos")]
public class VolSurfaceSymbolTheos {
public class VolSurfaceSymbolTheos
{
[ProtoBuf.ProtoMember(10)]
public List<VolSurfaceStrikeTheo> all_theos;
}
}
}
}
@@ -1,11 +1,12 @@
namespace mbts.analytics {
using bts.api.analytics;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace mbts.analytics
{
/// Computes greeks from VolMatrix
public class VolSurfaceTheoCalculator
{
@@ -25,27 +26,27 @@
{VolSurfaceGreeks.Moneyness, (volmat, is_call) => volmat.standard_strike},
{VolSurfaceGreeks.Theo, (volmat, is_call) => compute_theo (volmat, is_call)},
{VolSurfaceGreeks.Delta, (volmat, is_call) => compute_delta (volmat, is_call)},
{VolSurfaceGreeks.Bsmdelta, (volmat, is_call) => compute_bsm_delta (volmat, is_call)},
{VolSurfaceGreeks.BSMDelta, (volmat, is_call) => compute_bsm_delta (volmat, is_call)},
{VolSurfaceGreeks.FlatVolDelta, (volmat, is_call) => compute_flatvol_delta (volmat, is_call)},
{VolSurfaceGreeks.Vega, (volmat, is_call) => compute_vega (volmat, is_call)},
{VolSurfaceGreeks.Bsmvega, (volmat, is_call) => compute_bsm_vega (volmat)},
{VolSurfaceGreeks.BSMVega, (volmat, is_call) => compute_bsm_vega (volmat)},
{VolSurfaceGreeks.Theta, (volmat, is_call) => compute_theta (volmat, is_call)},
{VolSurfaceGreeks.TimeValue, (volmat, is_call) => compute_time_value (volmat, is_call)},
{VolSurfaceGreeks.Gamma, (volmat, is_call) => compute_gamma (volmat, is_call)},
{VolSurfaceGreeks.Bsmgamma, (volmat, is_call) => compute_bsm_gamma (volmat)},
{VolSurfaceGreeks.Oev, (volmat, is_call) => compute_oev (volmat, is_call)},
{VolSurfaceGreeks.Bsmoev, (volmat, is_call) => compute_bsm_oev (volmat, is_call)},
{VolSurfaceGreeks.BSMGamma, (volmat, is_call) => compute_bsm_gamma (volmat)},
{VolSurfaceGreeks.OEV, (volmat, is_call) => compute_oev (volmat, is_call)},
{VolSurfaceGreeks.BSMOEV, (volmat, is_call) => compute_bsm_oev (volmat, is_call)},
{VolSurfaceGreeks.Vanna, (volmat, is_call) => compute_vanna (volmat, is_call)},
{VolSurfaceGreeks.Volga, (volmat, is_call) => compute_volga (volmat, is_call)},
{VolSurfaceGreeks.Charm, (volmat, is_call) => compute_charm (volmat, is_call)},
{VolSurfaceGreeks.DvolDund, (volmat, is_call) => compute_dVolDUnd (volmat)},
{VolSurfaceGreeks.D2VolDund2, (volmat, is_call) => compute_d2VolDUnd2 (volmat)},
{VolSurfaceGreeks.DVolDUnd, (volmat, is_call) => compute_dVolDUnd (volmat)},
{VolSurfaceGreeks.D2VolDUnd2, (volmat, is_call) => compute_d2VolDUnd2 (volmat)},
{VolSurfaceGreeks.DpriceDriskReversal, (volmat, is_call) => compute_dPriceDRiskReversal (volmat, is_call)},
{VolSurfaceGreeks.DpriceDstrangle, (volmat, is_call) => compute_dPriceDStrangle (volmat, is_call)},
{VolSurfaceGreeks.DpriceDputTilt, (volmat, is_call) => compute_dPriceDPutTilt (volmat, is_call)},
{VolSurfaceGreeks.DpriceDcallTilt, (volmat, is_call) => compute_dPriceDCallTilt (volmat, is_call)},
{VolSurfaceGreeks.DPriceDRiskReversal, (volmat, is_call) => compute_dPriceDRiskReversal (volmat, is_call)},
{VolSurfaceGreeks.DPriceDStrangle, (volmat, is_call) => compute_dPriceDStrangle (volmat, is_call)},
{VolSurfaceGreeks.DPriceDPutTilt, (volmat, is_call) => compute_dPriceDPutTilt (volmat, is_call)},
{VolSurfaceGreeks.DPriceDCallTilt, (volmat, is_call) => compute_dPriceDCallTilt (volmat, is_call)},
};
}
@@ -442,4 +443,4 @@
}
}
}
}
}
@@ -1,72 +1,65 @@
#nullable enable
using System;
using bts.api;
using bts.api.analytics;
namespace mbts.analytics {
using bts.api.analytics;
using bts.utils;
using mbts.spark;
using System;
[Serializable]
public class AnalyticsExpirationParameters : IEquatable<AnalyticsExpirationParameters> {
public static readonly AnalyticsExpirationParameters empty =
new(
SecurityExpiration.empty,
null,
SecurityExpiration.empty,
SecurityExpiration.empty,
double.NaN,
double.NaN,
double.NaN,
double.NaN,
double.NaN);
public readonly SecurityExpiration security,
driver_security,
deliverable_security,
roll_schedule_expiration;
public readonly DriverCalculationType driver_calc_type =
DriverCalculationType.Direct;
public readonly double roll_target, riskless_rate, settlement_price;
public readonly double driver_addend, driver_factor,
driver_translation_target, delta_beta, vega_beta;
public readonly ExpirationDriverImmutable driver;
public readonly double roll_target;
public readonly double riskless_rate;
public readonly double settlement_price;
public readonly double driver_addend;
public readonly double driver_factor;
public readonly double driver_translation_target;
public readonly double delta_beta;
public readonly double vega_beta;
readonly bts.api.domain.SecurityExpirationImmutable _security;
readonly bts.api.domain.SecurityExpirationImmutable _deliverable;
readonly bts.api.domain.SecurityExpirationImmutable _roll_schedule;
public static AnalyticsExpirationParameters empty =
new AnalyticsExpirationParameters(SecurityExpiration.empty,
SecurityExpiration.empty,
SecurityExpiration.empty,
SecurityExpiration.empty,
Double.NaN, Double.NaN, Double.NaN,
Double.NaN, Double.NaN);
public AnalyticsExpirationParameters(
SecurityExpiration security,
ExpirationDriverImmutable? driver,
SecurityExpiration? deliverable_security,
SecurityExpiration? roll_schedule_expiration,
double roll_target,
double riskless_rate,
double settlement_price,
double delta_beta,
double vega_beta
) {
_security = security.to_api_sec_expi();
deliverable_security ??= SecurityExpiration.empty;
roll_schedule_expiration ??= SecurityExpiration.empty;
this.driver = driver ?? new(new() {
TimeWeightedInterpolated = new()
});
_deliverable = deliverable_security.to_api_sec_expi();
_roll_schedule = roll_schedule_expiration.to_api_sec_expi();
this.roll_target = roll_target;
this.riskless_rate = riskless_rate;
this.settlement_price = settlement_price;
this.delta_beta = delta_beta;
this.vega_beta = vega_beta;
SecurityExpiration this_security,
SecurityExpiration this_driver_security,
SecurityExpiration this_deliverable_security,
SecurityExpiration this_roll_schedule_expiration,
double this_roll_target, double this_riskless_rate,
double this_settlement_price, double this_delta_beta,
double this_vega_beta) {
security = this_security;
driver_security = this_driver_security ?? SecurityExpiration.empty;
deliverable_security = this_deliverable_security ?? SecurityExpiration.empty;
roll_schedule_expiration = this_roll_schedule_expiration ??
SecurityExpiration.empty;
roll_target = this_roll_target;
riskless_rate = this_riskless_rate;
settlement_price = this_settlement_price;
delta_beta = this_delta_beta;
vega_beta = this_vega_beta;
}
public AnalyticsExpirationParameters(ExpirationParameterEntryImmutable db_i) {
_security = db_i.SecurityExpiration;
_deliverable = db_i.Deliverable;
_roll_schedule = db_i.RollSchedule;
driver = db_i.Driver;
Func<ExpirationImmutable, DateTime> to_dt = (ExpirationImmutable e) =>
new DateTime((int)e.ExpirationYear, (int)e.ExpirationMonth,
(int)e.ExpirationDay);
security = new SecurityExpiration(db_i.Exchange,
db_i.SecurityType, db_i.Symbol, to_dt(db_i.Expiration));
driver_calc_type = db_i.DriverCalc;
driver_security = new SecurityExpiration(db_i.DriverExchange,
db_i.DriverSecurityType, db_i.DriverSymbol,
to_dt(db_i.DriverExpiration));
deliverable_security = new SecurityExpiration(db_i.DeliverableExchange,
db_i.DeliverableSecurityType, db_i.DeliverableSymbol,
to_dt(db_i.DeliverableExpiration));
roll_schedule_expiration = new SecurityExpiration(db_i.RollScheduleExchange,
db_i.RollScheduleSecurityType, db_i.RollScheduleSymbol,
to_dt(db_i.RollScheduleExpiration));
roll_target = db_i.RollTarget;
riskless_rate = db_i.RisklessRate;
settlement_price = db_i.SettlementPrice;
@@ -74,41 +67,66 @@ namespace mbts.analytics {
vega_beta = db_i.VegaBeta;
}
public SecurityExpiration security => _security.to_sec_exp();
public SecurityExpiration driver_security => driver.HasSecurity ?
driver.Security.to_sec_exp() : SecurityExpiration.empty;
public SecurityExpiration deliverable_security => _deliverable.to_sec_exp();
public SecurityExpiration roll_schedule_expiration => _roll_schedule.to_sec_exp();
public ExpirationParameterEntry to_exp_param_entry() =>
new() {
SecurityExpiration = _security.CloneToMutable(),
Driver = driver.CloneToMutable(),
Deliverable = _deliverable.CloneToMutable(),
RollSchedule = _roll_schedule.CloneToMutable(),
RollTarget = roll_target,
RisklessRate = riskless_rate,
SettlementPrice = settlement_price,
DeltaBeta = delta_beta,
VegaBeta = vega_beta
public bts.api.analytics.ExpirationParameterEntry to_exp_param_entry() {
Func<DateTime, Expiration> to_exp = (DateTime e) => {
Expiration rv = new Expiration();
rv.ExpirationDay = (uint)e.Day;
rv.ExpirationMonth = (uint)e.Month;
rv.ExpirationYear = (uint)e.Year;
return rv;
};
bts.api.analytics.ExpirationParameterEntry rv = new ExpirationParameterEntry();
rv.SecurityType = security.security_type;
rv.Symbol = security.symbol;
rv.Expiration = to_exp(security.expiration);
rv.Exchange = security.exchange;
public bool Equals(AnalyticsExpirationParameters? other) =>
other is not null &&
security.Equals(other.security) &&
driver_security.safe_equals(other.driver_security) &&
deliverable_security.safe_equals(other.deliverable_security) &&
roll_schedule_expiration.safe_equals(other.roll_schedule_expiration) &&
roll_target.Equals(other.roll_target) &&
riskless_rate.Equals(other.riskless_rate) &&
settlement_price.Equals(other.settlement_price) &&
delta_beta.Equals(other.delta_beta) &&
vega_beta.Equals(other.vega_beta);
rv.DriverSecurityType = driver_security.security_type;
rv.DriverSymbol = driver_security.symbol;
rv.DriverExpiration = to_exp(driver_security.expiration);
rv.DriverExchange = driver_security.exchange;
public override bool Equals(object? obj) =>
Equals(obj as AnalyticsExpirationParameters);
rv.DeliverableSecurityType = deliverable_security.security_type;
rv.DeliverableSymbol = deliverable_security.symbol;
rv.DeliverableExpiration = to_exp(deliverable_security.expiration);
rv.DeliverableExchange = deliverable_security.exchange;
public override int GetHashCode() =>
security.GetHashCode();
rv.RollScheduleSecurityType = roll_schedule_expiration.security_type;
rv.RollScheduleSymbol = roll_schedule_expiration.symbol;
rv.RollScheduleExpiration = to_exp(roll_schedule_expiration.expiration);
rv.RollScheduleExchange = roll_schedule_expiration.exchange;
rv.RollTarget = roll_target;
rv.RisklessRate = riskless_rate;
rv.SettlementPrice = settlement_price;
rv.DeltaBeta = delta_beta;
rv.VegaBeta = vega_beta;
return rv;
}
public bool Equals(AnalyticsExpirationParameters other) {
return other != null &&
security.Equals(other.security) &&
_null_equal(driver_security, other.driver_security) &&
_null_equal(deliverable_security, other.deliverable_security) &&
_null_equal(roll_schedule_expiration, other.roll_schedule_expiration) &&
roll_target.Equals(other.roll_target) &&
riskless_rate.Equals(other.riskless_rate) &&
settlement_price.Equals(other.settlement_price) &&
delta_beta.Equals(other.delta_beta) &&
vega_beta.Equals(other.vega_beta);
}
public override bool Equals(object obj) {
return Equals(obj as AnalyticsExpirationParameters);
}
public override int GetHashCode() { return security.GetHashCode(); }
private static bool _null_equal(SecurityExpiration a, SecurityExpiration b) {
a = a == null ? null : (a.is_empty() ? null : a);
b = b == null ? null : (b.is_empty() ? null : b);
return (a == null && b == null) || (a != null && b != null && a.Equals(b));
}
}
}
}
@@ -41,7 +41,7 @@ namespace mbts.analytics {
}
public IDictionary<mbts.SecurityTuple, double> get_cpp_map() {
return input.get_cpp_list().ToDictionaryCrushed(i => new mbts.SecurityTuple(i.Item1, i.Item2, Venue.Sim), i => i.Item3);
return input.get_cpp_list().ToDictionary(i => new mbts.SecurityTuple(i.Item1, i.Item2, Venue.Unset), i => i.Item3);
}
private static mbts.SecurityExpiration _unset = mbts.SecurityExpiration.empty;
@@ -59,4 +59,4 @@ namespace mbts.analytics {
return rv;
}
}
}
}
@@ -51,12 +51,13 @@ namespace mbts.analytics {
return null;
}
public IEnumerable<Tuple<SecurityType, string, double>> get_cpp_list() =>
public IEnumerable<Tuple<SecurityType, string, double>> get_cpp_list() {
List<Tuple<SecurityType, string, double>> rv = new List<Tuple<SecurityType, string, double>>();
// TODO, cpp
exp_input_map
.Select(kv => Tuple.Create(kv.Key.security_type, kv.Key.symbol, 1.0))
.Distinct()
.ToList();
return
exp_input_map.ToList().Select(kv =>
new Tuple<SecurityType, string, double>(kv.Key.security_type, kv.Key.symbol, 1));
}
public IDictionary<mbts.SecurityTuple, double> get_cpp_map() {
return get_cpp_list().ToDictionary(
@@ -67,4 +68,4 @@ namespace mbts.analytics {
return exp_input_map.Where(kv => filter(kv.Key)).ToDictionary(kv => kv.Key, kv => kv.Value.roll_target);
}
}
}
}
@@ -3,13 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using bts.api.analytics;
using NUnit.Framework;
using Spark.Core.Protobuf;
namespace mbts.analytics
{
[TestFixture]
@@ -26,16 +21,16 @@ namespace mbts.analytics
VolSurfaceGreeks.Gamma,
VolSurfaceGreeks.Vol,
VolSurfaceGreeks.AdjustedVega,
VolSurfaceGreeks.Oev,
VolSurfaceGreeks.OEV,
VolSurfaceGreeks.Theta,
VolSurfaceGreeks.DpriceDriskReversal,
VolSurfaceGreeks.DPriceDRiskReversal,
VolSurfaceGreeks.Vanna,
VolSurfaceGreeks.Bsmvega,
VolSurfaceGreeks.BSMVega,
VolSurfaceGreeks.Moneyness,
};
Theos t = new Theos();
ProtobufSerializationHelper.serialize(t);
VolSurfaceUtilityFunctions.serialize_proto(t);
VolSurfaceTimer timer = new VolSurfaceTimer ();
List<VolSurfaceStrikeTheo> all_theos = new List<VolSurfaceStrikeTheo>();
@@ -70,7 +65,7 @@ namespace mbts.analytics
{
Console.WriteLine("\nStrikes {0} Handles {1} Total {2}", n_exps * 1.0 * (strike_end - strike_beg) / strike_inc, n_handles, n_handles * n_exps * 1.0 * (strike_end - strike_beg) / strike_inc);
byte[] uncomp, comp;
timer.start (); uncomp = ProtobufSerializationHelper.serialize(sym_theos); timer.stop();
timer.start (); uncomp = VolSurfaceUtilityFunctions.serialize_proto(sym_theos); timer.stop();
Console.WriteLine("Serialization time {0}", timer.last_interval_time_ms);
timer.start(); comp = VolSurfaceUtilityFunctions.compress(uncomp); timer.stop();
Console.WriteLine("Compression time {0}", timer.last_interval_time_ms);
@@ -127,4 +122,4 @@ namespace mbts.analytics
Console.WriteLine(String.Format("Min time {0} Max time {1} Median time {2} msecs", times.First(), times.Last(), times[times.Count / 2]));
}
}
}
}
@@ -1,6 +0,0 @@
#nullable enable
namespace mbts.ui {
interface ITemplateSelectorKey {
string key { get; }
}
}
@@ -1,41 +0,0 @@
#nullable enable
namespace mbts.ui {
using bts.collections;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
[ContentProperty(nameof(Map))]
class KeyedTemplateSelector : DataTemplateSelector {
readonly KeyedCollection<TemplateSelectorKeyValue, object?> _map = new(kv => kv.Key);
public IList Map => _map;
public DataTemplate? Default { get; set; }
public bool TryMatchType { get; set; }
public override DataTemplate? SelectTemplate(object? item, DependencyObject container) {
if (item is null) {
return Default;
}
var k = _get_key(item);
return k is not null && _map.TryGetValue(k, out var result) ?
result.Value : Default;
}
object? _get_key(object? item) {
if (item is null) {
return null;
}
var key = item;
if (key is ITemplateSelectorKey tsk) {
key = tsk.key;
}
if (key is null && TryMatchType) {
key = item.GetType();
}
return key;
}
}
}
@@ -1,11 +0,0 @@
#nullable enable
namespace mbts.ui {
using System.Windows;
using System.Windows.Markup;
[ContentProperty(nameof(Value))]
class TemplateSelectorKeyValue {
public object? Key { get; set; }
public DataTemplate? Value { get; set; }
}
}
@@ -15,7 +15,6 @@ using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using bts.api.analytics;
using BCG;
using Disposable = mbts.Disposable;
@@ -25,9 +24,6 @@ namespace bts {
private readonly IBus _bus;
private readonly AnalyticsService _analytics_service;
private readonly VolSurfaceBusManager _vs_manager;
private readonly SpreadManager _spread_manager;
private readonly SpreadCalculationSynchronizer _spread_calc;
IDisposable _dispose;
[ImportingConstructor]
@@ -36,8 +32,6 @@ namespace bts {
_bus = bus;
_analytics_service = analytics_service;
_vs_manager = new VolSurfaceBusManager(_bus, _analytics_service);
_spread_manager = new SpreadManager(_vs_manager.bb(), "xxx");
_spread_calc = new SpreadCalculationSynchronizer(_vs_manager.bb());
}
public void Dispose() =>
@@ -46,7 +46,7 @@ namespace bts {
return;
}
log.info($"received request to delete the following {keys.Count} securities: {string.Join(", ", keys)}");
var (orders, orders_success) = await _orders_model.security_orders.FirstAsyncTask(SparkUtils.DefaultTimeOut);
var (orders, orders_success) = await _orders_model.security_order_groups.FirstAsyncTask(SparkUtils.DefaultTimeOut);
if (!orders_success) {
var msg = "Unable to delete synthetic securities: " +
$"timed out waiting for orders table (must verify that a synthetic security does not have any working orders before it can be deleted).";
@@ -1,94 +0,0 @@
#nullable enable
namespace bts.daemons {
using bts.api;
using bts.utils;
using mbts;
using mbts.spark;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
[Export(typeof(IShellDaemon))]
public sealed class FakeSymbolDriverDaemon : IShellDaemon, IDisposable {
IDisposable _dispose;
public FakeSymbolDriverDaemon(IBus bus) {
int tid_counter = 1;
IDictionary<int, string> vol_surfaces = new Dictionary<int, string>();
var sec_trades = new Dictionary<uint, List<ITradeLogRow>>();
_dispose = Disposable.Create(
bus.subscribe(SparkTags.VolSurfaceListTag).Subscribe(vss => vol_surfaces = vss),
bus.subscribe(SparkTags.SecuritiesTag).SubscribeEach(secs => {
var btc_secs = secs.Values.Where(
s => s.security.Symbol == "BTC" &&
s.security.ContractCase == Security.ContractOneofCase.Future)
.ToList();
var fake_trades = btc_secs.Select(
s => get_fake_trade(to_sec_exp(s.security), 4200)).ToList();
bus.post(SparkTags.TradeLogTag, fake_trades);
var bbo_upd_refs = btc_secs.ToDictionary(s => s.security.Id, _ => 0UL);
var driver_sym_prices = btc_secs.ToImmutableDictionary(
s => to_sec_exp(s.security), get_driver_price);
double get_driver_price(SecurityMD smd) {
var upd_ref = bbo_upd_refs[smd.security.Id];
var rv = double.NaN;
if (smd.md.get_bbo(ref upd_ref, out var bid, out var ask)) {
rv = bid.price.if_nan(ask.price);
}
bbo_upd_refs[smd.security.Id] = upd_ref;
return rv;
}
return Observable.Interval(TimeSpan.FromSeconds(2)).Subscribe(_ => {
var bd = driver_sym_prices.ToBuilder();
foreach (var sec in btc_secs) {
var sec_exp = to_sec_exp(sec.security);
bd[sec_exp] = get_driver_price(sec).if_nan(driver_sym_prices[sec_exp]);
}
driver_sym_prices = bd.ToImmutable();
foreach (var vsid in vol_surfaces.Keys) {
bus.post(SparkTags.VolSurfaceDriverSymbolPriceTag(vsid), driver_sym_prices);
}
});
}));
static SecurityExpiration to_sec_exp(SecurityImmutable sec) =>
new(sec.Exchange, sec.ContractCase, sec.Symbol, sec.security_expiration() ?? DateTime.MinValue, sec.Id);
ITradeLogRow get_fake_trade(
SecurityExpiration sec_exp,
double price,
int size = 1,
string account = "ACC A",
double? strike = null,
PutOrCall? cp = null,
double? theo = null
) {
var t1 = new FakeTradeLogRow(
Interlocked.Increment(ref tid_counter),
sec_exp,
strike,
cp,
size,
price,
theo ?? price + 10 * new Random().NextDouble(),
account,
true,
DateTime.Now,
"FakeTrader");
return t1;
}
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
+70 -147
View File
@@ -1,147 +1,70 @@
#nullable enable
namespace bts {
using bts.api;
using bts.api.domain;
using bts.api.synthetic;
using bts.md;
using bts.spark;
using bts.utils;
using mbts;
using mbts.co2;
using mbts.config;
using mbts.spark;
using mbts.ui;
using Spark.Core.Data;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using SecurityKey = System.UInt32;
[Export(typeof(IInitializable))]
class MDDaemon : IInitializable, IDisposable {
readonly Lazy<IBus> _bus_backing;
readonly Lazy<UserTuple> _user;
readonly Lazy<AuthTokenImmutable> _token;
readonly Lazy<SyntheticSecurityService> _ss;
readonly Lazy<MDSource> _md_source_backing;
readonly ISecurityMetadataStore _security_metadata;
readonly TimeSpan _relay_throttle;
readonly TimeSpan _output_throttle;
readonly List<IDisposable> _resources = new(2);
[ImportingConstructor]
public MDDaemon(
Lazy<IBus> bus,
Lazy<AuthTokenImmutable> token,
Lazy<SyntheticSecurityService> ss,
Lazy<UserTuple> user,
ISecurityMetadataStore security_metadata)
: this(
bus,
token,
ss,
user,
security_metadata,
TimeSpan.FromMilliseconds(Configuration.get<RelayOptions>().naggle_ms),
TimeSpan.FromSeconds(1)) { }
public MDDaemon(
Lazy<IBus> bus,
Lazy<AuthTokenImmutable> token,
Lazy<SyntheticSecurityService> ss,
Lazy<UserTuple> user,
ISecurityMetadataStore security_metadata,
TimeSpan relay_throttle,
TimeSpan output_throttle
) {
_bus_backing = bus;
_user = user;
_token = token;
_ss = ss;
_relay_throttle = relay_throttle;
_output_throttle = output_throttle;
_security_metadata = security_metadata;
_md_source_backing = new(() => new(_user.Value, _relay_throttle, _output_throttle));
}
public int priority => 55;
[Export]
public MDConsumer consumer => _md_source.consumer;
MDSource _md_source => _md_source_backing.Value;
IBus _bus => _bus_backing.Value;
public void initialize() {
_md_source.set_token(_token.Value);
var synth_src = _ss.Value.subscribei_metadata()
.Select(upd => upd.all.Where(m => m.HasStrategy)
.ToDictionary(m => m.SecurityKey, m => m.Strategy))
.Replay(1)
.RefCount();
// post synth strategies to bus
_resources.Add(synth_src.Subscribe(_bus.post_callback(SparkTags.SyntheticstrategiesTag)));
// state required to detect 'undeleted' synthetics on updates, and add them back to the
// security map
var deleted_synth_cache = new Dictionary<SecurityKey, SecurityMD>();
var last_synth_strategies = new Dictionary<SecurityKey, ExecutionStrategyImmutable>();
var synth_id_comparer =
EqualityComparer.Create<KeyValuePair<SecurityKey, ExecutionStrategyImmutable>, SecurityKey>(
kv => kv.Key);
_resources.Add(
_md_source.subscribe_securities().CombineLatest(
synth_src.StartWith(new Dictionary<SecurityKey, ExecutionStrategyImmutable>()))
.BufferLatest(_output_throttle)
.Subscribe(upd => on_md(upd.First, upd.Second)));
void on_md(
ConcurrentDictionary<SecurityKey, SecurityMD> exch_secs,
Dictionary<SecurityKey, ExecutionStrategyImmutable> synth_strategies
) {
synth_strategies.Where(kv => kv.Value.Deleted).difference_hard(
last_synth_strategies.Where(kv => kv.Value.Deleted),
out var deleted_synths,
out var undeleted_synths,
synth_id_comparer);
last_synth_strategies = synth_strategies;
// add back 'undeleted' synthetics
foreach (var (id, strategy) in undeleted_synths) {
if (deleted_synth_cache.TryPopValue(id, out var synth)) {
exch_secs.TryAdd(id, synth);
}
}
// remove newly deleted synthetics, and store them for potential undelete
foreach (var (id, _) in deleted_synths) {
if (exch_secs.TryRemove(id, out var deleted)) {
deleted_synth_cache[id] = deleted;
}
}
// set 'unit quantity' for each sec
foreach (var smd in exch_secs.Values) {
var meta = _security_metadata.get(smd.security);
if (meta.HasValue) {
exch_secs[smd.id] = new(
smd.security, smd.md, meta.Value.PriceDisplay, meta.Value.QuantityDisplay);
}
}
_bus.post(SparkTags.ServerSecuritiesTag, exch_secs);
}
}
public void Dispose() =>
Disposable.dispose(_resources);
}
}
using bts.api;
using bts.api.synthetic;
using bts.md;
using mbts;
using mbts.co2;
using mbts.spark;
using mbts.ui;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using SecurityKey = System.UInt32;
namespace bts {
[Export(typeof(IInitializable))]
class MDDaemon : md.MDSource, IObserver<List<SecurityAndHandle>>, IInitializable, IDisposable {
readonly Lazy<IBus> _bus;
readonly Lazy<AuthTokenImmutable> _token;
readonly Lazy<SyntheticSecurityService> _ss;
readonly Dictionary<SecurityKey, SecurityMD> _deleted_synthetics = new Dictionary<SecurityKey, SecurityMD>();
[ImportingConstructor]
public MDDaemon(Lazy<IBus> bus, Lazy<AuthTokenImmutable> token, Lazy<SyntheticSecurityService> ss, Lazy<UserTuple> user)
: base(mbts.config.Configuration.get<md.RelayOptions>().naggle_ms, MDSourceOptions.DeferInit, user.Value) {
_bus = bus;
_token = token;
_ss = ss;
}
public int priority => 55;
[Export]
public MDConsumer consumer => _consumer;
IBus bus => _bus.Value;
public override void initialize() {
_relay.set_token(_token.Value);
_dispose.Add(
_ss.Value.subscribei_metadata()
.Select(upd => upd.all.Where(i => i.HasStrategy).ToDictionary(i => i.SecurityKey, i => i.Strategy))
.Subscribe(t => {
var deleted_synthetic_keys = new HashSet<uint>(t.Where(kv => kv.Value.Deleted).Select(kv => kv.Key));
// add back 'undeleted' synthetics
foreach (var kvp in _deleted_synthetics.ToList()) {
if (!deleted_synthetic_keys.Contains(kvp.Key)) {
_exchange_sec_map.TryAdd(kvp.Key, kvp.Value);
_deleted_synthetics.Remove(kvp.Key);
_version = DateTime.UtcNow;
}
}
// Remove any newly deleted synthetics and store them for potential undelete
foreach (var key in deleted_synthetic_keys) {
if (_exchange_sec_map.TryRemove(key, out SecurityMD deleted)) {
_deleted_synthetics[key] = deleted;
_version = DateTime.UtcNow;
}
}
// Post full dictionary of syntheics here
bus.post(SparkTags.SyntheticstrategiesTag, t);
}));
_dispose.Add(on_securities.Subscribe(md => bus.post(SparkTags.ServerSecuritiesTag, md)));
Task.Run(run);
}
}
}
+1 -11
View File
@@ -66,17 +66,7 @@ namespace bts {
}
private void _merge_and_post() {
Func<SecurityMD, bool> is_active = (sec_md) => {
if (sec_md.security.HasFuture || sec_md.security.HasOption) {
var exp = sec_md.security.security_expiration();
if (exp.HasValue) {
return exp.Value.Date >= DateTime.Now.Date.AddDays(-1);
}
return true;
}
return true;
};
var to_pub = _server_sec_map.Where(kv => is_active(kv.Value)).ToDictionary(kv => kv.Key, kv => kv.Value);
Dictionary<uint, SecurityMD> to_pub = new Dictionary<uint, SecurityMD>(_server_sec_map);
foreach (var kv in _fake_sec_map) {
to_pub[kv.Key] = kv.Value;
}
+13 -42
View File
@@ -5,7 +5,6 @@ using bts.spark;
using mbts;
using mbts.config;
using mbts.persist;
using mbts.spark;
using mbts.ui;
using mbts.ui.spark;
@@ -24,7 +23,6 @@ namespace bts.shell {
class OrderTicketDaemon : IShellDaemon {
readonly IBus _bus;
readonly OrdersModel _model;
readonly UserSettingsHub _settings_hub;
readonly ErrorReporter _error_reporter;
readonly bool _close_on_send;
IReadOnlyDictionary<uint, SecurityMD> _md_map;
@@ -32,13 +30,12 @@ namespace bts.shell {
IDisposable _dispose;
[ImportingConstructor]
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, ErrorReporter error_reporter)
: this(bus, model, settings_hub, error_reporter, Configuration.get<bts.config.OrderTicketOptions>().close_on_send) { }
public OrderTicketDaemon(IBus bus, OrdersModel model, ErrorReporter error_reporter)
: this(bus, model, error_reporter, Configuration.get<bts.config.OrderTicketOptions>().close_on_send) { }
public OrderTicketDaemon(IBus bus, OrdersModel model, UserSettingsHub settings_hub, ErrorReporter error_reporter, bool close_on_send) {
public OrderTicketDaemon(IBus bus, OrdersModel model, ErrorReporter error_reporter, bool close_on_send) {
_bus = bus;
_model = model;
_settings_hub = settings_hub;
_error_reporter = error_reporter;
_close_on_send = close_on_send;
_dispose = Disposable.Create(
@@ -65,39 +62,22 @@ namespace bts.shell {
window.Show(-200, -160, true);
}
void _show_order_ticket(SecurityMD smd) {
var settings_src = _settings_hub.subscribe_default_settings()
.Select(s => s.get_ladder_profile(smd.security)?.value ?? LadderSettings.Default);
void _show_order_ticket(SecurityMD smd) =>
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, settings_src) {
DataContext = new NewOrderTicketVM(_model, smd,
Observable.Return(LadderSettings.Default)) {
close_on_send = _close_on_send
}
});
}
void _show_order_ticket((OrderDefinitionImmutable def, double price, uint size) ops) {
var (def, price, size) = ops;
if (!_md_map.TryGetValue(def.SecurityKey, out SecurityMD smd)) {
return;
}
if (def.Account.is_null_or_empty() && def.AccountId == 0) {
var settings = _settings_hub.current.get_ladder_profile(smd.security);
var default_account = settings?.value?.default_account;
if (default_account.HasValue) {
var mdef = def.CloneToMutable();
// The order ticket will resolve AccountId to a name
mdef.AccountId = default_account.Value;
def = new(mdef);
}
}
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, def, price, size,
Observable.Return(LadderSettings.Default.calculator_buttons)) {
close_on_send = _close_on_send
}
});
if (_md_map.TryGetValue(ops.def.SecurityKey, out SecurityMD smd))
_show_order_window(new OrderTicket {
DataContext = new NewOrderTicketVM(_model, smd, ops.def, ops.price, ops.size,
Observable.Return(LadderSettings.Default.calculator_buttons)) {
close_on_send = _close_on_send
}
});
}
void _show_order_tickets(IImmutableSet<uint> securities) {
@@ -119,14 +99,5 @@ namespace bts.shell {
});
}
}
LadderSettings _get_settings(SecurityImmutable sec) {
var settings = _settings_hub.current;
if (settings.ladder_profiles.TryGetFirst(
lsp => lsp.security_criteria.includes(sec), out var lsp)) {
return lsp.value;
}
return null;
}
}
}
-172
View File
@@ -1,172 +0,0 @@
#nullable enable
namespace bts.daemons {
using bts.api;
using bts.api.analytics;
using bts.api.core;
using bts.api.orderman;
using bts.api.position;
using bts.spark;
using mbts;
using mbts.analytics;
using mbts.spark;
using mbts.ui;
using Spark.Core.Collections;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
[Export(typeof(IShellDaemon))]
public sealed class ReportDaemon : IShellDaemon, IDisposable {
readonly ConcurrentFactory<int, IDisposable> _report_calculators;
readonly AnalyticsService _analytics_service;
readonly PositionService _position_service;
readonly OrderService _order_service;
readonly ErrorReporter _error_reporter;
readonly IBus _bus;
IReadOnlyDictionary<int, ReportImmutable> _report_parameters_map =
new Dictionary<int, ReportImmutable>();
IDisposable _dispose;
[ImportingConstructor]
public ReportDaemon(
IBus bus,
AnalyticsService analytics_service,
PositionService position_service,
OrderService order_service,
ErrorReporter error_reporter
) {
_bus = bus;
_analytics_service = analytics_service;
_position_service = position_service;
_error_reporter = error_reporter;
_order_service = order_service;
_report_calculators = new(mk_report_calculator);
_dispose = Disposable.Create(
bus.subscribe(SparkTags.ReportBlackboardTags.Create).Subscribe(rp => _create_report(rp).ignore()),
bus.subscribe(SparkTags.ReportBlackboardTags.Save).Subscribe(rp => _save_report(rp).ignore()),
bus.subscribe(SparkTags.ReportBlackboardTags.Delete).Subscribe(id => _delete_report(id).ignore()),
bus.subscribe(SparkTags.ReportBlackboardTags.Activate).Subscribe(_activate_report),
bus.subscribe(SparkTags.ReportBlackboardTags.Deactivate).Subscribe(_deactivate_report),
_analytics_service.subscribei_reports().Table().Subscribe(_on_reports),
_bus.subscribe(SparkTags.SystemContractsTag).CombineLatest(
_order_service.subscribe_fills(), _position_service.subscribe_manual_fills())
.Subscribe(tup => _on_all_trade_data(tup.First, tup.Second, tup.Third)),
_report_calculators);
IDisposable mk_report_calculator(int id) {
if (!_report_parameters_map.TryGetValue(id, out var r)) {
Log.Gen.warn($"ReportDaemon failed to find report for id {id}");
return Disposable.empty;
}
Log.Gen.info(
$"Activating report calculator for {fmt_rep_title(r)}");
var calc = r.ReportType switch {
Report.Types.ReportType.Slide => new SlideReportCalculator(_bus, r),
Report.Types.ReportType.Combo => new ComboReportCalculator(
_bus, r, TimeSpan.FromSeconds(1)),
_ => Disposable.empty
};
return Disposable.Create(() => {
r = _report_parameters_map.GetValueOrDefault(id, r);
Log.Gen.info(
$"Deactivating report calculator for {fmt_rep_title(r)}");
Disposable.dispose(ref calc);
});
}
static string fmt_rep_title(ReportImmutable r) =>
$"{r.ReportType} '{r.ReportName}' (id: {r.Id})";
}
public void Dispose() =>
Disposable.dispose(ref _dispose);
void _on_reports(TableUpdate<ReportImmutable, int> reports) {
_report_parameters_map = reports.state;
// recreate calculators with new/changed parameters
foreach (var r in reports.added.Concat(reports.changes.New())) {
if (_report_calculators.Remove(r.Id)) {
_report_calculators.get_or_add(r.Id);
}
}
_bus.post(SparkTags.ReportBlackboardTags.ListTag, _report_parameters_map);
}
async Task _create_report(ReportImmutable report) {
Log.Gen.info($"Creating report: {report}");
var (new_id, success) = await _error_reporter.safe_execute(
() => _analytics_service.get_new_report_id_async(new VoidMessage()),
reply => reply.Ok,
reply => string.Empty,
"creating report");
var mreport = report.CloneToMutable();
mreport.Id = new_id.NewId;
report = new(mreport);
await _save_report(report);
}
Task _save_report(ReportImmutable report) {
Log.Gen.info($"Saving report: {report}");
return _error_reporter.safe_execute(
() => _analytics_service.save_report_async(report),
rm => rm.Success,
rm => rm.ErrorMessage,
"saving report");
}
Task _delete_report(int id) {
Log.Gen.info($"Deleting report: id={id}");
return _error_reporter.safe_execute(
() => _analytics_service.delete_report_async(
new IntWrapperImmutable(new() { Data = id })),
rm => rm.Success,
rm => rm.ErrorMessage,
"deleting report");
}
void _on_all_trade_data(
SystemContractData sc_data, Update<Fill, string> fills, Update<ManualFill, int> man_fills) {
if (sc_data is null) {
return;
}
var fills_filtered = fills.all.Where(f => sc_data.sec_md_map.ContainsKey(f.SecurityKey));
if (fills.all.Count() > fills_filtered.Count()) {
Log.Ui.error(
$"ReportDaemon {fills.all.Count() - fills_filtered.Count()} fills could not be " +
"resolved");
}
var man_fills_filtered = man_fills.all
.Where(m => sc_data.sec_md_map.ContainsKey(m.SecurityKey));
if (man_fills.all.Count() > man_fills_filtered.Count()) {
Log.Ui.error(
$"ReportDaemon {man_fills.all.Count() - man_fills_filtered.Count()} manual fills " +
"could not be resolved");
}
var fills_tl = fills_filtered.Select(
f => new TradeLogRow(f, sc_data.sec_md_map[f.SecurityKey].security));
var m_fills_tl = man_fills_filtered.Select(
m => new TradeLogRow(m, sc_data.sec_md_map[m.SecurityKey].security));
var merged_fills = fills_tl.Concat(m_fills_tl).ToList();
Log.Ui.info($"ReportDaemon posting {merged_fills.Count} trades");
_bus.post(SparkTags.TradeLogTag, merged_fills);
}
void _activate_report(int id) =>
_report_calculators.get_or_add(id);
void _deactivate_report(int id) =>
_report_calculators.Remove(id);
}
}
+279 -479
View File
@@ -1,479 +1,279 @@
using bts;
using bts.collections;
using bts.utils;
using mbts.ui.dpi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace mbts.ui {
public class Icons {
public static class Smashicons {
public static readonly string
AddFileGeometryKey = _fmt("AddFile"),
EditDocumentGeometryKey = _fmt("EditDocument"),
DeleteDocumentGeometryKey = _fmt("DeleteDocument"),
SaveGeometryKey = _fmt("Save");
static string _fmt(string name) =>
$"{nameof(Smashicons)}.{name}.GeometryKey";
}
public const string
AddBoxesGeometryKey = nameof(AddBoxesGeometryKey),
AddFileGeometryKey = nameof(AddFileGeometryKey),
AddFileThinGeometryKey = nameof(AddFileThinGeometryKey),
ArrowGeometryKey = nameof(ArrowGeometryKey),
AttachAlgosKey = nameof(AttachAlgosKey),
CallPutGeometryKey = nameof(CallPutGeometryKey),
CandidateGeometryKey = nameof(CandidateGeometryKey),
CandidateWithAudienceGeometryKey = nameof(CandidateWithAudienceGeometryKey),
CheckMarkGeometryKey = nameof(CheckMarkGeometryKey),
CopyWFGeometryKey = nameof(CopyWFGeometryKey),
CopyBoxesGeometryKey = nameof(CopyBoxesGeometryKey),
CurrencyExchangeGeometryKey = nameof(CurrencyExchangeGeometryKey),
DataEditGeometryKey = nameof(DataEditGeometryKey),
DetachAlgosKey = nameof(DetachAlgosKey),
DiskGeometryKey = nameof(DiskGeometryKey),
DiskFileGeometryKey = nameof(DiskFileGeometryKey),
DocumentGeometryKey = nameof(DocumentGeometryKey),
DocumentAddGeometryKey = nameof(DocumentAddGeometryKey),
DocumentBrokenGeometryKey = nameof(DocumentBrokenGeometryKey),
DocumentCopyGeometryKey = nameof(DocumentCopyGeometryKey),
DocumentEmptyGeometryKey = nameof(DocumentEmptyGeometryKey),
DocumentPairGeometryKey = nameof(DocumentPairGeometryKey),
DocumentStarGeometryKey = nameof(DocumentStarGeometryKey),
DraggableGeometryKey = nameof(DraggableGeometryKey),
EditDocumentAltGeometryKey = nameof(EditDocumentAltGeometryKey),
EditDocumentGeometryKey = nameof(EditDocumentGeometryKey),
VolCurveGeometryKey = nameof(VolCurveGeometryKey),
FinancialGrowthGeometryKey = nameof(FinancialGrowthGeometryKey),
GearGeometryKey = nameof(GearGeometryKey),
HamburgerMenuGeometryKey = nameof(HamburgerMenuGeometryKey),
HornGeometryKey = nameof(HornGeometryKey),
KeyGeometryKey = nameof(KeyGeometryKey),
LetterAKey = nameof(LetterAKey),
LetterDKey = nameof(LetterDKey),
MenuOrientationGeometryKey = nameof(MenuOrientationGeometryKey),
OrdersGeometryKey = nameof(OrdersGeometryKey),
PauseGeometryKey = nameof(PauseGeometryKey),
PaymentGeometryKey = nameof(PaymentGeometryKey),
PencilGeometryKey = nameof(PencilGeometryKey),
PlayGeometryKey = nameof(PlayGeometryKey),
ProhibitedGeometryKey = nameof(ProhibitedGeometryKey),
RubberStampGeometryKey = nameof(RubberStampGeometryKey),
RecurringScheduleGeometryKey = nameof(RecurringScheduleGeometryKey),
SpeakerGeometryKey = nameof(SpeakerGeometryKey),
StarGeometryKey = nameof(StarGeometryKey),
ToolsGeometryKey = nameof(ToolsGeometryKey),
TrashGeometryKey = nameof(TrashGeometryKey),
UndoCircularGeometryKey = nameof(UndoCircularGeometryKey),
WarningExclamationGeometryKey = nameof(WarningExclamationGeometryKey),
WarningGeometryKey = nameof(WarningGeometryKey);
public static Geometry PlayGeometry => Geometry.Parse(get_geometric_path(PlayGeometryKey).FirstOrDefault() ?? string.Empty);
static readonly Pen _copy_boxes_pen = new Pen(Brushes.Black, HighDpiExtensions.RoundLayoutValue(5)).frozen();
static readonly string base_uri = "pack://application:,,,/Images/Icons/";
private static ResourceDictionary _resources = (ResourceDictionary)Application.LoadComponent(new Uri("/Images/Vector/Icons.xaml", UriKind.RelativeOrAbsolute));
private static Uri uri(string filename) {
return new Uri(base_uri + filename);
}
[Obsolete("Please only add new vector icons using icons.xaml")]
private static ImageSource load_image(string filename) {
return new BitmapImage(uri(filename)).frozen();
}
private static ImageSource load_resource_and_freeze(string resource_name) {
lock (_resources) {
return ((DrawingImage)_resources[resource_name]).frozen();
}
}
#pragma warning disable CS0618 // Type or member is obsolete
public static ImageSource Logo { get { return load_image("logo.ico"); } }
public static ImageSource Admin { get { return load_resource_and_freeze("Admin"); } }
public static ImageSource Analytics { get { return load_resource_and_freeze("Analytics"); } }
public static ImageSource Sheets { get { return load_resource_and_freeze("Sheets"); } }
public static ImageSource Trades { get { return load_resource_and_freeze("Trades"); } }
public static ImageSource Depth { get { return load_resource_and_freeze("Depth"); } }
public static ImageSource Ladder { get { return load_resource_and_freeze("Ladder"); } }
public static ImageSource SheetsRed { get { return load_image("SheetsRed.png"); } }
public static ImageSource SheetsGreen { get { return load_image("SheetsGreen.png"); } }
public static ImageSource Spreads { get { return load_resource_and_freeze("Spreads"); } }
public static ImageSource BlueSpreads { get { return load_image("BlueSpread.ico"); } }
public static ImageSource Reports { get { return load_resource_and_freeze("Reports"); } }
public static ImageSource Risk { get { return load_resource_and_freeze("Risk"); } }
public static ImageSource Eye { get { return load_resource_and_freeze("Eye"); } }
public static ImageSource Coins { get { return load_resource_and_freeze("Coins"); } }
public static ImageSource DataCopy { get { return load_image("DataCopy.ico"); } }
public static ImageSource Refresh { get { return load_image("Refresh.png"); } }
public static ImageSource FavoriteWindow { get { return load_image("FavoriteWindow.png"); } }
public static ImageSource Browser => load_resource_and_freeze("Browser");
public static ImageSource Date { get { return load_image("Date.png"); } }
public static ImageSource Cube3d { get { return load_resource_and_freeze("Cube"); } }
public static ImageSource Algo { get { return Cube3d; } }
public static ImageSource Quote { get { return Math; } }
public static ImageSource Math { get { return load_resource_and_freeze("Surface"); } }
public static ImageSource Abacus { get { return load_image("Abacus.png"); } }
public static ImageSource Delete { get { return load_image("Delete.png"); } }
public static ImageSource Up_Arrow { get { return load_image("Arrowhead-Up.png"); } }
public static ImageSource Down_Arrow { get { return load_image("Arrowhead-Down.png"); } }
public static ImageSource Zoom_In { get { return load_image("Zoom-In.png"); } }
public static ImageSource Zoom_Out { get { return load_image("Zoom-Out.png"); } }
public static ImageSource InsertionArrow { get { return load_image("InsertionArrow.png"); } }
#pragma warning restore CS0618
// Vector icons
public static ImageSource Bookmarks { get { return load_resource_and_freeze("Bookmarks"); } }
public static ImageSource Window { get { return load_resource_and_freeze("Window"); } }
public static ImageSource ActiveWindow { get { return load_resource_and_freeze("ActiveWindow"); } }
public static ImageSource Crucible { get { return load_resource_and_freeze("Crucible"); } }
public static ImageSource Accounting { get { return load_resource_and_freeze("Accounting"); } }
public static ImageSource Add { get { return load_resource_and_freeze("Add"); } }
public static ImageSource AddBoxes => create_icon(AddBoxesGeometryKey);
public static ImageSource AddEncircled { get { return load_resource_and_freeze("AddEncircled"); } }
public static ImageSource AddFile => create_icon(Smashicons.AddFileGeometryKey);
public static ImageSource AttachAlgos => create_icon(AttachAlgosKey);
public static ImageSource Beaker { get { return load_resource_and_freeze("Beaker"); } }
public static ImageSource Book { get { return load_resource_and_freeze("Book"); } }
public static ImageSource Orders => create_icon(OrdersGeometryKey);
public static ImageSource AddOrders { get { return load_resource_and_freeze("AddOrders"); } }
public static ImageSource CancelOrders { get { return load_resource_and_freeze("CancelOrders"); } }
public static ImageSource CancelBuys { get { return load_resource_and_freeze("CancelBuys"); } }
public static ImageSource CancelSells { get { return load_resource_and_freeze("CancelSells"); } }
public static ImageSource CancelSelected { get { return load_resource_and_freeze("CancelSelected"); } }
public static ImageSource LadderCancelOrders { get { return load_resource_and_freeze("LadderCancelOrders"); } }
public static ImageSource LadderCancelBuys { get { return load_resource_and_freeze("LadderCancelBuys"); } }
public static ImageSource LadderCancelSells { get { return load_resource_and_freeze("LadderCancelSells"); } }
public static ImageSource Synthetics { get { return load_resource_and_freeze("Synthetics"); } }
public static ImageSource AddSynthetic { get { return load_resource_and_freeze("AddSynthetic"); } }
public static ImageSource RemoveSynthetic { get { return load_resource_and_freeze("RemoveSynthetic"); } }
public static ImageSource ModifySynthetic { get { return load_resource_and_freeze("ModifySynthetic"); } }
public static ImageSource CloneSynthetic { get { return load_resource_and_freeze("CloneSynthetic"); } }
public static ImageSource analytics => Math;
public static ImageSource ModifyOrder { get { return load_resource_and_freeze("ModifyOrder"); } }
public static ImageSource call_put => create_icon(CallPutGeometryKey);
public static ImageSource call_put_checked =>
create_checked_icon(
CallPutGeometryKey,
brush: Brushes.Black,
check_brush: Brushes.Black,
check_off_x_pct: 0.9);
public static ImageSource call_put_unchecked =>
create_checked_icon(
CallPutGeometryKey,
brush: Brushes.Black,
check_brush: Brushes.Transparent,
check_off_x_pct: 0.9);
public static ImageSource candidate => create_icon(CandidateGeometryKey);
public static ImageSource candidate_unchecked =>
create_checked_icon(CandidateGeometryKey, Brushes.Black, check_brush: Brushes.Transparent);
public static ImageSource candidate_checked =>
create_checked_icon(CandidateGeometryKey, Brushes.Black, check_brush: Brushes.Black);
public static ImageSource candidate_with_audience =>
create_icon(CandidateWithAudienceGeometryKey);
public static ImageSource CheckMark => create_icon(CheckMarkGeometryKey);
public static ImageSource ChevronRight => new DrawingImage(create_chevron_right_drawing());
public static ImageSource ChevronDown => new DrawingImage(create_chevron_down_drawing());
public static ImageSource Clock { get { return load_resource_and_freeze("Clock"); } }
public static ImageSource CopyWF => create_icon(CopyWFGeometryKey);
public static ImageSource CopyBoxes => create_icon(CopyBoxesGeometryKey, null, _copy_boxes_pen);
public static ImageSource CurrencyExchange => create_icon(CurrencyExchangeGeometryKey);
public static ImageSource DataEdit => create_icon(DataEditGeometryKey);
public static ImageSource Defrag { get { return load_resource_and_freeze("Defrag"); } }
public static ImageSource DetachAlgos => create_icon_and_rotate(DetachAlgosKey, Brushes.Red);
public static ImageSource Disk => create_icon(DiskGeometryKey);
public static ImageSource DiskFile => create_icon(DiskFileGeometryKey);
public static ImageSource Display { get { return load_resource_and_freeze("Display"); } }
public static ImageSource DocumentAdd => create_icon(DocumentAddGeometryKey);
public static ImageSource DocumentBroken => create_icon(DocumentBrokenGeometryKey);
public static ImageSource DocumentCopy => create_icon(DocumentCopyGeometryKey);
public static ImageSource DocumentEmpty => create_icon(DocumentEmptyGeometryKey);
public static ImageSource DocumentPair => create_icon(DocumentPairGeometryKey);
public static ImageSource DocumentStar => create_icon(DocumentStarGeometryKey);
public static ImageSource Draggable => create_icon(DraggableGeometryKey);
public static ImageSource EditDocument => create_icon("Smashicons.EditDocument.GeometryKey");
public static ImageSource VolCurve => create_icon(VolCurveGeometryKey);
public static ImageSource Export => load_resource_and_freeze("Export");
public static ImageSource Filter { get { return load_resource_and_freeze("Filter"); } }
public static ImageSource FilterActive { get { return load_resource_and_freeze("FilterActive"); } }
public static ImageSource FilterError { get { return load_resource_and_freeze("FilterError"); } }
public static ImageSource FinancialGrowth => create_icon(FinancialGrowthGeometryKey);
public static ImageSource FinancialGrowthGray => create_icon(FinancialGrowthGeometryKey, Brushes.Gray);
public static ImageSource Gear => create_icon(GearGeometryKey);
public static ImageSource HamburgerMenu => create_icon(HamburgerMenuGeometryKey);
public static ImageSource Horn => create_icon(HornGeometryKey);
public static ImageSource Import => load_resource_and_freeze("Import");
public static ImageSource Key => create_icon(KeyGeometryKey);
public static ImageSource Knight { get { return load_resource_and_freeze("Knight"); } }
public static ImageSource MenuOrientation => create_icon(MenuOrientationGeometryKey);
public static ImageSource options_view => Sheets;
public static ImageSource Pause => create_icon(PauseGeometryKey);
public static ImageSource Payment => create_icon(PaymentGeometryKey);
public static ImageSource Pencil => create_icon(PencilGeometryKey);
public static ImageSource Play => create_icon(PlayGeometryKey);
public static ImageSource Prohibited => create_icon(ProhibitedGeometryKey);
public static ImageSource RecurringSchedule => create_icon(RecurringScheduleGeometryKey);
public static ImageSource RecurringScheduleGray => create_icon(RecurringScheduleGeometryKey, Brushes.Gray);
public static ImageSource RubberStamp => create_icon(RubberStampGeometryKey);
public static ImageSource RedoCircular => create_icon(UndoCircularGeometryKey, Brushes.Black, null, new ScaleTransform(-1, 1));
public static ImageSource Spawn { get { return load_resource_and_freeze("Spawn"); } }
public static ImageSource Speaker => create_icon(SpeakerGeometryKey);
public static ImageSource Star => create_icon(StarGeometryKey);
public static ImageSource Target { get { return load_resource_and_freeze("Target"); } }
public static ImageSource Tetris { get { return load_resource_and_freeze("Tetris"); } }
public static ImageSource Tools => create_icon(ToolsGeometryKey);
public static ImageSource Trash => create_icon(TrashGeometryKey);
public static ImageSource Warning => create_icon(WarningGeometryKey, Brushes.IndianRed);
public static ImageSource WarningExclamation => create_icon(WarningExclamationGeometryKey, Brushes.IndianRed);
public static ImageSource UndoCircular => create_icon(UndoCircularGeometryKey);
public static ImageSource ViewSettings => load_resource_and_freeze("ViewSettings");
public static ImageSource vol_curve_unchecked => create_checked_icon(
VolCurveGeometryKey, Brushes.Black, null, Brushes.Transparent, null, check_off_x_pct: 0.8);
public static ImageSource vol_curve_checked => create_checked_icon(
VolCurveGeometryKey, Brushes.Black, null, Brushes.Black, null, check_off_x_pct: 0.8);
public static ImageSource vol_surface => Math;
public static ImageSource Wrench { get { return load_resource_and_freeze("Wrench"); } }
public static ImageSource RightArrow => create_icon(
ArrowGeometryKey, null, new(Brushes.Black, 3));
public static ImageSource DownArrow => create_icon(
ArrowGeometryKey, null, new(Brushes.Black, 3), new RotateTransform(90, 0.5, 0.5));
public static ImageSource Factory { get { return (load_resource_and_freeze("Factory")); } }
public static ImageSource DotsVertical { get { return (load_resource_and_freeze("DotsVertical")); } }
public static ImageSource HandPointingOverDocument => load_resource_and_freeze("HandPointingOverDocument");
public static ImageSource Support => load_resource_and_freeze("SupportIcon");
public static ImageSource FloppyDisk => create_icon("FloppyDisk");
static Brush _default_chevron_brush => null;
static Pen _default_chevron_pen { get; } = new Pen(Brushes.Black, 3).frozen();
public static ImageSource create_icon(string geometric_path_key) =>
create_icon(geometric_path_key, Brushes.Black);
public static ImageSource create_icon(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) {
var rv = new DrawingImage(create_drawing(geometric_path_key, brush, pen, transform));
rv.Freeze();
return rv;
}
public static ImageSource create_icon_and_rotate(string geometric_path_key, Brush brush = null, Pen pen = null, Transform transform = null, double degrees = 90) {
if (brush == null) {
brush = Brushes.Black;
}
var drawing = create_drawing(geometric_path_key, brush, pen, transform);
var dg = new DrawingGroup();
dg.Children.Add(drawing);
dg.Transform = new RotateTransform(degrees);
var rv = new DrawingImage(dg);
rv.Freeze();
return rv;
}
public static Drawing create_drawing(string geometric_path_key) =>
create_drawing(geometric_path_key, Brushes.Black);
public static Drawing create_drawing(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) =>
create_drawing(get_geometric_path(geometric_path_key), brush, pen, transform);
public static Drawing create_drawing(IEnumerable<string> paths, Brush brush, Pen pen = null, Transform transform = null) {
var drawing_group = new DrawingGroup();
foreach (string p in paths) {
drawing_group.Children.Add(new GeometryDrawing(brush, pen, Geometry.Parse(p)));
}
if (transform != null)
drawing_group.Transform = transform;
return drawing_group;
}
public static IEnumerable<string> get_geometric_path(string geometric_path_key) {
object obj;
lock (_resources) {
obj = _resources[geometric_path_key];
}
if (obj is string path) {
if (string.IsNullOrEmpty(path)) {
Log.Api.error($"Resource lookup of '{geometric_path_key}' did not return a valid string.", nameof(geometric_path_key));
path = string.Empty;
}
return new[] { path };
} else if (obj is string[] paths) {
return paths.Where(p => !string.IsNullOrEmpty(p)).ToArray();
} else return null;
}
public static Drawing create_chevron_right_drawing() =>
create_chevron_right_drawing(_default_chevron_brush, _default_chevron_pen);
public static Drawing create_chevron_right_drawing(Brush brush, Pen pen) {
var drawing_group = new DrawingGroup();
var (left, right) = create_chevron_right_geometry();
drawing_group.Children.Add(new GeometryDrawing(brush, pen, left));
drawing_group.Children.Add(new GeometryDrawing(brush, pen, right));
return drawing_group;
}
public static (Geometry left, Geometry right) create_chevron_right_geometry() {
var arrow_geometry_str = _resources[ArrowGeometryKey] as string ?? throw new InvalidOperationException();
// Must clone bc for some reason Geometry.Parse returns a frozen Geometry
var left = Geometry.Parse(arrow_geometry_str).Clone();
var right = left.Clone();
// bump 2nd arrow to the right
right.Transform = new TranslateTransform(24.0.RoundLayoutValue(), 0);
return (left, right);
}
public static Drawing create_chevron_down_drawing() =>
create_chevron_down_drawing(_default_chevron_brush, _default_chevron_pen);
public static Drawing create_chevron_down_drawing(Brush brush, Pen pen) {
// Transform arrow1 (left -> top), arrow2 (right -> bottom)
var (arrow1, arrow2) = create_chevron_right_geometry();
arrow1.Transform = new RotateTransform(90, 0.5, 0.5);
var arrow2_transform = new TransformGroup();
arrow2_transform.Children.Add(new RotateTransform(90, 0.5, 0.5));
arrow2_transform.Children.Add(new TranslateTransform(0, -24.0.RoundLayoutValue()));
arrow2.Transform = arrow2_transform;
var drawing_group = new DrawingGroup();
drawing_group.Children.Add(new GeometryDrawing(brush, pen, arrow1));
drawing_group.Children.Add(new GeometryDrawing(brush, pen, arrow2));
return drawing_group;
}
public static ImageSource create_checked_icon(string geometric_path_key) =>
create_checked_icon(get_geometric_path(geometric_path_key));
public static ImageSource create_checked_icon(
string geometric_path_key,
Brush brush = null,
Pen pen = null,
Brush check_brush = null,
Pen check_pen = null,
double check_size_ratio = 0.3,
double check_off_x_pct = 1,
double check_off_y_pct = 1) =>
create_checked_icon(
get_geometric_path(geometric_path_key), brush, pen, check_brush, check_pen,
check_size_ratio, check_off_x_pct, check_off_y_pct);
public static ImageSource create_checked_icon(IEnumerable<string> paths) =>
create_checked_icon(paths, Brushes.Black, null);
public static ImageSource create_checked_icon(
IEnumerable<string> paths, Brush brush, Pen pen) =>
create_checked_icon(paths, brush, pen, Brushes.Black, null);
public static ImageSource create_checked_icon(
IEnumerable<string> paths,
Brush brush,
Pen pen,
Brush check_brush,
Pen check_pen,
double check_size_ratio = 0.3,
double check_off_x_pct = 1,
double check_off_y_pct = 1) {
var drawing = create_checked_drawing(
paths, brush,
pen,
check_brush,
check_pen,
check_size_ratio,
check_off_x_pct,
check_off_y_pct);
var rv = new DrawingImage(drawing);
rv.Freeze();
return rv;
}
public static Drawing create_checked_drawing(IEnumerable<string> paths) =>
create_checked_drawing(paths, Brushes.Black, null, Brushes.Black, null);
/// <summary>
/// Create a <see cref="DrawingGroup"/> whose children are a 'main drawing' and a check-mark
/// drawing
/// </summary>
/// <param name="brush">
/// The <see cref="Brush"/> to use for the main <see cref="Drawing"/>
/// </param>
/// <param name="pen">
/// The <see cref="Pen"/> to use for the main <see cref="Drawing"/>
/// </param>
/// <param name="check_brush">
/// The <see cref="Brush"/> to use for the check-mark <see cref="Drawing"/>
/// </param>
/// <param name="check_pen">
/// The <see cref="Pen"/> to use for the check-mark <see cref="Drawing"/>
/// </param>
/// <param name="check_size_ratio">
/// The size ratio of the check-mark and main drawing
/// </param>
/// <param name="check_off_x_pct">
/// The check-mark horizontal offset, defined as a percentage of the main drawing's width
/// </param>
/// <param name="check_off_y_pct">
/// The check-mark vertical offset, defined as a percentage of the main drawing's height
/// </param>
public static DrawingGroup create_checked_drawing(
IEnumerable<string> main_drawing_paths,
Brush brush,
Pen pen,
Brush check_brush,
Pen check_pen,
double check_size_ratio = 0.3,
double check_off_x_pct = 1,
double check_off_y_pct = 1
) {
var main_drawing_group = new DrawingGroup();
main_drawing_group.Children.AddRange(
main_drawing_paths.Select(p => new GeometryDrawing(brush, pen, Geometry.Parse(p))));
var check_geometry = _check_mark_geometry().Clone();
var main_right = main_drawing_group.Bounds.Right;
var main_bottom = main_drawing_group.Bounds.Bottom;
var check_scale = (main_right / check_geometry.Bounds.Width)
.max(main_bottom / check_geometry.Bounds.Height);
var check_net_scale = check_size_ratio * check_scale;
var check_transform = new TransformGroup();
check_transform.Children.AddRange(
new ScaleTransform(check_net_scale, check_net_scale),
new TranslateTransform(main_right * check_off_x_pct, main_bottom * check_off_y_pct));
check_geometry.Transform = check_transform;
main_drawing_group.Children.Add(new GeometryDrawing(check_brush, check_pen, check_geometry));
return main_drawing_group;
}
static Geometry _check_mark_geometry() =>
Geometry.Parse(_resources[CheckMarkGeometryKey] as string ??
throw new InvalidOperationException());
}
}
using bts;
using mbts.ui.dpi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace mbts.ui {
public class Icons {
public static class Smashicons {
public static readonly string
AddFileGeometryKey = _fmt("AddFile"),
EditDocumentGeometryKey = _fmt("EditDocument"),
DeleteDocumentGeometryKey = _fmt("DeleteDocument"),
SaveGeometryKey = _fmt("Save");
static string _fmt(string name) =>
$"{nameof(Smashicons)}.{name}.GeometryKey";
}
public const string
AddBoxesGeometryKey = nameof(AddBoxesGeometryKey),
AddFileGeometryKey = nameof(AddFileGeometryKey),
AddFileThinGeometryKey = nameof(AddFileThinGeometryKey),
AttachAlgosKey = nameof(AttachAlgosKey),
CheckMarkGeometryKey = nameof(CheckMarkGeometryKey),
CopyWFGeometryKey = nameof(CopyWFGeometryKey),
CopyBoxesGeometryKey = nameof(CopyBoxesGeometryKey),
CurrencyExchangeGeometryKey = nameof(CurrencyExchangeGeometryKey),
DataEditGeometryKey = nameof(DataEditGeometryKey),
DetachAlgosKey = nameof(DetachAlgosKey),
DiskGeometryKey = nameof(DiskGeometryKey),
DiskFileGeometryKey = nameof(DiskFileGeometryKey),
DocumentGeometryKey = nameof(DocumentGeometryKey),
DocumentAddGeometryKey = nameof(DocumentAddGeometryKey),
DocumentBrokenGeometryKey = nameof(DocumentBrokenGeometryKey),
DocumentCopyGeometryKey = nameof(DocumentCopyGeometryKey),
DocumentEmptyGeometryKey = nameof(DocumentEmptyGeometryKey),
DocumentPairGeometryKey = nameof(DocumentPairGeometryKey),
DocumentStarGeometryKey = nameof(DocumentStarGeometryKey),
DraggableGeometryKey = nameof(DraggableGeometryKey),
EditDocumentAltGeometryKey = nameof(EditDocumentAltGeometryKey),
EditDocumentGeometryKey = nameof(EditDocumentGeometryKey),
GearGeometryKey = nameof(GearGeometryKey),
HamburgerMenuGeometryKey = nameof(HamburgerMenuGeometryKey),
HornGeometryKey = nameof(HornGeometryKey),
KeyGeometryKey = nameof(KeyGeometryKey),
LetterAKey = nameof(LetterAKey),
LetterDKey = nameof(LetterDKey),
MenuOrientationGeometryKey = nameof(MenuOrientationGeometryKey),
OrdersGeometryKey = nameof(OrdersGeometryKey),
PauseGeometryKey = nameof(PauseGeometryKey),
PaymentGeometryKey = nameof(PaymentGeometryKey),
PencilGeometryKey = nameof(PencilGeometryKey),
PlayGeometryKey = nameof(PlayGeometryKey),
ProhibitedGeometryKey = nameof(ProhibitedGeometryKey),
RubberStampGeometryKey = nameof(RubberStampGeometryKey),
SpeakerGeometryKey = nameof(SpeakerGeometryKey),
StarGeometryKey = nameof(StarGeometryKey),
ToolsGeometryKey = nameof(ToolsGeometryKey),
TrashGeometryKey = nameof(TrashGeometryKey),
UndoCircularGeometryKey = nameof(UndoCircularGeometryKey),
WarningExclamationGeometryKey = nameof(WarningExclamationGeometryKey),
WarningGeometryKey = nameof(WarningGeometryKey);
public static Geometry PlayGeometry => Geometry.Parse(get_geometric_path(PlayGeometryKey).FirstOrDefault() ?? string.Empty);
static readonly Pen _copy_boxes_pen = new Pen(Brushes.Black, HighDpiExtensions.RoundLayoutValue(5)).frozen();
static readonly string base_uri = "pack://application:,,,/Images/Icons/";
private static ResourceDictionary _resources = (ResourceDictionary)Application.LoadComponent(new Uri("/Images/Vector/Icons.xaml", UriKind.RelativeOrAbsolute));
private static Uri uri(string filename) {
return new Uri(base_uri + filename);
}
[Obsolete("Please only add new vector icons using icons.xaml")]
private static ImageSource load_image(string filename) {
return new BitmapImage(uri(filename)).frozen();
}
private static ImageSource load_resource_and_freeze(string resource_name) {
lock (_resources) {
return ((DrawingImage)_resources[resource_name]).frozen();
}
}
#pragma warning disable CS0618 // Type or member is obsolete
public static ImageSource Logo { get { return load_image("logo.ico"); } }
public static ImageSource Admin { get { return load_resource_and_freeze("Admin"); } }
public static ImageSource Analytics { get { return load_resource_and_freeze("Analytics"); } }
public static ImageSource Sheets { get { return load_resource_and_freeze("Sheets"); } }
public static ImageSource Trades { get { return load_resource_and_freeze("Trades"); } }
public static ImageSource Depth { get { return load_resource_and_freeze("Depth"); } }
public static ImageSource Ladder { get { return load_resource_and_freeze("Ladder"); } }
public static ImageSource SheetsRed { get { return load_image("SheetsRed.png"); } }
public static ImageSource SheetsGreen { get { return load_image("SheetsGreen.png"); } }
public static ImageSource Spreads { get { return load_resource_and_freeze("Spreads"); } }
public static ImageSource BlueSpreads { get { return load_image("BlueSpread.ico"); } }
public static ImageSource Reports { get { return load_resource_and_freeze("Reports"); } }
public static ImageSource Risk { get { return load_resource_and_freeze("Risk"); } }
public static ImageSource Eye { get { return load_resource_and_freeze("Eye"); } }
public static ImageSource Coins { get { return load_resource_and_freeze("Coins"); } }
public static ImageSource DataCopy { get { return load_image("DataCopy.ico"); } }
public static ImageSource Refresh { get { return load_image("Refresh.png"); } }
public static ImageSource FavoriteWindow { get { return load_image("FavoriteWindow.png"); } }
public static ImageSource Browser => load_resource_and_freeze("Browser");
public static ImageSource Date { get { return load_image("Date.png"); } }
public static ImageSource Cube3d { get { return load_resource_and_freeze("Cube"); } }
public static ImageSource Algo { get { return Cube3d; } }
public static ImageSource Quote { get { return Math; } }
public static ImageSource Math { get { return load_resource_and_freeze("Surface"); } }
public static ImageSource Abacus { get { return load_image("Abacus.png"); } }
public static ImageSource Delete { get { return load_image("Delete.png"); } }
public static ImageSource Up_Arrow { get { return load_image("Arrowhead-Up.png"); } }
public static ImageSource Down_Arrow { get { return load_image("Arrowhead-Down.png"); } }
public static ImageSource Zoom_In { get { return load_image("Zoom-In.png"); } }
public static ImageSource Zoom_Out { get { return load_image("Zoom-Out.png"); } }
public static ImageSource InsertionArrow { get { return load_image("InsertionArrow.png"); } }
#pragma warning restore CS0618
// Vector icons
public static ImageSource Bookmarks { get { return load_resource_and_freeze("Bookmarks"); } }
public static ImageSource Window { get { return load_resource_and_freeze("Window"); } }
public static ImageSource ActiveWindow { get { return load_resource_and_freeze("ActiveWindow"); } }
public static ImageSource Crucible { get { return load_resource_and_freeze("Crucible"); } }
public static ImageSource Accounting { get { return load_resource_and_freeze("Accounting"); } }
public static ImageSource Add { get { return load_resource_and_freeze("Add"); } }
public static ImageSource AddBoxes => create_icon(AddBoxesGeometryKey);
public static ImageSource AddEncircled { get { return load_resource_and_freeze("AddEncircled"); } }
public static ImageSource AddFile => create_icon(Smashicons.AddFileGeometryKey);
public static ImageSource AttachAlgos => create_icon(AttachAlgosKey);
public static ImageSource Beaker { get { return load_resource_and_freeze("Beaker"); } }
public static ImageSource Book { get { return load_resource_and_freeze("Book"); } }
public static ImageSource Orders => create_icon(OrdersGeometryKey);
public static ImageSource AddOrders { get { return load_resource_and_freeze("AddOrders"); } }
public static ImageSource CancelOrders { get { return load_resource_and_freeze("CancelOrders"); } }
public static ImageSource CancelBuys { get { return load_resource_and_freeze("CancelBuys"); } }
public static ImageSource CancelSells { get { return load_resource_and_freeze("CancelSells"); } }
public static ImageSource CancelSelected { get { return load_resource_and_freeze("CancelSelected"); } }
public static ImageSource LadderCancelOrders { get { return load_resource_and_freeze("LadderCancelOrders"); } }
public static ImageSource LadderCancelBuys { get { return load_resource_and_freeze("LadderCancelBuys"); } }
public static ImageSource LadderCancelSells { get { return load_resource_and_freeze("LadderCancelSells"); } }
public static ImageSource Synthetics { get { return load_resource_and_freeze("Synthetics"); } }
public static ImageSource AddSynthetic { get { return load_resource_and_freeze("AddSynthetic"); } }
public static ImageSource RemoveSynthetic { get { return load_resource_and_freeze("RemoveSynthetic"); } }
public static ImageSource ModifySynthetic { get { return load_resource_and_freeze("ModifySynthetic"); } }
public static ImageSource CloneSynthetic { get { return load_resource_and_freeze("CloneSynthetic"); } }
public static ImageSource analytics => Math;
public static ImageSource ModifyOrder { get { return load_resource_and_freeze("ModifyOrder"); } }
public static ImageSource CheckMark => create_icon(CheckMarkGeometryKey);
public static ImageSource Clock { get { return load_resource_and_freeze("Clock"); } }
public static ImageSource CopyWF => create_icon(CopyWFGeometryKey);
public static ImageSource CopyBoxes => create_icon(CopyBoxesGeometryKey, null, _copy_boxes_pen);
public static ImageSource CurrencyExchange => create_icon(CurrencyExchangeGeometryKey);
public static ImageSource DataEdit => create_icon(DataEditGeometryKey);
public static ImageSource Defrag { get { return load_resource_and_freeze("Defrag"); } }
public static ImageSource DetachAlgos => create_icon_and_rotate(DetachAlgosKey, Brushes.Red);
public static ImageSource Disk => create_icon(DiskGeometryKey);
public static ImageSource DiskFile => create_icon(DiskFileGeometryKey);
public static ImageSource Display { get { return load_resource_and_freeze("Display"); } }
public static ImageSource DocumentAdd => create_icon(DocumentAddGeometryKey);
public static ImageSource DocumentBroken => create_icon(DocumentBrokenGeometryKey);
public static ImageSource DocumentCopy => create_icon(DocumentCopyGeometryKey);
public static ImageSource DocumentEmpty => create_icon(DocumentEmptyGeometryKey);
public static ImageSource DocumentPair => create_icon(DocumentPairGeometryKey);
public static ImageSource DocumentStar => create_icon(DocumentStarGeometryKey);
public static ImageSource Draggable => create_icon(DraggableGeometryKey);
public static ImageSource EditDocument => create_icon("Smashicons.EditDocument.GeometryKey");
public static ImageSource Export => load_resource_and_freeze("Export");
public static ImageSource Filter { get { return load_resource_and_freeze("Filter"); } }
public static ImageSource FilterActive { get { return load_resource_and_freeze("FilterActive"); } }
public static ImageSource FilterError { get { return load_resource_and_freeze("FilterError"); } }
public static ImageSource Gear => create_icon(GearGeometryKey);
public static ImageSource HamburgerMenu => create_icon(HamburgerMenuGeometryKey);
public static ImageSource Horn => create_icon(HornGeometryKey);
public static ImageSource Import => load_resource_and_freeze("Import");
public static ImageSource Key => create_icon(KeyGeometryKey);
public static ImageSource Knight { get { return load_resource_and_freeze("Knight"); } }
public static ImageSource MenuOrientation => create_icon(MenuOrientationGeometryKey);
public static ImageSource options_view => Sheets;
public static ImageSource Pause => create_icon(PauseGeometryKey);
public static ImageSource Payment => create_icon(PaymentGeometryKey);
public static ImageSource Pencil => create_icon(PencilGeometryKey);
public static ImageSource Play => create_icon(PlayGeometryKey);
public static ImageSource Prohibited => create_icon(ProhibitedGeometryKey);
public static ImageSource RubberStamp => create_icon(RubberStampGeometryKey);
public static ImageSource RedoCircular => create_icon(UndoCircularGeometryKey, Brushes.Black, null, new ScaleTransform(-1, 1));
public static ImageSource Spawn { get { return load_resource_and_freeze("Spawn"); } }
public static ImageSource Speaker => create_icon(SpeakerGeometryKey);
public static ImageSource Star => create_icon(StarGeometryKey);
public static ImageSource Target { get { return load_resource_and_freeze("Target"); } }
public static ImageSource Tetris { get { return load_resource_and_freeze("Tetris"); } }
public static ImageSource Tools => create_icon(ToolsGeometryKey);
public static ImageSource Trash => create_icon(TrashGeometryKey);
public static ImageSource Warning => create_icon(WarningGeometryKey, Brushes.IndianRed);
public static ImageSource WarningExclamation => create_icon(WarningExclamationGeometryKey, Brushes.IndianRed);
public static ImageSource UndoCircular => create_icon(UndoCircularGeometryKey);
public static ImageSource ViewSettings => load_resource_and_freeze("ViewSettings");
public static ImageSource vol_surface => Math;
public static ImageSource Wrench { get { return load_resource_and_freeze("Wrench"); } }
public static ImageSource RightArrow { get { return (load_resource_and_freeze("RightArrow")); } }
public static ImageSource DownArrow { get { return (load_resource_and_freeze("DownArrow")); } }
public static ImageSource Factory { get { return (load_resource_and_freeze("Factory")); } }
public static ImageSource DotsVertical { get { return (load_resource_and_freeze("DotsVertical")); } }
public static ImageSource HandPointingOverDocument => load_resource_and_freeze("HandPointingOverDocument");
public static ImageSource Support => load_resource_and_freeze("SupportIcon");
public static ImageSource FloppyDisk => create_icon("FloppyDisk");
public static ImageSource create_icon(string geometric_path_key) =>
create_icon(geometric_path_key, Brushes.Black);
public static ImageSource create_icon(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) {
var rv = new DrawingImage(create_drawing(geometric_path_key, brush, pen, transform));
rv.Freeze();
return rv;
}
public static ImageSource create_icon_and_rotate(string geometric_path_key, Brush brush = null, Pen pen = null, Transform transform = null, double degrees = 90) {
if (brush == null) {
brush = Brushes.Black;
}
var drawing = create_drawing(geometric_path_key, brush, pen, transform);
var dg = new DrawingGroup();
dg.Children.Add(drawing);
dg.Transform = new RotateTransform(degrees);
var rv = new DrawingImage(dg);
rv.Freeze();
return rv;
}
public static Drawing create_drawing(string geometric_path_key) =>
create_drawing(geometric_path_key, Brushes.Black);
public static Drawing create_drawing(string geometric_path_key, Brush brush, Pen pen = null, Transform transform = null) =>
create_drawing(get_geometric_path(geometric_path_key), brush, pen, transform);
public static Drawing create_drawing(IEnumerable<string> paths, Brush brush, Pen pen = null, Transform transform = null) {
var drawing_group = new DrawingGroup();
foreach (string p in paths) {
drawing_group.Children.Add(new GeometryDrawing(brush, pen, Geometry.Parse(p)));
}
if (transform != null)
drawing_group.Transform = transform;
return drawing_group;
}
public static IEnumerable<string> get_geometric_path(string geometric_path_key) {
object obj;
lock (_resources) {
obj = _resources[geometric_path_key];
}
if (obj is string path) {
if (string.IsNullOrEmpty(path)) {
Log.Api.error($"Resource lookup of '{geometric_path_key}' did not return a valid string.", nameof(geometric_path_key));
path = string.Empty;
}
return new[] { path };
} else if (obj is string[] paths) {
return paths.Where(p => !string.IsNullOrEmpty(p)).ToArray();
} else return null;
}
}
}
+4 -75
View File
@@ -166,22 +166,6 @@
</sys:String>
</x:Array>
<!-- Icon by <a href="https://freeicons.io/profile/6156">Reda</a> on <a href="https://freeicons.io">freeicons.io</a> -->
<x:Array x:Key="{x:Static mbts:Icons.RecurringScheduleGeometryKey}" Type="sys:String">
<sys:String>
M69.66,4.05c0-2.23,2.2-4.05,4.94-4.05c2.74,0,4.94,1.81,4.94,4.05v17.72c0,2.23-2.2,4.05-4.94,4.05 c-2.74,0-4.94-1.81-4.94-4.05V4.05L69.66,4.05z M91.37,57.03c4.26,0,8.33,0.85,12.05,2.39c3.87,1.6,7.34,3.94,10.24,6.84 c2.9,2.9,5.24,6.38,6.84,10.23c1.54,3.72,2.39,7.79,2.39,12.05c0,4.26-0.85,8.33-2.39,12.05c-1.6,3.87-3.94,7.34-6.84,10.24 c-2.9,2.9-6.38,5.24-10.23,6.84c-3.72,1.54-7.79,2.39-12.05,2.39c-4.26,0-8.33-0.85-12.05-2.39c-3.87-1.6-7.34-3.94-10.24-6.84 c-2.9-2.9-5.24-6.38-6.84-10.24c-1.54-3.72-2.39-7.79-2.39-12.05c0-4.26,0.85-8.33,2.39-12.05c1.6-3.87,3.94-7.34,6.84-10.24 c2.9-2.9,6.38-5.24,10.23-6.84C83.04,57.88,87.1,57.03,91.37,57.03L91.37,57.03z M89.01,75.37c0-0.76,0.31-1.45,0.81-1.95l0,0l0,0 c0.5-0.5,1.19-0.81,1.96-0.81c0.77,0,1.46,0.31,1.96,0.81c0.5,0.5,0.81,1.19,0.81,1.96v14.74l11.02,6.54l0.09,0.06 c0.61,0.39,1.01,0.98,1.17,1.63c0.17,0.68,0.09,1.42-0.28,2.06l-0.02,0.03c-0.02,0.04-0.04,0.07-0.07,0.1 c-0.39,0.6-0.98,1-1.62,1.16c-0.68,0.17-1.42,0.09-2.06-0.28l-12.32-7.29c-0.43-0.23-0.79-0.58-1.05-0.99 c-0.26-0.42-0.41-0.91-0.41-1.43h0L89.01,75.37L89.01,75.37L89.01,75.37z M109.75,70.16c-2.4-2.4-5.26-4.33-8.43-5.64 c-3.06-1.27-6.42-1.96-9.95-1.96s-6.89,0.7-9.95,1.96c-3.17,1.31-6.03,3.24-8.43,5.64c-2.4,2.4-4.33,5.26-5.64,8.43 c-1.27,3.06-1.96,6.42-1.96,9.95c0,3.53,0.7,6.89,1.96,9.95c1.31,3.17,3.24,6.03,5.64,8.43c2.4,2.4,5.26,4.33,8.43,5.64 c3.06,1.27,6.42,1.96,9.95,1.96s6.89-0.7,9.95-1.96c3.17-1.31,6.03-3.24,8.43-5.64c4.71-4.71,7.61-11.2,7.61-18.38 c0-3.53-0.7-6.89-1.96-9.95C114.08,75.42,112.15,72.56,109.75,70.16L109.75,70.16z M13.45,57.36c-0.28,0-0.53-1.23-0.53-2.74 c0-1.51,0.22-2.73,0.53-2.73h13.48c0.28,0,0.53,1.23,0.53,2.73c0,1.51-0.22,2.74-0.53,2.74H13.45L13.45,57.36z M34.94,57.36 c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.73,0.53-2.73h13.48c0.28,0,0.53,1.23,0.53,2.73c0,1.51-0.22,2.74-0.53,2.74H34.94 L34.94,57.36z M56.43,57.36c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.73,0.53-2.73h13.48c0.28,0,0.53,1.22,0.53,2.72 c-1.35,0.84-2.65,1.76-3.89,2.75H56.43L56.43,57.36z M13.48,73.04c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.74,0.53-2.74h13.48 c0.28,0,0.53,1.23,0.53,2.74c0,1.51-0.22,2.74-0.53,2.74H13.48L13.48,73.04z M34.97,73.04c-0.28,0-0.53-1.23-0.53-2.74 c0-1.51,0.22-2.74,0.53-2.74h13.48c0.28,0,0.53,1.23,0.53,2.74c0,1.51-0.22,2.74-0.53,2.74H34.97L34.97,73.04z M13.51,88.73 c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.74,0.53-2.74h13.48c0.28,0,0.53,1.23,0.53,2.74c0,1.51-0.22,2.74-0.53,2.74H13.51 L13.51,88.73z M35,88.73c-0.28,0-0.53-1.23-0.53-2.74c0-1.51,0.22-2.74,0.53-2.74h13.48c0.28,0,0.53,1.23,0.53,2.74 c0,1.51-0.22,2.74-0.53,2.74H35L35,88.73z M25.29,4.05c0-2.23,2.2-4.05,4.94-4.05c2.74,0,4.94,1.81,4.94,4.05v17.72 c0,2.23-2.21,4.05-4.94,4.05c-2.74,0-4.94-1.81-4.94-4.05V4.05L25.29,4.05z M5.44,38.74h94.08v-20.4c0-0.7-0.28-1.31-0.73-1.76 c-0.45-0.45-1.09-0.73-1.76-0.73h-9.02c-1.51,0-2.74-1.23-2.74-2.74c0-1.51,1.23-2.74,2.74-2.74h9.02c2.21,0,4.19,0.89,5.64,2.34 c1.45,1.45,2.34,3.43,2.34,5.64v32.39c-1.8-0.62-3.65-1.12-5.55-1.49v-5.06h0.06H5.44v52.83c0,0.7,0.28,1.31,0.73,1.76 c0.45,0.45,1.09,0.73,1.76,0.73h44.71c0.51,1.9,1.15,3.75,1.92,5.53H7.98c-2.2,0-4.19-0.89-5.64-2.34C0.89,101.26,0,99.28,0,97.07 V18.36c0-2.2,0.89-4.19,2.34-5.64c1.45-1.45,3.43-2.34,5.64-2.34h9.63c1.51,0,2.74,1.23,2.74,2.74c0,1.51-1.23,2.74-2.74,2.74H7.98 c-0.7,0-1.31,0.28-1.76,0.73c-0.45,0.45-0.73,1.09-0.73,1.76v20.4H5.44L5.44,38.74z M43.07,15.85c-1.51,0-2.74-1.23-2.74-2.74 c0-1.51,1.23-2.74,2.74-2.74h18.36c1.51,0,2.74,1.23,2.74,2.74c0,1.51-1.23,2.74-2.74,2.74H43.07L43.07,15.85z
</sys:String>
</x:Array>
<!-- Icon by <a href="https://freeicons.io/profile/75801">Hilmy Abiyyu Asad</a> on <a href="https://freeicons.io">freeicons.io</a> -->
<x:Array x:Key="{x:Static mbts:Icons.FinancialGrowthGeometryKey}" Type="sys:String">
<sys:String>
M29,25H27V13a2,2,0,0,0-2-2H23a2,2,0,0,0-2,2V25H19V16a2,2,0,0,0-2-2H15a2,2,0,0,0-2,2v9H11V19a2,2,0,0,0-2-2H7a2,2,0,0,0-2,2v6H3a1,1,0,0,0,0,2H29a1,1,0,0,0,0-2ZM7,25V19H9v6Zm8,0V16h2v9Zm8,0V13h2V25Z
</sys:String>
<sys:String>
M5,15a1,1,0,0,0,.346-.062L24.062,8.052l-.241.513a1,1,0,1,0,1.811.849L26.905,6.7a1,1,0,0,0-.481-1.33L23.707,4.094a1,1,0,0,0-.848,1.812l.547.256-18.752,6.9A1,1,0,0,0,5,15Z
</sys:String>
</x:Array>
<!--File (the icon is free to use if we include this information in our credit section)
Source: https://www.flaticon.com/authors/freepik
Ttile: File free icon
@@ -404,55 +388,6 @@
c-84.15,0-153-68.85-153-153h-51c0,112.2,91.8,204,204,204s204-91.8,204-204S360.825,89.25,248.625,89.25z
</sys:String>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<x:Array x:Key="{x:Static mbts:Icons.VolCurveGeometryKey}" Type="sys:String">
<sys:String>
M952.6,30.6C893.8,30.6,842.2,49.2,799,86c-36.8,31.3-67,75.1-92.4,133.7c-44.4,102.4-65.7,230.7-86.2,354.7C594.3,731.8,567.3,894.6,500,894.6c-24.3,0-60.5-10.5-94.2-101.6c-26.3-71.2-41.6-166-56.4-257.8C337,457.9,325.2,384.9,307.3,329c-10.5-32.8-22.5-57.5-36.6-75.4c-24.8-31.5-53-38.1-72.4-38.1c-27.9,0-54.2,11.6-76.2,33.6c-17.3,17.3-32.1,40.7-45.4,71.5c-20.1,46.8-36,111.1-47.4,190.9C10.2,644.7,10,775.4,10,780.9h0c0,0.2,0,0.3,0,0.5c0,20.7,16.8,37.4,37.4,37.4c20.7,0,37.4-16.8,37.4-37.4c0-0.5,0-1,0-1.5c0.1-12.6,1.1-136.5,18.6-258.3c10.5-73.2,24.7-131,42.1-171.6c9.6-22.3,29.1-59.6,52.8-59.6c1.7,0,6.2,0,13.7,9.5c8.4,10.7,16.5,28.1,24.2,52c16.2,50.5,27.5,120.8,39.5,195.3c15.3,95.3,31.2,193.8,60.1,271.8c16.7,45.2,36.2,79.2,59.6,103.8c29.4,31,64.7,46.7,104.7,46.7c34.4,0,64.5-13.7,89.5-40.8c19.5-21.2,35.9-50.6,49.9-90c24.2-67.8,39.1-157.3,54.8-252c19.8-119.5,40.3-243.2,81.1-337.2c42.4-97.8,98.4-143.6,176.1-144c0.4,0,0.8,0,1.2,0c20.7,0,37.4-16.7,37.4-37.4C990,47.4,973.3,30.6,952.6,30.6z
</sys:String>
</x:Array>
<x:Array x:Key="{x:Static mbts:Icons.CandidateGeometryKey}" Type="sys:String">
<sys:String>
m350.17 14.219c24.742 0.21484 44.621 20.449 44.402 45.191-0.21484 24.742-20.449 44.625-45.191 44.406-24.742-0.21484-44.625-20.449-44.406-45.191 0.21875-24.746 20.449-44.625 45.195-44.406
</sys:String>
<sys:String>
m235.2 92.961c8.9609 28 30.238 49.84 57.68 59.922 3.3594 1.1211 6.7188 1.6797 10.078 2.8008v54.32h92.961v-54.32c3.3594-1.1211 6.7188-1.6797 10.641-2.8008 27.441-10.078 48.719-31.922 57.68-59.922l10.641-32.48c3.3594-11.199-2.8008-22.961-13.441-26.879-11.199-3.3594-22.961 2.8008-26.879 13.441l-10.641 32.48c-5.0391 15.68-16.801 28-31.922 33.602-7.2812 2.8008-14.559 3.9219-22.398 3.9219h-40.32c-7.8398 0-15.121-1.1211-22.398-3.9219-15.121-5.6016-26.879-17.922-31.922-33.602l-10.641-32.48c-3.3594-11.199-15.68-17.359-26.879-13.441-11.199 3.3594-17.359 15.68-13.441 26.879z
</sys:String>
<sys:String>
m465.92 271.6c3.9219 0 7.2812-3.3594 7.2812-7.2812v-25.762c0-3.9219-3.3594-7.2812-7.2812-7.2812l-231.84 0.003906c-3.9219 0-7.2812 3.3594-7.2812 7.2812v25.762c0 3.9219 3.3594 7.2812 7.2812 7.2812h30.801v60.48c0 3.9219 3.3594 7.2812 7.2812 7.2812h156.8c3.9219 0 7.2812-3.3594 7.2812-7.2812l-0.003907-60.484z
</sys:String>
</x:Array>
<x:Array x:Key="{x:Static mbts:Icons.CandidateWithAudienceGeometryKey}" Type="sys:String">
<sys:String>
m350.17 14.219c24.742 0.21484 44.621 20.449 44.402 45.191-0.21484 24.742-20.449 44.625-45.191 44.406-24.742-0.21484-44.625-20.449-44.406-45.191 0.21875-24.746 20.449-44.625 45.195-44.406
</sys:String>
<sys:String>
m235.2 92.961c8.9609 28 30.238 49.84 57.68 59.922 3.3594 1.1211 6.7188 1.6797 10.078 2.8008v54.32h92.961v-54.32c3.3594-1.1211 6.7188-1.6797 10.641-2.8008 27.441-10.078 48.719-31.922 57.68-59.922l10.641-32.48c3.3594-11.199-2.8008-22.961-13.441-26.879-11.199-3.3594-22.961 2.8008-26.879 13.441l-10.641 32.48c-5.0391 15.68-16.801 28-31.922 33.602-7.2812 2.8008-14.559 3.9219-22.398 3.9219h-40.32c-7.8398 0-15.121-1.1211-22.398-3.9219-15.121-5.6016-26.879-17.922-31.922-33.602l-10.641-32.48c-3.3594-11.199-15.68-17.359-26.879-13.441-11.199 3.3594-17.359 15.68-13.441 26.879z
</sys:String>
<sys:String>
m210.56 468.16h-31.359c-24.641 0-45.359 17.922-48.719 42.559l-3.3594 23.52c-1.1211 6.1602 3.9219 11.762 10.078 11.762h114.24c6.1602 0 11.199-5.6016 10.078-11.762l-3.3594-23.52c-2.7969-24.078-23.516-42.559-47.598-42.559z
</sys:String>
<sys:String>
m239.12 411.6c0 24.43-19.809 44.238-44.242 44.238s-44.238-19.809-44.238-44.238c0-24.434 19.805-44.242 44.238-44.242s44.242 19.809 44.242 44.242
</sys:String>
<sys:String>
m365.68 468.16h-31.359c-24.641 0-45.359 17.922-48.719 42.559l-2.8008 23.52c-1.1211 6.1602 3.9219 11.762 10.078 11.762h114.24c6.1602 0 11.199-5.6016 10.078-11.762l-3.3594-23.52c-2.7969-24.078-23.516-42.559-48.156-42.559z
</sys:String>
<sys:String>
m394.24 411.6c0 24.43-19.805 44.238-44.238 44.238s-44.238-19.809-44.238-44.238c0-24.434 19.805-44.242 44.238-44.242s44.238 19.809 44.238 44.242
</sys:String>
<sys:String>
m569.52 510.72c-3.3594-24.078-24.078-42.559-48.719-42.559h-31.359c-24.641 0-45.359 17.922-48.719 42.559l-3.3594 23.52c-1.1211 6.1602 3.9219 11.762 10.078 11.762h114.24c6.1602 0 11.199-5.6016 10.078-11.762z
</sys:String>
<sys:String>
m549.36 411.6c0 24.43-19.805 44.238-44.238 44.238s-44.242-19.809-44.242-44.238c0-24.434 19.809-44.242 44.242-44.242s44.238 19.809 44.238 44.242
</sys:String>
<sys:String>
m465.92 271.6c3.9219 0 7.2812-3.3594 7.2812-7.2812v-25.762c0-3.9219-3.3594-7.2812-7.2812-7.2812l-231.84 0.003906c-3.9219 0-7.2812 3.3594-7.2812 7.2812v25.762c0 3.9219 3.3594 7.2812 7.2812 7.2812h30.801v60.48c0 3.9219 3.3594 7.2812 7.2812 7.2812h156.8c3.9219 0 7.2812-3.3594 7.2812-7.2812l-0.003907-60.484z
</sys:String>
</x:Array>
<sys:String x:Key="{x:Static mbts:Icons.WarningExclamationGeometryKey}">
M15.998999,17.988002C16.551,17.988002 16.999,18.437009 16.999,18.990018 16.999,19.543027 16.551,19.992034 15.998999,19.992034 15.446999,19.992034 14.998999,19.543027 14.998999,18.990018 14.998999,18.437009 15.446999,17.988002 15.998999,17.988002z
M15.998999,8.0630169C16.552,8.0630169,16.999,8.5110159,16.999,9.0650149L16.999,16.167001C16.999,16.721 16.552,17.168998 15.998999,17.168998 15.446,17.168998 14.998999,16.721 14.998999,16.167001L14.998999,9.0650149C14.998999,8.5110159,15.446,8.0630169,15.998999,8.0630169z
@@ -465,12 +400,6 @@
M15.999513,0C16.50052,-3.8678991E-07,17.001274,0.21826346,17.288297,0.65479128L31.74151,22.585975C32.057495,23.064982 32.084472,23.677966 31.812494,24.184989 31.541494,24.687009 31.02049,24.999999 30.450475,24.999999L1.5480773,24.999999C0.97903845,24.999999 0.45705819,24.687009 0.18703459,24.184989 -0.085979476,23.677966 -0.057963934,23.064982 0.25704309,22.585975L14.709219,0.65479128C14.997247,0.21826346,15.498506,-3.8678991E-07,15.999513,0z
</sys:String>
<x:Array x:Key="{x:Static mbts:Icons.CallPutGeometryKey}" Type="sys:String">
<sys:String>
M 11.736 2.328 L 11.04 4.248 Q 10.296 3.888 9.516 3.672 Q 8.846 3.486 7.972 3.46 A 9.769 9.769 0 0 0 7.68 3.456 A 5.081 5.081 0 0 0 5.783 3.805 A 4.795 4.795 0 0 0 4.932 4.248 A 5.08 5.08 0 0 0 3.404 5.827 A 6.475 6.475 0 0 0 3.024 6.528 Q 2.383 7.9 2.332 9.802 A 12.382 12.382 0 0 0 2.328 10.128 A 10.047 10.047 0 0 0 2.476 11.893 A 7.423 7.423 0 0 0 3.012 13.656 A 6.163 6.163 0 0 0 3.873 15.055 A 5.142 5.142 0 0 0 4.908 16.008 A 4.729 4.729 0 0 0 7.583 16.847 A 5.734 5.734 0 0 0 7.68 16.848 A 8.092 8.092 0 0 0 8.633 16.795 Q 9.227 16.724 9.72 16.56 Q 10.584 16.272 11.4 15.816 L 12.096 17.712 A 9.015 9.015 0 0 1 11.017 18.203 A 11.495 11.495 0 0 1 10.068 18.516 Q 9.002 18.819 7.61 18.839 A 13.78 13.78 0 0 1 7.416 18.84 Q 5.232 18.84 3.552 17.796 A 6.864 6.864 0 0 1 1.182 15.289 A 8.38 8.38 0 0 1 0.936 14.82 A 9.027 9.027 0 0 1 0.192 12.488 Q 0.006 11.464 0 10.299 A 15.082 15.082 0 0 1 0 10.224 Q 0 7.656 0.948 5.676 Q 1.896 3.696 3.636 2.58 A 7.049 7.049 0 0 1 6.679 1.521 A 8.95 8.95 0 0 1 7.704 1.464 A 10.953 10.953 0 0 1 8.918 1.528 A 8.448 8.448 0 0 1 9.888 1.692 A 9.174 9.174 0 0 1 11.682 2.303 A 8.552 8.552 0 0 1 11.736 2.328 Z M 28.296 18.552 L 26.016 18.552 L 26.016 1.8 Q 27 1.68 28.188 1.62 A 48.193 48.193 0 0 1 30.331 1.561 A 53.263 53.263 0 0 1 30.648 1.56 Q 32.736 1.56 34.2 2.22 A 5.906 5.906 0 0 1 35.42 2.947 A 4.65 4.65 0 0 1 36.432 4.032 Q 37.2 5.184 37.2 6.672 A 6.062 6.062 0 0 1 37.03 8.141 A 4.624 4.624 0 0 1 36.312 9.72 A 5.355 5.355 0 0 1 34.5 11.311 A 6.736 6.736 0 0 1 33.84 11.628 A 8.346 8.346 0 0 1 31.899 12.162 A 11.327 11.327 0 0 1 30.168 12.288 A 24.966 24.966 0 0 1 29.08 12.265 A 19.903 19.903 0 0 1 28.296 12.216 L 28.296 18.552 Z M 22.728 0.6 L 15.96 20.256 L 14.184 19.656 L 20.952 0 L 22.728 0.6 Z M 28.296 3.576 L 28.296 10.272 A 11.512 11.512 0 0 0 28.608 10.306 Q 28.747 10.32 28.904 10.332 A 23.1 23.1 0 0 0 29.232 10.356 Q 29.784 10.392 30.456 10.392 Q 32.592 10.392 33.768 9.432 A 3.095 3.095 0 0 0 34.933 7.166 A 4.157 4.157 0 0 0 34.944 6.864 A 3.468 3.468 0 0 0 34.762 5.714 A 2.913 2.913 0 0 0 33.816 4.392 A 3.711 3.711 0 0 0 32.597 3.753 Q 31.742 3.48 30.6 3.48 Q 29.952 3.48 29.376 3.504 Q 28.8 3.528 28.296 3.576 Z
</sys:String>
</x:Array>
<!--
'y' for equilateral triangle of side length x:
(x/2)^2 + Y^2 = x^2
@@ -493,9 +422,9 @@
M0,7.79422863406 L3,12.9903810568 6,7.79422863406 Z
</sys:String>
<sys:String x:Key="{x:Static mbts:Icons.ArrowGeometryKey}">
<Geometry x:Key="arrow_geometry">
F1 M 78.1398,324.18L 52.5865,298.626C 51.6892,297.728 50.3385,297.459 49.1678,297.946C 47.9971,298.43 47.2305,299.574 47.2305,300.843L 60.6385,326.398L 47.2305,351.952C 47.2305,353.223 47.9971,354.364 49.1678,354.848C 49.5558,355.011 49.9638,355.09 50.3678,355.09C 51.1838,355.09 51.9852,354.77 52.5865,354.171L 78.1398,328.616C 78.7238,328.032 79.0598,327.224 79.0598,326.398C 79.0598,325.572 78.7238,324.764 78.1398,324.18 Z
</sys:String>
</Geometry>
<DrawingImage x:Key="Bookmarks">
<DrawingImage.Drawing>
@@ -1204,7 +1133,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="{Binding Source={StaticResource {x:Static mbts:Icons.ArrowGeometryKey}}}">
<GeometryDrawing Geometry="{StaticResource arrow_geometry}">
<GeometryDrawing.Pen>
<Pen Thickness="3" Brush="Black"/>
</GeometryDrawing.Pen>
@@ -1218,7 +1147,7 @@ M0,0L63.999001,0 63.999001,48.792999 0,48.792999z">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="{Binding Source={StaticResource {x:Static mbts:Icons.ArrowGeometryKey}}}">
<GeometryDrawing Geometry="{StaticResource arrow_geometry}">
<GeometryDrawing.Pen>
<Pen Thickness="3" Brush="Black"/>
</GeometryDrawing.Pen>
@@ -1,37 +1,35 @@
namespace mbts.spark {
using bts.api.core;
using bts.api.md.auxiliary;
using mbts.utils;
using Spark.Core.Reactive;
using System;
using System.Composition;
using System.Reactive.Concurrency;
[Export]
class MarketDataAuxiliaryModel : IDisposable {
readonly MarketDataAuxiliaryService _service;
readonly TableUpdateDemuxer<VolumeAtPriceLevelImmutable, int, uint> _security_orders_demuxer;
IDisposable _dispose;
[ImportingConstructor]
public MarketDataAuxiliaryModel(MarketDataAuxiliaryService service) {
_service = service;
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
volume_at_price = service.subscribei_volume_at_price().Naggle(interval, scheduler).Table().Cache();
_security_orders_demuxer = new(o => o.RecordId, v => v.SecurityId);
_dispose = volume_at_price.Subscribe(_security_orders_demuxer);
}
public IObservable<TableUpdate<VolumeAtPriceLevelImmutable, int>> volume_at_price { get; }
public IObservable<TableUpdate<VolumeAtPriceLevelImmutable, int>> security_volume_at_price(uint security) =>
_security_orders_demuxer.subscribe(security);
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
using bts.api.core;
using bts.api.md.auxiliary;
using mbts.utils;
using System;
using System.Composition;
using System.Reactive.Concurrency;
namespace mbts.spark {
[Export]
class MarketDataAuxiliaryModel : IDisposable {
readonly MarketDataAuxiliaryService _service;
readonly LegacyTableUpdateDemuxer<VolumeAtPriceLevelImmutable, int, uint> _security_orders_demuxer;
IDisposable _dispose;
[ImportingConstructor]
public MarketDataAuxiliaryModel(MarketDataAuxiliaryService service) {
_service = service;
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
volume_at_price = service.subscribei_volume_at_price().Naggle(interval, scheduler).Table().Cache();
_security_orders_demuxer = new LegacyTableUpdateDemuxer<VolumeAtPriceLevelImmutable, int, uint>(o => o.RecordId, v => v.SecurityId);
_dispose = volume_at_price.AddRemoveOnly().Subscribe(_security_orders_demuxer);
}
public IObservable<TableUpdate<VolumeAtPriceLevelImmutable, int>> volume_at_price { get; }
public IObservable<ITableUpdateTransform<VolumeAtPriceLevelImmutable, int>> security_volume_at_price(uint security) =>
_security_orders_demuxer.subscribe(security);
public void Dispose() =>
Disposable.dispose(ref _dispose);
}
}
@@ -1,40 +0,0 @@
#nullable enable
namespace Spark.Model {
using bts.api;
using bts.spark;
using mbts.ui;
using Spark.ViewModel.Commands;
using System;
using System.Windows.Input;
using System.Windows.Media;
class SparkMenuItemToggleModel : SparkCommand, ISelectable {
readonly IToggleCommand _cmd;
public SparkMenuItemToggleModel(
string? title,
ImageSource? icon = null,
bool show_in_toolbar = true,
bool show_in_context_menu = true,
KeyGesture? key_gesture = null,
IToggleCommand? cmd = null)
: base(title, icon, show_in_toolbar, show_in_context_menu, key_gesture) =>
_cmd = cmd ?? new ToggleCommand();
public event Action<bool>? is_selected_changed {
add => _cmd.is_selected_changed += value;
remove => _cmd.is_selected_changed -= value;
}
public bool is_selected {
get => _cmd.is_selected;
set => _cmd.is_selected = value;
}
public override void execute(IBus bus) =>
is_selected = !is_selected;
}
}
@@ -1,33 +0,0 @@
#nullable enable
namespace bts.api.position {
using bts.api.core;
using bts.api.orderman;
using bts.shell.pnl;
using mbts.ui;
using Spark.Trading;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
interface IPositionModel {
// positions
IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_positions { get; }
IObservable<TableUpdate<(SecurityImmutable? sec, RetrievedExchangePositionImmutable exch_pos), AccountSecurityKey>> on_exchange_positions { get; }
IObservable<TableUpdate<ReconcileReportRowData, AccountSecurityKey>> merged_positions { get; }
// pnl
IObservable<TableUpdate<(SecurityImmutable?, PNLUnitImmutable, QuantityConversionData<double>), int>> on_pnl { get; }
IObservable<TableUpdate<PNLRowData, AccountSecurityKey>> security_account_pnl { get; }
IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_security_positions(
uint security_key);
Task<bool> override_cpp_async(IEnumerable<(uint security_key, double cpp)> cpp_overrides);
Task<IReadOnlyList<PositionServiceOpResponseImmutable>> reset_positions(
ResetPositionParametersImmutable new_positions);
}
}
@@ -1,72 +0,0 @@
#nullable enable
namespace Spark.Model.Trading {
using bts;
using bts.api;
using bts.api.core;
using bts.api.orderman;
using bts.api.position;
using bts.shell.pnl;
using bts.spark;
using mbts.spark;
using Spark.Core.Reactive;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
[Export]
class OrderDataSource {
[ImportingConstructor]
public OrderDataSource(
IBus bus,
AdminModel admin_model,
SecurityStore security_store,
OrderService order_service,
ISecurityAuxiliaryDataModel security_auxiliary_model,
ErrorReporter error_reporter
) {
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
orders = admin_model
.permission_filter(
order_service.subscribei_orders()
.Naggle(interval, scheduler),
o => o.account_id())
.join(security_store, o => o.security_key())
.Table()
.Cache();
working_orders = orders.Filter(tup => tup.order.is_active()).Cache();
security_orders = orders
.SelectKeyValue(tup => new OrderSecurity(tup), OrderSecurityHelper.key_fn)
.GroupTable(OrderSecurityHelper.key_fn, tup => tup.order.Def.SecurityKey)
.Cache();
account_security_orders = orders.GroupTable(
t => t.order.Key,
t => new AccountSecurityKey(t.order.account_id(), t.order.security_key()))
.Cache();
working_account_security_orders = working_orders
.Filter(o => o.order.is_exchange_order())
.GroupTable(
t => t.order.Key,
t => new AccountSecurityKey(t.order.account_id(), t.order.security_key()))
.Cache();
}
public IObservable<TableUpdate<(SecurityImmutable? sec, OrderRecordImmutable order), uint>> orders { get; }
public IObservable<TableUpdate<(SecurityImmutable? sec, OrderRecordImmutable order), uint>> working_orders { get; }
public IObservable<TableUpdate<TableUpdateGrouping<OrderSecurity, uint, uint>, uint>> security_orders { get; }
public IObservable<TableUpdate<TableUpdateGrouping<(SecurityImmutable? sec, OrderRecordImmutable order), uint, AccountSecurityKey>, AccountSecurityKey>> account_security_orders { get; }
public IObservable<TableUpdate<TableUpdateGrouping<(SecurityImmutable? sec, OrderRecordImmutable order), uint, AccountSecurityKey>, AccountSecurityKey>> working_account_security_orders { get; }
}
}
@@ -1,160 +0,0 @@
#nullable enable
namespace bts.api.position {
using bts.api.core;
using bts.api.orderman;
using bts.collections;
using bts.shell.pnl;
using bts.spark;
using mbts;
using mbts.spark;
using mbts.ui;
using Spark.Core;
using Spark.Core.Reactive;
using Spark.Model.Trading;
using Spark.Trading;
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Threading.Tasks;
[Export(typeof(IPositionModel))]
class PositionModel : IPositionModel, IDisposable {
readonly PositionService _position_service;
readonly ErrorReporter _error_reporter;
readonly TableUpdateDemuxer<(SecurityImmutable?, PositionUnitImmutable), int, uint> _security_positions_demuxer;
IDisposable _dispose;
[ImportingConstructor]
public PositionModel(
IBus bus,
AdminModel admin_model,
SecurityStore security_store,
PositionService position_service,
OrderService order_service,
OrderDataSource order_data,
ISecurityAuxiliaryDataModel security_auxiliary_model,
ErrorReporter error_reporter) {
var scheduler = ThreadPoolScheduler.Instance;
var interval = TimeSpan.FromMilliseconds(100);
_position_service = position_service ?? throw new ArgumentNullException(nameof(position_service));
_error_reporter = error_reporter ?? throw new ArgumentNullException(nameof(error_reporter));
_security_positions_demuxer = new TableUpdateDemuxer<(SecurityImmutable?, PositionUnitImmutable pos), int, uint>(
o => o.pos.RecordId, p => p.pos.SecurityId);
on_exchange_positions = order_service.subscribei_exchange_positions()
.Filter(ep => ep.SecurityKey != 0)
.SelectKeyValue(ep => ep, ep => new AccountSecurityKey(ep.AccountId, ep.SecurityKey))
.join(security_store, ep => ep.SecurityKey)
.Table()
.Cache();
on_positions = admin_model
.permission_filter(
_position_service.subscribei_position_data().Naggle(interval, scheduler),
p => p.AccountId)
.join(security_store, pos => pos.SecurityId)
.Table()
.Cache();
on_pnl = admin_model
.permission_filter(
_position_service.subscribei_pnl_data().Naggle(interval, scheduler),
p => p.Pos.AccountId)
.join(security_store, p => p.Pos.SecurityId)
.Select(
tup => (tup.sec, tup.val, new QuantityConversionData<double>(
security_auxiliary_model.get_display_quantity_divisor(tup.sec),
QuantityConversionOpType.DivideActual)),
tup => tup.val.RecordId)
.TableCheckedAutoCorrect(
EqualityComparer<(SecurityImmutable?, PNLUnitImmutable, QuantityConversionData<double>)>.Default)
.Where(t => t.has_changes())
.Cache();
// security account pnl
security_account_pnl = on_pnl
#if DEBUG
.AssertIncremental(p => new AccountSecurityKey(p.Item2.Pos.AccountId, p.Item2.Pos.SecurityId))
#endif
.SelectKeyValue(PNLRowDataFactory.create, PNLRowData.key_fn)
.FullJoin(
order_data.working_account_security_orders,
PNLRowData.key_fn,
acc_orders => acc_orders.group_key,
(row, acc_orders, pnl_key) => row.with(working: WorkingOrderData.Create(
acc_orders.table.state.Values.Select(t => t.order), row.qty_conversion)),
(row, pnl_id) => row,
(acc_orders, pnl_id) => {
var (security, account_id, account) =
acc_orders.table.state.Values.TryGetFirst(out var tup) ?
(tup.sec, tup.order.account_id(), tup.order.account()) :
(null, 0, null);
return new PNLRowData(pnl_id,
security: security,
account_id: account_id,
account_name: account,
working: WorkingOrderData.Create(
acc_orders.table.state.Values.Select(t => t.order),
new QuantityConversionData<double>(
security_auxiliary_model.get_display_quantity_divisor(security),
QuantityConversionOpType.DivideActual)));
},
PNLRowData.key_fn)
.Where(t => t.has_changes())
.Cache();
merged_positions = ReconcileReportDataSource.create(on_exchange_positions, on_positions)
.Cache();
_dispose = Disposable.Create(
on_positions.Subscribe(_security_positions_demuxer));
}
public IObservable<TableUpdate<(SecurityImmutable? sec, RetrievedExchangePositionImmutable exch_pos), AccountSecurityKey>> on_exchange_positions { get; }
public IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_positions { get; }
public IObservable<TableUpdate<(SecurityImmutable?, PNLUnitImmutable, QuantityConversionData<double>), int>> on_pnl { get; }
public IObservable<TableUpdate<ReconcileReportRowData, AccountSecurityKey>> merged_positions { get; }
public IObservable<TableUpdate<PNLRowData, AccountSecurityKey>> security_account_pnl { get; }
public IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_security_positions(uint security) =>
_security_positions_demuxer.subscribe(security);
public Task<bool> override_cpp_async(IEnumerable<(uint security_key, double cpp)> cpp_overrides) {
var sec_params_batch_op = new SecurityParametersBatchOp();
sec_params_batch_op.OpParams.AddRange(cpp_overrides.Select(tup => new SecurityParameters {
SecurityKey = tup.security_key,
CppOverride = new CppOverride { Value = tup.cpp }
}));
return _error_reporter.safe_execute(
() => _position_service.update_security_parameters_async(sec_params_batch_op),
r => r.Ok,
r => r.Msg,
(v, success) => success,
"override cpp");
}
public Task<IReadOnlyList<PositionServiceOpResponseImmutable>> reset_positions(
ResetPositionParametersImmutable new_positions) =>
_error_reporter.safe_execute(
() => _position_service.reset_position_async(new_positions),
reply => reply.Response.All(r => r.Ok),
reply => "\n".join(reply.Response.Select(r => r.Msg)),
(v, success) => success ?
v.Response
.WrapSelectorRO(r => new PositionServiceOpResponseImmutable(r))
.ToReadOnlyList() :
Array.Empty<PositionServiceOpResponseImmutable>(),
"reset positions");
public void Dispose() =>
Disposable.dispose_thread_safe(ref _dispose);
}
}
@@ -1,27 +0,0 @@
#nullable enable
namespace bts.api.position {
using bts.api.core;
using Spark.Api.Position;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
static class PositionModelExtensions {
public static Task<bool> override_cpp_async(
this IPositionModel position_model, IEnumerable<uint> security_keys, double cpp) =>
(position_model ?? throw new ArgumentNullException(nameof(position_model)))
.override_cpp_async(security_keys.Select(k => (k, cpp)));
public static IObservable<double> security_total_position(
this IPositionModel orders_model, uint security_key, string account) =>
orders_model.on_security_positions(security_key)
.Select((t, k) => t.state.Values.TryGetFirst(v => v.Item2.Account == account, out var v) ?
v.Item2.total_pos() : double.NaN)
.DistinctUntilChanged()
.StartWith(double.NaN);
}
}
@@ -1,56 +0,0 @@
#nullable enable
namespace Spark.Trading {
using bts;
using bts.api;
using bts.api.core;
using bts.api.position;
using bts.utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using RowData = ReconcileReportRowData;
using RowKey = bts.AccountSecurityKey;
class ReconcileReportModel {
readonly IPositionModel _position_model;
readonly UserTuple _user;
public ReconcileReportModel(IPositionModel position_model, UserTuple user) {
_position_model = position_model;
_user = user;
}
public IObservable<TableUpdate<RowData, RowKey>> data_source =>
_position_model.merged_positions;
public async Task<IReadOnlyList<PositionServiceOpResponseImmutable>[]> sync_with_exchange(
IEnumerable<RowData> position_rows) {
var acc_reqs = position_rows
.Where(rd => rd.exch_quantity().is_real_non_zero())
.GroupBy(rd => rd.account)
.Select(acc_positions => {
var acc_positions_out = new ManualFillBatch();
acc_positions_out.ManualFill.AddRange(
acc_positions.Select(rd => new ManualFill() {
AccountId = rd.account.id,
AccountName = rd.account.name,
FillType = ManualFill.Types.FillType.AdminDay,
Price = rd.exch_price(),
Quantity = rd.exch_quantity().abs(),
SecurityKey = rd.security_id,
Side = rd.exch_quantity() > 0 ? Side.Buy : Side.Sell,
UserId = _user.id,
}));
return new ResetPositionParametersImmutable(new() {
Account = acc_positions.Key.name,
TotalPosition = acc_positions_out
});
});
return await Task.WhenAll(acc_reqs.Select(_position_model.reset_positions));
}
}
}
@@ -1,75 +1,46 @@
namespace mbts.spark {
using bts;
using bts.api;
using bts.api.analytics;
using bts.api.core;
using bts.collections;
using bts.shell;
using bts.spark;
using mbts.analytics;
using mbts.persist;
using mbts.ui;
using mbts.ui.shell;
using mbts.ui.utility;
using Spark.Core.Reactive;
using Spark.ViewModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
[Export(typeof(IShellModule))]
class AnalyticsShellModule : IShellModule, IShellModuleViewFactory {
class AnalyticsShellModule : ViewModelBase, IShellModule, IShellModuleViewFactory {
readonly IBus _bus;
readonly IWindowManager _wm;
readonly List<IShellWindowFactory> _window_factories;
IDisposable _dispose;
string _new_vol_surface_name;
IDisposable _subscriptions;
[ImportingConstructor]
public AnalyticsShellModule(
IBus bus, WindowManager wm, UserSettingsHub settings_hub, OrdersModel orders_model) {
public AnalyticsShellModule(IBus bus, IWindowManager wm, persist.UserSettingsHub settings_hub, OrdersModel orders_model) {
_wm = wm;
_bus = bus;
var reports_demuxer = new TableUpdateDemuxer<ReportImmutable?, int>(default, false);
var nullable_reports_src = bus.subscribe(SparkTags.ReportBlackboardTags.ListTag)
.Table(r => r.Id)
.Select(
r => new ReportImmutable?(r),
r => r?.Id ?? throw new ArgumentNullException(nameof(r)));
_window_factories = new() {
new VolSurfaceWindowFactory(this, bus),
new AnalyticsExpirationParametersWindowFactory(this, bus),
new SlideReportWindowFactory(this, bus, reports_demuxer.subscribe),
new ComboReportWindowFactory(this, bus, reports_demuxer.subscribe),
};
var vol_surfaces_src = _bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher();
var reports_src = _bus.subscribe(SparkTags.ReportBlackboardTags.ListTag).OnDispatcher();
_dispose = new DisposableCombo(
vol_surfaces_src.Subscribe(_on_vol_surfaces),
reports_src.Subscribe(_on_reports),
nullable_reports_src.Subscribe(reports_demuxer),
reports_demuxer,
vm.launch_exp_params_view_cmd.subscribe_executed(_launch_exp_params_view),
// vol surface
vm.vol_surface_launcher_vm.launch_cmd.subscribe_executed(_launch_vol_surface),
vm.vol_surface_launcher_vm.create_cmd.subscribe_executed(_create_vol_surface),
vm.vol_surface_launcher_vm.delete_cmd.subscribe_executed(_delete_vol_surface),
// slide
vm.slide_report_launcher_vm.launch_cmd.subscribe_executed(_launch_slide_report),
vm.slide_report_launcher_vm.create_cmd.subscribe_executed(_create_slide_report),
vm.slide_report_launcher_vm.delete_cmd.subscribe_executed(_delete_slide_report),
// combo
vm.combo_report_launcher_vm.launch_cmd.subscribe_executed(_launch_combo_report),
vm.combo_report_launcher_vm.create_cmd.subscribe_executed(_create_combo_report),
vm.combo_report_launcher_vm.delete_cmd.subscribe_executed(_delete_combo_report));
_subscriptions = Disposable.Create(
_bus.subscribe(SparkTags.VolSurfaceListTag).OnDispatcher()
.Subscribe(async vs => await _set_current_vol_surfaces(vs)));
}
public enum WindowType { Main, Heatmap }
@@ -77,153 +48,99 @@ namespace mbts.spark {
public string name => "Analytics";
public ImageSource icon => Icons.analytics;
public int priority => 20;
public IEnumerable<SparkCommand> actions => Enumerable.Empty<SparkCommand>();
public AnalyticsShellModuleVM vm { get; } = new();
public IEnumerable<SparkCommand> actions {
get {
yield return _launch_exp_params_view_spark_cmd;
}
}
public ICommand launch_exp_params_view_cmd =>
_launch_exp_params_view_spark_cmd.ICommand(_bus);
static SparkCommand _launch_exp_params_view_spark_cmd =>
SparkCommands.show_analytics_exp_params().complete(AnalyticsExpirationParametersSettings.Default);
public ObservableCollection<AlgoMenuItemVM> current_vol_surfaces { get; } = new();
public string new_vol_surface_name {
get => _new_vol_surface_name;
set => Set(ref _new_vol_surface_name, value);
}
public ICommand create_new_vol_surface => new DelegateCommand(_create_new_vol_surface);
public UIElement create_view() =>
new AnalyticsShellModuleView { DataContext = this };
public Task<IShellWindow> create(Stream load_stream) =>
ShellWindowFactory.create(load_stream, _window_factories);
public UIElement create_view() =>
new AnalyticsShellModuleView { DataContext = vm };
public void Dispose() =>
Disposable.dispose(ref _dispose);
Disposable.dispose(ref _subscriptions);
void _create_vol_surface(string _) {
var settings = VolSurfaceSettings.Default(string.Empty);
var vm = new VolSurfaceSettingsEditorVM(
_bus, settings, v => _bus.post(SparkTags.VolSurfaceCreateTag, v)) {
can_edit_name = true
};
void _create_new_vol_surface() {
if (string.IsNullOrWhiteSpace(_new_vol_surface_name)) {
return;
}
var vm = new VolSurfaceSettingsEditorVM(_bus, new VolSurfaceSettings {
core_settings = new VolSurfaceCoreSettings {
vol_surface_name = new_vol_surface_name,
vol_surface_model = VolSurfaceEnums.VolSurfaceModel.Polynomial,
call_rotation = new VolCurveMovementOperation { strike_vol_movement_pairs = new List<Tuple<double, double>>() },
put_rotation = new VolCurveMovementOperation { strike_vol_movement_pairs = new List<Tuple<double, double>>() },
strangle = new VolCurveMovementOperation { strike_vol_movement_pairs = new List<Tuple<double, double>>() },
full_rotation = new VolCurveMovementOperation { strike_vol_movement_pairs = new List<Tuple<double, double>>() },
atm_shift = new VolCurveMovementOperation() { strike_vol_movement_pairs = new List<Tuple<double, double>>() },
symbols = new List<string>(),
symbol_structure_list = new List<VolSurfaceSymbolStructure>(),
wing_settings = new VolSurfaceWingSettings {
explicit_slope_wing_settings = new VolSurfaceExplicitSlopeWingSettings(),
implicit_slope_wing_settings = new VolSurfaceImplicitSlopeWingSettings(),
onepoint_slope_wing_settings = new VolSurfaceOnePointSlopeWingSettings()
},
unset_expiration_calculation_settings = new VolSurfaceUnsetExpirationCalculationSettings(),
volpath_settings = new VolPathSettings(),
safety_limits = new VolChangeSafetyCheck(),
},
polynomial_model_settings = new PolynomialModelVolSurfaceSettings()
},
(settings) => _bus.post(SparkTags.VolSurfaceCreateTag, settings));
_new_vol_surface_name = string.Empty;
RaisePropertyChanged(nameof(new_vol_surface_name));
var window = new VolSurfaceSettingsEditor {
DataContext = vm,
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
window.Show();
select_section_delayed("configuration");
async void select_section_delayed(string section) {
await Task.Delay(100);
vm.selected_section = section;
}
}
void _launch_exp_params_view() {
var settings = AnalyticsExpirationParametersSettings.Default;
_bus.post(SparkTags.show_analytics_exp_params, settings);
async Task<string> _get_vs_name(int vs_id) {
var (vol_surfaces, success) = await _bus.subscribe(SparkTags.VolSurfaceListTag).FirstAsyncTask(TimeSpan.FromSeconds(2));
return success && vol_surfaces != null && vol_surfaces.TryGetValue(vs_id, out var vs_name) ?
vs_name : "(...)";
}
void _launch_vol_surface(int id) {
var windows = _wm.list_windows();
if (windows.OfType<VolSurfaceWindow>().TryGetFirst(w => w.vs_id == id, out var win)) {
_wm.MakeVisible(win);
return;
}
_bus.post(SparkTags.ShowVolSurface, new() { id = id });
}
void _delete_vol_surface(int id) {
if (BTSMessageBox.Confirm($"Are you sure you want to delete {name}?", "Vol Surface")) {
_bus.post(SparkTags.VolSurfaceDeleteTag, id);
}
}
void _on_vol_surfaces(IDictionary<int, string> id_names) {
vm.vol_surface_launcher_vm.items.sync_with(id_names.Select(
kv => new KeyValueItemVM<int, string>(kv.Key, kv.Value)));
// reset titles for all open vol surface windows
async Task _set_current_vol_surfaces(IDictionary<int, string> id_names) {
current_vol_surfaces.SetItems(id_names.Select(kvp => new AlgoMenuItemVM(kvp.Key, kvp.Value,
(id, name) => {
var windows = _wm.list_windows();
if (windows.OfType<VolSurfaceWindow>().TryGetFirst(w => w.vs_id == id, out var w)) {
_wm.MakeVisible(w);
return;
}
_bus.post(SparkTags.ShowVolSurface, new() { id = id });
},
(id, name) => {
if (BTSMessageBox.Confirm($"Are you sure you want to delete {name}?", "Vol Surface")) {
_bus.post(SparkTags.VolSurfaceDeleteTag, id);
}
})));
//reset titles for all open vol surface windows
foreach (var window in _wm.list_windows().OfType<VolSurfaceWindow>()) {
window.Title = id_names.GetValueOrDefault(window.vs_id) ?? "(...)";
}
}
void _create_slide_report(string _) {
var vm = new SlideReportSettingsVM(
SlideReportSettings.Default(),
new(new Report { ReportType = Report.Types.ReportType.Slide }),
_bus.subscribe(SparkTags.VolSurfaceListTag),
_bus.subscribe(SparkTags.AccountsTag),
_bus.subscribe(SparkTags.SecuritiesTag));
vm.selected_section = vm.configuration_vm;
var win = new SlideReportCreationDialog() {
DataContext = vm
};
WindowUtilities.connect_vm(win, vm);
vm.ok_cmd.executed += commit;
win.move_to_mouse(-100, -200);
win.Show();
async void commit((GreekDisplay[] greeks, PriceDisplayFactors price_disp, ReportImmutable rep) tup) {
WindowUtilities.force_close(win);
_bus.post(SparkTags.ReportBlackboardTags.Create, tup.rep);
var persisted_rep = await _bus.subscribe(SparkTags.ReportBlackboardTags.ListTag)
.Select(reps => reps.Values.TryGetFirst(
r => r.ReportName == tup.rep.ReportName, out var prep) ? prep : (ReportImmutable?)null)
.Where(r => r.HasValue)
.FirstOrDefaultAsync();
if (!persisted_rep.HasValue) {
return;
}
var settings = SlideReportSettings.Default(persisted_rep.Value.Id);
settings.greeks = tup.greeks;
settings.price = tup.price_disp;
vm.grid_vm.assign_to(settings);
_bus.post(SparkTags.ShowSlideReportTag, settings);
}
}
void _delete_slide_report(int id) =>
_bus.post(SparkTags.ReportBlackboardTags.Delete, id);
void _launch_slide_report(int id) =>
_bus.post(SparkTags.ShowSlideReportTag, SlideReportSettings.Default(id));
void _create_combo_report(string _) {
var vm = new ComboReportSettingsVM(_bus.subscribe(SparkTags.AccountsTag));
vm.load_from(new(new Report { ReportType = Report.Types.ReportType.Slide }));
var win = new ComboReportCreationDialog() {
DataContext = vm
};
WindowUtilities.connect_vm(win, vm);
vm.commit_cmd.executed += commit;
win.move_to_mouse(-100, -100);
win.Show();
async void commit(ReportImmutable rep) {
WindowUtilities.force_close(win);
_bus.post(SparkTags.ReportBlackboardTags.Create, rep);
var persisted_rep = await _bus.subscribe(SparkTags.ReportBlackboardTags.ListTag)
.Select(reps => reps.Values.TryGetFirst(
r => r.ReportName == rep.ReportName, out var prep) ? prep : (ReportImmutable?)null)
.Where(r => r.HasValue)
.FirstOrDefaultAsync();
if (!persisted_rep.HasValue) {
return;
}
var settings = ComboReportSettings.Default(persisted_rep.Value.Id);
_bus.post(SparkTags.ShowComboReportTag, settings);
}
}
void _delete_combo_report(int id) =>
_bus.post(SparkTags.ReportBlackboardTags.Delete, id);
void _launch_combo_report(int id) =>
_bus.post(SparkTags.ShowComboReportTag, ComboReportSettings.Default(id));
void _on_reports(IReadOnlyDictionary<int, ReportImmutable> reports) {
vm.slide_report_launcher_vm.items.Clear();
vm.combo_report_launcher_vm.items.Clear();
foreach (var rep in reports.Values) {
switch (rep.ReportType) {
case Report.Types.ReportType.Slide:
vm.slide_report_launcher_vm.items.Add(new(rep.Id, rep.ReportName));
break;
case Report.Types.ReportType.Combo:
vm.combo_report_launcher_vm.items.Add(new(rep.Id, rep.ReportName));
break;
var vs_name = await _get_vs_name(window.vs_id);
if (window.vs_name != vs_name) {
window.Title = vs_name;
}
}
}
@@ -1,21 +0,0 @@
#nullable enable
namespace mbts.spark {
using mbts.ui;
using mbts.ui.shell;
using Spark.ViewModel;
class AnalyticsShellModuleVM : ViewModelBase {
string? _selected_window_type;
public EventCommand launch_exp_params_view_cmd { get; } = new();
public KeyValueLauncherVM<int, string> vol_surface_launcher_vm { get; } = new() { type_name = "Vol Surface" };
public KeyValueLauncherVM<int, string> slide_report_launcher_vm { get; } = new() { type_name = "Slide Report" };
public KeyValueLauncherVM<int, string> combo_report_launcher_vm { get; } = new() { type_name = "Combo Report" };
public string? selected_window_type {
get => _selected_window_type;
set => Set(ref _selected_window_type, value);
}
}
}
@@ -1,178 +1,146 @@
<UserControl
x:Class="mbts.ui.shell.AnalyticsShellModuleView"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:shell="clr-namespace:mbts.ui.shell"
x:Name="me"
Background="Transparent"
MinWidth="250"
>
x:Class="mbts.ui.shell.AnalyticsShellModuleView"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:mbts.ui.controls"
x:Name="me"
MinWidth="250">
<UserControl.Resources>
<Style x:Key="CommonList" TargetType="{x:Type ListBox}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Style
x:Key="CommonList"
TargetType="{x:Type ListBox}">
<Setter
Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter
Property="Background"
Value="Transparent" />
<Setter
Property="BorderThickness"
Value="0" />
</Style>
<DataTemplate x:Key="LaunchItemTemplate">
<Button
Height="32"
MinWidth="190"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
Padding="12,6,6,6"
Command="{Binding DataContext.launch_cmd, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding key}"
Style="{StaticResource LargeMenuButton}"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Label"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding value}" VerticalAlignment="Center" Margin="4,0,7,0" />
<Button
Grid.Column="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding DataContext.delete_cmd, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding key}"
Style="{StaticResource RoundCloseButton}"
/>
</Grid>
</Button>
</DataTemplate>
<DataTemplate x:Key="ReportLauncherTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl
ItemsSource="{Binding items}"
ItemTemplate="{StaticResource LaunchItemTemplate}"
/>
<Button
Grid.Row="1"
Margin="0,4,0,0"
HorizontalAlignment="Stretch"
Grid.Column="1"
Padding="16,6,6,6"
IsDefault="True"
Command="{Binding create_cmd}"
Style="{StaticResource LargeMenuButton}"
>
<TextBlock FontWeight="Bold" Text="{Binding type_name, StringFormat='New {0}'}" />
</Button>
</Grid>
</DataTemplate>
<Style x:Name="WindowTypeToggle" TargetType="ToggleButton" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="BorderThickness" Value="0" />
</Style>
<c:RadioButtonGroupManager
x:Key="WindowTypeRadioButtonGroupManager"
SelectedItem="{Binding DataContext.selected_window_type, Source={u:DirectReference me}, Mode=TwoWay}"
/>
</UserControl.Resources>
<Grid Margin="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button
Content="Analytics Expiration Parameters"
Command="{Binding launch_exp_params_view_cmd}"
Style="{StaticResource LargeMenuButton}"
/>
Style="{DynamicResource StartMenuButton}"
Content="Analytics Expiration Parameters"
Command="{Binding launch_exp_params_view_cmd}"
Padding="4" />
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Rectangle
Margin="5,1,5,0"
Fill="{DynamicResource StartMenuMouseOverBackground}"
HorizontalAlignment="Stretch"
Height="1"
/>
Margin="5,1,5,0"
Fill="{DynamicResource StartMenuMouseOverBackground}"
HorizontalAlignment="Stretch"
Height="1" />
<c:HelpButton
Grid.Column="1"
ManPage="AW2"
ToolTip="Click Here for help"
/>
Grid.Column="2"
ManPage="AW2"
ToolTip="Click Here for help" />
</Grid>
<ToggleButton
Grid.Row="2"
c:RadioButtonGroupManager.Value="vol_surfaces"
c:RadioButtonGroupManager.Manager="{StaticResource WindowTypeRadioButtonGroupManager}"
Content="Vol Surfaces"
IsChecked="{Binding Path='(u:ExpandCollapseAnimator.IsExpanded)', ElementName=VolSurfacesContent, Mode=TwoWay}"
Style="{StaticResource LargeMenuToggleButton}"
/>
<ContentControl Grid.Row="3" Height="0">
<ContentControl
x:Name="VolSurfacesContent"
Content="{Binding vol_surface_launcher_vm}"
ContentTemplate="{StaticResource ReportLauncherTemplate}"
/>
</ContentControl>
<ToggleButton
Grid.Row="4"
c:RadioButtonGroupManager.Value="slide_reports"
c:RadioButtonGroupManager.Manager="{StaticResource WindowTypeRadioButtonGroupManager}"
Margin="0,6,0,0"
Content="Slide Reports"
IsChecked="{Binding Path='(u:ExpandCollapseAnimator.IsExpanded)', ElementName=SlideReportContent, Mode=TwoWay}"
Style="{StaticResource LargeMenuToggleButton}"
/>
<ContentControl Grid.Row="5" Height="0">
<ContentControl
x:Name="SlideReportContent"
Content="{Binding slide_report_launcher_vm}"
ContentTemplate="{StaticResource ReportLauncherTemplate}"
/>
</ContentControl>
<ToggleButton
Grid.Row="6"
c:RadioButtonGroupManager.Value="combo_reports"
c:RadioButtonGroupManager.Manager="{StaticResource WindowTypeRadioButtonGroupManager}"
Margin="0,6,0,0"
Content="Combo Report"
IsChecked="{Binding Path='(u:ExpandCollapseAnimator.IsExpanded)', ElementName=ComboReportContent, Mode=TwoWay}"
Style="{StaticResource LargeMenuToggleButton}"
/>
<ContentControl Grid.Row="7" Height="0">
<ContentControl
x:Name="ComboReportContent"
Content="{Binding combo_report_launcher_vm}"
ContentTemplate="{StaticResource ReportLauncherTemplate}"
/>
</ContentControl>
<Expander
Grid.Row="2"
Margin="0,3,0,0"
Header="Current Vol Surfaces"
IsExpanded="True">
<ScrollViewer
MaxHeight="520"
VerticalScrollBarVisibility="Auto">
<ListBox
ItemsSource="{Binding current_vol_surfaces}"
Style="{StaticResource CommonList}"
Grid.IsSharedSizeScope="True"
ItemTemplate="{StaticResource ShellLaunchWithDeleteItemTemplate}" />
</ScrollViewer>
</Expander>
<GroupBox
Grid.Row="3"
Header="New Vol Surface">
<StackPanel>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl
Grid.Row="1"
ItemsSource="{Binding option_driver_groups_vm.driver_groups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<GroupBox Header="{Binding Key.symbol}">
<ItemsControl ItemsSource="{Binding Value}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
IsItemsHost="True"
Orientation="Vertical"
FlowDirection="LeftToRight"
MaxHeight="60" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox
Content="{Binding symbol}"
IsChecked="{Binding is_selected}"
Margin="5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</GroupBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Grid
Grid.Row="2"
HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="1"
HorizontalAlignment="Center"
Text="Select a name"
Foreground="Red"
Visibility="{Binding absent_name_message_visibility}" />
<TextBlock
Grid.Row="1"
Text="Name"
Margin="4,0,4,0"
VerticalAlignment="Center" />
<TextBox
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Stretch"
Margin="4"
Text="{Binding new_vol_surface_name, UpdateSourceTrigger=PropertyChanged}" />
<Button
Grid.Row="1"
Grid.Column="2"
MinWidth="60"
Margin="4"
IsDefault="True"
Command="{Binding create_new_vol_surface}">Create</Button>
</Grid>
</Grid>
</StackPanel>
</GroupBox>
</Grid>
</UserControl>
@@ -1,7 +0,0 @@
namespace mbts.spark {
using mbts.ui;
interface IReportWindow : IShellWindow {
int report_id { get; }
}
}
@@ -1,118 +0,0 @@
<TabControl
x:Class="mbts.ui.controls.VolSurfaceDriverGridTabControl"
x:ClassModifier="internal"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:mbts.ui;assembly=bts_uicore"
xmlns:u="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:cv="clr-namespace:mbts.ui.converters"
xmlns:shell="clr-namespace:mbts.ui.shell">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem" BasedOn="{StaticResource {x:Type TabItem}}">
<Setter Property="Header" Value="{Binding header}" />
</Style>
</TabControl.ItemContainerStyle>
<TabControl.ContentTemplate>
<DataTemplate>
<c:DataGridEx
VerticalAlignment="Top"
Margin="0,-2,0,0"
BorderThickness="0"
AutoGenerateColumns="False"
CanUserResizeColumns="False"
ItemsSource="{Binding symbols}"
RowBackground="Transparent">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Symbol">
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="BorderThickness" Value="1,0,0,0" />
<Setter Property="BorderBrush" Value="Black" />
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
Margin="3,0,3,0"
VerticalAlignment="Center"
Content="{Binding name}"
IsChecked="{Binding is_selected, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Master">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<c:ComboCheckBox
Margin="4"
ItemsSource="{Binding driver.symbols}"
SelectedItems="{Binding masters}"
TextBlock.Foreground="Black">
<c:ComboCheckBox.HeaderContent>
<MultiBinding>
<MultiBinding.Converter>
<cv:SelectedItemsHeaderTextConverter ShowFraction="False" />
</MultiBinding.Converter>
<Binding Path="mastersi" />
<Binding Path="driver.symbols.Count" />
</MultiBinding>
</c:ComboCheckBox.HeaderContent>
</c:ComboCheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Mkt Imp Vol">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<c:ComboCheckBox
Margin="4"
ItemsSource="{Binding driver.symbols}"
SelectedItems="{Binding fits}"
TextBlock.Foreground="Black">
<c:ComboCheckBox.HeaderContent>
<MultiBinding>
<MultiBinding.Converter>
<cv:SelectedItemsHeaderTextConverter ShowFraction="False" />
</MultiBinding.Converter>
<Binding Path="fitsi" />
<Binding Path="driver.symbols.Count" />
</MultiBinding>
</c:ComboCheckBox.HeaderContent>
</c:ComboCheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Pricing Model">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
Margin="4"
ItemsSource="{Binding
DataContext.pricing_models,
RelativeSource={RelativeSource AncestorType=c:VolSurfaceDriverGridTabControl}}"
SelectedValue="{Binding pricing_model, UpdateSourceTrigger=PropertyChanged}"
ItemTemplate="{StaticResource EnumDescriptionTemplate}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</c:DataGridEx>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
@@ -1,9 +0,0 @@
#nullable enable
namespace mbts.ui.controls {
using System.Windows.Controls;
partial class VolSurfaceDriverGridTabControl : TabControl {
public VolSurfaceDriverGridTabControl() =>
InitializeComponent();
}
}
@@ -57,29 +57,29 @@
<controls:TickUpDown
Content="Put Rotation"
TickCommand="{Binding put_rotation}"
TickUpCommandParameter="true"
TickDownCommandParameter="false" />
TickUpParameter="true"
TickDownParameter="false" />
<controls:TickUpDown
Content="Call Rotation"
TickCommand="{Binding call_rotation}"
TickUpCommandParameter="true"
TickDownCommandParameter="false" />
TickUpParameter="true"
TickDownParameter="false" />
<controls:TickUpDown
Content="Risk Reversal"
TickCommand="{Binding full_rotation}"
TickUpCommandParameter="true"
TickDownCommandParameter="false" />
TickUpParameter="true"
TickDownParameter="false" />
<controls:TickUpDown
Content="Strangle"
TickCommand="{Binding strangle}"
TickUpCommandParameter="true"
TickDownCommandParameter="false" />
TickUpParameter="true"
TickDownParameter="false" />
<controls:TickUpDown
Grid.Row="1"
Content="ATM Move"
TickCommand="{Binding atm_shift}"
TickUpCommandParameter="true"
TickDownCommandParameter="false" />
TickUpParameter="true"
TickDownParameter="false" />
<GroupBox Header="Fit To Market">
<StackPanel>
<ComboBox
@@ -121,8 +121,8 @@
<controls:TickUpDown
Content="Global Vol Shift"
TickCommand="{Binding vol_shift}"
TickUpCommandParameter="true"
TickDownCommandParameter="false"
TickUpParameter="true"
TickDownParameter="false"
Visibility="Collapsed" />
</StackPanel>
</ScrollViewer>
@@ -2,7 +2,20 @@ namespace mbts.ui {
using mbts.spark.VolSurface;
using mbts.ui.controls;
class VolSurfaceRowView : DIYGrid.HighPerformanceRow<VolSurfaceRowVM> {
public VolSurfaceRowVM vm => _row;
using System.Windows.Input;
class VolSurfaceRowView : DIYGrid.HighPerformanceRow<VolSurfaceRowContext> {
protected override void OnPreviewMouseRightButtonDown(MouseButtonEventArgs e) {
open_context_menu(DIYGrid.RowUtils.column_at(_column_layout, e.GetPosition(this)));
base.OnPreviewMouseRightButtonDown(e);
}
public void open_context_menu(DIYGrid.ColumnGeometry? cell) {
if (!cell.HasValue || DIYGrid.RowUtils.column_index(_column_layout, cell.Value) < _grid.FrozenColumnCount) {
return;
}
_row.context_menu.column = (VolSurfaceColumn)cell.Value.column;
_row.context_menu.super_header = cell.Value.super_column;
}
}
}
File diff suppressed because it is too large. Load diff
@@ -1,7 +1,12 @@
#nullable enable
namespace mbts.ui.shell {
using System.Windows;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace mbts.ui.shell {
partial class VolSurfaceSettingsEditor : Window {
public VolSurfaceSettingsEditor() =>
InitializeComponent();
@@ -6,7 +6,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:spark="clr-namespace:mbts.spark"
xmlns:vs="clr-namespace:mbts.spark.VolSurface"
xmlns:u="clr-namespace:mbts.ui"
xmlns:c="clr-namespace:mbts.ui.controls"
xmlns:cv="clr-namespace:mbts.ui.converters"
@@ -18,25 +17,6 @@
Background="{StaticResource CommonBackground}"
TextElement.FontSize="10">
<UserControl.Resources>
<Style x:Key="CopyColumnMenuItem" TargetType="MenuItem">
<Setter
Property="IsEnabled"
Value="{Binding column.type, Converter={x:Static shell:VolSurfaceView.copy_column_enabled_converter}}" />
<Setter
Property="Visibility"
Value="{Binding column.type, Converter={x:Static shell:VolSurfaceView.copy_column_visibility_converter}}" />
</Style>
<Style x:Key="CopyGroupMenuItem" TargetType="MenuItem">
<Setter
Property="IsEnabled"
Value="{Binding column.type, Converter={x:Static shell:VolSurfaceView.copy_group_enabled_converter}}" />
<Setter
Property="Visibility"
Value="{Binding column.type, Converter={x:Static shell:VolSurfaceView.copy_group_visibility_converter}}" />
</Style>
<Style x:Key="commit_style" TargetType="Button" BasedOn="{StaticResource ResourceKey={x:Type Button}}">
<Style.Triggers>
<DataTrigger Binding="{Binding is_dirty}" Value="true">
@@ -253,10 +233,9 @@
SuperHeaders="{Binding super_headers}"
Columns="{Binding columns}"
Rows="{Binding sorted_visible_rows}"
IsDragAdornerEnabled="False"
ContextMenuOpening="_on_context_menu_opening">
<c:DIYGrid.ContextMenu>
<ContextMenu>
IsDragAdornerEnabled="False">
<c:DIYGrid.Resources>
<ContextMenu x:Key="context_menu" DataContext="{Binding context_menu}">
<MenuItem Header="Settings">
<MenuItem.Icon>
<Image
@@ -268,11 +247,11 @@
RenderOptions.BitmapScalingMode="HighQuality"
SnapsToDevicePixels="True" />
</MenuItem.Icon>
<MenuItem Header="Vol Surface Settings" Command="{Binding main_settings_cmd}" />
<MenuItem Header="Vol Surface Advanced Settings" Command="{Binding advanced_settings_cmd}" />
<MenuItem Header="Vol Surface Settings" Command="{Binding main_settings_command}" />
<MenuItem Header="Vol Surface Advanced Settings" Command="{Binding advanced_settings_command}" />
<Separator />
<MenuItem Header="Grid Settings" Command="{Binding grid_settings_cmd}" />
<MenuItem Header="Graph Settings" Command="{Binding graph_settings_cmd}" />
<MenuItem Header="Grid Settings" Command="{Binding grid_settings_command}" />
<MenuItem Header="Graph Settings" Command="{Binding graph_settings_command}" />
</MenuItem>
<Separator />
<MenuItem Header="Copy...">
@@ -281,60 +260,54 @@
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Copy '{0}' to Selected Expirations"
Command="{Binding copy_to_selection_cmd}"
CommandParameter="Column"
Style="{StaticResource CopyColumnMenuItem}" />
Command="{Binding copy_to_selection_command}"
CommandParameter="Column" />
<MenuItem
Header="{Binding group_name}"
HeaderStringFormat="Copy '{0}' to Selected Expirations"
Command="{Binding copy_to_selection_cmd}"
CommandParameter="Group"
Style="{StaticResource CopyGroupMenuItem}" />
Command="{Binding copy_to_selection_command}"
CommandParameter="Group" />
<MenuItem
Header="{Binding expiration_name}"
HeaderStringFormat="Copy '{0}' to Selected Expirations"
Command="{Binding copy_to_selection_cmd}"
Command="{Binding copy_to_selection_command}"
CommandParameter="All" />
<Separator />
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Copy '{0}' to Master Expirations"
Command="{Binding copy_to_masters_cmd}"
CommandParameter="Column"
Style="{StaticResource CopyColumnMenuItem}" />
Command="{Binding copy_to_masters_command}"
CommandParameter="Column" />
<MenuItem
Header="{Binding group_name}"
HeaderStringFormat="Copy '{0}' to Master Expirations"
Command="{Binding copy_to_masters_cmd}"
CommandParameter="Group"
Style="{StaticResource CopyGroupMenuItem}" />
Command="{Binding copy_to_masters_command}"
CommandParameter="Group" />
<MenuItem
Header="{Binding expiration_name}"
HeaderStringFormat="Copy '{0}' to Master Expirations"
Command="{Binding copy_to_masters_cmd}"
Command="{Binding copy_to_masters_command}"
CommandParameter="All" />
<Separator />
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Copy '{0}' to All Expirations"
Command="{Binding copy_to_all_cmd}"
CommandParameter="Column"
Style="{StaticResource CopyColumnMenuItem}" />
Command="{Binding copy_to_all_command}"
CommandParameter="Column" />
<MenuItem
Header="{Binding group_name}"
HeaderStringFormat="Copy '{0}' to All Expirations"
Command="{Binding copy_to_all_cmd}"
CommandParameter="Group"
Style="{StaticResource CopyGroupMenuItem}" />
Command="{Binding copy_to_all_command}"
CommandParameter="Group" />
<MenuItem
Header="{Binding expiration_name}"
HeaderStringFormat="Copy '{0}' to All Expirations"
Command="{Binding copy_to_all_cmd}"
Command="{Binding copy_to_all_command}"
CommandParameter="All" />
<Separator />
<MenuItem
Header="Copy All To Clipboard"
Command="{Binding copy_all_to_clipboard_cmd}" />
Command="{Binding copy_all_to_clipboard_command}" />
</x:ArrayExtension>
</MenuItem.ItemsSource>
</MenuItem>
@@ -345,22 +318,22 @@
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Shift '{0}' for Selected Expirations"
Command="{Binding shift_selection_cmd}" />
Command="{Binding shift_selection_command}" />
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Shift '{0}' for Master Expirations"
Command="{Binding shift_masters_cmd}" />
Command="{Binding shift_masters_command}" />
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Shift '{0}' for All Expirations"
Command="{Binding shift_all_cmd}" />
Command="{Binding shift_all_command}" />
</x:ArrayExtension>
</MenuItem.ItemsSource>
</MenuItem>
<Separator />
<MenuItem
Header="Revert"
Command="{Binding revert_cmd}"
Command="{Binding revert_command}"
IsEnabled="{Binding is_input_cell}" />
<Separator />
<MenuItem Header="Clear...">
@@ -369,18 +342,18 @@
<MenuItem
Header="{Binding column_name}"
HeaderStringFormat="Clear '{0}'"
Command="{Binding clear_cmd}"
Command="{Binding clear_command}"
CommandParameter="Column"
IsEnabled="{Binding is_input_cell}" />
<MenuItem
Header="{Binding group_name}"
HeaderStringFormat="Clear '{0}'"
Command="{Binding clear_cmd}"
Command="{Binding clear_command}"
CommandParameter="Group" />
<MenuItem
Header="{Binding expiration_name}"
HeaderStringFormat="Clear '{0}'"
Command="{Binding clear_cmd}"
Command="{Binding clear_command}"
CommandParameter="All" />
</x:ArrayExtension>
</MenuItem.ItemsSource>
@@ -388,7 +361,7 @@
<Separator />
<MenuItem
Header="Sync Slave Ref Fwd's To Master"
Command="{Binding smart_copy_rolls_rates_cmd}" />
Command="{Binding smart_copy_rolls_rates_command}" />
<Separator />
<MenuItem
Header="Symbols"
@@ -403,9 +376,9 @@
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem Header="Import CSV..." Command="{Binding import_csv_cmd}" />
<MenuItem Header="Import CSV..." Command="{Binding import_csv_command}" />
</ContextMenu>
</c:DIYGrid.ContextMenu>
</c:DIYGrid.Resources>
<c:DIYGrid.RowStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource DIYGridRowStyle}">
<Setter Property="IsSelected" Value="{Binding is_selected}" />
@@ -429,7 +402,7 @@
<Button
Content="Commit"
HorizontalAlignment="Center"
Command="{Binding commit_cmd}"
Command="{Binding commit_command}"
Grid.Column="6"
Width="60"
Margin="5"
@@ -632,13 +605,13 @@
<Button
Content="Details"
Grid.Column="1"
Command="{Binding details_cmd}"
Command="{Binding details_command}"
Width="60"
Margin="5" />
<Button
Content="Heatmap"
Grid.Column="2"
Command="{Binding summary_cmd}"
Command="{Binding summary_command}"
Width="60"
Margin="5" />
@@ -651,20 +624,20 @@
MinWidth="150" />
<Button
Content="Load"
Command="{Binding load_previous_cmd}"
Command="{Binding load_previous_command}"
Width="60"
Margin="0,5,5,5" />
</StackPanel>
<Button
Content="Revert"
Command="{Binding revert_cmd}"
Command="{Binding revert_command}"
Grid.Column="5"
Width="60"
Margin="5" />
<Button
Content="Commit"
Command="{Binding commit_cmd}"
Command="{Binding commit_command}"
Grid.Column="6"
Width="60"
Margin="5"
Loaded 100 of 869 files, more files were not shown because too many files have changed in this diff. Show more