Compare commits
353
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f61907eefb | ||
|
|
e01a37e4cf | ||
|
|
64fd23f0ed | ||
|
|
0220401011 | ||
|
|
af52c752f0 | ||
|
|
dc86ebd92e | ||
|
|
1ca23d7d8a | ||
|
|
bf564eb918 | ||
|
|
10637db1eb | ||
|
|
ea13bb31ec | ||
|
|
c20bd60ff7 | ||
|
|
305dc62389 | ||
|
|
f599c940b3 | ||
|
|
21477b90fe | ||
|
|
582a442ae8 | ||
|
|
b0bc03335d | ||
|
|
318db81ced | ||
|
|
454fa05692 | ||
|
|
ebba07b994 | ||
|
|
e53b7713a4 | ||
|
|
ad43b8535b | ||
|
|
ba07a6cc8a | ||
|
|
bb419cf048 | ||
|
|
7b74ff1525 | ||
|
|
2974a04281 | ||
|
|
0089bafeaa | ||
|
|
217d83e955 | ||
|
|
8ea18cb74a | ||
|
|
1b836b24a8 | ||
|
|
bad703a847 | ||
|
|
27dce596f5 | ||
|
|
bda097c754 | ||
|
|
09353b897b | ||
|
|
31009e38bb | ||
|
|
e1d66e9a0e | ||
|
|
616361eaf1 | ||
|
|
67b70d2d8c | ||
|
|
9f0a24f1ec | ||
|
|
85ad072837 | ||
|
|
6327bcc109 | ||
|
|
2e51aebc94 | ||
|
|
50ec2f14f7 | ||
|
|
2457fe4e35 | ||
|
|
59240ae45f | ||
|
|
04acb4f459 | ||
|
|
23a1f65c5f | ||
|
|
c0de84c4ec | ||
|
|
2ce99ddbd2 | ||
|
|
301df9ca36 | ||
|
|
3c58607fe1 | ||
|
|
561d8d66d5 | ||
|
|
14fc68f8e6 | ||
|
|
f19391dac5 | ||
|
|
64226d3698 | ||
|
|
65728df991 | ||
|
|
897c9808d0 | ||
|
|
022a489b18 | ||
|
|
49e3ec2f05 | ||
|
|
e8f98102d2 | ||
|
|
e6d845f970 | ||
|
|
e3b3663a78 | ||
|
|
afefaa36d1 | ||
|
|
e934e28b43 | ||
|
|
eb55be6066 | ||
|
|
27c410c485 | ||
|
|
cd8dc02487 | ||
|
|
e31a4f7265 | ||
|
|
2e83868209 | ||
|
|
0cce94129b | ||
|
|
8c643d74c6 | ||
|
|
394f495bd1 | ||
|
|
68d5a28fd4 | ||
|
|
4182b30d22 | ||
|
|
7f44233ae3 | ||
|
|
a4510ebbd9 | ||
|
|
69d9e36b4e | ||
|
|
c496a426ab | ||
|
|
1612ae7959 | ||
|
|
7c7aa727e2 | ||
|
|
45d6d0f673 | ||
|
|
80a5ec5265 | ||
|
|
09cc78914f | ||
|
|
546dbfbd54 | ||
|
|
a9e5fb8f46 | ||
|
|
7dd6efb477 | ||
|
|
0c150e1caa | ||
|
|
d2278e6b4a | ||
|
|
1b81ad7638 | ||
|
|
bd21cf56fe | ||
|
|
c37d4479b5 | ||
|
|
3f7e7d38ff | ||
|
|
591239b13e | ||
|
|
08494728f0 | ||
|
|
ef833c5705 | ||
|
|
44216afd51 | ||
|
|
cad407827d | ||
|
|
9714135b7d | ||
|
|
c82e598313 | ||
|
|
e7806d2fec | ||
|
|
090a9dfb17 | ||
|
|
27aa43f44d | ||
|
|
19e087aa69 | ||
|
|
167c8c23a0 | ||
|
|
d235f4be41 | ||
|
|
ec43dbd82d | ||
|
|
f07998d6a6 | ||
|
|
b3dc2cdcd4 | ||
|
|
0963aee137 | ||
|
|
c2f8e92b10 | ||
|
|
7ae0142dff | ||
|
|
c30bab899f | ||
|
|
46544f36f1 | ||
|
|
c7df3ac43c | ||
|
|
db0ffba8ed | ||
|
|
a274a214b4 | ||
|
|
bbcfa3c75a | ||
|
|
89229d65f1 | ||
|
|
0e75cde409 | ||
|
|
42fa6dfaff | ||
|
|
400143c84d | ||
|
|
e915945880 | ||
|
|
ca6673e98f | ||
|
|
479f3dccff | ||
|
|
9601ebab20 | ||
|
|
c272d8a8c2 | ||
|
|
b344ab3377 | ||
|
|
ae3080b031 | ||
|
|
f0464331cb | ||
|
|
0648b618bf | ||
|
|
59282b8c70 | ||
|
|
34a86009ce | ||
|
|
0ad9ae9001 | ||
|
|
a296e1e772 | ||
|
|
7f53d8b161 | ||
|
|
fbd8bbd4a8 | ||
|
|
3da52b350f | ||
|
|
243d6827d4 | ||
|
|
00221f9bd9 | ||
|
|
a6171ae405 | ||
|
|
be5d01a797 | ||
|
|
e5d9d324bf | ||
|
|
c34dee9d96 | ||
|
|
e5a98aab41 | ||
|
|
10cd35372b | ||
|
|
ad4515be39 | ||
|
|
ff4d87dd6b | ||
|
|
8ddde3f9da | ||
|
|
51093dc3a5 | ||
|
|
5d5db9ad9f | ||
|
|
fca808fe0d | ||
|
|
07d14f877b | ||
|
|
5ea6dccdd4 | ||
|
|
ac956a5c02 | ||
|
|
1fba09cf94 | ||
|
|
0baa6b875e | ||
|
|
cdacc2d4d4 | ||
|
|
1433541947 | ||
|
|
1070ca7ace | ||
|
|
56fa27dd7e | ||
|
|
d87b522bc6 | ||
|
|
166cb03782 | ||
|
|
40bad84c48 | ||
|
|
c3786d9d64 | ||
|
|
9080e3124b | ||
|
|
d9c536124a | ||
|
|
7de6b2907e | ||
|
|
75f017e9f8 | ||
|
|
7757ab3ea0 | ||
|
|
3186dd383c | ||
|
|
45f751c9c6 | ||
|
|
e4d3774980 | ||
|
|
eedb3ce05d | ||
|
|
6a7d38c0fd | ||
|
|
7f9967834d | ||
|
|
31ccbfcd19 | ||
|
|
c2abf90cc4 | ||
|
|
8dc4735248 | ||
|
|
d940d9f11d | ||
|
|
1e0c75c6c7 | ||
|
|
fbaa17bc40 | ||
|
|
38e3cd6197 | ||
|
|
3bb9961af4 | ||
|
|
da8088fd8d | ||
|
|
748a65f671 | ||
|
|
66d80136bd | ||
|
|
10386311d4 | ||
|
|
629a7f8130 | ||
|
|
81189bb2cc | ||
|
|
e5681a50f2 | ||
|
|
69fe4569e3 | ||
|
|
c7caf66f9c | ||
|
|
14504f4a94 | ||
|
|
5b601a4016 | ||
|
|
e3207b921a | ||
|
|
98db8e61a5 | ||
|
|
45aa75e8bb | ||
|
|
b2471d45b2 | ||
|
|
11e2df8c76 | ||
|
|
cba6852655 | ||
|
|
5eeaedde26 | ||
|
|
b63052dbaa | ||
|
|
29f5bc798e | ||
|
|
04603acbb9 | ||
|
|
bc6890055e | ||
|
|
ea94c09c78 | ||
|
|
e3c3bc78fc | ||
|
|
a11d390dcd | ||
|
|
7c74a961d4 | ||
|
|
5db21ad2ca | ||
|
|
f703dabdfe | ||
|
|
237d3eea4b | ||
|
|
e009316bfb | ||
|
|
5528efd2d2 | ||
|
|
818bdec130 | ||
|
|
09f91735fe | ||
|
|
d9fc18547b | ||
|
|
d257cf2c77 | ||
|
|
079f46404f | ||
|
|
edcc73e934 | ||
|
|
5905ca3e92 | ||
|
|
bc7ac8523b | ||
|
|
0c4c2b7231 | ||
|
|
420351c093 | ||
|
|
f69e6b89c5 | ||
|
|
c3e22e4b23 | ||
|
|
32b7b7f40d | ||
|
|
54e5a68730 | ||
|
|
880c95d92b | ||
|
|
e7da6dd79e | ||
|
|
8bf78aa880 | ||
|
|
1c44165181 | ||
|
|
8165ec0e3d | ||
|
|
7d1ec5b82a | ||
|
|
02e7fb1ee0 | ||
|
|
c0ea6943e1 | ||
|
|
4c914a2d48 | ||
|
|
0ee86f2dd4 | ||
|
|
00bf3c7f47 | ||
|
|
3231ffb343 | ||
|
|
8d7f1738cf | ||
|
|
60d4dd87fd | ||
|
|
3a7eeda70e | ||
|
|
712146e028 | ||
|
|
9101214e66 | ||
|
|
59774ccbb5 | ||
|
|
fcb6c9b8d9 | ||
|
|
c6b2e2f21e | ||
|
|
2eac97c1a9 | ||
|
|
b4b0e10f29 | ||
|
|
38d9db4a90 | ||
|
|
6a679ff78c | ||
|
|
aba3f21020 | ||
|
|
fede19fd11 | ||
|
|
3fa8dbf112 | ||
|
|
77ae4703b3 | ||
|
|
a28bfa1175 | ||
|
|
4e4a48283d | ||
|
|
7a761d00ce | ||
|
|
968be6a99a | ||
|
|
03404eb3f1 | ||
|
|
ff1a970982 | ||
|
|
ed890b4d84 | ||
|
|
e87003cc41 | ||
|
|
bc06037843 | ||
|
|
c4c7cebfc5 | ||
|
|
f18bcd2995 | ||
|
|
a6a1b6ac53 | ||
|
|
8c3da4e43c | ||
|
|
06b955dceb | ||
|
|
e75d15146c | ||
|
|
cb07384c9f | ||
|
|
fc9e502539 | ||
|
|
fcbf3388c0 | ||
|
|
899bea940f | ||
|
|
14b7509607 | ||
|
|
25668e8df0 | ||
|
|
5345ba8ff8 | ||
|
|
9bf05973bd | ||
|
|
cea4d05bc4 | ||
|
|
0b7208784b | ||
|
|
059ccbdab6 | ||
|
|
75eaf8c3d4 | ||
|
|
1e8fcd794f | ||
|
|
726329c4bf | ||
|
|
2d01f3f0f4 | ||
|
|
2a595c0fd7 | ||
|
|
5f9866c9e8 | ||
|
|
78f1cf88e0 | ||
|
|
4877436877 | ||
|
|
1b43124756 | ||
|
|
a1feb3fddf | ||
|
|
024328bf8b | ||
|
|
80d7e34bf1 | ||
|
|
8ab69c919b | ||
|
|
99531bcfa0 | ||
|
|
6bd516d4f2 | ||
|
|
1a1d771e1b | ||
|
|
050fcf7c6e | ||
|
|
aadeae3201 | ||
|
|
b72e8aed02 | ||
|
|
0820cc3e9a | ||
|
|
b1ba9a1315 | ||
|
|
39ce4323a1 | ||
|
|
d9fcd290d9 | ||
|
|
05939b02c5 | ||
|
|
aa91638fe4 | ||
|
|
065fc54f73 | ||
|
|
95fb13f58b | ||
|
|
4eb2931cb8 | ||
|
|
5326015a48 | ||
|
|
fcbe319470 | ||
|
|
5ad21c88b2 | ||
|
|
3a9c1d557b | ||
|
|
9d1b03d1e2 | ||
|
|
9a677cf980 | ||
|
|
6fb5b83249 | ||
|
|
95830fafdf | ||
|
|
d68b03bb91 | ||
|
|
e7062ce01e | ||
|
|
932738f98e | ||
|
|
1426b00e83 | ||
|
|
e724409b58 | ||
|
|
9cf828e9a4 | ||
|
|
41408fb609 | ||
|
|
4c21e32838 | ||
|
|
385f3ea402 | ||
|
|
8d6d8cab18 | ||
|
|
01615f824a | ||
|
|
c6779ddc90 | ||
|
|
46eff65435 | ||
|
|
17b314ea3a | ||
|
|
25445d58d0 | ||
|
|
0b313a8aa8 | ||
|
|
54f954fd4b | ||
|
|
980f38ba03 | ||
|
|
9eada2724b | ||
|
|
b5f53ee918 | ||
|
|
efc175f654 | ||
|
|
6074afd999 | ||
|
|
219dff4055 | ||
|
|
9a3b07b622 | ||
|
|
e713210030 | ||
|
|
c057bf18f6 | ||
|
|
17a0bef824 | ||
|
|
9180c48b67 | ||
|
|
01acbe08f5 | ||
|
|
8a47cd4821 | ||
|
|
03050d9b07 | ||
|
|
9178878880 | ||
|
|
f38b1c7af9 | ||
|
|
45cd958b1e | ||
|
|
4d49c8f030 | ||
|
|
b2227ce37b |
No files matched your search
+7
-2
@@ -4,8 +4,7 @@ cmake-build-debug/
|
||||
.idea/
|
||||
.dir-locals.el
|
||||
*.pyc
|
||||
.vscode/*
|
||||
!.vscode/*.json
|
||||
*.vscode/*
|
||||
.vs
|
||||
obj/
|
||||
*.csproj.user
|
||||
@@ -34,5 +33,11 @@ trace_data/
|
||||
/doc/user/public/*
|
||||
.ionide/*
|
||||
/.ignore
|
||||
*.rej
|
||||
/build
|
||||
.clangd/
|
||||
/.cache/
|
||||
.venv/**
|
||||
install/**
|
||||
.devcontainer/**
|
||||
/src/Spark.Admin.WebApp/src/bin/
|
||||
Vendored
-107
@@ -1,107 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceFolder}/src",
|
||||
"${workspaceRoot}/externals/linux/include"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceFolder}/src",
|
||||
"${workspaceRoot}/externals/linux/include"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"compileCommands": "${workspaceFolder}/build/ninja_debug/compile_commands.json"
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"includePath": [
|
||||
"${workspaceRoot}/src",
|
||||
"${workspaceRoot}/build/src",
|
||||
"${workspaceRoot}/build/ninja_debug/src",
|
||||
"${workspaceRoot}/externals/windows/include",
|
||||
"${workspaceRoot}/externals/linux/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include"
|
||||
],
|
||||
"defines": [
|
||||
"__linux__",
|
||||
"__x86_64__"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceRoot}/src",
|
||||
"${workspaceRoot}/build/src",
|
||||
"${workspaceRoot}/build/ninja_debug/src",
|
||||
"${workspaceRoot}/externals/windows/include",
|
||||
"${workspaceRoot}/externals/linux/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/*"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
{
|
||||
"name": "WindowsQuick",
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"includePath": [
|
||||
"${workspaceRoot}/src",
|
||||
"${workspaceRoot}/build/src",
|
||||
"${workspaceRoot}/build/ninja_debug/src",
|
||||
"${workspaceRoot}/externals/windows/include",
|
||||
"${workspaceRoot}/externals/linux/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/local/include",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/lib/gcc/x86_64-linux-gnu/6/include-fixed",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu",
|
||||
"${workspaceRoot}/externals/windows/vscode/usr/include"
|
||||
],
|
||||
"defines": [
|
||||
"__linux__",
|
||||
"__x86_64__"
|
||||
],
|
||||
"browse": {
|
||||
"path": [
|
||||
"${workspaceRoot}/src"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": "${workspaceRoot}/.vscode/browse.vc.db"
|
||||
},
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-395
@@ -1,395 +0,0 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Spark Local",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"run",
|
||||
// "test",
|
||||
// "-a",
|
||||
// "[ilink3]"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceRoot}/build/ninja_debug/server/",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SparkVM Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"run"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server/",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"preLaunchTask": "",
|
||||
"logging": {
|
||||
"engineLogging": false
|
||||
},
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "enable pretty-printer",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Skip STL",
|
||||
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "LD LIBRARY",
|
||||
"text": "set env LD_LIBRARY_PATH=.",
|
||||
"ignoreFailures": false
|
||||
}
|
||||
],
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/ninja_debug/server/sparkd/sparkd",
|
||||
"args": [
|
||||
"run"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceRoot}/build/ninja_debug/src/server/sparkd",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Client Launch",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/spark.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "SDK Launch",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/spark_sdk.exe",
|
||||
"args": [
|
||||
"md",
|
||||
"GLBX",
|
||||
"Future",
|
||||
"CL",
|
||||
"CLZ9",
|
||||
"--user=bts",
|
||||
"--pass="
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Excel Launch",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "C:/Program Files/Microsoft Office/Office14/EXCEL.EXE",
|
||||
"args": [
|
||||
"${workspaceRoot}/build/Debug/bin/net471/spark_excel-addin64-packed.xll"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Client Tests",
|
||||
"type": "clr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/build/Debug/bin/net471/sparkcmd.exe",
|
||||
"args": [
|
||||
"test",
|
||||
"ApiUpdateTests"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Client Attach",
|
||||
"type": "clr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
},
|
||||
{
|
||||
"name": "Spreader Tests",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[spreader]"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server/",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"preLaunchTask": "",
|
||||
"logging": {
|
||||
"engineLogging": false
|
||||
},
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "enable pretty-printer",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Admin Service Tests",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[admin_service]"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"preLaunchTask": "",
|
||||
"logging": {
|
||||
"engineLogging": false
|
||||
},
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "enable pretty-printer",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Limiter Tests",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[limiter]"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/src/server/sparkd/",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"preLaunchTask": "",
|
||||
"logging": {
|
||||
"engineLogging": false
|
||||
},
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "enable pretty-printer",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "MD Tests",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/bts/spark/build/ninja_debug/server/sparkd",
|
||||
"args": [
|
||||
"test",
|
||||
"[algo]"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server/",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"preLaunchTask": "",
|
||||
"logging": {
|
||||
"engineLogging": false
|
||||
},
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Skip STL",
|
||||
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "SparkVM attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "/home/bts/spark/build/ninja_debug/src/server/sparkd/sparkd",
|
||||
"processId": "${command:pickRemoteProcess}",
|
||||
"MIMode": "gdb",
|
||||
"pipeTransport": {
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/usr/bin/gdb"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Python",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"stopOnEntry": false,
|
||||
"pythonPath": "${config:python.pythonPath}",
|
||||
"program": "${file}",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"env": {},
|
||||
"envFile": "${workspaceRoot}/.env",
|
||||
"args": [
|
||||
"DEBUG"
|
||||
],
|
||||
"debugOptions": [
|
||||
"WaitOnAbnormalExit",
|
||||
"WaitOnNormalExit",
|
||||
"RedirectOutput"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Remote Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickRemoteProcess}",
|
||||
"pipeTransport": {
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/home/bts/vsdbg/vsdbg",
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"quoteArgs": true
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
},
|
||||
"justMyCode": true
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Remote Launch",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "/usr/bin/dotnet",
|
||||
"args": [
|
||||
"sparkcmd.dll",
|
||||
"test",
|
||||
"test_join_create_and_takeout_market"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "/home/bts/spark/build/ninja_debug/server",
|
||||
"pipeTransport": {
|
||||
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
|
||||
"pipeArgs": [
|
||||
"bts@sparkvm"
|
||||
],
|
||||
"debuggerPath": "/home/bts/vsdbg/vsdbg",
|
||||
"pipeCwd": "${workspaceRoot}",
|
||||
"quoteArgs": true
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/home/bts/spark/": "${workspaceRoot}"
|
||||
},
|
||||
"justMyCode": false
|
||||
},
|
||||
]
|
||||
}
|
||||
Vendored
-16
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"utility": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"list": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"vector": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xstring": "cpp",
|
||||
"system_error": "cpp",
|
||||
"array": "cpp",
|
||||
"string_view": "cpp"
|
||||
"xutility": "cpp",
|
||||
"*.ipp": "cpp"
|
||||
}
|
||||
}
|
||||
Vendored
-63
@@ -1,63 +0,0 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "client_build",
|
||||
"type": "shell",
|
||||
"command": ".\\tools\\buildspark.cmd",
|
||||
"problemMatcher":"$msCompile",
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "shared"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "server_build",
|
||||
"type": "shell",
|
||||
"command": ".\\tools\\buildsparkd.cmd",
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
"owner": "cpp",
|
||||
"fileLocation": [
|
||||
"relative",
|
||||
"${workspaceFolder}"
|
||||
],
|
||||
"pattern": {
|
||||
"regexp": "(.?)(home)(.?)(bts)(.?)(spark)(.?)(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)",
|
||||
"file": 8,
|
||||
"line": 9,
|
||||
"column": 10,
|
||||
"severity": 11,
|
||||
"message": 12
|
||||
}
|
||||
},
|
||||
"presentation": {
|
||||
"echo": true,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "new"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "linux build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "cd build/ninja_debug; time ninja",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+9
-25
@@ -12,41 +12,22 @@ set (SPARK_PYTHON "${EXTERNALS_ROOT}/python")
|
||||
set (SPARK_BIN "${EXTERNALS_ROOT}/bin")
|
||||
set (SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
|
||||
set (SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
|
||||
set (BUILD_SDK OFF CACHE BOOL "Build the sdk")
|
||||
|
||||
include_directories (BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
|
||||
link_directories (${SPARK_LIB})
|
||||
|
||||
if (WIN32)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \
|
||||
/MP \
|
||||
/WX /wd4251 /wd4250 /wd4251 /wd4244 /wd4267 /wd4355 /wd4275 /wd4345 \
|
||||
/DCURL_STATICLIB \
|
||||
/D_WINSOCK_DEPRECATED_NO_WARNINGS \
|
||||
/D__TBB_NO_IMPLICIT_LINKAGE \
|
||||
/DBOOST_ALL_NO_LIB \
|
||||
/D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600")
|
||||
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} /MT")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF /LTCG")
|
||||
|
||||
add_subdirectory(src/lib)
|
||||
else ()
|
||||
# so that sparkd looks for libspark.so in its directory
|
||||
set (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
|
||||
set (CMAKE_INSTALL_RPATH ".")
|
||||
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} \
|
||||
-fPIC -Wall -pedantic -Wextra -Werror \
|
||||
-Wno-missing-braces -Wno-ignored-qualifiers \
|
||||
--std=c++17 -fdiagnostics-color")
|
||||
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -DNDEBUG -O3")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wno-undef")
|
||||
# so that sparkd looks for libspark.so in its directory
|
||||
add_subdirectory(src/server/sparkd)
|
||||
add_subdirectory(src/lib)
|
||||
add_subdirectory(src/web)
|
||||
# add_subdirectory(src/web)
|
||||
add_subdirectory(doc/user)
|
||||
add_subdirectory(src/sdk)
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(src/sdk)
|
||||
endif()
|
||||
add_subdirectory(src/data_files)
|
||||
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/server
|
||||
@@ -62,4 +43,7 @@ else ()
|
||||
DEPENDS sparkd data_files_dir)
|
||||
|
||||
add_custom_target(server_layout ALL DEPENDS ${CMAKE_BINARY_DIR}/server)
|
||||
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libACE-5.7.5.so" DESTINATION bin)
|
||||
install(FILES "${CMAKE_SOURCE_DIR}/externals/linux/lib/${CMAKE_BUILD_TYPE}/libOnixS.IceImpactMulticastPriceFeedHandlerCpp.so.3.16.0.0" DESTINATION bin)
|
||||
endif()
|
||||
@@ -0,0 +1,179 @@
|
||||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "spark",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"environment": {
|
||||
"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++17 /D_SCL_SECURE_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600",
|
||||
"DOTNET_TARGET_FRAMEWORK": "net471"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"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_CXX_STANDARD": "17",
|
||||
"CMAKE_SHARED_LINKER_FLAGS_DEBUG": "/DEBUG",
|
||||
"CMAKE_SHARED_LINKER_FLAGS_RELEASE": "/OPT:REF /OPT:ICF /LTCG",
|
||||
"DOTNET_BINARY_DIR": "${sourceDir}/build/$<CONFIG>/bin/$env{DOTNET_TARGET_FRAMEWORK}",
|
||||
"EXTERNALS_ROOT": "${sourceDir}/externals/windows",
|
||||
"SPARK_BIN": "${sourceDir}/externals/windows/bin",
|
||||
"SPARK_INCLUDE": "${sourceDir}/externals/windows/include",
|
||||
"SPARK_LIB": "${sourceDir}/externals/windows/lib/$<CONFIG>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sparkd",
|
||||
"hidden": true,
|
||||
"description": "Sparkd common config",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"generator": "Ninja",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_WITH_INSTALL_RPATH": {
|
||||
"type": "BOOL",
|
||||
"value": true
|
||||
},
|
||||
"CMAKE_CXX_STANDARD": "17",
|
||||
"CMAKE_EXE_LINKER_FLAGS": "-Wno-undef",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install/${presetName}",
|
||||
"CMAKE_INSTALL_RPATH": ".",
|
||||
"EXTERNALS_ROOT": "${sourceDir}/externals/linux",
|
||||
"SPARK_BIN": "${sourceDir}/externals/linux/bin",
|
||||
"SPARK_INCLUDE": "${sourceDir}/externals/linux/include"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sparkd-debug-clang",
|
||||
"displayName": "Debug (clang)",
|
||||
"description": "Debug build compiled w/ clang",
|
||||
"inherits": "sparkd",
|
||||
"binaryDir": "${sourceDir}/build/clang/debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-deprecated-copy -Wno-unused-but-set-variable -Wno-c++17-extensions --std=c++17 -fdiagnostics-color -DDEBUG",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": {
|
||||
"type": "BOOL",
|
||||
"value": true
|
||||
},
|
||||
"SPARK_LIB": "${sourceDir}/externals/linux/lib/Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sparkd-release-clang",
|
||||
"displayName": "Release (clang)",
|
||||
"description": "Release build compiled w/ clang",
|
||||
"binaryDir": "${sourceDir}/build/clang/release",
|
||||
"inherits": "sparkd",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-deprecated-copy -Wno-c++17-extensions --std=c++17 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3",
|
||||
"SPARK_LIB": "${sourceDir}/externals/linux/lib/Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sparkd-debug-gcc",
|
||||
"displayName": "Debug (gcc)",
|
||||
"description": "Debug build compiled w/ gcc",
|
||||
"inherits": "sparkd",
|
||||
"binaryDir": "${sourceDir}/build/gcc/debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "g++",
|
||||
"CMAKE_CXX_FLAGS_DEBUG": "-g -fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-deprecated-copy -Wno-catch-value --std=c++17 -fdiagnostics-color -DDEBUG",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": {
|
||||
"type": "BOOL",
|
||||
"value": true
|
||||
},
|
||||
"SPARK_LIB": "${sourceDir}/externals/linux/lib/Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sparkd-release-gcc",
|
||||
"displayName": "Release (gcc)",
|
||||
"description": "Release build compiled w/ gcc",
|
||||
"inherits": "sparkd",
|
||||
"binaryDir": "${sourceDir}/build/gcc/release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_C_COMPILER": "/usr/local/bin/gcc",
|
||||
"CMAKE_CXX_COMPILER": "/usr/local/bin/g++",
|
||||
"CMAKE_CXX_FLAGS_RELEASE": "-fPIC -Wall -pedantic -Wextra -Werror -Wno-missing-braces -Wno-ignored-qualifiers -Wno-deprecated-copy -Wno-catch-value --std=c++17 -fdiagnostics-color -fno-omit-frame-pointer -DNDEBUG -O3",
|
||||
"SPARK_LIB": "${sourceDir}/externals/linux/lib/Release"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "spark",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "spark-debug",
|
||||
"displayName": "Debug",
|
||||
"inherits": "spark",
|
||||
"configurePreset": "spark",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "spark-release",
|
||||
"displayName": "Release",
|
||||
"inherits": "spark",
|
||||
"configurePreset": "spark",
|
||||
"configuration": "Release"
|
||||
},
|
||||
{
|
||||
"name": "sparkd",
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"name": "sparkd-debug-clang",
|
||||
"configurePreset": "sparkd-debug-clang",
|
||||
"displayName": "Debug (clang)",
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
{
|
||||
"name": "sparkd-debug-gcc",
|
||||
"configurePreset": "sparkd-debug-gcc",
|
||||
"displayName": "Debug (gcc)",
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
{
|
||||
"name": "sparkd-release-clang",
|
||||
"configurePreset": "sparkd-release-clang",
|
||||
"displayName": "Release (clang)",
|
||||
"inherits": "sparkd"
|
||||
},
|
||||
{
|
||||
"name": "sparkd-release-gcc",
|
||||
"configurePreset": "sparkd-release-gcc",
|
||||
"displayName": "Release (gcc)",
|
||||
"inherits": "sparkd"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
set(sources /home/ppinto/Dropbox/bts/spark/doc/user/build.sh;content/_index.md;content/bts_spark/Glossary/_index.md;content/bts_spark/Help/_index.md;content/bts_spark/Help/about_spark.png;content/bts_spark/Help/image39.png;content/bts_spark/Help/image58.png;content/bts_spark/Launcher/_index.md;content/bts_spark/Launcher/image38.png;content/bts_spark/Launcher/image68.png;content/bts_spark/Logging-In-to-the-System/_index.md;content/bts_spark/Logging-In-to-the-System/image3.png;content/bts_spark/Logging-In-to-the-System/image64.png;content/bts_spark/Market/_index.md;content/bts_spark/Market/change_securities.png;content/bts_spark/Market/image11.png;content/bts_spark/Market/image14.png;content/bts_spark/Market/image20.png;content/bts_spark/Market/image21.png;content/bts_spark/Market/image23.png;content/bts_spark/Market/image24.png;content/bts_spark/Market/image34.png;content/bts_spark/Market/image49.png;content/bts_spark/Market/image53.png;content/bts_spark/Market/image66.png;content/bts_spark/Market/image69.png;content/bts_spark/Market/market_view.png;content/bts_spark/Market/settings_icon.png;content/bts_spark/Market/time_and_sales.png;content/bts_spark/My-Windows/_index.md;content/bts_spark/My-Windows/image15.png;content/bts_spark/My-Windows/image16.png;content/bts_spark/My-Windows/image37.png;content/bts_spark/Settings/_index.md;content/bts_spark/Settings/image51.png;content/bts_spark/Settings/image9.png;content/bts_spark/Spreader/_index.md;content/bts_spark/Spreader/image10.png;content/bts_spark/Spreader/image13.png;content/bts_spark/Spreader/image18.png;content/bts_spark/Spreader/image19.png;content/bts_spark/Spreader/image28.png;content/bts_spark/Spreader/image29.png;content/bts_spark/Spreader/image31.png;content/bts_spark/Spreader/image35.png;content/bts_spark/Spreader/image40.png;content/bts_spark/Spreader/image43.png;content/bts_spark/Spreader/image54.png;content/bts_spark/Spreader/image55.png;content/bts_spark/Spreader/image56.png;content/bts_spark/Spreader/image6.png;content/bts_spark/Spreader/image7.png;content/bts_spark/Spreader/image70.png;content/bts_spark/Spreader/image72.png;content/bts_spark/Spreader/image8.png;content/bts_spark/Trading/OrderTypes/index.md;content/bts_spark/Trading/_index.md;content/bts_spark/Trading/algo_studio.png;content/bts_spark/Trading/collapse_all_icon.png;content/bts_spark/Trading/cover_algo_control.png;content/bts_spark/Trading/expand_all_icon.png;content/bts_spark/Trading/image1.png;content/bts_spark/Trading/image17.png;content/bts_spark/Trading/image2.png;content/bts_spark/Trading/image25.png;content/bts_spark/Trading/image27.png;content/bts_spark/Trading/image33.png;content/bts_spark/Trading/image42.png;content/bts_spark/Trading/image44.png;content/bts_spark/Trading/image47.png;content/bts_spark/Trading/image48.png;content/bts_spark/Trading/image5.png;content/bts_spark/Trading/image50.png;content/bts_spark/Trading/image52.png;content/bts_spark/Trading/image57.png;content/bts_spark/Trading/image59.png;content/bts_spark/Trading/image60.png;content/bts_spark/Trading/image61.png;content/bts_spark/Trading/image62.png;content/bts_spark/Trading/image73.png;content/bts_spark/Trading/image74.png;content/bts_spark/Trading/join_algo_control.png;content/bts_spark/Trading/ladder.png;content/bts_spark/Trading/ladder_badges.png;content/bts_spark/Trading/ladder_main_part.png;content/bts_spark/Trading/lean_algo_control.png;content/bts_spark/Trading/mini_orderbook.png;content/bts_spark/Trading/oco_algo_control.png;content/bts_spark/Trading/offset_algo_control.png;content/bts_spark/Trading/pnl_calculation.png;content/bts_spark/Trading/pnl_window.png;content/bts_spark/Trading/recreate_icon.png;content/bts_spark/Trading/settings_icon.png;content/bts_spark/Trading/spark_menu_order_book.png;content/bts_spark/Trading/top_algo_control.png;content/bts_spark/Trading/trigger_algo_control.png;content/bts_spark/_index.md;content/release_notes/_index.md;content/system_requirements/_index.md;static/book.js;static/favicon.ico;static/image.js;templates/index.html;templates/page.html;templates/section.html;templates/shortcodes/back_button.html)
|
||||
+1
-1
Submodule docker/linux updated: 6f0dd9324b...26de8f7b3b.
+1
-1
Submodule externals updated: 2ea5e355a6...e9120dabfe.
@@ -0,0 +1,17 @@
|
||||
astroid==2.7.3
|
||||
autopep8==1.5.7
|
||||
cffi==1.14.6
|
||||
colorama==0.4.4
|
||||
isort==5.9.3
|
||||
lazy-object-proxy==1.6.0
|
||||
mccabe==0.6.1
|
||||
platformdirs==2.3.0
|
||||
protobuf==3.19.1
|
||||
pybars3==0.9.7
|
||||
pycodestyle==2.7.0
|
||||
pycparser==2.20
|
||||
pylint==2.10.2
|
||||
PyMeta3==0.5.1
|
||||
toml==0.10.2
|
||||
wrapt==1.12.1
|
||||
yapf==0.31.0
|
||||
+168
-232
@@ -1,232 +1,168 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2024
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libspark", "build\src\lib\libspark.vcxproj", "{3335AAF0-489D-359D-8305-9B7A44E2C760}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\sparkcmd\sparkcmd.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "build\ZERO_CHECK.vcxproj", "{2256015B-E7D5-3614-8F39-814CA68A4444}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760} = {3335AAF0-489D-359D-8305-9B7A44E2C760}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_excel", "src\client\spark_excel\spark_excel.csproj", "{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
MinSizeRel|Any CPU = MinSizeRel|Any CPU
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
MinSizeRel|x86 = MinSizeRel|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
RelWithDebInfo|Any CPU = RelWithDebInfo|Any CPU
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
RelWithDebInfo|x86 = RelWithDebInfo|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Debug|x64.Build.0 = Debug|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Release|x64.ActiveCfg = Release|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Release|x64.Build.0 = Release|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.Release|x86.ActiveCfg = Release|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{3335AAF0-489D-359D-8305-9B7A44E2C760}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x86.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|x64.Build.0 = Debug|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.MinSizeRel|x86.ActiveCfg = MinSizeRel|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|x64.ActiveCfg = Release|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|x64.Build.0 = Release|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.Release|x86.ActiveCfg = Release|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
|
||||
{2256015B-E7D5-3614-8F39-814CA68A4444}.RelWithDebInfo|x86.ActiveCfg = RelWithDebInfo|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x86.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x86.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Debug|x64.Build.0 = Debug|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Release|x64.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Release|x64.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.Release|x86.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{BE9F27C3-B583-47DF-95FA-1F8BBC89DCCB}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2024
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_api", "src\client\spark_api\spark_api.csproj", "{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spark", "src\client\spark\Spark.csproj", "{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sparkcmd", "src\client\sparkcmd\sparkcmd.csproj", "{387566C6-C6F6-412C-A30C-9855BBCB4816}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_core", "src\client\spark_core\spark_core.csproj", "{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_sdk", "src\client\spark_sdk\spark_sdk.csproj", "{6963C314-83C4-4667-B0D0-C2F7AE208C29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "spark_test", "src\client\spark_test\spark_test.csproj", "{ECD78CC5-138F-4809-A764-2358C2AC2E82}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
MinSizeRel|Any CPU = MinSizeRel|Any CPU
|
||||
MinSizeRel|x64 = MinSizeRel|x64
|
||||
MinSizeRel|x86 = MinSizeRel|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
RelWithDebInfo|Any CPU = RelWithDebInfo|Any CPU
|
||||
RelWithDebInfo|x64 = RelWithDebInfo|x64
|
||||
RelWithDebInfo|x86 = RelWithDebInfo|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.Release|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{DC9A8975-8211-4FC9-A9BA-C8B9D26AD481}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.Release|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{9A4D4D07-1AB6-4B2B-B111-A4F34D6C267E}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x64.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.Release|x86.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
|
||||
{387566C6-C6F6-412C-A30C-9855BBCB4816}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x64.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.Release|x86.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6E449EB6-20AC-4FA6-B8D9-10F4BB7E1FEE}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x64.Build.0 = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|Any CPU.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|Any CPU.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x86.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.MinSizeRel|x86.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.Release|x86.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|Any CPU.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|Any CPU.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x64.Build.0 = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x86.ActiveCfg = Release|x64
|
||||
{6963C314-83C4-4667-B0D0-C2F7AE208C29}.RelWithDebInfo|x86.Build.0 = Release|x64
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x64.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x86.ActiveCfg = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.MinSizeRel|x86.Build.0 = Debug|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x64.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.Release|x86.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x86.ActiveCfg = Release|Any CPU
|
||||
{ECD78CC5-138F-4809-A764-2358C2AC2E82}.RelWithDebInfo|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {422D1620-0166-4C26-9A81-CA8A2EB1AB58}
|
||||
EndGlobalSection
|
||||
GlobalSection(Performance) = preSolution
|
||||
HasPerformanceSessions = true
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,193 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using AlgoType = bts.api.orderman.CustomOrderDefinition.CustomOneofCase;
|
||||
|
||||
namespace mbts.spark {
|
||||
class AlgoProviderFactory {
|
||||
[ImportingConstructor]
|
||||
AlgoProviderFactory(IAlgoStudioModel studio_model, DynamicOrderHelper dynamic_helper, ISecurityAuxiliaryDataModel security_auxiliary_model) {
|
||||
var from_conf = config.Configuration.get<bts.config.AlgoTypeRuleSet>();
|
||||
if (from_conf.rules.Count == 0) {
|
||||
// There seems to be a config race bug, where the returned config values are empty, despite having entries in spark.conf.
|
||||
// [John]I've only noticed it happen when attached to the debugger,
|
||||
// but best to have a contingency plan in place anyways, to prevent any chance of regression.
|
||||
// The fallback sets below mimic the old hardcoded algo type arrays.
|
||||
var full_algo_set = new AlgoTypeSetImmutable(
|
||||
ImmutableHashSet.CreateRange(EnumHelper.get_values_except(
|
||||
// non-factory algos
|
||||
AlgoType.None,
|
||||
AlgoType.Dynamic,
|
||||
AlgoType.Composite,
|
||||
// obsolete algos
|
||||
AlgoType.Oco,
|
||||
AlgoType.TimeBox,
|
||||
AlgoType.Pricer,
|
||||
AlgoType.Tick,
|
||||
AlgoType.Trigger,
|
||||
AlgoType.QueueHolder)),
|
||||
ImmutableHashSet.CreateRange(dynamic_helper.dynamic_types));
|
||||
var rules = new[] {
|
||||
// Glbx: Futures/Spreads
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
new SecurityCriteriaClause(
|
||||
exchanges: new[] { Venue.Glbx },
|
||||
security_types: new[] { SecurityType.Future, SecurityType.Spread }),
|
||||
new AlgoTypeSetImmutable(
|
||||
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader }),
|
||||
full_algo_set.dynamic_types)),
|
||||
// Gen: Futures/Spreads
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
new SecurityCriteriaClause(
|
||||
exchanges: EnumHelper.get_values_except(Venue.Glbx, Venue.Unset).ToArray(),
|
||||
security_types: new[] { SecurityType.Future, SecurityType.Spread }),
|
||||
new AlgoTypeSetImmutable(
|
||||
full_algo_set.factory_types.Except(new[] { AlgoType.Spreader, AlgoType.GlbxIceberg }),
|
||||
full_algo_set.dynamic_types)),
|
||||
// Gen: Synthetics
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
new SecurityCriteriaClause(
|
||||
security_types: new[] { SecurityType.Synthetic }),
|
||||
new AlgoTypeSetImmutable(
|
||||
ImmutableHashSet.CreateRange(new[] {
|
||||
AlgoType.Spreader,
|
||||
AlgoType.Iceberg,
|
||||
AlgoType.Lean,
|
||||
AlgoType.Join,
|
||||
AlgoType.Cover,
|
||||
AlgoType.Offset,
|
||||
AlgoType.Top,
|
||||
AlgoType.Splitter,
|
||||
AlgoType.Scratch,
|
||||
AlgoType.Prorata
|
||||
}),
|
||||
full_algo_set.dynamic_types))
|
||||
};
|
||||
// attachable
|
||||
var attachable_algos =
|
||||
ImmutableHashSet.CreateRange(new[] {
|
||||
AlgoType.Iceberg,
|
||||
AlgoType.Lean,
|
||||
AlgoType.Join,
|
||||
AlgoType.Cover,
|
||||
AlgoType.Top,
|
||||
AlgoType.Offset,
|
||||
AlgoType.Scratch,
|
||||
AlgoType.Prorata
|
||||
});
|
||||
var attachable_rules = Array.ConvertAll(rules,
|
||||
satsi => new SecurityAlgoTypeSetImmutable(
|
||||
satsi.security_criteria,
|
||||
new AlgoTypeSetImmutable(
|
||||
satsi.algo_type_set.factory_types.Intersect(attachable_algos),
|
||||
satsi.algo_type_set.dynamic_types)));
|
||||
|
||||
Log.Config.warn($"Failed to load AlgoTypes config, falling back to the following algo set rules:" +
|
||||
"\n\tStandard\n" +
|
||||
rules.fmt_diagnostic("\n\t\t") +
|
||||
"\n\n\tAttachable\n" +
|
||||
attachable_rules.fmt_diagnostic("\n\t\t"));
|
||||
|
||||
security_algo_provider = new AlgoProvider(rules, studio_model, dynamic_helper, security_auxiliary_model);
|
||||
attachable_algo_provider = new AttachableAlgoProvider(attachable_rules, studio_model, dynamic_helper, security_auxiliary_model);
|
||||
} else {
|
||||
var algo_type_data =
|
||||
EnumHelper.get_values_except(AlgoType.Dynamic, AlgoType.Composite, AlgoType.None)
|
||||
.Select(t => _get_type_data(t))
|
||||
.Concat(dynamic_helper.dynamic_types.Select(dt => _get_type_data(AlgoType.Dynamic, dt)))
|
||||
.ToListLazy();
|
||||
var conf_sets = from_conf.rules.Select(r => _to_security_algo_set(r, dynamic_helper, algo_type_data)).ToList();
|
||||
security_algo_provider = new AlgoProvider(conf_sets.Select(tup => tup.standard).ToList(), studio_model, dynamic_helper, security_auxiliary_model);
|
||||
attachable_algo_provider = new AttachableAlgoProvider(conf_sets.Select(tup => tup.attachable).ToList(), studio_model, dynamic_helper, security_auxiliary_model);
|
||||
}
|
||||
}
|
||||
|
||||
[Export]
|
||||
public IAlgoProvider security_algo_provider { get; }
|
||||
[Export]
|
||||
public IAttachableAlgoProvider attachable_algo_provider { get; }
|
||||
|
||||
static (string name, AlgoType factory, string dynamic) _get_type_data(AlgoType type, string dynamic_type = null) {
|
||||
string type_name = type.ToString();
|
||||
return (type_name, type, dynamic_type ?? type_name);
|
||||
}
|
||||
|
||||
static SecurityCriteriaClause _to_clause(bts.config.AlgoTypeContext context) =>
|
||||
context == null ?
|
||||
new SecurityCriteriaClause() :
|
||||
new SecurityCriteriaClause(
|
||||
exchanges: context.exchanges?.Select(EnumHelper.parse<Venue>)?.ToArray(),
|
||||
security_types: context.security_types?.Select(EnumHelper.parse<Security.ContractOneofCase>)?.Select(t => t.security_type())?.ToArray(),
|
||||
symbols: context.symbols?.ToArray());
|
||||
|
||||
static (SecurityAlgoTypeSetImmutable standard, SecurityAlgoTypeSetImmutable attachable) _to_security_algo_set(
|
||||
bts.config.AlgoTypeRule rule,
|
||||
DynamicOrderHelper dynamic_helper,
|
||||
IEnumerable<(string name, AlgoType factory, string dynamic)> algo_type_data) {
|
||||
//
|
||||
var factory_types = ImmutableHashSet<AlgoType>.Empty.ToBuilder();
|
||||
var dynamic_types = ImmutableHashSet<string>.Empty.ToBuilder();
|
||||
var attachable_factory_types = ImmutableHashSet<AlgoType>.Empty.ToBuilder();
|
||||
var attachable_dynamic_types = ImmutableHashSet<string>.Empty.ToBuilder();
|
||||
foreach (var a in rule.algos) {
|
||||
if (Enum.TryParse(a.name, out AlgoType sys_algo) && sys_algo != AlgoType.Composite && sys_algo != AlgoType.Dynamic) {
|
||||
on_sys_match(sys_algo, a.is_attachable);
|
||||
}
|
||||
else if (dynamic_helper.try_parse(a.name, out var dyn_type)) {
|
||||
on_dyn_match(dyn_type, a.is_attachable);
|
||||
} else {
|
||||
foreach (var (name, factory, dynamic) in algo_type_data) {
|
||||
if (Regex.Match(name, a.name).Success) {
|
||||
switch (factory) {
|
||||
case AlgoType.None:
|
||||
case AlgoType.Composite:
|
||||
// unexpected, but no need to crash
|
||||
continue;
|
||||
case AlgoType.Dynamic:
|
||||
on_dyn_match(dynamic, a.is_attachable);
|
||||
break;
|
||||
default:
|
||||
on_sys_match(factory, a.is_attachable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
// standard
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
_to_clause(rule.context),
|
||||
new AlgoTypeSetImmutable(
|
||||
factory_types.ToImmutable(),
|
||||
dynamic_types.ToImmutable())),
|
||||
// attachable
|
||||
new SecurityAlgoTypeSetImmutable(
|
||||
_to_clause(rule.context),
|
||||
new AlgoTypeSetImmutable(
|
||||
attachable_factory_types.ToImmutable(),
|
||||
attachable_dynamic_types.ToImmutable())));
|
||||
|
||||
// local methods
|
||||
void on_sys_match(AlgoType sys_algo, bool is_attachable) {
|
||||
factory_types.Add(sys_algo);
|
||||
if (is_attachable)
|
||||
attachable_factory_types.Add(sys_algo);
|
||||
}
|
||||
void on_dyn_match(string dyn_algo, bool is_attachable) {
|
||||
dynamic_types.Add(dyn_algo);
|
||||
if (is_attachable)
|
||||
attachable_dynamic_types.Add(dyn_algo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using AlgoType = bts.api.orderman.CustomOrderDefinition.CustomOneofCase;
|
||||
|
||||
namespace mbts.spark {
|
||||
readonly struct AlgoTypeSetImmutable {
|
||||
public static readonly AlgoTypeSetImmutable empty = new AlgoTypeSetImmutable(ImmutableHashSet<AlgoType>.Empty, ImmutableHashSet<string>.Empty);
|
||||
public readonly ImmutableHashSet<AlgoType> factory_types;
|
||||
public readonly ImmutableHashSet<string> dynamic_types;
|
||||
|
||||
public AlgoTypeSetImmutable(
|
||||
ImmutableHashSet<AlgoType> factory_types,
|
||||
ImmutableHashSet<string> dynamic_types) {
|
||||
this.factory_types = factory_types;
|
||||
this.dynamic_types = dynamic_types;
|
||||
}
|
||||
}
|
||||
|
||||
readonly struct SecurityAlgoTypeSetImmutable {
|
||||
public readonly SecurityCriteriaClause security_criteria;
|
||||
public readonly AlgoTypeSetImmutable algo_type_set;
|
||||
|
||||
public SecurityAlgoTypeSetImmutable(SecurityCriteriaClause security_criteria, AlgoTypeSetImmutable algo_type_set, CustomOrderDefinitionImmutable? default_algo = null) {
|
||||
this.security_criteria = security_criteria;
|
||||
this.algo_type_set = algo_type_set;
|
||||
}
|
||||
}
|
||||
|
||||
static class AlgoTypeSetExtensions {
|
||||
public static string fmt_diagnostic(this IEnumerable<SecurityAlgoTypeSetImmutable> rules, string line_delim = "\n") {
|
||||
var sb = new StringBuilder();
|
||||
int rule_count = 1;
|
||||
using (var en = rules.GetEnumerator()) {
|
||||
if (en.MoveNext()) {
|
||||
string line_delim_tab1 = line_delim + "\t";
|
||||
string line_delim_tab2 = line_delim + "\t\t";
|
||||
append_rule(en.Current);
|
||||
while (en.MoveNext()) {
|
||||
sb.AppendLine();
|
||||
append_rule(en.Current);
|
||||
}
|
||||
//
|
||||
void append_rule(SecurityAlgoTypeSetImmutable r) {
|
||||
sb.Append(line_delim + $"**RULE {rule_count++}**");
|
||||
sb.Append(line_delim_tab1);
|
||||
sb.Append("Security Criteria: ");
|
||||
sb.Append(r.security_criteria.is_defined ? string.Join("; ", r.security_criteria.fmt_diagnostic_msgs()) : "(Undefined)");
|
||||
sb.Append(line_delim_tab1);
|
||||
// Factory
|
||||
sb.Append("Factory Types:");
|
||||
sb.Append(line_delim_tab2);
|
||||
sb.Append(string.Join(line_delim_tab2, r.algo_type_set.factory_types));
|
||||
sb.Append(line_delim_tab1);
|
||||
// Dynamic
|
||||
sb.Append("Dynamic Types:");
|
||||
sb.Append(line_delim_tab2);
|
||||
sb.Append(string.Join(line_delim_tab2, r.algo_type_set.dynamic_types));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static AlgoTypeSetImmutable intersect_with(this AlgoTypeSetImmutable a, AlgoTypeSetImmutable b) =>
|
||||
new AlgoTypeSetImmutable(a.factory_types.Intersect(b.factory_types), a.dynamic_types.Intersect(b.dynamic_types));
|
||||
|
||||
public static AlgoTypeSetImmutable union_with(this AlgoTypeSetImmutable a, AlgoTypeSetImmutable b) =>
|
||||
new AlgoTypeSetImmutable(a.factory_types.Union(b.factory_types), a.dynamic_types.Union(b.dynamic_types));
|
||||
|
||||
public static IEnumerable<AlgoData> define_algos(
|
||||
this AlgoTypeSetImmutable algo_set,
|
||||
DynamicOrderHelper dynamic_helper,
|
||||
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
|
||||
uint display_qty_divisor = 1) =>
|
||||
//
|
||||
algo_set.factory_types
|
||||
.Select(algo_type => {
|
||||
var def = OrderDataHelper.Defaults.CustomOrderDefinitionImmutable(algo_type);
|
||||
if (fit_to_type != null)
|
||||
def = fit_to_type(def);
|
||||
// multiply quantity props by display qty divisor to get appropriate actual value
|
||||
if (display_qty_divisor > 1) {
|
||||
switch (def.CustomCase) {
|
||||
case AlgoType.Iceberg:
|
||||
var mdef = def.CloneToMutable();
|
||||
mdef.Iceberg.ShowQuantity *= display_qty_divisor;
|
||||
def = new CustomOrderDefinitionImmutable(mdef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
})
|
||||
.Concat(algo_set.dynamic_types.Select(dynamic_helper.create_custom_defi))
|
||||
.Select(AlgoData.from_custom_def);
|
||||
|
||||
public static ImmutableDictionary<AlgoKey, AlgoData> match_algos(
|
||||
this IEnumerable<SecurityAlgoTypeSetImmutable> security_algo_sets,
|
||||
SecurityCriteriaClause clause,
|
||||
DynamicOrderHelper dynamic_helper,
|
||||
Func<CustomOrderDefinitionImmutable, CustomOrderDefinitionImmutable> fit_to_type = null,
|
||||
uint display_qty_divisor = 1) {
|
||||
//
|
||||
ImmutableDictionary<AlgoKey, AlgoData> rv = null;
|
||||
foreach (var set in security_algo_sets) {
|
||||
if (!clause.is_subset_of(set.security_criteria)) {
|
||||
continue;
|
||||
} else if (rv == null) {
|
||||
rv = ImmutableDictionary.CreateRange(
|
||||
set.algo_type_set.define_algos(dynamic_helper, fit_to_type, display_qty_divisor)
|
||||
.Select(a => new KeyValuePair<AlgoKey, AlgoData>(a.key, a)));
|
||||
} else {
|
||||
foreach (var kv in rv) {
|
||||
if (kv.Value.value.CustomCase == AlgoType.Dynamic) {
|
||||
if (!set.algo_type_set.dynamic_types.Contains(kv.Value.value.Dynamic.DynamicOrderType))
|
||||
rv = rv.Remove(kv.Key);
|
||||
} else if (!set.algo_type_set.factory_types.Contains(kv.Value.value.CustomCase))
|
||||
rv = rv.Remove(kv.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv ?? ImmutableDictionary<AlgoKey, AlgoData>.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using bts.utils;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui.utility;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace mbts.spark {
|
||||
interface IAlgoProvider {
|
||||
AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security);
|
||||
AlgoTypeSetImmutable get_permitted_algos(SecurityCriteriaClause clause);
|
||||
IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos();
|
||||
IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityImmutable security);
|
||||
IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityCriteriaClause clause);
|
||||
}
|
||||
|
||||
// This interface is used to distinguish the attachable algo provider
|
||||
// from the standard one wrt MEF export/import.
|
||||
interface IAttachableAlgoProvider : IAlgoProvider { }
|
||||
|
||||
class AlgoProvider : IAlgoProvider {
|
||||
readonly IEnumerable<SecurityAlgoTypeSetImmutable> _security_algo_types;
|
||||
readonly IAlgoStudioModel _studio_model;
|
||||
readonly ISecurityAuxiliaryDataModel _security_auxiliary_model;
|
||||
readonly IObservable<TableUpdate<AlgoData, AlgoKey>> _studio_algos_source;
|
||||
readonly DynamicOrderHelper _dynamic_helper;
|
||||
readonly AlgoTypeSetImmutable _full_set;
|
||||
|
||||
public AlgoProvider(IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets, IAlgoStudioModel studio_model, DynamicOrderHelper dynamic_helper, ISecurityAuxiliaryDataModel security_auxiliary_model) {
|
||||
_security_algo_types = algo_sets;
|
||||
_studio_model = studio_model;
|
||||
_dynamic_helper = dynamic_helper;
|
||||
_full_set = new AlgoTypeSetImmutable(
|
||||
ImmutableHashSet.CreateRange(
|
||||
EnumHelper.get_values_except(CustomOrderDefinition.CustomOneofCase.None, CustomOrderDefinition.CustomOneofCase.Dynamic, CustomOrderDefinition.CustomOneofCase.Composite)),
|
||||
ImmutableHashSet.CreateRange(dynamic_helper.dynamic_types));
|
||||
_security_auxiliary_model = security_auxiliary_model;
|
||||
/// initialize <see cref="_studio_algos_source"/> with an empty table, so the
|
||||
/// <see cref="UpdateExtensions.AppendTable{T, TKey}(IObservable{TableUpdate{T, TKey}}, IEnumerable{T})"/>
|
||||
/// calls made by the 'subscribe_algos' methods will fire at least once, even if the underlying
|
||||
/// studio algos stream is empty have been created (this would be the case if the user had not yet created any studio algos).
|
||||
/// <see cref="subscribe_algos"/>,
|
||||
/// <see cref="subscribe_algos(SecurityCriteriaClause)"/>,
|
||||
/// <see cref="subscribe_algos(SecurityImmutable)"/>
|
||||
_studio_algos_source = studio_model.definitions
|
||||
.StartWith(TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn))
|
||||
.Cache();
|
||||
}
|
||||
|
||||
public AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security) =>
|
||||
_security_algo_types.Where(p => p.security_criteria.includes(security))
|
||||
.Select(sec_algos => sec_algos.algo_type_set)
|
||||
.Aggregate(_full_set, (result, algos) => result.intersect_with(algos));
|
||||
|
||||
public AlgoTypeSetImmutable get_permitted_algos(SecurityCriteriaClause clause) =>
|
||||
_security_algo_types.Where(p => p.security_criteria.is_subset_of(clause))
|
||||
.Select(sec_algos => sec_algos.algo_type_set)
|
||||
.Aggregate(_full_set, (result, algos) => result.intersect_with(algos));
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos() =>
|
||||
_studio_algos_source
|
||||
.AppendTable(_security_algo_types
|
||||
.Select(s => s.algo_type_set)
|
||||
.Aggregate(AlgoTypeSetImmutable.empty, (a, b) => a.union_with(b))
|
||||
.define_algos(_dynamic_helper));
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityCriteriaClause security_clause) {
|
||||
var system_algos = _security_algo_types.match_algos(
|
||||
security_clause,
|
||||
_dynamic_helper,
|
||||
def => _fit_to_type(def, security_clause, _security_algo_types));
|
||||
|
||||
return _studio_algos_source.Select(
|
||||
a => (algo: a, fitted_def: _fit_to_type(a.value, security_clause, _security_algo_types)),
|
||||
tup => tup.algo.key)
|
||||
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), a => a.key)
|
||||
.AppendTable(system_algos.Values);
|
||||
}
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityImmutable security) {
|
||||
var clause = new SecurityCriteriaClause(
|
||||
exchanges: new[] { security.Exchange },
|
||||
security_types: new[] { security.security_type() });
|
||||
// i.e., non-studio algos
|
||||
var system_algos = _security_algo_types.match_algos(
|
||||
clause,
|
||||
_dynamic_helper,
|
||||
def => _fit_to_type(def, security, _security_algo_types),
|
||||
_security_auxiliary_model.get_display_quantity_divisor(security));
|
||||
|
||||
return _studio_algos_source.Select(
|
||||
a => (algo: a, fitted_def: _fit_to_type(a.value, security, _security_algo_types)),
|
||||
tup => tup.algo.key)
|
||||
// filter out algos that use an unsupported root, because this would have the effect of duplicating the default algo
|
||||
// (e.g., GlbxIceberg orders would be converted to Limit/Spreader orders for non-Glbx securities).
|
||||
.Filter(tup => tup.fitted_def.actual().CustomCase == tup.algo.value.actual().CustomCase, tup => tup.algo.key)
|
||||
.Select(tup => AlgoData.create(tup.fitted_def, tup.algo.name, tup.algo.key), AlgoData.key_fn)
|
||||
.AppendTable(system_algos.Values);
|
||||
}
|
||||
|
||||
protected virtual void assign_fallback_algo(CustomOrderDefinition mdef, SecurityCriteriaClause security_clause) {
|
||||
if (security_clause.security_types.empty_if_null().Contains(Security.ContractOneofCase.Synthetic.security_type())) {
|
||||
mdef.Spreader = new SpreaderOrderDefinition();
|
||||
} else {
|
||||
mdef.Limit = new LimitOrderDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void assign_fallback_algo(CustomOrderDefinition mdef, SecurityImmutable security) {
|
||||
if (security.ContractCase == Security.ContractOneofCase.Synthetic) {
|
||||
mdef.Spreader = new SpreaderOrderDefinition {
|
||||
Security = security.CloneToMutable()
|
||||
};
|
||||
} else {
|
||||
mdef.Limit = new LimitOrderDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
CustomOrderDefinitionImmutable _fit_to_type(CustomOrderDefinitionImmutable defi, SecurityCriteriaClause security_clause, IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets) {
|
||||
var mroot = defi.CloneToMutable();
|
||||
if (_fit_to_type(mroot, security_clause, algo_sets)) {
|
||||
defi = new CustomOrderDefinitionImmutable(mroot);
|
||||
}
|
||||
return defi;
|
||||
}
|
||||
|
||||
CustomOrderDefinitionImmutable _fit_to_type(CustomOrderDefinitionImmutable defi, SecurityImmutable security, IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets) {
|
||||
var mroot = defi.CloneToMutable();
|
||||
if (_fit_to_type(mroot, security, algo_sets)) {
|
||||
defi = new CustomOrderDefinitionImmutable(mroot);
|
||||
}
|
||||
return defi;
|
||||
}
|
||||
|
||||
bool _fit_to_type(CustomOrderDefinition mdef, SecurityCriteriaClause security_clause, IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets) {
|
||||
while (mdef.CustomCase == CustomOrderDefinition.CustomOneofCase.Composite)
|
||||
mdef = mdef.Composite.Definition;
|
||||
var sec_sets = algo_sets.Where(s => security_clause.is_subset_of(s.security_criteria));
|
||||
if (mdef.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic) {
|
||||
if (!algo_sets.All(s => s.algo_type_set.dynamic_types.Contains(mdef.Dynamic.DynamicOrderType))) {
|
||||
assign_fallback_algo(mdef, security_clause);
|
||||
return true;
|
||||
}
|
||||
} else if (!sec_sets.All(s => s.algo_type_set.factory_types.Contains(mdef.CustomCase))) {
|
||||
assign_fallback_algo(mdef, security_clause);
|
||||
return true;
|
||||
}
|
||||
return OrderDataHelper.get_child_algo_data(mdef).Count(cad => _fit_to_type(cad.get_child(mdef), security_clause, algo_sets)) > 0;
|
||||
}
|
||||
|
||||
bool _fit_to_type(CustomOrderDefinition mdef, SecurityImmutable security, IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets) {
|
||||
while (mdef.CustomCase == CustomOrderDefinition.CustomOneofCase.Composite)
|
||||
mdef = mdef.Composite.Definition;
|
||||
var sec_sets = algo_sets.Where(s => s.security_criteria.includes(security));
|
||||
if (mdef.CustomCase == CustomOrderDefinition.CustomOneofCase.Dynamic) {
|
||||
if (!sec_sets.All(s => s.algo_type_set.dynamic_types.Contains(mdef.Dynamic.DynamicOrderType))) {
|
||||
assign_fallback_algo(mdef, security);
|
||||
return true;
|
||||
}
|
||||
} else if (!sec_sets.All(s => s.algo_type_set.factory_types.Contains(mdef.CustomCase))) {
|
||||
assign_fallback_algo(mdef, security);
|
||||
return true;
|
||||
}
|
||||
return OrderDataHelper.get_child_algo_data(mdef).Count(cad => _fit_to_type(cad.get_child(mdef), security, algo_sets)) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
class AttachableAlgoProvider : AlgoProvider, IAttachableAlgoProvider {
|
||||
public AttachableAlgoProvider(IEnumerable<SecurityAlgoTypeSetImmutable> algo_sets, IAlgoStudioModel studio_model, DynamicOrderHelper dynamic_helper, ISecurityAuxiliaryDataModel security_auxiliary_model)
|
||||
: base(algo_sets, studio_model, dynamic_helper, security_auxiliary_model) { }
|
||||
|
||||
// arbitrarily assign LimitOrderDefinition (this is just a placeholder; the real child is the attach target algo).
|
||||
// Note: although 'None' might seem approrpriate, the server requires a valid definition (perhaps this will change in the future).
|
||||
protected override void assign_fallback_algo(CustomOrderDefinition mdef, SecurityCriteriaClause security_clause) =>
|
||||
mdef.Limit = new LimitOrderDefinition();
|
||||
|
||||
// arbitrarily assign LimitOrderDefinition (this is just a placeholder; the real child is the attach target algo).
|
||||
// Note: although 'None' might seem approrpriate, the server requires a valid definition (perhaps this will change in the future).
|
||||
protected override void assign_fallback_algo(CustomOrderDefinition mdef, SecurityImmutable security) =>
|
||||
mdef.Limit = new LimitOrderDefinition();
|
||||
}
|
||||
|
||||
static class AlgoProviderExtensions {
|
||||
// This stream filters out composite algos that are not subsets of the non-composite algo types in the table
|
||||
// (normally, such composites are 'auto-fit,' meaning the algo nodes that are not part of the set are replaced with ones that are).
|
||||
// For example, consider a composite algo the following structure: Offset -> GlbxIceberg.
|
||||
// If an update arrives with these noncomposite types: "Iceberg, Limit, Market," that composite algo is not a subset of the non-composite algo types,
|
||||
// because GlbxIceberg is not in the table, so it would only be added to the table if/when GlbxIceberg arrives.
|
||||
public static IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_complete_algos(this IAlgoProvider algo_provider, bool allow_undefined_child = false) =>
|
||||
subscribe_complete_algos(algo_provider.subscribe_algos(), allow_undefined_child);
|
||||
|
||||
public static IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_complete_algos(IObservable<TableUpdate<AlgoData, AlgoKey>> source, bool allow_undefined_child = false) =>
|
||||
Observable.Create<TableUpdate<AlgoData, AlgoKey>>(o => {
|
||||
var last_out = TableUpdate<AlgoData, AlgoKey>.mk_empty(AlgoData.key_fn);
|
||||
var incomplete_composites = ImmutableHashSet<AlgoData>.Empty;
|
||||
return source.Subscribe(table => {
|
||||
var bd = last_out.to_builder();
|
||||
foreach (var algo in incomplete_composites.Where(a => _validate_algo_structure(a.value, table.state, allow_undefined_child))) {
|
||||
incomplete_composites = incomplete_composites.Remove(algo);
|
||||
bd.add_or_update(algo);
|
||||
}
|
||||
foreach (var a in table.removed.Concat(table.changes.Old()))
|
||||
bd.remove(a.key);
|
||||
foreach (var a in table.added.Concat(table.changed)) {
|
||||
if (_validate_algo_structure(a.value, table.state, allow_undefined_child)) {
|
||||
bd.add_or_update(a);
|
||||
} else {
|
||||
incomplete_composites = incomplete_composites.Add(a);
|
||||
}
|
||||
}
|
||||
o.OnNext(last_out = bd.to_table());
|
||||
});
|
||||
});
|
||||
|
||||
static bool _validate_algo_structure(CustomOrderDefinitionImmutable custom_def, IReadOnlyDictionary<AlgoKey, AlgoData> allowed_algo_parts, bool allow_undefined_child) =>
|
||||
OrderDataHelper.enumerate_algo_structure(custom_def)
|
||||
.Select((algo_node, index) =>
|
||||
// None is an acceptable algo type as long as it's not the root algo (i.e., index > 0)
|
||||
(index > 0 && allow_undefined_child && algo_node.type == CustomOrderDefinition.CustomOneofCase.None) || _is_part_contained(algo_node, allowed_algo_parts))
|
||||
.All();
|
||||
|
||||
static bool _is_part_contained((CustomOrderDefinition.CustomOneofCase type, string dyn, uint studio_id, uint spreader_sec) structure, IReadOnlyDictionary<AlgoKey, AlgoData> state) =>
|
||||
structure.type == CustomOrderDefinition.CustomOneofCase.Composite ||
|
||||
structure.type == CustomOrderDefinition.CustomOneofCase.Dynamic ?
|
||||
state.ContainsKey(AlgoKey.from_dynamic_type(structure.dyn)) :
|
||||
state.ContainsKey(AlgoKey.from_known_type(structure.type));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using bts.api;
|
||||
using bts.co2;
|
||||
using bts.utils;
|
||||
using bts.utils.csv;
|
||||
using mbts;
|
||||
using mbts.spark;
|
||||
using mbts.ui.controls;
|
||||
@@ -49,6 +50,18 @@ namespace bts.shell.time_and_sales {
|
||||
public void raise_invalidated() =>
|
||||
invalidated?.Invoke();
|
||||
|
||||
public static System.Collections.Specialized.OrderedDictionary csv_ordered_properties =>
|
||||
CsvHelper.create_ordering_maintainer(
|
||||
typeof(TimeAndSalesRowVM),
|
||||
new string[] {
|
||||
nameof(security),
|
||||
nameof(time),
|
||||
nameof(price),
|
||||
nameof(size),
|
||||
nameof(aggressor_side),
|
||||
nameof(security_key),
|
||||
});
|
||||
|
||||
public bool Equals(TimeAndSalesRowVM other) =>
|
||||
other != null &&
|
||||
row_key == other.row_key;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using bts.shell.fills;
|
||||
using bts.spark;
|
||||
using bts.view;
|
||||
using bts.utils.csv;
|
||||
using mbts;
|
||||
using mbts.co2;
|
||||
using mbts.persist;
|
||||
@@ -124,6 +125,8 @@ namespace bts.shell.time_and_sales {
|
||||
show_in_context_menu = _can_pause_updates
|
||||
};
|
||||
_commands = new SparkCommand[] {
|
||||
// csv export
|
||||
new SparkCommandCommand("Export to csv", Icons.Export, FileDialogCommand.export_csv(() => _vm.rows.ToCsv(TimeAndSalesRowVM.csv_ordered_properties), "TaS")),
|
||||
// ladder
|
||||
SparkCommands.ShowLadderAutoLookup(SparkCommands.KeyGestures.ShowLadder)
|
||||
.complete(current_sec_key_src, sec_keys => sec_keys.Count > 0),
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace bts.shell {
|
||||
|
||||
async void _show_synthetic_create(SecurityCriteria security_criteria) {
|
||||
var found_securities = await security_criteria.securities(_bus);
|
||||
var respect_clause_security_ordering_is_possible = security_criteria.clauses.Any(clause => clause.security_keys != null && clause.security_keys.Count > 0);
|
||||
var respect_clause_security_ordering_is_possible = security_criteria.clauses.Any(clause => clause.security_keys != null && clause.security_keys.Length > 0);
|
||||
if (!respect_clause_security_ordering_is_possible) {
|
||||
_show_synthetic_create(found_securities.Values.ToList());
|
||||
} else {
|
||||
|
||||
@@ -85,9 +85,7 @@ namespace mbts.spark {
|
||||
icon = Icons.Synthetics;
|
||||
_has_working_orders = backing(nameof(has_working_orders), false);
|
||||
contract_picker_model = new ContractPickerModel(bus, false, null, new SecurityCriteria(new[] {
|
||||
new SecurityCriteriaClause() {
|
||||
exchanges = EnumHelper.get_values_except(Venue.Bts).ToArray()
|
||||
}
|
||||
new SecurityCriteriaClause(exchanges: EnumHelper.get_values_except(Venue.Bts).ToArray())
|
||||
}));
|
||||
contract_picker_model.cancel_action += _close_new_leg_popup;
|
||||
contract_picker_model.ok_action += () => {
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace mbts.spark {
|
||||
// This is a core data type on the front end, so data validation is strict, as bad values may yield weird/difficult to track bugs.
|
||||
// Descriptive factory methods are favored over public constructors, as they are less likely to be misused.
|
||||
struct AlgoData : IEquatable<AlgoData> {
|
||||
public static readonly Func<AlgoData, AlgoKey> key_fn = a => a.key;
|
||||
|
||||
public readonly CustomOrderDefinitionImmutable value;
|
||||
public readonly string name;
|
||||
public readonly AlgoKey key;
|
||||
|
||||
@@ -128,6 +128,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public bool is_persisted => mode == Mode.Persisted;
|
||||
public bool is_composite => _composite_key.HasValue || _unpersisted.HasValue;
|
||||
|
||||
public uint persisted => _composite_key.Value;
|
||||
public Guid unpersisted => _unpersisted.Value;
|
||||
@@ -199,6 +200,15 @@ namespace mbts.spark {
|
||||
}
|
||||
return EqualityComparer.phase_hash(hash, phase_mult);
|
||||
}
|
||||
public override string ToString() {
|
||||
switch (mode) {
|
||||
case Mode.Dynamic: return $"Dynamic: {dynamic_type}";
|
||||
case Mode.Factory: return $"Factory: {factory}";
|
||||
case Mode.Persisted: return $"Composite: {persisted}";
|
||||
case Mode.Unpersisted: return $"(Composite): {unpersisted}";
|
||||
default: return mode.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(AlgoKey a, AlgoKey b) => a.Equals(b);
|
||||
public static bool operator !=(AlgoKey a, AlgoKey b) => !a.Equals(b);
|
||||
|
||||
@@ -12,20 +12,20 @@ namespace mbts.spark {
|
||||
[Export(typeof(IAlgoStudioModel))]
|
||||
class AlgoStudioFlatDefinitionModel : IAlgoStudioModel, IDisposable {
|
||||
readonly AlgoDefinitionService _service;
|
||||
readonly AdminModel _admin_model;
|
||||
readonly UserTuple _user;
|
||||
readonly ErrorReporter _error_reporter;
|
||||
IReadOnlyDictionary<AlgoKey, AlgoData> _algos = DictionaryHelper.empty<AlgoKey, AlgoData>();
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public AlgoStudioFlatDefinitionModel(AlgoDefinitionService service, IAlgoDefinitionMetadataService metadata_service, AdminModel admin_model, ErrorReporter error_reporter) {
|
||||
public AlgoStudioFlatDefinitionModel(AlgoDefinitionService service, IAlgoDefinitionMetadataService metadata_service, UserTuple user, ErrorReporter error_reporter) {
|
||||
_service = service;
|
||||
this.metadata_service = metadata_service;
|
||||
_admin_model = admin_model;
|
||||
_user = user;
|
||||
_error_reporter = error_reporter;
|
||||
definitions =
|
||||
service.subscribei_algo_definitions()
|
||||
.Filter(r => r.Metadata.IsActive && _admin_model.user.can_access_user_data(r.Metadata.CreatorUserId))
|
||||
.Filter(r => r.Metadata.IsActive && _user.can_access_user_data(r.Metadata.CreatorUserId))
|
||||
.SelectKeyValue(_definition_data, d => d.key)
|
||||
.Table()
|
||||
.Cache();
|
||||
@@ -37,7 +37,7 @@ namespace mbts.spark {
|
||||
|
||||
public async Task<AlgoData?> save_definition(AlgoData definition_data) {
|
||||
var (value, success) = await _error_reporter.safe_execute(() => _service.save_algo_definition_async(
|
||||
_with_key(new AlgoDefinitionUpdateRequest { UserId = _admin_model.user.id, Algo = _api_definition(definition_data) }, definition_data.key)),
|
||||
_with_key(new AlgoDefinitionUpdateRequest { UserId = _user.id, Algo = _api_definition(definition_data) }, definition_data.key)),
|
||||
r => r.Success, r => r.ErrorMessage, "saving definition");
|
||||
if (success)
|
||||
return _definition_data(new AlgoDefinitionRecordImmutable(value.Record));
|
||||
@@ -93,4 +93,4 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,8 @@ namespace mbts.spark {
|
||||
/// decouple the client-side key type from the server-side one, so both key types may evolve independently moving forward.
|
||||
/// </summary>
|
||||
struct AlgoDefinitionMetadata : IEquatable<AlgoDefinitionMetadata> {
|
||||
public static readonly Func<AlgoDefinitionMetadata, AlgoKey> key_fn = m => m.id;
|
||||
|
||||
public readonly AlgoKey id, default_template;
|
||||
readonly AlgoKey[] _favorite_templates;
|
||||
public readonly bool is_favorite, is_hidden;
|
||||
|
||||
@@ -35,34 +35,21 @@ namespace mbts.spark {
|
||||
Comparer<IAlgoVM>.Create(_CompareUtils.compare_names)
|
||||
}).to_comparer().to_safe();
|
||||
|
||||
public static void update_persisted_definitions(ObservableKeyedCollection<AlgoDefinitionVM, AlgoKey> target, TableUpdate<AlgoData, AlgoKey> update, Func<AlgoData, AlgoDefinitionVM> factory) {
|
||||
foreach (var d in update.removed)
|
||||
target.Remove(d.key);
|
||||
foreach (var d in update.changed)
|
||||
public static void update_persisted_definitions(ObservableKeyedCollection<AlgoDefinitionVM, AlgoKey> target, TableUpdate<AlgoData, AlgoKey> update, Func<AlgoData, AlgoDefinitionVM> factory) =>
|
||||
update_persisted_definitions(target, update.added, update.changed, update.removed.Select(AlgoData.key_fn), factory);
|
||||
|
||||
public static void update_persisted_definitions(ObservableKeyedCollection<AlgoDefinitionVM, AlgoKey> target, IEnumerable<AlgoData> added, IEnumerable<AlgoData> changed, IEnumerable<AlgoKey> removed, Func<AlgoData, AlgoDefinitionVM> factory) {
|
||||
foreach (var k in removed)
|
||||
target.Remove(k);
|
||||
foreach (var d in changed)
|
||||
target[d.key].load(d);
|
||||
foreach (var d in update.added) {
|
||||
foreach (var d in added) {
|
||||
if (target.TryGetValue(d.key, out AlgoDefinitionVM def)) {
|
||||
def.load(d);
|
||||
} else target.Add(factory(d));
|
||||
}
|
||||
}
|
||||
|
||||
public static void update_persisted_definition_wrappers(IDictionary<AlgoKey, IAlgoVM> target, TableUpdate<AlgoData, AlgoKey> update, Func<AlgoData, AlgoDefinitionVM> factory) {
|
||||
foreach (var d in update.removed)
|
||||
target.Remove(d.key);
|
||||
foreach (var d in update.changed) {
|
||||
var vm = target[d.key];
|
||||
if (vm is AlgoVMWrapper wrapper) {
|
||||
wrapper.value.load(d);
|
||||
} else vm.load_from(d.value);
|
||||
}
|
||||
foreach (var d in update.added) {
|
||||
if (target.TryGetValue(d.key, out IAlgoVM def)) {
|
||||
def.load_from(d.value);
|
||||
} else target.Add(d.key, new AlgoVMWrapper(factory(d)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void commit_all(this IEnumerable<AlgoParamRowVM> algo_param_rows) =>
|
||||
algo_param_rows.Select(r => r.param).commit_all();
|
||||
|
||||
|
||||
@@ -42,21 +42,21 @@ namespace mbts.spark {
|
||||
readonly Property<string> _name, _abbreviation;
|
||||
readonly ObservableKeyedCollection<IAlgoVM, AlgoKey> _algo_roots = new ObservableKeyedCollection<IAlgoVM, AlgoKey>(vm => vm.id);
|
||||
readonly DeferrableActionWrapper _refresh_on_local_changes;
|
||||
readonly Property<AlgoFormats> _selected_format;
|
||||
readonly EnumMaskInt32<AlgoEditingPermissions> _permissions_mask = new EnumMaskInt32<AlgoEditingPermissions>();
|
||||
|
||||
int? _favorite_index;
|
||||
Brush _badge_fill;
|
||||
Snapshot? _committed;
|
||||
AlgoDefinitionMetadata _metadata;
|
||||
IDisposable _loaded_data_hook;
|
||||
|
||||
public static AlgoDefinitionVM create(OrdersModel model, AlgoData data, AlgoFormats init_format = AlgoFormats.Exchange, AlgoEditingPermissions editing_permissions = (AlgoEditingPermissions)int.MaxValue) =>
|
||||
new AlgoDefinitionVM(model, data, init_format, editing_permissions);
|
||||
public static AlgoDefinitionVM create(OrdersModel model, AlgoData data, AlgoEditingPermissions editing_permissions = (AlgoEditingPermissions)int.MaxValue) =>
|
||||
new AlgoDefinitionVM(model, data, editing_permissions);
|
||||
|
||||
public static AlgoDefinitionVM create_placeholder(OrdersModel model, CustomOrderDefinitionImmutable def, string name, AlgoFormats init_format) =>
|
||||
new AlgoDefinitionVM(model, AlgoData.create_unpersisted(def, name), init_format, (AlgoEditingPermissions)int.MaxValue);
|
||||
public static AlgoDefinitionVM create_placeholder(OrdersModel model, CustomOrderDefinitionImmutable def, string name) =>
|
||||
new AlgoDefinitionVM(model, AlgoData.create_unpersisted(def, name), (AlgoEditingPermissions)int.MaxValue);
|
||||
|
||||
AlgoDefinitionVM(OrdersModel model, AlgoData def_data, AlgoFormats init_format, AlgoEditingPermissions init_permissions) {
|
||||
AlgoDefinitionVM(OrdersModel model, AlgoData def_data, AlgoEditingPermissions init_permissions) {
|
||||
// init core data
|
||||
_model = model;
|
||||
_permissions_mask.mask = init_permissions;
|
||||
@@ -80,7 +80,6 @@ namespace mbts.spark {
|
||||
// init backing props
|
||||
_name = backing(nameof(name), def_data.name);
|
||||
_abbreviation = backing(nameof(abbreviation), string.Empty);
|
||||
_selected_format = backing(nameof(selected_format), init_format);
|
||||
_is_favorite = backing(nameof(is_favorite), () => _favorite_index.HasValue);
|
||||
_is_expanded = backing(nameof(is_expanded), true);
|
||||
_is_selected = backing(nameof(is_selected), true);
|
||||
@@ -133,17 +132,6 @@ namespace mbts.spark {
|
||||
break;
|
||||
}
|
||||
var permission_src = _permissions_mask.observe_result();
|
||||
resources.Add(_selected_format.observe_current(true).CombineLatest(permission_src, (fmt, perms) => (fmt, perms))
|
||||
.SubscribeEach(t => {
|
||||
if ((t.perms & AlgoEditingPermissions.AllowEditStructure) != 0) {
|
||||
using (_refresh_on_local_changes.defer_execution()) {
|
||||
var algo_data = model.factory.default_algos(t.fmt);
|
||||
var default_algo = AlgoKey.from_known_type(OrderDataHelper.get_default_algo(t.fmt));
|
||||
return this.load_algo_data_recursive(algo_data, default_algo);
|
||||
}
|
||||
}
|
||||
return Disposable.empty;
|
||||
}));
|
||||
resources.Add(permission_src.Subscribe(_ => RaisePropertyChanged(nameof(editing_permissions))));
|
||||
resources.Add(this.connect_data(permission_src));
|
||||
resources.Add(this.connect_data(Observable.Return(model)));
|
||||
@@ -202,9 +190,6 @@ namespace mbts.spark {
|
||||
public EnabledValueVM<Color> custom_badge_color { get; } = new EnabledValueVM<Color>();
|
||||
public ObservableCollection<ColorPaletteVM> custom_badge_color_palettes { get; } = new ObservableCollection<ColorPaletteVM>();
|
||||
public Brush badge_fill => _badge_fill;
|
||||
// format
|
||||
public AlgoFormats selected_format { get => _selected_format.Value; set => _selected_format.set(value); }
|
||||
public ObservableCollection<AlgoFormats> formats { get; } = new ObservableCollection<AlgoFormats> { AlgoFormats.Exchange, AlgoFormats.Spreader, AlgoFormats.Exchange | AlgoFormats.Spreader };
|
||||
// visual states
|
||||
public ObservableCollection<string> edit_pane_visual_states => _edit_pane_vs_model.states;
|
||||
public ObservableCollection<string> tree_view_visual_states => _tree_view_vs_model.states;
|
||||
@@ -270,17 +255,14 @@ namespace mbts.spark {
|
||||
void IObserver<(IReadOnlyDictionary<AlgoKey, AlgoData> algo_data, AlgoKey? default_algo)>.OnError(Exception error) { }
|
||||
#endregion
|
||||
|
||||
void _load_algo_data(IReadOnlyDictionary<AlgoKey, AlgoData> algo_data, AlgoKey? default_algo) {
|
||||
var orig_algo = algo_root?.id;
|
||||
_algo_roots.SyncWithDictionary(algo_data, d => OrderTypeVMFactory.create(d, is_expanded: true));
|
||||
if (!try_select(orig_algo) && !try_select(default_algo))
|
||||
algo_root = algo_roots.FirstOrDefault();
|
||||
//
|
||||
bool try_select(AlgoKey? algo_key) {
|
||||
if (algo_key.HasValue && _algo_roots.TryGetValue(algo_key.Value, out IAlgoVM match)) {
|
||||
void _load_algo_data(IReadOnlyDictionary<AlgoKey, AlgoData> data, AlgoKey? default_algo) {
|
||||
Disposable.dispose(ref _loaded_data_hook);
|
||||
_algo_roots.SyncWithDictionary(data, d => OrderTypeVMFactory.create(d, is_expanded: true));
|
||||
_loaded_data_hook = ObservableAutoWrapper.connect_item_hooks(algo_roots, vm =>
|
||||
ObservableAutoWrapper.connect_item_actions(vm.child_algo_selectors, s => s.load_algo_data(data, null)));
|
||||
if (algo_root == null || !_algo_roots.ContainsKey(algo_root.id)) {
|
||||
if (default_algo.HasValue && _algo_roots.TryGetValue(default_algo.Value, out IAlgoVM match))
|
||||
algo_root = match;
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +328,7 @@ namespace mbts.spark {
|
||||
|
||||
// pass a copy of the persisted state - rather than use local values - because if something goes wrong, it is better to be in sync with data fresh from the server/api.
|
||||
public AlgoDefinitionVM to_persisted(AlgoData def) =>
|
||||
new AlgoDefinitionVM(_model, def, selected_format, editing_permissions_mask);
|
||||
new AlgoDefinitionVM(_model, def, editing_permissions_mask);
|
||||
|
||||
public AlgoData create_algo_def() =>
|
||||
AlgoData.create(algo_root == null ? new CustomOrderDefinitionImmutable(new CustomOrderDefinition()) : algo_root.definition, name, key);
|
||||
@@ -368,7 +350,6 @@ namespace mbts.spark {
|
||||
|
||||
void _assign_from_data(Snapshot state) {
|
||||
_assign_from_data(state.data);
|
||||
_selected_format.set(state.format);
|
||||
_abbreviation.set(state.abbreviation);
|
||||
custom_badge_color.set_nullable(state.custom_badge_color);
|
||||
}
|
||||
@@ -429,41 +410,36 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
Snapshot _snapshot() =>
|
||||
new Snapshot(create_algo_def(), abbreviation, custom_badge_color.get_nullable(), selected_format);
|
||||
new Snapshot(create_algo_def(), abbreviation, custom_badge_color.get_nullable());
|
||||
|
||||
public struct Snapshot : IEquatable<Snapshot> {
|
||||
public readonly AlgoData data;
|
||||
public readonly string abbreviation;
|
||||
public readonly Color? custom_badge_color;
|
||||
public readonly AlgoFormats format;
|
||||
|
||||
public Snapshot(AlgoData data, string abbreviation, Color? custom_badge_color, AlgoFormats format) {
|
||||
public Snapshot(AlgoData data, string abbreviation, Color? custom_badge_color) {
|
||||
this.data = data;
|
||||
this.abbreviation = abbreviation;
|
||||
this.custom_badge_color = custom_badge_color;
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public bool Equals(Snapshot other) =>
|
||||
data == other.data &&
|
||||
abbreviation == other.abbreviation &&
|
||||
custom_badge_color == other.custom_badge_color &&
|
||||
format == other.format;
|
||||
custom_badge_color == other.custom_badge_color;
|
||||
|
||||
public override bool Equals(object obj) => EqualityComparer.equals_obj(this, obj);
|
||||
public override int GetHashCode() =>
|
||||
EqualityComparer.aggregate_hash(
|
||||
data.GetHashCode(),
|
||||
abbreviation?.GetHashCode() ?? 0,
|
||||
custom_badge_color?.GetHashCode() ?? 0,
|
||||
(int)format);
|
||||
custom_badge_color?.GetHashCode() ?? 0);
|
||||
#if DEBUG
|
||||
public override string ToString() {
|
||||
var sb = new System.Text.StringBuilder();
|
||||
sb.Append($"name: {data.name}; ");
|
||||
sb.Append($"abbrev.: {abbreviation}; ");
|
||||
sb.Append($"badge: {custom_badge_color} ");
|
||||
sb.Append($"fmt: {format} ");
|
||||
sb.Append($"def: {data.value}");
|
||||
return sb.ToString();
|
||||
}
|
||||
@@ -477,7 +453,6 @@ namespace mbts.spark {
|
||||
public bool Equals(Snapshot x, Snapshot y) =>
|
||||
x.abbreviation == y.abbreviation &&
|
||||
x.custom_badge_color == y.custom_badge_color &&
|
||||
x.format == y.format &&
|
||||
x.data.key == y.data.key &&
|
||||
x.data.name == y.data.name &&
|
||||
x.data.value.Equals(y.data.value);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using bts.utils;
|
||||
using mbts.collections;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.shell;
|
||||
using mbts.ui.utility;
|
||||
@@ -37,7 +41,6 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
class AlgoStudioVM : DisposableViewModelBase {
|
||||
static readonly AlgoFormats _studio_formats = AlgoFormats.Exchange;
|
||||
readonly OrdersModel _model;
|
||||
readonly Property<AlgoDefinitionVM> _selected_definition;
|
||||
readonly Property<IAlgoVM> _editable_content;
|
||||
@@ -70,12 +73,24 @@ namespace mbts.spark {
|
||||
_revert_cmd_tooltip = backing(nameof(revert_cmd_tooltip), get_revert_tooltip);
|
||||
//
|
||||
_dispose = new CompositeDisposable(
|
||||
_model.algo_model.definitions.Subscribe(_definitions_update_buffer),
|
||||
_definitions_update_buffer.OnDispatcher().Subscribe(u => {
|
||||
var orig_selected_def = selected_definition;
|
||||
AlgoCollectionHelper.update_persisted_definitions(_definitions, u, d => AlgoDefinitionVM.create(model, d, _studio_formats));
|
||||
_model.subscribe_complete_algos(allow_undefined_child: true).OnDispatcher().Subscribe(_definitions_update_buffer),
|
||||
_definitions_update_buffer.OnDispatcher()
|
||||
.SubscribeEach(u => {
|
||||
u.FilterIncremental(a => a.key.is_composite, out var added, out var changes, out var removed);
|
||||
AlgoCollectionHelper.update_persisted_definitions(
|
||||
_definitions, added, changes.New(), removed.Select(AlgoData.key_fn), algo => AlgoDefinitionVM.create(_model, algo));
|
||||
if (selected_definition == null)
|
||||
selected_definition = definitions.FirstOrDefault();
|
||||
// Load the algo building blocks (i.e., factory and dynamic algos):
|
||||
// - Composite algos cannot reference other composite algos - that would create awkward dependency issues as composite algos can be modified/deleted.
|
||||
// - Spreader algos are filtered out as well, because that don't actually mean anything to the algo structure.
|
||||
// Synthetic securities in our system are defined by a set of contract legs, and a [single]strategy.
|
||||
// Note: synthetic strategy templates, however, could be introduced at a later date (no reason why 1 synthetic security couldn't have several ExecutionStrategies).
|
||||
var algo_building_blocks = new FilteredDictionary<AlgoKey, AlgoData>(
|
||||
u.state,
|
||||
a => a.key.mode == AlgoKey.Mode.Dynamic || (a.key.mode == AlgoKey.Mode.Factory && a.key.factory != CustomOrderDefinition.CustomOneofCase.Spreader));
|
||||
return ObservableAutoWrapper.connect_item_actions(_definitions.AsCollection(),
|
||||
d => ((IAlgoSelector)d).load_algo_data(algo_building_blocks, null));
|
||||
}),
|
||||
_model.algo_model.metadata_service.subscribe_metadata().OnDispatcher().Subscribe(meta => {
|
||||
_persisted_meta = meta;
|
||||
@@ -125,7 +140,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
void add_definition_common(CustomOrderDefinitionImmutable def, string name) {
|
||||
var new_def = AlgoDefinitionVM.create_placeholder(_model, def, name, _studio_formats);
|
||||
var new_def = AlgoDefinitionVM.create_placeholder(_model, def, name);
|
||||
_definitions.Add(new_def);
|
||||
selected_definition = new_def;
|
||||
request_view_focus_name?.Invoke(new_def);
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using bts.spark;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.shell;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace mbts.spark {
|
||||
class AlgoVMWrapper : DisposableViewModelBase, IAlgoVM,
|
||||
IObserver<SecurityMD?>,
|
||||
IObserver<SecurityImmutable?>,
|
||||
IObserver<OrdersModel>,
|
||||
IObserver<AlgoEditingPermissions> {
|
||||
static readonly HashSet<string>
|
||||
_algo_root_echo_props = new HashSet<string> {
|
||||
nameof(is_expanded),
|
||||
nameof(editing_permissions),
|
||||
nameof(definition),
|
||||
nameof(display_name)
|
||||
};
|
||||
static readonly IReadOnlyDictionary<string, string>
|
||||
_value_echo_props = new Dictionary<string, string> {
|
||||
{ nameof(AlgoDefinitionVM.name), nameof(display_name) },
|
||||
{ nameof(AlgoDefinitionVM.abbreviation), nameof(abbreviation) },
|
||||
{ nameof(AlgoDefinitionVM.badge_fill), nameof(meta) }
|
||||
};
|
||||
readonly ObservableAggregateCollection<IAlgoSelector> _child_algo_selectors = new ObservableAggregateCollection<IAlgoSelector>();
|
||||
readonly ObservableAggregateCollection<IAlgoParamVM> _algo_params = new ObservableAggregateCollection<IAlgoParamVM>();
|
||||
readonly DisposableContainer _value_hooks = new DisposableContainer();
|
||||
Action _definition_changed = () => { };
|
||||
_ObservedData? _data_cache;
|
||||
AlgoDefinitionVM _value;
|
||||
|
||||
public AlgoVMWrapper(AlgoDefinitionVM algo_definition_vm) {
|
||||
value = algo_definition_vm;
|
||||
_dispose = new CompositeDisposable(_value_hooks) {
|
||||
_child_algo_selectors.clear_collections,
|
||||
_algo_params.clear_collections,
|
||||
() => _value?.Dispose()
|
||||
};
|
||||
}
|
||||
|
||||
public event Action definition_changed { add => _definition_changed += value; remove => _definition_changed -= value; }
|
||||
|
||||
public AlgoDefinitionVM value {
|
||||
get => _value;
|
||||
set {
|
||||
if (_value != value) {
|
||||
_value?.Dispose();
|
||||
_value = value;
|
||||
_value_hooks.replace(_set_hooks(value));
|
||||
RaisePropertyChanged(nameof(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
public AlgoKey id => _value.key;
|
||||
public CustomOrderDefinition.CustomOneofCase order_type => _algo_root?.order_type ?? CustomOrderDefinition.CustomOneofCase.None;
|
||||
public OrderMetadata meta {
|
||||
get {
|
||||
if (_value != null) {
|
||||
if (_value.custom_badge_color.enabled)
|
||||
return new OrderMetadata { Color = value.custom_badge_color.value.rgb_color(), KeyBinding = value.abbreviation.if_null_or_empty(value.name) };
|
||||
else if (_value.algo_root != null)
|
||||
return _value.algo_root.meta;
|
||||
}
|
||||
return OrderDataHelper.get_metadata(order_type);
|
||||
}
|
||||
}
|
||||
public AlgoEditingPermissions editing_permissions => _value?.editing_permissions ?? AlgoEditingPermissions.None;
|
||||
public bool can_expand => _algo_root?.can_expand ?? false;
|
||||
public bool is_expanded {
|
||||
get => _value.algo_root?.is_expanded ?? false;
|
||||
set {
|
||||
if (_value != null)
|
||||
_value.is_expanded = value;
|
||||
}
|
||||
}
|
||||
public string display_name => _value?.name ?? string.Empty;
|
||||
public string abbreviation => _value?.abbreviation;
|
||||
public AlgoDisplayGroup group => _value?.group ?? AlgoDisplayGroup.BTS;
|
||||
public CustomOrderDefinitionImmutable definition => _algo_root?.definition ?? new CustomOrderDefinitionImmutable(new CustomOrderDefinition());
|
||||
public ObservableCollection<IAlgoSelector> child_algo_selectors => _child_algo_selectors;
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public ObservableCollection<IAlgoSelector> child_algo_selectors_view {
|
||||
get {
|
||||
_value?.algo_root?.ensure_init();
|
||||
return _child_algo_selectors;
|
||||
}
|
||||
}
|
||||
public IReadOnlyObservableCollection<IAlgoParamVM> algo_params => _algo_params;
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public dynamic children_vm => _algo_root?.children_vm;
|
||||
|
||||
IAlgoVM _algo_root => _value?.algo_root;
|
||||
|
||||
public void assign_to(CustomOrderDefinition value) => _algo_root?.assign_to(value);
|
||||
public bool key_match(KeyEventArgs e) => _algo_root?.key_match(e) ?? false;
|
||||
public void load_from(CustomOrderDefinitionImmutable value) => _algo_root?.load_from(value);
|
||||
public void load_many(IEnumerable<CustomOrderDefinitionImmutable> values) => _algo_root?.load_many(values);
|
||||
void IAlgoVM.ensure_init() => _value?.algo_root?.ensure_init();
|
||||
|
||||
IDisposable _set_hooks(AlgoDefinitionVM vm) {
|
||||
var algo_root_subs = new DisposableContainer();
|
||||
vm.PropertyChanged += on_value_prop_changed;
|
||||
return new CompositeDisposable(
|
||||
vm.observe_algo_root().Subscribe(r => {
|
||||
algo_root_subs.replace(null);
|
||||
_child_algo_selectors.clear_collections();
|
||||
_algo_params.clear_collections();
|
||||
if (r != null) {
|
||||
if (_data_cache.HasValue) {
|
||||
_data_cache.Value.forward_to(r);
|
||||
}
|
||||
_child_algo_selectors.add_collection(r.child_algo_selectors);
|
||||
_algo_params.add_collection(r.algo_params);
|
||||
((INotifyPropertyChanged)r).PropertyChanged += on_algo_root_prop_changed;
|
||||
algo_root_subs.replace(new CompositeDisposable(
|
||||
r.subscribe_definition().Subscribe(_ => _definition_changed?.Invoke())) {
|
||||
() => ((INotifyPropertyChanged)r).PropertyChanged -= on_algo_root_prop_changed
|
||||
});
|
||||
}
|
||||
RaisePropertyChanged(nameof(group));
|
||||
}),
|
||||
algo_root_subs) {
|
||||
() => vm.PropertyChanged -= on_value_prop_changed
|
||||
};
|
||||
void on_algo_root_prop_changed(object sender, PropertyChangedEventArgs e) {
|
||||
if (_algo_root_echo_props.Contains(e.PropertyName))
|
||||
RaisePropertyChanged(e.PropertyName);
|
||||
}
|
||||
void on_value_prop_changed(object sender, PropertyChangedEventArgs e) {
|
||||
if (_value_echo_props.TryGetValue(e.PropertyName, out string wrapper_prop))
|
||||
RaisePropertyChanged(wrapper_prop);
|
||||
}
|
||||
}
|
||||
|
||||
// permissions
|
||||
void IObserver<AlgoEditingPermissions>.OnNext(AlgoEditingPermissions value) {
|
||||
_data_cache = _data_cache?.with(value) ?? new _ObservedData(value, default, default, default);
|
||||
(_algo_root as IObserver<AlgoEditingPermissions>)?.OnNext(value);
|
||||
}
|
||||
void IObserver<AlgoEditingPermissions>.OnError(Exception error) { }
|
||||
void IObserver<AlgoEditingPermissions>.OnCompleted() { }
|
||||
// model
|
||||
void IObserver<OrdersModel>.OnNext(OrdersModel value) {
|
||||
_data_cache = _data_cache?.with(value) ?? new _ObservedData(default, value, default, default);
|
||||
(_algo_root as IObserver<OrdersModel>)?.OnNext(value);
|
||||
}
|
||||
void IObserver<OrdersModel>.OnError(Exception error) { }
|
||||
void IObserver<OrdersModel>.OnCompleted() { }
|
||||
// security
|
||||
void IObserver<SecurityImmutable?>.OnNext(SecurityImmutable? value) {
|
||||
_data_cache = _data_cache?.with(value) ?? new _ObservedData(default, default, value, default);
|
||||
(_algo_root as IObserver<SecurityImmutable?>)?.OnNext(value);
|
||||
}
|
||||
void IObserver<SecurityImmutable?>.OnError(Exception error) { }
|
||||
void IObserver<SecurityImmutable?>.OnCompleted() { }
|
||||
// security md
|
||||
void IObserver<SecurityMD?>.OnNext(SecurityMD? value) {
|
||||
_data_cache = _data_cache?.with(value) ?? new _ObservedData(default, default, default, value);
|
||||
(_algo_root as IObserver<SecurityMD?>)?.OnNext(value);
|
||||
}
|
||||
void IObserver<SecurityMD?>.OnError(Exception error) { }
|
||||
void IObserver<SecurityMD?>.OnCompleted() { }
|
||||
|
||||
struct _ObservedData {
|
||||
public readonly AlgoEditingPermissions permissions;
|
||||
public readonly OrdersModel model;
|
||||
public readonly SecurityImmutable? security;
|
||||
public readonly SecurityMD? security_md;
|
||||
|
||||
public _ObservedData(AlgoEditingPermissions permissions, OrdersModel model, SecurityImmutable? security, SecurityMD? security_md) {
|
||||
this.permissions = permissions;
|
||||
this.model = model;
|
||||
this.security = security;
|
||||
this.security_md = security_md;
|
||||
}
|
||||
|
||||
public void forward_to(IAlgoVM recipient) {
|
||||
(recipient as IObserver<AlgoEditingPermissions>)?.OnNext(permissions);
|
||||
if (model != null)
|
||||
(recipient as IObserver<OrdersModel>)?.OnNext(model);
|
||||
if (security_md.HasValue)
|
||||
(recipient as IObserver<SecurityMD?>)?.OnNext(security_md);
|
||||
if (security.HasValue)
|
||||
(recipient as IObserver<SecurityImmutable?>)?.OnNext(security);
|
||||
}
|
||||
|
||||
public _ObservedData with(AlgoEditingPermissions? permissions) =>
|
||||
new _ObservedData(permissions ?? this.permissions, model, security, security_md);
|
||||
|
||||
public _ObservedData with(OrdersModel model) =>
|
||||
new _ObservedData(permissions, model, security, security_md);
|
||||
|
||||
public _ObservedData with(SecurityImmutable? security) =>
|
||||
new _ObservedData(permissions, model, security, security_md);
|
||||
|
||||
public _ObservedData with(SecurityMD? security_md) =>
|
||||
new _ObservedData(permissions, model, security, security_md);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -302,7 +302,7 @@
|
||||
<!--Double-->
|
||||
<usp:AlgoParamTemplateSelector.DoubleTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding param.value, Converter={StaticResource DoubleTextConverter}}"/>
|
||||
<TextBlock Text="{Binding param.display_value, Converter={StaticResource DoubleTextConverter}}"/>
|
||||
</DataTemplate>
|
||||
</usp:AlgoParamTemplateSelector.DoubleTemplate>
|
||||
<!--Enum-->
|
||||
@@ -406,7 +406,7 @@
|
||||
<!--Double-->
|
||||
<usp:AlgoParamTemplateSelector.DoubleTemplate>
|
||||
<DataTemplate>
|
||||
<c:TickUpDownDouble x:Name="tick_up_down" Focusable="False" HorizontalAlignment="Stretch" Value="{Binding param.value, UpdateSourceTrigger=PropertyChanged}" ArrowKeyTickModifiers="Ctrl">
|
||||
<c:TickUpDownDouble x:Name="tick_up_down" Focusable="False" HorizontalAlignment="Stretch" Value="{Binding param.display_value, UpdateSourceTrigger=PropertyChanged}" ArrowKeyTickModifiers="Ctrl">
|
||||
<c:TickUpDownDouble.CommandBindings>
|
||||
<CommandBinding Command="{x:Static u:NavigationHelper.MoveFocusCommand}" Executed="{x:Static u:NavigationHelper.KeyboardMoveFocusExecuted}"/>
|
||||
</c:TickUpDownDouble.CommandBindings>
|
||||
|
||||
+1
-26
@@ -39,31 +39,6 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
static IDisposable _wrap_rows(AlgoDefinitionVM algo_def, ObservableAggregateCollection<AlgoParamRowVM> rows, bool include_algo_type_rows) {
|
||||
AlgoParamRowVM root = null;
|
||||
ObservableAggregateCollection<AlgoParamRowVM> algo_params;
|
||||
if (include_algo_type_rows) {
|
||||
// while normal params live and die with the selected algo-type (when the algo-type changes, they are removed, and replaced with params for the new algo type),
|
||||
// the algo-type row is constant (it is the row with the algo-type dropdown, which the user may use to select different algos).
|
||||
algo_params = new ObservableAggregateCollection<AlgoParamRowVM>();
|
||||
rows.add_collection(new ObservableAppendCollection<AlgoParamRowVM>(algo_params, root = new AlgoSelectorParamRowVM(new AlgoVMWrapper(algo_def), algo_def, null)).AsReadOnly());
|
||||
} else {
|
||||
algo_params = rows;
|
||||
}
|
||||
return algo_def.observe_algo_root().SubscribeEach(a => {
|
||||
algo_params.clear_collections();
|
||||
if (a == null)
|
||||
return Disposable.empty;
|
||||
var child_rows = new ObservableAggregateCollection<AlgoParamRowVM>();
|
||||
/// Note: the order of operations here matters
|
||||
/// <see cref="_wrap_rows(IAlgoVM, AlgoParamRowVM, ObservableAggregateCollection{AlgoParamRowVM}, bool)" /> has the potential to trigger a lot of CollectionChanged events (depending on how deep the algo-tree is).
|
||||
/// There is no need to burden the aggregate 'rows' with echoing all of these events, if the child-row collection is finished changing when it is added to the aggregate.
|
||||
var hook = _wrap_rows(a, root, child_rows, include_algo_type_rows);
|
||||
algo_params.add_collection(child_rows.AsReadOnly());
|
||||
return hook;
|
||||
});
|
||||
}
|
||||
|
||||
static IDisposable _wrap_rows(IAlgoVM algo_root, AlgoParamRowVM parent, ObservableAggregateCollection<AlgoParamRowVM> all_rows, bool include_algo_type_rows) {
|
||||
var wrapped_params = new ObservableAutoWrapper<AlgoParamRowVM, IAlgoParamVM>(algo_root.algo_params, pvm => new AlgoParamRowVM(algo_root, pvm, parent));
|
||||
var selector_params = new ObservableCollection<AlgoParamRowVM>();
|
||||
@@ -85,4 +60,4 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@
|
||||
</GroupBox.Header>
|
||||
<ContentControl
|
||||
Grid.IsSharedSizeScope="True"
|
||||
Content="{Binding algo_root, Converter={x:Static usp:AlgoContentTemplateSelector.DataContextConverter}}"
|
||||
Content="{Binding algo_root}"
|
||||
ContentTemplateSelector="{StaticResource AlgoTemplateSelector}"
|
||||
Margin="{StaticResource Margin.TP1}"
|
||||
Visibility="{Binding algo_root.can_expand, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
|
||||
@@ -5,6 +5,7 @@ using bts.collections;
|
||||
using bts.shell.fills;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
using bts.utils.csv;
|
||||
using mbts.collections;
|
||||
using mbts.persist;
|
||||
using mbts.spark.filters;
|
||||
@@ -333,6 +334,27 @@ namespace mbts.spark {
|
||||
public override bool Equals(object obj) => Equals(obj as Row);
|
||||
public override int GetHashCode() => _fill.FillKey.GetHashCode() ^ _order.Key.GetHashCode();
|
||||
|
||||
public static System.Collections.Specialized.OrderedDictionary csv_ordered_properties =>
|
||||
CsvHelper.create_ordering_maintainer(typeof(Row),
|
||||
new string[] {
|
||||
nameof(security),
|
||||
nameof(order_type),
|
||||
nameof(root_algo_display_name),
|
||||
nameof(side),
|
||||
nameof(fill_time),
|
||||
nameof(user),
|
||||
nameof(account),
|
||||
nameof(exchange),
|
||||
nameof(time_in_force),
|
||||
nameof(size),
|
||||
nameof(price),
|
||||
nameof(fill_kind),
|
||||
nameof(fill_status),
|
||||
nameof(fill_key),
|
||||
nameof(order_key),
|
||||
nameof(security_key)
|
||||
});
|
||||
|
||||
public event Action invalidated;
|
||||
void IRowVM.raise_invalidated() => invalidated?.Invoke();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using bts.shell;
|
||||
using bts.shell.fills;
|
||||
using bts.spark;
|
||||
using bts.view;
|
||||
using bts.utils.csv;
|
||||
using mbts.persist;
|
||||
using mbts.ui;
|
||||
using mbts.ui.settings;
|
||||
@@ -61,6 +62,7 @@ namespace mbts.spark {
|
||||
_view = new FillsView { DataContext = _vm };
|
||||
|
||||
_commands = new List<SparkCommand> {
|
||||
new SparkCommandCommand("Export to csv", Icons.Export, FileDialogCommand.export_csv(() => _vm.rows.ToCsv(FillsVM.Row.csv_ordered_properties), "Fills")),
|
||||
// wrap the grid settings view factory in a dialogCommand here since the vm is destroyed/recreated when the security criteria changes
|
||||
SparkCommands.window_settings_command(new DialogCommand(() => {
|
||||
var vm = new ShellSettingsDialogVM<GridSettings, SimpleGridSettingsVM>(
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace mbts.spark {
|
||||
string candidate = string.Empty;
|
||||
if (a.HasValue) {
|
||||
var algo_name = a.Value.name;
|
||||
var words = algo_name.Split(delim);
|
||||
var words = algo_name.Split(delim, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (words.Length == 1) {
|
||||
var single_word = words[0];
|
||||
if (single_word.Length > 1) {
|
||||
@@ -153,7 +153,7 @@ namespace mbts.spark {
|
||||
candidate = single_word;
|
||||
}
|
||||
} else {
|
||||
candidate = words.Take(2).Select(w => w.Substring(0, 1)).list_string(string.Empty);
|
||||
candidate = string.Join(string.Empty, words.Take(2).Select(w => w.Substring(0, 1)));
|
||||
}
|
||||
}
|
||||
return candidate.ToUpper();
|
||||
|
||||
@@ -7,6 +7,7 @@ using bts.proto;
|
||||
using bts.shell.orderbook;
|
||||
using bts.utils;
|
||||
using mbts.collections;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using mbts.ui.controls.color_picker;
|
||||
@@ -115,7 +116,16 @@ namespace mbts.spark {
|
||||
foreach (var c in _observable_components)
|
||||
c.PropertyChanged += on_prop_changed;
|
||||
favorite_algos_vm.items.CollectionChanged += on_favorite_algo_items_CollectionChanged;
|
||||
_algo_definitions.AddRange(_model.factory.default_algos(security).Values.Select(algo_factory));
|
||||
_algo_definitions.AddRange(_model.get_permitted_algos(security).factory_types
|
||||
.Select(OrderDataHelper.Defaults.CustomOrderDefinitionImmutable)
|
||||
.Select(AlgoData.from_custom_def)
|
||||
.Select(algo_factory));
|
||||
_algo_definitions.AddRange(_model.get_permitted_algos(security).dynamic_types
|
||||
.Select(dyn_type => new CustomOrderDefinitionImmutable(new CustomOrderDefinition {
|
||||
Dynamic = _model.dynamic_helper.create_def(dyn_type)
|
||||
}))
|
||||
.Select(AlgoData.from_custom_def)
|
||||
.Select(algo_factory));
|
||||
_dispose = new CompositeDisposable(
|
||||
_model.factory.subscribe_accounts().OnDispatcher().Subscribe(acc_map => {
|
||||
_accounts.SyncWithDictionary(MappedDictionary.create(acc_map, account_factory));
|
||||
@@ -144,7 +154,7 @@ namespace mbts.spark {
|
||||
c.PropertyChanged -= on_prop_changed;
|
||||
}
|
||||
AccountTuple? account_factory(uint key, string name) => new AccountTuple(key, name);
|
||||
AlgoDefinitionVM algo_factory(AlgoData data) => AlgoDefinitionVM.create(_model, data, is_synthetic ? AlgoFormats.Spreader : AlgoFormats.Exchange);
|
||||
AlgoDefinitionVM algo_factory(AlgoData data) => AlgoDefinitionVM.create(_model, data);
|
||||
}
|
||||
|
||||
public event Action result_changed;
|
||||
|
||||
@@ -398,7 +398,8 @@ namespace mbts.spark {
|
||||
public uint last_column_width { get => _last_column_width.Value; set => _last_column_width.set(value); }
|
||||
public uint piq_column_width { get => _piq_column_width.Value; set => _piq_column_width.set(value); }
|
||||
public uint volume_column_width { get => _volume_column_width.Value; set => _volume_column_width.set(value); }
|
||||
public uint alternate_order_size_from_settings => current_settings.alternate_order_size;
|
||||
public uint actual_alternate_order_size =>
|
||||
(current_settings?.alternate_order_size ?? 0) * Math.Max(1, display_quantity_divisor);
|
||||
public bool show_warn_on_cross_from_settings => current_settings.show_warn_on_cross;
|
||||
public bool enforce_max_clip_from_settings => current_settings.enforce_max_clip;
|
||||
public uint max_clip_from_settings => current_settings.max_clip;
|
||||
@@ -489,11 +490,11 @@ namespace mbts.spark {
|
||||
public Task send_order_async((double price, Side? side, MouseButton button) args) {
|
||||
if (order_properties_vm != null && args.button != MouseButton.Middle) {
|
||||
var size_from_alternate = args.button == MouseButton.Right;
|
||||
if (!DoubleHelper.IsNaNOrInfinity(args.price) && args.side.HasValue && !HasErrors && !order_properties_vm.HasErrors && (!size_from_alternate || current_settings.alternate_order_size > 0)) {
|
||||
if (!DoubleHelper.IsNaNOrInfinity(args.price) && args.side.HasValue && !HasErrors && !order_properties_vm.HasErrors && (!size_from_alternate || actual_alternate_order_size > 0)) {
|
||||
if (!size_from_alternate && (!size_calculator.value.HasValue || size_calculator.value.Value == 0)) {
|
||||
size_calculator.flash_error();
|
||||
} else {
|
||||
uint size = size_from_alternate ? current_settings.alternate_order_size : (uint)Math.Abs(size_calculator.value ?? 0);
|
||||
uint size = size_from_alternate ? actual_alternate_order_size : (uint)Math.Abs(size_calculator.value ?? 0);
|
||||
// enforce max clip
|
||||
if (enforce_max_clip_from_settings && size > max_clip_from_settings) {
|
||||
size = max_clip_from_settings;
|
||||
@@ -530,7 +531,7 @@ namespace mbts.spark {
|
||||
if (fav_algo != null) {
|
||||
if (_favorite_algo_map.TryGetValue(fav_algo.key, out var d)) {
|
||||
if (!d.flags.HasFlag(LadderFavoriteAlgoFlags.Sticky) && !order_properties_vm.try_pop_selected_algo_definition()) {
|
||||
var key = new AlgoKey(OrderDataHelper.get_default_algo(OrderDataHelper.get_algo_format(security.ContractCase)));
|
||||
var key = new AlgoKey(OrderDataHelper.get_default_algo(security.ContractCase));
|
||||
if (order_properties_vm.try_get_algo_definition(key, out var r)) {
|
||||
order_properties_vm.selected_algo_definition = r;
|
||||
}
|
||||
|
||||
@@ -353,7 +353,9 @@ namespace mbts.spark {
|
||||
return;
|
||||
}
|
||||
} else if (_vm != null) {
|
||||
uint size = e.ChangedButton == MouseButton.Right ? _vm.alternate_order_size_from_settings : _vm.size_calculator.value ?? 0;
|
||||
uint size = e.ChangedButton == MouseButton.Right ?
|
||||
_vm.actual_alternate_order_size :
|
||||
_vm.size_calculator.value ?? 0;
|
||||
|
||||
// does the size violate the local max clip
|
||||
if (_vm.enforce_max_clip_from_settings && size > _vm.max_clip_from_settings) {
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace bts.shell.manual_fills {
|
||||
readonly Property<bool> _is_dirty;
|
||||
readonly Property<EditableItemState> _editable_item_state;
|
||||
readonly DelegateProperty<bool> _is_valid;
|
||||
readonly DisplayQuantityMultiplier _size = new DisplayQuantityMultiplier();
|
||||
readonly DisplayQuantityMultiplier<uint> _size = DisplayQuantityMultiplier.create_uint();
|
||||
readonly Func<SecurityImmutable?, uint> _get_display_qty_divisor;
|
||||
SecurityImmutable? _security;
|
||||
AccountTuple? _account;
|
||||
|
||||
@@ -4,6 +4,7 @@ using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using bts.spark;
|
||||
using bts.utils;
|
||||
using bts.utils.csv;
|
||||
using mbts.ui;
|
||||
using mbts.ui.controls;
|
||||
using System;
|
||||
@@ -11,6 +12,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Columns = mbts.spark.OrderBookGridView.ColumnKeys;
|
||||
@@ -29,7 +31,7 @@ namespace mbts.spark {
|
||||
int _depth_level;
|
||||
SecurityImmutable? _security => order_tuple.order.security;
|
||||
// for mini-ob
|
||||
DisplayQuantityMultiplier _prospective_qty_translator_backing;
|
||||
DisplayQuantityMultiplier<uint> _prospective_qty_translator_backing;
|
||||
uint _display_qty_divisor_backing;
|
||||
bool _display_qty_divisor_dirty = true;
|
||||
double _prospective_price;
|
||||
@@ -60,6 +62,35 @@ namespace mbts.spark {
|
||||
public event Action<(OrderSecurityRootPair oldval, OrderSecurityRootPair newval)> updated;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public static System.Collections.Specialized.OrderedDictionary csv_ordered_properties =>
|
||||
CsvHelper.create_ordering_maintainer(
|
||||
typeof(OrderBookRowVM),
|
||||
new string[] {
|
||||
nameof(security_text),
|
||||
nameof(symbol),
|
||||
nameof(time_created),
|
||||
nameof(last_change),
|
||||
nameof(user),
|
||||
nameof(account),
|
||||
nameof(exchange),
|
||||
nameof(time_in_force),
|
||||
nameof(order_type),
|
||||
nameof(root_algo_display_name),
|
||||
nameof(order_sub_type),
|
||||
nameof(side),
|
||||
nameof(quantity),
|
||||
nameof(filled_quantity),
|
||||
nameof(price),
|
||||
nameof(avg_price),
|
||||
nameof(last_price),
|
||||
nameof(piq),
|
||||
nameof(status),
|
||||
// last message (could contains commas, so skipping)
|
||||
nameof(security_key),
|
||||
nameof(order_key),
|
||||
nameof(parent_order_key),
|
||||
});
|
||||
|
||||
// Core
|
||||
public OrderSecurityRootPair order_tuple { get; private set; }
|
||||
public OrderRecordImmutable order => order_tuple.order.order;
|
||||
@@ -239,10 +270,9 @@ namespace mbts.spark {
|
||||
IDisplayTranslator<uint> _prospective_qty_translator {
|
||||
get {
|
||||
if (_prospective_qty_translator_backing == null) {
|
||||
_prospective_qty_translator_backing = new DisplayQuantityMultiplier {
|
||||
conversion_data = new QuantityConversionData(_display_qty_divisor, QuantityConversionData.OpType.DivideActual),
|
||||
actual_value = quantity
|
||||
};
|
||||
_prospective_qty_translator_backing = DisplayQuantityMultiplier.create_uint();
|
||||
_prospective_qty_translator_backing.conversion_data = new QuantityConversionData(_display_qty_divisor, QuantityConversionData.OpType.DivideActual);
|
||||
_prospective_qty_translator_backing.actual_value = quantity;
|
||||
_prospective_qty_translator.value_changed += () =>
|
||||
RaisePropertyChanged(nameof(is_qty_dirty));
|
||||
} else {
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace mbts.spark {
|
||||
_model = model;
|
||||
_selected_params_mon = new OrderParamsAggregator(model.dynamic_helper, _selection_change_throttle, k => _cached_orders.TryGetValue(k, out var o) ? o.order : (OrderSecurityAlgo?)null);
|
||||
ladder_vm = new LadderVMContainer(bus, model);
|
||||
order_mod_vm = new OrderParamsVM(this, AlgoFormats.Exchange, AlgoEditingPermissions.AllowEditValues);
|
||||
order_mod_vm = new OrderParamsVM(this, AlgoEditingPermissions.AllowEditValues);
|
||||
order_mod_vm.algo_vm.editing_permissions_mask = AlgoEditingPermissions.None;
|
||||
order_mod_vm.algo_vm.algo_root = null;
|
||||
_show_order_params = backing(nameof(show_order_params), () => (_right_panel.visible_components & OrderBookRightPanelSettings.Components.Params) != 0);
|
||||
@@ -99,7 +99,7 @@ namespace mbts.spark {
|
||||
};
|
||||
_can_attach_selected_orders = backing(nameof(can_attach_selected_orders), () => _attachable_selected_orders.Count == selected_rows.Count && selected_rows.Count > 0);
|
||||
_can_detach_selected_orders = backing(nameof(can_detach_selected_orders), () => _detachable_selected_orders.Count == selected_rows.Count && selected_rows.Count > 0);
|
||||
attach_vm = new OrderParamsVM(this, AlgoFormats.Attachable, AlgoEditingPermissions.AllowEditStructure | AlgoEditingPermissions.AllowEditValues);
|
||||
attach_vm = new OrderParamsVM(this, AlgoEditingPermissions.AllowEditStructure | AlgoEditingPermissions.AllowEditValues);
|
||||
_settings_manager = settings_manager;
|
||||
_columns = new OrderBookColumnCollection(bus, model, model.on_order_securities.Select(x => (x.added.Values, x.removed.Values)));
|
||||
// we use an ObservableAppendCollection b/c the mini-ob needs a cancel column at the front
|
||||
@@ -244,7 +244,22 @@ namespace mbts.spark {
|
||||
}),
|
||||
grid_settings_manager,
|
||||
order_mod_vm.algo_vm.connect_data(Observable.Return(model)),
|
||||
order_mod_vm.algo_vm.connect_data(_selected_params_mon.subscribe_spreader_security()),
|
||||
order_mod_vm.algo_vm.connect_data(
|
||||
/// This is not the same security source used to populate <see cref="OrderParamsVM.security_md"/>.
|
||||
/// The latter is always synced with the root of the selected row(s),
|
||||
/// while this source is synced with that row with one exception:
|
||||
/// If the root row's algo has a spreader algo (possibly nested),
|
||||
/// the synthetic security is taken instead of the root security.
|
||||
/// This has the affect of passing the synthetic security to the spreader algo viewmodel,
|
||||
/// which then uses the security to populate the synthetic params ui.
|
||||
/// TODO (maybe): clean this design up; the different security sources make it precarious.
|
||||
/// One idea is to pass a special data type to the algo vm (which contains the spreader
|
||||
/// security and execution strategy), which is only observed by the spreader algo vm.
|
||||
_selected_params_mon.subscribe_security().StartWith((SecurityImmutable?)null).CombineLatest(
|
||||
_selected_params_mon.subscribe_spreader_security().StartWith((SecurityImmutable?)null),
|
||||
(root_sec, spreader_sec) => (root_sec, spreader_sec))
|
||||
.Select(tup => tup.spreader_sec ?? tup.root_sec)
|
||||
.OnDispatcher()),
|
||||
order_mod_vm,
|
||||
attach_vm,
|
||||
_show_fills.observe_current(true)
|
||||
@@ -329,32 +344,32 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
void on_begin_attaching() {
|
||||
Disposable.replace(ref attach_vm_hooks,
|
||||
Disposable.Create(
|
||||
connect_common_selected_params(attach_vm),
|
||||
attach_vm.algo_vm.observe_algo_root().Subscribe(algo_root => {
|
||||
bool show_price, show_size;
|
||||
if (algo_root == null) {
|
||||
show_price = false;
|
||||
show_size = false;
|
||||
} else {
|
||||
show_price = AttachConf.show_price(algo_root.order_type);
|
||||
show_size = AttachConf.show_size(algo_root.order_type);
|
||||
}
|
||||
attach_vm.price_permissions = bool_to_perm(show_price);
|
||||
attach_vm.size_permissions = bool_to_perm(show_size);
|
||||
AlgoParamPermissions bool_to_perm(bool b) =>
|
||||
b ? AlgoParamPermissions.ReadWrite : AlgoParamPermissions.None;
|
||||
}),
|
||||
// custom templates (created by user)
|
||||
_model.algo_model.definitions.OnDispatcher().Subscribe(u =>
|
||||
AlgoCollectionHelper.update_persisted_definition_wrappers(attach_vm.algo_vm.algo_roots_index, u, mk_algo_def_vm))));
|
||||
// vm factory
|
||||
AlgoDefinitionVM mk_algo_def_vm(AlgoData fd) {
|
||||
var vm = AlgoDefinitionVM.create(_model, fd, OrderDataHelper.get_algo_format(_selected_params_mon.security?.ContractCase), AlgoEditingPermissions.AllowEditValues);
|
||||
vm.selected_format = OrderDataHelper.get_algo_format(_selected_params_mon.security?.ContractCase);
|
||||
return vm;
|
||||
}
|
||||
Disposable.dispose(ref attach_vm_hooks);
|
||||
attach_vm_hooks = Disposable.Create(
|
||||
_selected_security_mon.SubscribeThrottled(_selection_change_throttle).to_security_md(bus).OnDispatcher().SubscribeEach(newval => {
|
||||
attach_vm.security_md = newval;
|
||||
if (newval.HasValue) {
|
||||
return _model.subscribe_algos(newval.Value.security, true)
|
||||
.OnDispatcher()
|
||||
.Subscribe(t => ((IAlgoSelector)attach_vm.algo_vm).load_algo_data(t.state, null));
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
connect_common_selected_params(attach_vm),
|
||||
attach_vm.algo_vm.observe_algo_root().Subscribe(algo_root => {
|
||||
bool show_price, show_size;
|
||||
if (algo_root == null) {
|
||||
show_price = false;
|
||||
show_size = false;
|
||||
} else {
|
||||
show_price = AttachConf.show_price(algo_root.order_type);
|
||||
show_size = AttachConf.show_size(algo_root.order_type);
|
||||
}
|
||||
attach_vm.price_permissions = bool_to_perm(show_price);
|
||||
attach_vm.size_permissions = bool_to_perm(show_size);
|
||||
AlgoParamPermissions bool_to_perm(bool b) =>
|
||||
b ? AlgoParamPermissions.ReadWrite : AlgoParamPermissions.None;
|
||||
}));
|
||||
}
|
||||
void on_end_attaching() => Disposable.dispose(ref attach_vm_hooks);
|
||||
|
||||
@@ -365,11 +380,11 @@ namespace mbts.spark {
|
||||
modify_selected_orders_async_cmd.RaiseCanExecuteChanged();
|
||||
revert_selected_orders_cmd.RaiseCanExecuteChanged();
|
||||
}),
|
||||
_selected_params_mon.subscribe_security().to_security_md(bus).OnDispatcher().Subscribe(newval => order_mod_vm.security_md = newval),
|
||||
connect_common_selected_params(order_mod_vm));
|
||||
|
||||
IDisposable connect_common_selected_params(OrderParamsVM vm) =>
|
||||
Disposable.Create(
|
||||
_selected_params_mon.subscribe_security().OnDispatcher().to_security_md(bus).OnDispatcher().Subscribe(newval => vm.security_md = newval),
|
||||
_selected_params_mon.subscribe_price().OnDispatcher().Subscribe(vm.on_common_price),
|
||||
_selected_params_mon.subscribe_size().OnDispatcher().Subscribe(vm.on_common_size),
|
||||
_selected_params_mon.subscribe_account().OnDispatcher().Subscribe(newval => vm.selected_account = newval));
|
||||
@@ -807,12 +822,11 @@ namespace mbts.spark {
|
||||
_size_permissions = AlgoParamPermissions.ReadOnly | AlgoParamPermissions.Write;
|
||||
SecurityMD? _security_md;
|
||||
|
||||
public OrderParamsVM(OrderBookVM owner, AlgoFormats init_format, AlgoEditingPermissions init_permissions) {
|
||||
public OrderParamsVM(OrderBookVM owner, AlgoEditingPermissions init_permissions) {
|
||||
_owner = owner;
|
||||
algo_vm = AlgoDefinitionVM.create(
|
||||
owner._model,
|
||||
AlgoData.create_unpersisted(OrderDataHelper.Defaults.CustomOrderDefinitionImmutable(CustomOrderDefinition.CustomOneofCase.Iceberg), CustomOrderDefinition.CustomOneofCase.Iceberg.display_name()),
|
||||
init_format: init_format,
|
||||
editing_permissions: init_permissions);
|
||||
_accounts = backing(
|
||||
nameof(selected_account),
|
||||
@@ -879,6 +893,7 @@ namespace mbts.spark {
|
||||
public ReadOnlyObservableCollection<AccountTuple> accounts => _accounts.items;
|
||||
public AccountTuple? selected_account { get => _accounts.selected_item; set => _accounts.selected_item = value; }
|
||||
public SecurityImmutable? security => _owner._selected_params_mon.security;
|
||||
/// <see cref="security_md"/> should be synced with the root of the selected row(s),
|
||||
public SecurityMD? security_md {
|
||||
get => _security_md;
|
||||
set {
|
||||
|
||||
@@ -6,6 +6,7 @@ using bts.shell.fills;
|
||||
using bts.shell.orderbook;
|
||||
using bts.spark;
|
||||
using bts.view;
|
||||
using bts.utils.csv;
|
||||
using mbts.persist;
|
||||
using mbts.spark.utilities;
|
||||
using mbts.ui;
|
||||
@@ -231,6 +232,7 @@ namespace mbts.spark {
|
||||
toggle_collapse_all_command,
|
||||
toggle_expand_all_command,
|
||||
show_grid_settings_command,
|
||||
new SparkCommandCommand("Export to csv", Icons.Export, FileDialogCommand.export_csv(() => _vm.rows.ToCsv(OrderBookRowVM.csv_ordered_properties), "OrderBook")),
|
||||
// hidden cmds (i.e., keyboard shortcuts at window level)
|
||||
hidden_cmd(new SparkCommandCommand(OrderBookView.CommandDescriptions.ModifyOrders, null, _vm.modify_selected_orders_cmd, OrderBookView.KeyboardShortcuts.ModifyOrders)),
|
||||
hidden_cmd(new SparkCommandCommand(OrderBookView.CommandDescriptions.RevertOrders, null, _vm.revert_selected_orders_cmd, OrderBookView.KeyboardShortcuts.RevertOrders)),
|
||||
|
||||
@@ -622,9 +622,7 @@ namespace bts.shell.pnl {
|
||||
|
||||
static class PNLDataExtensions {
|
||||
public static string pnl_symbol(this SecurityImmutable security) {
|
||||
if(security.HasIce)
|
||||
return PNLICEHelper.get_symbol(security);
|
||||
return security.Symbol;
|
||||
return bts.api.ExchangeSpecificUitlities.get_pnl_symbol(security);
|
||||
}
|
||||
|
||||
// while override_cpp could use double.NaN to indicate the lack of an override,
|
||||
@@ -636,8 +634,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
public static (double default_cpp, double? override_cpp) pnl_cpp_tuple(this PNLUnitImmutable pnl_unit, SecurityImmutable security) {
|
||||
// TODO: actual impl
|
||||
double calced_pnl = PNLICEHelper.get_cpp(pnl_unit,security);
|
||||
return (calced_pnl, /*pnl_unit.HasCppOverride ? pnl_unit.CppOverride.Value : */(double?)null);
|
||||
double calced_pnl = bts.api.ExchangeSpecificUitlities.get_cpp(pnl_unit,security);
|
||||
return (calced_pnl, pnl_unit.HasCppOverride ? pnl_unit.CppOverride.Value : (double?)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.api.position;
|
||||
using bts.utils;
|
||||
using mbts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
|
||||
namespace bts.shell.pnl {
|
||||
|
||||
static class PNLICEHelper{
|
||||
|
||||
public static bool is_spread(SecurityImmutable sec){
|
||||
return sec.HasSpread && sec.Ice.StripName.Contains("/");
|
||||
}
|
||||
|
||||
public static bool is_strip(SecurityImmutable sec){
|
||||
return sec.HasSpread && !is_spread(sec);
|
||||
}
|
||||
|
||||
public static bool is_ice_lots(SecurityImmutable sec){
|
||||
return sec.Ice.MarketDescription.Contains("ICE Lots");
|
||||
}
|
||||
|
||||
public static double get_future_cpp (SecurityImmutable sec){
|
||||
if(sec.Symbol == "HHD")
|
||||
return 1;
|
||||
if(is_ice_lots(sec))
|
||||
return 2500;
|
||||
else{
|
||||
var days_in_month = DateTime.DaysInMonth(Convert.ToInt32(sec.Future.ExpirationYear),
|
||||
Convert.ToInt32(sec.Future.ExpirationMonth));
|
||||
return days_in_month; // because the size is multiplied by 2500 already
|
||||
}
|
||||
}
|
||||
|
||||
public static double get_spread_cpp(SecurityImmutable sec){
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static double get_strip_cpp(PNLUnitImmutable pnl,
|
||||
SecurityImmutable sec){
|
||||
double rv = 0;
|
||||
foreach (var l in sec.Spread.Legs)
|
||||
if(l.Security.HasFuture)
|
||||
rv += get_cpp(pnl,l.Security);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static string get_symbol (SecurityImmutable sec){
|
||||
var rv = String.Format("{0}{1}{2}",
|
||||
sec.Symbol,
|
||||
is_ice_lots(sec)? " ICE LOTS" : String.Empty,
|
||||
is_spread(sec)? " Spread" : String.Empty);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static double get_cpp (PNLUnitImmutable pnl,
|
||||
SecurityImmutable sec){
|
||||
if(sec.Symbol == "HHD")
|
||||
Console.WriteLine("yes!");
|
||||
if (sec.HasGlbx)
|
||||
return pnl.CashValue;
|
||||
else if (sec.HasIce){
|
||||
if(sec.HasFuture)
|
||||
return get_future_cpp(sec);
|
||||
else if(is_spread(sec))
|
||||
return get_spread_cpp(sec);
|
||||
else if(is_strip(sec))
|
||||
return get_strip_cpp(pnl,sec);
|
||||
}
|
||||
return Double.NaN;
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,5 +1,6 @@
|
||||
using bts;
|
||||
using bts.api;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using bts.collections;
|
||||
using bts.spark;
|
||||
@@ -26,11 +27,13 @@ namespace mbts.spark.utilities {
|
||||
public readonly Func<CustomOrderDefinition, CustomOrderDefinition> get_child;
|
||||
public readonly Action<CustomOrderDefinition, CustomOrderDefinition> assign_child;
|
||||
|
||||
public ChildAlgoData(string name, Func<IMessage, CustomOrderDefinition> get_child_from_impl,
|
||||
Action<IMessage, CustomOrderDefinition> assign_child_to_impl,
|
||||
Func<CustomOrderDefinition, CustomOrderDefinition> get_child,
|
||||
Action<CustomOrderDefinition, CustomOrderDefinition> assign_child)
|
||||
{
|
||||
public ChildAlgoData(
|
||||
string name,
|
||||
Func<IMessage, CustomOrderDefinition> get_child_from_impl,
|
||||
Action<IMessage, CustomOrderDefinition> assign_child_to_impl,
|
||||
Func<CustomOrderDefinition, CustomOrderDefinition> get_child,
|
||||
Action<CustomOrderDefinition, CustomOrderDefinition> assign_child) {
|
||||
//
|
||||
this.name = name;
|
||||
this.get_child = get_child;
|
||||
this.assign_child = assign_child;
|
||||
@@ -46,13 +49,19 @@ namespace mbts.spark.utilities {
|
||||
static readonly OrderMetadata _default_order_metadata = new OrderMetadata { KeyBinding = "", Color = BTSColors.Orders.default_order };
|
||||
readonly AdminModel _admin_model;
|
||||
readonly DynamicOrderHelper _dynamic_helper;
|
||||
readonly IAlgoProvider _security_algo_provider;
|
||||
readonly IReadOnlyDictionary<OneOf<CustomOrderDefinition.CustomOneofCase, string>, string> _algo_abbreviation_index;
|
||||
readonly IReadOnlyDictionary<string, DynamicOrderDescriptor> _dynamic_descriptors;
|
||||
IDisposable _dispose;
|
||||
|
||||
[ImportingConstructor]
|
||||
public OrderFactory(AdminModel admin_model, DynamicOrderHelper dynamic_helper) {
|
||||
public OrderFactory(OrderService service, AdminModel admin_model, DynamicOrderHelper dynamic_helper, IAlgoProvider security_algo_provider) {
|
||||
_admin_model = admin_model;
|
||||
_dynamic_helper = dynamic_helper;
|
||||
_dynamic_descriptors = service.get_registered_dynamic_order_types(new VoidMessage())
|
||||
.DynamicOrderDesc
|
||||
.ToDictionary(d => d.DynamicOrderType);
|
||||
_security_algo_provider = security_algo_provider;
|
||||
var algo_name_index = new HashSet<OneOf<CustomOrderDefinition.CustomOneofCase, string>>(OneOf<CustomOrderDefinition.CustomOneofCase, string>.ValueEqualityComparer);
|
||||
// add standard types
|
||||
algo_name_index.AddRange(
|
||||
@@ -86,66 +95,13 @@ namespace mbts.spark.utilities {
|
||||
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types() =>
|
||||
OrderDataHelper.exchange_order_types;
|
||||
|
||||
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types(SecurityImmutable? security) =>
|
||||
security.HasValue ? default_order_types(security.Value) : OrderDataHelper.exchange_order_types;
|
||||
|
||||
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types(SecurityImmutable security) {
|
||||
switch (security.ContractCase) {
|
||||
case Security.ContractOneofCase.Synthetic: return OrderDataHelper.spreader_order_types;
|
||||
default: return OrderDataHelper.exchange_order_types;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<CustomOrderDefinition.CustomOneofCase> default_order_types(SecurityImmutable? security, bool is_child = false) =>
|
||||
security.HasValue ? default_order_types(security.Value, is_child) : default_order_types();
|
||||
|
||||
public IEnumerable<TimeInForce> default_time_in_forces() =>
|
||||
EnumHelper.get_values_except(TimeInForce.Undefined);
|
||||
|
||||
public IEnumerable<TimeInForce> default_time_in_forces(SecurityImmutable security, bool is_child = false) =>
|
||||
default_time_in_forces();
|
||||
|
||||
public IEnumerable<TimeInForce> default_time_in_forces(SecurityImmutable security, CustomOrderDefinition.CustomOneofCase order_type, bool is_child = false) {
|
||||
var tifs = default_time_in_forces(security, is_child);
|
||||
var tifs = EnumHelper.get_values_except(TimeInForce.Undefined);
|
||||
if (order_type != CustomOrderDefinition.CustomOneofCase.Limit) {
|
||||
tifs = tifs.Except(new[] { TimeInForce.Ioc });
|
||||
}
|
||||
return tifs;
|
||||
}
|
||||
|
||||
public IEnumerable<TimeInForce> default_time_in_forces(SecurityImmutable? security, bool is_child = false) =>
|
||||
security.HasValue ? default_time_in_forces(security.Value, is_child) : default_time_in_forces();
|
||||
|
||||
public LadderSettings default_ladder_settings(SecurityImmutable security) {
|
||||
var settings = LadderSettings.Default;
|
||||
if (security.ContractCase == Security.ContractOneofCase.Synthetic)
|
||||
settings.default_order_type = CustomOrderDefinition.CustomOneofCase.Spreader;
|
||||
return settings;
|
||||
}
|
||||
|
||||
public Dictionary<AlgoKey, AlgoData> default_algos() =>
|
||||
default_algos((SecurityImmutable?)null);
|
||||
|
||||
public Dictionary<AlgoKey, AlgoData> default_algos(SecurityImmutable? security) =>
|
||||
default_algos(default_order_types(security));
|
||||
|
||||
public Dictionary<AlgoKey, AlgoData> default_algos(AlgoFormats algo_format) =>
|
||||
default_algos(OrderDataHelper.get_format_algo_types(algo_format));
|
||||
|
||||
public Dictionary<AlgoKey, AlgoData> default_algos(IEnumerable<CustomOrderDefinition.CustomOneofCase> types) {
|
||||
var def_map = new Dictionary<AlgoKey, AlgoData>();
|
||||
foreach (var ot in types.Except(new[] { CustomOrderDefinition.CustomOneofCase.Dynamic, CustomOrderDefinition.CustomOneofCase.Composite })) {
|
||||
var data = AlgoData.from_custom_def(OrderDataHelper.Defaults.CustomOrderDefinitionImmutable(ot));
|
||||
def_map[data.key] = data;
|
||||
}
|
||||
var dynamic_defs = new List<CustomOrderDefinitionImmutable>();
|
||||
_dynamic_helper.add_dynamic_order_defs(dynamic_defs, custom_order);
|
||||
foreach (var dd in dynamic_defs) {
|
||||
var data = AlgoData.from_custom_def(dd);
|
||||
def_map[data.key] = data;
|
||||
}
|
||||
return def_map;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public OrderDefinitionImmutable order(SecurityImmutable security) =>
|
||||
@@ -156,7 +112,7 @@ namespace mbts.spark.utilities {
|
||||
SecurityKey = security.Id,
|
||||
Side = Side.Buy,
|
||||
TimeInForce = TimeInForce.Day,
|
||||
CustomDef = custom_order(),
|
||||
CustomDef = OrderDataHelper.Defaults.CustomOrderDefinition(),
|
||||
CtiCode = CTICode.CtiCode1,
|
||||
CustomerOrFirm = CustomerOrFirm.Firm,
|
||||
// this will be the tag 50 on CME orders
|
||||
@@ -173,9 +129,6 @@ namespace mbts.spark.utilities {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public string abbreviate_algo(CustomOrderDefinitionImmutable defi) =>
|
||||
abbreviate_algo(_simple_algo_id(defi));
|
||||
|
||||
public string abbreviate_algo(OneOf<CustomOrderDefinition.CustomOneofCase, string> id) {
|
||||
if (id == null)
|
||||
throw new ArgumentNullException(nameof(id));
|
||||
@@ -187,26 +140,6 @@ namespace mbts.spark.utilities {
|
||||
}
|
||||
|
||||
// mutable definitions
|
||||
public CustomOrderDefinition custom_order() => OrderDataHelper.Defaults.CustomOrderDefinition();
|
||||
public MarketOrderDefinition market_order() => OrderDataHelper.Defaults.MarketOrderDefinition();
|
||||
public LimitOrderDefinition limit_order() => OrderDataHelper.Defaults.LimitOrderDefinition();
|
||||
public StopOrderDefinition stop_order() => OrderDataHelper.Defaults.StopOrderDefinition();
|
||||
public StopLimitOrderDefinition stop_limit_order() => OrderDataHelper.Defaults.StopLimitOrderDefinition();
|
||||
public GLBXIcebergOrderDefinition glbx_iceberg_order() => OrderDataHelper.Defaults.GLBXIcebergOrderDefinition();
|
||||
public IcebergOrderDefinition iceberg_order() => OrderDataHelper.Defaults.IcebergOrderDefinition();
|
||||
public TimeBoxOrderDefinition time_box_order() => OrderDataHelper.Defaults.TimeBoxOrderDefinition();
|
||||
public TickOrderDefinition tick_order() => OrderDataHelper.Defaults.TickOrderDefinition();
|
||||
public LeanOrderDefinition lean_order() => OrderDataHelper.Defaults.LeanOrderDefinition();
|
||||
public JoinOrderDefinition join_order() => OrderDataHelper.Defaults.JoinOrderDefinition();
|
||||
public TopOrderDefinition top_order() => OrderDataHelper.Defaults.TopOrderDefinition();
|
||||
public CoverOrderDefinition cover_order() => OrderDataHelper.Defaults.CoverOrderDefinition();
|
||||
public OCOOrderDefinition oco_order() => OrderDataHelper.Defaults.OCOOrderDefinition();
|
||||
public PricerOrderDefinition pricer_order() => OrderDataHelper.Defaults.PricerOrderDefinition();
|
||||
public OffsetOrderDefinition offset_order() => OrderDataHelper.Defaults.OffsetOrderDefinition();
|
||||
public TriggerOrderDefinition trigger_order() => OrderDataHelper.Defaults.TriggerOrderDefinition();
|
||||
public DynamicOrderDefinition dynamic_order() => OrderDataHelper.Defaults.DynamicOrderDefinition();
|
||||
public SpreaderOrderDefinition spreader_order() => OrderDataHelper.Defaults.SpreaderOrderDefinition();
|
||||
public SplitterOrderDefinition splitter_order() => OrderDataHelper.Defaults.SplitterOrderDefinition();
|
||||
public SpreaderOrderDefinition spreader_order(SecurityImmutable security, ExecutionStrategyImmutable strategy) =>
|
||||
new SpreaderOrderDefinition {
|
||||
Security = security.CloneToMutable(),
|
||||
@@ -214,40 +147,8 @@ namespace mbts.spark.utilities {
|
||||
};
|
||||
|
||||
// immutable definitions
|
||||
public CustomOrderDefinitionImmutable custom_orderi(CustomOrderDefinition.CustomOneofCase order_type) => new CustomOrderDefinitionImmutable(custom_order(order_type));
|
||||
public SpreaderOrderDefinitionImmutable spreader_orderi(SecurityImmutable security, ExecutionStrategyImmutable strategy) => new SpreaderOrderDefinitionImmutable(spreader_order(security, strategy));
|
||||
|
||||
public CustomOrderDefinition custom_order(CustomOrderDefinition.CustomOneofCase order_type) {
|
||||
var rv = new CustomOrderDefinition();
|
||||
switch (order_type) {
|
||||
case CustomOrderDefinition.CustomOneofCase.Market: rv.Market = market_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Limit: rv.Limit = limit_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Stop: rv.Stop = stop_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.StopLimit: rv.StopLimit = stop_limit_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.GlbxIceberg: rv.GlbxIceberg = glbx_iceberg_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Iceberg: rv.Iceberg = iceberg_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.TimeBox: rv.TimeBox = time_box_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Tick: rv.Tick = tick_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Lean: rv.Lean = lean_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Join: rv.Join = join_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Top: rv.Top = top_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Cover: rv.Cover = cover_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Oco: rv.Oco = oco_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Pricer: rv.Pricer = pricer_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Offset: rv.Offset = offset_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Trigger: rv.Trigger = trigger_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Spreader: rv.Spreader = spreader_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Splitter: rv.Splitter = splitter_order(); break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Dynamic: rv.Dynamic = dynamic_order(); break;
|
||||
//case CustomOrderDefinition.CustomOneofCase.QueueHolder: rv.QueueHolder = queue_holder_order(); break;
|
||||
default:
|
||||
OrderTypeVMFactory.GenericOrderFactory.setup_generic_custom_order(rv, order_type);
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
public OrderMetadata get_metadata(IMessage order_type_def) => get_metadata(OrderDataHelper.get_order_type(order_type_def));
|
||||
public OrderMetadata get_metadata(OrderRecordImmutable order) => get_metadata(order.Def.CustomDef.CustomCase);
|
||||
public OrderMetadata get_metadata(CustomOrderDefinition.CustomOneofCase order_type) {
|
||||
switch (order_type) {
|
||||
@@ -278,14 +179,6 @@ namespace mbts.spark.utilities {
|
||||
|
||||
public void Dispose() =>
|
||||
Disposable.dispose(ref _dispose);
|
||||
|
||||
static OneOf<CustomOrderDefinition.CustomOneofCase, string> _simple_algo_id(CustomOrderDefinitionImmutable defi) {
|
||||
switch (defi.CustomCase) {
|
||||
case CustomOrderDefinition.CustomOneofCase.Dynamic:
|
||||
return new OneOf<CustomOrderDefinition.CustomOneofCase, string>(defi.Dynamic.DynamicOrderType);
|
||||
default: return new OneOf<CustomOrderDefinition.CustomOneofCase, string>(defi.CustomCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class OrderDataHelper {
|
||||
@@ -301,8 +194,6 @@ namespace mbts.spark.utilities {
|
||||
}
|
||||
}
|
||||
|
||||
public static OneofDescriptor oneof_descriptor => _oneof_desc;
|
||||
|
||||
const double _price_error_margin = 0.0000001;
|
||||
const decimal _price_error_margin_decimal = 0.0000001m;
|
||||
|
||||
@@ -320,10 +211,10 @@ namespace mbts.spark.utilities {
|
||||
});
|
||||
|
||||
public static readonly IComparer<decimal> PriceComparerDecimal = Comparer<decimal>.Create((a, b) => {
|
||||
decimal diff = a - b;
|
||||
if (diff <= _price_error_margin_decimal && diff >= -_price_error_margin_decimal)
|
||||
return 0;
|
||||
return diff > 0 ? 1 : -1;
|
||||
decimal diff = a - b;
|
||||
if (diff <= _price_error_margin_decimal && diff >= -_price_error_margin_decimal)
|
||||
return 0;
|
||||
return diff > 0 ? 1 : -1;
|
||||
});
|
||||
|
||||
const string _primary_child_field = "child";
|
||||
@@ -378,7 +269,7 @@ namespace mbts.spark.utilities {
|
||||
switch (cd.CustomCase) {
|
||||
case CustomOrderDefinition.CustomOneofCase.Composite: studio = cd.Composite.AlgoTemplateKey; break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Dynamic: dyn = cd.Dynamic.DynamicOrderType; break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Spreader: spreader_sec = cd.Spreader.Security.Id; break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Spreader: spreader_sec = cd.Spreader.Security?.Id ?? 0; break;
|
||||
}
|
||||
yield return (cd.CustomCase, dyn, studio, spreader_sec);
|
||||
}
|
||||
@@ -466,22 +357,6 @@ namespace mbts.spark.utilities {
|
||||
child_data.TryGetFirst(out best_match) ? best_match : (ChildAlgoData?)null;
|
||||
}
|
||||
|
||||
public static CustomOrderDefinition create_algo(CustomOrderDefinition.CustomOneofCase algo_type) {
|
||||
var algo = new CustomOrderDefinition();
|
||||
if (_algo_type_case_descriptor_data.TryGetValue(algo_type, out AlgoTypeCaseDescriptorData desc))
|
||||
desc.type_case_descriptor.Accessor.SetValue(algo, ProtoHelper.mutable_factory(ProtoHelper.get_field_type(desc.type_case_descriptor)));
|
||||
return algo;
|
||||
}
|
||||
|
||||
public static bool append_algo_node(CustomOrderDefinition target, CustomOrderDefinition.CustomOneofCase algo_type) {
|
||||
if (_algo_type_case_descriptor_data.TryGetValue(algo_type, out var desc)) {
|
||||
var node = ProtoHelper.mutable_factory(ProtoHelper.get_field_type(desc.type_case_descriptor));
|
||||
desc.type_case_descriptor.Accessor.SetValue(target, node);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IReadOnlyList<ChildAlgoData> get_child_algo_data(CustomOrderDefinition.CustomOneofCase algo_type) =>
|
||||
_algo_type_case_descriptor_data.TryGetValue(algo_type, out AlgoTypeCaseDescriptorData d) ? d.child_algo_data : Array.Empty<ChildAlgoData>();
|
||||
#endregion
|
||||
@@ -535,122 +410,10 @@ namespace mbts.spark.utilities {
|
||||
}
|
||||
}
|
||||
|
||||
public static AlgoFormats get_algo_format(Security.ContractOneofCase? security_type) =>
|
||||
security_type.HasValue ? get_algo_format(security_type.Value) : AlgoFormats.Exchange;
|
||||
|
||||
public static AlgoFormats get_algo_format(Security.ContractOneofCase security_type) =>
|
||||
security_type == Security.ContractOneofCase.Synthetic ? AlgoFormats.Spreader : AlgoFormats.Exchange;
|
||||
|
||||
public static HashSet<CustomOrderDefinition.CustomOneofCase> get_format_algo_types(AlgoFormats f) {
|
||||
var rv = new HashSet<CustomOrderDefinition.CustomOneofCase>();
|
||||
if ((f & AlgoFormats.Exchange) == AlgoFormats.Exchange) {
|
||||
rv.AddRange(exchange_order_types);
|
||||
if ((f & AlgoFormats.Spreader) == AlgoFormats.Spreader) {
|
||||
rv.IntersectWith(spreader_order_types);
|
||||
}
|
||||
} else if ((f & AlgoFormats.Spreader) == AlgoFormats.Spreader) {
|
||||
rv.AddRange(spreader_order_types);
|
||||
}
|
||||
if ((f & AlgoFormats.Attachable) == AlgoFormats.Attachable)
|
||||
rv.AddRange(attachable_order_types);
|
||||
if ((f & AlgoFormats.DefaultPlaceholder) == AlgoFormats.DefaultPlaceholder)
|
||||
rv.Add(CustomOrderDefinition.CustomOneofCase.None);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static CustomOrderDefinition.CustomOneofCase get_default_algo(AlgoFormats f) {
|
||||
switch (f) {
|
||||
case AlgoFormats.Exchange: return CustomOrderDefinition.CustomOneofCase.Limit;
|
||||
case AlgoFormats.Spreader: return CustomOrderDefinition.CustomOneofCase.Spreader;
|
||||
default: return CustomOrderDefinition.CustomOneofCase.None;
|
||||
}
|
||||
}
|
||||
|
||||
public static IReadOnlyDictionary<AlgoKey, AlgoData> get_format_algo_data(AlgoFormats f) {
|
||||
var algo_types = get_format_algo_types(f);
|
||||
var algo_dict = algo_types.Select(at => AlgoData.from_custom_def(Defaults.CustomOrderDefinitionImmutable(at))).ToDictionaryCrushed(a => a.key);
|
||||
return algo_dict;
|
||||
}
|
||||
|
||||
public static HashSet<CustomOrderDefinition.CustomOneofCase> get_algo_types_present(CustomOrderDefinitionImmutable def) {
|
||||
return new HashSet<CustomOrderDefinition.CustomOneofCase>(impl(def.CloneToMutable()));
|
||||
// hide mutable-def implementation
|
||||
IEnumerable<CustomOrderDefinition.CustomOneofCase> impl(CustomOrderDefinition mdef) {
|
||||
yield return mdef.CustomCase;
|
||||
foreach (var sd in get_child_algo_data(mdef)) {
|
||||
var child = sd.get_child(mdef);
|
||||
if (child != null) {
|
||||
yield return child.CustomCase;
|
||||
foreach (var t in impl(child))
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static CustomOrderDefinitionImmutable? fit_to_type(CustomOrderDefinitionImmutable defi, Security.ContractOneofCase security_type, bool fit_all_to_spreader = false) {
|
||||
var mdef = defi.CloneToMutable();
|
||||
public static CustomOrderDefinition.CustomOneofCase get_default_algo(Security.ContractOneofCase security_type) {
|
||||
switch (security_type) {
|
||||
case Security.ContractOneofCase.Synthetic:
|
||||
mdef = spreader_impl(mdef);
|
||||
break;
|
||||
default:
|
||||
mdef = outright_impl(mdef);
|
||||
break;
|
||||
}
|
||||
if (mdef == null)
|
||||
return null;
|
||||
return new CustomOrderDefinitionImmutable(mdef);
|
||||
// local methods
|
||||
CustomOrderDefinition spreader_impl(CustomOrderDefinition def) {
|
||||
if (def == null) {
|
||||
def = new CustomOrderDefinition { Spreader = new SpreaderOrderDefinition() };
|
||||
} else {
|
||||
switch (def.CustomCase) {
|
||||
case CustomOrderDefinition.CustomOneofCase.Limit:
|
||||
case CustomOrderDefinition.CustomOneofCase.None:
|
||||
def = new CustomOrderDefinition { Spreader = new SpreaderOrderDefinition() };
|
||||
break;
|
||||
case CustomOrderDefinition.CustomOneofCase.Stop:
|
||||
case CustomOrderDefinition.CustomOneofCase.StopLimit:
|
||||
case CustomOrderDefinition.CustomOneofCase.Market:
|
||||
case CustomOrderDefinition.CustomOneofCase.GlbxIceberg:
|
||||
def = fit_all_to_spreader ? new CustomOrderDefinition { Spreader = new SpreaderOrderDefinition() } : null;
|
||||
break;
|
||||
default:
|
||||
var desc_data = _algo_type_case_descriptor_data[def.CustomCase];
|
||||
foreach (var cad in desc_data.child_algo_data) {
|
||||
var child = spreader_impl(cad.get_child(def));
|
||||
if (child == null)
|
||||
return null;
|
||||
var type_def = (IMessage)desc_data.type_case_descriptor.Accessor.GetValue(def);
|
||||
cad.assign_child_to_impl(type_def, child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
}
|
||||
CustomOrderDefinition outright_impl(CustomOrderDefinition def) {
|
||||
if (def == null) {
|
||||
def = new CustomOrderDefinition { Limit = new LimitOrderDefinition() };
|
||||
} else {
|
||||
switch (def.CustomCase) {
|
||||
case CustomOrderDefinition.CustomOneofCase.Spreader:
|
||||
case CustomOrderDefinition.CustomOneofCase.None:
|
||||
def = new CustomOrderDefinition { Limit = new LimitOrderDefinition() };
|
||||
break;
|
||||
default:
|
||||
foreach (var cad in get_child_algo_data(def)) {
|
||||
var child = outright_impl(cad.get_child(def));
|
||||
if (child == null)
|
||||
return null;
|
||||
cad.assign_child(def, child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return def;
|
||||
case Security.ContractOneofCase.Synthetic: return CustomOrderDefinition.CustomOneofCase.Spreader;
|
||||
default: return CustomOrderDefinition.CustomOneofCase.Limit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,7 +441,7 @@ namespace mbts.spark.utilities {
|
||||
CustomOrderDefinition.CustomOneofCase.Iceberg,
|
||||
CustomOrderDefinition.CustomOneofCase.Lean,
|
||||
CustomOrderDefinition.CustomOneofCase.Join,
|
||||
CustomOrderDefinition.CustomOneofCase.Cover,
|
||||
CustomOrderDefinition.CustomOneofCase.Cover,
|
||||
CustomOrderDefinition.CustomOneofCase.Top,
|
||||
CustomOrderDefinition.CustomOneofCase.Splitter,
|
||||
CustomOrderDefinition.CustomOneofCase.Scratch,
|
||||
@@ -764,12 +527,6 @@ namespace mbts.spark.utilities {
|
||||
|
||||
public static bool equals(CustomOrderDefinitionImmutable a, CustomOrderDefinitionImmutable b) => custom_order_defi_comparer.Equals(a, b);
|
||||
|
||||
public static bool structure_equals(CustomOrderDefinitionImmutable a, CustomOrderDefinitionImmutable b) {
|
||||
return impl(a.CloneToMutable(), b.CloneToMutable());
|
||||
bool impl(CustomOrderDefinition ma, CustomOrderDefinition mb) =>
|
||||
ma.CustomCase == mb.CustomCase && get_child_algo_data(ma).All(cad => impl(cad.get_child(ma), cad.get_child(mb)));
|
||||
}
|
||||
|
||||
public static bool iceberg_equals(IcebergOrderDefinitionImmutable a, IcebergOrderDefinitionImmutable b) =>
|
||||
a.ShowQuantity.Equals(b.ShowQuantity) && a.HasChild ? b.HasChild && equals(a.Child, b.Child) : !b.HasChild;
|
||||
|
||||
@@ -1031,7 +788,6 @@ namespace mbts.spark.utilities {
|
||||
}
|
||||
};
|
||||
|
||||
public static OrderDefinitionImmutable OrderDefinitionImmutable { get; } = new OrderDefinitionImmutable(OrderDefinition);
|
||||
public static OrderRecordImmutable OrderRecordImmutable { get; } = new OrderRecordImmutable(OrderRecord);
|
||||
|
||||
public static CustomOrderDefinition CustomOrderDefinition() => new CustomOrderDefinition { Limit = LimitOrderDefinition() };
|
||||
@@ -1084,9 +840,6 @@ namespace mbts.spark.utilities {
|
||||
public static TriggerOrderDefinition TriggerOrderDefinition() => new TriggerOrderDefinition { Child = CustomOrderDefinition(), TriggerCondition = new TriggerCondition(), TriggerAction = new TriggerAction(), };
|
||||
public static DynamicOrderDefinition DynamicOrderDefinition() => new DynamicOrderDefinition();
|
||||
public static SpreaderOrderDefinition SpreaderOrderDefinition() => new SpreaderOrderDefinition { ExecutionStrategy = new ExecutionStrategy() };
|
||||
|
||||
public static SplitterOrderDefinition SplitterOrderDefinition() => new SplitterOrderDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -82,13 +82,8 @@ namespace mbts.spark {
|
||||
CustomSort = AlgoCollectionHelper.algo_definition_vm_comparer.to_non_generic(),
|
||||
IsLiveSorting = true
|
||||
};
|
||||
algo_definitions_view.Filter = d => {
|
||||
if (d.key.mode == AlgoKey.Mode.Persisted && _algo_metadata.TryGetValue(d.key, out AlgoDefinitionMetadata meta) && meta.is_hidden)
|
||||
return false;
|
||||
var sec_fmt = OrderDataHelper.get_algo_format(security.ContractCase);
|
||||
return (d.selected_format & sec_fmt) == sec_fmt;
|
||||
};
|
||||
_algo_definitions_view.LiveFilteringProperties.Add(nameof(AlgoDefinitionVM.selected_format));
|
||||
algo_definitions_view.Filter = d =>
|
||||
!(d.key.mode == AlgoKey.Mode.Persisted && _algo_metadata.TryGetValue(d.key, out AlgoDefinitionMetadata meta) && meta.is_hidden);
|
||||
_algo_definitions_view.LiveSortingProperties.Add(nameof(AlgoDefinitionVM.group));
|
||||
_algo_definitions_view.LiveSortingProperties.Add(nameof(AlgoDefinitionVM.name));
|
||||
algo_definitions_view.GroupDescriptions.Add(new PropertyGroupDescription(nameof(AlgoDefinitionVM.group)));
|
||||
@@ -167,33 +162,27 @@ namespace mbts.spark {
|
||||
undo_definition_observer,
|
||||
redo_definition_observer,
|
||||
revert_definition_observer),
|
||||
security_md_source.Select(smd => model.factory.default_algos(smd.security)).Table(s => s.key).Subscribe(factory_defs => {
|
||||
using (_selected_algo_definition.begin_update())
|
||||
AlgoCollectionHelper.update_persisted_definitions(_algo_definitions, factory_defs, fd => {
|
||||
var vm = AlgoDefinitionVM.create(_model, fd, init_format: OrderDataHelper.get_algo_format(security.ContractCase), editing_permissions: AlgoEditingPermissions.AllowEditValues);
|
||||
vm.selected_format = OrderDataHelper.get_algo_format(security.ContractCase);
|
||||
return vm;
|
||||
});
|
||||
}),
|
||||
model.algo_model.definitions.Subscribe(_definitions_buffer),
|
||||
_definitions_buffer.OnDispatcher().Subscribe(u => {
|
||||
AlgoCollectionHelper.update_persisted_definitions(_algo_definitions, u, def_data => {
|
||||
var def_vm = AlgoDefinitionVM.create(model, def_data, OrderDataHelper.get_algo_format(security.ContractCase), AlgoEditingPermissions.AllowEditValues);
|
||||
def_vm.selected_format = OrderDataHelper.get_algo_format(security.ContractCase);
|
||||
def_vm.favorite_index = _get_favorite_algo_index(def_vm.key);
|
||||
return def_vm;
|
||||
});
|
||||
security_source.SelectManyInSeries(model.subscribe_algo_meta_tuples)
|
||||
.OnDispatcher()
|
||||
.Subscribe(table => {
|
||||
using (_selected_algo_definition.begin_update()) {
|
||||
foreach (var (algo, meta) in table.removed)
|
||||
_algo_definitions.Remove(algo.key);
|
||||
foreach (var (algo, meta) in table.changed) {
|
||||
var vm = _algo_definitions[algo.key];
|
||||
vm.load(algo);
|
||||
vm.favorite_index = _get_favorite_algo_index(vm.key);
|
||||
}
|
||||
foreach (var (algo, meta) in table.added) {
|
||||
var vm = AlgoDefinitionVM.create(_model, algo, AlgoEditingPermissions.AllowEditValues);
|
||||
vm.favorite_index = _get_favorite_algo_index(vm.key);
|
||||
_algo_definitions.Add(vm);
|
||||
}
|
||||
}
|
||||
}),
|
||||
model.algo_model.metadata_service.subscribe_metadata().OnDispatcher().Subscribe(_on_template_metadata),
|
||||
ObservableAutoWrapper.connect_item_hooks(algo_definitions, vm =>
|
||||
Disposable.Create(
|
||||
vm.connect_data(nullable_security_md_source),
|
||||
security_source.Subscribe(s => {
|
||||
var fmt = OrderDataHelper.get_algo_format(s.ContractCase);
|
||||
foreach (var d in algo_definitions)
|
||||
d.selected_format = fmt;
|
||||
}),
|
||||
vm),
|
||||
Disposable.Create(vm.connect_data(nullable_security_md_source), vm),
|
||||
true)) {
|
||||
() => Disposable.dispose(ref _algo_param_rows_hook)
|
||||
};
|
||||
@@ -325,13 +314,11 @@ namespace mbts.spark {
|
||||
public bool open_algo_popup_on_select { get => _open_algo_popup_on_select; set => Set(ref _open_algo_popup_on_select, value); }
|
||||
// commands
|
||||
public ICommand save_definition_cmd { get; }
|
||||
public ICommand save_template_cmd { get; }
|
||||
public ICommand revert_definition_cmd { get; }
|
||||
public ICommand set_default_algo_params_cmd { get; }
|
||||
public ICommand revert_algo_params_cmd { get; }
|
||||
public ICommand undo_definition_cmd { get; }
|
||||
public ICommand redo_definition_cmd { get; }
|
||||
public ICommand remove_template_cmd { get; }
|
||||
public ICommand toggle_is_favorite_cmd { get; }
|
||||
|
||||
public IObservable<AccountTuple?> observe_account(bool start_immediately = false) =>
|
||||
@@ -396,4 +383,4 @@ namespace mbts.spark {
|
||||
algo_definitions_view.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,7 @@ using mbts.ui;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AlgoDef = bts.api.orderman.CustomOrderDefinition;
|
||||
using AlgoDefi = bts.api.orderman.CustomOrderDefinitionImmutable;
|
||||
using CompositeDef = bts.api.orderman.CompositeOrderDefinition;
|
||||
using CompositeDefi = bts.api.orderman.CompositeOrderDefinitionImmutable;
|
||||
|
||||
@@ -21,6 +19,7 @@ namespace mbts.spark {
|
||||
: base(id, display_name, editing_permissions) { }
|
||||
|
||||
public override string abbreviation => _studio_meta?.abbreviation ?? base.abbreviation;
|
||||
public override AlgoDisplayGroup group => AlgoDisplayGroup.Studio;
|
||||
public override OrderMetadata meta {
|
||||
get {
|
||||
var m = new OrderMetadata { KeyBinding = string.Empty, NoProps = false };
|
||||
@@ -66,4 +65,4 @@ namespace mbts.spark {
|
||||
protected override void validate() => base.validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using AlgoDef = bts.api.orderman.CustomOrderDefinition;
|
||||
using AlgoDefi = bts.api.orderman.CustomOrderDefinitionImmutable;
|
||||
@@ -19,7 +18,6 @@ namespace mbts.spark {
|
||||
static readonly AlgoDefi _empty = new AlgoDefi(new AlgoDef());
|
||||
readonly ObservableAggregateCollection<IAlgoParamVM> _algo_params = new ObservableAggregateCollection<IAlgoParamVM>();
|
||||
readonly VersionContainer<AlgoDefi> _definition;
|
||||
AlgoFormats _format;
|
||||
AlgoEditingPermissions _editing_permissions;
|
||||
SecurityMD? _security_md;
|
||||
OrdersModel _model;
|
||||
@@ -84,10 +82,8 @@ namespace mbts.spark {
|
||||
void IObserver<SecurityMD?>.OnNext(SecurityMD? security_md) {
|
||||
var orig_group = group;
|
||||
_security_md = security_md;
|
||||
if (security_md.HasValue)
|
||||
_format = OrderDataHelper.get_algo_format(security_md.Value.security.ContractCase);
|
||||
var orig_def = definition;
|
||||
var fmt_type = OrderDataHelper.get_default_algo(_format);
|
||||
var fmt_type = OrderDataHelper.get_default_algo(security_md.HasValue ? security_md.Value.security.ContractCase : bts.api.Security.ContractOneofCase.None);
|
||||
switch (fmt_type) {
|
||||
case AlgoType.None: _clear_impl(); break;
|
||||
default:
|
||||
|
||||
@@ -2,7 +2,6 @@ using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.utils;
|
||||
using Google.Protobuf.Reflection;
|
||||
using mbts.utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
@@ -15,13 +14,15 @@ namespace mbts.spark {
|
||||
static readonly IReadOnlyDictionary<DynamicOrderParam.ValueOneofCase, (FieldDescriptor field_descriptor, Type field_type)> _descriptor_case_index =
|
||||
ProtoHelper.get_oneof_descriptor_index<DynamicOrderParam, DynamicOrderParam.ValueOneofCase>(nameof(DynamicOrderParam.ValueCase));
|
||||
|
||||
readonly RegisteredDynamicOrderTypes _dynamic_types;
|
||||
readonly Dictionary<string, DynamicOrderDescriptor> _dyn_types = new Dictionary<string, DynamicOrderDescriptor>(StringComparer.CurrentCultureIgnoreCase);
|
||||
|
||||
[ImportingConstructor]
|
||||
DynamicOrderHelper(OrderService order_service) =>
|
||||
_dynamic_types = order_service.get_registered_dynamic_order_types(new VoidMessage());
|
||||
DynamicOrderHelper(OrderService order_service) {
|
||||
foreach (var dt in order_service.get_registered_dynamic_order_types(new VoidMessage()).DynamicOrderDesc)
|
||||
_dyn_types[dt.DynamicOrderType] = dt;
|
||||
}
|
||||
|
||||
public IEnumerable<string> dynamic_types => _dynamic_types.DynamicOrderDesc.Select(d => d.DynamicOrderType);
|
||||
public IEnumerable<string> dynamic_types => _dyn_types.Keys;
|
||||
|
||||
public static string fmt_param(DynamicOrderParam dyn_param) {
|
||||
if (dyn_param == null)
|
||||
@@ -50,7 +51,7 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public void add_dynamic_order_defs(List<CustomOrderDefinitionImmutable> defs, Func<CustomOrderDefinition.CustomOneofCase, CustomOrderDefinition> factory) {
|
||||
foreach (var d in _dynamic_types.DynamicOrderDesc) {
|
||||
foreach (var d in _dyn_types.Values) {
|
||||
var dorder = factory(CustomOrderDefinition.CustomOneofCase.Dynamic);
|
||||
dorder.Dynamic.DynamicOrderType = d.DynamicOrderType;
|
||||
var ddef = dorder.Dynamic;
|
||||
@@ -60,8 +61,20 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
public bool try_parse(string str, out string dynamic_type) {
|
||||
if (_dyn_types.TryGetValue(str, out var desc)) {
|
||||
dynamic_type = desc.DynamicOrderType;
|
||||
return true;
|
||||
}
|
||||
dynamic_type = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal DynamicOrderDescriptor get_descriptor(string dynamic_type) =>
|
||||
_dynamic_types.DynamicOrderDesc.FirstOrDefault(d => d.DynamicOrderType == dynamic_type) ?? new DynamicOrderDescriptor();
|
||||
_dyn_types.TryGetValue(dynamic_type, out var desc) ? desc : new DynamicOrderDescriptor();
|
||||
|
||||
internal CustomOrderDefinitionImmutable create_custom_defi(string dynamic_type) =>
|
||||
new CustomOrderDefinitionImmutable(new CustomOrderDefinition { Dynamic = create_def(dynamic_type) });
|
||||
|
||||
internal DynamicOrderDefinition create_def(string dynamic_type) {
|
||||
var desc = get_descriptor(dynamic_type);
|
||||
|
||||
@@ -122,12 +122,6 @@ namespace mbts.spark {
|
||||
public static Color safe_get_badge_color(this IAlgoVM vm) =>
|
||||
vm == null ? default : vm.meta.Color.rgb_color();
|
||||
|
||||
public static IDisposable load_algo_data_recursive(this IAlgoSelector selector, IReadOnlyDictionary<AlgoKey, AlgoData> algo_data, AlgoKey? default_algo) {
|
||||
selector.load_algo_data(algo_data, default_algo);
|
||||
return ObservableAutoWrapper.connect_item_hooks(selector.algos, vm =>
|
||||
ObservableAutoWrapper.connect_item_hooks(vm.child_algo_selectors, s => load_algo_data_recursive(s, algo_data, default_algo)));
|
||||
}
|
||||
|
||||
public static IEnumerable<IAlgoParamVM> enumerate_all_params(this IAlgoVM vm) =>
|
||||
vm == null ? Enumerable.Empty<IAlgoParamVM>() : vm.algo_params.Concat(vm.child_algo_selectors.SelectMany(s => enumerate_all_params(s.selected_algo)));
|
||||
|
||||
|
||||
@@ -1,16 +1,82 @@
|
||||
using bts.api.orderman;
|
||||
using mbts.ui;
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace mbts.spark {
|
||||
static partial class OrderTypeVMFactory {
|
||||
class IcebergOrderVM : OrderTypeVMBase<IcebergOrderDefinition, IcebergOrderDefinitionImmutable> {
|
||||
readonly Property<double> _show_quantity;
|
||||
readonly DisplayQuantityMultiplier<double> _display_qty_translator = DisplayQuantityMultiplier.create_double();
|
||||
new IDisposable _dispose;
|
||||
|
||||
public IcebergOrderVM(AlgoKey key, string display_name, AlgoEditingPermissions editing_permissions)
|
||||
: base(key, display_name, editing_permissions) {
|
||||
_show_quantity = add_property(nameof(show_quantity), IcebergOrderDefinition.ShowQuantityFieldNumber, double.NaN, double.NaN);
|
||||
_show_quantity = add_property(
|
||||
"show_quantity",
|
||||
IcebergOrderDefinition.ShowQuantityFieldNumber,
|
||||
double.NaN,
|
||||
double.NaN,
|
||||
to_display_value: v => _qty_conversion.to_display(v),
|
||||
from_display_value: v => _qty_conversion.from_display(v),
|
||||
refresh_display_value:
|
||||
Observable.Create<Unit>(o => {
|
||||
_request_refresh_display += refresh;
|
||||
return Disposable.Create(() => _request_refresh_display -= refresh);
|
||||
void refresh() =>
|
||||
o.OnNext(Unit.Default);
|
||||
}));
|
||||
_show_quantity.Changed += on_show_quantity_changed;
|
||||
_dispose = Disposable.Create(
|
||||
_display_qty_translator.connect_owner(this, nameof(display_show_quantity)),
|
||||
_display_qty_translator.subscribe_actual_value().Subscribe(v => _show_quantity.Value = v),
|
||||
Disposable.Create(() => _show_quantity.Changed -= on_show_quantity_changed));
|
||||
|
||||
void on_show_quantity_changed(double oldval, double newval) =>
|
||||
_display_qty_translator.actual_value = newval;
|
||||
}
|
||||
|
||||
public double show_quantity { get => _show_quantity.Value; set => _show_quantity.set(value); }
|
||||
event Action _request_refresh_display;
|
||||
|
||||
public double display_show_quantity {
|
||||
get => _display_qty_translator.display_value;
|
||||
set => _display_qty_translator.display_value = value;
|
||||
}
|
||||
|
||||
QuantityConversionData _qty_conversion {
|
||||
get => _display_qty_translator.conversion_data;
|
||||
set {
|
||||
if (_display_qty_translator.conversion_data != value) {
|
||||
_display_qty_translator.conversion_data = value;
|
||||
_request_refresh_display?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void on_model_internal() =>
|
||||
_refresh_display();
|
||||
|
||||
protected override void on_security_internal() =>
|
||||
_refresh_display();
|
||||
|
||||
void _refresh_display() {
|
||||
if (model == null) {
|
||||
_qty_conversion = default;
|
||||
} else {
|
||||
var divisor = model.security_auxiliary_model.get_display_quantity_divisor(security);
|
||||
if (divisor == 1 || divisor == 0) {
|
||||
_qty_conversion = default;
|
||||
} else {
|
||||
_qty_conversion = new QuantityConversionData(divisor, QuantityConversionData.OpType.DivideActual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing) {
|
||||
Disposable.dispose(ref _dispose);
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -61,7 +62,9 @@ namespace mbts.spark {
|
||||
public static IAlgoVM composite(AlgoKey key, string display_name, AlgoEditingPermissions editing_permissions) => new CompositeAlgoVM(key, display_name, editing_permissions);
|
||||
|
||||
public static IAlgoVM create(AlgoData def_data, AlgoEditingPermissions editing_permissions = default_editing_permissions, bool is_expanded = false) {
|
||||
var vm = create(def_data.key, def_data.name, def_data.value.CustomCase, editing_permissions, is_expanded);
|
||||
var vm = def_data.key.is_persisted ?
|
||||
new CompositeAlgoVM(def_data.key, def_data.name, editing_permissions) :
|
||||
create(def_data.key, def_data.name, def_data.value.CustomCase, editing_permissions, is_expanded);
|
||||
vm.load_from(def_data.value);
|
||||
return vm;
|
||||
}
|
||||
@@ -79,7 +82,7 @@ namespace mbts.spark {
|
||||
case AlgoType.Join: vm = join(key, name, editing_permissions); break;
|
||||
case AlgoType.Top: vm = top(key, name, editing_permissions); break;
|
||||
case AlgoType.Cover: vm = cover(key, name, editing_permissions); break;
|
||||
case AlgoType.Oco : return oco(key, name, editing_permissions);
|
||||
case AlgoType.Oco: return oco(key, name, editing_permissions);
|
||||
case AlgoType.Pricer: return pricer(key, name, editing_permissions);
|
||||
case AlgoType.Offset: vm = offset(key, name, editing_permissions); break;
|
||||
case AlgoType.Trigger: vm = trigger(key, name, editing_permissions); break;
|
||||
@@ -87,13 +90,10 @@ namespace mbts.spark {
|
||||
case AlgoType.Iceberg: vm = iceberg(key, name, editing_permissions); break;
|
||||
case AlgoType.Spreader: vm = spreader(key, name, editing_permissions); break;
|
||||
case AlgoType.Dynamic: vm = dynamic(key, name, name, editing_permissions); break;
|
||||
case AlgoType.Splitter: vm = splitter(key,name,editing_permissions); break;
|
||||
case AlgoType.Splitter: vm = splitter(key, name, editing_permissions); break;
|
||||
case AlgoType.Composite: vm = composite(key, name, editing_permissions); break;
|
||||
case AlgoType.None: vm = new DefaultAlgoVM(); break;
|
||||
default: vm = generic(key, name, algo_type, editing_permissions); break;
|
||||
//default:
|
||||
// Log.Ui.debug_fatal($"Failed to create {typeof(IAlgoVM)}: unknown algo type '{algo_type}.'");
|
||||
// return new DefaultAlgoVM();
|
||||
}
|
||||
vm.is_expanded = is_expanded && vm.can_expand;
|
||||
return vm;
|
||||
@@ -269,12 +269,7 @@ namespace mbts.spark {
|
||||
|
||||
void selector_load_impl(AlgoSelectorData sd) {
|
||||
var inner_def = sd.get_order(value);
|
||||
if (inner_def.HasValue) {
|
||||
if (security.HasValue) {
|
||||
inner_def = OrderDataHelper.fit_to_type(inner_def.Value, security.Value.ContractCase);
|
||||
if (!inner_def.HasValue)
|
||||
return;
|
||||
}
|
||||
if (inner_def.HasValue && inner_def.Value.CustomCase != AlgoType.None) {
|
||||
var ival = inner_def.Value;
|
||||
var vm = sd.selector.algos.GetOrAdd(
|
||||
AlgoKey.from_custom_def(ival),
|
||||
@@ -317,18 +312,12 @@ namespace mbts.spark {
|
||||
}
|
||||
AlgoKey key;
|
||||
if (security.HasValue) {
|
||||
init = OrderDataHelper.fit_to_type(init.Value, security.Value.ContractCase);
|
||||
if (!init.HasValue)
|
||||
return;
|
||||
key = AlgoKey.from_custom_def(init.Value);
|
||||
child_list.Add(init.Value);
|
||||
for (int i = 1; i < algos.Count; i++) {
|
||||
var child = sd.get_from_impl(algos[i]);
|
||||
if (!child.HasValue || key != AlgoKey.from_custom_def(child.Value))
|
||||
return;
|
||||
child = OrderDataHelper.fit_to_type(child.Value, security.Value.ContractCase);
|
||||
if (!child.HasValue)
|
||||
return;
|
||||
child_list.Add(child.Value);
|
||||
}
|
||||
} else {
|
||||
@@ -372,7 +361,6 @@ namespace mbts.spark {
|
||||
}),
|
||||
c.assign_child);
|
||||
}
|
||||
_populate_selectors();
|
||||
}
|
||||
// local methods
|
||||
IDisposable reset() {
|
||||
@@ -415,9 +403,19 @@ namespace mbts.spark {
|
||||
#endregion
|
||||
|
||||
#region Auto-Properties (non-child-algo params)
|
||||
protected Property<T> add_property<T>(string prop_name, int target_field_number, T init_value = default, T non_uniform_value = default, bool validate_on_changed = false, AlgoParamPermissions permissions = AlgoParamPermissions.ReadWrite) {
|
||||
protected Property<T> add_property<T>(
|
||||
string prop_name,
|
||||
int target_field_number,
|
||||
T init_value = default,
|
||||
T non_uniform_value = default,
|
||||
bool validate_on_changed = false,
|
||||
AlgoParamPermissions permissions = AlgoParamPermissions.ReadWrite,
|
||||
Func<T, T> to_display_value = null,
|
||||
Func<T, T> from_display_value = null,
|
||||
IObservable<Unit> refresh_display_value = null) {
|
||||
//
|
||||
var prop = backing(prop_name, init_value);
|
||||
_on_property_added(prop_name, target_field_number, prop, prop.set, non_uniform_value, validate_on_changed, permissions);
|
||||
_on_property_added(prop_name, target_field_number, prop, prop.set, non_uniform_value, validate_on_changed, permissions, to_display_value, from_display_value, refresh_display_value);
|
||||
return prop;
|
||||
}
|
||||
|
||||
@@ -592,17 +590,25 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
void _on_property_added<T>(string prop_name, int target_field_number, IProperty<T> prop, Action<T> assign_to_prop, T non_uniform_value, bool validate_on_changed, AlgoParamPermissions permissions) {
|
||||
void _on_property_added<T>(string prop_name, int target_field_number, IProperty<T> prop, Action<T> assign_to_prop, T non_uniform_value, bool validate_on_changed, AlgoParamPermissions permissions, Func<T, T> to_display_value = null, Func<T, T> from_display_value = null, IObservable<Unit> refresh_display_value = null) {
|
||||
var field_desc = new TMutable().Descriptor.FindFieldByNumber(target_field_number);
|
||||
var param = new AlgoParamVM<T>(prop_name, DisplayNameHelper.snake_to_title_case(prop_name), prop.Value) { permissions = permissions };
|
||||
var param = new AlgoParamVM<T>(prop_name, DisplayNameHelper.snake_to_title_case(prop_name), prop.Value, EqualityComparer<T>.Default, null, to_display_value, from_display_value) {
|
||||
permissions = permissions
|
||||
};
|
||||
_algo_params.Add(param);
|
||||
var prop_hook = _link_props(param, prop, assign_to_prop, non_uniform_value, validate_on_changed);
|
||||
if (refresh_display_value != null) {
|
||||
prop_hook = Disposable.Create(
|
||||
refresh_display_value.Subscribe(_ => param.refresh_display_value()),
|
||||
prop_hook);
|
||||
}
|
||||
_auto_props.Add(new AutoProp(prop_name, mval => {
|
||||
if (mval != null && param.has_value)
|
||||
field_desc.Accessor.SetValue(mval, prop.Value);
|
||||
},
|
||||
mval => assign_to_prop_and_commit(mval == null ? default : ConvertUtils.try_convert<T>(field_desc.Accessor.GetValue(mval))),
|
||||
mvals => assign_to_prop_and_commit(mvals.Select(v => ConvertUtils.try_convert<T>(field_desc.Accessor.GetValue(v))).Distinct().SafeSingleOrDefault(non_uniform_value)),
|
||||
_link_props(param, prop, assign_to_prop, non_uniform_value, validate_on_changed)));
|
||||
prop_hook));
|
||||
void assign_to_prop_and_commit(T value) {
|
||||
assign_to_prop(value);
|
||||
param.mark_committed();
|
||||
@@ -814,8 +820,6 @@ namespace mbts.spark {
|
||||
return Disposable.Create(() => {
|
||||
if (security != old_sec) {
|
||||
on_security_internal();
|
||||
if (_editing_permissions.HasFlag(AlgoEditingPermissions.AllowEditStructure))
|
||||
_populate_selectors();
|
||||
_security_changed?.Invoke(security);
|
||||
}
|
||||
if (security_md != old_sec_md)
|
||||
@@ -823,21 +827,6 @@ namespace mbts.spark {
|
||||
});
|
||||
}
|
||||
|
||||
IDisposable _selector_data_hooks;
|
||||
void _populate_selectors() {
|
||||
if (model != null && security.HasValue) {
|
||||
var algo_data = model.factory.default_algos(security.Value);
|
||||
var default_algo = AlgoKey.from_known_type(OrderDataHelper.get_default_algo(OrderDataHelper.get_algo_format(security.Value.ContractCase)));
|
||||
foreach (var sd in _child_algo_selectors)
|
||||
sd.load_algo_data_recursive(algo_data, default_algo);
|
||||
Disposable.dispose(ref _selector_data_hooks);
|
||||
_selector_data_hooks = ObservableAutoWrapper.connect_item_hooks(child_algo_selectors, s => {
|
||||
s.load_algo_data_recursive(algo_data, default_algo);
|
||||
return Disposable.empty;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class AutoProp : IDisposable {
|
||||
public readonly string name;
|
||||
public readonly Action<TMutable> assign, load;
|
||||
@@ -924,6 +913,7 @@ namespace mbts.spark {
|
||||
AlgoParamPermissions _permissions = AlgoParamPermissions.ReadWrite;
|
||||
IReadOnlyDictionary<AlgoKey, AlgoData> _pending_data;
|
||||
AlgoKey? _pending_default;
|
||||
IDisposable _loaded_data_hook;
|
||||
|
||||
public AlgoSelector(string id, string display_name) {
|
||||
this.id = id;
|
||||
@@ -1020,8 +1010,11 @@ namespace mbts.spark {
|
||||
|
||||
void _sync_formats() {
|
||||
if (initialized && _pending_data != null) {
|
||||
var fmt_algos = _pending_data;
|
||||
algos.SyncWithDictionary(fmt_algos, d => create(d, is_expanded: true));
|
||||
Disposable.dispose(ref _loaded_data_hook);
|
||||
var data = _pending_data;
|
||||
algos.SyncWithDictionary(data, d => create(d, is_expanded: true));
|
||||
_loaded_data_hook = ObservableAutoWrapper.connect_item_hooks(algos, vm =>
|
||||
ObservableAutoWrapper.connect_item_actions(vm.child_algo_selectors, s => s.load_algo_data(data, null)));
|
||||
if (_algo == null || !algos.ContainsKey(_algo.id)) {
|
||||
if (_pending_default.HasValue && algos.TryGetValue(_pending_default.Value, out IAlgoVM match))
|
||||
selected_algo = match;
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace mbts.spark {
|
||||
new DialogSkirtItem("Save Strategy", commit);
|
||||
|
||||
void _ensure_init() {
|
||||
if (_vm == null && _model != null && _template.HasValue && _template.Value.HasSecurity) {
|
||||
if (_vm == null && _model != null && _template.HasValue && _template.Value.HasSecurity && _template.Value.HasExecutionStrategy) {
|
||||
Log.isnull(_save_strategy_item);
|
||||
Log.isnull(_vm_strategy_sub);
|
||||
var tmp = _template.Value;
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace mbts.spark {
|
||||
public readonly ISecurityAuxiliaryDataModel security_auxiliary_model;
|
||||
|
||||
readonly IBus _bus;
|
||||
readonly IAlgoProvider _algo_provider, _attachable_algo_provider;
|
||||
readonly OrderFactory _factory;
|
||||
readonly OrderService _service;
|
||||
readonly PositionService _position_service;
|
||||
@@ -57,6 +58,8 @@ namespace mbts.spark {
|
||||
IAlgoStudioModel algo_model,
|
||||
ISecurityAuxiliaryDataModel security_auxiliary_model,
|
||||
MarketDataAuxiliaryModel md_auxiliary_model,
|
||||
IAlgoProvider algo_provider,
|
||||
IAttachableAlgoProvider attachable_algo_provider,
|
||||
SecurityStore sstore,
|
||||
ErrorReporter error) {
|
||||
//
|
||||
@@ -67,6 +70,8 @@ namespace mbts.spark {
|
||||
_mbo_service = mbo_service;
|
||||
_spreader = spreader;
|
||||
_error = error;
|
||||
_algo_provider = algo_provider;
|
||||
_attachable_algo_provider = attachable_algo_provider;
|
||||
_dynamic_helper = dynamic_helper;
|
||||
this.admin_model = admin_model;
|
||||
this.algo_model = algo_model;
|
||||
@@ -314,6 +319,9 @@ namespace mbts.spark {
|
||||
public MBOService mbo_service => _mbo_service;
|
||||
public IAlgoStudioModel algo_model { get; }
|
||||
|
||||
public AlgoTypeSetImmutable get_permitted_algos(SecurityImmutable security) =>
|
||||
_algo_provider.get_permitted_algos(security);
|
||||
|
||||
public IObservable<TableUpdate<OrderSecurity, uint>> on_security_working_orders_with_piq(uint security) =>
|
||||
_security_working_orders_with_piq_demuxer.subscribe(security);
|
||||
|
||||
@@ -322,6 +330,15 @@ namespace mbts.spark {
|
||||
|
||||
public IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_security_positions(uint security) =>
|
||||
_security_positions_demuxer.subscribe(security);
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(bool attachable_only = false) =>
|
||||
(attachable_only ? _attachable_algo_provider : _algo_provider).subscribe_algos();
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_algos(SecurityImmutable security, bool attachable_only = false) =>
|
||||
(attachable_only ? _attachable_algo_provider : _algo_provider).subscribe_algos(security);
|
||||
|
||||
public IObservable<TableUpdate<AlgoData, AlgoKey>> subscribe_complete_algos(bool attachable_only = false, bool allow_undefined_child = false) =>
|
||||
(attachable_only ? _attachable_algo_provider : _algo_provider).subscribe_complete_algos(allow_undefined_child);
|
||||
#endregion
|
||||
|
||||
#region Input
|
||||
@@ -634,14 +651,10 @@ namespace mbts.spark {
|
||||
}).Select(r => r.last_update);
|
||||
|
||||
public static IObservable<TableUpdate<(AlgoData algo, AlgoDefinitionMetadata? meta), AlgoKey>> subscribe_all_algos(this OrdersModel orders_model) =>
|
||||
orders_model.studio_algos_with_meta.MergeTable(Observable.Return(
|
||||
new TableUpdate<(AlgoData algo, AlgoDefinitionMetadata? meta), AlgoKey>(
|
||||
ImmutableDictionary<AlgoKey, (AlgoData algo, AlgoDefinitionMetadata? meta)>.Empty.AddRange(orders_model.factory.default_algos(OrderDataHelper.all_order_types).Select(kv => new KeyValuePair<AlgoKey, (AlgoData algo, AlgoDefinitionMetadata? meta)>(kv.Key, (kv.Value, null)))),
|
||||
Array.Empty<(AlgoData, AlgoDefinitionMetadata?)>(),
|
||||
Array.Empty<Change<(AlgoData, AlgoDefinitionMetadata?)>>(),
|
||||
Array.Empty<(AlgoData, AlgoDefinitionMetadata?)>(),
|
||||
d => d.algo.key
|
||||
).as_snapshot()));
|
||||
_subscribe_algo_meta_tuples(orders_model, orders_model.subscribe_algos());
|
||||
|
||||
public static IObservable<TableUpdate<(AlgoData algo, AlgoDefinitionMetadata? meta), AlgoKey>> subscribe_algo_meta_tuples(this OrdersModel orders_model, SecurityImmutable security) =>
|
||||
_subscribe_algo_meta_tuples(orders_model, orders_model.subscribe_algos(security));
|
||||
|
||||
public static async Task<OrderRecordImmutable?> order_from_key(this OrdersModel orders_model, uint order_key) {
|
||||
(var tu, var success) = await orders_model.on_orders.FirstAsyncTask(t => t.state.ContainsKey(order_key), TimeSpan.FromSeconds(3));
|
||||
@@ -684,6 +697,15 @@ namespace mbts.spark {
|
||||
return false;
|
||||
}
|
||||
|
||||
static IObservable<TableUpdate<(AlgoData algo, AlgoDefinitionMetadata? meta), AlgoKey>> _subscribe_algo_meta_tuples(OrdersModel orders_model, IObservable<TableUpdate<AlgoData, AlgoKey>> algos) =>
|
||||
algos.LeftJoin(
|
||||
orders_model.algo_model.metadata_service.subscribe_metadata().Table(AlgoDefinitionMetadata.key_fn),
|
||||
AlgoData.key_fn,
|
||||
AlgoDefinitionMetadata.key_fn,
|
||||
(algo, key, meta) => (algo, (AlgoDefinitionMetadata?)meta),
|
||||
(algo, key) => (algo, (AlgoDefinitionMetadata?)null),
|
||||
tup => tup.algo.key);
|
||||
|
||||
class RootOrderData {
|
||||
public readonly SetMap<uint, uint> parent_to_children = new SetMap<uint, uint>();
|
||||
public TableUpdateTransform<OrderRecordImmutable, uint> last_update { get; set; } = new TableUpdateTransform<OrderRecordImmutable, uint>();
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
<Platforms>x64</Platforms>
|
||||
<RuntimeIdentifiers>win7-x64</RuntimeIdentifiers>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<LanguageTargets>$(MSBuildExtensionsPath)\$(VisualStudioVersion)\Bin\Microsoft.CSharp.targets</LanguageTargets>
|
||||
<LanguageTargets Condition="'$(VisualStudioVersion)'=='16.0'">$(MSBuildToolsPath)\Microsoft.CSharp.targets</LanguageTargets>
|
||||
<LanguageTargets Condition="'$(VisualStudioVersion)'=='17.0'">
|
||||
C:/Program Files/Microsoft Visual Studio/2022/Community/Msbuild/Current/Bin/amd64/Microsoft.CSharp.targets
|
||||
</LanguageTargets>
|
||||
<ApplicationIcon>logo.ico</ApplicationIcon>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<StartupObject>mbts.ui.shell.App</StartupObject>
|
||||
@@ -34,7 +35,7 @@
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="IronPython" Version="2.7.7" />
|
||||
<PackageReference Include="NAudio" Version="1.8.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
|
||||
@@ -947,7 +947,7 @@
|
||||
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center">Show Quantity</TextBlock>
|
||||
<c:HelpButton Margin="{StaticResource Margin.LP1}" ToolTip="Maximum size to show on exchange, this is the BTS provided iceberg"/>
|
||||
</StackPanel>
|
||||
<c:TickUpDownDouble x:Name="PART_ShowQuantity_TickUpDownDouble" Grid.Column="2" HorizontalAlignment="Stretch" Value="{Binding show_quantity}"/>
|
||||
<c:TickUpDownDouble x:Name="PART_ShowQuantity_TickUpDownDouble" Grid.Column="2" HorizontalAlignment="Stretch" Value="{Binding display_show_quantity}"/>
|
||||
<uag:AlgoPickerNodeView
|
||||
x:Name="PART_Child_AlgoPickerNodeView"
|
||||
Grid.Row="2"
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace mbts.ui.spark {
|
||||
AlgoDropDownStyleKeyConverter = ValueConverter.create(obj => {
|
||||
if (obj is AlgoDefinitionVM) return DefinitionDropDownStyleKey;
|
||||
return null;
|
||||
}),
|
||||
DataContextConverter = ValueConverter.create(obj => obj is AlgoVMWrapper w ? w.value.algo_root : obj);
|
||||
});
|
||||
|
||||
public static IMultiValueConverter TriggerTimeoutStateConverter =
|
||||
ValueConverter.create<bool, AlgoEditingPermissions, string>((is_timeout_enabled, editing_permissions) =>
|
||||
|
||||
@@ -64,6 +64,25 @@ namespace mbts.ui {
|
||||
}
|
||||
}, can_execute == null ? null : new Func<object, bool>(_ => can_execute()));
|
||||
|
||||
public static IDialogCommand export_csv(
|
||||
Func<string> get_file_content,
|
||||
string source_window_name) =>
|
||||
new AnonymousFileDialogCommand<object>(_ =>
|
||||
_create_save_file_dialog(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
|
||||
$"BTS_Spark_{source_window_name}_{DateTime.Now.ToString("yyyyMMdd_HHmm")}.csv",
|
||||
new[] { ("CSV (comma delimited)", new string[] { "csv" }) }
|
||||
),
|
||||
(_, file) => {
|
||||
try {
|
||||
File.WriteAllText(file, get_file_content.Invoke());
|
||||
} catch (Exception ex) {
|
||||
BTSMessageBox.Show($"Error exporting data to csv: {ex}.", "CSV Export Error", BTSMessageBoxButtons.OK, System.Windows.MessageBoxImage.Error, true, false, true);
|
||||
}
|
||||
},
|
||||
// we are always able to perform an export, even when no rows (it will just be a header)
|
||||
(_) => true);
|
||||
|
||||
static TDialog _create_file_dialog<TDialog>(string initial_dir = null, IReadOnlyList<(string name, string[] extensions)> filter_items = null) where TDialog : FileDialog, new() {
|
||||
var rv = new TDialog();
|
||||
if (!string.IsNullOrEmpty(initial_dir))
|
||||
|
||||
@@ -43,24 +43,24 @@ namespace mbts.spark {
|
||||
foreach (var selected_item in all_securities.Where(s => selected_securities.Contains(s.Key))) {
|
||||
// verify clause isn't already in the list
|
||||
if (!security_criteria_clauses.Any(x => x.pretty_name == selected_item.Value.security.ToString())) {
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause() {
|
||||
pretty_name = selected_item.Value.security.ToString(),
|
||||
exchanges = selected_exchanges.ToArray(),
|
||||
security_types = selected_security_types.ToArray(),
|
||||
symbols = selected_symbols.ToArray(),
|
||||
security_keys = new List<uint>() { selected_item.Key }
|
||||
});
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause(
|
||||
pretty_name: selected_item.Value.security.ToString(),
|
||||
exchanges: selected_exchanges.ToArray(),
|
||||
security_types: selected_security_types.ToArray(),
|
||||
symbols: selected_symbols.ToArray(),
|
||||
security_keys: new[] { selected_item.Key }
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!security_criteria_clauses.Any(x => x.pretty_name == criteria_input_name)) {
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause() {
|
||||
pretty_name = criteria_input_name,
|
||||
exchanges = selected_exchanges.ToArray(),
|
||||
security_types = selected_security_types.ToArray(),
|
||||
symbols = selected_symbols.ToArray(),
|
||||
security_keys = selected_securities
|
||||
});
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause(
|
||||
pretty_name: criteria_input_name,
|
||||
exchanges: selected_exchanges.ToArray(),
|
||||
security_types: selected_security_types.ToArray(),
|
||||
symbols: selected_symbols.ToArray(),
|
||||
security_keys: selected_securities.ToArray()
|
||||
));
|
||||
}
|
||||
}
|
||||
criteria_input_name = string.Empty;
|
||||
@@ -97,12 +97,12 @@ namespace mbts.spark {
|
||||
add_symbol_command = new DelegateCommand<string>(symbol => {
|
||||
_compose_criteria_clause_name(true);
|
||||
if (!security_criteria_clauses.Any(x => x.pretty_name == _criteria_input_name_from_double_click)) {
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause() {
|
||||
pretty_name = _criteria_input_name_from_double_click,
|
||||
exchanges = selected_exchanges.ToArray(),
|
||||
security_types = selected_security_types.ToArray(),
|
||||
symbols = new string[] { symbol },
|
||||
});
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause(
|
||||
pretty_name: _criteria_input_name_from_double_click,
|
||||
exchanges: selected_exchanges.ToArray(),
|
||||
security_types: selected_security_types.ToArray(),
|
||||
symbols: new string[] { symbol }
|
||||
));
|
||||
}
|
||||
ok_button_command.TryRaiseCanExecuteChanged();
|
||||
remove_criteria_command.TryRaiseCanExecuteChanged();
|
||||
@@ -110,11 +110,11 @@ namespace mbts.spark {
|
||||
add_security_type_command = new DelegateCommand<SecurityType>(sec_type => {
|
||||
_compose_criteria_clause_name(true, true);
|
||||
if (!security_criteria_clauses.Any(x => x.pretty_name == _criteria_input_name_from_double_click)) {
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause() {
|
||||
pretty_name = _criteria_input_name_from_double_click,
|
||||
exchanges = selected_exchanges.ToArray(),
|
||||
security_types = new SecurityType[] { sec_type },
|
||||
});
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause(
|
||||
pretty_name: _criteria_input_name_from_double_click,
|
||||
exchanges: selected_exchanges.ToArray(),
|
||||
security_types: new SecurityType[] { sec_type }
|
||||
));
|
||||
}
|
||||
ok_button_command.TryRaiseCanExecuteChanged();
|
||||
remove_criteria_command.TryRaiseCanExecuteChanged();
|
||||
@@ -122,10 +122,10 @@ namespace mbts.spark {
|
||||
add_exchange_command = new DelegateCommand<Venue>(exchange => {
|
||||
_compose_criteria_clause_name(true, true, true);
|
||||
if (!security_criteria_clauses.Any(x => x.pretty_name == _criteria_input_name_from_double_click)) {
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause() {
|
||||
pretty_name = _criteria_input_name_from_double_click,
|
||||
exchanges = new Venue[] { exchange },
|
||||
});
|
||||
security_criteria_clauses.Insert(0, new SecurityCriteriaClause(
|
||||
pretty_name: _criteria_input_name_from_double_click,
|
||||
exchanges: new Venue[] { exchange }
|
||||
));
|
||||
}
|
||||
ok_button_command.TryRaiseCanExecuteChanged();
|
||||
remove_criteria_command.TryRaiseCanExecuteChanged();
|
||||
@@ -343,12 +343,16 @@ namespace mbts.spark {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should return a nullable (if no specific security is selected, the result should be null)
|
||||
public SecurityMD result {
|
||||
get {
|
||||
SecurityCriteriaClause scc = new SecurityCriteriaClause();
|
||||
scc.security_keys = selected_securities;
|
||||
SecurityCriteria crit = new SecurityCriteria(new SecurityCriteriaClause[] { scc });
|
||||
return all_securities.Where(s => security_in_criteria(crit, s.Value.security)).FirstOrDefault().Value;
|
||||
if (selected_securities.Count == 0)
|
||||
throw new InvalidOperationException("No securities selected.");
|
||||
foreach (var k in selected_securities) {
|
||||
if (all_securities.TryGetValue(k, out var smd))
|
||||
return smd;
|
||||
}
|
||||
throw new InvalidOperationException("None of the selected security keys are present in the security map.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +431,7 @@ namespace mbts.spark {
|
||||
bool check_exchanges = !(x.exchanges == null || x.exchanges.Length == 0);
|
||||
bool check_security_types = !(x.security_types == null || x.security_types.Length == 0);
|
||||
bool check_symbols = !(x.symbols == null || x.symbols.Length == 0);
|
||||
bool check_security_keys = !(x.security_keys == null || x.security_keys.Count == 0);
|
||||
bool check_security_keys = !(x.security_keys == null || x.security_keys.Length == 0);
|
||||
bool check_something_in_clause = check_exchanges || check_security_types || check_symbols || check_security_keys;
|
||||
|
||||
if (check_something_in_clause) {
|
||||
|
||||
@@ -8,8 +8,7 @@ using System.Reactive.Linq;
|
||||
|
||||
namespace mbts.spark {
|
||||
[ProtoContract]
|
||||
public class SecurityCriteria : IEquatable<SecurityCriteria>
|
||||
{
|
||||
class SecurityCriteria : IEquatable<SecurityCriteria> {
|
||||
public SecurityCriteria()
|
||||
{
|
||||
clauses = new SecurityCriteriaClause[] { };
|
||||
@@ -29,9 +28,7 @@ namespace mbts.spark {
|
||||
|
||||
internal static SecurityCriteria from_keys(IEnumerable<uint> keys) =>
|
||||
new SecurityCriteria(new[] {
|
||||
new SecurityCriteriaClause {
|
||||
security_keys = keys.ToList()
|
||||
}
|
||||
new SecurityCriteriaClause (security_keys: keys.ToArray())
|
||||
});
|
||||
|
||||
internal static SecurityCriteria from_securities(ISet<SecurityImmutable> securities) =>
|
||||
@@ -49,27 +46,38 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
[ProtoContract]
|
||||
public class SecurityCriteriaClause : IEquatable<SecurityCriteriaClause>
|
||||
{
|
||||
public SecurityCriteriaClause() { }
|
||||
internal SecurityCriteriaClause(IEnumerable<SecurityImmutable> securities) {
|
||||
security_keys = securities.Select(s => s.Id).ToList();
|
||||
readonly struct SecurityCriteriaClause : IEquatable<SecurityCriteriaClause> {
|
||||
public SecurityCriteriaClause(
|
||||
Venue[] exchanges = null,
|
||||
SecurityType[] security_types = null,
|
||||
string[] symbols = null,
|
||||
uint[] security_keys = null,
|
||||
string pretty_name = null) {
|
||||
//
|
||||
this.exchanges = exchanges;
|
||||
this.security_types = security_types;
|
||||
this.symbols = symbols;
|
||||
this.security_keys = security_keys;
|
||||
this.pretty_name = pretty_name;
|
||||
}
|
||||
|
||||
public SecurityCriteriaClause(IEnumerable<SecurityImmutable> securities)
|
||||
: this(security_keys: securities.Select(s => s.Id).ToArray()) { }
|
||||
|
||||
[ProtoMember(1)]
|
||||
public string pretty_name;
|
||||
public readonly string pretty_name;
|
||||
|
||||
[ProtoMember(2)]
|
||||
public Venue[] exchanges;
|
||||
public readonly Venue[] exchanges;
|
||||
|
||||
[ProtoMember(3)]
|
||||
public SecurityType[] security_types;
|
||||
public readonly SecurityType[] security_types;
|
||||
|
||||
[ProtoMember(4)]
|
||||
public string[] symbols;
|
||||
public readonly string[] symbols;
|
||||
|
||||
[ProtoMember(5)]
|
||||
public List<uint> security_keys;
|
||||
public readonly uint[] security_keys;
|
||||
|
||||
public bool is_defined =>
|
||||
!string.IsNullOrEmpty(pretty_name) ||
|
||||
@@ -84,7 +92,6 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
public bool Equals(SecurityCriteriaClause other) =>
|
||||
other != null &&
|
||||
EqualityComparer.safe_sequence_equals(exchanges, other.exchanges) &&
|
||||
EqualityComparer.safe_sequence_equals(security_types, other.security_types) &&
|
||||
EqualityComparer.safe_sequence_equals(symbols, other.symbols) &&
|
||||
|
||||
@@ -90,7 +90,6 @@ namespace mbts.spark {
|
||||
/// <param name="clause">A SecurityCriteriaClause.</param>
|
||||
/// <returns>true if the clause is non-null and specifies one security-key, and nothing else; otherwise false.</returns>
|
||||
public static bool is_single_security(this SecurityCriteriaClause clause) =>
|
||||
clause != null &&
|
||||
clause.exchanges.is_null_or_empty() &&
|
||||
clause.symbols.is_null_or_empty() &&
|
||||
clause.security_types.is_null_or_empty() &&
|
||||
@@ -98,6 +97,45 @@ namespace mbts.spark {
|
||||
!clause.security_keys.Distinct().Skip(1).Any();
|
||||
|
||||
public static bool includes(this SecurityCriteria security_criteria, SecurityImmutable security) =>
|
||||
security_criteria != null && ContractPickerModel.security_in_criteria(security_criteria, security);
|
||||
security_criteria.is_defined() && ContractPickerModel.security_in_criteria(security_criteria, security);
|
||||
|
||||
public static bool includes(this SecurityCriteriaClause clause, SecurityImmutable security) =>
|
||||
_to_predicates(clause).AnyAndAll(p => p(security));
|
||||
|
||||
public static bool is_subset_of(this SecurityCriteriaClause clause, SecurityCriteriaClause other) =>
|
||||
// exchanges
|
||||
(other.exchanges.is_null_or_empty() ||
|
||||
(!clause.exchanges.is_null_or_empty() && clause.exchanges.All(other.exchanges.Contains))) &&
|
||||
// symbols
|
||||
(other.symbols.is_null_or_empty() ||
|
||||
(!clause.symbols.is_null_or_empty() && clause.symbols.All(other.symbols.Contains))) &&
|
||||
// security_types
|
||||
(other.security_types.is_null_or_empty() ||
|
||||
(!clause.security_types.is_null_or_empty() && clause.security_types.All(other.security_types.Contains))) &&
|
||||
// security_keys
|
||||
(other.security_keys.is_null_or_empty() ||
|
||||
(!clause.security_keys.is_null_or_empty() && clause.security_keys.All(other.security_keys.Contains)));
|
||||
|
||||
public static IEnumerable<string> fmt_diagnostic_msgs(this SecurityCriteriaClause clause) {
|
||||
if (clause.exchanges != null && clause.exchanges.Length > 0)
|
||||
yield return "Exchanges: " + string.Join(", ", clause.exchanges);
|
||||
if (clause.symbols != null && clause.symbols.Length > 0)
|
||||
yield return "Symbols: " + string.Join(", ", clause.symbols);
|
||||
if (clause.security_types != null && clause.security_types.Length > 0)
|
||||
yield return "Security Types: " + string.Join(", ", clause.security_types);
|
||||
if (clause.security_keys != null && clause.security_keys.Length > 0)
|
||||
yield return "Security Keys: " + string.Join(", ", clause.security_keys);
|
||||
}
|
||||
|
||||
static IEnumerable<Func<SecurityImmutable, bool>> _to_predicates(SecurityCriteriaClause clause) {
|
||||
if (clause.exchanges != null && clause.exchanges.Length > 0)
|
||||
yield return sec => clause.exchanges.Contains(sec.Exchange);
|
||||
if (clause.symbols != null && clause.symbols.Length > 0)
|
||||
yield return sec => clause.symbols.Contains(sec.Symbol);
|
||||
if (clause.security_types != null && clause.security_types.Length > 0)
|
||||
yield return sec => clause.security_types.Contains(sec.security_type());
|
||||
if (clause.security_keys != null && clause.security_keys.Length > 0)
|
||||
yield return sec => clause.security_keys.Contains(sec.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,25 +40,53 @@ namespace mbts.ui {
|
||||
public static bool operator !=(QuantityConversionData x, QuantityConversionData y) => !x.Equals(y);
|
||||
}
|
||||
|
||||
class DisplayQuantityMultiplier : IDisplayTranslator<uint> {
|
||||
uint _actual_value;
|
||||
static class DisplayQuantityMultiplier {
|
||||
public static DisplayQuantityMultiplier<uint> create_uint() =>
|
||||
new DisplayQuantityMultiplier<uint>(
|
||||
DisplayTranslatorExtensions.to_display,
|
||||
DisplayTranslatorExtensions.from_display);
|
||||
|
||||
public static DisplayQuantityMultiplier<double> create_double() =>
|
||||
new DisplayQuantityMultiplier<double>(
|
||||
DisplayTranslatorExtensions.to_display,
|
||||
DisplayTranslatorExtensions.from_display);
|
||||
}
|
||||
|
||||
class DisplayQuantityMultiplier<T> : IDisplayTranslator<T> {
|
||||
readonly Func<QuantityConversionData, T, T> _to_display, _from_display;
|
||||
readonly IEqualityComparer<T> _comparer;
|
||||
T _actual_value;
|
||||
QuantityConversionData _conversion_data;
|
||||
|
||||
public DisplayQuantityMultiplier(
|
||||
Func<QuantityConversionData, T, T> to_display,
|
||||
Func<QuantityConversionData, T, T> from_display,
|
||||
IEqualityComparer<T> comparer = null,
|
||||
T actual_value = default,
|
||||
QuantityConversionData conversion_data = default) {
|
||||
//
|
||||
_to_display = to_display ?? throw new ArgumentNullException(nameof(to_display));
|
||||
_from_display = from_display ?? throw new ArgumentNullException(nameof(from_display));
|
||||
_comparer = comparer ?? EqualityComparer<T>.Default;
|
||||
_actual_value = actual_value;
|
||||
_conversion_data = conversion_data;
|
||||
}
|
||||
|
||||
public event Action value_changed;
|
||||
|
||||
public uint actual_value {
|
||||
public T actual_value {
|
||||
get => _actual_value;
|
||||
set {
|
||||
if (_actual_value != value) {
|
||||
if (!_comparer.Equals(_actual_value, value)) {
|
||||
_actual_value = value;
|
||||
value_changed?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint display_value {
|
||||
get => _conversion_data.to_display(_actual_value);
|
||||
set => actual_value = _conversion_data.from_display(value);
|
||||
public T display_value {
|
||||
get => _to_display(_conversion_data, _actual_value);
|
||||
set => actual_value = _from_display(_conversion_data, value);
|
||||
}
|
||||
|
||||
public QuantityConversionData conversion_data {
|
||||
@@ -168,5 +196,13 @@ namespace mbts.ui {
|
||||
default: return display_value;
|
||||
}
|
||||
}
|
||||
|
||||
public static double from_display(this QuantityConversionData quantity_conversion_data, double display_value) {
|
||||
switch (quantity_conversion_data.op) {
|
||||
case QuantityConversionData.OpType.DivideActual: return display_value * quantity_conversion_data.value;
|
||||
case QuantityConversionData.OpType.MultiplyActual: return display_value.safe_divide(quantity_conversion_data.value);
|
||||
default: return display_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,6 +259,7 @@ namespace mbts.co2 {
|
||||
}
|
||||
}
|
||||
|
||||
// If Size is wrong remember to update from
|
||||
[StructLayout(LayoutKind.Sequential, Size = 704)]
|
||||
internal struct ColdEntry {
|
||||
public int exchange_status;
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
using bts.api;
|
||||
using bts.api.orderman;
|
||||
using bts.api.position;
|
||||
using bts.utils;
|
||||
using mbts;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
|
||||
namespace bts.api {
|
||||
|
||||
static class ExchangeSpecificUitlities{
|
||||
private static string _default_hub = "Henry";
|
||||
static class ICE{
|
||||
|
||||
#region Contract Type
|
||||
public static bool is_spread(SecurityImmutable sec){
|
||||
return sec.HasSpread && sec.Ice.StripName.Contains("/");
|
||||
}
|
||||
|
||||
public static bool is_strip(SecurityImmutable sec){
|
||||
return sec.HasSpread && !is_spread(sec);
|
||||
}
|
||||
|
||||
public static bool is_ice_lots(SecurityImmutable sec){
|
||||
return sec.Ice.MarketDescription.Contains("ICE Lots");
|
||||
}
|
||||
|
||||
public static bool is_tas(SecurityImmutable sec){
|
||||
return sec.Ice.MarketDescription.Contains("TAS");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CPP
|
||||
public static double get_future_cpp (SecurityImmutable sec){
|
||||
if(sec.Symbol == "HHD")
|
||||
// only futures in HHD are the dailies, everything
|
||||
// else is a strip or spread
|
||||
return 1;
|
||||
if(is_ice_lots(sec))
|
||||
return 2500;
|
||||
else{
|
||||
var days_in_month = DateTime.DaysInMonth(Convert.ToInt32(sec.Future.ExpirationYear),
|
||||
Convert.ToInt32(sec.Future.ExpirationMonth));
|
||||
return days_in_month; // because the size is multiplied by 2500 already
|
||||
}
|
||||
}
|
||||
|
||||
public static double get_spread_cpp(SecurityImmutable sec){
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static double get_strip_cpp(PNLUnitImmutable pnl,
|
||||
SecurityImmutable sec){
|
||||
// add up all the legs
|
||||
double rv = 0;
|
||||
foreach (var l in sec.Spread.Legs)
|
||||
if(l.Security.HasFuture)
|
||||
rv += get_cpp(pnl,l.Security);
|
||||
return rv;
|
||||
}
|
||||
|
||||
public static double get_cpp (PNLUnitImmutable pnl,
|
||||
SecurityImmutable sec){
|
||||
if(sec.HasFuture)
|
||||
return get_future_cpp(sec);
|
||||
else if(is_spread(sec))
|
||||
return get_spread_cpp(sec);
|
||||
else if(is_strip(sec))
|
||||
return get_strip_cpp(pnl,sec);
|
||||
return Double.NaN;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Symbol
|
||||
public static string get_pnl_symbol (SecurityImmutable sec){
|
||||
// for pnl purposes, for a symbol, the division is :
|
||||
// Futures and Strips
|
||||
// ICE Lots
|
||||
// Spreads
|
||||
var rv = String.Format("{0}{1}{2}",
|
||||
sec.Symbol,
|
||||
is_ice_lots(sec)? " ICE LOTS" : String.Empty,
|
||||
is_spread(sec)? " Spread" : String.Empty);
|
||||
return rv;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Formatting
|
||||
public static string format_security (SecurityImmutable? security){
|
||||
if(security.HasValue && security.Value.HasIce){
|
||||
bool ice_lots = is_ice_lots(security.Value),
|
||||
tas = is_tas(security.Value);
|
||||
return String.Format("{0}{1}{2}{3}{4}",
|
||||
security?.Symbol,
|
||||
ice_lots? " ICE Lots" : String.Empty,
|
||||
tas ? " TAS" : String.Empty,
|
||||
String.Compare(security.Value.Ice.HubAlias, _default_hub,true)==0 ? String.Empty :
|
||||
" " + security.Value.Ice.HubAlias,
|
||||
" " + security?.Ice.StripName);
|
||||
}
|
||||
return String.Empty;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static double get_cpp (PNLUnitImmutable pnl,
|
||||
SecurityImmutable sec){
|
||||
if(sec.HasIce)
|
||||
return ICE.get_cpp(pnl,sec);
|
||||
return pnl.CashValue;
|
||||
}
|
||||
|
||||
public static string get_pnl_symbol (SecurityImmutable sec){
|
||||
if(sec.HasIce)
|
||||
return ICE.get_pnl_symbol(sec);
|
||||
return sec.Symbol;
|
||||
}
|
||||
|
||||
public static string format_security(SecurityImmutable? security){
|
||||
if(security?.HasIce == true)
|
||||
return ICE.format_security(security);
|
||||
return security?.ToString();
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -1,10 +1,15 @@
|
||||
using System;
|
||||
using bts.api;
|
||||
|
||||
namespace bts.api
|
||||
{
|
||||
public static class SecurityExtensions
|
||||
{
|
||||
namespace bts.api {
|
||||
public static class SecurityExtensions {
|
||||
public static SecurityType security_type(this Security s) { return ((SecurityImmutable)s).security_type(); }
|
||||
|
||||
public static SecurityType security_type(this Security.ContractOneofCase contract_case) {
|
||||
switch (contract_case) {
|
||||
case Security.ContractOneofCase.Future: return SecurityType.Future;
|
||||
case Security.ContractOneofCase.Option: return SecurityType.Option;
|
||||
case Security.ContractOneofCase.Spread: return SecurityType.Spread;
|
||||
case Security.ContractOneofCase.Synthetic: return SecurityType.Synthetic;
|
||||
default: return SecurityType.Unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace bts.api {
|
||||
switch (security?.ContractCase) {
|
||||
case ContractOneofCase.Future:
|
||||
if(security?.HasIce == true)
|
||||
return _format_ICE(security);
|
||||
return bts.api.ExchangeSpecificUitlities.format_security(security);
|
||||
return format_future(security?.Symbol, security?.security_desc(), security.Value.Future);
|
||||
case ContractOneofCase.Spread:
|
||||
if (security?.HasGlbx == true) {
|
||||
@@ -50,7 +50,7 @@ namespace bts.api {
|
||||
return security?.Glbx.SecurityDesc;
|
||||
}
|
||||
else if(security?.HasIce == true)
|
||||
return _format_ICE(security);
|
||||
return bts.api.ExchangeSpecificUitlities.format_security(security);
|
||||
return string.Join("", _format_future_legs(SecurityHelper.get_flat_future_legs(security?.Spread.Legs)));
|
||||
case ContractOneofCase.Synthetic: return security?.Synthetic.Name;
|
||||
default: return "Unknown-security";
|
||||
@@ -84,28 +84,5 @@ namespace bts.api {
|
||||
default: return $"{fl.quantity:+0;-0}{sym_exp_name}";
|
||||
}
|
||||
}
|
||||
|
||||
static string _format_ICE (SecurityImmutable? security){
|
||||
string symbol = security?.Symbol,
|
||||
strip = security?.Ice.StripName,
|
||||
md_desc = security?.Ice.MarketDescription,
|
||||
type_append = "";
|
||||
|
||||
if(md_desc.Contains("25k ICE Lots")){
|
||||
if(md_desc.Contains("TAS"))
|
||||
type_append = "TAS";
|
||||
}
|
||||
else if(md_desc.Contains("ICE Lots")){
|
||||
if(md_desc.Contains("TAS"))
|
||||
type_append = "ICE Lots TAS";
|
||||
else
|
||||
type_append = "ICE Lots";
|
||||
}
|
||||
else if(md_desc.Contains("TAS"))
|
||||
type_append = "TAS";
|
||||
type_append = string.IsNullOrEmpty(type_append) ?
|
||||
" " : $" {type_append} ";
|
||||
return $"{symbol}{type_append}{strip}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,26 +83,37 @@ namespace bts.api {
|
||||
}
|
||||
|
||||
public static int Compare(SecurityImmutable x, SecurityImmutable y) {
|
||||
if (x.ContractCase == ContractOneofCase.Future) {
|
||||
return y.ContractCase == ContractOneofCase.Future ? Compare(x.Symbol, x.Future, y.Symbol, y.Future) : -1;
|
||||
} else if (y.ContractCase == ContractOneofCase.Future) {
|
||||
return 1;
|
||||
int c = non_deterministic_impl();
|
||||
if (c == 0) {
|
||||
c = x.ToString().CompareTo(y.ToString());
|
||||
if (c == 0)
|
||||
c = x.Id.CompareTo(y.Id);
|
||||
}
|
||||
var xlegs = get_flat_future_legs(x).ToList();
|
||||
var ylegs = get_flat_future_legs(y).ToList();
|
||||
int max = Math.Min(xlegs.Count, ylegs.Count);
|
||||
for (int i = 0; i < max; i++) {
|
||||
int rv = Compare(xlegs[i].symbol, xlegs[i].future, ylegs[i].symbol, ylegs[i].future);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
rv = xlegs[i].quantity.CompareTo(ylegs[i].quantity);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
rv = xlegs[i].exchange.CompareTo(ylegs[i].exchange);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
return c;
|
||||
// this has been observed to be non-determinisitc with certain ICE securities
|
||||
// (it is determenistic with other exchanges..as far as we know).
|
||||
int non_deterministic_impl() {
|
||||
if (x.ContractCase == ContractOneofCase.Future) {
|
||||
return y.ContractCase == ContractOneofCase.Future ? Compare(x.Symbol, x.Future, y.Symbol, y.Future) : -1;
|
||||
} else if (y.ContractCase == ContractOneofCase.Future) {
|
||||
return 1;
|
||||
}
|
||||
var xlegs = get_flat_future_legs(x).ToList();
|
||||
var ylegs = get_flat_future_legs(y).ToList();
|
||||
int max = Math.Min(xlegs.Count, ylegs.Count);
|
||||
for (int i = 0; i < max; i++) {
|
||||
int rv = Compare(xlegs[i].symbol, xlegs[i].future, ylegs[i].symbol, ylegs[i].future);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
rv = xlegs[i].quantity.CompareTo(ylegs[i].quantity);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
rv = xlegs[i].exchange.CompareTo(ylegs[i].exchange);
|
||||
if (rv != 0)
|
||||
return rv;
|
||||
}
|
||||
return xlegs.Count.CompareTo(ylegs.Count);
|
||||
}
|
||||
return xlegs.Count.CompareTo(ylegs.Count);
|
||||
}
|
||||
|
||||
public static int Compare(string x_sym, FutureContract x, string y_sym, FutureContract y) {
|
||||
@@ -116,4 +127,4 @@ namespace bts.api {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
|
||||
<PackageReference Include="System.Reactive" Version="3.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace bts {
|
||||
Plugin,
|
||||
Sdk,
|
||||
Http,
|
||||
iLink3
|
||||
// Please keep this list in sync with logging.h/logging.cpp
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,42 @@ using System.Reactive.Linq;
|
||||
|
||||
namespace System.Collections.Generic {
|
||||
public static class EnumerableExtensions {
|
||||
/// <summary>
|
||||
/// Determines whether all elements of a sequence are true.
|
||||
/// </summary>
|
||||
/// <param name="source">An <see cref="IEnumerable{bool}"/> that contains the elements to which to apply the predicate.</param>
|
||||
/// <returns>True if every element of the source sequence is true, or if the sequence is empty; otherwise false.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="source"/> is null</exception>
|
||||
public static bool All(this IEnumerable<bool> source) {
|
||||
if (source is null)
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
foreach (var v in source) {
|
||||
if (!v)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Similar to <see cref="Enumerable.All{TSource}(IEnumerable{TSource}, Func{TSource, bool})"/>, but returns false if the <paramref name="source"/> is empty.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements in the source.</typeparam>
|
||||
/// <param name="source">The sequence of elements to which the predicate will be applied.</param>
|
||||
/// <param name="predicate">The predicate applied to each element in the specified sequence.</param>
|
||||
/// <returns>True if the source sequence is not empty, and every element within it passes the test in the specified predicate; otherwise, false.</returns>
|
||||
public static bool AnyAndAll<T>(this IEnumerable<T> source, Func<T, bool> predicate) {
|
||||
using (var en = source.GetEnumerator()) {
|
||||
if (en.MoveNext()) {
|
||||
do {
|
||||
if (!predicate(en.Current))
|
||||
return false;
|
||||
} while (en.MoveNext());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#region Ordered
|
||||
public static IOrderedEnumerable<T> Ordered<T>(this IEnumerable<T> enumerable) =>
|
||||
enumerable.OrderBy(t => t);
|
||||
@@ -165,6 +201,9 @@ namespace System.Collections.Generic {
|
||||
}
|
||||
}
|
||||
|
||||
public static IList<T> ToListLazy<T>(this IEnumerable<T> source) =>
|
||||
new LazyList<T>(source);
|
||||
|
||||
public static bool TryGetFirst<T>(this IEnumerable<T> source, out T result) {
|
||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||
using (var en = source.GetEnumerator()) {
|
||||
@@ -590,6 +629,9 @@ namespace System.Collections.Generic {
|
||||
public static bool is_null_or_empty<T>(this IEnumerable<T> source) =>
|
||||
source == null || !source.Any();
|
||||
|
||||
public static bool is_null_or_empty<T>(this T[] array) =>
|
||||
array == null || array.Length == 0;
|
||||
|
||||
public static IEnumerable<T> empty_if_null<T>(this IEnumerable<T> source) =>
|
||||
source ?? Enumerable.Empty<T>();
|
||||
|
||||
@@ -634,5 +676,44 @@ namespace System.Collections.Generic {
|
||||
|
||||
public int? Count => _collection?.Count ?? _ro_collection?.Count;
|
||||
}
|
||||
|
||||
class LazyList<T> : IList<T> {
|
||||
IEnumerable<T> _source;
|
||||
IList<T> _list_backing;
|
||||
|
||||
public LazyList(IEnumerable<T> source) =>
|
||||
_source = source;
|
||||
|
||||
public T this[int index] { get => _list[index]; set => _list[index] = value; }
|
||||
|
||||
public int Count => _list.Count;
|
||||
|
||||
public bool IsReadOnly => _list.IsReadOnly;
|
||||
|
||||
IList<T> _list {
|
||||
get {
|
||||
if (_list_backing == null) {
|
||||
if (_source == null) {
|
||||
_list_backing = new List<T>(0);
|
||||
} else {
|
||||
_list_backing = new List<T>(_source);
|
||||
_source = null;
|
||||
}
|
||||
}
|
||||
return _list_backing;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(T item) => _list.Add(item);
|
||||
public void Clear() => _list.Clear();
|
||||
public bool Contains(T item) => _list.Contains(item);
|
||||
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
|
||||
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
|
||||
public int IndexOf(T item) => _list.IndexOf(item);
|
||||
public void Insert(int index, T item) => _list.Insert(index, item);
|
||||
public bool Remove(T item) => _list.Remove(item);
|
||||
public void RemoveAt(int index) => _list.RemoveAt(index);
|
||||
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace bts.utils.csv {
|
||||
public static class CsvHelper {
|
||||
|
||||
public static string ToCsv<T>(this IEnumerable<T> items, OrderedDictionary properties = null) where T : class {
|
||||
var output = "";
|
||||
var delimiter = ",";
|
||||
if (properties == null) {
|
||||
properties = new OrderedDictionary();
|
||||
foreach (var pi in typeof(T).GetProperties()) {
|
||||
properties.Add(pi.Name, pi);
|
||||
}
|
||||
}
|
||||
|
||||
using (var sw = new StringWriter()) {
|
||||
var dict_values = properties.Values.OfType<PropertyInfo>();
|
||||
var header = dict_values.Select(n => n.Name).Aggregate((first, second) => first + delimiter + second);
|
||||
sw.WriteLine(header);
|
||||
foreach (var i in items) {
|
||||
var row = dict_values.Select(x => x.GetValue(i, null))
|
||||
.Select(x => x == null ? "null" : x.ToString())
|
||||
.Aggregate((first, second) => first + delimiter + second);
|
||||
sw.WriteLine(row);
|
||||
}
|
||||
output = sw.ToString();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static OrderedDictionary create_ordering_maintainer(Type t, string[] property_names_in_order) {
|
||||
OrderedDictionary od = new OrderedDictionary();
|
||||
var props = t.GetProperties();
|
||||
foreach (var n in property_names_in_order) {
|
||||
var query = props.Where(pi => pi.Name == n);
|
||||
if (query.Any()) {
|
||||
var property_info = query.First();
|
||||
if (!od.Contains(property_info)) {
|
||||
od.Add(n, property_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
return od;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,17 @@ namespace bts.utils {
|
||||
});
|
||||
}
|
||||
|
||||
public static void FilterIncremental<T, TKey>(this TableUpdate<T, TKey> table, Func<T, bool> predicate, out IEnumerable<T> added, out IEnumerable<Change<T>> changes, out IEnumerable<T> removed) where TKey : IEquatable<TKey> {
|
||||
// added
|
||||
added = table.added.Where(predicate).Concat(
|
||||
table.changes.Where(ch => predicate(ch.New) && !predicate(ch.Old)).Select(ch => ch.New));
|
||||
// changes
|
||||
changes = table.changes.Where(ch => predicate(ch.New) && predicate(ch.Old));
|
||||
// removed
|
||||
removed = table.removed.Where(predicate).Concat(
|
||||
table.changes.Where(ch => !predicate(ch.New) && predicate(ch.Old)).Select(ch => ch.Old));
|
||||
}
|
||||
|
||||
public static TableUpdate<T, TKey> with_added<T, TKey>(this TableUpdate<T, TKey> table, IEnumerable<T> added) where TKey : IEquatable<TKey> =>
|
||||
TableUpdate<T, TKey>.update(table, added, Enumerable.Empty<Change<T>>(), Enumerable.Empty<T>(), table.key_extractor);
|
||||
|
||||
@@ -81,7 +92,8 @@ namespace bts.utils {
|
||||
void update(TableUpdate<T, TKey> input) {
|
||||
state = input.state;
|
||||
var builder = output.to_builder();
|
||||
// execute all parent_to_children changes first, so descendent-propagation will be efficient (otherwise propagation might be needlessly performed on values that are yet to be removed, or performed with the wrong root, if the real root is yet to be added).
|
||||
// execute all parent_to_children changes first, so descendent-propagation will be efficient
|
||||
// (otherwise propagation might be needlessly performed on values that are yet to be removed, or performed with the wrong root, if the real root is yet to be added).
|
||||
foreach (var v in input.removed.Concat(input.changes.Select(ch => ch.Old))) {
|
||||
var k = input.key_extractor(v);
|
||||
parent_to_children.remove(parent_key(v), v);
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
|
||||
using System.IO;
|
||||
using System.Security.Policy;
|
||||
using System.Diagnostics;
|
||||
|
||||
using ExcelDna.Integration;
|
||||
using ExcelDna.IntelliSense;
|
||||
using ExcelDna.Logging;
|
||||
|
||||
namespace bts.excel
|
||||
{
|
||||
public class TestMethod
|
||||
{
|
||||
[ExcelFunction]
|
||||
static public string bts_excel_test_string(string x) { return "Hello " + x; }
|
||||
[ExcelFunction]
|
||||
static public object bts_excel_test_int(int x) { return x; }
|
||||
[ExcelFunction]
|
||||
static public object bts_excel_test_long(long x) { return x; }
|
||||
}
|
||||
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public class ContextTeardown : ExcelComAddIn
|
||||
{
|
||||
private api.core.ServiceContext _context;
|
||||
public ContextTeardown(api.core.ServiceContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
//This is called on application shutdown
|
||||
public override void OnBeginShutdown(ref Array custom)
|
||||
{
|
||||
_context.Dispose();
|
||||
_context = null;
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public class ExcelAddin : IExcelAddIn
|
||||
{
|
||||
public void AutoClose()
|
||||
{
|
||||
//don't do anything here, it's only called when the addin is removed, not on shutdown
|
||||
IntelliSenseServer.Uninstall();
|
||||
}
|
||||
public void AutoOpen() //This is called on EXCEL startup, when the addin is loaded
|
||||
{
|
||||
Trace.Listeners.Add(new LogDisplayTraceListener("bts"));
|
||||
IntelliSenseServer.Install();
|
||||
ExcelIntegration.RegisterUnhandledExceptionHandler(ex => ex.ToString());
|
||||
|
||||
load_assemblies();
|
||||
ExcelComAddInHelper.LoadComAddIn(new ContextTeardown(APIDispatch.service_context.Value));
|
||||
}
|
||||
|
||||
private void load_assemblies()
|
||||
{
|
||||
var config = System.Configuration.ConfigurationManager.AppSettings["load_assemblies"];
|
||||
if (config != null)
|
||||
{
|
||||
var asses = config.Split(new char[] { ';', ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var ass in asses)
|
||||
Utilities.bts_load_assembly(ass);
|
||||
}
|
||||
}
|
||||
|
||||
public static void calculate_full_rebuild()
|
||||
{
|
||||
object app = ExcelDnaUtil.Application;
|
||||
var mi = app?.GetType().GetMethod("CalculateFullRebuild", BindingFlags.Instance | BindingFlags.Public);
|
||||
if(mi != null)
|
||||
mi.Invoke(app, null);
|
||||
}
|
||||
|
||||
public static void calculate_full()
|
||||
{
|
||||
object app = ExcelDnaUtil.Application;
|
||||
var mi = app?.GetType().GetMethod("CalculateFull", BindingFlags.Instance | BindingFlags.Public);
|
||||
if (mi != null)
|
||||
mi.Invoke(app, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("spark")]
|
||||
[assembly: InternalsVisibleTo("spark_core")]
|
||||
[assembly: InternalsVisibleTo("sparkcmd")]
|
||||
[assembly: InternalsVisibleTo("spark_test")]
|
||||
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b319f835-7390-47e5-8093-461ed0dfce63")]
|
||||
@@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="ExcelDnaProps"> -->
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!--
|
||||
If you change properties in this file, they may not come into effect until you:
|
||||
* Rebuild the solution/project
|
||||
|
||||
or
|
||||
|
||||
* Close Visual Studio
|
||||
* Delete .vs folder, if exists
|
||||
* Delete ProjectName.csproj.user (or equivalent for VB, F#, etc.), if exists
|
||||
* Delete SolutionName.suo, if exists
|
||||
* Open your solution/project again in Visual Studio
|
||||
-->
|
||||
|
||||
<!--
|
||||
Configuration properties for building .dna files
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
Enable/Disable automatic generation of platform-specific versions of .dna files
|
||||
-->
|
||||
<ExcelDnaCreate32BitAddIn Condition="'$(ExcelDnaCreate32BitAddIn)' == ''">false</ExcelDnaCreate32BitAddIn>
|
||||
<ExcelDnaCreate64BitAddIn Condition="'$(ExcelDnaCreate64BitAddIn)' == ''">true</ExcelDnaCreate64BitAddIn>
|
||||
|
||||
<!--
|
||||
Define the suffix used for each platform-specific file e.g. MyAddIn64.dna
|
||||
-->
|
||||
<ExcelDna32BitAddInSuffix Condition="'$(ExcelDna32BitAddInSuffix)' == ''"></ExcelDna32BitAddInSuffix>
|
||||
<ExcelDna64BitAddInSuffix Condition="'$(ExcelDna64BitAddInSuffix)' == ''">64</ExcelDna64BitAddInSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
Configuration properties for packing .dna files
|
||||
-->
|
||||
<PropertyGroup>
|
||||
<!--
|
||||
Enable/Disable packing of .dna files
|
||||
-->
|
||||
<RunExcelDnaPack Condition="'$(RunExcelDnaPack)' == ''">true</RunExcelDnaPack>
|
||||
|
||||
<!--
|
||||
Suffix used for packed .xll files e.g. MyAddIn-packed.xll
|
||||
-->
|
||||
<ExcelDnaPackXllSuffix Condition="'$(ExcelDnaPackXllSuffix)' == ''">-packed</ExcelDnaPackXllSuffix>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace bts.excel.extensions
|
||||
{
|
||||
public static class EnumParser
|
||||
{
|
||||
public static T ToEnum<T>(this string val, T default_val = default(T)) where T : struct, IConvertible, IComparable
|
||||
{
|
||||
val = val ?? string.Empty;
|
||||
T eval;
|
||||
if (!Enum.TryParse(val, true, out eval))
|
||||
{
|
||||
string[] names = Enum.GetNames(typeof(T));
|
||||
val = names.FirstOrDefault(x => x.ToLower().Contains(val));
|
||||
if(val != null)
|
||||
Enum.TryParse(val, true, out eval);
|
||||
|
||||
if (eval.CompareTo(default(T)) == 0 && default_val.CompareTo(default(T)) != 0)
|
||||
eval = default_val;
|
||||
}
|
||||
return eval;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ExcelDna.Integration;
|
||||
using ExcelDna.Integration.Rtd;
|
||||
using ExcelDna.Registration.Utils;
|
||||
|
||||
using bts.api.admin;
|
||||
using bts.excel;
|
||||
using bts.excel.extensions;
|
||||
using bts.excel.rtd;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace bts.api.orderman
|
||||
{
|
||||
public partial class OrderService_Excel
|
||||
{
|
||||
readonly static Lazy<user.AuthService> _users = new Lazy<user.AuthService>(() => Locator.locate<user.AuthService>(), true);
|
||||
readonly static Lazy<admin.AdminService> _admin = new Lazy<admin.AdminService>(() => Locator.locate<admin.AdminService>(), true);
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Get All Accessible Accounts")]
|
||||
async public static void spark_get_accounts(string login_token, ExcelAsyncHandle handle)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> accts = new List<string>();
|
||||
var admin = await _admin.Value.get_filtered_admin_data_async(new FilteredAdminDataRequest());
|
||||
if (admin.success)
|
||||
{
|
||||
foreach (var acc in admin.value.Accounts)
|
||||
if(acc.IsPresent)
|
||||
accts.Add(acc.Name);
|
||||
}
|
||||
var res = Utilities.make_column_vector(accts.ToArray());
|
||||
handle.SetResult(res);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
handle.SetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Cancel an Order by Order ID", IsMacroType = true)]
|
||||
public static object spark_orderservice_cancel_order(long order_id)
|
||||
{
|
||||
var resp = _service.Value.cancel_order(new Cancel() { OrderKey = Convert.ToUInt32(order_id) });
|
||||
return parse_response(resp);
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Update an Order by Order ID", IsMacroType = true)]
|
||||
public static object spark_orderservice_update_order(long order_id, double price, long quantity)
|
||||
{
|
||||
var resp = _service.Value.update_order(new Update() { OrderKey = Convert.ToUInt32(order_id), Price = price, Quantity = Convert.ToUInt32(quantity) });
|
||||
return parse_response(resp);
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Send an Order to Spark via security_key", IsMacroType = true)]
|
||||
public static object spark_orderservice_send_order_key(
|
||||
[ExcelArgument("Required. Only send the order if > last")] long local_order_id,
|
||||
[ExcelArgument("Required. Security key")] long security_key,
|
||||
[ExcelArgument("Required. Side BUY or SELL")] string side,
|
||||
[ExcelArgument("Required. User")] string user,
|
||||
[ExcelArgument("Required. Account")] string account,
|
||||
[ExcelArgument("Required. Price")] double price,
|
||||
[ExcelArgument("Required. Quantity")] long quantity,
|
||||
[ExcelArgument("Required. OrderType (Limit, Stop, Stop_Limit, Iceberg) - Default Limit")] string order_type,
|
||||
[ExcelArgument("OPTIONAL. Order Params JSON (\"stop_price\" : 51.88)")] string order_params = null,
|
||||
|
||||
[ExcelArgument("OPTIONAL. (DAY,GTC,IOC) - Default DAY")] string time_in_force = null,
|
||||
[ExcelArgument("OPTIONAL. (YES,NO) - Default YES")] string manual_order_indicator = null,
|
||||
[ExcelArgument("OPTIONAL. (1,2,3,4) - Default 1")] string cti_code = null,
|
||||
[ExcelArgument("OPTIONAL. (CUSTOMER,FIRM) - Default FIRM")] string customer_or_firm = null)
|
||||
{
|
||||
if (local_order_id <= _local_order_id)
|
||||
return "local_order_id must be greater than " + _local_order_id;
|
||||
Create cr = new Create();
|
||||
cr.NewOrder = new OrderDefinition()
|
||||
{
|
||||
SecurityKey = Convert.ToUInt32(security_key),
|
||||
Side = EnumParser.ToEnum<api.Side>(side),
|
||||
TimeInForce = time_in_force.ToEnum<TimeInForce>(TimeInForce.Day),
|
||||
ManualOrderIndicator = manual_order_indicator.ToEnum<ManualOrderIndicator>(ManualOrderIndicator.Yes),
|
||||
CtiCode = cti_code.ToEnum<CTICode>(CTICode.CtiCode1),
|
||||
CustomerOrFirm = customer_or_firm.ToEnum<CustomerOrFirm>(CustomerOrFirm.Firm),
|
||||
};
|
||||
cr.Price = price;
|
||||
cr.Quantity = Convert.ToUInt32(quantity);
|
||||
|
||||
var btsuser = resolve_user(user);
|
||||
if(btsuser == null)
|
||||
return "Could not resolve user: " + user;
|
||||
cr.NewOrder.User = btsuser.Name;
|
||||
cr.NewOrder.UserId = btsuser.Id;
|
||||
var btaccount = resolve_account(account);
|
||||
if(btaccount == null)
|
||||
return "Could not resolve account: " + account;
|
||||
cr.NewOrder.Account = btaccount.Name;
|
||||
cr.NewOrder.AccountId = btaccount.Id;
|
||||
cr.NewOrder.CustomDef = custom_def(order_type, order_params);
|
||||
if(cr.NewOrder.CustomDef == null || cr.NewOrder.CustomDef.CustomCase == CustomOrderDefinition.CustomOneofCase.None)
|
||||
return "Could not parse order_type and/or order_params info";
|
||||
|
||||
var resp = _service.Value.create_order(cr);
|
||||
_local_order_id = local_order_id;
|
||||
return parse_response(resp, true);
|
||||
}
|
||||
|
||||
private static object parse_response(Response resp, bool show_vertically = false)
|
||||
{
|
||||
object[,] response_cells = new JsonFormatter(resp).format(false);
|
||||
if(show_vertically)
|
||||
response_cells = bts.excel.Utilities.transpose_keep_dimension(response_cells);
|
||||
return response_cells;
|
||||
}
|
||||
|
||||
static Lazy<AdminData> _admin_data = new Lazy<AdminData>(() => _admin.Value.get_admin_data(new VoidMessage()), true);
|
||||
static BTSUser resolve_user(string username)
|
||||
{
|
||||
var user = _admin_data.Value.Users.FirstOrDefault(x => username != null ? x.Name.ToLowerInvariant() == username.ToLowerInvariant() : true);
|
||||
return user;
|
||||
}
|
||||
|
||||
static BTSAccount resolve_account(string acctname)
|
||||
{
|
||||
var acc = _admin_data.Value.Accounts.FirstOrDefault(x => x.Name.ToLowerInvariant() == acctname.ToLowerInvariant());
|
||||
return acc;
|
||||
}
|
||||
|
||||
static CustomOrderDefinition custom_def(string order_type, string order_params)
|
||||
{
|
||||
var member = ReflectionExtensions.get_fields_or_properties(typeof(CustomOrderDefinition))
|
||||
.Where(x => x.Name.ToLower() == order_type.ToLower()).FirstOrDefault();
|
||||
if (member != null)
|
||||
{
|
||||
var mi = member.member_type();
|
||||
var instance = APIDispatch.generate_imessage(mi, order_params, false);
|
||||
var cust = new CustomOrderDefinition();
|
||||
ReflectionExtensions.set_value(member, cust, instance);
|
||||
return cust;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
static long _local_order_id = 0;
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Send an Order to Spark via security_key", IsMacroType = true)]
|
||||
public static object spark_orderservice_send_order(
|
||||
[ExcelArgument("Required. Only send the order if > last")] long local_order_id,
|
||||
[ExcelArgument("Required. Exchange (GLBX,SIM)")] string exchange,
|
||||
[ExcelArgument("Required. Security Desc (ZNZ9 or ZNZ9-ZNH0)")] string security_desc,
|
||||
[ExcelArgument("Required. Side BUY or SELL")] string side,
|
||||
[ExcelArgument("Required. User")] string user,
|
||||
[ExcelArgument("Required. Account")] string account,
|
||||
[ExcelArgument("Required. Price")] double price,
|
||||
[ExcelArgument("Required. Quantity")] long quantity,
|
||||
[ExcelArgument("Required. OrderType (Limit, Stop, Stop_Limit, Iceberg) - Default Limit")] string order_type,
|
||||
[ExcelArgument("OPTIONAL. Order Params JSON (\"stop_price\" : 51.88)")] string order_params = null,
|
||||
|
||||
[ExcelArgument("OPTIONAL. (DAY,GTC,IOC) - Default DAY")] string time_in_force = null,
|
||||
[ExcelArgument("OPTIONAL. (YES,NO) - Default YES")] string manual_order_indicator = null,
|
||||
[ExcelArgument("OPTIONAL. (1,2,3,4) - Default 1")] string cti_code = null,
|
||||
[ExcelArgument("OPTIONAL. (CUSTOMER,FIRM) - Default FIRM")] string customer_or_firm = null)
|
||||
{
|
||||
if (local_order_id <= _local_order_id)
|
||||
return "local_order_id must be greater than " + _local_order_id;
|
||||
Venue ven;
|
||||
if (!Utilities.parse_venue(exchange, out ven))
|
||||
return "Can't Parse Exchange: " + (exchange ?? string.Empty);
|
||||
|
||||
uint key;
|
||||
if (MDSubscribe.market_data(ven).lookup_security_key_from_desc(security_desc, out key))
|
||||
{
|
||||
return spark_orderservice_send_order_key(local_order_id, (long)key, side, user, account, price, quantity, order_type, order_params,
|
||||
time_in_force, manual_order_indicator, cti_code, customer_or_firm);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Can't find security desc " + security_desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reflection;
|
||||
|
||||
namespace bts.excel.extensions
|
||||
{
|
||||
public static class ReflectionExtensions
|
||||
{
|
||||
public static void set_value(this MemberInfo info, object target, object value)
|
||||
{
|
||||
if (info is FieldInfo)
|
||||
((FieldInfo)info).SetValue(target, value);
|
||||
else if (info is PropertyInfo)
|
||||
((PropertyInfo)info).SetValue(target, value);
|
||||
}
|
||||
|
||||
public static object get_value(this MemberInfo info, object target)
|
||||
{
|
||||
if (info is FieldInfo)
|
||||
return ((FieldInfo)info).GetValue(target);
|
||||
else if (info is PropertyInfo)
|
||||
return ((PropertyInfo)info).GetValue(target);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemberInfo[] get_fields_or_properties(this Type t)
|
||||
{
|
||||
MemberInfo[] mi = t.GetMembers(BindingFlags.Instance | BindingFlags.Public
|
||||
| BindingFlags.NonPublic).Where(m => (m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property)).ToArray();
|
||||
return mi;
|
||||
}
|
||||
|
||||
public static MemberInfo[] get_fields(this Type t)
|
||||
{
|
||||
MemberInfo[] mi = t.GetMembers(BindingFlags.Instance | BindingFlags.Public
|
||||
| BindingFlags.NonPublic).Where(m => (m.MemberType == MemberTypes.Field)).ToArray();
|
||||
return mi;
|
||||
}
|
||||
|
||||
public static MemberInfo[] get_properties(this Type t)
|
||||
{
|
||||
MemberInfo[] mi = t.GetMembers(BindingFlags.Instance | BindingFlags.Public
|
||||
| BindingFlags.NonPublic).Where(m => (m.MemberType == MemberTypes.Property)).ToArray();
|
||||
return mi;
|
||||
}
|
||||
|
||||
public static MemberInfo get_field_or_property(this Type t, string name)
|
||||
{
|
||||
MemberInfo[] mi = t.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => (m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property))
|
||||
.Where(m => (m.Name == name))
|
||||
.ToArray();
|
||||
if (mi != null && mi.Length > 0)
|
||||
return mi[0];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemberInfo get_static_field_or_property(this Type t, string name)
|
||||
{
|
||||
MemberInfo[] mi = t.GetMembers(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => (m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property))
|
||||
.Where(m => (m.Name == name))
|
||||
.ToArray();
|
||||
if (mi != null && mi.Length > 0)
|
||||
return mi[0];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MemberInfo[] search_field_or_property(this Type t, Func<MemberInfo, bool> criteria)
|
||||
{
|
||||
MemberInfo[] mi = t.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(m => (m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property))
|
||||
.Where(criteria)
|
||||
.ToArray();
|
||||
if (mi != null && mi.Length > 0)
|
||||
return mi;
|
||||
else
|
||||
return new MemberInfo[0];
|
||||
}
|
||||
|
||||
|
||||
public static Type member_type(this MemberInfo info)
|
||||
{
|
||||
if (info is FieldInfo)
|
||||
return ((FieldInfo)info).FieldType;
|
||||
else if (info is PropertyInfo)
|
||||
return ((PropertyInfo)info).PropertyType;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MethodInfo[] find_method(this Type t, Func<MethodInfo, bool> criteria)
|
||||
{
|
||||
var mi = t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(criteria).ToArray();
|
||||
if (mi != null && mi.Length > 0)
|
||||
return mi;
|
||||
else
|
||||
return new MethodInfo[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ExcelDna.AddIn" version="0.34.6" targetFramework="net471" />
|
||||
<package id="ExcelDna.Integration" version="0.34.6" targetFramework="net471" />
|
||||
</packages>
|
||||
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
|
||||
using ExcelDna.Integration;
|
||||
using ExcelDna.Integration.Rtd;
|
||||
using bts.excel.extensions;
|
||||
using bts.api.core;
|
||||
using bts.api;
|
||||
using bts.api.md;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
[System.Runtime.InteropServices.ComVisible(true)]
|
||||
public class APIRTDServer : ExcelRtdServer
|
||||
{
|
||||
readonly Dictionary<int, IObservable<object>> _subs = new Dictionary<int, IObservable<object>>();
|
||||
readonly List<IDisposable> _disps = new List<IDisposable>();
|
||||
readonly static ConcurrentDictionary<string, object> data_store = new ConcurrentDictionary<string, object>();
|
||||
public APIRTDServer()
|
||||
{
|
||||
}
|
||||
|
||||
static public bool retrieve(string key, out object data)
|
||||
{
|
||||
return data_store.TryGetValue(key, out data);
|
||||
}
|
||||
|
||||
protected override bool ServerStart() { return true; }
|
||||
protected override void ServerTerminate() { }
|
||||
|
||||
protected override ExcelRtdServer.Topic CreateTopic(int topicId, IList<string> topicInfo)
|
||||
{
|
||||
string[] tagvals = new string[topicInfo.Count - 2];
|
||||
Array.Copy(topicInfo.ToArray(), 2, tagvals, 0, tagvals.Length);
|
||||
var bt = new APITopic(this, topicId, topicInfo[0], topicInfo[1], tagvals);
|
||||
return bt;
|
||||
}
|
||||
|
||||
protected override object ConnectData(Topic topic, IList<string> topicInfo, ref bool newValues)
|
||||
{
|
||||
//return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA);
|
||||
newValues = true;
|
||||
TopicBase bt = (TopicBase)topic;
|
||||
IObservable<object> obs = null;
|
||||
try
|
||||
{
|
||||
string error = subscribe(bt, out obs);
|
||||
if (obs == null)
|
||||
return error;
|
||||
_subs[topic.TopicId] = obs;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return "PLEASE RESUBSCRIBE! Error: " + e.ToString();
|
||||
}
|
||||
_disps.Add(obs.Subscribe((data) =>
|
||||
{
|
||||
string gstring = bt.id.ToString();
|
||||
|
||||
data_store[gstring] = data;
|
||||
bt.UpdateValue(gstring);
|
||||
bt.UpdateNotify();
|
||||
},
|
||||
(error) =>
|
||||
{
|
||||
topic.UpdateValue(error.ToString());
|
||||
},
|
||||
() => { }));
|
||||
return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA); //success!
|
||||
}
|
||||
|
||||
protected override void DisconnectData(ExcelRtdServer.Topic topic)
|
||||
{
|
||||
IObservable<object> sub;
|
||||
if (_subs.TryGetValue(topic.TopicId, out sub))
|
||||
{
|
||||
IDisposable disp = sub as IDisposable;
|
||||
if (disp != null)
|
||||
disp.Dispose();
|
||||
_subs.Remove(topic.TopicId);
|
||||
}
|
||||
}
|
||||
|
||||
protected override int Heartbeat()
|
||||
{
|
||||
return base.Heartbeat();
|
||||
}
|
||||
|
||||
|
||||
string subscribe(TopicBase topic, out IObservable<object> stream)
|
||||
{
|
||||
if(topic is APITopic apitopic)
|
||||
return subscribe(apitopic, out stream);
|
||||
else
|
||||
{
|
||||
stream = null;
|
||||
return "Unknown Topic Type";
|
||||
}
|
||||
}
|
||||
|
||||
string subscribe(APITopic topic, out IObservable<object> stream)
|
||||
{
|
||||
stream = null;
|
||||
if (topic.service_type == null)
|
||||
return "Unknown ServiceType: " + topic.service_type_string;
|
||||
if (topic.request_type == null)
|
||||
return "Unknown MethodName: " + topic.method_name;
|
||||
|
||||
var service = APIDispatch.locate_service(topic.service_type);
|
||||
var request = APIDispatch.generate_request(topic.service_type, topic.method_name, topic.parameters[0]);
|
||||
if (service != null) //request can be null here
|
||||
{
|
||||
var subscription = APIDispatch.invoke_service_call(service, topic.method_name, request);
|
||||
stream = subscription as IObservable<object>;
|
||||
if (stream != null)
|
||||
{
|
||||
dynamic dtable = ObservableUpdateExtensions.Table((dynamic)subscription);
|
||||
stream = dtable as IObservable<object>;
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using ExcelDna.Integration;
|
||||
using ExcelDna.Integration.Rtd;
|
||||
using bts.excel.extensions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class TopicBase : ExcelRtdServer.Topic
|
||||
{
|
||||
public Guid id { get; protected set; }
|
||||
|
||||
public TopicBase(ExcelRtdServer server, int topicid) : base(server, topicid)
|
||||
{
|
||||
id = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
|
||||
class APITopic : TopicBase
|
||||
{
|
||||
public Type service_type { get; private set; }
|
||||
public Type request_type { get; private set; }
|
||||
public string method_name { get; private set; }
|
||||
public string[] parameters { get; private set; }
|
||||
|
||||
public string service_type_string { get; private set; }
|
||||
public const string topic_type = "api";
|
||||
|
||||
public APITopic(ExcelRtdServer server, int topicid,
|
||||
string serv_type, string methodname, string[] param) : base(server, topicid)
|
||||
{
|
||||
service_type_string = serv_type;
|
||||
method_name = methodname;
|
||||
service_type = find_api_type(service_type_string, null, typeof(bts.api.core.IApiClient));
|
||||
request_type = APIDispatch.find_request_type(service_type, method_name);
|
||||
parameters = param;
|
||||
}
|
||||
|
||||
Type find_api_type(string type, string assem_regex = null, Type assignable = null)
|
||||
{
|
||||
return Utilities.find_full_type_in_all_assemblies(type, assem_regex, assignable);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var h = service_type?.GetHashCode() ^ request_type?.GetHashCode() ^ all_params().GetHashCode();
|
||||
if (h.HasValue)
|
||||
return h.Value;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
string all_params()
|
||||
{
|
||||
if (parameters != null)
|
||||
return parameters.Aggregate((a, b) => a + b);
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
APITopic top = (obj as APITopic);
|
||||
if (top == null)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
return top.service_type.Equals(this.service_type) &&
|
||||
top.request_type.Equals(this.request_type) &&
|
||||
top.all_params().Equals(this.all_params());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using bts.excel.extensions;
|
||||
using System.Text.RegularExpressions;
|
||||
using bts.api.core;
|
||||
|
||||
namespace bts.excel
|
||||
{
|
||||
public class DataParser
|
||||
{
|
||||
private static Type analyze_type(Type type, out bool is_array)
|
||||
{
|
||||
Type element_type = type;
|
||||
is_array = false;
|
||||
if (element_type.IsArray)
|
||||
{
|
||||
is_array = true;
|
||||
element_type = element_type.GetElementType();
|
||||
}
|
||||
return element_type;
|
||||
}
|
||||
|
||||
public static bool supported_primitive(Type t)
|
||||
{
|
||||
bool dummy;
|
||||
return supported_primitive(t, out dummy);
|
||||
}
|
||||
|
||||
public static bool supported_primitive(Type t, out bool is_array)
|
||||
{
|
||||
is_array = t.IsArray;
|
||||
if (is_array)
|
||||
t = t.GetElementType();
|
||||
return t.IsPrimitive || t.IsEnum || t == typeof(string) || t == typeof(DateTime);
|
||||
}
|
||||
|
||||
public static bool excluded_member(MemberInfo s)
|
||||
{
|
||||
return s.Name.ToLower() == "extensionobject" ||
|
||||
s.Name.ToLower() == "proto" ||
|
||||
s.Name.ToLower() == "descriptor" ||
|
||||
|
||||
s.Name.Contains(".")
|
||||
;
|
||||
}
|
||||
|
||||
private static void analyze_fields(Type element_type,
|
||||
out List<MemberInfo> superduperfields, out List<MemberInfo> superfields, out List<MemberInfo> fields,
|
||||
out List<string> superdupernames, out List<string> supernames, out List<string> names, out List<string> combined)
|
||||
{
|
||||
var members = ReflectionExtensions.get_fields_or_properties(element_type);
|
||||
superduperfields = new List<MemberInfo>();
|
||||
superfields = new List<MemberInfo>();
|
||||
fields = new List<MemberInfo>();
|
||||
superdupernames = new List<string>();
|
||||
supernames = new List<string>();
|
||||
names = new List<string>();
|
||||
combined = new List<string>();
|
||||
foreach (var r in members)
|
||||
{
|
||||
if (excluded_member(r))
|
||||
continue;
|
||||
if (supported_primitive(ReflectionExtensions.member_type(r)))
|
||||
{
|
||||
superduperfields.Add(r);
|
||||
superdupernames.Add(r.Name);
|
||||
superfields.Add(r);
|
||||
supernames.Add(r.Name);
|
||||
fields.Add(r);
|
||||
names.Add(r.Name);
|
||||
combined.Add(r.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sub = ReflectionExtensions.get_fields_or_properties(ReflectionExtensions.member_type(r));
|
||||
foreach (var s in sub)
|
||||
{
|
||||
if (excluded_member(s))
|
||||
continue;
|
||||
if (supported_primitive(ReflectionExtensions.member_type(s)))
|
||||
{
|
||||
superduperfields.Add(r);
|
||||
superdupernames.Add(r.Name);
|
||||
superfields.Add(r);
|
||||
supernames.Add(r.Name);
|
||||
fields.Add(s);
|
||||
names.Add(s.Name);
|
||||
combined.Add(r.Name + "." + s.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
var subsub = ReflectionExtensions.get_fields_or_properties(ReflectionExtensions.member_type(s));
|
||||
foreach (var ss in subsub)
|
||||
{
|
||||
if (excluded_member(ss) || !supported_primitive(ReflectionExtensions.member_type(ss)))
|
||||
continue;
|
||||
superduperfields.Add(r);
|
||||
superdupernames.Add(r.Name);
|
||||
superfields.Add(s);
|
||||
supernames.Add(s.Name);
|
||||
fields.Add(ss);
|
||||
names.Add(ss.Name);
|
||||
combined.Add(r.Name + "." + s.Name + "." + ss.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public object gather_data(Type type, object[,] data)
|
||||
{
|
||||
if (type == null)
|
||||
return null;
|
||||
bool is_array;
|
||||
Type element_type = analyze_type(type, out is_array);
|
||||
|
||||
bool field_name_headers = true;
|
||||
List<MemberInfo> superduperfields, superfields, fields;
|
||||
List<string> superdupernames, supernames, names, combined;
|
||||
analyze_fields(element_type, out superduperfields, out superfields, out fields,
|
||||
out superdupernames, out supernames, out names, out combined);
|
||||
|
||||
int object_len = data.GetLength(1) - (field_name_headers ? 1 : 0);
|
||||
Array objects = Array.CreateInstance(element_type, object_len);
|
||||
for (int j = 0; j < objects.Length; j++)
|
||||
{
|
||||
object target = Activator.CreateInstance(element_type);
|
||||
for (int zz = 0; zz < superduperfields.Count; zz++)
|
||||
{
|
||||
if (Regex.Matches(combined[zz], @"\.").Count == 2)
|
||||
ReflectionExtensions.set_value(superduperfields[zz], target, Activator.CreateInstance(ReflectionExtensions.member_type(superduperfields[zz])));
|
||||
}
|
||||
for (int z = 0; z < superfields.Count; z++)
|
||||
{
|
||||
if (combined[z].Contains("."))
|
||||
ReflectionExtensions.set_value(superfields[z], target, Activator.CreateInstance(ReflectionExtensions.member_type(superfields[z])));
|
||||
}
|
||||
for (int i = 0; i < data.GetLength(0); i++)
|
||||
{
|
||||
string name = data[i, 0].ToString();
|
||||
int idx = combined.IndexOf(name);
|
||||
if (idx < 0 || idx >= combined.Count)
|
||||
continue;
|
||||
|
||||
MemberInfo fi = fields[idx];
|
||||
object val = val = data[i, j + (field_name_headers ? 1 : 0)];
|
||||
val = read_data(ReflectionExtensions.member_type(fi), val);
|
||||
int dotcount = Regex.Matches(combined[i], @"\.").Count;
|
||||
if (dotcount == 2)
|
||||
{
|
||||
object subsubtarget = ReflectionExtensions.get_value(superduperfields[i], target);
|
||||
if (subsubtarget != null)
|
||||
{
|
||||
object subtarget = ReflectionExtensions.get_value(superfields[i], subsubtarget);
|
||||
if (subtarget != null)
|
||||
ReflectionExtensions.set_value(fi, subtarget, val);
|
||||
}
|
||||
}
|
||||
else if (dotcount == 1)
|
||||
{
|
||||
object subtarget = ReflectionExtensions.get_value(superfields[i], target);
|
||||
if (subtarget != null)
|
||||
ReflectionExtensions.set_value(fi, subtarget, val);
|
||||
}
|
||||
else if (dotcount == 0)
|
||||
ReflectionExtensions.set_value(fi, target, val);
|
||||
}
|
||||
objects.SetValue(target, j);
|
||||
}
|
||||
|
||||
if (is_array)
|
||||
return objects;
|
||||
else if (objects.Length > 0)
|
||||
return objects.GetValue(0);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static object read_data(Type field_type, object val)
|
||||
{
|
||||
if (typeof(Array).IsAssignableFrom(field_type))
|
||||
val = unstringify_array(val, field_type);
|
||||
else if (field_type == typeof(DateTime))
|
||||
val = DateTime.FromOADate(Convert.ToDouble(val));
|
||||
else if (field_type.IsEnum)
|
||||
val = Enum.Parse(field_type, val.ToString());
|
||||
else
|
||||
val = Convert.ChangeType(val, field_type);
|
||||
return val;
|
||||
}
|
||||
|
||||
public static Tuple<object[], object[]> key_value_tuple<T, TKey>(TableUpdate<T, TKey> source) where TKey : IEquatable<TKey>
|
||||
{
|
||||
return Tuple.Create(source.state.Keys.Cast<object>().ToArray(), source.state.Values.Cast<object>().ToArray());
|
||||
}
|
||||
|
||||
public static object[,] scatter_data(object data, bool include_field_names = true, Type type_override = null)
|
||||
{
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
bool is_array;
|
||||
Type type = type_override ?? data.GetType();
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(TableUpdate<,>)))
|
||||
{
|
||||
Tuple<object[], object[]> tup = key_value_tuple((dynamic)data);
|
||||
return scatter_data(tup.Item2, include_field_names, tup.Item2.FirstOrDefault()?.GetType().MakeArrayType());
|
||||
}
|
||||
Type element_type = analyze_type(type, out is_array);
|
||||
|
||||
List<MemberInfo> superduperfields, superfields, fields;
|
||||
List<string> superdupernames, supernames, names, combined;
|
||||
analyze_fields(element_type, out superduperfields, out superfields, out fields,
|
||||
out superdupernames, out supernames, out names, out combined);
|
||||
|
||||
Array the_data = (is_array) ? (Array)data : new object[] { data };
|
||||
int len = the_data.GetLength(0);
|
||||
|
||||
var ret = new object[fields.Count, len + (include_field_names ? 1 : 0)];
|
||||
for (int j = 0; j < ret.GetLength(1); j++)
|
||||
{
|
||||
for (int i = 0; i < ret.GetLength(0); i++)
|
||||
{
|
||||
object dat = "";
|
||||
int dotcount = Regex.Matches(combined[i], @"\.").Count;
|
||||
if (dotcount == 2)
|
||||
{
|
||||
if (j == 0 && include_field_names)
|
||||
dat = combined[i];
|
||||
else
|
||||
{
|
||||
object subsub = ReflectionExtensions.get_value(superduperfields[i], the_data.GetValue(j - (include_field_names ? 1 : 0)));
|
||||
if (subsub != null)
|
||||
{
|
||||
object sub = ReflectionExtensions.get_value(superfields[i], subsub);
|
||||
if (sub != null)
|
||||
dat = ReflectionExtensions.get_value(fields[i], sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dotcount == 1)
|
||||
{
|
||||
if (j == 0 && include_field_names)
|
||||
dat = combined[i];
|
||||
else
|
||||
{
|
||||
object sub = ReflectionExtensions.get_value(superfields[i], the_data.GetValue(j - (include_field_names ? 1 : 0)));
|
||||
if (sub != null)
|
||||
dat = ReflectionExtensions.get_value(fields[i], sub);
|
||||
}
|
||||
}
|
||||
else if (dotcount == 0)
|
||||
{
|
||||
if (j == 0 && include_field_names)
|
||||
dat = names[i];
|
||||
else
|
||||
dat = ReflectionExtensions.get_value(fields[i], the_data.GetValue(j - (include_field_names ? 1 : 0)));
|
||||
}
|
||||
else
|
||||
dat = "Unknown value: " + combined[i];
|
||||
write_data(out ret[i, j], dat);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void write_data(out object ret, object dat)
|
||||
{
|
||||
ret = dat;
|
||||
if (dat is DateTime)
|
||||
ret = ((DateTime)dat).ToOADate();
|
||||
else if (dat is Enum)
|
||||
ret = dat.ToString();
|
||||
else if (dat is Array)
|
||||
{
|
||||
Array ary = (Array)dat;
|
||||
ret = stringify_array(ary);
|
||||
}
|
||||
}
|
||||
|
||||
public static string stringify_array(Array array)
|
||||
{
|
||||
string stringify = "{ ";
|
||||
int idx = 0;
|
||||
foreach (object d in array)
|
||||
{
|
||||
object o;
|
||||
write_data(out o, d);
|
||||
stringify += o.ToString() + ((idx++ == array.Length - 1) ? string.Empty : ",");
|
||||
}
|
||||
stringify += " }";
|
||||
return stringify;
|
||||
}
|
||||
|
||||
public static Array unstringify_array(object val, Type field_type = null)
|
||||
{
|
||||
if (field_type == null)
|
||||
field_type = typeof(string[]);
|
||||
|
||||
string[] data = val.ToString().Split(new char[] { ',', '{', '}' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
Type dt = field_type.GetElementType();
|
||||
Array ary = Array.CreateInstance(dt, data.Length);
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
object entry = null;
|
||||
try
|
||||
{
|
||||
entry = read_data(dt, Convert.ChangeType(data[i], dt));
|
||||
}
|
||||
catch (FormatException) { }
|
||||
ary.SetValue(entry, i);
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using bts.md;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class BookMDFormatter : IExcelFormatter
|
||||
{
|
||||
readonly IMDBook _update;
|
||||
public BookMDFormatter(IMDBook upd)
|
||||
{
|
||||
_update = upd;
|
||||
}
|
||||
|
||||
public object[,] format(bool include_headers = false)
|
||||
{
|
||||
return format(_update, include_headers);
|
||||
}
|
||||
|
||||
static public object[,] format(IMDBook update, bool include_headers = false)
|
||||
{
|
||||
const int cols = 5;
|
||||
const int rows = 30;
|
||||
var ret = new object[rows, cols];
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
ret[i, j] = string.Empty;
|
||||
|
||||
if (update != null)
|
||||
{
|
||||
int idx = 0;
|
||||
for (int j = update.asks.Count - 1; j >= 0 && idx < rows; j--)
|
||||
{
|
||||
var ask = update.asks[j];
|
||||
ret[idx, 1] = ask.price;
|
||||
ret[idx, 2] = ask.size;
|
||||
idx++;
|
||||
}
|
||||
for (int j = 0; j < update.bids.Count && idx < rows; j++)
|
||||
{
|
||||
var bid = update.bids[j];
|
||||
ret[idx, 1] = bid.price;
|
||||
ret[idx, 0] = bid.size;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System;
|
||||
using bts.md;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class FormatterFactory
|
||||
{
|
||||
public static IExcelFormatter make_formatter(object data)
|
||||
{
|
||||
if(data is IMDBook upd)
|
||||
return new BookMDFormatter(upd);
|
||||
else
|
||||
{
|
||||
return new JsonFormatter(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
internal interface IExcelFormatter
|
||||
{
|
||||
object[,] format(bool include_headers = false);
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using Google.Protobuf;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using ExcelDna.Integration;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class JsonFormatter : IExcelFormatter
|
||||
{
|
||||
private object _data;
|
||||
static Google.Protobuf.JsonFormatter _protoformatter =
|
||||
new Google.Protobuf.JsonFormatter(Google.Protobuf.JsonFormatter.Settings.Default.WithFormatDefaultValues(true));
|
||||
public JsonFormatter(object data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
#region parser
|
||||
static IDictionary<string, object> parse_dictionary(object[,] range)
|
||||
{
|
||||
Dictionary<string, object> dict = new Dictionary<string, object>();
|
||||
if (range.Rank > 1)
|
||||
{
|
||||
for (int i = 0; i < range.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 1; j < range.GetLength(1); j++)
|
||||
dict[range.GetValue(i, 0).ToString()] = range.GetValue(i, j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 1; j < range.Length; j++)
|
||||
dict[range.GetValue(0).ToString()] = range.GetValue(j);
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
public static string parse_json(Type type, object[,] range)
|
||||
{
|
||||
var dict = parse_dictionary(range);
|
||||
string str = JsonConvert.SerializeObject(dict);
|
||||
return str;
|
||||
}
|
||||
|
||||
public static object parse_json_object(Type type, object[,] range)
|
||||
{
|
||||
string json = parse_json(type, range);
|
||||
var obj = JsonConvert.DeserializeObject(json);
|
||||
return obj;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public object[,] format(bool include_headers = false)
|
||||
{
|
||||
if (_data is IEnumerable iem)
|
||||
return format_many(iem, include_headers);
|
||||
else
|
||||
return format_one(_data, include_headers);
|
||||
}
|
||||
|
||||
object[,] format_many(IEnumerable data, bool include_headers = false)
|
||||
{
|
||||
List<SortedDictionary<string, object>> res = new List<SortedDictionary<string, object>>();
|
||||
foreach (var d in data)
|
||||
res.Add(to_dictionary(d));
|
||||
object[,] ret = fill_object_array(res, include_headers);
|
||||
return ret;
|
||||
}
|
||||
|
||||
object[,] format_one(object data, bool include_headers = false)
|
||||
{
|
||||
var d = to_dictionary(data);
|
||||
object[,] ret = fill_object_array(new[] { d }, include_headers);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SortedDictionary<string, object> to_dictionary(object data)
|
||||
{
|
||||
string json = null;
|
||||
if(data is IMessage imsg)
|
||||
json = _protoformatter.Format(imsg);
|
||||
else
|
||||
json = JsonConvert.SerializeObject(data);
|
||||
|
||||
JObject jo = JObject.Parse(json);
|
||||
SortedDictionary<string, object> results = new SortedDictionary<string, object>();
|
||||
parse_object(jo, results);
|
||||
return results;
|
||||
}
|
||||
|
||||
void parse_object(JObject jo, SortedDictionary<string, object> results)
|
||||
{
|
||||
foreach (var kvp in jo)
|
||||
{
|
||||
if (kvp.Value is JArray jar) //arrays we'll just leave
|
||||
{
|
||||
for (int i = 0; i < jar.Count; i++)
|
||||
results[kvp.Key + "_" + i] = jar[i].ToString();
|
||||
}
|
||||
else if (kvp.Value is JValue jv)
|
||||
results[kvp.Key] = jv.ToString();
|
||||
else if (kvp.Value.HasValues)
|
||||
parse_object((JObject)kvp.Value, results);
|
||||
}
|
||||
}
|
||||
|
||||
object[,] fill_object_array(IEnumerable<SortedDictionary<string, object>> data, bool include_headers = false)
|
||||
{
|
||||
int count = 0;
|
||||
SortedDictionary<string, string> keys = new SortedDictionary<string, string>();
|
||||
foreach (var d in data)
|
||||
{
|
||||
count++;
|
||||
foreach (var kv in d)
|
||||
keys[kv.Key] = null;
|
||||
}
|
||||
object[,] ret = new object[count + (include_headers ? 1 : 0), keys.Count];
|
||||
int r = 0, c = 0;
|
||||
if (include_headers)
|
||||
{
|
||||
foreach (var k in keys.Keys)
|
||||
ret[r, c++] = k;
|
||||
r++;
|
||||
}
|
||||
foreach (var d in data)
|
||||
{
|
||||
c = 0;
|
||||
foreach (var k in keys.Keys)
|
||||
{
|
||||
d.TryGetValue(k, out object val);
|
||||
ret[r, c++] = val; //It found me!
|
||||
}
|
||||
r++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System;
|
||||
using bts.md;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class LastMDFormatter : IExcelFormatter
|
||||
{
|
||||
readonly IMDLast _update;
|
||||
public LastMDFormatter(IMDLast upd)
|
||||
{
|
||||
_update = upd;
|
||||
}
|
||||
|
||||
public object[,] format(bool include_headers = false)
|
||||
{
|
||||
return format(_update, include_headers);
|
||||
}
|
||||
|
||||
static public object[,] format(IMDLast update, bool include_headers = false)
|
||||
{
|
||||
const int cols = 3;
|
||||
const int rows = 1;
|
||||
var ret = new object[rows, cols];
|
||||
|
||||
if (update != null)
|
||||
{
|
||||
ret[0, 0] = update.last?.price;
|
||||
ret[0, 1] = update.last?.size;
|
||||
ret[0, 1] = update.last_time;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using bts.md;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class MiscMDFormatter : IExcelFormatter
|
||||
{
|
||||
readonly IMDMisc _update;
|
||||
public MiscMDFormatter(IMDMisc upd)
|
||||
{
|
||||
_update = upd;
|
||||
}
|
||||
|
||||
public object[,] format(bool include_headers = false)
|
||||
{
|
||||
return format(_update, include_headers);
|
||||
}
|
||||
|
||||
static public object[,] format(IMDMisc update, bool include_headers = false)
|
||||
{
|
||||
return new object[0, 0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
using System;
|
||||
using bts.md;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class TopOfBookMDFormatter : IExcelFormatter
|
||||
{
|
||||
readonly IMDBook _update;
|
||||
public TopOfBookMDFormatter(IMDBook upd)
|
||||
{
|
||||
_update = upd;
|
||||
}
|
||||
|
||||
public object[,] format(bool include_headers = false)
|
||||
{
|
||||
return format(_update, include_headers);
|
||||
}
|
||||
|
||||
static public object[,] format(IMDBook update, bool include_headers = false)
|
||||
{
|
||||
const int cols = 4;
|
||||
const int rows = 1;
|
||||
var ret = new object[rows, cols];
|
||||
for (int i = 0; i < rows; i++)
|
||||
for (int j = 0; j < cols; j++)
|
||||
ret[i, j] = string.Empty;
|
||||
|
||||
if (update != null)
|
||||
{
|
||||
int idx = 0;
|
||||
for (int j = 0; j < update.asks.Count && idx < rows; j++)
|
||||
{
|
||||
var ask = update.asks[j];
|
||||
ret[idx, 2] = ask.price;
|
||||
ret[idx, 3] = ask.size;
|
||||
idx++;
|
||||
}
|
||||
idx = 0;
|
||||
for (int j = 0; j < update.bids.Count && idx < rows; j++)
|
||||
{
|
||||
var bid = update.bids[j];
|
||||
ret[idx, 1] = bid.price;
|
||||
ret[idx, 0] = bid.size;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
|
||||
using System;
|
||||
using bts.md;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
class TopicMDFormatter : IExcelFormatter
|
||||
{
|
||||
readonly IMDCombined _update;
|
||||
readonly string _topic;
|
||||
public TopicMDFormatter(IMDCombined upd, string topic)
|
||||
{
|
||||
_update = upd;
|
||||
_topic = topic;
|
||||
}
|
||||
|
||||
public object[,] format(bool include_headers = false)
|
||||
{
|
||||
return format(_update, _topic, include_headers);
|
||||
}
|
||||
|
||||
static public object[,] format(IMDCombined update, string topic, bool include_headers = false)
|
||||
{
|
||||
var retval = new object[1, 1];
|
||||
if(update == null || string.IsNullOrEmpty(topic))
|
||||
return retval;
|
||||
|
||||
switch (topic.ToLower())
|
||||
{
|
||||
case "bid":
|
||||
case "bidprice":
|
||||
retval[0, 0] = update.bids?[0]?.price;
|
||||
break;
|
||||
case "ask":
|
||||
case "askprice":
|
||||
retval[0, 0] = update.asks?[0]?.price;
|
||||
break;
|
||||
case "bidsize":
|
||||
case "bidqty":
|
||||
retval[0, 0] = update.bids?[0]?.size;
|
||||
break;
|
||||
case "asksize":
|
||||
case "askqty":
|
||||
retval[0, 0] = update.asks?[0]?.size;
|
||||
break;
|
||||
case "impliedbid":
|
||||
case "impliedbidprice":
|
||||
retval[0, 0] = update.bids?[0]?.price; //TODO is this the first price with impsz > 0?
|
||||
break;
|
||||
case "impliedask":
|
||||
case "impliedaskprice":
|
||||
retval[0, 0] = update.asks?[0]?.price;
|
||||
break;
|
||||
case "impliedbidsize":
|
||||
case "impliedbidqty":
|
||||
retval[0, 0] = update.bids?[0]?.implied_size;
|
||||
break;
|
||||
case "impliedasksize":
|
||||
case "impliedaskqty":
|
||||
retval[0, 0] = update.asks?[0]?.implied_size;
|
||||
break;
|
||||
case "settlement":
|
||||
case "settlementprice":
|
||||
retval[0, 0] = update.settlement_price;
|
||||
break;
|
||||
case "previoussettlement":
|
||||
case "previoussettlementprice":
|
||||
retval[0, 0] = update.previous_settlement_price;
|
||||
break;
|
||||
case "open":
|
||||
case "openprice":
|
||||
retval[0, 0] = update.open_price;
|
||||
break;
|
||||
case "close":
|
||||
case "closeprice":
|
||||
retval[0, 0] = update.close_price;
|
||||
break;
|
||||
case "high":
|
||||
case "highprice":
|
||||
retval[0, 0] = update.session_high;
|
||||
break;
|
||||
case "low":
|
||||
case "lowprice":
|
||||
retval[0, 0] = update.session_low;
|
||||
break;
|
||||
case "last":
|
||||
case "lastprice":
|
||||
retval[0, 0] = update?.last?.price;
|
||||
break;
|
||||
case "lastsize":
|
||||
case "lastqty":
|
||||
retval[0, 0] = update?.last?.size;
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,194 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ExcelDna.Integration;
|
||||
using ExcelDna.Integration.Rtd;
|
||||
using ExcelDna.Registration.Utils;
|
||||
using System.Reactive.Linq;
|
||||
using bts.api;
|
||||
using bts.md;
|
||||
using bts.api.orderman;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
public class MDSubscribe
|
||||
{
|
||||
[ExcelFunction(Category = "BTS", Description = "Log in to BTS Spark")]
|
||||
async public static void spark_login(string login, string password, ExcelAsyncHandle handle)
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = await Locator.login(login, password);
|
||||
if (res.success && Locator.token.HasValue)
|
||||
{
|
||||
_md.set_auth_token(Locator.token);
|
||||
handle.SetResult("Login Successful");
|
||||
}
|
||||
else
|
||||
handle.SetResult("Login Error: Could not log in check user/pass " + res.reason);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
handle.SetException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static MarketDataClient _md = new MarketDataClient();
|
||||
public static MarketDataClient market_data(api.Venue exchange)
|
||||
{
|
||||
return _md;
|
||||
}
|
||||
|
||||
static public object spark_lookup_security_desc(string exchange, long security_key)
|
||||
{
|
||||
Venue ven;
|
||||
if (!Utilities.parse_venue(exchange, out ven))
|
||||
return Observable.Return("Can't Parse Exchange: " + exchange ?? string.Empty);
|
||||
MDSubscribe.market_data(ven).lookup_security_desc((uint)security_key, out string desc);
|
||||
return desc ?? string.Empty;
|
||||
}
|
||||
|
||||
static IObservable<IEnumerable<object>> md_observable(string contract, string symbol, string security_type, string exchange)
|
||||
{
|
||||
security_type = string.IsNullOrEmpty(security_type) ? SecurityType.Future.ToString() : security_type;
|
||||
exchange = string.IsNullOrEmpty(exchange) ? Security.ExchangeDataOneofCase.Glbx.ToString() : exchange;
|
||||
symbol = string.IsNullOrEmpty(symbol) ? contract.Substring(0, 2) : symbol;
|
||||
|
||||
Venue ven;
|
||||
SecurityType sectype;
|
||||
if (!Utilities.parse_venue(exchange, out ven))
|
||||
return Observable.Return(new [] {"Can't Parse Exchange: " + exchange ?? string.Empty});
|
||||
if (!Utilities.parse_security_type(security_type, out sectype))
|
||||
return Observable.Return(new [] {"Can't Parse Security Type: " + security_type ?? string.Empty});
|
||||
if (string.IsNullOrEmpty(symbol))
|
||||
return Observable.Return(new []{"Can't Parse Symbol: " + symbol ?? string.Empty});
|
||||
if (string.IsNullOrEmpty(contract))
|
||||
return Observable.Return(new []{"Can't Parse Contract: " + contract ?? string.Empty});
|
||||
|
||||
Func<SecurityImmutable, bool> desc = null;
|
||||
switch(ven)
|
||||
{
|
||||
case Venue.Sim:
|
||||
case Venue.Glbx:
|
||||
desc = (x=> x.Glbx.SecurityDesc == contract);
|
||||
break;
|
||||
case Venue.Ice:
|
||||
desc = (x=> x.Ice.SecurityDesc == contract);
|
||||
break;
|
||||
default:
|
||||
desc = (x => true);
|
||||
break;
|
||||
}
|
||||
|
||||
Func<SecurityImmutable, bool> where = (x => x.Exchange == ven && x.Symbol == symbol && x.security_type() == sectype && desc(x) );
|
||||
|
||||
var stream = market_data(ven).subscribe_combined(where);
|
||||
return stream;
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Subscribe to BTS Spark full depth market data")]
|
||||
public static object spark_md_book(
|
||||
[ExcelArgument("Required. The specific contract, GCZ8 or ZNU8-ZNZ8, etc")] string contract,
|
||||
[ExcelArgument("Required. The symbol, GC or ZN, etc")] string symbol,
|
||||
[ExcelArgument("Optional. The type, Future or Spread, default = Future")] string security_type = null,
|
||||
[ExcelArgument("Optional. The exchange, default = GLBX")] string exchange = null)
|
||||
{
|
||||
|
||||
var param = new object[] { contract, symbol, security_type, exchange };
|
||||
return ObservableRtdUtil.Observe(nameof(spark_md_book), param,
|
||||
() => md_observable(contract, symbol, security_type, exchange).Select(data =>
|
||||
{
|
||||
var x = data.FirstOrDefault();
|
||||
if (x != null && x is IMDBook upd)
|
||||
return BookMDFormatter.format(upd);
|
||||
return x;
|
||||
}));
|
||||
// security_type = string.IsNullOrEmpty(security_type) ? SecurityType.Future.ToString() : security_type;
|
||||
// exchange = string.IsNullOrEmpty(exchange) ? Security.ExchangeDataOneofCase.Glbx.ToString() : exchange;
|
||||
// symbol = string.IsNullOrEmpty(symbol) ? contract.Substring(0, 2) : symbol;
|
||||
// string[] topic = new[] { MDTopic.topic_type, MDTopic.book_request_type,
|
||||
// contract, symbol, security_type, exchange};
|
||||
// object val = XlCall.RTD(typeof(RTDServer).FullName, null, topic);
|
||||
// return Subscribe.spark_unpack(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Subscribe to BTS Spark top of book market data")]
|
||||
public static object spark_md_top_of_book(
|
||||
[ExcelArgument("Required. The specific contract, GCZ8 or ZNU8-ZNZ8, etc")] string contract,
|
||||
[ExcelArgument("Required. The symbol, GC or ZN, etc")] string symbol,
|
||||
[ExcelArgument("Optional. The type, Future or Spread, default = Future")] string security_type = null,
|
||||
[ExcelArgument("Optional. The exchange, default = GLBX")] string exchange = null)
|
||||
{
|
||||
var param = new object[] { contract, symbol, security_type, exchange };
|
||||
return ObservableRtdUtil.Observe(nameof(spark_md_top_of_book), param,
|
||||
() => md_observable(contract, symbol, security_type, exchange).Select(data =>
|
||||
{
|
||||
var x = data.FirstOrDefault();
|
||||
if (x != null && x is IMDBook upd)
|
||||
return TopOfBookMDFormatter.format(upd);
|
||||
return x;
|
||||
}));
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Subscribe to BTS Spark last trade market data")]
|
||||
public static object spark_md_last(
|
||||
[ExcelArgument("Required. The specific contract, GCZ8 or ZNU8-ZNZ8, etc")] string contract,
|
||||
[ExcelArgument("Required. The symbol, GC or ZN, etc")] string symbol,
|
||||
[ExcelArgument("Optional. The type, Future or Spread, default = Future")] string security_type = null,
|
||||
[ExcelArgument("Optional. The exchange, default = GLBX")] string exchange = null)
|
||||
{
|
||||
var param = new object[] { contract, symbol, security_type, exchange };
|
||||
return ObservableRtdUtil.Observe(nameof(spark_md_last), param,
|
||||
() => md_observable(contract, symbol, security_type, exchange).Select(data =>
|
||||
{
|
||||
var x = data.FirstOrDefault();
|
||||
if (x != null && x is IMDLast upd)
|
||||
return LastMDFormatter.format(upd);
|
||||
return x;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Subscribe to BTS Spark miscellaneous market data")]
|
||||
public static object spark_md_misc(
|
||||
[ExcelArgument("Required. The specific contract, GCZ8 or ZNU8-ZNZ8, etc")] string contract,
|
||||
[ExcelArgument("Required. The symbol, GC or ZN, etc")] string symbol,
|
||||
[ExcelArgument("Optional. The type, Future or Spread, default = Future")] string security_type = null,
|
||||
[ExcelArgument("Optional. The exchange, default = GLBX")] string exchange = null)
|
||||
{
|
||||
var param = new object[] { contract, symbol, security_type, exchange };
|
||||
return ObservableRtdUtil.Observe(nameof(spark_md_misc), param,
|
||||
() => md_observable(contract, symbol, security_type, exchange).Select(data =>
|
||||
{
|
||||
var x = data.FirstOrDefault();
|
||||
if (x != null && x is IMDMisc upd)
|
||||
return MiscMDFormatter.format(upd);
|
||||
return x;
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Subscribe to BTS Spark topic based market data")]
|
||||
public static object spark_md(
|
||||
[ExcelArgument("Required. The 'Topic' string, 'bid', 'ask', etc")] string topic,
|
||||
[ExcelArgument("Required. The specific contract, GCZ8 or ZNU8-ZNZ8, etc")] string contract,
|
||||
[ExcelArgument("Required. The symbol, GC or ZN, etc")] string symbol,
|
||||
[ExcelArgument("Optional. The type, Future or Spread, default = Future")] string security_type = null,
|
||||
[ExcelArgument("Optional. The exchange, default = GLBX")] string exchange = null)
|
||||
{
|
||||
var param = new object[] { topic, contract, symbol, security_type, exchange };
|
||||
return ObservableRtdUtil.Observe(nameof(spark_md), param,
|
||||
() => md_observable(contract, symbol, security_type, exchange).Select(data =>
|
||||
{
|
||||
var x = data.FirstOrDefault();
|
||||
if (x != null && x is IMDCombined upd)
|
||||
return TopicMDFormatter.format(upd, topic);
|
||||
return x;
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ExcelDna.Integration;
|
||||
using ExcelDna.Integration.Rtd;
|
||||
using ExcelDna.Registration;
|
||||
using ExcelDna.Registration.Utils;
|
||||
using System.Reactive.Linq;
|
||||
using bts.api;
|
||||
using bts.api.md;
|
||||
using bts.api.core;
|
||||
using bts.api.orderman;
|
||||
using bts.co2;
|
||||
|
||||
namespace bts.excel.rtd
|
||||
{
|
||||
public class Subscribe
|
||||
{
|
||||
[ExcelFunction(Category = "BTS", Description = "Subscribe to BTS Spark API Service")]
|
||||
public static object spark_api_subscribe(string service_type, string method_name, object parameters)
|
||||
{
|
||||
IList<string> topic = Utilities.get_tokens(parameters);
|
||||
topic.Insert(0, method_name);
|
||||
topic.Insert(0, service_type);
|
||||
object val = XlCall.RTD(typeof(APIRTDServer).FullName, null, topic.ToArray());
|
||||
return val;
|
||||
}
|
||||
|
||||
[ExcelFunction(Category = "BTS", Description = "Unpacks BTS Spark data from a GUID reference")]
|
||||
public static object spark_unpack(object reference)
|
||||
{
|
||||
object data;
|
||||
if(unpack(reference, out data))
|
||||
return data;
|
||||
else
|
||||
return reference;
|
||||
}
|
||||
|
||||
public static bool unpack(object reference, out object data)
|
||||
{
|
||||
object tempdata; data = null;
|
||||
if (reference is string && APIRTDServer.retrieve(reference.ToString(), out tempdata))
|
||||
{
|
||||
if (tempdata is IExcelFormatter fdata)
|
||||
data = fdata.format();
|
||||
else
|
||||
data = DataParser.scatter_data(tempdata);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//[ExcelFunction]
|
||||
//public static object bts_subscribe_deprecated(string service_type, string request_type, object parameters)
|
||||
//{
|
||||
// IList<string> topic = Utilities.get_tokens(parameters);
|
||||
// topic.Insert(0, request_type);
|
||||
// topic.Insert(0, service_type);
|
||||
// object val = XlCall.RTD(typeof(APIRTDServer).FullName, null, topic.ToArray());
|
||||
|
||||
// if(val is string)
|
||||
// {
|
||||
// //I can't marshal just any old object through the excel machinery, so in order to retain a 'registration free'
|
||||
// //model, I have to pass this string-guid from the RTDServer, up through excel and back here.
|
||||
// object data;
|
||||
// if(APIRTDServer.retrieve(val.ToString(), out data))
|
||||
// {
|
||||
// object[,] ret = DataParser.scatter_data(data);
|
||||
// return ret;
|
||||
// }
|
||||
// }
|
||||
// return val;
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<DnaLibrary Name="spark_excel" RuntimeVersion="v4.0">
|
||||
<ExternalLibrary Path="spark_excel.dll" ExplicitExports="false" LoadFromBytes="true" Pack="true" />
|
||||
|
||||
<Reference Path="ExcelDna.IntelliSense.dll" Pack="true" />
|
||||
<Reference Path="ExcelDna.Registration.dll" Pack="true" />
|
||||
<Reference Path="ExcelDna.Integration.dll" Pack="true" />
|
||||
|
||||
<Reference Path="Google.Protobuf.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="System.Linq.Dynamic.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="Newtonsoft.Json.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="nunit.framework.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="System.Reactive.Core.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="System.Reactive.Interfaces.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="System.Reactive.Providers.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="System.Reactive.Linq.dll" Pack="true" ExplicitExports="true" />
|
||||
<Reference Path="System.Reactive.Runtime.Remoting.dll" Pack="true" ExplicitExports="true" />
|
||||
|
||||
<!--
|
||||
The RuntimeVersion attribute above allows two settings:
|
||||
* RuntimeVersion="v2.0" - for .NET 2.0, 3.0 and 3.5
|
||||
* RuntimeVersion="v4.0" - for .NET 4 and 4.5
|
||||
|
||||
Additional referenced assemblies can be specified by adding 'Reference' tags.
|
||||
These libraries will not be examined and registered with Excel as add-in libraries,
|
||||
but will be packed into the -packed.xll file and loaded at runtime as needed.
|
||||
For example:
|
||||
|
||||
<Reference Path="Another.Library.dll" Pack="true" />
|
||||
|
||||
Excel-DNA also allows the xml for ribbon UI extensions to be specified in the .dna file.
|
||||
See the main Excel-DNA site at http://excel-dna.net for downloads of the full distribution.
|
||||
-->
|
||||
|
||||
</DnaLibrary>
|
||||
@@ -1,83 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
|
||||
<TargetFrameworks>net471</TargetFrameworks>
|
||||
<OutputType>Library</OutputType>
|
||||
<!-- <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput> -->
|
||||
|
||||
<Authors>Blue Trading Systems</Authors>
|
||||
<Company>Blue Trading Systems</Company>
|
||||
<Product>Spark</Product>
|
||||
<Description />
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Platforms>x64</Platforms>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<WarningsAsErrors />
|
||||
<Version>$(major).$(minor).$(patch)</Version>
|
||||
<Version Condition="'$(version)'=='..'">1.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
|
||||
<PackageReference Include="System.Reactive" Version="3.1.1" />
|
||||
<PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
|
||||
<PackageReference Include="System.Linq.Dynamic" Version="1.0.7" />
|
||||
|
||||
<PackageReference Include="ExcelDna.AddIn" Version="0.34.6" />
|
||||
<PackageReference Include="ExcelDna.Integration" Version="0.34.6" />
|
||||
<PackageReference Include="ExcelDna.IntelliSense" Version="1.1.0" />
|
||||
<PackageReference Include="ExcelDna.Registration" Version="0.34.7" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="spark_excel-AddIn.dna" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\ExcelDna.Build.props" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../spark_api/spark_api.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Proto3Excel Include="**/*.proto" />
|
||||
<Proto3Excel Include="../../lib/api/services/*.proto" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="spark_excel_example_2019.xlsm"><CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory></None>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- <Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
|
||||
<ItemGroup>
|
||||
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)..\net471\libspark.dll"/>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
-->
|
||||
|
||||
<!-- <Import Project="$(NuGetPackageRoot)\ExcelDna.AddIn\0.34.6\tools\ExcelDna.AddIn.targets" Condition="Exists('$(NuGetPackageRoot)\ExcelDna.AddIn\0.34.6\tools\ExcelDna.AddIn.targets')" /> -->
|
||||
<Import Project="$(NuGetPackageRoot)\ExcelDna.AddIn\0.34.6\tools\ExcelDna.AddIn.targets"/>
|
||||
<Target Name="EnsureExcelDnaTargetsImported" BeforeTargets="BeforeBuild" Condition="'$(ExcelDnaTargetsImported)' == ''">
|
||||
<Error Condition="!Exists('$(NuGetPackageRoot)\ExcelDna.AddIn\0.34.6\tools\ExcelDna.AddIn.targets') And ('$(RunExcelDnaBuild)' != '' And $(RunExcelDnaBuild))" Text="You are trying to build with ExcelDna, but the NuGet targets file that ExcelDna depends on is not available on this computer. This is probably because the ExcelDna package has not been committed to source control, or NuGet Package Restore is not enabled. Please enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
|
||||
<Error Condition="Exists('$(NuGetPackageRoot)\ExcelDna.AddIn\0.34.6\tools\ExcelDna.AddIn.targets') And ('$(RunExcelDnaBuild)' != '' And $(RunExcelDnaBuild))" Text="ExcelDna cannot be run because NuGet packages were restored prior to the build running, and the targets file was unavailable when the build started. Please build the project again to include these packages in the build. You may also need to make sure that your build server does not delete packages prior to each build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
|
||||
</Target>
|
||||
</Project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,134 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ExcelDna.Integration;
|
||||
|
||||
using bts.api.core;
|
||||
using bts.excel.extensions;
|
||||
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.Reflection;
|
||||
|
||||
namespace bts.excel
|
||||
{
|
||||
public class APIDispatch
|
||||
{
|
||||
public static Lazy<ServiceContext> service_context = new Lazy<ServiceContext>(() => new ServiceContext(), true);
|
||||
static MethodInfo _locate_meth;
|
||||
readonly static Dictionary<object, object> _services = new Dictionary<object, object>();
|
||||
const string descriptor_property_name = "Descriptor";
|
||||
|
||||
static MethodInfo locate_method
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_locate_meth == null)
|
||||
{
|
||||
_locate_meth = service_context.Value.GetType().find_method((_) =>
|
||||
{
|
||||
return _.Name == nameof(ServiceContext.locate) && _.IsGenericMethod;
|
||||
})[0];
|
||||
}
|
||||
return _locate_meth;
|
||||
}
|
||||
}
|
||||
|
||||
static public object api_call_internal(Type service_type, string method_name, IMessage parameters)
|
||||
{
|
||||
object response = null;
|
||||
if (service_type != null && method_name != null)
|
||||
{
|
||||
object service = locate_service(service_type);
|
||||
response = invoke_service_call(service, method_name, parameters);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
//static public object invoke_service_call(object service, Type request_type, IMessage request)
|
||||
//{
|
||||
// var sub_method = service.GetType().GetMethods().Where(meth =>
|
||||
// {
|
||||
// var par = meth.GetParameters().FirstOrDefault();
|
||||
// return (par != null && par.ParameterType.IsAssignableFrom(request_type));
|
||||
// }).FirstOrDefault();
|
||||
// object subscription = null;
|
||||
// if(sub_method != null)
|
||||
// subscription = sub_method.Invoke(service, new[] { request });
|
||||
// return subscription;
|
||||
//}
|
||||
|
||||
static public object invoke_service_call(object service, string method_name, IMessage request)
|
||||
{
|
||||
var sub_method = service.GetType().GetMethod(method_name);
|
||||
object subscription = null;
|
||||
if (sub_method != null)
|
||||
subscription = sub_method.Invoke(service, new[] { request });
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public static Type find_request_type(Type service_type, string method_name)
|
||||
{
|
||||
return service_type?.GetMethod(method_name)?.GetParameters().FirstOrDefault()?.ParameterType;
|
||||
}
|
||||
|
||||
static public IMessage generate_imessage(Type type, string json, bool null_for_empty = false)
|
||||
{
|
||||
IMessage request = null;
|
||||
var descproperty = type?.get_static_field_or_property(descriptor_property_name);
|
||||
if (descproperty != null)
|
||||
{
|
||||
MessageDescriptor desc = (MessageDescriptor)descproperty.get_value(null);
|
||||
if (null_for_empty)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(json) && json != "{ }" && json != "{}")
|
||||
request = JsonParser.Default.Parse(json, desc);
|
||||
else
|
||||
request = null; //TODO this is a workaround for Eric's bug that requires 'empty' requests to pass null instead
|
||||
}
|
||||
else
|
||||
{
|
||||
if(string.IsNullOrEmpty(json))
|
||||
json = "{}";
|
||||
request = JsonParser.Default.Parse(json, desc);
|
||||
}
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
static public IMessage generate_request(Type service_type, string method_name, string request_json)
|
||||
{
|
||||
Type request_type = find_request_type(service_type, method_name);
|
||||
return generate_imessage(request_type, request_json, true);
|
||||
}
|
||||
|
||||
static public object locate_service(Type service_type)
|
||||
{
|
||||
//object svc = null;
|
||||
//if(service_type != null && !_services.TryGetValue(service_type, out svc))
|
||||
//{
|
||||
var method = locate_method?.MakeGenericMethod(service_type);
|
||||
object svc = method?.Invoke(service_context.Value, new object[] { null });
|
||||
if (svc != null)
|
||||
_services[svc] = null;
|
||||
return svc;
|
||||
}
|
||||
|
||||
|
||||
[ExcelFunction]
|
||||
static public object spark_api_call(string service_type, string method_name, object parameters)
|
||||
{
|
||||
Type svc = Utilities.find_full_type_in_all_assemblies(service_type, ".*api.*");
|
||||
|
||||
var tok = Utilities.get_tokens(parameters);
|
||||
string json = tok.FirstOrDefault();
|
||||
IMessage request = generate_request(svc, method_name, json);
|
||||
object resp = api_call_internal(svc, method_name, request);
|
||||
if (resp != null)
|
||||
return DataParser.scatter_data(resp);
|
||||
else
|
||||
return ExcelErrorUtil.ToComError(ExcelError.ExcelErrorNA);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using ExcelDna.Integration;
|
||||
using bts.api;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace bts.excel
|
||||
{
|
||||
public class Utilities
|
||||
{
|
||||
|
||||
[ExcelFunction]
|
||||
public static object bts_json_lookup(string json, string key1, string key2 = null, string key3 = null)
|
||||
{
|
||||
var jo = JObject.Parse(json);
|
||||
JToken val = json;
|
||||
if (!string.IsNullOrEmpty(key1) && !string.IsNullOrEmpty(key2) && !string.IsNullOrEmpty(key3))
|
||||
val = jo[key1][key2][key3];
|
||||
else if (!string.IsNullOrEmpty(key1) && !string.IsNullOrEmpty(key2))
|
||||
val = jo[key1][key2];
|
||||
else if (!string.IsNullOrEmpty(key1))
|
||||
val = jo[key1];
|
||||
return val.ToString();
|
||||
}
|
||||
|
||||
public static bool parse_venue(string exch, out Venue ven)
|
||||
{
|
||||
if (!Enum.TryParse(exch.ToUpper(), true, out ven))
|
||||
return Enum.TryParse("VENUE_" + exch.ToUpper(), true, out ven);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool parse_security_type(string sectype, out SecurityType st)
|
||||
{
|
||||
if (!Enum.TryParse(sectype.ToUpper(), true, out st))
|
||||
return Enum.TryParse("SECURITY_TYPE" + sectype.ToUpper(), true, out st);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static ConcurrentDictionary<string, Type> _types = new ConcurrentDictionary<string, Type>();
|
||||
public static Type find_full_type_in_all_assemblies(string type, string assembly_regex = null, Type assignable_from = null)
|
||||
{
|
||||
if (assignable_from == null)
|
||||
assignable_from = typeof(object);
|
||||
if (type == null)
|
||||
return null;
|
||||
Type res = null;
|
||||
if (!_types.TryGetValue(type, out res))
|
||||
{
|
||||
int idx = type.IndexOf("<");
|
||||
if (idx > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] zargs = type.Substring(idx + 1, type.Length - idx - 1).Replace(">", string.Empty).Split(',');
|
||||
string gtstring = type.Substring(0, idx) + "`" + zargs.Length.ToString();
|
||||
var gt = find_full_type_in_all_assemblies(gtstring, assembly_regex);
|
||||
Type[] args = new Type[zargs.Length];
|
||||
for (int i = 0; i < zargs.Length; i++)
|
||||
args[i] = find_full_type_in_all_assemblies(zargs[i], assembly_regex);
|
||||
res = gt.MakeGenericType(args);
|
||||
}
|
||||
catch (Exception) { /*TODO log?*/ }
|
||||
}
|
||||
else
|
||||
{
|
||||
List<Type> alltypes = find_all_types_in_all_assemblies(type, assembly_regex);
|
||||
foreach (Type at in alltypes)
|
||||
{
|
||||
if (!assignable_from.IsAssignableFrom(at))
|
||||
continue;
|
||||
res = at;
|
||||
_types[type] = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static public List<Type> find_all_types_in_all_assemblies(string type, string assembly_regex = null)
|
||||
{
|
||||
List<Type> res = new List<Type>();
|
||||
var asses = AppDomain.CurrentDomain.GetAssemblies();
|
||||
foreach (Assembly a in asses)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(assembly_regex))
|
||||
{
|
||||
if (!Regex.Match(a.GetName().Name, assembly_regex).Success)
|
||||
continue;
|
||||
}
|
||||
Type t = a.GetType(type, false, true);
|
||||
if (t != null)
|
||||
res.Add(t);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static public T[,] transpose_keep_dimension<T>(T[,] array)
|
||||
{
|
||||
var res = new T[array.GetLength(1), array.GetLength(0)];
|
||||
for (int i = 0; i < array.GetLength(1); i++)
|
||||
for (int j = 0; j < array.GetLength(0); j++)
|
||||
res[i, j] = array[j, i];
|
||||
return res;
|
||||
}
|
||||
|
||||
static public T[,] transpose<T>(T[,] array)
|
||||
{
|
||||
var res = new T[array.Length, 1];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
res[i, 0] = array[0, i];
|
||||
return res;
|
||||
}
|
||||
|
||||
static public T[,] transpose<T>(T[] array)
|
||||
{
|
||||
var res = new T[array.Length, 1];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
res[i, 0] = array[i];
|
||||
return res;
|
||||
}
|
||||
|
||||
static public object[,] transpose(Array array)
|
||||
{
|
||||
var res = new object[array.Length, 1];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
res[i, 0] = array.GetValue(i);
|
||||
return res;
|
||||
}
|
||||
|
||||
static public T[,] make_column_vector<T>(T[] row_array)
|
||||
{
|
||||
return transpose<T>(row_array);
|
||||
}
|
||||
|
||||
static public T[] make_row_vector<T>(T[,] col_array)
|
||||
{
|
||||
var res = new List<T>();
|
||||
for (int i = 0; i < col_array.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < col_array.GetLength(1); j++)
|
||||
{
|
||||
res.Add(col_array[i, j]);
|
||||
}
|
||||
}
|
||||
return res.ToArray();
|
||||
}
|
||||
|
||||
|
||||
static public Array make_row_vector(Type type, object[,] col_array)
|
||||
{
|
||||
var res = Array.CreateInstance(type, col_array.Length);
|
||||
int len = col_array.GetLength(1);
|
||||
for (int i = 0; i < col_array.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < len; j++)
|
||||
{
|
||||
var obj = col_array[i, j];
|
||||
if (type.IsAssignableFrom(obj.GetType()))
|
||||
res.SetValue(obj, i * len + j);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static public string bts_stringify_array_typed(object[,] data, string typename)
|
||||
{
|
||||
Type type = find_full_type_in_all_assemblies(typename);
|
||||
object array = DataParser.gather_data(type, data);
|
||||
|
||||
object ret;
|
||||
DataParser.write_data(out ret, array);
|
||||
return ret.ToString();
|
||||
}
|
||||
|
||||
static public string bts_stringify_array(object[] array)
|
||||
{
|
||||
object ret;
|
||||
DataParser.write_data(out ret, array);
|
||||
return ret.ToString();
|
||||
}
|
||||
|
||||
static public object[,] bts_read_stringified_array(object array, string typename)
|
||||
{
|
||||
Type type = find_full_type_in_all_assemblies(typename);
|
||||
object data = DataParser.read_data(type, array);
|
||||
object[,] ret = DataParser.scatter_data(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static public object[,] bts_read_double_array(object array)
|
||||
{
|
||||
object data = DataParser.read_data(typeof(double[]), array);
|
||||
object[,] ret = DataParser.scatter_data(data, false);
|
||||
var t = transpose(ret);
|
||||
return t;
|
||||
}
|
||||
|
||||
static public object[,] bts_read_string_array(object array)
|
||||
{
|
||||
object data = DataParser.read_data(typeof(string[]), array);
|
||||
object[,] ret = DataParser.scatter_data(data, false);
|
||||
var t = transpose(ret);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
static public T[,] combine_arrays_vertically<T>(IEnumerable<T[,]> arrays)
|
||||
{
|
||||
int rows = 0, cols = 0;
|
||||
foreach (var a in arrays)
|
||||
{
|
||||
if (a.GetLength(1) > cols)
|
||||
cols = a.GetLength(1);
|
||||
rows += a.GetLength(0);
|
||||
}
|
||||
T[,] result = new T[rows, cols]; int idx = 0;
|
||||
foreach (T[,] a in arrays)
|
||||
{
|
||||
for (int i = 0; i < a.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < a.GetLength(1); j++)
|
||||
result[idx, j] = (T)a.GetValue(i, j);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static private Dictionary<string, System.Reflection.Assembly> _ass = new Dictionary<string, System.Reflection.Assembly>();
|
||||
[ExcelFunction(IsMacroType = true)]
|
||||
public static string bts_load_assembly(string assembly_path)
|
||||
{
|
||||
//XlCall.Excel(XlCall.xlfVolatile, false);
|
||||
System.Reflection.Assembly ass;
|
||||
if (!_ass.TryGetValue(assembly_path, out ass))
|
||||
{
|
||||
ass = System.Reflection.Assembly.Load(assembly_path);
|
||||
_ass[assembly_path] = ass;
|
||||
}
|
||||
return (ass == null) ? "ERROR: Couldn't load assembly " + assembly_path : "Assembly Loaded: " + assembly_path + " " + DateTime.Now.ToLongTimeString();
|
||||
}
|
||||
|
||||
static public IList<string> get_tokens(object tag)
|
||||
{
|
||||
List<string> list = new List<string>();
|
||||
if (tag is Array)
|
||||
{
|
||||
Array array = (Array)tag;
|
||||
if (array.Rank > 1)
|
||||
{
|
||||
for (int i = 0; i < array.GetLength(0); i++)
|
||||
{
|
||||
for (int j = 0; j < array.GetLength(1); j++)
|
||||
list.Add(array.GetValue(i, j).ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < array.Length; j++)
|
||||
list.Add(array.GetValue(j).ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
list.Add(tag.ToString());
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.6.1" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.24.3" />
|
||||
<PackageReference Include="System.Reactive" Version="3.1.1" />
|
||||
<PackageReference Include="System.Reactive.PlatformServices" Version="3.1.1" />
|
||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||
@@ -47,54 +47,39 @@
|
||||
</PropertyGroup>
|
||||
-->
|
||||
<!-- $(SparkRoot) is something we define on our build at BTS, if it's empty, this project file is in the wild-->
|
||||
<ItemGroup Condition= " '$(SparkRoot)' != '' ">
|
||||
<ProjectReference Include="../spark_api/spark_api.csproj"/>
|
||||
<ItemGroup Condition=" '$(SparkRoot)' != '' ">
|
||||
<ProjectReference Include="../spark_api/spark_api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition= " '$(SparkRoot)' != '' and '$(TargetFramework)' == 'net471' ">
|
||||
<ItemGroup Condition=" '$(SparkRoot)' != '' and '$(TargetFramework)' == 'net471' ">
|
||||
<!-- This is so we can ship excel in the nupkg -->
|
||||
<ProjectReference Include="../spark_excel/spark_excel.csproj"/>
|
||||
<ProjectReference Include="../spark_excel/spark_excel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition= " '$(SparkRoot)' != '' ">
|
||||
<None Include="README.md" pack="true" PackagePath="." />
|
||||
<None Include="$(OutputPath)\net471\spark_excel_example_2019.xlsm" pack="true" PackagePath=".\excel\spark_excel_example_2019.xlsm" />
|
||||
<None Include="$(OutputPath)\net471\spark_excel-addin64-packed.xll" pack="true" PackagePath=".\excel\spark_excel-addin64-packed.xll" />
|
||||
<None Include="$(OutputPath)\net471\spark_excel-addin64.dna" pack="true" PackagePath=".\excel\spark_excel-addin64.dna" />
|
||||
<None Include="doc/**" pack="true" PackagePath=".\doc\" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences" Condition= " '$(SparkRoot)' != '' ">
|
||||
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences" Condition=" '$(SparkRoot)' != '' ">
|
||||
<ItemGroup>
|
||||
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)..\net471\libspark.dll"/>
|
||||
<BuildOutputInPackage Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
|
||||
<BuildOutputInPackage Include="$(OutputPath)..\net471\libspark.dll" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<!-- deployed sdk build net471 -->
|
||||
<ItemGroup Condition= " '$(SparkRoot)' == '' and '$(TargetFramework)' == 'net471'">
|
||||
<ItemGroup Condition=" '$(SparkRoot)' == '' and '$(TargetFramework)' == 'net471'">
|
||||
<Reference Include="spark_api">
|
||||
<HintPath>..\..\lib\net471\spark_api.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<!-- deployed sdk build netcoreapp2.1 -->
|
||||
<ItemGroup Condition= " '$(SparkRoot)' == '' and '$(TargetFramework)' == 'netcoreapp2.1'">
|
||||
<ItemGroup Condition=" '$(SparkRoot)' == '' and '$(TargetFramework)' == 'netcoreapp2.1'">
|
||||
<Reference Include="spark_api">
|
||||
<HintPath>..\..\lib\netcoreapp2.1\spark_api.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<Target Name="copy_lib_deployed" AfterTargets="PostBuildEvent" Condition= " '$(SparkRoot)' == '' " >
|
||||
<Target Name="copy_lib_deployed" AfterTargets="PostBuildEvent" Condition=" '$(SparkRoot)' == '' ">
|
||||
<Copy SourceFiles="..\..\lib\net471\libspark.dll" DestinationFolder="$(OutputPath)\" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="copy_lib_deployed471" AfterTargets="PostBuildEvent" Condition= " '$(SparkRoot)' == '' and '$(TargetFramework)' == 'net471'" >
|
||||
<Copy SourceFiles="..\..\lib\net471\spark_excel.dll" DestinationFolder="$(OutputPath)\" SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="..\..\excel\spark_excel_example_2019.xlsm" DestinationFolder="$(OutputPath)\" SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="..\..\excel\spark_excel-addin64-packed.xll" DestinationFolder="$(OutputPath)\" SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="..\..\excel\spark_excel-addin64.dna" DestinationFolder="$(OutputPath)\" SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
Loaded 100 of 488 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user