Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dbfca8304 | ||
|
|
661e224fd5 |
No files matched your search
+3
-2
@@ -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
@@ -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.
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.
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
Submodule externals updated: 99c440f568...1dffb78a8e.
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.200",
|
||||
"version": "2.1.508",
|
||||
"rollForward": "latestMajor"
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@
|
||||
<EnableDefaultContentItems>False</EnableDefaultContentItems>
|
||||
<ShowMissingItemTypes>false</ShowMissingItemTypes>
|
||||
<Configuration Condition="'$(configuration)'==''">Debug</Configuration>
|
||||
<EnablePreviewFeatures>true</EnablePreviewFeatures>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Label="Output">
|
||||
|
||||
@@ -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" />
|
||||
|
||||
+30
-24
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
+35
-37
@@ -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; }
|
||||
}
|
||||
}
|
||||
-118
@@ -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>
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
#nullable enable
|
||||
namespace mbts.ui.controls {
|
||||
using System.Windows.Controls;
|
||||
|
||||
partial class VolSurfaceDriverGridTabControl : TabControl {
|
||||
public VolSurfaceDriverGridTabControl() =>
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1102
-785
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
Reference in new issue
Block a user