Compare commits
43
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e0a92fd65 | ||
|
|
a9c4173b02 | ||
|
|
7c99fe90de | ||
|
|
feff24bf10 | ||
|
|
8eccb869e1 | ||
|
|
40f4333fc7 | ||
|
|
319d5c2384 | ||
|
|
4a74713369 | ||
|
|
082beef1da | ||
|
|
f92d789e90 | ||
|
|
cd3e845dd9 | ||
|
|
a5b704eef1 | ||
|
|
afee63e061 | ||
|
|
fc9356d1a0 | ||
|
|
a85f22c6a8 | ||
|
|
2024eba4d0 | ||
|
|
1a49a828ad | ||
|
|
c0448c7c8d | ||
|
|
a6c6e7faf3 | ||
|
|
56445d2d66 | ||
|
|
ccf1bd51c2 | ||
|
|
fd21269df7 | ||
|
|
fe85c3e648 | ||
|
|
e1d33ecadf | ||
|
|
83df96c70f | ||
|
|
f718f5b15c | ||
|
|
5d752f3b73 | ||
|
|
d308dbf15a | ||
|
|
21c43b9240 | ||
|
|
e1553f1b04 | ||
|
|
a26918efe9 | ||
|
|
f729fc4c59 | ||
|
|
fa67adbe36 | ||
|
|
72f9ec582e | ||
|
|
8fea31bdf6 | ||
|
|
ca96e41391 | ||
|
|
d4e5c95fde | ||
|
|
f6e0ec3617 | ||
|
|
3fa5284838 | ||
|
|
4dcaa565f6 | ||
|
|
75ecfa89d6 | ||
|
|
1c930439a4 | ||
|
|
25084b8cd9 |
No files matched your search
@@ -51,7 +51,8 @@ SPARKD__QUICKBUS_PORT=8001
|
||||
SPARKD__SIM_FIX_PORT=8002
|
||||
SPARKD__SHM_SIZE=4gb
|
||||
SPARKD__PYTHON_REQUIREMENTS=requirements.txt
|
||||
SPARKD__ENTRYPOINT=src/app_sparkd/sparkd-entrypoint.sh
|
||||
SPARKD__SPARKD_ENTRYPOINT=src/app_sparkd/sparkd-entrypoint.sh
|
||||
SPARKD__MAIN_ENTRYPOINT=./sparkd-entrypoint.sh
|
||||
|
||||
### PubSubServer ###
|
||||
PUBSUB__CONFIG_DIR=src/DataStreamSuite/PubSubServer/Configurations/Development
|
||||
|
||||
Vendored
+9
-9
@@ -183,11 +183,10 @@
|
||||
"windows": {
|
||||
"program": "PubSubServer.exe",
|
||||
},
|
||||
"args": [
|
||||
"--config",
|
||||
"${workspaceFolder}/src/DataStreamSuite/PubSubServer/Configurations/${input:pubSubServerConfig}.json"
|
||||
],
|
||||
"cwd": "build/Debug/bin/net8.0",
|
||||
"env": {
|
||||
"DOTNET_ENVIRONMENT": "${input:pubSubServerEnvironment}",
|
||||
},
|
||||
"stopAtEntry": false,
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
@@ -449,14 +448,15 @@
|
||||
"default": "Local",
|
||||
},
|
||||
{
|
||||
"id": "pubSubServerConfig",
|
||||
"id": "pubSubServerEnvironment",
|
||||
"type": "pickString",
|
||||
"description": "PubSub Configuration",
|
||||
"description": "PubSubServer Configuration",
|
||||
"options": [
|
||||
"PubSubServer",
|
||||
"SimpleEchoClient",
|
||||
"Development",
|
||||
"EchoServer",
|
||||
"Local",
|
||||
],
|
||||
"default": "PubSubServer",
|
||||
"default": "Development",
|
||||
},
|
||||
{
|
||||
"id": "sdkDemoEnvironment",
|
||||
|
||||
@@ -17,14 +17,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Spark.Sdk", "src\cs\Bts
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Spark.Sdk.Demo", "src\cs\Bts.Spark.Sdk.Demo\Bts.Spark.Sdk.Demo.csproj", "{FCFDBDBE-74B0-41C4-9011-C651B21056D4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Collections", "src\cs\Bts.Collections\Bts.Collections.csproj", "{3BF4DF96-5AFF-4674-866A-71A8090627FF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Core", "src\cs\Bts.Core\Bts.Core.csproj", "{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Disposables", "src\cs\Bts.Disposables\Bts.Disposables.csproj", "{62067659-AA2E-4CB5-B7CE-0B38EAA92080}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Numerics", "src\cs\Bts.Numerics\Bts.Numerics.csproj", "{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -95,54 +87,6 @@ Global
|
||||
{FCFDBDBE-74B0-41C4-9011-C651B21056D4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FCFDBDBE-74B0-41C4-9011-C651B21056D4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FCFDBDBE-74B0-41C4-9011-C651B21056D4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Release|x64.Build.0 = Release|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080}.Release|x86.Build.0 = Release|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -154,9 +98,5 @@ Global
|
||||
{37E4E890-D025-4729-90F9-6F95862F47BC} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{A5FF3FAF-43CB-496B-AF4B-F61EFD645579} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{FCFDBDBE-74B0-41C4-9011-C651B21056D4} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{3BF4DF96-5AFF-4674-866A-71A8090627FF} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{CD0A3EEF-303A-44EE-85F2-76F4CE632A3B} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{62067659-AA2E-4CB5-B7CE-0B38EAA92080} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{2FE1E5D0-168A-4D83-9B18-0D48250B4BFE} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+2
-8
@@ -32,20 +32,14 @@
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"generator": "Ninja Multi-Config",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"environment": {
|
||||
"SPARK_CMAKE_CXX_FLAGS": "/WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
|
||||
"SPARK_CMAKE_CXX_FLAGS": "/MP /WX /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 /bigobj /EHsc /DCURL_STATICLIB /D_WINSOCK_DEPRECATED_NO_WARNINGS /D__TBB_NO_IMPLICIT_LINKAGE /DBOOST_ALL_NO_LIB /std:c++20 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang-cl",
|
||||
"CMAKE_CXX_COMPILER": "clang-cl",
|
||||
"CMAKE_CXX_FLAGS": "$env{SPARK_CMAKE_CXX_FLAGS}",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "$env{SPARK_CMAKE_CXX_FLAGS} /MTd",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "$env{SPARK_CMAKE_CXX_FLAGS} /MT",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": {
|
||||
"type": "BOOL",
|
||||
"value": "ON"
|
||||
},
|
||||
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG",
|
||||
"CMAKE_SHARED_LINKER_FLAGS_RELEASE": "/OPT:REF /OPT:ICF /LTCG",
|
||||
"EXTERNALS_ROOT": "${sourceDir}/externals/windows"
|
||||
|
||||
@@ -51,14 +51,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Net", "src\cs\Bts.Net\B
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.IO.Compression", "src\cs\Bts.IO.Compression\Bts.IO.Compression.csproj", "{BC277499-8215-4F9F-B9AB-07B6391110BF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Collections", "src\cs\Bts.Collections\Bts.Collections.csproj", "{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Core", "src\cs\Bts.Core\Bts.Core.csproj", "{802ECF0B-7264-4168-95D1-158E47FB65CC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Disposables", "src\cs\Bts.Disposables\Bts.Disposables.csproj", "{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Numerics", "src\cs\Bts.Numerics\Bts.Numerics.csproj", "{0354655D-2394-42BB-B1D4-2D75B9BCABF1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@@ -579,102 +571,6 @@ Global
|
||||
{BC277499-8215-4F9F-B9AB-07B6391110BF}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BC277499-8215-4F9F-B9AB-07B6391110BF}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{BC277499-8215-4F9F-B9AB-07B6391110BF}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Release|x64.Build.0 = Release|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.Release|x86.Build.0 = Release|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Release|x64.Build.0 = Release|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.Release|x86.Build.0 = Release|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -696,10 +592,6 @@ Global
|
||||
{385C4948-E080-56A6-E29E-8B0F4913175C} = {267F81EF-A8AB-49FD-9F56-D7EC3C1F7C7C}
|
||||
{43FB297B-7A4D-4835-A878-E6DF345B580C} = {385C4948-E080-56A6-E29E-8B0F4913175C}
|
||||
{BC277499-8215-4F9F-B9AB-07B6391110BF} = {385C4948-E080-56A6-E29E-8B0F4913175C}
|
||||
{C42F4CCB-9E65-4370-939A-527ACDBC4DA6} = {385C4948-E080-56A6-E29E-8B0F4913175C}
|
||||
{802ECF0B-7264-4168-95D1-158E47FB65CC} = {385C4948-E080-56A6-E29E-8B0F4913175C}
|
||||
{95C5F6C0-88E5-4338-9A4F-614CF6C03CC0} = {385C4948-E080-56A6-E29E-8B0F4913175C}
|
||||
{0354655D-2394-42BB-B1D4-2D75B9BCABF1} = {385C4948-E080-56A6-E29E-8B0F4913175C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
|
||||
+32
-4
@@ -10,7 +10,7 @@ services:
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
- PYTHON_REQUIREMENTS=${SPARKD__PYTHON_REQUIREMENTS}
|
||||
- ENTRYPOINT_SCRIPT=${SPARKD__ENTRYPOINT}
|
||||
- SPARKD_ENTRYPOINT=${SPARKD__SPARKD_ENTRYPOINT}
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
env_file:
|
||||
- .env
|
||||
@@ -19,6 +19,7 @@ services:
|
||||
- "${SPARKD__CONFIG_PORT}:${SPARKD__CONFIG_PORT}"
|
||||
- "${SPARKD__QUICKBUS_PORT}:${SPARKD__QUICKBUS_PORT}"
|
||||
- "${SPARKD__SIM_FIX_PORT}:${SPARKD__SIM_FIX_PORT}"
|
||||
entrypoint: ${SPARKD__MAIN_ENTRYPOINT}
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
@@ -35,7 +36,7 @@ services:
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
- PYTHON_REQUIREMENTS=${SPARKD__PYTHON_REQUIREMENTS}
|
||||
- ENTRYPOINT_SCRIPT=${SPARKD__ENTRYPOINT}
|
||||
- SPARKD_ENTRYPOINT=${SPARKD__SPARKD_ENTRYPOINT}
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
command: "do sleep 1; done"
|
||||
env_file:
|
||||
@@ -53,6 +54,7 @@ services:
|
||||
sparkd-symbols:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/.local/share/bts/sparkd/data
|
||||
- ${SPARKD__MD_RECORDING_DIR:-md_recording}:/md_recording
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/.local/share/bts/sparkd/conf
|
||||
build:
|
||||
dockerfile: src/app_sparkd/Dockerfile
|
||||
@@ -61,7 +63,7 @@ services:
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
- PYTHON_REQUIREMENTS=${SPARKD__PYTHON_REQUIREMENTS}
|
||||
- ENTRYPOINT_SCRIPT=${SPARKD__ENTRYPOINT}
|
||||
- SPARKD_ENTRYPOINT=${SPARKD__SPARKD_ENTRYPOINT}
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
env_file:
|
||||
- .env
|
||||
@@ -70,6 +72,33 @@ services:
|
||||
- "${SPARKD__CONFIG_PORT}:${SPARKD__CONFIG_PORT}"
|
||||
- "${SPARKD__QUICKBUS_PORT}:${SPARKD__QUICKBUS_PORT}"
|
||||
- "${SPARKD__SIM_FIX_PORT}:${SPARKD__SIM_FIX_PORT}"
|
||||
entrypoint: ${SPARKD__MAIN_ENTRYPOINT}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: any
|
||||
delay: 3s
|
||||
resources:
|
||||
limits:
|
||||
memory: "${SPARKD__MEMORY:-4gb}"
|
||||
sparkd-multicast:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/.local/share/bts/sparkd/data
|
||||
- ${SPARKD__MD_RECORDING_DIR:-md_recording}:/md_recording
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/.local/share/bts/sparkd/conf
|
||||
build:
|
||||
dockerfile: src/app_sparkd/Dockerfile
|
||||
args:
|
||||
- IMAGE=${SPARKD__IMAGE}
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
- PYTHON_REQUIREMENTS=${SPARKD__PYTHON_REQUIREMENTS}
|
||||
- SPARKD_ENTRYPOINT=${SPARKD__SPARKD_ENTRYPOINT}
|
||||
shm_size: "${SPARKD__SHM_SIZE:-2048mb}"
|
||||
env_file:
|
||||
- .env
|
||||
- ${SPARKD__CONFIG_DIR}/.env
|
||||
network_mode: "host"
|
||||
entrypoint: ${SPARKD__MAIN_ENTRYPOINT}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: any
|
||||
@@ -77,7 +106,6 @@ services:
|
||||
resources:
|
||||
limits:
|
||||
memory: "${SPARKD__MEMORY:-4gb}"
|
||||
|
||||
sparkd-tail:
|
||||
image: bluetradingsystems/linux_dotnet8
|
||||
volumes:
|
||||
|
||||
Submodule
+1
Submodule docker/linux added at 6537812262.
Submodule
+1
Submodule docker/windows added at de7d40c09d.
+1
-1
Submodule externals updated: 9fa7a9898e...2755fd6b8f.
@@ -49,14 +49,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "spark_test", "src\client\sp
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spark.Console", "src\client\Spark.Console\Spark.Console.csproj", "{2B8243FF-60C6-4607-8AAE-7762D29B0A48}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Collections", "src\cs\Bts.Collections\Bts.Collections.csproj", "{00D21F82-61F4-467F-B125-268018A185E5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Core", "src\cs\Bts.Core\Bts.Core.csproj", "{513A3F0D-46B5-4AC2-B700-8671933F6347}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Disposables", "src\cs\Bts.Disposables\Bts.Disposables.csproj", "{D419D996-9870-4FF5-82AD-08370D1C945F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Numerics", "src\cs\Bts.Numerics\Bts.Numerics.csproj", "{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -283,102 +275,6 @@ Global
|
||||
{2B8243FF-60C6-4607-8AAE-7762D29B0A48}.Release|x64.Build.0 = Release|x64
|
||||
{2B8243FF-60C6-4607-8AAE-7762D29B0A48}.Release|x86.ActiveCfg = Release|x64
|
||||
{2B8243FF-60C6-4607-8AAE-7762D29B0A48}.Release|x86.Build.0 = Release|x64
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{00D21F82-61F4-467F-B125-268018A185E5}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Release|x64.Build.0 = Release|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.Release|x86.Build.0 = Release|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.Release|x86.Build.0 = Release|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Release|x64.Build.0 = Release|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.Release|x86.Build.0 = Release|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.RelWithDebInfo|x64.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.RelWithDebInfo|x64.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.RelWithDebInfo|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.RelWithDebInfo|Any CPU.Build.0 = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.RelWithDebInfo|x86.ActiveCfg = Debug|Any CPU
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049}.RelWithDebInfo|x86.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -406,9 +302,5 @@ Global
|
||||
{D432F3E9-3D2F-4623-B7B9-CEBA6701FFC3} = {42C014A0-00C5-0620-8552-38912E891A7F}
|
||||
{DD00F5D5-6C2F-4FDA-AE3D-25CF01A9A224} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{2B8243FF-60C6-4607-8AAE-7762D29B0A48} = {C5A3B5EA-BE9F-76E5-E9B8-8A22B289B295}
|
||||
{00D21F82-61F4-467F-B125-268018A185E5} = {D7C6B9C7-1058-B1EA-FEE6-34C56B05AEDB}
|
||||
{513A3F0D-46B5-4AC2-B700-8671933F6347} = {D7C6B9C7-1058-B1EA-FEE6-34C56B05AEDB}
|
||||
{D419D996-9870-4FF5-82AD-08370D1C945F} = {D7C6B9C7-1058-B1EA-FEE6-34C56B05AEDB}
|
||||
{697BC3A3-1A98-43D3-A6E8-BB39A05EA049} = {D7C6B9C7-1058-B1EA-FEE6-34C56B05AEDB}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1 @@
|
||||
r=TimeSeriesStream(ReplayFutureLiveBBOStream("ES"))
|
||||
@@ -0,0 +1,3 @@
|
||||
x,y,z,id
|
||||
123,1.001,abc,1
|
||||
123,1.001,abc,0
|
||||
|
@@ -0,0 +1,3 @@
|
||||
x,y,z,id
|
||||
123,1.001,abc,1
|
||||
123,1.001,abc,0
|
||||
|
@@ -0,0 +1,78 @@
|
||||
id,ts_event,contract,bid_price,bid_size,ask_price,ask_size,timestamp
|
||||
76,2026-03-13T05:57:25.177965500Z,ESU5,6363.75,51,6364,63,3/13/2026 5:57:25 AM
|
||||
75,2026-03-13T05:57:25.068062900Z,ESU5,6363.75,52,6364,63,3/13/2026 5:57:25 AM
|
||||
74,2026-03-13T05:57:24.963428500Z,ESU5,6363.75,56,6364,63,3/13/2026 5:57:24 AM
|
||||
73,2026-03-13T05:57:24.781215700Z,ESU5,6363.75,57,6364,63,3/13/2026 5:57:24 AM
|
||||
72,2026-03-13T05:57:24.676290100Z,ESU5,6363.75,57,6364,63,3/13/2026 5:57:24 AM
|
||||
71,2026-03-13T05:57:24.566898400Z,ESU5,6363.75,56,6364,63,3/13/2026 5:57:24 AM
|
||||
70,2026-03-13T05:57:24.430800400Z,ESU5,6363.75,57,6364,63,3/13/2026 5:57:24 AM
|
||||
69,2026-03-13T05:57:24.273683400Z,ESU5,6363.75,56,6364,63,3/13/2026 5:57:24 AM
|
||||
68,2026-03-13T05:57:24.167656100Z,ESU5,6363.75,56,6364,64,3/13/2026 5:57:24 AM
|
||||
67,2026-03-13T05:57:23.995720100Z,ESU5,6363.75,56,6364,65,3/13/2026 5:57:23 AM
|
||||
66,2026-03-13T05:57:23.894029100Z,ESU5,6363.75,56,6364,68,3/13/2026 5:57:23 AM
|
||||
65,2026-03-13T05:57:23.728897300Z,ESU5,6363.75,56,6364,68,3/13/2026 5:57:23 AM
|
||||
64,2026-03-13T05:57:23.614316800Z,ESU5,6363.75,52,6364,68,3/13/2026 5:57:23 AM
|
||||
63,2026-03-13T05:57:23.503752700Z,ESU5,6363.75,51,6364,68,3/13/2026 5:57:23 AM
|
||||
62,2026-03-13T05:57:23.289108200Z,ESU5,6363.75,50,6364,68,3/13/2026 5:57:23 AM
|
||||
61,2026-03-13T05:57:23.155673400Z,ESU5,6363.75,49,6364,68,3/13/2026 5:57:23 AM
|
||||
60,2026-03-13T05:57:23.028898400Z,ESU5,6363.75,48,6364,68,3/13/2026 5:57:23 AM
|
||||
59,2026-03-13T05:57:22.887132700Z,ESU5,6363.75,46,6364,68,3/13/2026 5:57:22 AM
|
||||
58,2026-03-13T05:57:22.676916300Z,ESU5,6363.75,44,6364,68,3/13/2026 5:57:22 AM
|
||||
57,2026-03-13T05:57:22.520328000Z,ESU5,6363.75,43,6364,68,3/13/2026 5:57:22 AM
|
||||
56,2026-03-13T05:57:22.405244600Z,ESU5,6363.75,43,6364,69,3/13/2026 5:57:22 AM
|
||||
55,2026-03-13T05:57:22.294674100Z,ESU5,6363.75,41,6364,69,3/13/2026 5:57:22 AM
|
||||
54,2026-03-13T05:57:22.163467900Z,ESU5,6363.75,38,6364,69,3/13/2026 5:57:22 AM
|
||||
53,2026-03-13T05:57:21.992443000Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:21 AM
|
||||
52,2026-03-13T05:57:21.872338400Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:21 AM
|
||||
51,2026-03-13T05:57:21.742801800Z,ESU5,6363.75,37,6364,71,3/13/2026 5:57:21 AM
|
||||
50,2026-03-13T05:57:21.557711100Z,ESU5,6363.75,37,6364,72,3/13/2026 5:57:21 AM
|
||||
49,2026-03-13T05:57:21.434977000Z,ESU5,6363.75,37,6364,73,3/13/2026 5:57:21 AM
|
||||
48,2026-03-13T05:57:21.285751600Z,ESU5,6363.75,37,6364,72,3/13/2026 5:57:21 AM
|
||||
47,2026-03-13T05:57:21.184392000Z,ESU5,6363.75,37,6364,73,3/13/2026 5:57:21 AM
|
||||
46,2026-03-13T05:57:21.076843800Z,ESU5,6363.75,34,6364,73,3/13/2026 5:57:21 AM
|
||||
45,2026-03-13T05:57:20.894131800Z,ESU5,6363.75,32,6364,73,3/13/2026 5:57:20 AM
|
||||
44,2026-03-13T05:57:20.759550000Z,ESU5,6363.75,30,6364,73,3/13/2026 5:57:20 AM
|
||||
43,2026-03-13T05:57:20.641547900Z,ESU5,6363.75,28,6364,73,3/13/2026 5:57:20 AM
|
||||
42,2026-03-13T05:57:20.540293200Z,ESU5,6363.75,27,6364,73,3/13/2026 5:57:20 AM
|
||||
41,2026-03-13T05:57:20.439034600Z,ESU5,6363.75,27,6364,74,3/13/2026 5:57:20 AM
|
||||
40,2026-03-13T05:57:20.337795000Z,ESU5,6363.75,27,6364,73,3/13/2026 5:57:20 AM
|
||||
39,2026-03-13T05:57:20.236606600Z,ESU5,6363.75,27,6364,72,3/13/2026 5:57:20 AM
|
||||
38,2026-03-13T05:57:20.135417700Z,ESU5,6363.75,30,6364,72,3/13/2026 5:57:20 AM
|
||||
37,2026-03-13T05:57:20.034272700Z,ESU5,6363.75,32,6364,72,3/13/2026 5:57:20 AM
|
||||
36,2026-03-13T05:57:19.933096800Z,ESU5,6363.75,34,6364,72,3/13/2026 5:57:19 AM
|
||||
35,2026-03-13T05:57:19.832012600Z,ESU5,6363.75,36,6364,72,3/13/2026 5:57:19 AM
|
||||
34,2026-03-13T05:57:19.730878500Z,ESU5,6363.75,38,6364,72,3/13/2026 5:57:19 AM
|
||||
33,2026-03-13T05:57:19.629787400Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:19 AM
|
||||
32,2026-03-13T05:57:19.528697000Z,ESU5,6363.75,38,6364,70,3/13/2026 5:57:19 AM
|
||||
31,2026-03-13T05:57:19.427077000Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:19 AM
|
||||
30,2026-03-13T05:57:19.326450300Z,ESU5,6363.75,39,6364,71,3/13/2026 5:57:19 AM
|
||||
29,2026-03-13T05:57:19.225427900Z,ESU5,6363.75,39,6364,70,3/13/2026 5:57:19 AM
|
||||
28,2026-03-13T05:57:19.123339800Z,ESU5,6363.75,40,6364,70,3/13/2026 5:57:19 AM
|
||||
27,2026-03-13T05:57:19.021936500Z,ESU5,6363.75,41,6364,70,3/13/2026 5:57:19 AM
|
||||
26,2026-03-13T05:57:18.920859200Z,ESU5,6363.75,45,6364,70,3/13/2026 5:57:18 AM
|
||||
25,2026-03-13T05:57:18.820148400Z,ESU5,6363.75,46,6364,70,3/13/2026 5:57:18 AM
|
||||
24,2026-03-13T05:57:18.718988100Z,ESU5,6363.75,46,6364,69,3/13/2026 5:57:18 AM
|
||||
23,2026-03-13T05:57:18.618299700Z,ESU5,6363.75,49,6364,69,3/13/2026 5:57:18 AM
|
||||
22,2026-03-13T05:57:18.517138100Z,ESU5,6363.75,52,6364,69,3/13/2026 5:57:18 AM
|
||||
21,2026-03-13T05:57:18.416335200Z,ESU5,6363.75,53,6364,69,3/13/2026 5:57:18 AM
|
||||
20,2026-03-13T05:57:18.315335900Z,ESU5,6363.75,55,6364,69,3/13/2026 5:57:18 AM
|
||||
19,2026-03-13T05:57:18.214368600Z,ESU5,6363.75,57,6364,69,3/13/2026 5:57:18 AM
|
||||
18,2026-03-13T05:57:18.113754700Z,ESU5,6363.75,57,6364,65,3/13/2026 5:57:18 AM
|
||||
17,2026-03-13T05:57:18.012706500Z,ESU5,6363.75,56,6364,65,3/13/2026 5:57:18 AM
|
||||
16,2026-03-13T05:57:17.911672600Z,ESU5,6363.75,54,6364,65,3/13/2026 5:57:17 AM
|
||||
15,2026-03-13T05:57:17.810879900Z,ESU5,6363.75,52,6364,65,3/13/2026 5:57:17 AM
|
||||
14,2026-03-13T05:57:17.710089700Z,ESU5,6363.75,49,6364,65,3/13/2026 5:57:17 AM
|
||||
13,2026-03-13T05:57:17.609388300Z,ESU5,6363.75,49,6364,67,3/13/2026 5:57:17 AM
|
||||
12,2026-03-13T05:57:17.508697400Z,ESU5,6363.75,49,6364,67,3/13/2026 5:57:17 AM
|
||||
11,2026-03-13T05:57:17.408027000Z,ESU5,6363.75,53,6364,67,3/13/2026 5:57:17 AM
|
||||
10,2026-03-13T05:57:17.307406200Z,ESU5,6363.75,49,6364,67,3/13/2026 5:57:17 AM
|
||||
9,2026-03-13T05:57:17.206714300Z,ESU5,6363.75,49,6364,71,3/13/2026 5:57:17 AM
|
||||
8,2026-03-13T05:57:17.105530300Z,ESU5,6363.75,48,6364,71,3/13/2026 5:57:17 AM
|
||||
7,2026-03-13T05:57:17.004796800Z,ESU5,6363.75,47,6364,71,3/13/2026 5:57:17 AM
|
||||
6,2026-03-13T05:57:16.904113900Z,ESU5,6363.75,46,6364,71,3/13/2026 5:57:16 AM
|
||||
5,2026-03-13T05:57:16.803381900Z,ESU5,6363.75,43,6364,71,3/13/2026 5:57:16 AM
|
||||
4,2026-03-13T05:57:16.701969600Z,ESU5,6363.75,43,6364,72,3/13/2026 5:57:16 AM
|
||||
3,2026-03-13T05:57:16.600765600Z,ESU5,6363.75,43,6364,73,3/13/2026 5:57:16 AM
|
||||
2,2026-03-13T05:57:16.499986300Z,ESU5,6363.75,43,6364,74,3/13/2026 5:57:16 AM
|
||||
1,2026-03-13T05:57:16.399241700Z,ESU5,6363.75,43,6364,75,3/13/2026 5:57:16 AM
|
||||
0,2026-03-13T05:57:16.264038000Z,ESU5,6363.75,43,6364,76,3/13/2026 5:57:16 AM
|
||||
|
@@ -0,0 +1,91 @@
|
||||
id,ts_event,contract,bid_price,bid_size,ask_price,ask_size,timestamp
|
||||
89,2026-03-13T05:57:26.904401600Z,ESU5,6363.75,43,6364,67,3/13/2026 5:57:26 AM
|
||||
88,2026-03-13T05:57:26.778037200Z,ESU5,6363.75,43,6364,69,3/13/2026 5:57:26 AM
|
||||
87,2026-03-13T05:57:26.597038500Z,ESU5,6363.75,43,6364,69,3/13/2026 5:57:26 AM
|
||||
86,2026-03-13T05:57:26.438768300Z,ESU5,6363.75,43,6364,68,3/13/2026 5:57:26 AM
|
||||
85,2026-03-13T05:57:26.328259100Z,ESU5,6363.75,43,6364,67,3/13/2026 5:57:26 AM
|
||||
84,2026-03-13T05:57:26.216211200Z,ESU5,6363.75,44,6364,67,3/13/2026 5:57:26 AM
|
||||
83,2026-03-13T05:57:26.099281200Z,ESU5,6363.75,46,6364,67,3/13/2026 5:57:26 AM
|
||||
82,2026-03-13T05:57:25.979814900Z,ESU5,6363.75,48,6364,67,3/13/2026 5:57:25 AM
|
||||
81,2026-03-13T05:57:25.852317700Z,ESU5,6363.75,48,6364,66,3/13/2026 5:57:25 AM
|
||||
80,2026-03-13T05:57:25.684323100Z,ESU5,6363.75,48,6364,65,3/13/2026 5:57:25 AM
|
||||
79,2026-03-13T05:57:25.539436900Z,ESU5,6363.75,48,6364,64,3/13/2026 5:57:25 AM
|
||||
78,2026-03-13T05:57:25.425439200Z,ESU5,6363.75,49,6364,64,3/13/2026 5:57:25 AM
|
||||
77,2026-03-13T05:57:25.298054100Z,ESU5,6363.75,51,6364,64,3/13/2026 5:57:25 AM
|
||||
76,2026-03-13T05:57:25.177965500Z,ESU5,6363.75,51,6364,63,3/13/2026 5:57:25 AM
|
||||
75,2026-03-13T05:57:25.068062900Z,ESU5,6363.75,52,6364,63,3/13/2026 5:57:25 AM
|
||||
74,2026-03-13T05:57:24.963428500Z,ESU5,6363.75,56,6364,63,3/13/2026 5:57:24 AM
|
||||
73,2026-03-13T05:57:24.781215700Z,ESU5,6363.75,57,6364,63,3/13/2026 5:57:24 AM
|
||||
72,2026-03-13T05:57:24.676290100Z,ESU5,6363.75,57,6364,63,3/13/2026 5:57:24 AM
|
||||
71,2026-03-13T05:57:24.566898400Z,ESU5,6363.75,56,6364,63,3/13/2026 5:57:24 AM
|
||||
70,2026-03-13T05:57:24.430800400Z,ESU5,6363.75,57,6364,63,3/13/2026 5:57:24 AM
|
||||
69,2026-03-13T05:57:24.273683400Z,ESU5,6363.75,56,6364,63,3/13/2026 5:57:24 AM
|
||||
68,2026-03-13T05:57:24.167656100Z,ESU5,6363.75,56,6364,64,3/13/2026 5:57:24 AM
|
||||
67,2026-03-13T05:57:23.995720100Z,ESU5,6363.75,56,6364,65,3/13/2026 5:57:23 AM
|
||||
66,2026-03-13T05:57:23.894029100Z,ESU5,6363.75,56,6364,68,3/13/2026 5:57:23 AM
|
||||
65,2026-03-13T05:57:23.728897300Z,ESU5,6363.75,56,6364,68,3/13/2026 5:57:23 AM
|
||||
64,2026-03-13T05:57:23.614316800Z,ESU5,6363.75,52,6364,68,3/13/2026 5:57:23 AM
|
||||
63,2026-03-13T05:57:23.503752700Z,ESU5,6363.75,51,6364,68,3/13/2026 5:57:23 AM
|
||||
62,2026-03-13T05:57:23.289108200Z,ESU5,6363.75,50,6364,68,3/13/2026 5:57:23 AM
|
||||
61,2026-03-13T05:57:23.155673400Z,ESU5,6363.75,49,6364,68,3/13/2026 5:57:23 AM
|
||||
60,2026-03-13T05:57:23.028898400Z,ESU5,6363.75,48,6364,68,3/13/2026 5:57:23 AM
|
||||
59,2026-03-13T05:57:22.887132700Z,ESU5,6363.75,46,6364,68,3/13/2026 5:57:22 AM
|
||||
58,2026-03-13T05:57:22.676916300Z,ESU5,6363.75,44,6364,68,3/13/2026 5:57:22 AM
|
||||
57,2026-03-13T05:57:22.520328000Z,ESU5,6363.75,43,6364,68,3/13/2026 5:57:22 AM
|
||||
56,2026-03-13T05:57:22.405244600Z,ESU5,6363.75,43,6364,69,3/13/2026 5:57:22 AM
|
||||
55,2026-03-13T05:57:22.294674100Z,ESU5,6363.75,41,6364,69,3/13/2026 5:57:22 AM
|
||||
54,2026-03-13T05:57:22.163467900Z,ESU5,6363.75,38,6364,69,3/13/2026 5:57:22 AM
|
||||
53,2026-03-13T05:57:21.992443000Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:21 AM
|
||||
52,2026-03-13T05:57:21.872338400Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:21 AM
|
||||
51,2026-03-13T05:57:21.742801800Z,ESU5,6363.75,37,6364,71,3/13/2026 5:57:21 AM
|
||||
50,2026-03-13T05:57:21.557711100Z,ESU5,6363.75,37,6364,72,3/13/2026 5:57:21 AM
|
||||
49,2026-03-13T05:57:21.434977000Z,ESU5,6363.75,37,6364,73,3/13/2026 5:57:21 AM
|
||||
48,2026-03-13T05:57:21.285751600Z,ESU5,6363.75,37,6364,72,3/13/2026 5:57:21 AM
|
||||
47,2026-03-13T05:57:21.184392000Z,ESU5,6363.75,37,6364,73,3/13/2026 5:57:21 AM
|
||||
46,2026-03-13T05:57:21.076843800Z,ESU5,6363.75,34,6364,73,3/13/2026 5:57:21 AM
|
||||
45,2026-03-13T05:57:20.894131800Z,ESU5,6363.75,32,6364,73,3/13/2026 5:57:20 AM
|
||||
44,2026-03-13T05:57:20.759550000Z,ESU5,6363.75,30,6364,73,3/13/2026 5:57:20 AM
|
||||
43,2026-03-13T05:57:20.641547900Z,ESU5,6363.75,28,6364,73,3/13/2026 5:57:20 AM
|
||||
42,2026-03-13T05:57:20.540293200Z,ESU5,6363.75,27,6364,73,3/13/2026 5:57:20 AM
|
||||
41,2026-03-13T05:57:20.439034600Z,ESU5,6363.75,27,6364,74,3/13/2026 5:57:20 AM
|
||||
40,2026-03-13T05:57:20.337795000Z,ESU5,6363.75,27,6364,73,3/13/2026 5:57:20 AM
|
||||
39,2026-03-13T05:57:20.236606600Z,ESU5,6363.75,27,6364,72,3/13/2026 5:57:20 AM
|
||||
38,2026-03-13T05:57:20.135417700Z,ESU5,6363.75,30,6364,72,3/13/2026 5:57:20 AM
|
||||
37,2026-03-13T05:57:20.034272700Z,ESU5,6363.75,32,6364,72,3/13/2026 5:57:20 AM
|
||||
36,2026-03-13T05:57:19.933096800Z,ESU5,6363.75,34,6364,72,3/13/2026 5:57:19 AM
|
||||
35,2026-03-13T05:57:19.832012600Z,ESU5,6363.75,36,6364,72,3/13/2026 5:57:19 AM
|
||||
34,2026-03-13T05:57:19.730878500Z,ESU5,6363.75,38,6364,72,3/13/2026 5:57:19 AM
|
||||
33,2026-03-13T05:57:19.629787400Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:19 AM
|
||||
32,2026-03-13T05:57:19.528697000Z,ESU5,6363.75,38,6364,70,3/13/2026 5:57:19 AM
|
||||
31,2026-03-13T05:57:19.427077000Z,ESU5,6363.75,38,6364,71,3/13/2026 5:57:19 AM
|
||||
30,2026-03-13T05:57:19.326450300Z,ESU5,6363.75,39,6364,71,3/13/2026 5:57:19 AM
|
||||
29,2026-03-13T05:57:19.225427900Z,ESU5,6363.75,39,6364,70,3/13/2026 5:57:19 AM
|
||||
28,2026-03-13T05:57:19.123339800Z,ESU5,6363.75,40,6364,70,3/13/2026 5:57:19 AM
|
||||
27,2026-03-13T05:57:19.021936500Z,ESU5,6363.75,41,6364,70,3/13/2026 5:57:19 AM
|
||||
26,2026-03-13T05:57:18.920859200Z,ESU5,6363.75,45,6364,70,3/13/2026 5:57:18 AM
|
||||
25,2026-03-13T05:57:18.820148400Z,ESU5,6363.75,46,6364,70,3/13/2026 5:57:18 AM
|
||||
24,2026-03-13T05:57:18.718988100Z,ESU5,6363.75,46,6364,69,3/13/2026 5:57:18 AM
|
||||
23,2026-03-13T05:57:18.618299700Z,ESU5,6363.75,49,6364,69,3/13/2026 5:57:18 AM
|
||||
22,2026-03-13T05:57:18.517138100Z,ESU5,6363.75,52,6364,69,3/13/2026 5:57:18 AM
|
||||
21,2026-03-13T05:57:18.416335200Z,ESU5,6363.75,53,6364,69,3/13/2026 5:57:18 AM
|
||||
20,2026-03-13T05:57:18.315335900Z,ESU5,6363.75,55,6364,69,3/13/2026 5:57:18 AM
|
||||
19,2026-03-13T05:57:18.214368600Z,ESU5,6363.75,57,6364,69,3/13/2026 5:57:18 AM
|
||||
18,2026-03-13T05:57:18.113754700Z,ESU5,6363.75,57,6364,65,3/13/2026 5:57:18 AM
|
||||
17,2026-03-13T05:57:18.012706500Z,ESU5,6363.75,56,6364,65,3/13/2026 5:57:18 AM
|
||||
16,2026-03-13T05:57:17.911672600Z,ESU5,6363.75,54,6364,65,3/13/2026 5:57:17 AM
|
||||
15,2026-03-13T05:57:17.810879900Z,ESU5,6363.75,52,6364,65,3/13/2026 5:57:17 AM
|
||||
14,2026-03-13T05:57:17.710089700Z,ESU5,6363.75,49,6364,65,3/13/2026 5:57:17 AM
|
||||
13,2026-03-13T05:57:17.609388300Z,ESU5,6363.75,49,6364,67,3/13/2026 5:57:17 AM
|
||||
12,2026-03-13T05:57:17.508697400Z,ESU5,6363.75,49,6364,67,3/13/2026 5:57:17 AM
|
||||
11,2026-03-13T05:57:17.408027000Z,ESU5,6363.75,53,6364,67,3/13/2026 5:57:17 AM
|
||||
10,2026-03-13T05:57:17.307406200Z,ESU5,6363.75,49,6364,67,3/13/2026 5:57:17 AM
|
||||
9,2026-03-13T05:57:17.206714300Z,ESU5,6363.75,49,6364,71,3/13/2026 5:57:17 AM
|
||||
8,2026-03-13T05:57:17.105530300Z,ESU5,6363.75,48,6364,71,3/13/2026 5:57:17 AM
|
||||
7,2026-03-13T05:57:17.004796800Z,ESU5,6363.75,47,6364,71,3/13/2026 5:57:17 AM
|
||||
6,2026-03-13T05:57:16.904113900Z,ESU5,6363.75,46,6364,71,3/13/2026 5:57:16 AM
|
||||
5,2026-03-13T05:57:16.803381900Z,ESU5,6363.75,43,6364,71,3/13/2026 5:57:16 AM
|
||||
4,2026-03-13T05:57:16.701969600Z,ESU5,6363.75,43,6364,72,3/13/2026 5:57:16 AM
|
||||
3,2026-03-13T05:57:16.600765600Z,ESU5,6363.75,43,6364,73,3/13/2026 5:57:16 AM
|
||||
2,2026-03-13T05:57:16.499986300Z,ESU5,6363.75,43,6364,74,3/13/2026 5:57:16 AM
|
||||
1,2026-03-13T05:57:16.399241700Z,ESU5,6363.75,43,6364,75,3/13/2026 5:57:16 AM
|
||||
0,2026-03-13T05:57:16.264038000Z,ESU5,6363.75,43,6364,76,3/13/2026 5:57:16 AM
|
||||
|
@@ -0,0 +1,187 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataPacket:
|
||||
state: List[Any]
|
||||
deleted_ids: List[int]
|
||||
added_ids: List[int]
|
||||
|
||||
|
||||
@dataclass
|
||||
class DslResponse:
|
||||
data_packet: DataPacket | None
|
||||
req_id: str | None
|
||||
error: str | None
|
||||
|
||||
|
||||
def _resolve_interop_exe() -> str:
|
||||
env_path = os.environ.get("BLUEORB_DSL_INTEROP")
|
||||
if env_path and os.path.isfile(env_path):
|
||||
return env_path
|
||||
candidates = [
|
||||
"/workspaces/spark/build/Debug/bin/net8.0/BlueOrbDSLInteropServer",
|
||||
"/workspaces/spark/build/Release/bin/net8.0/BlueOrbDSLInteropServer",
|
||||
]
|
||||
for path in candidates:
|
||||
if os.path.isfile(path):
|
||||
return path
|
||||
raise FileNotFoundError(
|
||||
"BlueOrbDSLInterop executable not found. "
|
||||
"Set BLUEORB_DSL_INTEROP to the full path."
|
||||
)
|
||||
|
||||
_interop_proc: Optional[subprocess.Popen] = None
|
||||
_reader_thread: Optional[threading.Thread] = None
|
||||
_callbacks: Dict[str, Callable[[DslResponse], None]] = {}
|
||||
_first_response_events: Dict[str, threading.Event] = {}
|
||||
_first_responses: Dict[str, DslResponse] = {}
|
||||
_state_lock = threading.Lock()
|
||||
|
||||
|
||||
def start_interop() -> None:
|
||||
"""
|
||||
Start the BlueOrbDSLInteropServer process if it's not already running.
|
||||
"""
|
||||
global _interop_proc
|
||||
if _interop_proc is not None and _interop_proc.poll() is None:
|
||||
return
|
||||
exe = _resolve_interop_exe()
|
||||
_interop_proc = subprocess.Popen(
|
||||
[exe],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
_start_reader_thread()
|
||||
|
||||
|
||||
def stop_interop() -> None:
|
||||
"""
|
||||
Stop the BlueOrbDSLInteropServer process if it's running.
|
||||
"""
|
||||
global _interop_proc
|
||||
if _interop_proc is None:
|
||||
return
|
||||
if _interop_proc.poll() is None and _interop_proc.stdin is not None:
|
||||
_interop_proc.stdin.write(":exit\n")
|
||||
_interop_proc.stdin.flush()
|
||||
_interop_proc.stdin.close()
|
||||
_interop_proc.wait(timeout=5)
|
||||
global _reader_thread
|
||||
if _reader_thread is not None:
|
||||
_reader_thread.join(timeout=1)
|
||||
_reader_thread = None
|
||||
with _state_lock:
|
||||
_callbacks.clear()
|
||||
_first_response_events.clear()
|
||||
_first_responses.clear()
|
||||
_interop_proc = None
|
||||
|
||||
|
||||
def get_interop_status() -> tuple[bool, int | None]:
|
||||
"""
|
||||
Returns current interop process status as (is_running, exit_code).
|
||||
exit_code is None when process was never started or is still running.
|
||||
"""
|
||||
proc = _interop_proc
|
||||
if proc is None:
|
||||
return (False, None)
|
||||
rc = proc.poll()
|
||||
return (rc is None, rc)
|
||||
|
||||
|
||||
def get_dsl(dsl: str, req_id: str, callback: Callable[[DslResponse], None]) -> DslResponse:
|
||||
"""
|
||||
Sends the DSL to BlueOrbDSLInteropServer and returns the first response for this req_id.
|
||||
Subsequent streaming updates for the same req_id are delivered via callback.
|
||||
Requires start_interop() to be called first.
|
||||
"""
|
||||
assert _interop_proc is not None and _interop_proc.poll() is None, (
|
||||
"Interop process is not running. Call start_interop() first."
|
||||
)
|
||||
assert _interop_proc.stdin is not None
|
||||
|
||||
payload = {"dsl": dsl, "req_id": req_id}
|
||||
first_event = threading.Event()
|
||||
with _state_lock:
|
||||
_callbacks[req_id] = callback
|
||||
_first_response_events[req_id] = first_event
|
||||
_first_responses.pop(req_id, None)
|
||||
|
||||
_interop_proc.stdin.write(json.dumps(payload) + "\n")
|
||||
_interop_proc.stdin.flush()
|
||||
|
||||
if not first_event.wait(timeout=10):
|
||||
with _state_lock:
|
||||
_first_response_events.pop(req_id, None)
|
||||
_callbacks.pop(req_id, None)
|
||||
raise TimeoutError(f"No response received for req_id '{req_id}' from BlueOrbDSLInterop.")
|
||||
|
||||
with _state_lock:
|
||||
response = _first_responses.pop(req_id, None)
|
||||
_first_response_events.pop(req_id, None)
|
||||
if response is None:
|
||||
raise RuntimeError(f"Missing first response for req_id '{req_id}'.")
|
||||
return response
|
||||
|
||||
|
||||
def _start_reader_thread() -> None:
|
||||
global _reader_thread
|
||||
if _reader_thread is not None and _reader_thread.is_alive():
|
||||
return
|
||||
_reader_thread = threading.Thread(target=_reader_loop, daemon=True)
|
||||
_reader_thread.start()
|
||||
|
||||
|
||||
def _reader_loop() -> None:
|
||||
while True:
|
||||
proc = _interop_proc
|
||||
if proc is None or proc.poll() is not None:
|
||||
return
|
||||
assert proc.stdout is not None
|
||||
raw = proc.stdout.readline()
|
||||
if raw == "":
|
||||
return
|
||||
|
||||
line = raw.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
try:
|
||||
payload = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
response = DslResponse(
|
||||
data_packet=DataPacket(state=[payload.get("data_packet")], deleted_ids=[], added_ids=[]),
|
||||
req_id=payload.get("req_id"),
|
||||
error=payload.get("error"),
|
||||
)
|
||||
req_id = response.req_id
|
||||
if not req_id:
|
||||
continue
|
||||
|
||||
callback: Optional[Callable[[DslResponse], None]]
|
||||
event: Optional[threading.Event]
|
||||
with _state_lock:
|
||||
callback = _callbacks.get(req_id)
|
||||
event = _first_response_events.get(req_id)
|
||||
if event is not None and req_id not in _first_responses:
|
||||
_first_responses[req_id] = response
|
||||
event.set()
|
||||
|
||||
if callback is not None:
|
||||
try:
|
||||
callback(response)
|
||||
except Exception:
|
||||
# Keep the reader alive if callback logic fails.
|
||||
pass
|
||||
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
_here = os.path.dirname(os.path.abspath(__file__))
|
||||
_parent = os.path.dirname(_here)
|
||||
if _parent not in sys.path:
|
||||
sys.path.insert(0, _parent)
|
||||
|
||||
from BlueOrbDSL import get_dsl, start_interop, stop_interop, DslResponse
|
||||
|
||||
|
||||
def on_packet(response: DslResponse) -> None:
|
||||
print("callback from DSL Server, DslResponse:", response)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
start_interop()
|
||||
try:
|
||||
while True:
|
||||
dsl = input("Enter DSL (or 'quit'): ").strip()
|
||||
if dsl.lower() == "quit":
|
||||
break
|
||||
if not dsl:
|
||||
continue
|
||||
response = get_dsl(dsl, str(uuid.uuid4()), on_packet)
|
||||
print("return:", response)
|
||||
finally:
|
||||
stop_interop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,844 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import uuid
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
|
||||
from rich.text import Text
|
||||
from rich.style import Style
|
||||
from textual import events
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.binding import Binding
|
||||
from textual.containers import Container, Horizontal, Vertical
|
||||
from textual.widgets.text_area import TextAreaTheme
|
||||
from textual.widgets import Button, DataTable, Input, Static, TabbedContent, TabPane, TextArea, Tree
|
||||
|
||||
_here = os.path.dirname(os.path.abspath(__file__))
|
||||
_parent = os.path.dirname(_here)
|
||||
if _parent not in sys.path:
|
||||
sys.path.insert(0, _parent)
|
||||
|
||||
from BlueOrbDSL import DslResponse, get_dsl, get_interop_status, start_interop, stop_interop
|
||||
|
||||
|
||||
class DSQALiveConsole(App):
|
||||
DEFAULT_QUERY = (
|
||||
'FROM market.ticks\n'
|
||||
'WHERE symbol IN ("BTCUSD", "ETHUSD")\n'
|
||||
"SELECT symbol, price, change, time"
|
||||
)
|
||||
LAST_QUERY_PATH = os.path.join(_here, "DSQA_LAST_EXECUTED_QUERY.txt")
|
||||
DSL_HIGHLIGHT_QUERY = r"""
|
||||
; comments
|
||||
(comment) @comment
|
||||
|
||||
; assignment vars: lhs in x = SomeStream(...)
|
||||
(assignment_expression
|
||||
left: (identifier) @variable)
|
||||
|
||||
; stream operators (function names ending with Stream)
|
||||
(call_expression
|
||||
function: (identifier) @function
|
||||
(#match? @function "^[A-Za-z_][A-Za-z0-9_]*Stream$"))
|
||||
|
||||
; normal function calls
|
||||
(call_expression
|
||||
function: (identifier) @function.method)
|
||||
|
||||
; arguments and literals
|
||||
(arguments (identifier) @parameter)
|
||||
(string) @string
|
||||
(number) @number
|
||||
(true) @constant.builtin
|
||||
(false) @constant.builtin
|
||||
(null) @constant.builtin
|
||||
"""
|
||||
|
||||
BINDINGS = [
|
||||
Binding("ctrl+r", "execute", "Execute"),
|
||||
Binding("f11", "execute", show=False),
|
||||
Binding("alt+enter", "execute", show=False),
|
||||
# Override Textual's default Ctrl+Q quit to avoid accidental VS Code close.
|
||||
Binding("ctrl+q", "noop", show=False),
|
||||
Binding("ctrl+x", "quit", "Quit"),
|
||||
]
|
||||
CSS = """
|
||||
Screen {
|
||||
background: #060a1c;
|
||||
color: #d8dff4;
|
||||
}
|
||||
|
||||
#window_close_button {
|
||||
width: 3;
|
||||
min-width: 3;
|
||||
height: 1;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: #3a1015;
|
||||
color: #ff9ca8;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
#window_close_button:hover,
|
||||
#window_close_button:focus {
|
||||
background: #5a1620;
|
||||
color: #ffd6db;
|
||||
}
|
||||
|
||||
#root {
|
||||
padding: 0 1 0 1;
|
||||
height: 1fr;
|
||||
}
|
||||
|
||||
#query_panel {
|
||||
background: #070d27;
|
||||
height: 33%;
|
||||
margin-top: 1;
|
||||
}
|
||||
|
||||
#query_header_row {
|
||||
height: 1;
|
||||
border-bottom: solid #596285;
|
||||
}
|
||||
|
||||
#query_header {
|
||||
width: auto;
|
||||
color: #9eb0d4;
|
||||
content-align: left middle;
|
||||
}
|
||||
|
||||
#query_header_spacer {
|
||||
width: 1fr;
|
||||
}
|
||||
|
||||
#query_input {
|
||||
border: solid #697597;
|
||||
background: #050b22;
|
||||
color: #cfd7eb;
|
||||
height: 1fr;
|
||||
padding-left: 1;
|
||||
}
|
||||
|
||||
#results_panel {
|
||||
background: #070d27;
|
||||
height: 1fr;
|
||||
margin-top: 1;
|
||||
}
|
||||
|
||||
#results_toolbar {
|
||||
height: 3;
|
||||
padding: 0 1;
|
||||
}
|
||||
|
||||
#results_left {
|
||||
width: auto;
|
||||
height: 3;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#stream_toggle_button {
|
||||
width: auto;
|
||||
min-width: 11;
|
||||
margin-top: 0;
|
||||
margin-left: 1;
|
||||
border: none;
|
||||
background: #070d27;
|
||||
color: #79afe7;
|
||||
}
|
||||
|
||||
#stream_toggle_button:hover,
|
||||
#stream_toggle_button:focus {
|
||||
background: #111a3f;
|
||||
color: #9bc9f6;
|
||||
}
|
||||
|
||||
#execute_button {
|
||||
width: 5;
|
||||
min-width: 5;
|
||||
margin-top: 0;
|
||||
margin-left: 1;
|
||||
border: none;
|
||||
background: #10341f;
|
||||
color: #7ef1ac;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
#execute_button:hover,
|
||||
#execute_button:focus {
|
||||
background: #1a4f30;
|
||||
color: #b3ffd0;
|
||||
}
|
||||
|
||||
#results_actions {
|
||||
width: auto;
|
||||
height: 3;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#results_spacer {
|
||||
width: 1fr;
|
||||
}
|
||||
|
||||
#results_search {
|
||||
width: 30;
|
||||
min-width: 24;
|
||||
margin-right: 1;
|
||||
border: none;
|
||||
background: #060d28;
|
||||
color: #d5def3;
|
||||
padding: 0 1;
|
||||
}
|
||||
|
||||
#search_button,
|
||||
#copy_button,
|
||||
#export_button {
|
||||
width: auto;
|
||||
min-width: 11;
|
||||
margin-left: 1;
|
||||
border: none;
|
||||
background: #070d27;
|
||||
color: #79afe7;
|
||||
}
|
||||
|
||||
#search_button:hover,
|
||||
#copy_button:hover,
|
||||
#export_button:hover,
|
||||
#search_button:focus,
|
||||
#copy_button:focus,
|
||||
#export_button:focus {
|
||||
background: #111a3f;
|
||||
color: #9bc9f6;
|
||||
}
|
||||
|
||||
#results_table {
|
||||
border: solid #697597;
|
||||
background: #050b22;
|
||||
height: 1fr;
|
||||
}
|
||||
|
||||
#results_table .datatable--header,
|
||||
#results_table .datatable--header-hover,
|
||||
#results_table .datatable--header-cursor {
|
||||
background: #0c1535;
|
||||
color: #6ea6df;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
#results_table .datatable--even-row {
|
||||
background: #050b22;
|
||||
}
|
||||
|
||||
#results_table .datatable--odd-row {
|
||||
background: #07102a;
|
||||
}
|
||||
|
||||
#results_table .datatable--cursor {
|
||||
background: #19335b;
|
||||
color: #dbe8ff;
|
||||
}
|
||||
|
||||
#results_table .datatable--fixed-cursor {
|
||||
background: #132949;
|
||||
color: #c8dbff;
|
||||
}
|
||||
|
||||
#results_table.error .datatable--odd-row,
|
||||
#results_table.error .datatable--even-row,
|
||||
#results_table.error .datatable--cursor,
|
||||
#results_table.error .datatable--fixed-cursor {
|
||||
color: #f17486;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
#results_panel.paused {
|
||||
background: #150f1f;
|
||||
}
|
||||
|
||||
#results_table.paused {
|
||||
background: #130f18;
|
||||
}
|
||||
|
||||
#results_table.paused .datatable--header,
|
||||
#results_table.paused .datatable--header-hover,
|
||||
#results_table.paused .datatable--header-cursor {
|
||||
background: #262338;
|
||||
color: #8b90a1;
|
||||
text-style: bold;
|
||||
}
|
||||
|
||||
#results_tabs {
|
||||
height: 1fr;
|
||||
background: #070d27;
|
||||
}
|
||||
|
||||
#data_tab,
|
||||
#tree_tab {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#ops_tree {
|
||||
border: solid #697597;
|
||||
background: #050b22;
|
||||
color: #cfd7eb;
|
||||
height: 1fr;
|
||||
}
|
||||
|
||||
#bottom_status_bar {
|
||||
border-top: solid #596285;
|
||||
background: #070d27;
|
||||
height: 2;
|
||||
margin: 0;
|
||||
padding: 0 1;
|
||||
}
|
||||
|
||||
#status_right_wrap {
|
||||
width: 1fr;
|
||||
}
|
||||
|
||||
#status_row {
|
||||
height: 1;
|
||||
margin-top: 0;
|
||||
width: 1fr;
|
||||
}
|
||||
|
||||
#live_status {
|
||||
width: 1fr;
|
||||
color: #b3bed9;
|
||||
content-align: right middle;
|
||||
}
|
||||
"""
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with Container(id="root"):
|
||||
with Vertical(id="query_panel"):
|
||||
with Horizontal(id="query_header_row"):
|
||||
yield Static("DSL Query", id="query_header")
|
||||
yield Static("", id="query_header_spacer")
|
||||
yield Button("✕", id="window_close_button")
|
||||
yield TextArea(
|
||||
text=self._load_last_query(),
|
||||
id="query_input",
|
||||
language="javascript",
|
||||
theme="vscode_dark",
|
||||
show_line_numbers=True,
|
||||
)
|
||||
with Vertical(id="results_panel"):
|
||||
with Horizontal(id="results_toolbar"):
|
||||
with Horizontal(id="results_left"):
|
||||
yield Button("▶", id="execute_button")
|
||||
yield Button("⏸ Pause", id="stream_toggle_button")
|
||||
yield Static("", id="results_spacer")
|
||||
with Horizontal(id="results_actions"):
|
||||
yield Input(placeholder="Search: col:value", id="results_search")
|
||||
yield Button("⌕ Search", id="search_button")
|
||||
yield Button("⧉ Copy", id="copy_button")
|
||||
yield Button("⇩ Export", id="export_button")
|
||||
with TabbedContent(initial="data_tab", id="results_tabs"):
|
||||
with TabPane("Data", id="data_tab"):
|
||||
table = DataTable(id="results_table")
|
||||
table.cursor_type = "cell"
|
||||
table.show_cursor = True
|
||||
table.zebra_stripes = True
|
||||
yield table
|
||||
with TabPane("Operators", id="tree_tab"):
|
||||
tree = Tree("Assemblies", id="ops_tree")
|
||||
tree.show_root = False
|
||||
yield tree
|
||||
with Horizontal(id="bottom_status_bar"):
|
||||
with Horizontal(id="status_right_wrap"):
|
||||
with Horizontal(id="status_row"):
|
||||
yield Static(
|
||||
"Rows: 0 | Rate: 0.0/s | Total Updates: 0 | Uptime: 00:00:00 | Last Update: --:--:--",
|
||||
id="live_status",
|
||||
)
|
||||
|
||||
def on_mount(self) -> None:
|
||||
self._update_timestamps: deque[float] = deque()
|
||||
self._last_update_at: datetime | None = None
|
||||
self._stream_started_at: float | None = None
|
||||
self._total_updates = 0
|
||||
self._last_row_count = 0
|
||||
self._current_col_names: list[str] = []
|
||||
self._current_rows: list[dict[str, Any]] = []
|
||||
self._column_width_cache: dict[str, int] = {}
|
||||
self._ops_catalog_rows: list[dict[str, Any]] = []
|
||||
self._ops_catalog_error: str | None = None
|
||||
self._ops_catalog_loaded = False
|
||||
self._ops_catalog_loading = False
|
||||
self._interop_is_running = False
|
||||
self._interop_exit_code: int | None = None
|
||||
self._grid_updates_enabled = True
|
||||
self._paused_latest_response: DslResponse | None = None
|
||||
self._ensure_interop_started()
|
||||
self._refresh_ops_tree()
|
||||
self._refresh_ops_tree_async()
|
||||
self._configure_query_highlighting()
|
||||
self._set_pause_visuals()
|
||||
self.set_interval(0.5, self._refresh_status)
|
||||
|
||||
def _configure_query_highlighting(self) -> None:
|
||||
query_input = self.query_one("#query_input", TextArea)
|
||||
query_input.language = "javascript"
|
||||
dsl_theme = TextAreaTheme(
|
||||
"dsqa_ide",
|
||||
base_style=Style.parse("#d7deee on #171a22"),
|
||||
gutter_style=Style.parse("#8a93a8 on #1c212b"),
|
||||
cursor_style=Style.parse("#ffffff on #2b3242"),
|
||||
cursor_line_style=Style.parse("on #202534"),
|
||||
cursor_line_gutter_style=Style.parse("#a6afc4 on #202534"),
|
||||
selection_style=Style.parse("on #2a3f67"),
|
||||
bracket_matching_style=Style.parse("bold #7fd9ff"),
|
||||
syntax_styles={
|
||||
"comment": Style.parse("italic #6f778a"),
|
||||
"variable": Style.parse("bold #4ec9b0"),
|
||||
"function": Style.parse("bold #4fc1ff"),
|
||||
"function.method": Style.parse("bold #70d4ff"),
|
||||
"parameter": Style.parse("#c6d4f8"),
|
||||
"string": Style.parse("#d7ba7d"),
|
||||
"number": Style.parse("#b5cea8"),
|
||||
"constant.builtin": Style.parse("bold #569cd6"),
|
||||
},
|
||||
)
|
||||
query_input.register_theme(dsl_theme)
|
||||
query_input.theme = "dsqa_ide"
|
||||
try:
|
||||
query_input.update_highlight_query(self.DSL_HIGHLIGHT_QUERY)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def on_shutdown(self) -> None:
|
||||
stop_interop()
|
||||
|
||||
@staticmethod
|
||||
def _ensure_interop_started() -> None:
|
||||
try:
|
||||
start_interop()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def action_execute(self) -> None:
|
||||
tabs = self.query_one("#results_tabs", TabbedContent)
|
||||
tabs.active = "data_tab"
|
||||
self._grid_updates_enabled = True
|
||||
self._set_stream_toggle_label()
|
||||
self._set_pause_visuals()
|
||||
self._execute_query_async()
|
||||
|
||||
def action_noop(self) -> None:
|
||||
pass
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||
button_id = event.button.id
|
||||
if button_id == "search_button":
|
||||
self._search_results()
|
||||
elif button_id == "copy_button":
|
||||
self._copy_selected_cell()
|
||||
elif button_id == "export_button":
|
||||
self._export_results_csv()
|
||||
elif button_id == "execute_button":
|
||||
self.action_execute()
|
||||
elif button_id == "window_close_button":
|
||||
self.exit()
|
||||
elif button_id == "stream_toggle_button":
|
||||
self._toggle_stream_painting()
|
||||
|
||||
def on_input_submitted(self, event: Input.Submitted) -> None:
|
||||
if event.input.id == "results_search":
|
||||
self._search_results()
|
||||
|
||||
def on_click(self, event: events.Click) -> None:
|
||||
if getattr(event.widget, "id", None) != "ops_tree":
|
||||
return
|
||||
line = event.style.meta.get("line")
|
||||
if line is None:
|
||||
return
|
||||
tree = self.query_one("#ops_tree", Tree)
|
||||
node = tree.get_node_at_line(line)
|
||||
if node is None:
|
||||
return
|
||||
node_data = node.data
|
||||
if not isinstance(node_data, dict) or node_data.get("kind") != "constructor":
|
||||
return
|
||||
self._append_operator_to_query(self._stringify(node_data.get("op", "")).strip())
|
||||
|
||||
def _append_operator_to_query(self, op_name: str) -> None:
|
||||
if not op_name:
|
||||
return
|
||||
query_input = self.query_one("#query_input", TextArea)
|
||||
existing = query_input.text
|
||||
if existing.strip():
|
||||
separator = "" if existing.endswith("\n") else "\n"
|
||||
query_input.text = f"{existing}{separator}{op_name}"
|
||||
else:
|
||||
query_input.text = op_name
|
||||
query_input.focus()
|
||||
|
||||
def _execute_query_async(self) -> None:
|
||||
self._ensure_interop_started()
|
||||
query = self.query_one(TextArea).text.strip()
|
||||
if not query:
|
||||
return
|
||||
self._column_width_cache.clear()
|
||||
self._save_last_query(query)
|
||||
self._update_timestamps.clear()
|
||||
self._last_update_at = None
|
||||
self._stream_started_at = time.monotonic()
|
||||
self._total_updates = 0
|
||||
self._last_row_count = 0
|
||||
self._paused_latest_response = None
|
||||
self._refresh_status()
|
||||
|
||||
req_id = str(uuid.uuid4())
|
||||
|
||||
def _run() -> None:
|
||||
try:
|
||||
def _on_response(resp: DslResponse) -> None:
|
||||
self.call_from_thread(self._render_response, resp)
|
||||
|
||||
get_dsl(query, req_id, _on_response)
|
||||
except Exception as exc:
|
||||
error_resp = DslResponse(data_packet=None, req_id=req_id, error=str(exc))
|
||||
self.call_from_thread(self._render_response, error_resp)
|
||||
|
||||
threading.Thread(target=_run, daemon=True).start()
|
||||
|
||||
def _render_response(self, response: DslResponse) -> None:
|
||||
if not self._grid_updates_enabled:
|
||||
self._paused_latest_response = response
|
||||
return
|
||||
self._render_response_internal(response)
|
||||
|
||||
def _render_response_internal(self, response: DslResponse) -> None:
|
||||
self._record_update()
|
||||
table = self.query_one(DataTable)
|
||||
table.remove_class("error")
|
||||
prev_scroll_x = table.scroll_offset.x
|
||||
prev_scroll_y = table.scroll_offset.y
|
||||
table.clear(columns=True)
|
||||
|
||||
if response.error:
|
||||
table.add_class("error")
|
||||
error_text = self._stringify(response.error)
|
||||
error_lines = error_text.splitlines() or [error_text]
|
||||
self._current_col_names = []
|
||||
self._current_rows = []
|
||||
self._last_row_count = len(error_lines)
|
||||
self._refresh_ops_tree()
|
||||
table.add_columns("error")
|
||||
for line in error_lines:
|
||||
table.add_row(Text(line, style="bold #f17486"))
|
||||
return
|
||||
|
||||
if response.data_packet is None or not response.data_packet.state:
|
||||
self._current_col_names = []
|
||||
self._current_rows = []
|
||||
self._last_row_count = 0
|
||||
self._refresh_ops_tree()
|
||||
table.add_columns("empty")
|
||||
table.add_row("no data")
|
||||
return
|
||||
|
||||
data_packet = response.data_packet.state[0]
|
||||
columns = data_packet.get("columns", [])
|
||||
rows = data_packet.get("all", [])
|
||||
if not isinstance(rows, list):
|
||||
rows = []
|
||||
|
||||
col_names = [c.get("name", "") for c in columns]
|
||||
if not col_names:
|
||||
col_names = list(rows[0].keys()) if rows else ["empty"]
|
||||
|
||||
self._current_col_names = col_names
|
||||
self._current_rows = rows
|
||||
self._last_row_count = len(rows)
|
||||
self._refresh_ops_tree()
|
||||
for col_name in col_names:
|
||||
width = self._column_width_cache.get(col_name, len(col_name))
|
||||
for row in rows:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
cell_text = self._stringify(row.get(col_name, ""))
|
||||
width = max(width, len(cell_text))
|
||||
self._column_width_cache[col_name] = width
|
||||
table.add_column(col_name, width=width)
|
||||
for row in rows:
|
||||
table.add_row(*[self._format_cell(c, row.get(c, "")) for c in col_names])
|
||||
# Preserve user's viewport during streaming refreshes.
|
||||
table.scroll_to(
|
||||
x=min(prev_scroll_x, table.max_scroll_x),
|
||||
y=min(prev_scroll_y, table.max_scroll_y),
|
||||
animate=False,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _stringify(value: Any) -> str:
|
||||
return "" if value is None else str(value)
|
||||
|
||||
@staticmethod
|
||||
def _format_cell(column_name: str, value: Any) -> str | Text:
|
||||
text = DSQALiveConsole._stringify(value)
|
||||
lowered = column_name.lower()
|
||||
if lowered == "id":
|
||||
return Text(text, style="bold #9eb1d8")
|
||||
if lowered == "symbol":
|
||||
return Text(text, style="bold #dce6ff")
|
||||
if lowered == "price":
|
||||
return Text(text, style="bold #d4ddf2")
|
||||
if lowered == "time":
|
||||
return Text(text, style="#aab5d0")
|
||||
if lowered == "change":
|
||||
cleaned = text.strip()
|
||||
if cleaned.startswith("-"):
|
||||
return Text(text, style="bold #f17486")
|
||||
if cleaned.startswith("+"):
|
||||
return Text(text, style="bold #92d67e")
|
||||
return Text(text, style="bold #c7d3ef")
|
||||
if lowered == "bid":
|
||||
return Text(text, style="bold #8cf3c0 on #123526")
|
||||
if lowered == "ask":
|
||||
return Text(text, style="bold #ffd5d9 on #3b1b25")
|
||||
return text
|
||||
|
||||
def _record_update(self) -> None:
|
||||
now = time.monotonic()
|
||||
self._update_timestamps.append(now)
|
||||
self._total_updates += 1
|
||||
if self._stream_started_at is None:
|
||||
self._stream_started_at = now
|
||||
self._last_update_at = datetime.now()
|
||||
self._refresh_status()
|
||||
|
||||
def _refresh_status(self) -> None:
|
||||
self._refresh_interop_heartbeat()
|
||||
now = time.monotonic()
|
||||
cutoff = now - 1.0
|
||||
while self._update_timestamps and self._update_timestamps[0] < cutoff:
|
||||
self._update_timestamps.popleft()
|
||||
|
||||
rate = float(len(self._update_timestamps))
|
||||
if self._stream_started_at is not None:
|
||||
uptime_seconds = max(0, int(now - self._stream_started_at))
|
||||
uptime = self._format_duration(uptime_seconds)
|
||||
else:
|
||||
uptime = "--:--:--"
|
||||
last_update = self._last_update_at.strftime("%H:%M:%S") if self._last_update_at else "--:--:--"
|
||||
status = Text()
|
||||
if self._interop_is_running:
|
||||
status.append("Interop: ● UP", style="bold #92d67e")
|
||||
elif self._interop_exit_code is not None:
|
||||
status.append(f"Interop: ● DOWN({self._interop_exit_code})", style="bold #f17486")
|
||||
else:
|
||||
status.append("Interop: ● DOWN", style="bold #8b90a1")
|
||||
status.append(" | ")
|
||||
status.append(f"Rows: {self._last_row_count} | Rate: {rate:.1f}/s | ")
|
||||
status.append(f"Total Updates: {self._total_updates}", style="bold #79afe7")
|
||||
status.append(f" | Uptime: {uptime} | ")
|
||||
status.append(f"Last Update: {last_update}", style="bold #79afe7")
|
||||
self.query_one("#live_status", Static).update(status)
|
||||
|
||||
def _refresh_interop_heartbeat(self) -> None:
|
||||
is_running, exit_code = get_interop_status()
|
||||
self._interop_is_running = is_running
|
||||
self._interop_exit_code = exit_code
|
||||
|
||||
@staticmethod
|
||||
def _format_duration(total_seconds: int) -> str:
|
||||
hours = total_seconds // 3600
|
||||
minutes = (total_seconds % 3600) // 60
|
||||
seconds = total_seconds % 60
|
||||
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||
|
||||
def _search_results(self) -> None:
|
||||
raw = self.query_one("#results_search", Input).value.strip()
|
||||
if ":" not in raw:
|
||||
return
|
||||
col_part, value_part = raw.split(":", 1)
|
||||
target_col = col_part.strip()
|
||||
target_value = value_part.strip()
|
||||
if not target_col:
|
||||
return
|
||||
|
||||
lookup = {name.lower(): idx for idx, name in enumerate(self._current_col_names)}
|
||||
col_idx = lookup.get(target_col.lower())
|
||||
if col_idx is None:
|
||||
return
|
||||
|
||||
col_name = self._current_col_names[col_idx]
|
||||
needle = target_value.lower()
|
||||
for row_idx, row in enumerate(self._current_rows):
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
cell_value = self._stringify(row.get(col_name, ""))
|
||||
if needle in cell_value.lower():
|
||||
table = self.query_one("#results_table", DataTable)
|
||||
table.move_cursor(row=row_idx, column=col_idx)
|
||||
table.focus()
|
||||
return
|
||||
|
||||
def _copy_selected_cell(self) -> None:
|
||||
table = self.query_one("#results_table", DataTable)
|
||||
if table.row_count == 0 or not self._current_col_names:
|
||||
return
|
||||
coordinate = table.cursor_coordinate
|
||||
try:
|
||||
cell = table.get_cell_at(coordinate)
|
||||
except Exception:
|
||||
return
|
||||
if isinstance(cell, Text):
|
||||
value = cell.plain
|
||||
else:
|
||||
value = self._stringify(cell)
|
||||
self.copy_to_clipboard(value)
|
||||
|
||||
def _export_results_csv(self) -> None:
|
||||
if not self._current_col_names:
|
||||
return
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
export_path = os.path.join(_here, f"DSQA_RESULTS_EXPORT_{timestamp}.csv")
|
||||
with open(export_path, "w", newline="", encoding="utf-8") as csv_file:
|
||||
writer = csv.writer(csv_file)
|
||||
writer.writerow(self._current_col_names)
|
||||
for row in self._current_rows:
|
||||
if isinstance(row, dict):
|
||||
writer.writerow([self._stringify(row.get(col, "")) for col in self._current_col_names])
|
||||
|
||||
def _refresh_ops_tree(self) -> None:
|
||||
tree = self.query_one("#ops_tree", Tree)
|
||||
root = tree.root
|
||||
root.remove_children()
|
||||
|
||||
if self._ops_catalog_error:
|
||||
root.add(Text(self._ops_catalog_error, style="bold #f17486"))
|
||||
root.expand()
|
||||
return
|
||||
|
||||
grouped: dict[str, dict[str, dict[str, set[str]]]] = {}
|
||||
for row in self._ops_catalog_rows:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
row_lookup = {self._stringify(k).lower(): v for k, v in row.items()}
|
||||
assembly_name = self._stringify(row_lookup.get("assembly_name", "")).strip() or "(unknown assembly)"
|
||||
namespace = self._stringify(row_lookup.get("namespace", "")).strip() or "(global)"
|
||||
op = self._stringify(row_lookup.get("op", "")).strip() or "(unknown op)"
|
||||
constructor = self._stringify(row_lookup.get("constructor", "")).strip() or "(none)"
|
||||
grouped.setdefault(assembly_name, {}).setdefault(namespace, {}).setdefault(op, set()).add(constructor)
|
||||
|
||||
if not grouped:
|
||||
root.add(Text("No operator metadata available", style="#8ea0c6"))
|
||||
root.expand()
|
||||
return
|
||||
|
||||
for assembly_name in sorted(grouped.keys(), key=str.lower):
|
||||
assembly_node = root.add(Text(assembly_name, style="bold #79afe7"))
|
||||
for namespace in sorted(grouped[assembly_name].keys(), key=str.lower):
|
||||
namespace_node = assembly_node.add(Text(namespace, style="#cfd7eb"))
|
||||
for op in sorted(grouped[assembly_name][namespace].keys(), key=str.lower):
|
||||
op_node = namespace_node.add(
|
||||
Text(op, style="#b8c8e7"),
|
||||
data={"kind": "op", "op": op},
|
||||
)
|
||||
for constructor in sorted(grouped[assembly_name][namespace][op], key=str.lower):
|
||||
op_node.add(
|
||||
Text(constructor, style="#9eb0d4"),
|
||||
data={"kind": "constructor", "op": op, "constructor": constructor},
|
||||
)
|
||||
op_node.expand()
|
||||
namespace_node.expand()
|
||||
assembly_node.expand()
|
||||
root.expand()
|
||||
|
||||
def _refresh_ops_tree_async(self) -> None:
|
||||
if self._ops_catalog_loaded or self._ops_catalog_loading:
|
||||
return
|
||||
self._ensure_interop_started()
|
||||
self._ops_catalog_loading = True
|
||||
req_id = str(uuid.uuid4())
|
||||
|
||||
def _run() -> None:
|
||||
try:
|
||||
def _on_response(resp: DslResponse) -> None:
|
||||
self.call_from_thread(self._update_ops_catalog, resp)
|
||||
|
||||
get_dsl("OpsStream()", req_id, _on_response)
|
||||
except Exception as exc:
|
||||
error_resp = DslResponse(data_packet=None, req_id=req_id, error=str(exc))
|
||||
self.call_from_thread(self._update_ops_catalog, error_resp)
|
||||
|
||||
threading.Thread(target=_run, daemon=True).start()
|
||||
|
||||
def _update_ops_catalog(self, response: DslResponse) -> None:
|
||||
self._ops_catalog_loading = False
|
||||
if response.error:
|
||||
self._ops_catalog_rows = []
|
||||
self._ops_catalog_error = self._stringify(response.error)
|
||||
self._refresh_ops_tree()
|
||||
return
|
||||
|
||||
if response.data_packet is None or not response.data_packet.state:
|
||||
self._ops_catalog_rows = []
|
||||
self._ops_catalog_error = "OpsStream() returned no data"
|
||||
self._refresh_ops_tree()
|
||||
return
|
||||
|
||||
data_packet = response.data_packet.state[0]
|
||||
rows = data_packet.get("all", [])
|
||||
if not isinstance(rows, list):
|
||||
rows = []
|
||||
normalized_rows: list[dict[str, Any]] = []
|
||||
for row in rows:
|
||||
if isinstance(row, dict):
|
||||
normalized_rows.append(row)
|
||||
self._ops_catalog_rows = normalized_rows
|
||||
self._ops_catalog_error = None
|
||||
self._ops_catalog_loaded = True
|
||||
self._refresh_ops_tree()
|
||||
|
||||
def _toggle_stream_painting(self) -> None:
|
||||
self._grid_updates_enabled = not self._grid_updates_enabled
|
||||
self._set_stream_toggle_label()
|
||||
self._set_pause_visuals()
|
||||
if self._grid_updates_enabled and self._paused_latest_response is not None:
|
||||
latest = self._paused_latest_response
|
||||
self._paused_latest_response = None
|
||||
self._render_response_internal(latest)
|
||||
|
||||
def _set_stream_toggle_label(self) -> None:
|
||||
button = self.query_one("#stream_toggle_button", Button)
|
||||
button.label = "⏸ Pause" if self._grid_updates_enabled else "▶ Play"
|
||||
|
||||
def _set_pause_visuals(self) -> None:
|
||||
table = self.query_one("#results_table", DataTable)
|
||||
panel = self.query_one("#results_panel", Vertical)
|
||||
if self._grid_updates_enabled:
|
||||
table.remove_class("paused")
|
||||
panel.remove_class("paused")
|
||||
else:
|
||||
table.add_class("paused")
|
||||
panel.add_class("paused")
|
||||
|
||||
def _load_last_query(self) -> str:
|
||||
try:
|
||||
with open(self.LAST_QUERY_PATH, "r", encoding="utf-8") as file:
|
||||
text = file.read().strip()
|
||||
return text if text else self.DEFAULT_QUERY
|
||||
except FileNotFoundError:
|
||||
return self.DEFAULT_QUERY
|
||||
except OSError:
|
||||
return self.DEFAULT_QUERY
|
||||
|
||||
def _save_last_query(self, query: str) -> None:
|
||||
try:
|
||||
with open(self.LAST_QUERY_PATH, "w", encoding="utf-8") as file:
|
||||
file.write(query)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
DSQALiveConsole().run()
|
||||
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>BlueOrbDSLInteropServer</AssemblyName>
|
||||
<RootNamespace>BlueOrbDSLInteropServer</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<Choose>
|
||||
<When Condition="'$(UseProjectRefs)' == 'true'">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\cs\Bts.Spark.Api\Bts.Spark.Api.csproj" />
|
||||
<ProjectReference Include="..\DataStream\DataStream.csproj" />
|
||||
<ProjectReference Include="..\PubSub\PubSub.csproj" />
|
||||
<ProjectReference Include="..\BlueOrbOperatorStreams\BlueOrbOperatorStreams.csproj" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bts.Spark.Api" Version="$(SparkVersion)" />
|
||||
<PackageReference Include="DataStream" Version="$(SparkVersion)" />
|
||||
<PackageReference Include="PubSub" Version="$(SparkVersion)" />
|
||||
<PackageReference Include="BlueOrbOperatorStreams" Version="$(SparkVersion)" />
|
||||
</ItemGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using BCG;
|
||||
|
||||
using bts.BlueOrb;
|
||||
|
||||
using Bts.DataStream;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
using Bts.DataStreamExpressions;
|
||||
using Bts.PubSub;
|
||||
|
||||
using MathNet.Numerics.Statistics;
|
||||
|
||||
|
||||
namespace BlueOrbDSLInteropServer {
|
||||
// BlueOrbDSLInteropServer reads DSL lines from stdin, validates them,
|
||||
// and writes one DataPacket JSON line to stdout per input.
|
||||
internal static class Program {
|
||||
private const string ExitSignal = ":exit";
|
||||
private static SyncQueue<DslRequest> _work_queue = new SyncQueue<DslRequest>();
|
||||
private static JsonSerializerOptions response_json_options = new JsonSerializerOptions {
|
||||
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals
|
||||
};
|
||||
private static string _current_req_id;
|
||||
|
||||
// Request from Python
|
||||
private sealed class DslRequest {
|
||||
public string? dsl { get; set; }
|
||||
public string? req_id { get; set; }
|
||||
}
|
||||
|
||||
// Response envelope for Python: includes DataPacket, request id, and optional error.
|
||||
private sealed class DslResponse {
|
||||
public DataPacket? data_packet { get; set; }
|
||||
public string? req_id { get; set; }
|
||||
public string? error { get; set; }
|
||||
}
|
||||
|
||||
private static void Main(string[] args) {
|
||||
//System.Threading.Thread.Sleep(20000);
|
||||
System.Threading.Thread thread = new Thread(_worker_loop);
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
response_json_options.Converters.Add(new DataPacketJsonConverter {
|
||||
IncludeCurrent = true,
|
||||
UseObjectRows = true,
|
||||
});
|
||||
string? line;
|
||||
while ((line = Console.ReadLine()) != null) {
|
||||
line = line.Trim();
|
||||
if (line.Length == 0) {
|
||||
continue;
|
||||
}
|
||||
if (string.Equals(line, ExitSignal, StringComparison.OrdinalIgnoreCase)) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
DslRequest req = JsonSerializer.Deserialize<DslRequest>(line);
|
||||
_work_queue.enqueue(req);
|
||||
} catch (Exception ex) {
|
||||
bts.Log.assert(false, ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void _worker_loop() {
|
||||
Dictionary<string, ViewStream> req_map = new Dictionary<string, ViewStream>();
|
||||
while (true) {
|
||||
System.Threading.Thread.Sleep(100);
|
||||
ViewStreamDatabase.instance.doWork();
|
||||
var new_reqs = _work_queue.dequeue_all();
|
||||
if (new_reqs == null || new_reqs.Count == 0) {
|
||||
continue;
|
||||
}
|
||||
// ubsubscribing to previous stream(s)
|
||||
foreach (var kv in req_map) {
|
||||
kv.Value.onChange -= dp_obj => _on_dp(kv.Key, dp_obj);
|
||||
}
|
||||
foreach (var r in new_reqs) {
|
||||
var req_id = string.IsNullOrWhiteSpace(r.req_id) ? Guid.NewGuid().ToString() : r.req_id;
|
||||
_current_req_id = req_id;
|
||||
try {
|
||||
DSLStream dsl_str = new DSLStream(r.dsl);
|
||||
req_map[req_id] = dsl_str;
|
||||
dsl_str.onChange += dp_obj => _on_dp(req_id, dp_obj);
|
||||
} catch (Exception ex) {
|
||||
_write_error(req_id, ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void _on_dp(string req_id, object dp_obj) {
|
||||
// eventhough we unsubscribe to all the other streams except the currrent one,
|
||||
// sometimes the onLastSub is not implemented and we still get updates, this masks them
|
||||
if (req_id != _current_req_id)
|
||||
return;
|
||||
DataPacket dp = dp_obj as DataPacket;
|
||||
DslResponse response = new DslResponse() {
|
||||
data_packet = dp,
|
||||
req_id = req_id,
|
||||
error = ""
|
||||
};
|
||||
var json = JsonSerializer.Serialize(response, response_json_options);
|
||||
Console.WriteLine(json);
|
||||
}
|
||||
|
||||
private static void _write_error(string req_id, string error) {
|
||||
DslResponse response = new DslResponse() {
|
||||
data_packet = null,
|
||||
req_id = req_id,
|
||||
error = error
|
||||
};
|
||||
var json = JsonSerializer.Serialize(response, response_json_options);
|
||||
Console.WriteLine(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,514 @@
|
||||
// namespace BlueOrb.Operators.Signal;
|
||||
|
||||
// using BCG;
|
||||
|
||||
// using bts;
|
||||
|
||||
// using System;
|
||||
// using System.Collections.Generic;
|
||||
// using System.Globalization;
|
||||
// using System.Linq;
|
||||
|
||||
// [DataStreamUserRespresentation("BarBuilderStream")]
|
||||
// public class BarBuilderStream : ViewStream
|
||||
// {
|
||||
// enum BarType
|
||||
// {
|
||||
// TIME,
|
||||
// TICK,
|
||||
// VOLUME,
|
||||
// DOLLAR,
|
||||
// }
|
||||
|
||||
// enum PriceSource
|
||||
// {
|
||||
// trade_price,
|
||||
// mid,
|
||||
// bid,
|
||||
// ask,
|
||||
// }
|
||||
|
||||
// enum VolumeSource
|
||||
// {
|
||||
// trade_size,
|
||||
// none,
|
||||
// }
|
||||
|
||||
// enum SessionReset
|
||||
// {
|
||||
// NONE,
|
||||
// DAY,
|
||||
// RTH,
|
||||
// ETH,
|
||||
// }
|
||||
|
||||
// sealed class BarState
|
||||
// {
|
||||
// public string Contract = string.Empty;
|
||||
// public DateTime StartTs;
|
||||
// public DateTime EndTs;
|
||||
// public double Open;
|
||||
// public double High;
|
||||
// public double Low;
|
||||
// public double Close;
|
||||
// public double Volume;
|
||||
// public int TradeCount;
|
||||
// public double SumPriceSize;
|
||||
// public double SumSize;
|
||||
// public double DollarNotional;
|
||||
// public bool HasData;
|
||||
// public DateTime SessionDay;
|
||||
// public bool InitialSnapshotEmitted;
|
||||
// }
|
||||
|
||||
// readonly ViewStream _priceStream;
|
||||
// readonly BarType _barType;
|
||||
// readonly int _barSize;
|
||||
// readonly PriceSource _priceSource;
|
||||
// readonly VolumeSource _volumeSource;
|
||||
// readonly string _timestampCol;
|
||||
// readonly bool _emitForming;
|
||||
// readonly bool _emitInitialSnapshot;
|
||||
// readonly SessionReset _sessionReset;
|
||||
|
||||
// readonly Dictionary<string, BarState> _stateByContract = new(StringComparer.Ordinal);
|
||||
// readonly Dictionary<string, bool> _validCols = new(StringComparer.OrdinalIgnoreCase);
|
||||
// bool _validated;
|
||||
// int _nextId;
|
||||
// readonly BlueTable _outTable;
|
||||
// readonly IBlueTableSchema _outSchema;
|
||||
|
||||
// public BarBuilderStream(
|
||||
// ViewStream price_stream,
|
||||
// string bar_type,
|
||||
// int bar_size,
|
||||
// string price_source,
|
||||
// string volume_source,
|
||||
// string timestamp_col = "ts_event",
|
||||
// int emit_forming_i = 0,
|
||||
// string session_reset = "NONE",
|
||||
// int emit_initial_snapshot_i = 0
|
||||
// )
|
||||
// {
|
||||
// _priceStream = price_stream;
|
||||
// _barType = ParseBarType(bar_type);
|
||||
// _barSize = bar_size;
|
||||
// _priceSource = ParsePriceSource(price_source);
|
||||
// _volumeSource = ParseVolumeSource(volume_source);
|
||||
// _timestampCol = timestamp_col;
|
||||
// _emitForming = emit_forming_i == 1;
|
||||
// _emitInitialSnapshot = emit_initial_snapshot_i == 1;
|
||||
// _sessionReset = ParseSessionReset(session_reset);
|
||||
|
||||
// if (_barSize <= 0)
|
||||
// {
|
||||
// throw new ArgumentException("bar_size must be > 0");
|
||||
// }
|
||||
|
||||
// _outSchema = BlueDataUtility.form_schema(
|
||||
// "BarBuilder",
|
||||
// Tuple.Create("id", TypeCode.Int32),
|
||||
// Tuple.Create("ts_event", TypeCode.String),
|
||||
// Tuple.Create("bar_start_ts", TypeCode.String),
|
||||
// Tuple.Create("bar_end_ts", TypeCode.String),
|
||||
// Tuple.Create("contract", TypeCode.String),
|
||||
// Tuple.Create("open", TypeCode.Double),
|
||||
// Tuple.Create("high", TypeCode.Double),
|
||||
// Tuple.Create("low", TypeCode.Double),
|
||||
// Tuple.Create("close", TypeCode.Double),
|
||||
// Tuple.Create("volume", TypeCode.Double),
|
||||
// Tuple.Create("trade_count", TypeCode.Int32),
|
||||
// Tuple.Create("vwap", TypeCode.Double),
|
||||
// Tuple.Create("is_forming", TypeCode.Boolean)
|
||||
// );
|
||||
// _outTable = new BlueTable(_outSchema);
|
||||
// }
|
||||
|
||||
// protected override void myOnFirstSubscriber()
|
||||
// {
|
||||
// _priceStream.onChange += _on_price_change;
|
||||
// }
|
||||
|
||||
// protected override void myOnLastSubscriber()
|
||||
// {
|
||||
// _priceStream.onChange -= _on_price_change;
|
||||
// }
|
||||
|
||||
// void _on_price_change(object newValue)
|
||||
// {
|
||||
// var dp = newValue as IDataPacket;
|
||||
// if (dp is null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// if (!_validated)
|
||||
// {
|
||||
// ValidateInputSchema(dp.newRows.schema);
|
||||
// _validated = true;
|
||||
// }
|
||||
|
||||
// var emitted = new List<IBlueRow>();
|
||||
// foreach (IBlueRow row in dp.addedRows)
|
||||
// {
|
||||
// ProcessEvent(row, emitted);
|
||||
// }
|
||||
|
||||
// if (emitted.Count == 0)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// foreach (var r in emitted)
|
||||
// {
|
||||
// _outTable.addRow(r);
|
||||
// }
|
||||
// var outDp = BlueDataUtility.build_dp_inc(_outTable, myLastValue as IDataPacket);
|
||||
// myFireEvent(outDp);
|
||||
// }
|
||||
|
||||
// void ValidateInputSchema(IBlueTableSchema schema)
|
||||
// {
|
||||
// _validCols.Clear();
|
||||
// foreach (var name in schema.columnNames)
|
||||
// {
|
||||
// _validCols[name] = true;
|
||||
// }
|
||||
|
||||
// if (!_validCols.ContainsKey(_timestampCol))
|
||||
// {
|
||||
// throw new ArgumentException($"Missing required column: {_timestampCol}");
|
||||
// }
|
||||
|
||||
// switch (_priceSource)
|
||||
// {
|
||||
// case PriceSource.trade_price:
|
||||
// RequireCol("trade_price");
|
||||
// break;
|
||||
// case PriceSource.mid:
|
||||
// RequireCol("bid_price");
|
||||
// RequireCol("ask_price");
|
||||
// break;
|
||||
// case PriceSource.bid:
|
||||
// RequireCol("bid_price");
|
||||
// break;
|
||||
// case PriceSource.ask:
|
||||
// RequireCol("ask_price");
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (_barType is BarType.VOLUME or BarType.DOLLAR)
|
||||
// {
|
||||
// if (_volumeSource == VolumeSource.none || !_validCols.ContainsKey("trade_size"))
|
||||
// {
|
||||
// throw new ArgumentException("VOLUME/DOLLAR require executed trade volume; invalid for BBO-only streams.");
|
||||
// }
|
||||
// }
|
||||
// else if (_volumeSource == VolumeSource.trade_size)
|
||||
// {
|
||||
// RequireCol("trade_size");
|
||||
// }
|
||||
// }
|
||||
|
||||
// void RequireCol(string name)
|
||||
// {
|
||||
// if (!_validCols.ContainsKey(name))
|
||||
// {
|
||||
// throw new ArgumentException($"Missing required column for selected source: {name}");
|
||||
// }
|
||||
// }
|
||||
|
||||
// void ProcessEvent(IBlueRow row, List<IBlueRow> emitted)
|
||||
// {
|
||||
// var ts = ParseTimestamp(row);
|
||||
// var contract = ResolveContract(row);
|
||||
// var price = ResolvePrice(row);
|
||||
// var size = ResolveSize(row);
|
||||
// var state = GetOrCreateState(contract);
|
||||
|
||||
// if (state.HasData && _sessionReset != SessionReset.NONE && ts.Date != state.SessionDay.Date)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, ts_event: state.EndTs, isForming: false));
|
||||
// state.HasData = false;
|
||||
// }
|
||||
|
||||
// switch (_barType)
|
||||
// {
|
||||
// case BarType.TIME:
|
||||
// ProcessTimeBar(state, ts, price, size, emitted);
|
||||
// break;
|
||||
// case BarType.TICK:
|
||||
// ProcessThresholdBar(state, ts, price, size, emitted, state.TradeCount + 1 >= _barSize);
|
||||
// break;
|
||||
// case BarType.VOLUME:
|
||||
// ProcessThresholdBar(state, ts, price, size, emitted, state.Volume + size >= _barSize);
|
||||
// break;
|
||||
// case BarType.DOLLAR:
|
||||
// ProcessThresholdBar(state, ts, price, size, emitted, state.DollarNotional + (price * size) >= _barSize);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// void ProcessTimeBar(BarState state, DateTime ts, double price, double size, List<IBlueRow> emitted)
|
||||
// {
|
||||
// var bucketStart = AlignTimeBucket(ts, _barSize);
|
||||
// var bucketEnd = bucketStart.AddSeconds(_barSize);
|
||||
|
||||
// if (!state.HasData)
|
||||
// {
|
||||
// StartBar(state, ts, bucketStart, bucketEnd, price, size);
|
||||
// MaybeEmitInitialSnapshot(state, ts, emitted);
|
||||
// if (_emitForming)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, ts, isForming: true));
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (bucketStart < state.StartTs)
|
||||
// {
|
||||
// Log.Gen.error(
|
||||
// $"BarBuilderStream ignored out-of-order event. contract={state.Contract} ts={ToIso(ts)} " +
|
||||
// $"current_bar_start={ToIso(state.StartTs)}");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (bucketStart > state.StartTs)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, state.EndTs, isForming: false));
|
||||
// StartBar(state, ts, bucketStart, bucketEnd, price, size);
|
||||
// if (_emitForming)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, ts, isForming: true));
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Accumulate(state, price, size);
|
||||
// state.EndTs = bucketEnd;
|
||||
// if (_emitForming)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, ts, isForming: true));
|
||||
// }
|
||||
// }
|
||||
|
||||
// void ProcessThresholdBar(
|
||||
// BarState state,
|
||||
// DateTime ts,
|
||||
// double price,
|
||||
// double size,
|
||||
// List<IBlueRow> emitted,
|
||||
// bool shouldClose
|
||||
// )
|
||||
// {
|
||||
// if (!state.HasData)
|
||||
// {
|
||||
// StartBar(state, ts, ts, ts, price, size);
|
||||
// MaybeEmitInitialSnapshot(state, ts, emitted);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Accumulate(state, price, size);
|
||||
// }
|
||||
// state.EndTs = ts;
|
||||
|
||||
// if (_emitForming)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, ts, isForming: true));
|
||||
// }
|
||||
// if (shouldClose)
|
||||
// {
|
||||
// emitted.Add(ToBarRow(state, ts, isForming: false));
|
||||
// state.HasData = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// static DateTime AlignTimeBucket(DateTime ts, int seconds)
|
||||
// {
|
||||
// var utc = ts.ToUniversalTime();
|
||||
// long bucketTicks = TimeSpan.FromSeconds(seconds).Ticks;
|
||||
// long aligned = (utc.Ticks / bucketTicks) * bucketTicks;
|
||||
// return new DateTime(aligned, DateTimeKind.Utc);
|
||||
// }
|
||||
|
||||
// void MaybeEmitInitialSnapshot(BarState state, DateTime ts, List<IBlueRow> emitted)
|
||||
// {
|
||||
// if (!_emitInitialSnapshot || state.InitialSnapshotEmitted)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// emitted.Add(ToBarRow(state, ts, isForming: false));
|
||||
// state.InitialSnapshotEmitted = true;
|
||||
// }
|
||||
|
||||
// void StartBar(
|
||||
// BarState state,
|
||||
// DateTime ts,
|
||||
// DateTime barStart,
|
||||
// DateTime barEnd,
|
||||
// double price,
|
||||
// double size
|
||||
// )
|
||||
// {
|
||||
// state.StartTs = barStart;
|
||||
// state.EndTs = barEnd;
|
||||
// state.Open = price;
|
||||
// state.High = price;
|
||||
// state.Low = price;
|
||||
// state.Close = price;
|
||||
// state.Volume = 0;
|
||||
// state.TradeCount = 0;
|
||||
// state.SumPriceSize = 0;
|
||||
// state.SumSize = 0;
|
||||
// state.DollarNotional = 0;
|
||||
// state.SessionDay = ts.Date;
|
||||
// state.HasData = true;
|
||||
// Accumulate(state, price, size);
|
||||
// }
|
||||
|
||||
// static void Accumulate(BarState state, double price, double size)
|
||||
// {
|
||||
// state.High = Math.Max(state.High, price);
|
||||
// state.Low = Math.Min(state.Low, price);
|
||||
// state.Close = price;
|
||||
// state.TradeCount++;
|
||||
// if (size > 0)
|
||||
// {
|
||||
// state.Volume += size;
|
||||
// state.SumSize += size;
|
||||
// state.SumPriceSize += price * size;
|
||||
// state.DollarNotional += price * size;
|
||||
// }
|
||||
// }
|
||||
|
||||
// IBlueRow ToBarRow(BarState state, DateTime ts_event, bool isForming)
|
||||
// {
|
||||
// double vwap = state.SumSize > 0 ? state.SumPriceSize / state.SumSize : state.Close;
|
||||
// var row = new MutableBlueRow(_outSchema);
|
||||
// row.setValue("id", _nextId++);
|
||||
// row.setValue("ts_event", ToIso(ts_event));
|
||||
// row.setValue("bar_start_ts", ToIso(state.StartTs));
|
||||
// row.setValue("bar_end_ts", ToIso(state.EndTs));
|
||||
// row.setValue("contract", state.Contract);
|
||||
// row.setValue("open", state.Open);
|
||||
// row.setValue("high", state.High);
|
||||
// row.setValue("low", state.Low);
|
||||
// row.setValue("close", state.Close);
|
||||
// row.setValue("volume", _volumeSource == VolumeSource.none ? 0.0 : state.Volume);
|
||||
// row.setValue("trade_count", state.TradeCount);
|
||||
// row.setValue("vwap", vwap);
|
||||
// row.setValue("is_forming", isForming);
|
||||
// return row;
|
||||
// }
|
||||
|
||||
// BarState GetOrCreateState(string contract)
|
||||
// {
|
||||
// if (_stateByContract.TryGetValue(contract, out var existing))
|
||||
// {
|
||||
// return existing;
|
||||
// }
|
||||
// var created = new BarState { Contract = contract };
|
||||
// _stateByContract[contract] = created;
|
||||
// return created;
|
||||
// }
|
||||
|
||||
// DateTime ParseTimestamp(IBlueRow row)
|
||||
// {
|
||||
// object? raw = row[_timestampCol];
|
||||
// if (raw is DateTime dt)
|
||||
// {
|
||||
// return dt;
|
||||
// }
|
||||
// if (raw is string s && DateTime.TryParse(s, null, DateTimeStyles.RoundtripKind, out dt))
|
||||
// {
|
||||
// return dt;
|
||||
// }
|
||||
// throw new ArgumentException($"Invalid timestamp value in column '{_timestampCol}'.");
|
||||
// }
|
||||
|
||||
// string ResolveContract(IBlueRow row)
|
||||
// {
|
||||
// if (_validCols.ContainsKey("contract"))
|
||||
// {
|
||||
// return (row["contract"]?.ToString() ?? string.Empty).Trim();
|
||||
// }
|
||||
// if (_validCols.ContainsKey("symbol"))
|
||||
// {
|
||||
// return (row["symbol"]?.ToString() ?? string.Empty).Trim();
|
||||
// }
|
||||
// return string.Empty;
|
||||
// }
|
||||
|
||||
// double ResolvePrice(IBlueRow row)
|
||||
// {
|
||||
// return _priceSource switch
|
||||
// {
|
||||
// PriceSource.trade_price => ToDouble(row["trade_price"], "trade_price"),
|
||||
// PriceSource.mid => (ToDouble(row["bid_price"], "bid_price") + ToDouble(row["ask_price"], "ask_price")) / 2.0,
|
||||
// PriceSource.bid => ToDouble(row["bid_price"], "bid_price"),
|
||||
// PriceSource.ask => ToDouble(row["ask_price"], "ask_price"),
|
||||
// _ => throw new ArgumentOutOfRangeException()
|
||||
// };
|
||||
// }
|
||||
|
||||
// double ResolveSize(IBlueRow row)
|
||||
// {
|
||||
// if (_volumeSource == VolumeSource.none)
|
||||
// {
|
||||
// return 0;
|
||||
// }
|
||||
// return ToDouble(row["trade_size"], "trade_size");
|
||||
// }
|
||||
|
||||
// static double ToDouble(object? value, string colName)
|
||||
// {
|
||||
// var d = BlueDataUtility.GetDouble(value!);
|
||||
// if (!d.HasValue)
|
||||
// {
|
||||
// throw new ArgumentException($"Column '{colName}' must be numeric.");
|
||||
// }
|
||||
// return d.Value;
|
||||
// }
|
||||
|
||||
// static string ToIso(DateTime dt) =>
|
||||
// dt.ToUniversalTime().ToString("O");
|
||||
|
||||
// static BarType ParseBarType(string value)
|
||||
// {
|
||||
// if (Enum.TryParse<BarType>(value, true, out var parsed))
|
||||
// {
|
||||
// return parsed;
|
||||
// }
|
||||
// throw new ArgumentException("bar_type must be one of: TIME | TICK | VOLUME | DOLLAR");
|
||||
// }
|
||||
|
||||
// static PriceSource ParsePriceSource(string value)
|
||||
// {
|
||||
// if (Enum.TryParse<PriceSource>(value, true, out var parsed))
|
||||
// {
|
||||
// return parsed;
|
||||
// }
|
||||
// throw new ArgumentException("price_source must be one of: trade_price | mid | bid | ask");
|
||||
// }
|
||||
|
||||
// static VolumeSource ParseVolumeSource(string value)
|
||||
// {
|
||||
// if (Enum.TryParse<VolumeSource>(value, true, out var parsed))
|
||||
// {
|
||||
// return parsed;
|
||||
// }
|
||||
// throw new ArgumentException("volume_source must be one of: trade_size | none");
|
||||
// }
|
||||
|
||||
// static SessionReset ParseSessionReset(string value)
|
||||
// {
|
||||
// if (!Enum.TryParse<SessionReset>(value, true, out var parsed))
|
||||
// {
|
||||
// throw new ArgumentException("session_reset must be one of: NONE | DAY | RTH | ETH");
|
||||
// }
|
||||
// // TODO: differentiate RTH/ETH session boundaries; currently treated as DAY.
|
||||
// if (parsed is SessionReset.RTH or SessionReset.ETH)
|
||||
// {
|
||||
// return SessionReset.DAY;
|
||||
// }
|
||||
// return parsed;
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
|
||||
<PackageReference Include="OpenAI" Version="2.0.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<Choose>
|
||||
<When Condition="'$(UseProjectRefs)' == 'true'">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\cs\Bts.Spark.Api\Bts.Spark.Api.csproj" />
|
||||
<ProjectReference Include="..\DataStreamCore\DataStreamCore.csproj" />
|
||||
<ProjectReference Include="..\DataStream\DataStream.csproj" />
|
||||
<ProjectReference Include="..\PubSub\PubSub.csproj" />
|
||||
</ItemGroup>
|
||||
</When>
|
||||
<Otherwise>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bts.Spark.Api" Version="$(SparkVersion)" />
|
||||
<PackageReference Include="DataStream" Version="$(SparkVersion)" />
|
||||
<PackageReference Include="PubSub" Version="$(SparkVersion)" />
|
||||
</ItemGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
|
||||
<!-- <ItemGroup>
|
||||
<RowType Include="RowTemplates\RefTypeRow.tt" SchemaJson="RowTemplates\PubSubHeartbeatSchema.json" TypeName="PubSubHeartbeatRow" TableName="PubSubHeartbeat" />
|
||||
<RowType Include="RowTemplates\RefTypeRow.tt" SchemaJson="RowTemplates\PubSubRouteSchema.json" TypeName="PubSubRouteRow" TableName="PubSubRoute" />
|
||||
<RowType Include="RowTemplates\RefTypeRow.tt" SchemaJson="RowTemplates\PubSubServerStateSchema.json" TypeName="PubSubServerStateRow" TableName="PubSubServerState" />
|
||||
<RowType Include="RowTemplates\RefTypeRow.tt" SchemaJson="RowTemplates\PubSubServerTagStatsSchema.json" TypeName="PubSubServerTagStatsRow" TableName="PubSubServerTagStats" />
|
||||
<RowType Include="RowTemplates\RefTypeRow.tt" SchemaJson="RowTemplates\TableMetadataSchema.json" TypeName="TableMetadataRow" TableName="TableMetadata" />
|
||||
</ItemGroup> -->
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,294 @@
|
||||
namespace BlueOrb.Internal
|
||||
{
|
||||
using bts;
|
||||
//using bts.api;
|
||||
//using bts.spark;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
public static class ContractUtils
|
||||
{
|
||||
public record FutureTradableContract(
|
||||
string Symbol,
|
||||
DateTime Expiration,
|
||||
Exchange Exchange,
|
||||
string? ContractText);
|
||||
|
||||
public class FutureSpreadContract
|
||||
{
|
||||
public List<Tuple<double, FutureTradableContract>> legs = new(2);
|
||||
public string Symbol
|
||||
{
|
||||
get
|
||||
{
|
||||
return legs == null || legs.Count == 0 ? string.Empty : legs.ElementAt(0).Item2.Symbol;
|
||||
}
|
||||
}
|
||||
public string? ContractText;
|
||||
}
|
||||
|
||||
public record FutureContinousContract(string Symbol, Exchange Exchange);
|
||||
|
||||
// this is for all future conytracts belonging to a symbol
|
||||
public record FutureWildcardContract(string Symbol, Exchange Exchange);
|
||||
|
||||
public class FutureContract
|
||||
{
|
||||
public FutureWildcardContract? wildcard_contract;
|
||||
public FutureTradableContract? future_tradable_contract;
|
||||
public FutureSpreadContract? spread_tradable_contract;
|
||||
public FutureContinousContract? continous_constract;
|
||||
|
||||
public FutureContract(string txt)
|
||||
{
|
||||
wildcard_contract = parse_wildcard_contract(txt);
|
||||
if (wildcard_contract != null)
|
||||
return;
|
||||
var fc = parse_future_contract(txt);
|
||||
if (fc != null)
|
||||
{
|
||||
future_tradable_contract = fc;
|
||||
return;
|
||||
}
|
||||
var sc = parse_future_spread_contract(txt);
|
||||
if (sc != null)
|
||||
{
|
||||
spread_tradable_contract = sc;
|
||||
return;
|
||||
}
|
||||
// this is not totally true, since ParseFutureSpreadContract does not
|
||||
// parse ICS spreads
|
||||
continous_constract = new(txt, Exchange.CME);
|
||||
}
|
||||
|
||||
[MemberNotNullWhen(true, nameof(continous_constract))]
|
||||
public bool is_continous_contract => continous_constract != null;
|
||||
|
||||
[MemberNotNullWhen(true, nameof(wildcard_contract))]
|
||||
public bool is_wildcard_contract => wildcard_contract != null;
|
||||
|
||||
[MemberNotNullWhen(true, nameof(future_tradable_contract))]
|
||||
public bool is_future_tradable_contract => future_tradable_contract != null;
|
||||
|
||||
[MemberNotNullWhen(true, nameof(spread_tradable_contract))]
|
||||
public bool is_spread_tradable_contract => spread_tradable_contract != null;
|
||||
|
||||
public string symbol()
|
||||
{
|
||||
if (wildcard_contract != null)
|
||||
return wildcard_contract.Symbol;
|
||||
if (continous_constract != null)
|
||||
{
|
||||
return continous_constract.Symbol;
|
||||
}
|
||||
else if (future_tradable_contract != null)
|
||||
{
|
||||
return future_tradable_contract.Symbol;
|
||||
}
|
||||
else if (spread_tradable_contract != null)
|
||||
{
|
||||
return spread_tradable_contract.Symbol;
|
||||
}
|
||||
Log.assert(false);
|
||||
return string.Empty;
|
||||
}
|
||||
public string? contract_text
|
||||
{
|
||||
get
|
||||
{
|
||||
if (future_tradable_contract != null)
|
||||
return future_tradable_contract.ContractText;
|
||||
if (spread_tradable_contract != null)
|
||||
return spread_tradable_contract.ContractText;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
#region Parsing
|
||||
public static FutureWildcardContract? parse_wildcard_contract(string contract_txt, Exchange exchange = Exchange.CME)
|
||||
{
|
||||
if (contract_txt.EndsWith("*"))
|
||||
{
|
||||
contract_txt = contract_txt.Replace("*", string.Empty);
|
||||
return new FutureWildcardContract(contract_txt, exchange);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static FutureTradableContract? parse_future_contract(string contract_txt, Exchange exchange = Exchange.CME)
|
||||
{
|
||||
// Validate the future string length
|
||||
if (!contract_txt.All(c => char.IsLetterOrDigit(c)))
|
||||
return null;
|
||||
if (contract_txt.Length < 4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract the symbol and the expiration month/year codes
|
||||
string symbol = contract_txt.Substring(0, contract_txt.Length - 2);
|
||||
char monthCode = contract_txt[contract_txt.Length - 2];
|
||||
char yearCode = contract_txt[contract_txt.Length - 1];
|
||||
|
||||
// Map month code to month, return null if the month code is invalid
|
||||
int month = monthCode switch
|
||||
{
|
||||
'F' => 1, // January
|
||||
'G' => 2, // February
|
||||
'H' => 3, // March
|
||||
'J' => 4, // April
|
||||
'K' => 5, // May
|
||||
'M' => 6, // June
|
||||
'N' => 7, // July
|
||||
'Q' => 8, // August
|
||||
'U' => 9, // September
|
||||
'V' => 10, // October
|
||||
'X' => 11, // November
|
||||
'Z' => 12, // December
|
||||
_ => 0 // Return 0 for invalid month code
|
||||
};
|
||||
|
||||
if (month == 0)
|
||||
{
|
||||
return null; // Invalid month code
|
||||
}
|
||||
|
||||
// Calculate the year based on the current decade
|
||||
int currentYear = DateTime.Now.Year;
|
||||
int decadeStart = currentYear / 10 * 10;
|
||||
int year = decadeStart + (yearCode - '0');
|
||||
|
||||
// If the year is in the past, assume the next decade
|
||||
if (year < currentYear)
|
||||
{
|
||||
year += 10;
|
||||
}
|
||||
|
||||
// Create the FutureContract instance and set its properties
|
||||
DateTime expiration = new DateTime(year, month, 1);
|
||||
return new(symbol, expiration, exchange, contract_txt);
|
||||
}
|
||||
// Method to parse a futures spread, e.g. "CLX4-CLZ4"
|
||||
public static FutureSpreadContract? parse_future_spread_contract(string contract_txt, Exchange exchange = Exchange.CME)
|
||||
{
|
||||
// Split the string by '-' to handle each leg
|
||||
var spreadParts = contract_txt.Split('-');
|
||||
if (spreadParts.Length < 2)
|
||||
{
|
||||
return null; // Not a valid spread format
|
||||
}
|
||||
|
||||
var spreadContract = new FutureSpreadContract { legs = new List<Tuple<double, FutureTradableContract>>() };
|
||||
|
||||
foreach (var part in spreadParts)
|
||||
{
|
||||
// Split each leg by '*', assuming the format is weight*future or just future
|
||||
string[] legParts = part.Split('*');
|
||||
double weight = 1.0;
|
||||
string futurePart;
|
||||
|
||||
if (legParts.Length == 2)
|
||||
{
|
||||
if (!double.TryParse(legParts[0], out weight))
|
||||
{
|
||||
return null; // Invalid weight, parsing failed
|
||||
}
|
||||
futurePart = legParts[1];
|
||||
}
|
||||
else if (legParts.Length == 1)
|
||||
{
|
||||
futurePart = legParts[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null; // Invalid format, too many '*' parts
|
||||
}
|
||||
|
||||
// Parse the future contract
|
||||
var futureContract = parse_future_contract(futurePart, exchange);
|
||||
if (futureContract == null)
|
||||
{
|
||||
return null; // Failed to parse the future part
|
||||
}
|
||||
|
||||
// Add the leg to the spread contract
|
||||
spreadContract.legs.Add(new Tuple<double, FutureTradableContract>(weight, futureContract));
|
||||
}
|
||||
return spreadContract;
|
||||
}
|
||||
|
||||
// public static ContractType DetermineFutureOrSpread(string contract) {
|
||||
// if (contract.Contains("-")) {
|
||||
// return ContractType.FutureSpread;
|
||||
// } else {
|
||||
// return ContractType.Future;
|
||||
// }
|
||||
// }
|
||||
#endregion
|
||||
|
||||
public static ContractType get_type(string contract_txt)
|
||||
{
|
||||
var fc = parse_future_contract(contract_txt);
|
||||
if (fc != null)
|
||||
{
|
||||
return ContractType.Future;
|
||||
}
|
||||
var sc = parse_future_spread_contract(contract_txt);
|
||||
if (sc != null)
|
||||
{
|
||||
return ContractType.FutureSpread;
|
||||
}
|
||||
// tehre are some non calendar spreads we cant parse
|
||||
//Log.assert(false);
|
||||
return ContractType.FutureSpread;
|
||||
}
|
||||
|
||||
public static ContractCategory get_category(string symbol)
|
||||
{
|
||||
var tp = get_symbol_category(symbol);
|
||||
return tp.Item1;
|
||||
}
|
||||
|
||||
public static Tuple<ContractCategory, string> get_symbol_category(string symbol)
|
||||
{
|
||||
var fc = parse_future_contract(symbol);
|
||||
if (fc != null)
|
||||
{
|
||||
return Tuple.Create(ContractCategory.FutureString, fc.Symbol);
|
||||
}
|
||||
var sc = parse_future_spread_contract(symbol);
|
||||
if (sc != null)
|
||||
{
|
||||
return Tuple.Create(ContractCategory.FutureString, sc.Symbol);
|
||||
}
|
||||
return Tuple.Create(ContractCategory.Symbol, symbol);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum ContractType
|
||||
{
|
||||
Spot,
|
||||
Option,
|
||||
Future,
|
||||
FutureSpread,
|
||||
OptionSpread
|
||||
}
|
||||
public enum ContractCategory
|
||||
{
|
||||
Symbol = 0,
|
||||
FutureString,
|
||||
SpreadString
|
||||
}
|
||||
public enum CallPut
|
||||
{
|
||||
Call,
|
||||
Put
|
||||
}
|
||||
public enum Exchange
|
||||
{
|
||||
CME
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
namespace BlueOrb.Operators.Data {
|
||||
using BCG;
|
||||
|
||||
using bts;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using BlueOrb.Internal;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
[DataStreamUserRespresentation("ReplayFutureLiveBBOStream")]
|
||||
public class ReplayFutureLiveBBOStream : ViewStream, BCG.Utilities.General.IWorker {
|
||||
private class LastFireTime {
|
||||
public DateTime last_fireitme_file = DateTime.MinValue;
|
||||
public DateTime last_firetime_clock = DateTime.MinValue;
|
||||
}
|
||||
private class RowsWithPointer {
|
||||
public List<IBlueRow>? rows;
|
||||
public int pointer;
|
||||
}
|
||||
|
||||
|
||||
readonly ViewStreamDatabase? _vsd;
|
||||
readonly ContractUtils.FutureContinousContract? _fcc;
|
||||
private readonly LastFireTime _last_fire_time = new LastFireTime();
|
||||
private RowsWithPointer _rows = new RowsWithPointer();
|
||||
|
||||
public ReplayFutureLiveBBOStream(string continous_contract) {
|
||||
Func<string> iso_8601_now = () => {
|
||||
DateTime utc_now = DateTime.UtcNow;
|
||||
long ticks = utc_now.Ticks; // 1 tick = 100 ns
|
||||
long nanoseconds = ticks % TimeSpan.TicksPerSecond * 100;
|
||||
string formatted = utc_now.ToString("yyyy-MM-ddTHH:mm:ss");
|
||||
formatted += $".{nanoseconds:D9}Z";
|
||||
return formatted;
|
||||
};
|
||||
ViewStream rs = new ReplayFutureLiveBBOStream(continous_contract, true);
|
||||
IBlueTableSchema schema_out = BlueDataUtility.form_schema("BBO",
|
||||
Tuple.Create("id", TypeCode.Int32),
|
||||
Tuple.Create("ts_event", TypeCode.String),
|
||||
Tuple.Create("contract", TypeCode.String),
|
||||
Tuple.Create("bid_price", TypeCode.Double),
|
||||
Tuple.Create("bid_size", TypeCode.Int32),
|
||||
Tuple.Create("ask_price", TypeCode.Double),
|
||||
Tuple.Create("ask_size", TypeCode.Int32));
|
||||
rs = new MapStream(rs, s => schema_out,
|
||||
r =>
|
||||
new BlueRow(schema_out, r["id"], /*r.get<string>("ts_event")*/iso_8601_now(), r.get<string>("symbol"),
|
||||
r.get<double>("bid_px_00"), r.get<int>("bid_sz_00"),
|
||||
r.get<double>("ask_px_00"), r.get<int>("ask_sz_00")));
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
private ReplayFutureLiveBBOStream(string continous_contract, bool noop)
|
||||
: this(ViewStreamDatabase.instance, new ContractUtils.FutureContract(continous_contract)) { }
|
||||
|
||||
public ReplayFutureLiveBBOStream(ViewStreamDatabase vsd, ContractUtils.FutureContract fc) {
|
||||
var fcc = fc.continous_constract;
|
||||
Log.assert(fcc != null);
|
||||
_vsd = vsd;
|
||||
_fcc = fcc;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
Log.notnull(_fcc);
|
||||
var file_path = Path.Combine(SQLiteHelper.location, $"mbp1_{_fcc.Symbol}_small.csv".ToLower());
|
||||
var rows = BCG.CSVReaderStream.LoadFile(file_path);
|
||||
_rows.rows = new(rows.Count);
|
||||
_rows.rows.AddRange(rows.OfType<IBlueRow>().OrderBy(r => r.get<string>("ts_event")));
|
||||
_rows.pointer = 0;
|
||||
ExceptionAssert.NotNull(_vsd).addWorker(this);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
ExceptionAssert.NotNull(_vsd).removeWorker(this);
|
||||
}
|
||||
|
||||
public void doWork() {
|
||||
var rows = ExceptionAssert.NotNull(_rows.rows);
|
||||
IBlueRow cand_row = rows[_rows.pointer];
|
||||
string cand_ts_event = cand_row.get<string>("ts_event");
|
||||
DateTime cand_ts_event_dt = DateTime.Parse(cand_ts_event, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
TimeSpan cand_ts_span_file = cand_ts_event_dt - _last_fire_time.last_fireitme_file;
|
||||
TimeSpan ts_clock = DateTime.Now - _last_fire_time.last_firetime_clock;
|
||||
if (ts_clock >= cand_ts_span_file) {
|
||||
_rows.pointer++;
|
||||
_last_fire_time.last_firetime_clock = DateTime.Now;
|
||||
_last_fire_time.last_fireitme_file = cand_ts_event_dt;
|
||||
BlueTable bt_out = new BlueTable(cand_row.schema);
|
||||
bt_out.addRow(cand_row);
|
||||
var dp_out = BlueDataUtility.build_dp(bt_out, myLastValue as IDataPacket);
|
||||
myFireEvent(dp_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
namespace Blueorb.Operators.Data
|
||||
{
|
||||
using BCG;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
using BlueOrb.Internal;
|
||||
using bts;
|
||||
using BlueOrb.Operators.Core;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
[DataStreamUserRespresentation("ReplayFutureLiveTradeStream")]
|
||||
public class ReplayFutureLiveTradeStream : ViewStream, BCG.Utilities.General.IWorker
|
||||
{
|
||||
private class LastFireTime
|
||||
{
|
||||
public DateTime last_fireitme_file = DateTime.MinValue;
|
||||
public DateTime last_firetime_clock = DateTime.MinValue;
|
||||
}
|
||||
private class RowsWithPointer
|
||||
{
|
||||
public List<IBlueRow>? rows;
|
||||
public int pointer;
|
||||
}
|
||||
|
||||
|
||||
readonly ViewStreamDatabase? _vsd;
|
||||
readonly ContractUtils.FutureContinousContract? _fcc;
|
||||
private readonly LastFireTime _last_fire_time = new LastFireTime();
|
||||
readonly RowsWithPointer _rows = new();
|
||||
|
||||
public ReplayFutureLiveTradeStream(string continous_contract)
|
||||
{
|
||||
Func<string> iso_8601_now = () =>
|
||||
{
|
||||
DateTime utc_now = DateTime.UtcNow;
|
||||
long ticks = utc_now.Ticks; // 1 tick = 100 ns
|
||||
long nanoseconds = ticks % TimeSpan.TicksPerSecond * 100;
|
||||
string formatted = utc_now.ToString("yyyy-MM-ddTHH:mm:ss");
|
||||
formatted += $".{nanoseconds:D9}Z";
|
||||
return formatted;
|
||||
};
|
||||
ViewStream rs = new ReplayFutureLiveTradeStream(continous_contract, true);
|
||||
IBlueTableSchema schema_out = BlueDataUtility.form_schema("BBO",
|
||||
Tuple.Create("id", TypeCode.Int32),
|
||||
Tuple.Create("ts_event", TypeCode.String),
|
||||
Tuple.Create("contract", TypeCode.String),
|
||||
Tuple.Create("trade_size", TypeCode.Double),
|
||||
Tuple.Create("trade_price", TypeCode.Int32),
|
||||
Tuple.Create("aggressor_side", TypeCode.String));
|
||||
rs = new MapStream(rs, s => schema_out,
|
||||
r =>
|
||||
new BlueRow(schema_out, r["id"], /*r.get<string>("ts_event")*/iso_8601_now(), r.get<string>("symbol"),
|
||||
r.get<double>("size"), r.get<double>("price"),
|
||||
r.get<string>("side").StartsWith("B") ? "BUY" : (r.get<string>("side").StartsWith("A") ? "SELL" : "NONE")));
|
||||
rs = new TimeSeriesStream(rs);
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
private ReplayFutureLiveTradeStream(string continous_contract, bool noop)
|
||||
: this(ViewStreamDatabase.instance, new ContractUtils.FutureContract(continous_contract)) { }
|
||||
|
||||
public ReplayFutureLiveTradeStream(ViewStreamDatabase vsd, ContractUtils.FutureContract fc)
|
||||
{
|
||||
var fcc = fc.continous_constract;
|
||||
Log.assert(fcc != null);
|
||||
_vsd = vsd;
|
||||
_fcc = fcc;
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber()
|
||||
{
|
||||
Log.notnull(_vsd);
|
||||
Log.notnull(_fcc);
|
||||
var file_path = Path.Combine(SQLiteHelper.location, $"trades_{_fcc.Symbol}.csv");
|
||||
var csv_rd = new BlueOrb.Operators.Core.CSVReaderStream(file_path, false);
|
||||
var rows = BCG.CSVReaderStream.LoadFile(file_path);
|
||||
_rows.rows = new(rows.Count);
|
||||
_rows.rows.AddRange(rows.OfType<IBlueRow>().OrderBy(r => r.get<string>("ts_event")));
|
||||
_rows.pointer = 0;
|
||||
ExceptionAssert.NotNull(_vsd).addWorker(this);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber()
|
||||
{
|
||||
ExceptionAssert.NotNull(_vsd).removeWorker(this);
|
||||
}
|
||||
|
||||
public void doWork()
|
||||
{
|
||||
var rows = ExceptionAssert.NotNull(_rows.rows);
|
||||
IBlueRow cand_row = rows[_rows.pointer];
|
||||
string cand_ts_event = cand_row.get<string>("ts_event");
|
||||
DateTime cand_ts_event_dt = DateTime.Parse(cand_ts_event, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||
TimeSpan cand_ts_span_file = cand_ts_event_dt - _last_fire_time.last_fireitme_file;
|
||||
TimeSpan ts_clock = DateTime.Now - _last_fire_time.last_firetime_clock;
|
||||
if (ts_clock >= cand_ts_span_file)
|
||||
{
|
||||
_rows.pointer++;
|
||||
_last_fire_time.last_firetime_clock = DateTime.Now;
|
||||
_last_fire_time.last_fireitme_file = cand_ts_event_dt;
|
||||
BlueTable bt_out = new BlueTable(cand_row.schema);
|
||||
bt_out.addRow(cand_row);
|
||||
var dp_out = BlueDataUtility.build_dp(bt_out, myLastValue as IDataPacket);
|
||||
myFireEvent(dp_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BlueOrb.Internal
|
||||
{
|
||||
|
||||
public static class SQLiteHelper
|
||||
{
|
||||
public static string location = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? "C:\\BlueOrb_Data\\"
|
||||
: Path.Combine(Environment.GetEnvironmentVariable("HOME") ?? string.Empty, "BlueOrb_Data");
|
||||
public static string db_name = "stream_data.db";
|
||||
|
||||
public static DataTable execute_select_query(string connection_string, string query)
|
||||
{
|
||||
// Create a new DataTable to store the results
|
||||
DataTable dataTable = new DataTable();
|
||||
|
||||
// Create and open a SQLite connection using the provided connection string
|
||||
using (SQLiteConnection connection = new SQLiteConnection(connection_string))
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
// Create a SQLite command with the provided query
|
||||
using (SQLiteCommand command = new SQLiteCommand(query, connection))
|
||||
{
|
||||
// Use SQLiteDataAdapter to fill the DataTable
|
||||
using (SQLiteDataAdapter adapter = new SQLiteDataAdapter(command))
|
||||
{
|
||||
adapter.Fill(dataTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("An error occurred: " + ex.Message);
|
||||
}
|
||||
}
|
||||
// Return the populated DataTable
|
||||
return dataTable;
|
||||
}
|
||||
|
||||
public static List<Dictionary<string, object>> ExecuteBulkRead(string connectionString, string query)
|
||||
{
|
||||
var result = new List<Dictionary<string, object>>();
|
||||
|
||||
using (var connection = new SQLiteConnection(connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
// Begin a transaction to optimize read speed
|
||||
using (var transaction = connection.BeginTransaction())
|
||||
using (var command = new SQLiteCommand(query, connection, transaction))
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var row = new Dictionary<string, object>();
|
||||
|
||||
for (int i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
string columnName = reader.GetName(i);
|
||||
object columnValue = reader.IsDBNull(i) ? null : reader.GetValue(i);
|
||||
row[columnName] = columnValue;
|
||||
}
|
||||
|
||||
result.Add(row);
|
||||
}
|
||||
|
||||
// Commit the transaction
|
||||
transaction.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Dictionary<string, object>> get_table(string connectionString, string query)
|
||||
{
|
||||
var result = new List<Dictionary<string, object>>();
|
||||
|
||||
using (var connection = new SQLiteConnection(connectionString))
|
||||
{
|
||||
try
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
using (var command = new SQLiteCommand(query, connection))
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var row = new Dictionary<string, object>();
|
||||
|
||||
for (int i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
string columnName = reader.GetName(i);
|
||||
object columnValue = reader.IsDBNull(i) ? null : reader.GetValue(i);
|
||||
row[columnName] = columnValue;
|
||||
}
|
||||
|
||||
result.Add(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("An error occurred: " + ex.Message);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IEnumerable<Dictionary<string, object>> get_table_2(string connectionString, string query)
|
||||
{
|
||||
using (var connection = new SQLiteConnection(connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
using (var command = new SQLiteCommand(query, connection))
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
var row = new Dictionary<string, object>();
|
||||
for (int i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
string columnName = reader.GetName(i);
|
||||
object columnValue = reader.IsDBNull(i) ? null : reader.GetValue(i);
|
||||
row[columnName] = columnValue;
|
||||
}
|
||||
yield return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace BlueOrb.Internal
|
||||
{
|
||||
using bts;
|
||||
using System;
|
||||
using BCG;
|
||||
using System.Collections.Generic;
|
||||
using Bts.DataStreamExpressions;
|
||||
using System.Xml;
|
||||
|
||||
// All this does is take in a dsl expression, parse it and fire the data that come out of running it.
|
||||
// So for example, if an expresison is passed
|
||||
[DataStreamUserRespresentation("dsl")]
|
||||
public class DSLStream : ViewStream
|
||||
{
|
||||
private readonly string _dsl;
|
||||
public DSLStream(string dsl)
|
||||
{
|
||||
Log.Gen.info($"DSLStream.cons dsl: {dsl}");
|
||||
// Remove all colons
|
||||
string sanitizedDsl = dsl.Replace(":", "COLON");
|
||||
_dsl = dsl;
|
||||
ViewStream rs = build_stream(dsl) ?? new LiteralStream("error", $"msg:invalid dsl");
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
|
||||
static ViewStream? build_stream(string stream_expression)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exp = DataStreamExpressionsInterpreter.Evaluate(stream_expression);
|
||||
var rv = exp.getView(new Dictionary<string, StatementExpression>(0));
|
||||
return rv;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//send to blueorb
|
||||
Log.Gen.error($"Could not build stream: {stream_expression} ex: {ex}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
|
||||
using BCG.Utilities.General;
|
||||
using BCG;
|
||||
using bts;
|
||||
|
||||
namespace BlueOrb.Internal
|
||||
{
|
||||
[DataStreamUserRespresentation("MillisecondStream")]
|
||||
public class MillisecondStream : ViewStream, IWorker
|
||||
{
|
||||
private DateTime _last_fire_time = DateTime.MinValue;
|
||||
private readonly TimeSpan _period;
|
||||
private readonly int _size;
|
||||
private readonly ViewStreamDatabase _vsd;
|
||||
private IBlueTableSchema _schema;
|
||||
private bts.CircularBufferTable _table;
|
||||
|
||||
public MillisecondStream(int interval_msecs, int size)
|
||||
: this(ViewStreamDatabase.instance, interval_msecs, size)
|
||||
{
|
||||
}
|
||||
|
||||
public MillisecondStream(ViewStreamDatabase vsd, int interval_msecs, int size)
|
||||
{
|
||||
_vsd = vsd;
|
||||
_period = TimeSpan.FromMilliseconds(interval_msecs);
|
||||
_size = size;
|
||||
_schema = BlueDataUtility.form_schema("Milliseconds",
|
||||
Tuple.Create("id", TypeCode.Int32),
|
||||
Tuple.Create("time", TypeCode.DateTime),
|
||||
Tuple.Create("display_time", TypeCode.String));
|
||||
_table = new CircularBufferTable(_schema, _size);
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber()
|
||||
{
|
||||
_vsd.addWorker(this);
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber()
|
||||
{
|
||||
_vsd.removeWorker(this);
|
||||
}
|
||||
|
||||
private int _id = 0;
|
||||
public void doWork()
|
||||
{
|
||||
if (DateTime.Now - _last_fire_time >= _period)
|
||||
{
|
||||
_last_fire_time = DateTime.Now;
|
||||
IBlueRow nr = new BlueRow(_schema, _id++, _last_fire_time,
|
||||
_last_fire_time.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
_table.add_row(nr);
|
||||
var dp = BlueDataUtility.build_dp_inc(_table, myLastValue as DataPacket);
|
||||
myFireEvent(dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal class MSecondStream : TimeUnitStream
|
||||
{
|
||||
public MSecondStream(int intervalInms, int size)
|
||||
: base(DateTime.Now, new TimeSpan(0, 0, 0, 0, intervalInms), size, ViewStreamDatabase.instance) { }
|
||||
|
||||
protected override DateTime myRoundTime(DateTime dt) { return dt; }
|
||||
}
|
||||
|
||||
internal class DisplayableMillisecondStream : ViewStream, IStreamMapper
|
||||
{
|
||||
private IBlueTableSchema mySchema = new BlueTableSchema("ms",
|
||||
new ColumnInfo("id", 0, typeof(int)),
|
||||
new ColumnInfo("time", 1, typeof(string)));
|
||||
public DisplayableMillisecondStream(int intervalInMs, int sz)
|
||||
{
|
||||
mySetRealSource(new MapStream(new MSecondStream(intervalInMs, sz), this));
|
||||
}
|
||||
#region IStreamMapper Members
|
||||
|
||||
public IBlueTableSchema getOutputSchema(IBlueTableSchema inputSchema)
|
||||
{
|
||||
return mySchema;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDynamicStreamMapper Members
|
||||
|
||||
public IBlueRow map(IBlueRow row)
|
||||
{
|
||||
DateTime time = row.get_datetime("time");
|
||||
var time_txt = time.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
return new BlueRow(mySchema, row["id"], time_txt);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private string myToString(DateTime dt)
|
||||
{
|
||||
string sep = ":";
|
||||
return dt.Hour + sep + dt.Minute + sep + dt.Second + sep + dt.Millisecond;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
namespace BlueOrb.Operators.Signal
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using BCG;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System.Data;
|
||||
|
||||
|
||||
public enum BarType
|
||||
{
|
||||
TIME,
|
||||
TICK,
|
||||
VOLUME,
|
||||
DOLLAR,
|
||||
}
|
||||
|
||||
public class BarBuilderSchemaInfo
|
||||
{
|
||||
[JsonPropertyName("price_col")]
|
||||
public string price_col { get; set; } = "trade_price";
|
||||
|
||||
[JsonPropertyName("volume_col")]
|
||||
public string volume_col { get; set; } = "trade_size";
|
||||
|
||||
[JsonPropertyName("timestamp_col")]
|
||||
public string timestamp_col { get; set; } = "ts_event";
|
||||
}
|
||||
|
||||
|
||||
public class SingleBar : IBlueRow
|
||||
{
|
||||
private BarBuilderStream _parent_str;
|
||||
private IBlueTableSchema _schema;
|
||||
private MutableBlueRow _row;
|
||||
public SingleBar(BarBuilderStream parent_str)
|
||||
{
|
||||
_parent_str = parent_str;
|
||||
_schema = BlueDataUtility.form_schema(
|
||||
"bar_builder_single_bar",
|
||||
Tuple.Create("id", TypeCode.Int32),
|
||||
Tuple.Create("ts_event", TypeCode.DateTime),
|
||||
Tuple.Create("bar_start_ts", TypeCode.DateTime),
|
||||
Tuple.Create("bar_end_ts", TypeCode.DateTime),
|
||||
Tuple.Create("open", TypeCode.Double),
|
||||
Tuple.Create("high", TypeCode.Double),
|
||||
Tuple.Create("low", TypeCode.Double),
|
||||
Tuple.Create("close", TypeCode.Double),
|
||||
Tuple.Create("volume", TypeCode.Double),
|
||||
Tuple.Create("notional", TypeCode.Double),
|
||||
Tuple.Create("trade_count", TypeCode.Int32),
|
||||
Tuple.Create("n_events", TypeCode.Int32),
|
||||
Tuple.Create("vwap", TypeCode.Double),
|
||||
Tuple.Create("is_active", TypeCode.Boolean)
|
||||
);
|
||||
_row = new MutableBlueRow(_schema);
|
||||
}
|
||||
|
||||
public IBlueTableSchema schema => _row.schema;
|
||||
|
||||
public object this[int index] => _row[index];
|
||||
|
||||
public object this[string col_name] => _row[col_name];
|
||||
|
||||
|
||||
public IBlueRow add_event(IBlueRow r)
|
||||
{
|
||||
// initiaizes _row
|
||||
void reset_new_bar()
|
||||
{
|
||||
_row = new MutableBlueRow(_schema);
|
||||
_row.setValue("id", _parent_str.get_new_id());
|
||||
_row.setValue("volume", 0.0);
|
||||
_row.setValue("notional", 0.0);
|
||||
_row.setValue("trade_count", 0);
|
||||
_row.setValue("n_events", 0);
|
||||
_row.setValue("is_active", true);
|
||||
}
|
||||
|
||||
void absorb_into_row(IBlueRow input_row)
|
||||
{
|
||||
var ts = input_row.get_datetime(_parent_str._schema_info.timestamp_col, DateTime.UtcNow).ToUniversalTime();
|
||||
var price = input_row.get<double>(_parent_str._schema_info.price_col, 0.0);
|
||||
var volume = input_row.get<double>(_parent_str._schema_info.volume_col, 0.0);
|
||||
var notional = price * volume;
|
||||
|
||||
if (_row.is_null("bar_start_ts"))
|
||||
{
|
||||
DateTime bar_start_ts;
|
||||
DateTime bar_end_ts;
|
||||
if (_parent_str._bar_type == BarType.TIME)
|
||||
{
|
||||
var bucket_ticks = (long)(Math.Max(1.0, _parent_str._bar_size) * TimeSpan.TicksPerSecond);
|
||||
var start_ticks = (ts.Ticks / bucket_ticks) * bucket_ticks;
|
||||
bar_start_ts = new DateTime(start_ticks, DateTimeKind.Utc);
|
||||
bar_end_ts = bar_start_ts.AddTicks(bucket_ticks);
|
||||
}
|
||||
else
|
||||
{
|
||||
bar_start_ts = ts;
|
||||
bar_end_ts = ts;
|
||||
}
|
||||
_row.setValue("bar_start_ts", bar_start_ts);
|
||||
_row.setValue("bar_end_ts", bar_end_ts);
|
||||
_row.setValue("open", price);
|
||||
_row.setValue("high", price);
|
||||
_row.setValue("low", price);
|
||||
}
|
||||
else
|
||||
{
|
||||
var high = _row.get<double>("high", price);
|
||||
var low = _row.get<double>("low", price);
|
||||
_row.setValue("high", Math.Max(high, price));
|
||||
_row.setValue("low", Math.Min(low, price));
|
||||
}
|
||||
|
||||
_row.setValue("ts_event", ts);
|
||||
_row.setValue("close", price);
|
||||
_row.setValue("volume", _row.get<double>("volume", 0.0) + volume);
|
||||
_row.setValue("notional", _row.get<double>("notional", 0.0) + notional);
|
||||
_row.setValue("trade_count", _row.get<int>("trade_count", 0) + 1);
|
||||
_row.setValue("n_events", _row.get<int>("n_events", 0) + 1);
|
||||
var running_volume = _row.get<double>("volume", 0.0);
|
||||
var running_notional = _row.get<double>("notional", 0.0);
|
||||
_row.setValue("vwap", running_volume > 0.0 ? running_notional / running_volume : price);
|
||||
}
|
||||
|
||||
bool is_closed()
|
||||
{
|
||||
bool closed;
|
||||
if (_parent_str._bar_type == BarType.TIME)
|
||||
{
|
||||
var ts = _row.get_datetime("ts_event", DateTime.MinValue);
|
||||
var bar_end_ts = _row.get_datetime("bar_end_ts", DateTime.MaxValue);
|
||||
closed = ts >= bar_end_ts;
|
||||
}
|
||||
else if (_parent_str._bar_type == BarType.TICK)
|
||||
{
|
||||
closed = _row.get<int>("n_events", 0) >= _parent_str._bar_size;
|
||||
}
|
||||
else if (_parent_str._bar_type == BarType.VOLUME)
|
||||
{
|
||||
closed = _row.get<double>("volume", 0.0) >= _parent_str._bar_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
closed = _row.get<double>("notional", 0.0) >= _parent_str._bar_size;
|
||||
}
|
||||
_row.setValue("is_active", !closed);
|
||||
return closed;
|
||||
}
|
||||
|
||||
if (_row == null)
|
||||
{
|
||||
reset_new_bar();
|
||||
}
|
||||
absorb_into_row(r);
|
||||
if (is_closed())
|
||||
{
|
||||
IBlueRow closed_row = new BlueRow(_row);
|
||||
reset_new_bar();
|
||||
return closed_row;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class BarState : IBlueRowCollection
|
||||
{
|
||||
private SingleBar _curr_row;
|
||||
private BlueTable _state;
|
||||
|
||||
public BarState(BarBuilderStream parent_str)
|
||||
{
|
||||
_curr_row = new SingleBar(parent_str);
|
||||
_state = new BlueTable(_curr_row.schema);
|
||||
}
|
||||
|
||||
public bool add_event(IBlueRow r)
|
||||
{
|
||||
var closed_bar = _curr_row.add_event(r);
|
||||
if (closed_bar is not null)
|
||||
{
|
||||
// curr bar is closed, only then its added
|
||||
// when bars are evolving we dont add it
|
||||
_state.addRow(closed_bar);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IBlueRow this[int id] => _state[id];
|
||||
|
||||
public IBlueTableSchema schema => _state.schema;
|
||||
|
||||
public bool containsID(int id) => _state.containsID(id);
|
||||
|
||||
public int Count => _state.Count;
|
||||
|
||||
public System.Collections.IEnumerator GetEnumerator() => _state.GetEnumerator();
|
||||
}
|
||||
|
||||
[DataStreamUserRespresentation("BarBuilderStream")]
|
||||
public class BarBuilderStream : ViewStream
|
||||
{
|
||||
readonly ViewStream _price_stream;
|
||||
internal readonly BarType _bar_type;
|
||||
internal readonly double _bar_size;
|
||||
internal readonly bool _show_open_bars;
|
||||
internal readonly BarBuilderSchemaInfo _schema_info;
|
||||
private BarState _state;
|
||||
|
||||
public BarBuilderStream(ViewStream price_stream,
|
||||
BarType bar_type,
|
||||
double bar_size,
|
||||
bool show_open_bars,
|
||||
BarBuilderSchemaInfo schema_info)
|
||||
{
|
||||
_price_stream = price_stream;
|
||||
_bar_type = bar_type;
|
||||
_bar_size = bar_size;
|
||||
_show_open_bars = show_open_bars;
|
||||
_schema_info = schema_info;
|
||||
_state = new BarState(this);
|
||||
}
|
||||
|
||||
int _id = 0;
|
||||
internal int get_new_id()
|
||||
{
|
||||
return _id++;
|
||||
}
|
||||
|
||||
public BarBuilderStream(ViewStream price_stream,
|
||||
string bar_type,
|
||||
double bar_size,
|
||||
string schema_info_json)
|
||||
:
|
||||
this(price_stream,
|
||||
Enum.Parse<BarType>(bar_type),
|
||||
bar_size,
|
||||
true,
|
||||
_parse_and_validate_schema_info_json(schema_info_json))
|
||||
{
|
||||
}
|
||||
|
||||
public BarBuilderStream(ViewStream price_stream,
|
||||
string bar_type,
|
||||
double bar_size,
|
||||
string price_col,
|
||||
string volume_col,
|
||||
string timestamp_col)
|
||||
:
|
||||
this(price_stream,
|
||||
Enum.Parse<BarType>(bar_type),
|
||||
bar_size,
|
||||
true,
|
||||
_create_and_validate_schema_info(price_col, volume_col, timestamp_col))
|
||||
{
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber()
|
||||
{
|
||||
_price_stream.onChange += _on_price_stream_change;
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber()
|
||||
{
|
||||
_price_stream.onChange -= _on_price_stream_change;
|
||||
}
|
||||
|
||||
void _on_price_stream_change(object dp_obj)
|
||||
{
|
||||
DataPacket dp = dp_obj as DataPacket;
|
||||
var sz_0 = _state.Count;
|
||||
foreach (IBlueRow r in dp.addedRows)
|
||||
{
|
||||
_state.add_event(r);
|
||||
}
|
||||
if (_state.Count != sz_0)
|
||||
// we will check for _show_open_bars here
|
||||
{
|
||||
var dp_out = BlueDataUtility.build_dp_inc(_state, myLastValue as DataPacket, false);
|
||||
myFireEvent(dp_out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static BarBuilderSchemaInfo _parse_and_validate_schema_info_json(string schema_info_json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schema_info_json))
|
||||
{
|
||||
throw new ArgumentException("schema_info_json cannot be null or empty.", nameof(schema_info_json));
|
||||
}
|
||||
|
||||
var schema_info = JsonSerializer.Deserialize<BarBuilderSchemaInfo>(schema_info_json);
|
||||
_validate_schema_info(schema_info);
|
||||
return schema_info!;
|
||||
}
|
||||
|
||||
static BarBuilderSchemaInfo _create_and_validate_schema_info(
|
||||
string price_col,
|
||||
string volume_col,
|
||||
string timestamp_col)
|
||||
{
|
||||
var schema_info = new BarBuilderSchemaInfo
|
||||
{
|
||||
price_col = price_col,
|
||||
volume_col = volume_col,
|
||||
timestamp_col = timestamp_col,
|
||||
};
|
||||
_validate_schema_info(schema_info);
|
||||
return schema_info;
|
||||
}
|
||||
|
||||
static void _validate_schema_info(BarBuilderSchemaInfo? schema_info)
|
||||
{
|
||||
if (schema_info is null)
|
||||
{
|
||||
throw new ArgumentException("schema_info_json did not deserialize into BarBuilderSchemaInfo.");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(schema_info.price_col))
|
||||
{
|
||||
throw new ArgumentException("BarBuilderSchemaInfo.PriceCol cannot be null or empty.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(schema_info.volume_col))
|
||||
{
|
||||
throw new ArgumentException("BarBuilderSchemaInfo.VolumeCol cannot be null or empty.");
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(schema_info.timestamp_col))
|
||||
{
|
||||
throw new ArgumentException("BarBuilderSchemaInfo.TimestampCol cannot be null or empty.");
|
||||
}
|
||||
|
||||
if (schema_info.price_col.Equals(schema_info.volume_col, StringComparison.OrdinalIgnoreCase) ||
|
||||
schema_info.price_col.Equals(schema_info.timestamp_col, StringComparison.OrdinalIgnoreCase) ||
|
||||
schema_info.volume_col.Equals(schema_info.timestamp_col, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new ArgumentException("BarBuilderSchemaInfo columns must be distinct.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
namespace BlueOrb.Internal;
|
||||
|
||||
using BCG;
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
[DataStreamUserRespresentation("TestStream")]
|
||||
public class TestStream : ViewStream {
|
||||
public TestStream() {
|
||||
var rs = new BlueOrb.Operators.Core.LiteralStream("table1", "x:123, y:1.001, z:abc;x:123, y:1.001, z:abc");
|
||||
mySetRealSource(rs);
|
||||
}
|
||||
}
|
||||
|
||||
[DataStreamUserRespresentation("OpsStream")]
|
||||
public class OpsStream : ViewStream {
|
||||
public OpsStream() {
|
||||
}
|
||||
|
||||
protected override void myOnFirstSubscriber() {
|
||||
IBlueTableSchema schema = new BlueTableSchema("Ops");
|
||||
schema = schema.add_column(System.TypeCode.Int32, "id");
|
||||
schema = schema.add_column(System.TypeCode.String, "op");
|
||||
schema = schema.add_column(System.TypeCode.String, "namespace");
|
||||
schema = schema.add_column(System.TypeCode.String, "assembly_name");
|
||||
schema = schema.add_column(System.TypeCode.String, "constructor");
|
||||
var loaded_streams = PrimitiveManager.instance.get_loaded_streams();
|
||||
BlueTable rv = new BlueTable(schema);
|
||||
foreach (var kv in loaded_streams.OrderBy(kv => kv.Key, StringComparer.OrdinalIgnoreCase)) {
|
||||
string sn = kv.Key;
|
||||
Type t = kv.Value;
|
||||
string ns = t.Namespace ?? string.Empty;
|
||||
string assembly_name = t.Assembly.GetName().Name ?? string.Empty;
|
||||
var constructors = t.GetConstructors()
|
||||
.OrderBy(c => c.GetParameters().Length)
|
||||
.ThenBy(c => c.ToString());
|
||||
if (!constructors.Any()) {
|
||||
IBlueRow r = new BlueRow(schema, rv.Count, sn, ns, assembly_name, "(no public constructor)");
|
||||
rv.addRow(r);
|
||||
continue;
|
||||
}
|
||||
foreach (var ctor in constructors) {
|
||||
var parameters = ctor.GetParameters();
|
||||
string constructor = $"{t.Name}({string.Join(", ", parameters.Select(p => p.ParameterType.Name))})";
|
||||
IBlueRow r = new BlueRow(schema, rv.Count, sn, ns, assembly_name, constructor);
|
||||
rv.addRow(r);
|
||||
}
|
||||
}
|
||||
myFireEvent(new DataPacket(rv, rv, new BlueTable(schema)));
|
||||
}
|
||||
|
||||
protected override void myOnLastSubscriber() {
|
||||
base.myOnLastSubscriber();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+3
-3
@@ -102,10 +102,10 @@ namespace BCG
|
||||
List<ColumnInfo> col_info = new List<ColumnInfo>();
|
||||
col_info.Add(new ColumnInfo("id", col_index++, typeof(int)));
|
||||
foreach (Pair<string, Type> p in group_by_col_info)
|
||||
col_info.Add(new ColumnInfo(p.first ?? string.Empty, col_index++, ExceptionAssert.NotNull(p.second)));
|
||||
col_info.Add(new ColumnInfo(p.first, col_index++, p.second));
|
||||
foreach (string tc_prefix in tc_prefixes)
|
||||
foreach (Pair<string, Type> p in _cols_per_transposed)
|
||||
col_info.Add(new ColumnInfo(_get_full_column_name(tc_prefix, p.first ?? string.Empty), col_index++, ExceptionAssert.NotNull(p.second)));
|
||||
col_info.Add(new ColumnInfo(_get_full_column_name(tc_prefix, p.first ?? string.Empty), col_index++, p.second));
|
||||
IBlueTableSchema schema = new BlueTableSchema(col_info.ToArray(), "xy_transposed_" + table_name);
|
||||
if (_schema == null)
|
||||
_schema = schema;
|
||||
@@ -182,7 +182,7 @@ namespace BCG
|
||||
if (_transpsed_col_value_comparer_wrapper != null)
|
||||
tc_values.Sort(_transpsed_col_value_comparer_wrapper);
|
||||
List<string> prefixes = new List<string>();
|
||||
foreach (Pair<int, object?[]> p in tc_values)
|
||||
foreach (Pair<int, object[]> p in tc_values)
|
||||
prefixes.Add(tc_prefixes[p.first]);
|
||||
_set_schema(prefixes, group_by_col_info, table_name);
|
||||
BlueTable result = new BlueTable(_schema);
|
||||
|
||||
+19
-25
@@ -1,17 +1,17 @@
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
using BCG;
|
||||
using BCG.Utilities;
|
||||
|
||||
namespace BCG
|
||||
{
|
||||
public class ConcatenateColumnsMapper : IStreamMapper
|
||||
{
|
||||
protected IDictionary myTempColMap = new SortedList ();
|
||||
protected ArrayList? myColMap;
|
||||
protected BlueTableSchema? mySchema;
|
||||
protected ArrayList myColMap;
|
||||
protected BlueTableSchema mySchema;
|
||||
|
||||
public ConcatenateColumnsMapper(params string [] columnDefs)
|
||||
{
|
||||
@@ -55,7 +55,11 @@ namespace BCG
|
||||
myColMap = new ArrayList (myTempColMap.Count);
|
||||
foreach (DictionaryEntry de in myTempColMap)
|
||||
{
|
||||
myColMap.Add(Array.ConvertAll((string[])de.Value!, c => inputSchema[c].colNo));
|
||||
string[] cols = de.Value as string[];
|
||||
ArrayList temp = new ArrayList ();
|
||||
foreach (string col in cols)
|
||||
temp.Add (inputSchema[col].colNo);
|
||||
myColMap.Add (temp.ToArray(typeof(int)) as int[]);
|
||||
}
|
||||
myTempColMap.Clear ();
|
||||
}
|
||||
@@ -68,8 +72,6 @@ namespace BCG
|
||||
|
||||
public virtual IBlueRow map (IBlueRow row)
|
||||
{
|
||||
requireSchema();
|
||||
requireColMap();
|
||||
object[] retVal = new object[mySchema.columnInfo.Length];
|
||||
row.CopyTo (retVal, myColMap.Count);
|
||||
for (int colNo = 0; colNo < myColMap.Count; colNo ++)
|
||||
@@ -88,21 +90,11 @@ namespace BCG
|
||||
/// <returns></returns>
|
||||
protected virtual object myGetConcatValue (IBlueRow row, int colNo)
|
||||
{
|
||||
requireColMap();
|
||||
StringBuilder b = new StringBuilder();
|
||||
foreach (int cn in (int[])myColMap[colNo]!) {
|
||||
b.Append(row[cn]?.ToString());
|
||||
}
|
||||
foreach (int cn in myColMap[colNo] as int[])
|
||||
b.Append(row[cn].ToString());
|
||||
return b.ToString ();
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(myColMap))]
|
||||
protected void requireColMap() =>
|
||||
ExceptionAssert.NotNull(myColMap);
|
||||
|
||||
[MemberNotNull(nameof(mySchema))]
|
||||
void requireSchema() =>
|
||||
ExceptionAssert.NotNull(mySchema);
|
||||
}
|
||||
|
||||
public class ConcatenateColumnsMapperForSameDataSet : ConcatenateColumnsMapper
|
||||
@@ -115,21 +107,23 @@ namespace BCG
|
||||
myDicts = new HashTableND [columnDefs.Length];
|
||||
int i = 0;
|
||||
foreach (DictionaryEntry de in myTempColMap)
|
||||
myDicts[i++] = new HashTableND(((string[])de.Value!).Length);
|
||||
myDicts[i++] = new HashTableND ((de.Value as string[]).Length);
|
||||
}
|
||||
|
||||
protected override object myGetConcatValue (IBlueRow row, int colNo)
|
||||
{
|
||||
requireColMap();
|
||||
int[] cols = myColMap[colNo] as int[];
|
||||
object[] vals = new object[cols.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
vals[i] = row[cols[i]];
|
||||
HashTableND ht = myDicts[colNo];
|
||||
var vals = Array.ConvertAll((int[])myColMap[colNo]!, c => row[c]);
|
||||
var rv = ht.getValue(vals);
|
||||
object rv = ht.getValue (vals);
|
||||
if (rv != null)
|
||||
return rv;
|
||||
else
|
||||
{
|
||||
rv = base.myGetConcatValue (row, colNo);
|
||||
var args = new object?[vals.Length + 1];
|
||||
object[] args = new object[vals.Length + 1];
|
||||
vals.CopyTo (args, 0);
|
||||
args[args.Length-1] = rv;
|
||||
ht.add (args);
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace BCG
|
||||
{
|
||||
IDictionary<string, double> columnSums = new Dictionary<string, double>();
|
||||
|
||||
IBlueRow? resultRow = null;
|
||||
IBlueRow resultRow = null;
|
||||
foreach (IBlueRow row in rows)
|
||||
{
|
||||
resultRow = row;
|
||||
@@ -29,7 +29,7 @@ namespace BCG
|
||||
{
|
||||
double sum = 0.0f;
|
||||
columnSums.TryGetValue(colName, out sum);
|
||||
sum += (double)row[colName]!;
|
||||
sum += (double) row[colName];
|
||||
columnSums[colName] = sum;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using BCG.Utilities;
|
||||
|
||||
namespace BCG
|
||||
{
|
||||
public class DistinctRowEvaluator : GroupByEvaluator
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace BCG {
|
||||
}
|
||||
#endregion
|
||||
|
||||
public event FilterChangeDelegate? onFilterChange;
|
||||
public event FilterChangeDelegate onFilterChange;
|
||||
|
||||
#region IStreamFilter
|
||||
public bool filter(IBlueRow row) {
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace bts.SilverPine {
|
||||
operations = operations_;
|
||||
}
|
||||
|
||||
public static IBlueRow? group_by(List<IBlueRow> rows, MultiRowOpHelper parameters) {
|
||||
public static IBlueRow group_by(List<IBlueRow> rows, MultiRowOpHelper parameters) {
|
||||
if (rows.Count() == 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ namespace bts.SilverPine {
|
||||
// rolling_rows are the rolling window of rows. the 0th row is the one thats gettin
|
||||
// calculated. rows 1 - n-1 are its window rows. the schema is based on the operations.
|
||||
|
||||
public IBlueRow? rolling_calc(List<IBlueRow> rolling_rows) {
|
||||
public IBlueRow rolling_calc(List<IBlueRow> rolling_rows) {
|
||||
if (rolling_rows.Count() == 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -123,4 +123,4 @@ namespace bts.SilverPine {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Bts.DataStreamCore;
|
||||
using System;
|
||||
|
||||
namespace BCG
|
||||
{
|
||||
@@ -9,18 +9,18 @@ namespace BCG
|
||||
public abstract class GroupByEvaluator : IGroupByEvaluator
|
||||
{
|
||||
protected string[] myGroupByCols;
|
||||
protected string? myOutputColumn;
|
||||
protected GroupByOutputTable? myOutputTable;
|
||||
protected string? myColMapExpression;
|
||||
protected string myOutputColumn;
|
||||
protected GroupByOutputTable myOutputTable;
|
||||
protected string myColMapExpression;
|
||||
|
||||
#region constructors
|
||||
public GroupByEvaluator (string? outputCol, string[] groupByCols)
|
||||
public GroupByEvaluator (string outputCol, string[] groupByCols)
|
||||
{
|
||||
myOutputColumn = outputCol;
|
||||
myGroupByCols = groupByCols;
|
||||
}
|
||||
|
||||
public GroupByEvaluator (string colMapExpression, string? outputCol, string[] groupByCols)
|
||||
public GroupByEvaluator (string colMapExpression, string outputCol, string[] groupByCols)
|
||||
: this (outputCol, groupByCols) {myColMapExpression = colMapExpression;}
|
||||
#endregion
|
||||
|
||||
@@ -52,20 +52,21 @@ namespace BCG
|
||||
/// <param name="r"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
protected IBlueRow? myProject(IBlueRow? r, int id) =>
|
||||
r is null
|
||||
? null
|
||||
: myColMapExpression is null || myColMapExpression.Length < 1
|
||||
? BlueDataUtility.getNewReplacedRow(r, id, "id")
|
||||
: BlueDataUtility.getNewReplacedRow(myProjectRow(r, myColMapExpression), id, "id");
|
||||
|
||||
protected IBlueRow myProject (IBlueRow r, int id)
|
||||
{
|
||||
return r == null ? null :
|
||||
myColMapExpression == null || myColMapExpression.Length < 1 ?
|
||||
BlueDataUtility.getNewReplacedRow (r, id, "id") :
|
||||
BlueDataUtility.getNewReplacedRow(myProjectRow (r, myColMapExpression),
|
||||
id, "id");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Projects the id, conserving the id
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <returns></returns>
|
||||
protected IBlueRow? myProject(IBlueRow? r) =>
|
||||
myProject(r, r is null ? int.MinValue : r.Id());
|
||||
protected IBlueRow myProject (IBlueRow r) {return myProject (r, r == null ? Int32.MinValue : (int)r["id"]);}
|
||||
#endregion
|
||||
|
||||
IBlueRow myProjectRow (IBlueRow r, string colMapExpression) =>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using System;
|
||||
using BCG.Utilities;
|
||||
using System.Collections;
|
||||
|
||||
namespace BCG
|
||||
@@ -23,12 +22,10 @@ namespace BCG
|
||||
/// <param name="groupRepString"></param>
|
||||
public void addRow (IBlueRow row, string groupRepString)
|
||||
{
|
||||
var grp = myDict[groupRepString];
|
||||
if (grp is not null) {
|
||||
myTable.deleteRow((IBlueRow)grp);
|
||||
}
|
||||
if (myDict[groupRepString] != null)
|
||||
myTable.deleteRow ((IBlueRow)myDict[groupRepString]);
|
||||
myTable.addRow (row);
|
||||
myDict[groupRepString] = myTable[row.Id()];
|
||||
myDict[groupRepString] = myTable[(int)row["id"]];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -38,7 +35,7 @@ namespace BCG
|
||||
public void removeRow (string groupRepString)
|
||||
{
|
||||
// BlueEventLog.logAssert (myDict[groupRepString] != null);
|
||||
myTable.deleteRow ((IBlueRow)myDict[groupRepString]!);
|
||||
myTable.deleteRow ((IBlueRow)myDict[groupRepString]);
|
||||
myDict.Remove (groupRepString);
|
||||
}
|
||||
|
||||
@@ -51,8 +48,11 @@ namespace BCG
|
||||
myDict.Clear ();
|
||||
}
|
||||
|
||||
public IBlueRow? getRow(string groupRepString) =>
|
||||
myDict[groupRepString] as IBlueRow;
|
||||
public IBlueRow getRow (string groupRepString)
|
||||
{
|
||||
return myDict[groupRepString] == null ? null :
|
||||
myDict[groupRepString] as IBlueRow;
|
||||
}
|
||||
|
||||
#region IBlueRowCollection members
|
||||
public IBlueRow this[int id] {get{return myTable[id];}}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using BCG.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace BCG {
|
||||
@@ -28,12 +26,11 @@ namespace BCG {
|
||||
/// Serves as a quick way to access all rows belonging to the same group
|
||||
/// </summary>
|
||||
private bool myIdGuard = true;
|
||||
RowDictionaryTable? myBookKeepingTable;
|
||||
private RowDictionaryTable myBookKeepingTable;
|
||||
private IGroupByEvaluator myGroupByEvaluator;
|
||||
// input schema, as output schema can differ (IGroupByEvaluator's
|
||||
IBlueTableSchema? mySchema;
|
||||
private IBlueTableSchema mySchema; //input schema, as output schema can differ (IGroupByEvaluator's
|
||||
//can map a schema to another
|
||||
IBlueTableSchema? myOutputSchema;
|
||||
private IBlueTableSchema myOutputSchema;
|
||||
private int myIdGenerator = 0;
|
||||
|
||||
public GroupByStream(ViewStream stream, IEnumerable<string> groupby_cols, Func<IDataPacket, IBlueRow> groupby_func)
|
||||
@@ -49,14 +46,14 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myHandleFirstCall() {
|
||||
requireLastArrivedPacket();
|
||||
mySchema = myLastArrivedPacket.schema;
|
||||
myOutputSchema = myGroupByEvaluator.getOutputSchema(mySchema);
|
||||
myBookKeepingTable = new RowDictionaryTable(myLastArrivedPacket.newRows,
|
||||
myGroupByEvaluator.groupByColumns);
|
||||
GroupByOutputTable temp = new GroupByOutputTable(myOutputSchema);
|
||||
foreach (IBlueRowCollection rowGroup in myBookKeepingTable.getGroups()) {
|
||||
var newRow = myEvaluate(new DataPacket(rowGroup, rowGroup, new BlueTable(mySchema)));
|
||||
IBlueRow newRow = myEvaluate(new DataPacket(rowGroup,
|
||||
rowGroup, new BlueTable(mySchema)));
|
||||
if (newRow != null)
|
||||
temp.addRow(newRow, myGetGroupString(rowGroup));
|
||||
}
|
||||
@@ -82,14 +79,15 @@ namespace BCG {
|
||||
ArrayList handledAddGroups = new ArrayList();
|
||||
string groupRepString;
|
||||
|
||||
requireBookKeeping();
|
||||
foreach (IBlueRowCollection delGroup in delGroups.getGroups()) {
|
||||
// BlueEventLog.logAssert (delGroup.Count > 0);
|
||||
groupRepString = myGetGroupString(delGroup);
|
||||
IBlueRowCollection addGroup = addGroups.getGroup(groupRepString) ?? new BlueTable(mySchema);
|
||||
IBlueRowCollection addGroup = addGroups.getGroup(groupRepString) == null ?
|
||||
new BlueTable(mySchema) : addGroups.getGroup(groupRepString);
|
||||
handledAddGroups.Add(addGroup);
|
||||
IBlueRowCollection aggGroup = myBookKeepingTable.getGroup(groupRepString) ?? new BlueTable(mySchema);
|
||||
var newRow = myEvaluate(new DataPacket(aggGroup, addGroup, delGroup));
|
||||
IBlueRowCollection aggGroup = myBookKeepingTable.getGroup(groupRepString) == null ?
|
||||
new BlueTable(mySchema) : myBookKeepingTable.getGroup(groupRepString);
|
||||
IBlueRow newRow = myEvaluate(new DataPacket(aggGroup, addGroup, delGroup));
|
||||
myFireSwitch |= myMergeRow(newRow, groupRepString);
|
||||
}
|
||||
|
||||
@@ -101,16 +99,16 @@ namespace BCG {
|
||||
//the loop above
|
||||
|
||||
groupRepString = myGetGroupString(addGroup);
|
||||
var aggGroup = ExceptionAssert.NotNull(myBookKeepingTable.getGroup(groupRepString));
|
||||
IBlueRowCollection aggGroup = myBookKeepingTable.getGroup(groupRepString);
|
||||
// BlueEventLog.logAssert (aggGroup != null && aggGroup.Count > 0);
|
||||
var newRow = myEvaluate(new DataPacket(aggGroup, addGroup, new BlueTable(aggGroup.schema)));
|
||||
IBlueRow newRow = myEvaluate(new DataPacket(aggGroup, addGroup,
|
||||
new BlueTable(aggGroup.schema)));
|
||||
myFireSwitch |= myMergeRow(newRow, groupRepString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool myMergeRow(IBlueRow? newRow, string groupRepString) {
|
||||
requireLastFiredPacket();
|
||||
private bool myMergeRow(IBlueRow newRow, string groupRepString) {
|
||||
IBlueRow existingRow = ((GroupByOutputTable)myLastFiredPacket.newRows).getRow(groupRepString);
|
||||
//BlueEventLog.logAssert (newRow != null || existingRow != null);
|
||||
if (existingRow == null && newRow == null)
|
||||
@@ -118,7 +116,6 @@ namespace BCG {
|
||||
else if (existingRow != null && newRow != null && BlueDataUtility.compute_equality(existingRow, newRow))
|
||||
return false;
|
||||
else if (existingRow == null) {
|
||||
ArgumentNullException.ThrowIfNull(newRow);
|
||||
//row added for the first time
|
||||
((GroupByOutputTable)myLastFiredPacket.newRows).addRow(newRow, groupRepString);
|
||||
((BlueTable)myLastFiredPacket.addedRows).addRow(newRow);
|
||||
@@ -141,9 +138,6 @@ namespace BCG {
|
||||
/// <param name="delGroups"></param>
|
||||
/// <param name="addGroups"></param>
|
||||
private void myInitIncrementalChangeData(out RowDictionaryTable delGroups, out RowDictionaryTable addGroups) {
|
||||
ExceptionAssert.NotNull(myBookKeepingTable);
|
||||
requireLastFiredPacket();
|
||||
requireLastArrivedPacket();
|
||||
delGroups =
|
||||
new RowDictionaryTable(myLastArrivedPacket.deletedRows, myGroupByEvaluator.groupByColumns);
|
||||
addGroups =
|
||||
@@ -157,19 +151,16 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myOnTableClear() {
|
||||
if (ExceptionAssert.NotNull(myBookKeepingTable).Count == 0) {
|
||||
// ie there arent any rows, so no need to optimize the 'cleansing' process
|
||||
return;
|
||||
}
|
||||
requireLastFiredPacket();
|
||||
if (myBookKeepingTable.Count == 0)
|
||||
return; //ie there arent any rows, so no need to optimize the 'cleansing' process
|
||||
myLastFiredPacket.deletedRows = new BlueTable(myLastFiredPacket.newRows);
|
||||
myLastFiredPacket.addedRows = new BlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
((GroupByOutputTable)myLastFiredPacket.newRows).clear();
|
||||
(myLastFiredPacket.newRows as GroupByOutputTable).clear();
|
||||
myBookKeepingTable.clear();
|
||||
myGroupByEvaluator.clear();
|
||||
}
|
||||
|
||||
private IBlueRow? myEvaluate(DataPacket dp) {
|
||||
private IBlueRow myEvaluate(DataPacket dp) {
|
||||
IBlueRow evalRow = myGroupByEvaluator.evaluate(dp);
|
||||
return evalRow == null ? null :
|
||||
myIdGuard ?
|
||||
@@ -201,7 +192,7 @@ namespace BCG {
|
||||
return BlueDataUtility.rowToString(getRepRow(dp), colNames);
|
||||
}
|
||||
|
||||
public static IBlueRow? getRepRow(IDataPacket dp) {
|
||||
public static IBlueRow getRepRow(IDataPacket dp) {
|
||||
if (dp.newRows.Count > 0)
|
||||
return BlueDataUtility.extractRow(dp.newRows, 0);
|
||||
else if (dp.addedRows.Count > 0)
|
||||
@@ -220,13 +211,13 @@ namespace BCG {
|
||||
/// <param name="newValue"></param>
|
||||
/// <param name="isAdd"></param>
|
||||
/// <returns></returns>
|
||||
public static object? incrementalAdd(object lastValue, object newValue, bool isAdd) {
|
||||
public static object incrementalAdd(object lastValue, object newValue, bool isAdd) {
|
||||
if (lastValue == null || lastValue.Equals(DBNull.Value))
|
||||
return newValue;
|
||||
// BlueEventLog.logAssert (lastValue.GetType().Equals (typeof(Int32)) && newValue.GetType().Equals (typeof(Int32)) ||
|
||||
// lastValue.GetType().Equals (typeof(Double)) && newValue.GetType().Equals (typeof(Double)) ||
|
||||
// lastValue.GetType().Equals (typeof(Decimal)) && newValue.GetType().Equals (typeof(Decimal)));
|
||||
object? retVal = null;
|
||||
Object retVal = null;
|
||||
if (newValue.GetType().Equals(typeof(int)))
|
||||
retVal = isAdd ? (int)lastValue + (int)newValue : (int)lastValue - (int)newValue;
|
||||
else if (newValue.GetType().Equals(typeof(Double)))
|
||||
@@ -238,9 +229,6 @@ namespace BCG {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(myBookKeepingTable))]
|
||||
void requireBookKeeping() =>
|
||||
ExceptionAssert.NotNull(myBookKeepingTable);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using BCG.Utilities;
|
||||
|
||||
namespace BCG {
|
||||
/// <summary>
|
||||
/// Computes the max for a given column
|
||||
@@ -12,10 +17,10 @@ namespace BCG {
|
||||
public override IBlueRow? evaluate(IDataPacket dp) {
|
||||
myOutputTable ??= new GroupByOutputTable(dp.Schema);
|
||||
string hashString = BlueDataUtility.rowToString(GroupByStream.getRepRow(dp), myGroupByCols);
|
||||
var currMaxRow = myOutputTable.getRow(hashString);
|
||||
IBlueRow currMaxRow = myOutputTable.getRow(hashString);
|
||||
IBlueRow maxRow = BlueDataUtility.computeMaxRow(dp.deletedRows, myOutputColumn);
|
||||
if (maxRow != null) {
|
||||
bts.Log.notnull(currMaxRow);
|
||||
bts.Log.assert(currMaxRow != null);
|
||||
bts.Log.assert(BlueDataUtility.compare_rows(maxRow, currMaxRow, myOutputColumn) <= 0);
|
||||
if (BlueDataUtility.compare_rows(maxRow, currMaxRow, myOutputColumn) == 0) {
|
||||
maxRow = BlueDataUtility.computeMaxRow(dp.newRows, myOutputColumn);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using BCG.Utilities;
|
||||
using System.IO;
|
||||
|
||||
namespace BCG
|
||||
{
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
/// <summary>
|
||||
/// Some basic event handling functionality factorred out of any Stream whose behaviour
|
||||
/// is driven by some interface passed on by the user
|
||||
@@ -11,8 +12,8 @@ namespace BCG
|
||||
public abstract class MethodDrivenStream : ViewStream
|
||||
{
|
||||
protected ViewStream myStream;
|
||||
protected DataPacket? myLastArrivedPacket;
|
||||
protected DataPacket? myLastFiredPacket;
|
||||
protected DataPacket myLastArrivedPacket;
|
||||
protected DataPacket myLastFiredPacket;
|
||||
protected bool myFireSwitch = true;
|
||||
|
||||
public MethodDrivenStream(ViewStream vs) {myStream = vs;}
|
||||
@@ -58,7 +59,6 @@ namespace BCG
|
||||
/// To handle the first call, the LastFiredPacket is supposed to be initialized and filled
|
||||
/// with data.
|
||||
/// </summary>
|
||||
[MemberNotNull(nameof(myLastFiredPacket))]
|
||||
protected abstract void myHandleFirstCall ();
|
||||
|
||||
/// <summary>
|
||||
@@ -89,13 +89,5 @@ namespace BCG
|
||||
{
|
||||
myStream.onChange -= new DataStream.ChangeDelegate (myChangeHandler);
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(myLastArrivedPacket))]
|
||||
protected void requireLastArrivedPacket() =>
|
||||
ExceptionAssert.NotNull(myLastArrivedPacket);
|
||||
|
||||
[MemberNotNull(nameof(myLastFiredPacket))]
|
||||
protected void requireLastFiredPacket() =>
|
||||
ExceptionAssert.NotNull(myLastFiredPacket);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace BCG {
|
||||
public override IBlueRow? evaluate(IDataPacket dp) {
|
||||
myOutputTable ??= new GroupByOutputTable(dp.Schema);
|
||||
string stringRep = BlueDataUtility.rowToString(GroupByStream.getRepRow(dp), myGroupByCols);
|
||||
var currMinRow = myOutputTable.getRow(stringRep);
|
||||
IBlueRow currMinRow = myOutputTable.getRow(stringRep);
|
||||
IBlueRow minRow = BlueDataUtility.computeMinRow(dp.deletedRows, myOutputColumn);
|
||||
if (minRow != null) {
|
||||
// BlueEventLog.logAssert (currMinRow != null);
|
||||
|
||||
@@ -45,13 +45,12 @@ namespace BCG {
|
||||
}
|
||||
|
||||
public SumStream(ViewStream stream, string[] output_columns, string[] groupby_columns, bool force_null_into_other_columns) {
|
||||
ViewStream? rs = null;
|
||||
ViewStream rs = null;
|
||||
groupby_columns = groupby_columns ?? new string[] { };
|
||||
if (groupby_columns.Length == 0) {
|
||||
// rs = new AddColumnsStream(stream, "fake_col=0");
|
||||
// rs = new GroupByStream(rs, new MultiColumnSumGroupByEvaluator(output_columns, new string[] { "fake_col" }));
|
||||
// rs = new ProjectStream(rs, "!fake_col");
|
||||
throw new ArgumentException("No groupby columns specified", nameof(groupby_columns));
|
||||
} else {
|
||||
rs = new GroupByStream(stream, new MultiColumnSumGroupByEvaluator(output_columns, groupby_columns));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using mbts;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -37,7 +35,7 @@ namespace BCG {
|
||||
List<NonIncJoinSpec> rv = new List<NonIncJoinSpec>();
|
||||
foreach (Triplet<ViewStream, string, string> r in join_specs) {
|
||||
string[] keys = String.IsNullOrEmpty(r.second) ? new string[] { } : r.second.Split(' ');
|
||||
string[] visible_cols = ExceptionAssert.NotNull(r.third).Split(' ');
|
||||
string[] visible_cols = r.third.Split(' ');
|
||||
List<string> data_col_names = new List<string>(), mapped_col_names = new List<string>();
|
||||
foreach (string s in visible_cols) {
|
||||
string[] toks = s.Split(':');
|
||||
@@ -49,7 +47,7 @@ namespace BCG {
|
||||
mapped_col_names.Add(toks[1]);
|
||||
}
|
||||
}
|
||||
rv.Add(new(ExceptionAssert.NotNull(r.first), keys, data_col_names.ToArray(), mapped_col_names.ToArray()));
|
||||
rv.Add(new NonIncJoinSpec(r.first, keys, data_col_names.ToArray(), mapped_col_names.ToArray()));
|
||||
}
|
||||
return rv.ToArray();
|
||||
}
|
||||
|
||||
@@ -290,7 +290,6 @@ namespace BCG
|
||||
}
|
||||
}
|
||||
}
|
||||
ExceptionAssert.NotNull(myState);
|
||||
}
|
||||
|
||||
private void myAddRows(IBlueRowCollection addedRows, bool isLeft, BlueTable state, BlueTable addedRowsOut)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
|
||||
namespace BCG
|
||||
@@ -20,21 +18,16 @@ namespace BCG
|
||||
|
||||
public override void onTableClear (bool isLeft)
|
||||
{
|
||||
requireSchema();
|
||||
requireLastFiredPacket();
|
||||
myLastFiredPacket.deletedRows = myLastFiredPacket.newRows;
|
||||
myLastFiredPacket.newRows = new JoinForeignTable (mySchema);
|
||||
myLastFiredPacket.addedRows = new BlueTable (mySchema);
|
||||
if (!isLeft) {
|
||||
ExceptionAssert.NotNull(myLeftDataPacket);
|
||||
if (!isLeft)
|
||||
foreach (IBlueRow row in myLeftDataPacket.newRows)
|
||||
((JoinTable)myLastFiredPacket.newRows).addRow (row, null, myLastFiredPacket);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void myInitFiredPacket ()
|
||||
{
|
||||
requireSchema();
|
||||
myLastFiredPacket = new DataPacket ();
|
||||
myLastFiredPacket.newRows = new JoinForeignTable (mySchema);
|
||||
myLastFiredPacket.addedRows = new BlueTable (mySchema);
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace BCG
|
||||
: this (r, null, null)
|
||||
{}
|
||||
|
||||
public SimpleNode(IBlueRow? r, SimpleNode? nx, SimpleNode? pv) {
|
||||
public SimpleNode(IBlueRow r, SimpleNode? nx, SimpleNode? pv) {
|
||||
row = r;
|
||||
next = nx;
|
||||
prev = pv;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using bts;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -62,7 +60,7 @@ namespace BCG {
|
||||
if (columnAndType.Length == 1)
|
||||
ci[n] = new ColumnInfo(c, n, typeof(double));
|
||||
else
|
||||
ci[n] = new(columnAndType[0], n, ExceptionAssert.NotNull(Type.GetType("System." + columnAndType[1], true)));
|
||||
ci[n] = new ColumnInfo(columnAndType[0], n, Type.GetType("System." + columnAndType[1], true));
|
||||
n++;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace bts {
|
||||
BlueDataUtility.group_together(dp.newRows, new string[] { _group_by_col })
|
||||
:
|
||||
new Dictionary<int, List<IBlueRow>>() { { 0, dp.newRows.to_list() } };
|
||||
BlueTable? out_table = null;
|
||||
BlueTable out_table = null;
|
||||
foreach (var kv in groups) {
|
||||
List<IBlueRow> group_rows = kv.Value;
|
||||
group_rows.Sort((r1, r2) => BlueDataUtility.compare_rows(r2, r1, _sort_col_name));
|
||||
@@ -73,4 +73,4 @@ namespace bts {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,6 @@ namespace BCG
|
||||
/// fires an event when the mapper
|
||||
/// changes itself
|
||||
/// </summary>
|
||||
event MapperChangeDelegate? onMapperChange;
|
||||
event MapperChangeDelegate onMapperChange;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,6 @@ namespace BCG {
|
||||
|
||||
protected override void myHandleFirstCall() {
|
||||
ArgumentNullException.ThrowIfNull(myMapper);
|
||||
requireLastArrivedPacket();
|
||||
IBlueTableSchema outputSchema = myMapper.getOutputSchema(myLastArrivedPacket.newRows.schema);
|
||||
myLastFiredPacket = new DataPacket();
|
||||
myLastFiredPacket.newRows = new BlueTable(outputSchema);
|
||||
@@ -86,12 +85,10 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myHandleIncrementalAdd() {
|
||||
requireLastArrivedPacket();
|
||||
if (myLastArrivedPacket.addedRows.Count == 0) {
|
||||
Log.Gen.warn("MapStream.myHandleIncrementalAdd called with 0 addedRows");
|
||||
return;
|
||||
}
|
||||
requireLastFiredPacket();
|
||||
ArgumentNullException.ThrowIfNull(myMapper);
|
||||
var addedRows = new BlueTable(myLastFiredPacket.newRows.schema);
|
||||
var newRows = ExceptionAssert.Cast(myLastFiredPacket.newRows).To<BlueTable>();
|
||||
@@ -104,12 +101,10 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myHandleIncrementalDelete() {
|
||||
requireLastArrivedPacket();
|
||||
if (myLastArrivedPacket.deletedRows.Count == 0) {
|
||||
Log.Gen.warn("MapStream.myHandleIncrementalDelete called with 0 deletedRows");
|
||||
return;
|
||||
}
|
||||
requireLastFiredPacket();
|
||||
var deletedRows = new BlueTable(myLastFiredPacket.newRows.schema);
|
||||
var newRows = ExceptionAssert.Cast(myLastFiredPacket.newRows).To<BlueTable>();
|
||||
foreach (IBlueRow row in myLastArrivedPacket.deletedRows) {
|
||||
@@ -132,7 +127,6 @@ namespace BCG {
|
||||
}
|
||||
|
||||
protected override void myOnTableClear() {
|
||||
requireLastFiredPacket();
|
||||
myLastFiredPacket.deletedRows = myLastFiredPacket.newRows;
|
||||
myLastFiredPacket.newRows = new BlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
myLastFiredPacket.addedRows = new BlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
|
||||
@@ -47,14 +47,14 @@ namespace BCG {
|
||||
_map_rows = map_rows;
|
||||
}
|
||||
|
||||
event MapperChangeDelegate? ISuperStreamMapper.onMapperChange { add { } remove { } }
|
||||
|
||||
public IBlueTableSchema getOutputSchema(IBlueTableSchema schema) { return _get_schema(schema); }
|
||||
|
||||
public IBlueRow[] map(IBlueRow r) {
|
||||
IEnumerable<IBlueRow> rows = _map_rows(r);
|
||||
return rows == null ? new IBlueRow[] { } : new List<IBlueRow>(rows).ToArray();
|
||||
}
|
||||
|
||||
public event MapperChangeDelegate? onMapperChange;
|
||||
}
|
||||
|
||||
//maps the id of the underlying stream to the
|
||||
|
||||
@@ -608,8 +608,8 @@ namespace BCG {
|
||||
// 5. deserialize the state into a stream op
|
||||
str_io_msg_p = deser.deserialize(content_p);
|
||||
// 6. check to make sure the state's rows are good
|
||||
passes &= str_io_msg_p.op == StreamIOMessage.StreamOp.CREATE
|
||||
&& BlueDataUtility.compute_equality(cr_rows, ExceptionAssert.NotNull(str_io_msg_p.create_message).rows);
|
||||
passes = passes && str_io_msg_p.op == bts.StreamIOMessage.StreamOp.CREATE &&
|
||||
BlueDataUtility.compute_equality(cr_rows, str_io_msg_p.create_message.rows);
|
||||
return new TestResult {
|
||||
test_result = passes,
|
||||
test_name = "run_pubsub_server_stream_tag_handler_test"
|
||||
@@ -692,7 +692,7 @@ namespace BCG {
|
||||
var content = st_data.get_current_content();
|
||||
var msg_p = deser.deserialize(content);
|
||||
Log.assert(msg_p.op == bts.StreamIOMessage.StreamOp.CREATE);
|
||||
return ExceptionAssert.NotNull(msg_p.create_message).rows;
|
||||
return msg_p.create_message.rows;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using Bts.ColumnSortExpressions;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@@ -41,7 +39,7 @@ public class SortRow : IComparable, IBlueRow {
|
||||
var otherVal = otherRow[col.Name];
|
||||
int rv = myIsNull(this[col.Name]) ?
|
||||
(myIsNull(otherVal) ? 0 : -1) :
|
||||
(myIsNull(otherVal) ? 1 : ExceptionAssert.Argument.Is<IComparable>(this[col.Name]).CompareTo(otherVal));
|
||||
(myIsNull(otherVal) ? 1 : ((IComparable)this[col.Name]).CompareTo(otherVal));
|
||||
rv *= col.IsAscending ? 1 : -1;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@@ -62,13 +60,13 @@ namespace BCG
|
||||
List<string> columnInfoStrParts = new List<string>(columnInfoStr.Split(new char[] { ':' }, StringSplitOptions.None));
|
||||
if (columnInfoStrParts.Count != 2)
|
||||
{
|
||||
throw new Exception($"Unable to decode schema string '{schemaStr}'");
|
||||
throw (new Exception(String.Format("Unable to decode schema string '{0}'", schemaStr)));
|
||||
}
|
||||
|
||||
columnInfos.Add(new ColumnInfo(columnInfoStrParts[0], i, ExceptionAssert.NotNull(Type.GetType(columnInfoStrParts[1]))));
|
||||
columnInfos.Add(new ColumnInfo(columnInfoStrParts[0], i, Type.GetType(columnInfoStrParts[1])));
|
||||
}
|
||||
|
||||
return new BlueTableSchema(columnInfos.ToArray(), string.Empty);
|
||||
return (new BlueTableSchema(columnInfos.ToArray(), ""));
|
||||
}
|
||||
|
||||
private IBlueRow myGetRow(IBlueTableSchema schema, string rowStr)
|
||||
@@ -77,7 +75,7 @@ namespace BCG
|
||||
|
||||
if (schema.columnInfo.Length != valueStrs.Count)
|
||||
{
|
||||
throw new Exception($"Unable to decode row string '{rowStr}'");
|
||||
throw (new Exception(String.Format("Unable to decode row string '{0}'", rowStr)));
|
||||
}
|
||||
|
||||
List<object> values = new List<object>();
|
||||
@@ -86,7 +84,7 @@ namespace BCG
|
||||
values.Add(Convert.ChangeType(valueStrs[i], schema.columnInfo[i].colType));
|
||||
}
|
||||
|
||||
return new BlueRow(schema, values.ToArray());
|
||||
return (new BlueRow(schema, values.ToArray()));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using BCG.Utilities.General;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace BCG
|
||||
@@ -98,7 +97,7 @@ namespace BCG
|
||||
// BlueEventLog2.instance().assert(Thread.CurrentThread.ManagedThreadId == _target_thread,
|
||||
// "onTargetDoWork should only be called from target thread");
|
||||
var updates = _queued_updates.dequeueAll();
|
||||
foreach (var u in updates.ExceptNull()) {
|
||||
foreach (var u in updates) {
|
||||
if (u.subscription == _current_target_subscription)
|
||||
myFireEvent(u.dp);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using BCG.Utilities.General;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
using System;
|
||||
|
||||
using BCG.Utilities.General;
|
||||
|
||||
namespace BCG {
|
||||
public abstract class TimeUnitStream : ViewStream, IWorker {
|
||||
protected TimeSpan myOffset;
|
||||
@@ -48,8 +46,8 @@ namespace BCG {
|
||||
myRoundTime(myZeroTime + new TimeSpan(myOffset.Ticks * periods));
|
||||
|
||||
|
||||
var latestRow = myGetLatestRow();
|
||||
if (latestRow is null || !ExceptionAssert.Argument.Is<DateTime>(latestRow["time"]).Equals(dt)) {
|
||||
if (myGetLatestRow() == null ||
|
||||
!myGetLatestRow()["time"].Equals(dt)) {
|
||||
IBlueRow ar = new BlueRow(myCollection.schema,
|
||||
myId++, dt);
|
||||
IBlueRow dr = myCollection.addRowWithReturn(ar);
|
||||
@@ -73,10 +71,11 @@ namespace BCG {
|
||||
|
||||
#region Private Helper methods
|
||||
|
||||
IBlueRow? myGetLatestRow() =>
|
||||
myCollection.Count == 0
|
||||
? null
|
||||
: BlueDataUtility.extractRow(myCollection, myCollection.Count - 1);
|
||||
private IBlueRow myGetLatestRow() {
|
||||
return myCollection.Count == 0 ?
|
||||
null :
|
||||
BlueDataUtility.extractRow(myCollection, myCollection.Count - 1);
|
||||
}
|
||||
|
||||
private IBlueRowCollection myConvertToCollection(IBlueRow r) {
|
||||
BlueTable retVal = new BlueTable(myCollection.schema);
|
||||
|
||||
@@ -1,42 +1,43 @@
|
||||
namespace BCG;
|
||||
using System;
|
||||
|
||||
public class TopStream : MethodDrivenStream {
|
||||
int myTopCount;
|
||||
namespace BCG {
|
||||
public class TopStream : MethodDrivenStream {
|
||||
private int myTopCount;
|
||||
|
||||
public TopStream(ViewStream stream, int topCount)
|
||||
: base(stream) =>
|
||||
myTopCount = topCount;
|
||||
public TopStream(ViewStream stream, int topCount) : base(stream) { myTopCount = topCount; }
|
||||
|
||||
public TopStream(ViewStream stream, int topCount, string sortExpression)
|
||||
: this(sortExpression is null ? stream : new SortStream(stream, sortExpression), topCount) { }
|
||||
public TopStream(ViewStream stream,
|
||||
int topCount,
|
||||
string sortExpression)
|
||||
:
|
||||
this(sortExpression == null ?
|
||||
stream :
|
||||
new SortStream(stream, sortExpression), topCount) { }
|
||||
|
||||
protected override void myOnTableClear() {
|
||||
requireLastFiredPacket();
|
||||
myLastFiredPacket.deletedRows = myLastFiredPacket.newRows;
|
||||
myLastFiredPacket.newRows = new OrderedBlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
myLastFiredPacket.addedRows = new OrderedBlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
}
|
||||
protected override void myOnTableClear() {
|
||||
myLastFiredPacket.deletedRows = myLastFiredPacket.newRows;
|
||||
myLastFiredPacket.newRows = new OrderedBlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
myLastFiredPacket.addedRows = new OrderedBlueTable(myLastFiredPacket.deletedRows.schema);
|
||||
}
|
||||
|
||||
protected override void myHandleFirstCall() {
|
||||
requireLastArrivedPacket();
|
||||
myLastFiredPacket = new DataPacket();
|
||||
myLastFiredPacket.newRows = new OrderedBlueTable(myLastArrivedPacket.newRows, myTopCount);
|
||||
myLastFiredPacket.addedRows = new OrderedBlueTable(myLastFiredPacket.newRows);
|
||||
myLastFiredPacket.deletedRows = new OrderedBlueTable(myLastFiredPacket.newRows.schema);
|
||||
}
|
||||
protected override void myHandleFirstCall() {
|
||||
myLastFiredPacket = new DataPacket();
|
||||
myLastFiredPacket.newRows = new OrderedBlueTable(myLastArrivedPacket.newRows, myTopCount);
|
||||
myLastFiredPacket.addedRows = new OrderedBlueTable(myLastFiredPacket.newRows);
|
||||
myLastFiredPacket.deletedRows = new OrderedBlueTable(myLastFiredPacket.newRows.schema);
|
||||
}
|
||||
|
||||
protected override void myHandleIncrementalAdd() { }
|
||||
protected override void myHandleIncrementalAdd() { }
|
||||
|
||||
protected override void myHandleIncrementalDelete() {
|
||||
requireLastArrivedPacket();
|
||||
requireLastFiredPacket();
|
||||
IBlueRowCollection oldRows = myLastFiredPacket.newRows;
|
||||
myLastFiredPacket.newRows = new OrderedBlueTable(myLastArrivedPacket.newRows, myTopCount);
|
||||
BlueDataUtility.computeDifferences(myLastFiredPacket.newRows,
|
||||
oldRows,
|
||||
myLastFiredPacket.schema.columnNames,
|
||||
out myLastFiredPacket.deletedRows,
|
||||
out myLastFiredPacket.addedRows);
|
||||
myFireSwitch = myLastFiredPacket.addedRows.Count + myLastFiredPacket.deletedRows.Count == 0 ? false : true;
|
||||
}
|
||||
protected override void myHandleIncrementalDelete() {
|
||||
IBlueRowCollection oldRows = myLastFiredPacket.newRows;
|
||||
myLastFiredPacket.newRows = new OrderedBlueTable(myLastArrivedPacket.newRows, myTopCount);
|
||||
BlueDataUtility.computeDifferences(myLastFiredPacket.newRows,
|
||||
oldRows,
|
||||
myLastFiredPacket.schema.columnNames,
|
||||
out myLastFiredPacket.deletedRows,
|
||||
out myLastFiredPacket.addedRows);
|
||||
myFireSwitch = myLastFiredPacket.addedRows.Count + myLastFiredPacket.deletedRows.Count == 0 ? false : true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace BCG {
|
||||
|
||||
public class AlphabetizeColumnsStream : ViewStream {
|
||||
private ViewStream mySrc;
|
||||
IBlueTableSchema? mySchema = null;
|
||||
private IBlueTableSchema mySchema = null;
|
||||
|
||||
public AlphabetizeColumnsStream(ViewStream src) {
|
||||
mySrc = src;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace BCG
|
||||
{
|
||||
public class AppendStreamModified : ViewStream
|
||||
{
|
||||
private AppendCollection myColl = new AppendCollection ();
|
||||
ViewStream? myLeftStream, myRightstream;
|
||||
|
||||
private ViewStream myLeftStream, myRightstream;
|
||||
|
||||
public AppendStreamModified (ViewStream leftStream, ViewStream rightStream)
|
||||
{
|
||||
myLeftStream = leftStream;
|
||||
@@ -15,24 +15,11 @@ namespace BCG
|
||||
|
||||
public AppendStreamModified (ViewStream[] vss)
|
||||
{
|
||||
switch (vss.Length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
mySetRealSource (vss[0]);
|
||||
break;
|
||||
default:
|
||||
mySetRealSource(
|
||||
vss[1..].Aggregate(
|
||||
new AppendStreamModified(new[] { vss[0] }),
|
||||
(asm, vs) => new AppendStreamModified(asm, vs)));
|
||||
break;
|
||||
}
|
||||
if (vss.Length == 1)
|
||||
mySetRealSource (vss[0]);
|
||||
else
|
||||
{
|
||||
AppendStreamModified? rv = null;
|
||||
AppendStreamModified rv = null;
|
||||
foreach (ViewStream s in vss)
|
||||
rv = rv == null ? new AppendStreamModified (new ViewStream[] {s}) : new AppendStreamModified (rv, s);
|
||||
mySetRealSource (rv);
|
||||
|
||||
@@ -8,11 +8,11 @@ using Bts.DataStreamCore;
|
||||
using Bts.DataStreamExpressions;
|
||||
using Bts.PubSub;
|
||||
|
||||
using global::Spark.Core.Disposables;
|
||||
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Spark.Core.Disposables;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -8,6 +8,7 @@ using Bts.PubSub.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
using Spark.Api.MarketData;
|
||||
using Spark.Api.Services;
|
||||
using Spark.Core.Services;
|
||||
|
||||
|
||||
@@ -43,14 +43,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Net", "..\cs\Bts.Net\Bt
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.IO.Compression", "..\cs\Bts.IO.Compression\Bts.IO.Compression.csproj", "{3BF059B0-51C0-44A8-8297-9B7464DC5BA3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Collections", "..\cs\Bts.Collections\Bts.Collections.csproj", "{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Core", "..\cs\Bts.Core\Bts.Core.csproj", "{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Disposables", "..\cs\Bts.Disposables\Bts.Disposables.csproj", "{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bts.Numerics", "..\cs\Bts.Numerics\Bts.Numerics.csproj", "{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -301,54 +293,6 @@ Global
|
||||
{3BF059B0-51C0-44A8-8297-9B7464DC5BA3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3BF059B0-51C0-44A8-8297-9B7464DC5BA3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3BF059B0-51C0-44A8-8297-9B7464DC5BA3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ADBEBCB3-5367-431B-AFC8-F57CAF9F029D}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4E3D817D-9A0A-40F4-A1A1-4865375F40DD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ED034E82-07F4-473D-9C3A-F5EF9C961CFD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9A3E289A-3A88-4A76-AD0B-32C12EBA1B8B}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
// namespace Bts.DataStreamTests;
|
||||
|
||||
// using BCG;
|
||||
|
||||
// using BlueOrb.Operators.Core;
|
||||
|
||||
// [TestFixture]
|
||||
// public class BarBuilderStreamTests {
|
||||
// static readonly DateTime T0 = new(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
// [Test]
|
||||
// public void TimeBars_FromTrades_AcrossBoundary() {
|
||||
// var schema = TradeSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "TIME", 60, "trade_price", "trade_size");
|
||||
// var rows = CaptureAddedRows(bars);
|
||||
|
||||
// var sent = new List<IBlueRow>();
|
||||
// sent.Add(TradeRow(schema, 1, T0.AddSeconds(10), "BTCUSD", 100, 2));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 2, T0.AddSeconds(20), "BTCUSD", 101, 3));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 3, T0.AddMinutes(1).AddSeconds(5), "BTCUSD", 99, 1));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 4, T0.AddMinutes(2), "BTCUSD", 102, 1));
|
||||
// driver.Reset(sent);
|
||||
|
||||
// Assert.That(rows.Count, Is.EqualTo(2));
|
||||
// AssertBar(rows[0], 100, 101, 100, 101, 5, 2, 100.6, false);
|
||||
// AssertBar(rows[1], 99, 99, 99, 99, 1, 1, 99, false);
|
||||
// }
|
||||
|
||||
// [Test]
|
||||
// public void TimeBars_FromBboMid_VolumeIsZero() {
|
||||
// var schema = BboSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "TIME", 60, "mid", "none");
|
||||
// var rows = CaptureAddedRows(bars);
|
||||
|
||||
// var sent = new List<IBlueRow>();
|
||||
// sent.Add(BboRow(schema, 1, T0.AddSeconds(0), "ETHUSD", 99, 101));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(BboRow(schema, 2, T0.AddSeconds(30), "ETHUSD", 101, 103));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(BboRow(schema, 3, T0.AddMinutes(1).AddSeconds(1), "ETHUSD", 100, 104));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(BboRow(schema, 4, T0.AddMinutes(2), "ETHUSD", 100, 102));
|
||||
// driver.Reset(sent);
|
||||
|
||||
// Assert.That(rows.Count, Is.EqualTo(2));
|
||||
// AssertBar(rows[0], 100, 102, 100, 102, 0, 2, 102, false);
|
||||
// AssertBar(rows[1], 102, 102, 102, 102, 0, 1, 102, false);
|
||||
// }
|
||||
|
||||
// [Test]
|
||||
// public void TickBars_CloseExactlyOnNEvents() {
|
||||
// var schema = TradeSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "TICK", 3, "trade_price", "trade_size");
|
||||
// var rows = CaptureAddedRows(bars);
|
||||
|
||||
// var sent = new List<IBlueRow>();
|
||||
// sent.Add(TradeRow(schema, 1, T0, "NQ", 10, 1));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 2, T0.AddSeconds(1), "NQ", 11, 1));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 3, T0.AddSeconds(2), "NQ", 9, 1));
|
||||
// driver.Reset(sent);
|
||||
|
||||
// Assert.That(rows.Count, Is.EqualTo(1));
|
||||
// AssertBar(rows[0], 10, 11, 9, 9, 3, 3, 10, false);
|
||||
// }
|
||||
|
||||
// [Test]
|
||||
// public void VolumeBars_CloseOnThreshold() {
|
||||
// var schema = TradeSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "VOLUME", 10, "trade_price", "trade_size");
|
||||
// var rows = CaptureAddedRows(bars);
|
||||
|
||||
// var sent = new List<IBlueRow>();
|
||||
// sent.Add(TradeRow(schema, 1, T0, "ES", 100, 3));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 2, T0.AddSeconds(1), "ES", 120, 4));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 3, T0.AddSeconds(2), "ES", 110, 5));
|
||||
// driver.Reset(sent);
|
||||
|
||||
// Assert.That(rows.Count, Is.EqualTo(1));
|
||||
// AssertBar(rows[0], 100, 120, 100, 110, 12, 3, (100 * 3 + 120 * 4 + 110 * 5) / 12.0, false);
|
||||
// }
|
||||
|
||||
// [Test]
|
||||
// public void DollarBars_CloseOnThreshold() {
|
||||
// var schema = TradeSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "DOLLAR", 1000, "trade_price", "trade_size");
|
||||
// var rows = CaptureAddedRows(bars);
|
||||
|
||||
// var sent = new List<IBlueRow>();
|
||||
// sent.Add(TradeRow(schema, 1, T0, "CL", 100, 3));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 2, T0.AddSeconds(1), "CL", 120, 4));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 3, T0.AddSeconds(2), "CL", 110, 3));
|
||||
// driver.Reset(sent);
|
||||
|
||||
// Assert.That(rows.Count, Is.EqualTo(1));
|
||||
// AssertBar(rows[0], 100, 120, 100, 110, 10, 3, 111, false);
|
||||
// }
|
||||
|
||||
// [Test]
|
||||
// public void Validation_VolumeOnBboOnly_Throws() {
|
||||
// var schema = BboSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "VOLUME", 10, "mid", "trade_size");
|
||||
|
||||
// var row = BboRow(schema, 1, T0, "BTCUSD", 99, 101);
|
||||
// Assert.Throws<ArgumentException>(() => {
|
||||
// using var _ = SubscribeNoOp(bars);
|
||||
// driver.Reset(row);
|
||||
// });
|
||||
// }
|
||||
|
||||
// [Test]
|
||||
// public void EmitForming_EmitsFormingAndFinal() {
|
||||
// var schema = TradeSchema();
|
||||
// var driver = new TestDriverStream(schema);
|
||||
// var bars = new BarBuilderStream(driver, "TICK", 2, "trade_price", "trade_size", emit_forming: true);
|
||||
// var rows = CaptureAddedRows(bars);
|
||||
|
||||
// var sent = new List<IBlueRow>();
|
||||
// sent.Add(TradeRow(schema, 1, T0, "MNQ", 10, 1));
|
||||
// driver.Reset(sent);
|
||||
// sent.Add(TradeRow(schema, 2, T0.AddSeconds(1), "MNQ", 12, 1));
|
||||
// driver.Reset(sent);
|
||||
|
||||
// Assert.That(rows.Count, Is.EqualTo(3));
|
||||
// Assert.That(rows[0].get<bool>("is_forming"), Is.True);
|
||||
// Assert.That(rows[1].get<bool>("is_forming"), Is.True);
|
||||
// Assert.That(rows[2].get<bool>("is_forming"), Is.False);
|
||||
// AssertBar(rows[2], 10, 12, 10, 12, 2, 2, 11, false);
|
||||
// }
|
||||
|
||||
// static IDisposable SubscribeNoOp(ViewStream stream) {
|
||||
// DataStream.ChangeDelegate d = _ => { };
|
||||
// stream.onChange += d;
|
||||
// return new Subscription(() => stream.onChange -= d);
|
||||
// }
|
||||
|
||||
// static List<IBlueRow> CaptureAddedRows(ViewStream stream) {
|
||||
// var rows = new List<IBlueRow>();
|
||||
// stream.onChange += o => {
|
||||
// var dp = (IDataPacket)o;
|
||||
// foreach (IBlueRow r in dp.addedRows) {
|
||||
// rows.Add(new BlueRow(r));
|
||||
// }
|
||||
// };
|
||||
// return rows;
|
||||
// }
|
||||
|
||||
// static BlueTableSchema TradeSchema() =>
|
||||
// new(
|
||||
// new[] {
|
||||
// new ColumnInfo("id", 0, typeof(int)),
|
||||
// new ColumnInfo("ts_event", 1, typeof(string)),
|
||||
// new ColumnInfo("contract", 2, typeof(string)),
|
||||
// new ColumnInfo("trade_price", 3, typeof(double)),
|
||||
// new ColumnInfo("trade_size", 4, typeof(double)),
|
||||
// },
|
||||
// "trade_events"
|
||||
// );
|
||||
|
||||
// static BlueTableSchema BboSchema() =>
|
||||
// new(
|
||||
// new[] {
|
||||
// new ColumnInfo("id", 0, typeof(int)),
|
||||
// new ColumnInfo("ts_event", 1, typeof(string)),
|
||||
// new ColumnInfo("contract", 2, typeof(string)),
|
||||
// new ColumnInfo("bid_price", 3, typeof(double)),
|
||||
// new ColumnInfo("ask_price", 4, typeof(double)),
|
||||
// },
|
||||
// "bbo_events"
|
||||
// );
|
||||
|
||||
// static IBlueRow TradeRow(IBlueTableSchema schema, int id, DateTime ts, string contract, double px, double sz) =>
|
||||
// new BlueRow(schema, id, ts.ToString("O"), contract, px, sz);
|
||||
|
||||
// static IBlueRow BboRow(IBlueTableSchema schema, int id, DateTime ts, string contract, double bid, double ask) =>
|
||||
// new BlueRow(schema, id, ts.ToString("O"), contract, bid, ask);
|
||||
|
||||
// static void AssertBar(
|
||||
// IBlueRow r,
|
||||
// double open,
|
||||
// double high,
|
||||
// double low,
|
||||
// double close,
|
||||
// double volume,
|
||||
// int tradeCount,
|
||||
// double vwap,
|
||||
// bool isForming
|
||||
// ) {
|
||||
// Assert.That(r.get<double>("open"), Is.EqualTo(open).Within(1e-9));
|
||||
// Assert.That(r.get<double>("high"), Is.EqualTo(high).Within(1e-9));
|
||||
// Assert.That(r.get<double>("low"), Is.EqualTo(low).Within(1e-9));
|
||||
// Assert.That(r.get<double>("close"), Is.EqualTo(close).Within(1e-9));
|
||||
// Assert.That(r.get<double>("volume"), Is.EqualTo(volume).Within(1e-9));
|
||||
// Assert.That(r.get<int>("trade_count"), Is.EqualTo(tradeCount));
|
||||
// Assert.That(r.get<double>("vwap"), Is.EqualTo(vwap).Within(1e-9));
|
||||
// Assert.That(r.get<bool>("is_forming"), Is.EqualTo(isForming));
|
||||
// }
|
||||
|
||||
// sealed class Subscription : IDisposable {
|
||||
// readonly Action _dispose;
|
||||
// public Subscription(Action dispose) => _dispose = dispose;
|
||||
// public void Dispose() => _dispose();
|
||||
// }
|
||||
// }
|
||||
@@ -5,7 +5,7 @@ using BCG.Utilities.General;
|
||||
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Core.Collections;
|
||||
using global::Spark.Core.Collections;
|
||||
|
||||
public class TestDriverStream : ViewStream, IWorker {
|
||||
readonly IBlueTableSchema schema;
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace BCG {
|
||||
/// with PubSub, as some clients are still using ManagedSubcribers)
|
||||
/// </summary>
|
||||
public class ManagedSubscriber : IManagedSubscriber, IWorker, IDisposable {
|
||||
private static ManagedSubscriber? _self;
|
||||
private ISubscriberCore _subcore;
|
||||
// private IDictionary myTypedDispatchTable = new Hashtable(),
|
||||
// myRawDispatchTable = new Hashtable();
|
||||
@@ -33,6 +34,7 @@ namespace BCG {
|
||||
ManagedSubscriber(ISubscriberCore subsCore) { _subcore = subsCore; }
|
||||
|
||||
public void doWork() {
|
||||
var msg_map = new Dictionary<string, List<bts.PubSubServerMessage>>();
|
||||
var updates = _subcore.get_updates(TimeSpan.Zero);
|
||||
if (updates.Count() == 0)
|
||||
return;
|
||||
|
||||
@@ -45,7 +45,11 @@ namespace BCG
|
||||
get { return myConnInfo; }
|
||||
}
|
||||
|
||||
public override string ToString() =>
|
||||
$"type: {myMsgType} conn: {myConnInfo} msg: {myMsg?.Length ?? 0}";
|
||||
override public string ToString()
|
||||
{
|
||||
Func<byte[], int> len = (byte[] m) => { return m == null ? 0 : m.Length; };
|
||||
return $"type: {myMsgType} conn: {myConnInfo} msg: {len(myMsg)}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ namespace bts {
|
||||
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
|
||||
_accept_socket.BeginAccept(new AsyncCallback(_on_accept), new object[] { });
|
||||
if (ex is OutOfMemoryException)
|
||||
throw;
|
||||
throw ex;
|
||||
return;
|
||||
}
|
||||
new_sock.LingerState = new LingerOption(false, 0);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using bts;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using bts;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BCG {
|
||||
/// <summary>
|
||||
@@ -68,8 +69,7 @@ namespace BCG {
|
||||
|
||||
public static byte[] getBytesFromStream(params Stream[] streams) {
|
||||
long totalSize = 0;
|
||||
using var ms = new MemoryStream();
|
||||
using var bw = new BinaryWriter(ms, Encoding.UTF8, true);
|
||||
BinaryWriter bw = new BinaryWriter(new MemoryStream());
|
||||
foreach (Stream s in streams)
|
||||
totalSize += s.Length - s.Position;
|
||||
bw.Write(Convert.ToInt32(totalSize));
|
||||
@@ -78,8 +78,7 @@ namespace BCG {
|
||||
int lengthToReadForThisStream = Convert.ToInt32(s.Length - s.Position);
|
||||
bw.Write(br.ReadBytes(lengthToReadForThisStream));
|
||||
}
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
return (bw.BaseStream as MemoryStream).ToArray();
|
||||
}
|
||||
|
||||
public static byte[] read_bytes(Stream str) {
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace BCG {
|
||||
|
||||
public void publish(PubSubClientMessage msg) {
|
||||
Log.assert(msg.msg_type == PubSubMessageType.PUBLISH);
|
||||
Log.assert(!string.IsNullOrEmpty(msg.pub_msg?.tag_type));
|
||||
Log.assert(!String.IsNullOrEmpty(msg.pub_msg.tag_type));
|
||||
bts.Log.Gen.info($"PublisherCore.publish msg: {msg}");
|
||||
_main_queue.enqueue(msg);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace BCG {
|
||||
public void doWork() {
|
||||
if (_connection_cb != null) {
|
||||
var conns = _conn_callback_queue.dequeueAll();
|
||||
foreach (var ci in conns.ExceptNull()) {
|
||||
foreach (var ci in conns) {
|
||||
_connection_cb(ci.client_url, ci.status);
|
||||
}
|
||||
}
|
||||
@@ -175,7 +175,7 @@ namespace BCG {
|
||||
case RemoteMessageType.Data:
|
||||
// if callback is registered fire it right away, else enqueue it
|
||||
if (_data_cb != null)
|
||||
_data_cb(sender_rci.ToString(), message.message ?? Array.Empty<byte>());
|
||||
_data_cb(sender_rci.ToString(), message.message);
|
||||
else
|
||||
_received_data_queue.enqueue(new Pair<string, byte[]>(sender_rci.ToString(), message.message));
|
||||
break;
|
||||
@@ -258,7 +258,7 @@ namespace BCG {
|
||||
// (which gets called in another thread)
|
||||
private void _handle_new_connections() {
|
||||
var new_conns = _new_connections.dequeueAll();
|
||||
foreach (var conn in new_conns.ExceptNull()) {
|
||||
foreach (ITCPConnection conn in new_conns) {
|
||||
var peer_rci = conn.get_peer_address();
|
||||
bts.Log.Gen.info($"ManagedTCPMessageHub._handle_new_connections conn: {conn}");
|
||||
///to stop it from being garbabge collected immediatly
|
||||
|
||||
@@ -16,8 +16,8 @@ public interface IPubSubState {
|
||||
|
||||
ICollection<string> all_tags { get; }
|
||||
|
||||
byte[]? get_content(string tag);
|
||||
string? getTagType(string tag);
|
||||
byte[] get_content(string tag);
|
||||
string getTagType(string tag);
|
||||
void get_all_connections(
|
||||
string tag,
|
||||
out Dictionary<string, string> subscribers,
|
||||
|
||||
@@ -188,11 +188,11 @@ namespace BCG {
|
||||
_state.handle_sub(sub_msg); // state keeps the list of all subscribers
|
||||
///to all these new subscriber s, send the existing data
|
||||
foreach (string tag in sub_msg.tags.empty_if_null()) {
|
||||
byte[]? data = _state.get_content(tag);
|
||||
byte[] data = _state.get_content(tag);
|
||||
//ie data has been published once
|
||||
if (data != null) {
|
||||
bts.Log.Gen.info($"ManagedTCPMessgeHub._handle_sub get_content tag: {tag} data len: {data.Length}");
|
||||
string? tag_type_ = _state.getTagType(tag);
|
||||
string tag_type_ = _state.getTagType(tag);
|
||||
var msg_to_send = new PubSubServerMessage() {
|
||||
tag = tag,
|
||||
tag_type = tag_type_,
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace BCG {
|
||||
return new string[] { };
|
||||
}
|
||||
|
||||
public byte[]? get_content(string tag) {
|
||||
public byte[] get_content(string tag) {
|
||||
if (!_tag_to_data_map.ContainsKey(tag))
|
||||
return null;
|
||||
var rv = _tag_to_data_map[tag].get_current_content();
|
||||
@@ -157,7 +157,7 @@ namespace BCG {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public string? getTagType(string tag) {
|
||||
public string getTagType(string tag) {
|
||||
if (!_tag_to_data_map.ContainsKey(tag))
|
||||
return null;
|
||||
else
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace bts {
|
||||
public class SingleTagData {
|
||||
private readonly IPubSubServerTagHandler? _tag_handler;
|
||||
|
||||
public SingleTagData(string tag, string tag_type, IPubSubServerTagHandler? tag_handler) {
|
||||
public SingleTagData(string tag, string tag_type, IPubSubServerTagHandler tag_handler) {
|
||||
bts.Log.Gen.info($"SingleTagData constructed for tag: {tag} tag_type: {tag_type}");
|
||||
this.tag = tag;
|
||||
this.tag_type = tag_type;
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace BCG {
|
||||
}
|
||||
|
||||
public void onConnection(ITCPConnection connection) {
|
||||
string ip; int port;
|
||||
var peer_rci = connection.get_peer_address();
|
||||
bts.Log.Gen.info($"SimpleTCPClient.onConnection connected to server: {peer_rci}, starting task to send data in a loop");
|
||||
if (_listener != null) {
|
||||
|
||||
@@ -5,10 +5,9 @@ using BCG;
|
||||
using bts.api;
|
||||
using bts.md;
|
||||
|
||||
using Bts.DataStream;
|
||||
using Bts.DataStreamCore;
|
||||
|
||||
using Spark.Api.MarketData;
|
||||
using global::Spark.Api.MarketData;
|
||||
|
||||
public class BookSchemaBuilder {
|
||||
public int NumLevels { get; set; } = 5;
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace Bts.SharedStreams;
|
||||
|
||||
using bts.api;
|
||||
|
||||
using Spark.Api.Orders;
|
||||
using global::Spark.Api.Orders;
|
||||
|
||||
public static class WellKnownColumns {
|
||||
public static (string Name, Type Type) AskNotional => (WellKnownColumnNames.AskNotional, typeof(double));
|
||||
|
||||
@@ -3,7 +3,6 @@ using bts.config;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace BCG {
|
||||
|
||||
@@ -22,9 +21,7 @@ namespace BCG {
|
||||
}
|
||||
public class RenkoCalculator {
|
||||
public readonly double brick_size;
|
||||
public RenkoBrick? current_brick;
|
||||
|
||||
[MemberNotNull(nameof(current_brick))]
|
||||
public RenkoBrick current_brick = null;
|
||||
private bool _add_price(double price) {
|
||||
if (current_brick == null) {
|
||||
current_brick = new RenkoBrick {
|
||||
@@ -312,4 +309,4 @@ namespace BCG {
|
||||
return wma_values;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
[DataStreamUserRespresentation("nl")]
|
||||
public class BlueOrbNLStream : ViewStream {
|
||||
private readonly string _nl_prompt;
|
||||
private ViewStream? _nl_to_dsl_stream, _dsl_stream;
|
||||
private ViewStream _nl_to_dsl_stream, _dsl_stream;
|
||||
private IDictionary<string, object> _dp_metadata = new Dictionary<string, object>();
|
||||
public BlueOrbNLStream(string nl_prompt) {
|
||||
_nl_prompt = nl_prompt;
|
||||
|
||||
@@ -85,8 +85,7 @@ namespace bts.BlueOrb {
|
||||
.GetProperty("choices")[0]
|
||||
.GetProperty("message")
|
||||
.GetProperty("content")
|
||||
.GetString()
|
||||
?? string.Empty;
|
||||
.GetString();
|
||||
|
||||
//return gpt_response;
|
||||
DateTime t1 = DateTime.Now;
|
||||
|
||||
@@ -4,8 +4,6 @@ using BCG.Utilities.General;
|
||||
using Bts.PubSub;
|
||||
using Bts.SharedStreams.Tables;
|
||||
|
||||
using Spark.Core.Diagnostics;
|
||||
|
||||
namespace bts {
|
||||
// TODO: Use dependency injection to instantiate this stream, and others like it that depend on
|
||||
// ISubscriberCore(Factory). Until then, hide it from DSQA.
|
||||
@@ -42,7 +40,7 @@ namespace bts {
|
||||
foreach (var u in updates) {
|
||||
if (u.tag != "System_AllStatistics")
|
||||
continue;
|
||||
var tag_infos = TagStatsInfo.deserialize(ExceptionAssert.NotNull(u.data));
|
||||
var tag_infos = TagStatsInfo.deserialize(u.data);
|
||||
foreach (var ti in tag_infos) {
|
||||
_tag_map[ti.tag] = ti;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ ARG IMAGE="sparkd"
|
||||
ARG CONFIG_DIR="src/app_sparkd/configurations/dev"
|
||||
ARG SOURCE_DIR="install/sparkd-release-gcc"
|
||||
ARG PYTHON_REQUIREMENTS="requirements.txt"
|
||||
ARG ENTRYPOINT_SCRIPT="src/app_sparkd/sparkd-entrypoint.sh"
|
||||
ARG SPARKD_ENTRYPOINT="src/app_sparkd/sparkd-entrypoint.sh"
|
||||
|
||||
# sparkd_base
|
||||
FROM bluetradingsystems/linux_dotnet8 AS sparkd_base
|
||||
ARG CONFIG_DIR
|
||||
ARG SOURCE_DIR
|
||||
ARG PYTHON_REQUIREMENTS
|
||||
ARG ENTRYPOINT_SCRIPT
|
||||
ARG SPARKD_ENTRYPOINT
|
||||
|
||||
USER "root"
|
||||
RUN apt-get update && apt-get install -y liblttng-ust-dev
|
||||
@@ -23,7 +23,7 @@ RUN pip3 install -r "/home/bts/bin/requirements.txt"
|
||||
USER "bts"
|
||||
COPY --chown=bts:bts "${SOURCE_DIR}" "."
|
||||
COPY --chown=bts:bts "${CONFIG_DIR}" "/home/bts/.local/share/bts/sparkd/conf"
|
||||
COPY --chown=bts:bts "${ENTRYPOINT_SCRIPT}" "/home/bts/bin/sparkd-entrypoint.sh"
|
||||
COPY --chown=bts:bts "${SPARKD_ENTRYPOINT}" "/home/bts/bin/sparkd-entrypoint.sh"
|
||||
WORKDIR "/home/bts/bin"
|
||||
|
||||
# sparkd
|
||||
@@ -38,7 +38,7 @@ COPY --chown=bts:bts "${MD_RECORDING_DIR}" "/home/bts/.local/share/bts/sparkd/da
|
||||
FROM bluetradingsystems/linux_dotnet8 AS sparkd_symbols
|
||||
ARG SOURCE_DIR
|
||||
ARG PYTHON_REQUIREMENTS="requirements.txt"
|
||||
ARG ENTRYPOINT_SCRIPT
|
||||
ARG SPARKD_ENTRYPOINT
|
||||
|
||||
USER "root"
|
||||
RUN apt-get update && apt-get install -y liblttng-ust-dev
|
||||
@@ -51,9 +51,8 @@ RUN pip3 install -r "/home/bts/bin/requirements.txt"
|
||||
|
||||
USER "bts"
|
||||
COPY --chown=bts:bts "${SOURCE_DIR}" "."
|
||||
COPY --chown=bts:bts "${ENTRYPOINT_SCRIPT}" "/home/bts/bin/sparkd-entrypoint.sh"
|
||||
COPY --chown=bts:bts "${SPARKD_ENTRYPOINT}" "/home/bts/bin/sparkd-entrypoint.sh"
|
||||
WORKDIR "/home/bts/bin"
|
||||
|
||||
# selected image
|
||||
FROM ${IMAGE}
|
||||
ENTRYPOINT "./sparkd-entrypoint.sh"
|
||||
@@ -1,4 +0,0 @@
|
||||
SPARKD__CONFIG_DIR=src/app_sparkd/configurations/cme_replay
|
||||
SPARKD__PYTHON_REQUIREMENTS=src/app_sparkd/configurations/cme_replay/requirements.txt
|
||||
SPARKD__ENTRYPOINT=src/app_sparkd/sparkd-entrypoint.sh
|
||||
TZ=America/Chicago
|
||||
@@ -1,38 +0,0 @@
|
||||
PublisherOptions {
|
||||
value {
|
||||
network_interface: "0.0.0.0"
|
||||
heartbeat_ms: 5000
|
||||
heartbeat_boot_seconds: 60
|
||||
skip_options: true
|
||||
hot_initial: 1024
|
||||
hot_growth: 1024
|
||||
cold_initial: 8192
|
||||
cold_growth: 2048
|
||||
channel_prefix: ""
|
||||
disable_heartbeat: true
|
||||
}
|
||||
}
|
||||
|
||||
MarketDataConfig {
|
||||
value {
|
||||
# glbx{
|
||||
# use_databento: true
|
||||
# databento_settings {
|
||||
# read_from_file: true
|
||||
# key: "db-DgxpuTXneNgVvd7sJCAEKYDhyCApW"
|
||||
# bbo_file_name: "glbx-mdp3-20251103.mbp-1.dbn.zst"
|
||||
# contracts_file_name: "glbx-mdp3-20251103.definition.dbn.zst"
|
||||
# }
|
||||
# }
|
||||
# recording{
|
||||
# venue: VENUE_GLBX
|
||||
# num_of_seconds_to_run_file_writer: 240
|
||||
# num_of_seconds_to_run_db_writer : 0
|
||||
# n_book_levels: 10
|
||||
# batch_size: 100 #for the db writer
|
||||
# }
|
||||
replay {
|
||||
venue: VENUE_GLBX
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
Symbols {
|
||||
value {
|
||||
venues {
|
||||
name: "VENUE_GLBX"
|
||||
future: "ES"
|
||||
# option: "E1A"
|
||||
# option: "E1B"
|
||||
# option: "E1C"
|
||||
# option: "E1D"
|
||||
# option: "E2A"
|
||||
# option: "E2B"
|
||||
# option: "E2C"
|
||||
# option: "E2D"
|
||||
# option: "E3A"
|
||||
# option: "E3B"
|
||||
# option: "E3C"
|
||||
# option: "E3D"
|
||||
# option: "E4A"
|
||||
# option: "E4B"
|
||||
# option: "E4C"
|
||||
# option: "E4D"
|
||||
# option: "E5A"
|
||||
# option: "E5B"
|
||||
# option: "E5C"
|
||||
# option: "E5D"
|
||||
# option: "EW1"
|
||||
# option: "EW2"
|
||||
# option: "EW3"
|
||||
# option: "EW4"
|
||||
# option: "ESH9"
|
||||
# option: "ESZ6"
|
||||
# option: "ESH0"
|
||||
# option: "ESM6"
|
||||
# option: "ESZ7"
|
||||
# option: "ESH6"
|
||||
# option: "ESM7"
|
||||
# option: "ESZ8"
|
||||
# option: "ESH7"
|
||||
# option: "ESH8"
|
||||
# option: "ESU6"
|
||||
# option: "ESZ5"
|
||||
# option: "ESZ9"
|
||||
# option: "E1D"
|
||||
# option: "ESZ5"
|
||||
# option: "ES"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
SPARKD__CONFIG_DIR=src/app_sparkd/configurations/ophir_sim_live_wb
|
||||
SPARKD__DATA_DIR=/home/wedbushprod/8000/sparkdata/data
|
||||
SPARKD__IMAGE=sparkd_symbols
|
||||
SPARKD__PYTHON_REQUIREMENTS=src/app_sparkd/configurations/ophir_sim_live_wb/requirements.txt
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/wedbushprod/8000/sparkdata/conf
|
||||
@@ -0,0 +1,5 @@
|
||||
numpy==2.2.6
|
||||
pybit==5.11.0
|
||||
requests==2.31.0
|
||||
websocket-client==1.8.0
|
||||
websockets==15.0.1
|
||||
@@ -0,0 +1,116 @@
|
||||
JetFIX {
|
||||
value {
|
||||
connection {
|
||||
name: "glbx_1"
|
||||
venue: VENUE_GLBX
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PublisherOptions {
|
||||
value {
|
||||
network_interface_a: 'enp193s0f0np0'
|
||||
network_interface_b: 'enp193s0f0np0'
|
||||
#these get overriden if not entered here
|
||||
heartbeat_ms: 5000
|
||||
heartbeat_boot_seconds: 60
|
||||
skip_options: false
|
||||
hot_initial: 1024
|
||||
hot_growth: 1024
|
||||
cold_initial: 8192
|
||||
cold_growth: 2048
|
||||
channel_prefix: ""
|
||||
disable_heartbeat: false
|
||||
}
|
||||
}
|
||||
|
||||
CMEOptions {
|
||||
value {
|
||||
feed_engine {
|
||||
name: "mdp3feed"
|
||||
spin_time: 0
|
||||
channels_per_thread: 3
|
||||
data_wait: 10
|
||||
udp_socket_buffer_size: 268435456
|
||||
}
|
||||
channel {
|
||||
id: "*"
|
||||
feed_engine: "mdp3feed"
|
||||
use_tcp_replay: false
|
||||
recovery_queue_size: 640000
|
||||
lost_packet_wait_timeout_ms: 10
|
||||
onixs_log_mode: CME_ONIXS_LOG_MODE_UNSPECIFIED:q
|
||||
#max_gap_recovery_cache_size: 4
|
||||
use_natural_refresh: false
|
||||
join_snapshot_on_gap: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logging {
|
||||
value {
|
||||
initial_queue_size: 120001
|
||||
max_queue_growth: 4
|
||||
console {
|
||||
default_level: "Info"
|
||||
subsystem {
|
||||
name: "md"
|
||||
level: "Info"
|
||||
}
|
||||
subsystem {
|
||||
name: "OrderMan"
|
||||
level: "Info"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MarketDataConfig {
|
||||
value {
|
||||
glbx {
|
||||
unique_check_value: 15
|
||||
use_databento: false
|
||||
}
|
||||
recording{
|
||||
venue: VENUE_GLBX
|
||||
num_of_seconds_to_run_file_writer: 300
|
||||
num_of_seconds_to_run_db_writer : 0
|
||||
n_book_levels: 10
|
||||
batch_size: 100 #for the db writer
|
||||
enable_book_recording: true
|
||||
enable_trade_recording: true
|
||||
enable_bbo_recording: false
|
||||
enable_tbbo_recording: false
|
||||
enable_misc_recording: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# JetFIX {
|
||||
# value {
|
||||
# #connection: @JetFIXSimConnection.sim
|
||||
# connection {
|
||||
# name: "mlx_004_54"
|
||||
# venue: VENUE_GLBX
|
||||
# socket_connect_host_ip: "69.50.112.191"
|
||||
# socket_connect_port: 42876
|
||||
# sender_compid: "MLX004"
|
||||
# target_compid: "CME"
|
||||
# target_subid: "54"
|
||||
# cme_market_segment_id: 54
|
||||
# start_time: "00:10:00"
|
||||
# end_time: "23:55:00"
|
||||
# start_day: "sunday"
|
||||
# end_day: "friday"
|
||||
# seconds_between_hbs: 30
|
||||
# sender_subid: "BTS"
|
||||
# use_ilink3: true
|
||||
# # raw_data: "S4PMA"
|
||||
# # auto_fix_seq_num: true
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
SymbolLists {
|
||||
value {
|
||||
list {
|
||||
key: "GlbxFutures"
|
||||
symbol: "ES"
|
||||
}
|
||||
list {
|
||||
key: "GlbxOptions"
|
||||
symbol: "E1A"
|
||||
symbol: "E1B"
|
||||
symbol: "E1C"
|
||||
symbol: "E1D"
|
||||
symbol: "E2A"
|
||||
symbol: "E2B"
|
||||
symbol: "E2C"
|
||||
symbol: "E2D"
|
||||
symbol: "E3A"
|
||||
symbol: "E3B"
|
||||
symbol: "E3C"
|
||||
symbol: "E3D"
|
||||
symbol: "E4A"
|
||||
symbol: "E4B"
|
||||
symbol: "E4C"
|
||||
symbol: "E4D"
|
||||
symbol: "E5A"
|
||||
symbol: "E5B"
|
||||
symbol: "E5C"
|
||||
symbol: "E5D"
|
||||
symbol: "EW1"
|
||||
symbol: "EW2"
|
||||
symbol: "EW3"
|
||||
symbol: "EW4"
|
||||
symbol: "ESH9"
|
||||
symbol: "ESZ6"
|
||||
symbol: "ESH0"
|
||||
symbol: "ESM6"
|
||||
symbol: "ESZ7"
|
||||
symbol: "ESH6"
|
||||
symbol: "ESM7"
|
||||
symbol: "ESZ8"
|
||||
symbol: "ESH7"
|
||||
symbol: "ESH8"
|
||||
symbol: "ESU6"
|
||||
symbol: "ESZ5"
|
||||
symbol: "ESZ9"
|
||||
symbol: "E1D"
|
||||
symbol: "ESZ5"
|
||||
symbol: "ES"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Symbols {
|
||||
value {
|
||||
venues {
|
||||
name: "VENUE_GLBX"
|
||||
future: @SymbolLists.list[GlbxFutures].symbol
|
||||
option: @SymbolLists.list[GlbxOptions].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
SPARKD__CONFIG_DIR=src/app_sparkd/configurations/ophir_sim_replay
|
||||
SPARKD__PYTHON_REQUIREMENTS=src/app_sparkd/configurations/ophir_sim_replay/requirements.txt
|
||||
TZ=America/Chicago
|
||||
SPARKD__MD_RECORDING_DIR=/home/wedbushprod/8000/md_recording
|
||||
File renamed without changes.
@@ -0,0 +1,33 @@
|
||||
JetFIX {
|
||||
value {
|
||||
connection {
|
||||
name: "glbx_1"
|
||||
venue: VENUE_GLBX
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PublisherOptions {
|
||||
value {
|
||||
network_interface: "0.0.0.0"
|
||||
heartbeat_ms: 5000
|
||||
heartbeat_boot_seconds: 60
|
||||
skip_options: true
|
||||
hot_initial: 1024
|
||||
hot_growth: 1024
|
||||
cold_initial: 8192
|
||||
cold_growth: 2048
|
||||
channel_prefix: ""
|
||||
disable_heartbeat: true
|
||||
}
|
||||
}
|
||||
|
||||
MarketDataConfig {
|
||||
value {
|
||||
replay {
|
||||
venue: VENUE_GLBX
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
SymbolLists {
|
||||
value {
|
||||
list {
|
||||
key: "GlbxFutures"
|
||||
symbol: "ES"
|
||||
}
|
||||
list {
|
||||
key: "GlbxOptions"
|
||||
symbol: "E1A"
|
||||
symbol: "E1B"
|
||||
symbol: "E1C"
|
||||
symbol: "E1D"
|
||||
symbol: "E2A"
|
||||
symbol: "E2B"
|
||||
symbol: "E2C"
|
||||
symbol: "E2D"
|
||||
symbol: "E3A"
|
||||
symbol: "E3B"
|
||||
symbol: "E3C"
|
||||
symbol: "E3D"
|
||||
symbol: "E4A"
|
||||
symbol: "E4B"
|
||||
symbol: "E4C"
|
||||
symbol: "E4D"
|
||||
symbol: "E5A"
|
||||
symbol: "E5B"
|
||||
symbol: "E5C"
|
||||
symbol: "E5D"
|
||||
symbol: "ES"
|
||||
symbol: "EW1"
|
||||
symbol: "EW2"
|
||||
symbol: "EW3"
|
||||
symbol: "EW4"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Symbols {
|
||||
value {
|
||||
venues {
|
||||
name: "VENUE_GLBX"
|
||||
future: @SymbolLists.list[GlbxFutures].symbol
|
||||
option: @SymbolLists.list[GlbxOptions].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
SPARKD__CONFIG_DIR=src/app_sparkd/configurations/ophir_sim_replay_wb
|
||||
SPARKD__DATA_DIR=/home/wedbushprod/9000/sparkdata/data
|
||||
SPARKD__IMAGE=sparkd_symbols
|
||||
SPARKD__PYTHON_REQUIREMENTS=src/app_sparkd/configurations/ophir_sim_replay_wb/requirements.txt
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/wedbushprod/9000/sparkdata/conf
|
||||
SPARKD__MD_RECORDING_DIR=/home/wedbushprod/md_recording
|
||||
SPARKD__CONFIG_PORT=9000
|
||||
SPARKD__QUICKBUS_PORT=9001
|
||||
SPARKD__SIM_FIX_PORT=9002
|
||||
@@ -0,0 +1,5 @@
|
||||
numpy==2.2.6
|
||||
pybit==5.11.0
|
||||
requests==2.31.0
|
||||
websocket-client==1.8.0
|
||||
websockets==15.0.1
|
||||
@@ -0,0 +1,46 @@
|
||||
JetFIX {
|
||||
value {
|
||||
connection {
|
||||
name: "glbx_1"
|
||||
venue: VENUE_GLBX
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ports {
|
||||
value {
|
||||
config_port: 9000
|
||||
qbus_port: 9001
|
||||
glbx_sim_fix_port: 9002
|
||||
ice_sim_fix_port: 9003
|
||||
}
|
||||
}
|
||||
|
||||
Logging {
|
||||
value {
|
||||
initial_queue_size: 120001
|
||||
max_queue_growth: 4
|
||||
console {
|
||||
default_level: "Info"
|
||||
subsystem {
|
||||
name: "md"
|
||||
level: "Info"
|
||||
}
|
||||
subsystem {
|
||||
name: "OrderMan"
|
||||
level: "Info"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MarketDataConfig {
|
||||
value {
|
||||
replay {
|
||||
venue: VENUE_GLBX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
SymbolLists {
|
||||
value {
|
||||
list {
|
||||
key: "GlbxFutures"
|
||||
symbol: "ES"
|
||||
}
|
||||
list {
|
||||
key: "GlbxOptions"
|
||||
symbol: "E1A"
|
||||
symbol: "E1B"
|
||||
symbol: "E1C"
|
||||
symbol: "E1D"
|
||||
symbol: "E2A"
|
||||
symbol: "E2B"
|
||||
symbol: "E2C"
|
||||
symbol: "E2D"
|
||||
symbol: "E3A"
|
||||
symbol: "E3B"
|
||||
symbol: "E3C"
|
||||
symbol: "E3D"
|
||||
symbol: "E4A"
|
||||
symbol: "E4B"
|
||||
symbol: "E4C"
|
||||
symbol: "E4D"
|
||||
symbol: "E5A"
|
||||
symbol: "E5B"
|
||||
symbol: "E5C"
|
||||
symbol: "E5D"
|
||||
symbol: "EW1"
|
||||
symbol: "EW2"
|
||||
symbol: "EW3"
|
||||
symbol: "EW4"
|
||||
symbol: "ESH9"
|
||||
symbol: "ESZ6"
|
||||
symbol: "ESH0"
|
||||
symbol: "ESM6"
|
||||
symbol: "ESZ7"
|
||||
symbol: "ESH6"
|
||||
symbol: "ESM7"
|
||||
symbol: "ESZ8"
|
||||
symbol: "ESH7"
|
||||
symbol: "ESH8"
|
||||
symbol: "ESU6"
|
||||
symbol: "ESZ5"
|
||||
symbol: "ESZ9"
|
||||
symbol: "E1D"
|
||||
symbol: "ESZ5"
|
||||
symbol: "ES"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Symbols {
|
||||
value {
|
||||
venues {
|
||||
name: "VENUE_GLBX"
|
||||
future: @SymbolLists.list[GlbxFutures].symbol
|
||||
option: @SymbolLists.list[GlbxOptions].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,12 @@ init_timezone() {
|
||||
tz="${1:-$TZ}"
|
||||
zoneinfo_dir=/usr/share/zoneinfo
|
||||
if [ -f "$zoneinfo_dir/$tz" -a "$(readlink -f /etc/localtime)" != "$zoneinfo_dir/$tz" ]; then
|
||||
echo "Initializing locales and timezone"
|
||||
ln -snf "$zoneinfo_dir/$tz" /etc/localtime
|
||||
sudo echo $tz > /etc/timezone
|
||||
echo "Setting locales and timezone to $tz"
|
||||
if [ -e /etc/localtime ]; then
|
||||
sudo -n rm -f /etc/localtime
|
||||
fi
|
||||
sudo -n ln -snf "$zoneinfo_dir/$tz" /etc/localtime
|
||||
echo $tz | sudo -n tee /etc/timezone > /dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -36,10 +39,17 @@ roll_log() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Acquire sudo permission once for the script (needed for a few calls)
|
||||
echo bts | sudo -S -v
|
||||
data_root="${HOME:-/home/bts}/.local/share/bts/sparkd"
|
||||
echo bts | sudo -S chown -R bts:bts "$data_root"
|
||||
sudo -n chown -R bts:bts "$data_root"
|
||||
load_env "$data_root/conf/.env.local"
|
||||
init_timezone "$TZ"
|
||||
roll_log "$data_root/data/logging.sparkd/log"
|
||||
symlink "$data_root/conf/plugins" /home/bts/bin/plugins
|
||||
|
||||
if [ -e "/md_recording" -a ! -e "/home/bts/.local/share/bts/sparkd/data/md_recording" ]; then
|
||||
symlink "/md_recording" /home/bts/.local/share/bts/sparkd/data/md_recording
|
||||
fi
|
||||
|
||||
bash -c "${@:-./sparkd run}"
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "spark/md/MBOServiceServer.h"
|
||||
#include "spark/md/MDClient.h"
|
||||
#include "spark/md/SyntheticSecurityService.h"
|
||||
#include "spark/md/relay/query_server.h"
|
||||
#include "spark/md/relay/QueryServer.h"
|
||||
#include "spark/md/service/MarketDataServiceServer.h"
|
||||
#include "spark/metrics/metrics.h"
|
||||
#include "spark/metrics/system_metrics.h"
|
||||
|
||||
Loaded 100 of 388 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user